Usamos cookies para medir audiência e melhorar sua experiência. Você pode aceitar ou recusar a qualquer momento. Veja sobre o iMasters.
Olá. Ao desenvolver projetos costumo pensar primeiro na forma de uso, porém acho que fiz umas burrices aqui numa classe que estou mexendo.
Ela é uma simples classe de geração de SQL (quem ver meus outros tópicos vai notar que estou a muito tempo mexendo nela, mas é por falta de tempo). Para gerar o seguinte código SQL...:
SELECT login, level FROM players WHERE level >= 15 AND level <= 60 OR vip = 1 GROUP BY class
Minha classe é usada da seguinte forma:
use Database\SQL\Generator;
$generator = new SQL_Generator(SQL_Generator::PARAM_MYSQL);
$sql = $generator->select('login', 'level')->from('players')->where(
$generator->_or(
$generator->_and(
$generator->greater('level', 15, SQL_Generator::GREATER_OR_EQUAL),
$generator->less('level', 60, SQL_Generator::LESS_OR_EQUAL)
),
$generator->equal('vip', true)
)
)->groupBy('class');
Porém acho que não está certo eu usar métodos para cada "pedaço" do SQL, já que desde o nome, métodos e funções devem representar ação (do(), add()...).
Então estou pensando em mudar a forma de uso pro seguinte:
use Database\SQL\Generator;
$generator = new SQL_Generator(SQL_Generator::PARAM_MYSQL);
$sql = $generator->add(SQL_Generator::ADD_SELECT, ['login', 'level'])->add(SQL_Generator::ADD_FROM, ['players'])->add(SQL_Generator::ADD_WHERE, [
$generator->add(SQL_Generator::ADD_OR, [
$generator->add(SQL_Generator::ADD_AND, [
$generator->add(SQL_Generator::ADD_GREATER_OR_EQUAL, ['level', 15]),
$generator->add(SQL_Generator::ADD_LESS_OR_EQUAL, ['level', 60])
]),
$generator->add(SQL_Generator::ADD_EQUAL, ['vip', true])
])
])->add(SQL_Generator::ADD_GROUP_BY, ['class']);
Ficou horrível esse tanto de constante né? (é pra responder).
Estava vendo aqui, e não sei que versão do Doctrine que na classe Doctrine_Query ele usa métodos parecidos com os do meu primeiro código aí, mas mesmo sendo um FW grande e popular, isso não foi capaz de tirar a sensação de que estou fazendo errado aí (no caso seria referente ao nome dos métodos).
Esse segundo código aí me agradou mais pelo nome do método fazer mais sentido (ação de adicionar), mas acho que ficou muito feio isso aí. Se isso for muita frescura, a culpa é dos blogs que falam da importância de um código limpo, hehe.
Então, alguém poderia me dar alguma dica sobre esse caso aí? ^^
Ate mais.
Colega a algum tempo também passei por isso, então decidir criar uma classe utilizando PDO que me permitisse fazer varias ações no mysql de forma simples e sem ter que ficar toda hora criando select, segue o link onde postei a classe aqui no iMaster pode te ajudar a ter uma ideia para a sua, qualquer dúvida é só perguntar
Mesmo usando PDO, você não escapa das diferenças sintáticas existentes entre as implementações do SQL de cada SGBD. Por exemplo, para fazer um casting, no MySQL se utiliza a função CAST(), enquanto que no PostgreSQL a forma mais usual é campo::tipo_de_casting.
Veja, Tiago, não sei se propositalmente ou não, mas sua primeira implementação se parece muito com a estrutura do Zend Framework 1.X, já a segunda, lembra a do Zend Framework 2.X:
:seta: http://framework.zend.com/manual/2.0/en/modules/zend.db.sql.html
A primeira é mais específica, totalmente voltada ao SQL. A vantagen é ser mais simples e menos verbosa.
A segunda implementação é conhecida como Predicate Collection, que consiste de vários predicados (partes de sentença de uma linguagem qualquer) construídos conforme uma orientação. É mais genérica e mais flexível. Você pode adaptar isso para qualquer outra linguagem, desde que não seja muito complexa.
Não sou capaz de eleger uma melhor, fica ao gosto do freguês.
Nota: até onde eu sei, no quesito operadores de comparação, todos os SGBDs que eu conheço implementam os mesmos e funcionam da mesma maneira. Talvez seja desnecessário gerar até isso através do PHP.
>
Colega a algum tempo também passei por isso, então decidir criar uma classe utilizando PDO que me permitisse fazer varias ações no mysql de forma simples e sem ter que ficar toda hora criando select, segue o link onde postei a classe aqui no iMaster pode te ajudar a ter uma ideia para a sua, qualquer dúvida é só perguntar /applications/core/interface/imageproxy/imageproxy.php?img=http://forum.imasters.com.br/public/style_emoticons/default/wink.gif&key=0566fd943552bcff9cb1b879403ca34b5ff8f67befaac7fe4648006e9f764689" alt="wink.gif" />/>
http://forum.imaster..._1#entry1775048
Atualizei a página e cadastrou novamente a mensagem, ADMIN favor excluir este.
Interessante essa sua classe, só achei um pouco diferente mas é legal /applications/core/interface/imageproxy/imageproxy.php?img=http://forum.imasters.com.br/public/style_emoticons/default/biggrin.gif&key=cb0fdb2382312b39ddcb15831fcae62157015f17d2417528782628663387e929" alt="biggrin.gif" />
>
Veja, Tiago, não sei se propositalmente ou não, mas sua primeira implementação se parece muito com a estrutura do Zend Framework 1.X, já a segunda, lembra a do Zend Framework 2.X:
/applications/core/interface/imageproxy/imageproxy.php?img=http://forum.imasters.com.br/public/style_emoticons/default/seta.gif&key=e2d72b30771339c36df1f88688ecc571784dab60a19e2c7c2ff398c277802ac0" alt="seta.gif" />http://framework.zen...end.db.sql.html
A primeira é mais específica, totalmente voltada ao SQL. A vantagen é ser mais simples e menos verbosa.
A segunda implementação é conhecida como Predicate Collection, que consiste de vários predicados (partes de sentença de uma linguagem qualquer) construídos conforme uma orientação. É mais genérica e mais flexível. Você pode adaptar isso para qualquer outra linguagem, desde que não seja muito complexa.
Não sou capaz de eleger uma melhor, fica ao gosto do freguês.
Nota: até onde eu sei, no quesito operadores de comparação, todos os SGBDs que eu conheço implementam os mesmos e funcionam da mesma maneira. Talvez seja desnecessário gerar até isso através do PHP.
Obrigado por responder Henrique /applications/core/interface/imageproxy/imageproxy.php?img=http://forum.imasters.com.br/public/style_emoticons/default/smile.gif&key=15294d64c22e9e9c4ae0bf82a62ec27d13f27d6ba7078a5f7982077798029364" alt="smile.gif" />
Não, não foi proposital isso aí, hehe, não conheço praticamente nada no Zend, mas legal saber que estou pensando um pouco semelhantemente aos desenvolvedores dele ^^
Realmente a primeira é mais simples de usar e entender, mas como eu disse no post inicial do tópico, acho estranho funções ou métodos em que o nome não dê ideia de ação. O where por exemplo: isso não é nome de ação... eu onde, tu ondes? kkk, por isso acho estranho. Nos vários sites por aí que leio sempre tem algum artigo falando das boas práticas de programação, e uma delas é que o nome de funções/métodos deem ideia de ação, aí fazendo dessa primeira maneira dá a impressão de que estou fazendo do jeito errado... Eu podia adicionar add no começo do nome de todos métodos, mas ia ficar repetitivo e feio, por isso bolei essa segunda forma de uso aí. Nela não teria a sensação de estar fazendo nada errado se não fosse o que sempre dizem de manter o código mais legível possível. Achei essa segunda forma mais confusa de entender, mas não sei se todo mundo acharia o mesmo, por isso criei o tópico. Se essa segunda forma aí não for tão ilegível assim, vou usar ela, já que vai ser realmente bem mais flexível, como você disse /applications/core/interface/imageproxy/imageproxy.php?img=http://forum.imasters.com.br/public/style_emoticons/default/smile.gif&key=15294d64c22e9e9c4ae0bf82a62ec27d13f27d6ba7078a5f7982077798029364" alt="smile.gif" />
Sobre os operadores: essa foi a forma que achei de adicionar o operador lá no código e ao mesmo tempo pegar o valor lá e adicionar num array que será em prepared statements... Acabei de imaginar uma forma melhor de fazer isso, sem precisar criar um método pra cada operador, usando esse esquema da segunda implementação aí, mas só vou fazê-la se essa segunda forma aí não for mesmo muito confusa de entender (que é o que quero saber agora).
Até mais;
Bom, para mim, legibilidade é um fator importante.
Como você bem falou, poderia criar métodos como addWhereClause, addOrderClause, etc., mas pense como isso ficaria:
$generator->addFromClause('tabela')->addWhereClause("bar = 'foo'")->addGroupClause('bla')->addOrderClause('bazzinga');
Realmente, para mim, ambas as implementações são válidas, vão apresentar o mesmo resultado. Se fosse para escolher, tendo em vista que eu não precisaria que esse gerador fosse útil para outras linguagens, além do SQL, eu preferiria a primeira, pois vai mais direto ao ponto.
Quanto ao seu problema de implementação, utilize sempre placeholders e deixe para associar os parâmetros no instante anterior a execução da query. Ex:
$generator->from('tabela')->where('id = ?', SQL_Generator::AND)->where('name = ?', SQL_Generator::OR);
// Gera: SELECT * FROM tabela WHERE id = ? OR name = ?
$driver->execute($generator->__toString(), array(421, 'Bazzinga'));>
Bom, para mim, legibilidade é um fator importante.
Como você bem falou, poderia criar métodos como addWhereClause, addOrderClause, etc., mas pense como isso ficaria:
$generator->addFromClause('tabela')->addWhereClause("bar = 'foo'")->addGroupClause('bla')->addOrderClause('bazzinga');
Realmente, para mim, ambas as implementações são válidas, vão apresentar o mesmo resultado. Se fosse para escolher, tendo em vista que eu não precisaria que esse gerador fosse útil para outras linguagens, além do SQL, eu preferiria a primeira, pois vai mais direto ao ponto.
Quanto ao seu problema de implementação, utilize sempre placeholders e deixe para associar os parâmetros no instante anterior a execução da query. Ex:
$generator->from('tabela')->where('id = ?', SQL_Generator::AND)->where('name = ?', SQL_Generator::OR);
// Gera: SELECT * FROM tabela WHERE id = ? OR name = ?
$driver->execute($generator->__toString(), array(421, 'Bazzinga'));
Olá. Eu já faço uso de placeholders. No SQL lá do primeiro post eu esqueci e coloquei os valores, mas o código gerado lá seria:
SELECT login, level FROM players WHERE level >= ? AND level <= ? OR vip = ? GROUP BY class
Um array dentro da classe que salva os valores estaria assim:
Array
(
[0] => 15
[1] => 60
[2] => 1
)
Na hora de usar faria assim:
$stmt = $driver->prepare($sql); //__toString()
$stmt->execute($sql->getValues()); //Obtém o array que citei
Então... acho que vou ficar com a primeira implementação lá devida a legibilidade. Só vou mudar a forma de uso dos operadores, que será +/- como a segunda implementação lá pra não ficar criando vários métodos desnecessariamente. Aí ficaria assim, por exemplo:
$generator->operator(SQL_Generator::OP_GTE, 'level', 15);
Mesmo que essa classe não vá ser muito útil na hora de usar, está sendo útil para eu entender mais de SQL, estou tendo que estudar bastante pra fazer ela bem completa com inclusive adaptação entre diferentes SGBD's /applications/core/interface/imageproxy/imageproxy.php?img=http://forum.imasters.com.br/public/style_emoticons/default/biggrin.gif&key=cb0fdb2382312b39ddcb15831fcae62157015f17d2417528782628663387e929" alt="biggrin.gif" />
Valeu aí, se tiver algo mais a acrescentar, melhor ainda /applications/core/interface/imageproxy/imageproxy.php?img=http://forum.imasters.com.br/public/style_emoticons/default/biggrin.gif&key=cb0fdb2382312b39ddcb15831fcae62157015f17d2417528782628663387e929" alt="biggrin.gif" />
Até mais.
Colega a algum tempo também passei por isso, então decidir criar uma classe utilizando PDO que me permitisse fazer varias ações no mysql de forma simples e sem ter que ficar toda hora criando select, segue o link onde postei a classe aqui no iMaster pode te ajudar a ter uma ideia para a sua, qualquer dúvida é só perguntar ;)/>
http://forum.imasters.com.br/topic/448961-completa-classe-crud-com-validacao-de-dados/page__p__1775048__fromsearch__1#entry1775048
Atualizei a página e cadastrou novamente a mensagem, ADMIN favor excluir este.