Usamos cookies para medir audiência e melhorar sua experiência. Você pode aceitar ou recusar a qualquer momento. Veja sobre o iMasters.
public function read($tabela, $where = null, $limit = null, $offset = null, $orderby = null){
$where = ($where != null ? "WHERE {$this->AntiSQL($where)}" : "");
$limit = ($limit != null ? "LIMIT {$this->AntiSQL($limit)}" : "");
$offset = ($offset != null ? "OFFSET {$this->AntiSQL($offset)}" : "");
$orderby = ($orderby != null ? "ORDER BY {$this->AntiSQL($orderby)}" : "");
$query = "SELECT * FROM {$tabela} {$where} {$orderby} {$limit} {$offset}";
#echo $query."<br />";
$q = $this->_db->query($query);
if ($q){
$q->setFetchMode(PDO::FETCH_ASSOC);
return $q->fetchAll();
} else {
return false;
}
}
Alguém pode me dá uma luz de como separar o WHERE, LIMIT, OFFSET e ORDERBY de forma que sejam enviados em parametros para o $pdo->exec?
Desde já, grato. :v
Então seria mais vantajoso criar um método separado para preparar os parâmetros, não?
Você quer fazer isso com select ou insert? Porque no título diz insert, enfim.. de qualquer forma o principio será o mesmo.
>
public function read($tabela, $where = null, $limit = null, $offset = null, $orderby = null){
$where = ($where != null ? "WHERE {$this->AntiSQL($where)}" : "");
$limit = ($limit != null ? "LIMIT {$this->AntiSQL($limit)}" : "");
$offset = ($offset != null ? "OFFSET {$this->AntiSQL($offset)}" : "");
$orderby = ($orderby != null ? "ORDER BY {$this->AntiSQL($orderby)}" : "");
$query = "SELECT * FROM {$tabela} {$where} {$orderby} {$limit} {$offset}";
#echo $query."<br />";
$q = $this->_db->query($query);
if ($q){
$q->setFetchMode(PDO::FETCH_ASSOC);
return $q->fetchAll();
} else {
return false;
}
}
Não tenha medo de usar OOP, nesse caso se parece mais à programação estruturada.
Você poderia ter classes Insert, Select, Update e Delete para manipular SQL Statements, as cláusulas (where, limit...) poderiam ser métodos, assim além de ser mais fácil você tratar os casos separadamente ainda teria uma interface mais amigável, mas não se esquecendo também que no final tudo isso se resume em montar uma string e ter parâmetros.
Um exemplo de como poderia ser feito da forma que falei:
class Select {
private $from;
private $where;
private $parameters = array();
private $pdo;
public function __construct(PDO $pdo) {
$this->pdo = $pdo;
}
public function from($from) {
$this->from = (array)$from;
return $this;
}
public function where($where, array $parameters = array()) {
if (empty($this->where)) {
$this->where = sprintf(' WHERE %s', $where);
} else {
$this->where .= sprintf(' AND %s', $where);
}
$this->parameters = array_merge($this->parameters, $parameters);
return $this;
}
public function execute() {
$stmt = $this->pdo->prepare($this);
foreach ($this->parameters as $key => $value) {
if (is_int($key)) {
$stmt->bindValue(++$key, $value);
} else {
$stmt->bindValue($key, $value);
}
}
$stmt->execute();
return $stmt;
}
public function toString() {
return sprintf('SELECT * FROM %s%s', implode(',', $this->from), $this->where);
}
public function __toString() {
return $this->toString();
}
}
Usando..
$pdo = new PDO('...');
$select = new Select($pdo);
$select->from('user')
->where('name = "Marcelo"');
echo $select; // Select::__toString(): SELECT * FROM user WHERE name = "Marcelo"
Executando a consulta..
$stmt = $select->from('user')
// usando named placeholders
->where('name = :name', array('name' => 'Marcelo'))
->execute();
print_r($stmt->fetchAll());
Ou você pode passar parâmetros posicionais ao invés de nomeados..
$select->where('name = ?', array('Marcelo')); // usando positional placeholders
Antes você utilizava um método que supostamente era para SQL Injections, AntiSQL() mas esqueça isso, você está usando PDO e ele possui recursos para lidar com isso e se chamam Prepared Statements, veja: http://www.php.net/manual/pt_BR/pdo.prepared-statements.php
É apenas uma ideia, a classe está bem incompleta sendo que há várias outras cláusulas à serem implementadas aí, mas agora é com você!
Ah e pesquise também sobre Fluent Interfaces..
Quero fazer com um SELECT, com o Insert eu já possuo. rs
O que me mata é como pegar o WHERE caso houver mais de um parametro. rs
O que me mata é como pegar o WHERE caso houver mais de um parametro. rs
Não entendi muito bem o que você quis dizer. Você analisou o exemplo do post #4?
No caso do exemplo, para adicionar várias condições bastaria fazer:
$select->from('user')
->where('name = :name', array('name' => 'Marcelo'))
->where('age = :age', array('age' => 20));
echo $select; // Saída: SELECT * FROM user WHERE name = :name AND age = :age
Ou..
$select->from('user')
->where('name = :name AND age = :age', array('name' => 'Marcelo', 'age' => 20));
echo $select; // Saída: SELECT * FROM user WHERE name = :name AND age = :age
Sendo que para cada vez que invocamos o método where() podemos passar junto a condição os valores dos parâmetros. Quando a consulta for executada os valores serão adicionados automaticamente ao statement, como você pode ver no método execute():
>
public function execute() {
$stmt = $this->pdo->prepare($this);
foreach ($this->parameters as $key => $value) {
if (is_int($key)) {
$stmt->bindValue(++$key, $value);
} else {
$stmt->bindValue($key, $value);
}
}
$stmt->execute();
return $stmt;
}
forma que sejam enviados em parametros para o $pdo->exec?
Creio que o que você esteja confundindo é querer adicionar parâmetros ao PDO::exec(), ele pede como parâmetro apenas um SQL Statement, portanto você teria que passar o valor literal à string SQL o que é totalmente inseguro, então não há como passar parâmetros à esse método. Por isso disse para que você estude sobre Prepared Statements.. http://www.php.net/manual/pt_BR/pdo.prepared-statements.php
Olá,
Bom, uma vez que o tópico foi resolvido, gostaria de me intrometer para tirar uma dúvida com a galera que programa em OO, se possível.
Como comecei a usar OO agora, ainda faço algo do tipo em minhas models:
Exemplo.php
public function __contruct( Database $db )
{
$this->db = $db; //Instância de PDO, p. ex.
}
public function insert( Entity $entity ) $stmt = $this->db->prepare('
INSERT INTO `test`
(id, name)
VALUES
(:id, :name)
');
$stmt->bindParam( ':id', $entity->getId(), PDO::PARAM_INT );
$stmt->bindParam( ':name', $entity->getName(), PDO::PARAM_STR );
if ( $stmt->execute() ) {
return (int)$this->db->lastInsertId();
}
throw new Exception( 'Não foi possível inserir....' );
}
public function getById( Entity $entity ) $stmt = $this->db->prepare('
SELECT
`id`, `name`
FROM
`test`
WHERE
`id` = :id;
');
$stmt->bindParam( ':id', $entity->getId(), PDO::PARAM_INT );
$stmt->execute();
$data = $stmt->fetch();
$stmt->closeCursor();
return $data;
}
Ou seja, eu sempre monto uma consulta para cada caso (Update, select, insert etc), às vezes até repetindo a estrutura... O que a estrutura acima, por exemplo, poderia me beneficiar ?vi um tópico aqui do João Neto, onde ele abstrai ao máximo essas expressões e a conexão com o banco, mas ficou muito avançado pra mim encaixar as coisas, mesmo relendo algumas vezes:
http://forum.imasters.com.br/topic/401441-organizar-cdigo/?p=1572696
Será que acabdo caindo nas mesmas situações que ele mencionou? DRY e KISS?
Obrigado
Ou seja, eu sempre monto uma consulta para cada caso (Update, select, insert etc), às vezes até repetindo a estrutura...
O que você poderia fazer seria criar algo mais genérico. Por exemplo, atualmente eu possuo um GenericDAO, um DAO único no projeto com as funcionalidades de CRUD implementadas genericamente. Na verdade isso gira em torno de uma estrutura mais elaborada. Mas basicamente funciona assim, para obter os dados/popular uma entidade eu uso Reflection e monto o SQL dinamicamente. Um pouco parecido com o que o Doctrine faz, porém mais simples..
Reusabilidade? Elegância/Legibilidade? Performance?
Reusabilidade? :upset: ops! Acho que você confundiu o termo, usabilidade é outra coisa. Creio que você estava se referindo à reutilização de código. Bom se for isso então a reposta mais obvia é que não, pois o SQL em si pode variar de uma entidade à outra tonando o código não reutilizável..
Performance, se for em relação ao caso do exemplo que citei no post #4 é claro que você "perderá" alguns milissegundos talvez em relação a string literal, você terá instâncias que por si só requerem espaço de memória e para montar a string irá requerer processamento.
É uma má prática fazer como fiz o exemplo acima?
Pelo trecho postado, é a implementação simples de um DAO.. qual seria a má prática? :huh:
>
vi um tópico aqui do João Neto, onde ele abstrai ao máximo essas expressões e a conexão com o banco, mas ficou muito avançado pra mim encaixar as coisas, mesmo relendo algumas vezes:
http://forum.imasters.com.br/topic/401441-organizar-cdigo/?p=1572696
Será que acabdo caindo nas mesmas situações que ele mencionou? DRY e KISS?
Se o mais simples te atende, continue! Não analisei totalmente a implementação mas me pareceu bem interessante..
Algumas implementações parecidas podem ser vistas no QueryBuilder do Doctrine e também no Zend, Zend\Db\Sql.
Reusabilidade? :upset: ops! Acho que você confundiu o termo, usabilidade é outra coisa. Creio que você estava se referindo à reutilização de código. Bom se for isso então a reposta mais obvia é que não, pois o SQL em si pode variar de uma entidade à outra tonando o código não reutilizável..
Opa, acho que foi isso mesmo, estava pensando em reutilização de código.
Pelo trecho postado, é a implementação simples de um DAO.. qual seria a má prática? :huh:
Não sei se é má prática, é que como estou iniciando em oo, às vezes fico na dúvida se o caminho percorrido por mim está correto... é um mundo totalmente diferente e novo pra mim, sinceramente não estava acostumado com padrões e princípios do tipo SOLID, DAO, Active Record, Pattenrs e afins... :upset:
Se o mais simples te atende, continue! Não analisei totalmente a implementação mas me pareceu bem interessante..
Bom, se não há nada de errado com o DAO acima, acho que vou continuar simples mesmo no início, estou em fase de testes e estudos então tem me atendido bem...
Essa implementação acima também me pareceu bem interessante, mas está alguns níveis acima ainda pra mim, embora possa parecer simples pela didática apresentada..
Algumas implementações parecidas podem ser vistas no QueryBuilder do Doctrine e também no Zend, Zend\Db\Sql.
Vou dar uma olhada nestas duas implementações com calma, obrigado pelos links de referência!
Fiz um bem simples como modelo, adapte como quiser.
Ta aqui o codigo:http://pastebin.com/NYUicEux