Skip to content

Instantly share code, notes, and snippets.

@filhodanuvem
Created November 9, 2012 18:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save filhodanuvem/4047259 to your computer and use it in GitHub Desktop.
Save filhodanuvem/4047259 to your computer and use it in GitHub Desktop.
<?php
/**
* Comentario do arquivos
*
* @author Vinícius Fontoura <vinicius@aprimorar.com>
* @copyright 2012 Aprimorar Desenvolvimento Ltda(c)
* @version SVN: $Rev$ $LastChangedDate$ $LastChangedBy$
*/
namespace Aprimorar\DataTableBundle\Grid;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Aprimorar\EssencialBundle\Repository\ApEntityRepository;
use Aprimorar\EssencialBundle\Exception\ApException;
use Respect\Validation\Validator;
use Aprimorar\EssencialBundle\Interfaces\InputSearchType;
/**
* Descicao de Request
*
* @author Vinícius fontoura <vinicius@aprimorar.com>
* @author Claudson Oliveira <claudson@aprimorar.com>
*/
class Response implements \Aprimorar\EssencialBundle\Interfaces\GridResponse
{
/**
* Registros
* @var array
*/
public $aaData = array();
/**
* Registros totais
* @var string
*/
public $iTotalDisplayRecords;
/**
* Registros totais sem limit ou where
* @var string
*/
public $iTotalRecords;
/**
* Informação que dataTables usa para processamento
* @var integer
*/
public $sEcho = 1;
protected $iColumns = 0;
protected $request;
public function __construct($request)
{
$this->sEcho = $request['sEcho'];
$this->request = $request;
}
/**
* Rece uma 'coleção', um array de objetos
* e o transforma num array valido para o gridResponse
* baseado nas colunas
* @author Claudson Oliveira
* @param array $dados
* @param array $colunas
*/
public function setConteudo(Array $dados, Array $colunas)
{
$gridDados = array();
$i = 0;
$propriedades = $colunas;
foreach ($dados as $instancia) {
$ateUltimaPropriedade = 0; // contador do for de propriedades
foreach ($propriedades as $propriedade => $label) {
if (is_numeric($propriedade)) {
// para pular colunas, passamos chaves inteiras
$gridDados[$i][] = null;
continue;
}
$gridDados[$i][] = $this->acessa($propriedade, $instancia);
++$ateUltimaPropriedade;
}
$i++;
}
// uma grid pode ter 6 colunas e só buscar no banco 5 atributos,
// entao precisamos preencher o resto do json de retorno com
// null para esses casos onde o valor da coluna sera gerado
// dinamicamente.
// @example: ultima coluna de ações
if (count($colunas) < $this->iColumns) {
foreach ($gridDados as &$linha) {
for ($i = count($colunas); $i < $this->iColumns; $i++) {
$linha[$i] = null;
}
}
}
$this->setTotalDisplay(count($dados));
$this->aaData = array_merge($this->aaData, $gridDados);
}
/**
*
* @param type $propriedade
* @param Object $instancia
* @return mixed
*/
private function acessa($propriedade, $instancia)
{
// a propriedade é na verdade uma composição
// precisaremos acessar um atributo de um atributo de um atributo ...
// @example filho.filho.nome vira $instancia->getFilho()->getFilho()->getNome();
if ($instancia && !is_object($instancia)) {
return null; // @todo exception;
}
if (strpos($propriedade, '.') !== false) {
// se há um ponto quer dizer que precisamos quebrar a
// expressao e chamar recursivamente o metodo para continuar
// tratando a cadeia de metodos
$dados = explode('.', $propriedade, 2); // @todo é 2 mesmo?
$atributo = $dados[0];
$propriedade = $dados[1];
$get = 'get'.ucfirst($atributo);
if (method_exists($instancia, $get)) {
$filho = $instancia->$get();
return $this->acessa($propriedade, $filho);
}
$className= get_class($instancia);
throw new ApException(" Método {$get} e {$is} não encontrados em instancia de {$className}");
}
$get = 'get'.ucfirst($propriedade);
if (method_exists($instancia, $get)) {
return $instancia->$get();
}else {
$is = 'is'.ucfirst($propriedade);
if (method_exists($instancia, $is)) {
return $instancia->$is();
}
}
$className= get_class($instancia);
throw new ApException(" Métodos {$get} e {$is} não encontrados em instancia {$className}");
}
/**
*
* @param array $request
* @param array $colunas
* @return array requisicao formatada para um padrão entendivel pelos repositorios, meio indexcms isso :P
*/
public function formatRequest(Array $request, Array $colunas)
{
$requestFormatada = array(
'limit' => null,
'orderBy' => null,
'like' => null,
'search' => null,
);
if (array_key_exists('iDisplayLength', $request)) {
$requestFormatada['limit'] = $request['iDisplayLength'];
}
if (array_key_exists('iSortCol_0', $request)) {
$campos = array_keys($colunas);
$requestFormatada['orderBy'] = $campos[$request['iSortCol_0']];
}
if (array_key_exists('sSearch', $request)) {
$like_array = $request['sSearch'];
if (Validator::create()->json()->validate($like_array)) {
$like_array = json_decode($like_array,true);
}
if (is_array($like_array)) {
foreach ($like_array as $nome => $like) {
if (!strpos($nome,'_') || !$like) {
continue; // exception?
}
$dados = explode('_', $nome);
$nome = $dados[0];
$tipoCampo = $dados[1];
$requestFormatada['like'][$nome] = InputSearchType::formatLike($nome, $tipoCampo, $like);
}
}
}
if (array_key_exists('sSortDir_0', $request)) {
$requestFormatada['orderDir'] = $request['sSortDir_0'];
}
if (array_key_exists('iColumns', $request)) {
$this->iColumns = $request['iColumns'];
}
return $requestFormatada;
}
public function setTotal($total)
{
$this->iTotalRecords = $total;
}
public function setTotalDisplay($total)
{
$this->iTotalDisplayRecords = $total;
}
/**
* Preenche os atributos desta classe
* @param ContainerInterface $container
* @param array $repository
* @param array $request
*/
public function fromEntity(ContainerInterface $container, $repository)
{
// Transformando os indices do array em variaveis
extract($this->request);
$campos = array();
$i=0;
// loop para pegar todos os campos passados no request
while (true) {
$variavel = 'aCampo_'.$i;
if (!isset($$variavel)) {
break;
}
$campos[$i] = $$variavel;
$i++;
}
// Deixando no indice de $campos apenas o campo sem alias,
// pricipalmente para campos com relação
array_walk(
$campos,
function (&$valor) {
if (strpos($valor, '.') !== false) {
$valor = str_replace('.', '_', $valor);
} else {
$valor = 't_'.$valor;
}
}
);
foreach ($repository as $registro) {
$linha = array();
foreach ($campos as $campo) {
$linha[] = $registro[$campo];
}
$linha[] = $linha[0];
$this->aaData[] = $linha;
}
// // O resutlado da consulta passado por parametro é um array
// if(is_array($repository)) {
// $serializer = $container->get('serializer');
// /* @var $serializer \Symfony\Component\Serializer\Serializer */
// // Varrendo todos os registros
// foreach($repository as $registro) {
// // Faço isso por que alem dos campos que eu pedi ele faz um "*"
// // na tabela pricipal e poem dentro de um array indice "0"
// unset($registro[0]);
// // objetos são transformados em arrays por normalizar mas usando o metodo "get" da classe
// $normalizado = $serializer->normalize($registro);
//
// $linha = array();
// // Varrendo todos os campos para remover o nome e deixar apenas o valor
// foreach($normalizado as $campo=>$valor) {
// // este campo não tem em $campos? continua o foreach
// if(!empty($campos) && !in_array($campo, $campos)) continue;
// $linha[] = $valor;
// }
// $this->aaData[] = $linha;
// }
// }
// atributo iTotalDisplayRecords ainda ta nulo?
// Vamos preencher ele porque se não o dataTables da pau
if (is_null($this->iTotalDisplayRecords)) {
$this->iTotalDisplayRecords = (string)count($repository);
}
// atributo iTotalRecords ainda ta nulo?
// Vamos preencher ele porque se não o dataTables da pau
if (is_null($this->iTotalRecords)) {
$this->iTotalRecords = (string)count($repository);
}
$this->sEcho = $sEcho;
}
/**
* Retorna um json da instancia atual
* @return string
*/
public function toJson()
{
$this->sEcho++;
return json_encode($this);
}
/**
* Metodo de consulta para o DataTables
*
* @author Vinicius Fontoura Correa 29/02/2012
* @since 29/02/2012
* @param array $request
* @param boolean $completo
* @return array|mixed
*/
public function search($request, ApEntityRepository $repositorio, $extras = array())
{
// Transformando os campos do array en variaveis locais
extract($request);
$campos = array();
$i=0;
// loop para criar o campo aCampo_#
// que serve par a dizer ao dataDables quais campos queremos exibir
while (true) {
$variavel = 'aCampo_'.$i;
if (!isset($$variavel)) {
break;
}
$campos[$i] = $$variavel;
$i++;
}
// Ordenção simples quando clica em um cabecalho
$orderBy = array($campos[$iSortCol_0]=>$sSortDir_0);
// Alias para a tabela do from
$aliasPrincipal = $repositorio->getAliasPrincipal();
// Expressao regular para pegar o nome do campo que você quer consulta
// Sei que da pra fazer com 1 expressao mas eu nao consegui
$regexpSimples = '/^(?<tabela>('.$aliasPrincipal.'\.)?)(?<campo>\w*)$/i';
$regexpRelacao = '/(?<relacao>(^'.$aliasPrincipal.'\.)(?<tabela>.*(?=\.)))(?<campo>\.\w*)/i';
// Criando um QueryBuilder
$queryBuilder = $repositorio->createQueryBuilder($aliasPrincipal);
/* @var $expr \Doctrine\ORM\Query\Expr */
$expr = $queryBuilder->expr();
// Varrendo todos os campos
foreach ($campos as $campo) {
// É um campo para tabela principal
// "codigo" ou "principal.codigo"
if (preg_match($regexpSimples, $campo, $matches)) {
// Se não ta usando o alias da tabela principal adiciona ele
// para não dar erro
if (empty($matches['tabela'])) {
$matches['tabela'] = $aliasPrincipal.'.';
}
// Adicionando o campo ao SELECT
$queryBuilder->addSelect($matches['tabela'].$matches['campo'].' as ' . str_replace('.', '_', $matches['tabela']).str_replace('.', '_', $matches['campo']));
// É um campo de relacionamento?
// "principal.camporelacao.codigo"
} elseif(preg_match($regexpRelacao, $campo, $matches)) {
// Fazendo INNER JOIN
$queryBuilder->innerJoin($matches['relacao'], $matches['tabela']);
// Adiciona ao SELECT
$queryBuilder->addSelect($matches['tabela'].$matches['campo'].' as ' . $aliasPrincipal.'_'.str_replace('.', '_', $matches['tabela']).str_replace('.', '_', $matches['campo']));
}
// Fazer pesquisa simples?
// Essa é a pesquisa simple, aquela que pesquisa em todos os campos
if (!empty($sSearch) && !is_null($sSearch)) {
// Se não ta usando o alias da tabela principal adiciona ele
// para não dar erro
if (empty($matches['tabela'])) {
$matches['tabela'] = $aliasPrincipal.'.';
}
// Adicionando clausula WHERE com LIKE %%
// $queryBuilder->orWhere($queryBuilder->expr()->like($matches['tabela'].$matches['campo'], $queryBuilder->expr()->literal('%'.$sSearch.'%')));
$queryBuilder->orWhere('cast('.$matches['tabela'].str_replace('.', '_', $matches['campo']).' as text) LIKE ?1')
->setParameter(1, '%'.$sSearch.'%');
}
}
$i=0;
while (true) {
$variavel = 'sSearch_'.$i;
if (!isset($$variavel)) {
break;
}
if (empty($$variavel) || is_null($$variavel)) {
$i++;
continue;
}
if (preg_match($regexpSimples, $campos[$i], $matches)) {
if (empty($matches['tabela'])) {
$matches['tabela'] = $aliasPrincipal.'.';
}
// Adicionando o campo ao SELECT
$queryBuilder->andWhere($expr->eq($matches['tabela'].$matches['campo'], $$variavel));
}
$i++;
}
if (array_key_exists('andWhere', $extras) && $extras['andWhere']) {
// isso cheira a gambis
foreach ($extras['andWhere'] as $field => $value) {
$queryBuilder->andWhere($expr->eq($matches['tabela'].$field, $value));
}
}
// Fazendo ORDER BY simples quando clica em um cabecalho
foreach ($orderBy as $campo => $direcao) {
// Casou com alguma das expressoes?
if (preg_match($regexpSimples, $campo, $matches) || preg_match($regexpRelacao, $campo, $matches)) {
// Se não ta usando o alias da tabela principal adiciona ele
// para não dar erro
if (empty($matches['tabela'])) {
$matches['tabela'] = $aliasPrincipal.'.';
}
// Adiciona clausula ORDER BY
$queryBuilder->addOrderBy($matches['tabela'].$matches['campo'], $direcao);
}
}
// OFFER
$queryBuilder->setFirstResult($iDisplayStart);
// LIMIT
if ($iDisplayLength < 0 ) {
$iDisplayLength = self::LIMIT_DEFAULT;
}
$queryBuilder->setMaxResults($iDisplayLength);
// Resultado da consulta
$aaData = $queryBuilder->getQuery()->execute();
// É pra retornar em formato para o AjaxSource?
if (!array_key_exists('completo', $extras) || $extras['completo']) {
// Removendo LIMIT para contar quantos registro existem, mas com o WHERE
$queryBuilder->setMaxResults(null);
$queryBuilder->setFirstResult(null);
$iTotalDisplayRecords = count($queryBuilder->getQuery()->execute());
// Gambiarra para trazer todos os regestros da tabela
$queryBuilder->orWhere('1=1');
$iTotalRecords = count($queryBuilder->getQuery()->execute());
$this->setTotal($iTotalRecords);
// Transformando em array
$retorno = compact('aaData', 'iTotalRecords', 'iTotalDisplayRecords');
} else {
$retorno = $aaData;
$this->setTotal($repositorio->getTotalRegistros());
}
/* @var $cache \Aprimorar\EssencialBundle\Repository\Cache */
$cache = $repositorio->getCache();
$cache->saveState($queryBuilder, $repositorio->getAlias());
return $retorno;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment