Usamos cookies para medir audiência e melhorar sua experiência. Você pode aceitar ou recusar a qualquer momento. Veja sobre o iMasters.
Olá. Baseando-me um pouco no CodeIgniter, estou fazendo uma classe para formar query's e executá-las, só que um pouco diferente, de um jeito que achei melhor :)
Então... minha classe vai ter um método chamado query, esse método é quem vai executar o sql, e o único parâmetro dele é um encadeamento de métodos (que de alguma forma tem que retornar um código SQL), ex:
$manager->query($manager->select("table", "column1,column2")->where("id", "=", "5"))->fetch();
Parte da classe:
class manager {
/**
* Armazena o código SQL atual
* @var string
*/
private $sql;
/**
* Obtém o SQL atual
* @return string
*/
public function getSql() {
return $this->sql;
}
/**
* Insere um SELECT no SQL atual
* @param string $table Tabela a usar
* @param string $columns Colunas a selecionar
* @return mixed
*/
public function select($table, $columns) {
$this->sql = "SELECT ".$columns." FROM ".$table;
return $this;
}
/**
* Executa o código SQL atual
* @param string SQL a executar
* @return bool
*/
public function query($sql) {
return $pdo_instance->query($sql);
}
}
Bom, como todo encadeamento, no final eles retornam a instância (antes modificam o SQL atual, claro).
Imagino que se eu fizesse isso, funcionaria:
$manager->query($manager->select("table", "column1,column2")->where("id", "=", "5")->getSql())->fetch();
Porém quero que não precise usar nenhum método para obter o código SQL. Seria possível? Não quero ter que adicionar o método query() no final do encadeamento e apenas usar a propriedade $sql no query do PDO, fica meio sem sentido e feio e o que planejo fazer não funcionaria assim...
Alguém se dispõe a ajudar? :P
Obrigado por responder :)
Então... no meu caso, eu vou ter que fazer igual no último código que mostrei, usando o método getSql() para obter o SQL atual ($sql) para o query()?
Ah, uma coisa, eu preciso usar o $manager-> dentro do método query, assim:
$manager->query($manager->select("table", "column1,column2")->where("id", "=", "5")->getSql())->fetch();
?
ou o certo é
$manager->query(select("table", "column1,column2")->where("id", "=", "5")->getSql())->fetch();
?
De qualquer forma, vou fazer testes pra ver qual o jeito certo, mas se alguém responder evitará um trabalhão danado que tenho que fazer aqui :)
Ah, pra evitar confusão, ou sei lá o que: $manager é a instância da classe manager...
>
Obrigado por responder :)
Então... no meu caso, eu vou ter que fazer igual no último código que mostrei, usando o método getSql() para obter o SQL atual ($sql) para o query()?
Implementar um __toString pode ajudar a dar cabo do getSql.
Sugiro que estude sobre a implementação de Fluent Interface. Se você já usou jQuery, já usou uma Fluent Interface.
>
Ah, uma coisa, eu preciso usar o $manager-> dentro do método query, assim:
$manager->query($manager->select("table", "column1,column2")->where("id", "=", "5")->getSql())->fetch();
?
ou o certo é
$manager->query(select("table", "column1,column2")->where("id", "=", "5")->getSql())->fetch();
?
De qualquer forma, vou fazer testes pra ver qual o jeito certo, mas se alguém responder evitará um trabalhão danado que tenho que fazer aqui :)
Ah, pra evitar confusão, ou sei lá o que: $manager é a instância da classe manager...
Deṕende. Fazer
select()
implica na declaração de uma função chamada select. A forma como select vai encontrar um manager é variável. Desde que ela retorne uma interface que seja possível chamar where(), é viável.Já que você falou em CI (codeigniter) em questão, verá que ele possui a classe Active Record. O que faz isso que você está tentando fazer.
Então... no meu caso, eu vou ter que fazer igual no último código que mostrei, usando o método getSql() para obter o SQL atual ($sql) para o query()?
Sim, precisará. De outra forma, estaria confundindo as funcionalidades de cada método.
Ah, uma coisa, eu preciso usar o $manager-> dentro do método query, assim:
Sim, pois os métodos encadeados são utilizados na referência de outro método de um objeto. Dentro de:
$manager->query()
Não existe nenhum método e muito menos objeto. Assim que você incluir ele ao menos uma vez:
$manager->query($manager->...)
Poderá encadear outros métodos.
>
Implementar um __toString pode ajudar a dar cabo do getSql.
@Evandro Oliveira, bem lembrado. Mas convém salientar que o método __toString() deve ser usado só, e somente só, quando o retorno irá ser uma string. O nome, do qual, já deixa bem explícito.
FluentInterface: Não sabia que era esse o nome. Só sabia sua implementação.
Obrigado por responderem :D
@Gabriel Heming: É exatamente nessa classe (Active Record) que estou baseando a minha, porém com algumas diferenças pra adaptar ao meu sistema, além de deixar a forma de uso mais "coerente".
Ah, obrigado pela resposta sobre o $manager-> :)
@Evandro Oliveira: Não entendi o que esse __toString tem de diferente... pelo que vi no exemplo do php.net, é um método qualquer, que retorna uma string qualquer, assim como o método getSql da minha classe.
Fluent Interface é apenas retornar $this a cada método? Se for, como pode ver no meu código lá do primeiro post, já estou fazendo isso em todos métodos onde é necessário (obs: alí no código não contém todos métodos, é apenas uma parte da classe).
Até mais.
Na verdade, é muito mais que um método qualquer. Esse método é chamado quando um objeto é tratado como string. Normalmente, define-se "impressão", mas não é somente isso.
Um exemplo bem básico:
Classe Pessoa:
class Pessoa {
private $nome;
private $sobrenome;
public function __construct($nome , $sobrenome) {
$this->nome = $nome;
$this->sobrenome = $sobrenome;
}
public function __toString() {
return 'meu nome é '.$this->nome.' '.$this->sobrenome;
}
}
Teste:
$pessoa = new Pessoa('Gabriel' , 'Heming');
echo $pessoa;
Saída:
meu nome é Gabriel Heming
Veja que eu não chamei nenhum método, somente imprimi um objeto.
As vezes os objetos de uma classe precisam de um tratamento similar que envolvem muitos métodos. E esse tratamento deverá ser na forma de uma string.
Com o método __toString(), você fica livre em deixar a classe cuidar do comportamento do objeto. Mas como eu salientei lá em cima, o retorno precisa ser uma string. Isso está especificado no manual do PHP, como também no de outras linguagens de programação (Java por exemplo).
Ah, interessante -
Então, basta eu adicionar isso na minha classe, né?:
public function __toString() {
return $this->sql;
}
Assim, quanto terminar o encadeamento já vai ser retornada a string contida na propriedade $sql?
$manager->query($manager->select("table", "column1,column2")->where("id", "=", "5"))->fetch();
Supondo que quando o encadeamento terminar, $sql tenha o valor "SELECT * FROM teste", seria executado algo mais ou menos assim?
$manager->query("SELECT * FROM teste")->fetch();
Se for isso mesmo, problema resolvido :D
Ah, não tem nenhuma forma de não precisar inserir o $manager-> dentro do método não? PHP sempre tem jeito pra tudo, hehe.
Sim, essa é a teoria. Teste e nos de o seu retorno.
Entretanto, acredito que os métodos (select/from/where) não podem possuir retornos. Não tenho certeza agora. Mas de qualquer modo, você poderia fazer o seguinte:
$manager->select("table", "column1,column2")->where("id", "=", "5");
$manager->query($manager)->fetch();
O resultado, assim, tenho certeza de seu funcionamento.
Segundo meus testes, funciona perfeitamente -
Obrigado aí :D
Acho que você está confundindo as coisas. O encadeamento não é uma funcionalidade diferente ou nova. Ele é apenas uma forma resumida de escreve isso:
Todos os métodos acima possuem retorno, todos serão executados. Entretanto, no final do processo, somente o retorno do metodoQuatro() é que estará na variável $variavel. Pois a cada execução de método, o seu retorno irá para a variável. E como o método metodoQuatro() é o ultimo a ser executada, por lógica, ele sobrescreverá todos os outros métodos.
Métodos encadeados são bons para utilizar em "seteres" (set/add), pois normalmente não possuem retorno.
Se você quer encadear métodos e possuir um único retorno, vai precisar de um método de retorno.