Created
September 19, 2010 18:13
-
-
Save hlegius/586984 to your computer and use it in GitHub Desktop.
[PHP] Realiza queries SQL com PDO.
This file contains hidden or 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 | |
/** | |
* Criteria para a QueryObject | |
* | |
* @author Hélio Costa e Silva <[email protected]> | |
* | |
* @created Novembro, 25 2008 | |
* @revised Dezembro, 26 2008 | |
* @version desenvolvimento / development | |
* | |
* [Dezembro, 26 2008] | |
* + Controle das tabelas manipuladas com addFrom() | |
* + Controle sobre JOIN's com o grupo: addJoin(), removeJoin() e flushJoins() | |
*/ | |
final class Criteria { | |
private $rows = array(); | |
private $filtro = array(); | |
private $start = null; | |
private $registros = null; | |
private $order = null; | |
private $entity = null; | |
private $from = null; | |
private $join = array(); | |
/** | |
* Injeta a entidade na criteria. Serve como base para os dados n�o padr�es | |
* @param Object $classe | |
* @return Criteria (referencia) | |
*/ | |
public function setEntity($classe) { | |
$this->entity = is_object($classe) ? $classe : null; | |
return $this; | |
} | |
/** | |
* Adiciona um crit�rio de busca | |
* @param string $campo (nome do campo da tabela) | |
* @param string $operacao (=, !=, >, <, >=, <= IS, IS NOT) para LIKE, use $this->addLike() | |
* @param string $valor (nome do getter na entidade sem o get. getNome() seria 'nome' ou valor real) | |
* @param bool $valorReal (se TRUE, o $valor � usado como par�metro(valor real) e n�o como atalho da entidade) | |
* @return Criteria (refer�ncia) | |
*/ | |
public function add($campo, $operacao, $valor = -1, $valorReal = false) { | |
if(is_bool($valor) && $valor !== false) | |
settype($valor, 'bool'); | |
else | |
$valor = $valor === -1 ? $campo : $valor; | |
$this->filtro[] = array('field' => $campo, 'oper' => $operacao, 'value' => $valor, 'valorReal' => $valorReal); | |
return $this; | |
} | |
/** | |
* Adiciona um crit�rio usando o LIKE e suas variantes | |
* @param string $campo (nome do campo da tabela) | |
* @param string $operacao (=, !=, >, <, >=, <= IS, IS NOT) para LIKE, use $this->addLike() | |
* @param array $criterio (geralmente usado para completar a busca. i.e: %) | |
* @param string $valor (nome do getter na entidade sem o get. getNome() seria 'nome' ou valor real) | |
* @param bool $valorReal (se TRUE, o $valor � usado como par�metro(valor real) e n�o como atalho da entidade) | |
* @return Criteria (refer�ncia) | |
*/ | |
public function addLike($campo, $operacao, array $criterio, $valor = null, $valorReal = false) { | |
if($operacao != 'LIKE' && $operacao != 'NOT LIKE' && $operacao != "iLIKE") return $this; | |
foreach($criterio as &$criterio_split) { ## s� aceitamos %. � % ou nada ! | |
if($criterio_split !== '%') | |
$criterio_split = ''; | |
} | |
$valor = is_null($valor) ? $campo : $valor; | |
$this->filtro[] = array('field' => $campo, 'oper' => $operacao, 'criterio' => $criterio, 'value' => $valor, 'valorReal' => $valorReal); | |
return $this; | |
} | |
/** | |
* Adiciona um operador | |
* @param string $operator (and, or) | |
* @return Criteria (refer�ncia) | |
*/ | |
public function addOperator($operator) { | |
$this->filtro[] = $operator; | |
return $this; | |
} | |
/** | |
* Adiciona um novo grupo - coloca abre parent�ses | |
* @return Criteria (refer�ncia) | |
*/ | |
public function startParentGroup() { | |
$this->filtro[] = ' ( '; | |
return $this; | |
} | |
/** | |
* Finaliza um grupo - coloca fecha parent�ses | |
* @return Criteria (refer�ncia) | |
*/ | |
public function endParentGroup() { | |
$this->filtro[] = ' ) '; | |
return $this; | |
} | |
/** | |
* Seta o inicio da busca (LIMIT $inicio) | |
* @param int $inicio | |
* @return Criteria (refer�ncia) | |
*/ | |
public function startFrom($inicio) { | |
settype($inicio,'int'); | |
$this->start = $inicio; | |
return $this; | |
} | |
/** | |
* Itens a buscar (LIMIT $inicio,$registros) | |
* @param int $registros | |
* @return Criteria (Refer�ncia) | |
*/ | |
public function stopWith($registros) { | |
settype($registros,'int'); | |
$this->registros = $registros; | |
return $this; | |
} | |
/** | |
* Adiciona a ordem de resultados | |
* @param string $field (campo) | |
* @param string $order (ASC,DESC) | |
* @return Criteria (refer�ncia) | |
*/ | |
public function orderBy($field, $order) { | |
$this->order = $field . ' ' . strtoupper($order); | |
return $this; | |
} | |
/** | |
* Campo a ser buscado (*, COUNT(1), DISTINCT(), nome,idade,id...) | |
* @param string $row | |
* @return Criteria (refer�ncia) | |
*/ | |
public function addRow($row) { | |
if(is_array($row)) { | |
foreach($row as $campo) { | |
$this->rows[] = $campo; | |
} | |
}else{ | |
$this->rows[] = $row; | |
} | |
return $this; | |
} | |
/** | |
* Remove os rows j� setados | |
* @return this | |
*/ | |
public function flushRow() { | |
$this->rows = null; | |
return $this; | |
} | |
/** | |
* Seta as tabelas a serem lidas | |
* @param string $from | |
*/ | |
public function addFrom($from) { | |
$this->from = $from; | |
return $this; | |
} | |
/** | |
* Adiciona um Join ao criteria | |
* @param string(LEFT, RIGHT, INNER) $tipo | |
* @param string(sqltable) $table | |
* @param string(join clause) $join | |
* @param mixed $internal_name | |
* @return this | |
*/ | |
public function addJoin($tipo, $table, $join, $internal_name = null) { | |
$internal_name = !is_null($internal_name) ? $internal_name : count($this->join); | |
$this->join[$internal_name] = strtoupper(str_replace(" JOIN", "",$tipo)) . ' JOIN ' . $table . ' ON ' . $join . ' '; | |
return $this; | |
} | |
/** | |
* Remove um Join que tenha sido previamente identificado com um internal_name | |
* @param mixed $internal_name | |
* @return this | |
*/ | |
public function removeJoin($internal_name) { | |
if (key_exists($internal_name, $this->join)) { | |
(unset)$this->join[$internal_name]; | |
} | |
return $this; | |
} | |
/** | |
* Reseta todas as Joins anteriormente setadas. | |
* @return this | |
*/ | |
public function flushJoins() { | |
$this->join = array(); | |
return $this; | |
} | |
/** | |
* Verifica se h� algum filtro setado | |
* @return boolean | |
*/ | |
public function hasFiltros() { | |
if(count($this->filtro) == 0) | |
return false; | |
else | |
return true; | |
} | |
/** | |
* Reseta os filtros | |
* @return void | |
*/ | |
public function cleanup() { | |
$this->rows = array(); | |
$this->filtro = array(); | |
$this->start = null; | |
$this->registros = null; | |
$this->order = null; | |
$this->entity = null; | |
$this->from = null; | |
$this->join = array(); | |
} | |
public function getFrom() { return $this->from; } | |
public function getRows() { return $this->rows; } | |
public function getJoins() { return $this->join; } | |
public function getFiltro() { return $this->filtro; } | |
public function getStart() { return $this->start; } | |
public function getRegistros() { return $this->registros; } | |
public function getOrder() { return $this->order; } | |
public function getEntity() { return $this->entity; } | |
public function dump() { | |
var_dump($this->filtro); | |
} | |
} |
This file contains hidden or 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 | |
/** | |
* Classe que implementa a QueryObject | |
* Funciona apenas com MySQL | |
* basicamente funciona com SELECTs, e DELETEs | |
* | |
* @author Hélio Costa e Silva <[email protected]> | |
* | |
* @created Novembro, 25 2008 | |
* @revised Janeiro, 13 2009 | |
* @version desenvolvimento / development | |
* | |
* [Janeiro, 13 2009] | |
* + Arrumado BUG do 'auto-and' mode | |
* + Adicionado controle contra 'and'/'or' solitário no final da Query | |
* | |
* [Dezembro, 26 2008] | |
* + Possibilidade de setar as tabelas com criteria->addFrom() | |
* + Manipulação de JOIN's | |
* | |
* @internal Exemplos no final do arquivo comentado ! | |
*/ | |
/** | |
* @todo criar classes especializadas que irão extender uma base. | |
* Servirá para criar UPDATEs, INSERTs com maior precisão | |
* Criar JOIN's (agora temos JOIN's \o/ [Dez, 26 08], HAVING, GROUP BY e outros | |
*/ | |
final class QueryObject { | |
/** | |
* Recebe a Criteria | |
* @var Criteria | |
*/ | |
private $criteria = null; | |
/** | |
* Rows a serem pegos | |
* @var string | |
*/ | |
private $rows = null; | |
/** | |
* Tabelas a serem pesquisadas | |
* @var string | |
*/ | |
private $from = null; | |
/** | |
* A clausula where | |
* @var string | |
*/ | |
private $condition = null; | |
/** | |
* Ordenação e limites | |
* @var string | |
*/ | |
private $limit = null; | |
/** | |
* Elementos do prepared-statement (PDO) | |
* @var array | |
*/ | |
private $bind = null; | |
/** | |
* Construtor da classe. Recebe a Criteria | |
* @param Criteria $criteria | |
*/ | |
public function __construct(Criteria $criteria) { | |
$this->criteria = $criteria; | |
$this->getInstruction(); ## roda a Query | |
} | |
/** | |
* Monta a estrutura de critérios | |
* @return string | |
*/ | |
private function getInstruction() { | |
$this->rowsInstruction(); ## setando os campos a serem buscados | |
$this->joinsInstruction(); ## montando os possíveis joins | |
$criterios = $this->criteria->getFiltro(); | |
if (count($criterios) == 0) { | |
$this->condition = $this->trim($this->condition . $this->limitInstruction()); | |
return ; | |
} | |
$this->condition .= ' WHERE '; | |
$otherFlags = false; | |
foreach ($criterios as $indice => $criterio) { | |
if (!is_array($criterio)) { ## usado em AND, OR, (, )... | |
$this->condition .= ' ' . $criterio . ' '; | |
$otherFlags = trim($criterio) != ')' ? true : false; ## controla o "auto 'and' condition" | |
continue; | |
} | |
if ($indice != 0 && $otherFlags === false) { ## auto 'and' condition mode | |
$this->condition .= is_array($criterio) ? ' and ' : ''; | |
$otherFlags = false; | |
} | |
if (is_null($criterio['value']) && ($criterio['oper'] == 'IS NOT' || $criterio['oper'] == "IS")) { | |
$this->condition .= $criterio['field'] . '' . (($criterio['oper'] == 'IS NOT') ? ' IS NOT' : ' IS') . ' NULL '; | |
continue; ## IS NOT NULL, IS NULL | |
} | |
if (isset($criterio['criterio']) && is_array($criterio['criterio'])) { # LIKE, NOT LIKE... | |
$this->condition .= $criterio['field'] . ' ' . $criterio['oper'] . " " . '?' . ""; | |
$this->_bindValue($criterio['criterio'][0] . $criterio['value'] . $criterio['criterio'][1], $criterio['valorReal']); | |
continue; | |
} | |
if (is_string($criterio['value']) || is_object($criterio['value']) || is_null($criterio['value'])) { # normal foo=, !=, > ? (foo>?) | |
$this->condition .= $criterio['field'] . '' . $criterio['oper'] . '?'; | |
$this->_bindValue($criterio['value'], $criterio['valorReal']); | |
continue; | |
} | |
if (is_int($criterio['value'])) { ## idade > 19 | |
$this->condition .= $criterio['field'] . '' . $criterio['oper'] . '' . $criterio['value'] . ' '; | |
continue; | |
} | |
if (is_bool($criterio['value'])) { ## selected = TRUE | |
$criterio['value'] = $criterio['value'] === true ? 'TRUE' : 'FALSE'; | |
$this->condition .= $criterio['field'] . '' . $criterio['oper'] . '' . $criterio['value'] . ' '; | |
continue; | |
} | |
} | |
if (substr($this->trim($this->condition), -3) == 'and' || | |
substr($this->trim($this->condition), -2) == 'or') { ## retirando o 'and'/'or' do final (usado em 'and' ou 'or' forçados via addOperator() | |
$this->condition = substr($this->trim($this->condition), 0, -3); | |
} | |
$this->condition = $this->trim($this->condition . $this->limitInstruction()); | |
} | |
/** | |
* Monta o bindValue procurando o seu get$Value na entidade da critéria | |
* @param string $value | |
*/ | |
private function _bindValue($value, $valorReal) { | |
if ($valorReal === false) { ## o possível valor passado é o nome da propriedade da entidade | |
if(method_exists($this->criteria->getEntity(), "get{$value}")) { | |
$this->bind[] = $this->criteria->getEntity()->{"get{$value}"}(); | |
} | |
} else { | |
$this->bind[] = $value; ## relaxa, isso irá via prepared-statement ! | |
} | |
} | |
/** | |
* Cria as Joins da critéria | |
*/ | |
private function joinsInstruction() { | |
$this->condition = ''; ## as Joins vem antes do WHERE ;) | |
foreach ($this->criteria->getJoins() as $join) { | |
$this->condition .= $join . ' '; | |
} | |
} | |
/** | |
* Monta as instruções de retorno. | |
* SELECT (isso aqui!) FROM ... | |
* @return void | |
*/ | |
private function rowsInstruction() { | |
$this->from = $this->criteria->getFrom(); ## anexando o FROM | |
if (is_null($this->criteria->getRows()) || count($this->criteria->getRows()) < 1) { | |
$this->rows = '*'; | |
return ; | |
} | |
if (is_array($this->criteria->getRows())) { | |
foreach ($this->criteria->getRows() as $row) { | |
$this->rows .= $row . ','; | |
} | |
$this->rows = rtrim($this->rows,","); | |
} | |
} | |
/** | |
* Monta as instruções orderby | |
*/ | |
private function orderbyInstruction() { | |
if ($this->criteria->getOrder()) { | |
$this->limit = ' ORDER BY ' . $this->criteria->getOrder() . ' '; | |
} | |
} | |
/** | |
* Monta as instruções de limites | |
* @return string | |
*/ | |
private function limitInstruction() { | |
$this->orderbyInstruction(); | |
if ($this->criteria->getStart() || $this->criteria->getRegistros()) { | |
$this->limit .= ' LIMIT '; | |
if ($this->criteria->getStart()) { | |
$this->limit .= $this->criteria->getStart() . ','; | |
} | |
$this->limit .= ($this->criteria->getRegistros() > 0) ? $this->criteria->getRegistros() : 5; | |
} | |
return $this->limit; | |
} | |
/** | |
* Clausulas de JOIN's, where, OrderBy e Limit | |
* @return string | |
*/ | |
public function getWhere() { return $this->condition; } | |
/** | |
* Retorma os campos a serem buscados | |
* @return string | |
*/ | |
public function getRows() { return $this->rows; } | |
/** | |
* Retorna as tabelas a serem pesquisadas | |
* @return string | |
*/ | |
public function getFrom() { return $this->from ; } | |
/** | |
* Retorna os elementos a serem passados à prepared-statement | |
* @return array | |
*/ | |
public function bindValues() { return $this->bind; } | |
/** | |
* Remove espaços excedentes do começo, meio e fim da string | |
* @param string $String | |
* @return string | |
*/ | |
private function trim($String) { | |
$space = 0; | |
$newstr = ""; | |
$strlen = strlen($String); | |
for ($i=0;$i<$strlen;$i++) { | |
if ($String[$i] == " ") { | |
$space++; | |
if ($space == 2) : | |
$space--; | |
continue; | |
endif; | |
} else { | |
$space = 0; | |
} | |
$newstr .= $String[$i]; | |
} | |
$space = null; $strlen = null; // trash garbage | |
return trim($newstr); | |
} | |
/** | |
* Dumpa a classe toda para análise. | |
* Developer only! | |
*/ | |
public function dump() { | |
var_dump($this); | |
} | |
/* | |
* Exemplo de utilização da Query Object | |
* | |
$criteria = new Criteria; | |
$criteria->setEntity(new Pessoa(id, 'nome', idade)) | |
->addRow('nome') | |
->addRow('idade') | |
->addLike('nome', 'LIKE', array(null, '%')) | |
->addOperator('and') | |
->startParentGroup() | |
->add('idade','>') | |
->addOperator('or') | |
->add('idade', '<', 50) | |
->addOperator('and') | |
->startParentGroup() | |
->add('selected','=', false) | |
->addOperator('or') | |
->add('hahaha','IS NOT', null) | |
->endParentGroup() | |
->addOperator('and') | |
->add('hohoho','IS', null) | |
->endParentGroup() | |
->add('nome','=') | |
->startFrom(1) | |
->stopWith(10) | |
->orderBy('idade', 'DESC'); | |
$qo = new QueryObject(new Criteria); | |
var_dump($qo); | |
* | |
*/ | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment