Created
November 9, 2012 18:13
-
-
Save filhodanuvem/4047259 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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