Ir para conteúdo

POWERED BY:

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

felini

[Resolvido] Criando Select Com Join

Recommended Posts

Estou migrando o sistema para dentro do ZEND e me deparei com a seguinte situação:

 

Tenho a seguinte query:

 

SELECT cat.nome nome_categoria, sub . *
FROM categorias cat
INNER JOIN subcategorias sub 
ON cat.id = sub.categoria_id
ORDER BY cat.nome

 

 

E ao passar pra dentro do framework, eu até achei simples, de acordo com a documentação:

http://framework.zend.com/manual/en/zend.db.select.html

 

No entanto pra criar esta query, eu preciso de fato criar o objeto Zend_Db_Select?

 

Lá eu tenho o seguinte exemplo:

 

$db = Zend_Db::factory( ...options... );
$select = $db->select();

 

 

Eu consigo criar esta query, sem ter de passar os dados através do factory()? Eles já estão configurados no application.ini.

 

 

Eu criei um protótipo, segue abaixo:

 

 

$rs = $this->getDbAdapter()->select()
                                ->from(array('cat' => 'categorias'),
                                       array('nome'))
                                ->join(array('sub' => 'subcategorias'),
                                       array('cat.id = sub.categoria_id'));

 

Valeu pela ajuda.

 

Abraço,

 

 

 

 

Compartilhar este post


Link para o post
Compartilhar em outros sites

Não fiz o mapeamento! Tu acha melhor fazê-lo?

 

Meu 'application.ini' está da seguinte forma:

 

[production]
phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0
includePaths.library = APPLICATION_PATH "/../library"
bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
bootstrap.class = "Bootstrap"
appnamespace = "Application"
resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
resources.frontController.params.displayExceptions = 0

; Banco de Dados
resources.db.adapter = "PDO_MYSQL"
resources.db.params.host = "localhost"
resources.db.params.dbname = "store"
resources.db.params.username = "root"
resources.db.params.password = ""

 

 

Meu factory está da seguinte forma:

 

 

$db = Zend_Db::factory('Pdo_Mysql', array(
           'host'     => 'localhost',
           'username' => 'root',
           'password' => '',
           'dbname'   => 'store'
       ));

 

 

No entanto não queria utilizar o factory. Queria saber como fazer a consulta SQL sem ter que 'conectar' no banco e ao invés disso, utilizar as configs do application.ini

 

Valeu!

Compartilhar este post


Link para o post
Compartilhar em outros sites

O mapeamento é interessante, mas não é obrigatório. Vai depender da sua aplicação.

 

Ao fazer como você descreve no application.ini, não é necessário utilizar o Factory. Você pode utilizar getDefaultAdapter(); Algo assim:

 

$db = Zend_Db_Table::getDefaultAdapter ();
$select = $db->select ();

 

Isto considerando que você não esteja estendendo a classe Zend_Db_Table_Abstract. Caso esteja, não é necessário fazer nada disto. Só utilizar $this->select().

 

Carlos Eduardo

Compartilhar este post


Link para o post
Compartilhar em outros sites

Minha classe Application_Model_DbTable_SubCategorias esta estendendo da Zend_Db_Table_Abstract,

Então, na Mapper, eu faço o seguinte:

 

public function fetchAll(){
      $select = $this->getDbTable()->select();
       $select->from(array('cat' => 'categorias'),array('nome'));
       $select->join(array('sub' => 'subcategorias'),array('cat.id = sub.categoria_id'));

       $resultado = $this->fetchAll($select);
       return $resultado;

  }

 

Quando vou na view e mando printar o fetchAll, me aparece o seguinte resultado:

Fatal error: Maximum function nesting level of '100' reached, aborting! in C:\wamp\library\Zend\Db\Table\Abstract.php on line 889

errozendframework.png

Compartilhar este post


Link para o post
Compartilhar em outros sites

 

Mapper


<?php
/**
* Mapeamento da tabela SUBCATEGORIAS
* Funções para inclusao, exclusao e edicao
*
* @author Matheus
* @version 1.0
*/
class Application_Model_SubCategoriasMapper  {

   protected $_dbTable;

   public function setDbTable($dbTable) {
       // Verifica se o parâmetro é mesmo uma string
       if (is_string($dbTable)) {
           $dbTable = new $dbTable;
       }
       // Testa se o objeto é uma instancia de uma classe especifica
       if (!$dbTable instanceof Zend_Db_Table_Abstract) {
           // lanca excessao
           throw new Exception("Gateway Inválido");
       }

       // se passar nos dois testes, aceita a atribuicao
       $this->_dbTable = $dbTable;
       // retorna o objeto
       return $this;
   }

   public function getDbTable() {
       // testa pra saber se a instancia criada pelo setDbTable é nula
       if (NULL === $this->_dbTable) {
           $this->setDbTable("Application_Model_DbTable_SubCategorias");
       }
       return $this->_dbTable;
   }

   public function fetchAll(){

       $select = $this->getDbTable()->select();
       $select->from(array('cat' => 'categorias'),array('nome'));
       $select->join(array('sub' => 'subcategorias'),array('cat.id = sub.categoria_id'));

       $resultado = $this->fetchAll($select);

       var_dump($select);

       /*
       $results = array();
       foreach ($resultado AS $row){
           $entry = new Application_Model_SubCategorias();
           $entry->setId($row->id);
           $entry->setNomeCategoria($row->nome_categoria);
           $entry->setNome($row->nome);
           $results[] = $entry;
       }
       */
       return $resultado;

   }

   /**
    * Método para cadastrar subcategorias
    *
    * @param array $dados
    */
   public function cadastrar($dados){
       $this->getDbTable()->insert($dados);
   }

   /**
    * Método que exclui a subcategoria que é passada pelo IDs
    *
    * @param int $id
    */
   public function excluir($id){
       $table = $this->getDbTable();
       $where = $table->getAdapter()->quoteInto('id = ?',$id);
       $table->delete($where);
   }


}
?>

 

DbTable

 

<?php
class Application_Model_DbTable_SubCategorias extends Zend_Db_Table_Abstract {
   protected $_name = "subcategorias";
}
?>

 

Compartilhar este post


Link para o post
Compartilhar em outros sites

Uhn... Acho que aqui tem coisa errada...

 

$resultado = $this->fetchAll($select);

Quando você faz $this->fetchAll(), está chamando o próprio método (recursividade). Isto é interessante, mas acredito que no seu caso você queria pegar o método fetchAll() da classe Application_Model_DbTable_SubCategorias. Então, seria:

$resultado = $this->getDbTable()->fetchAll($select).

 

--------------------------------

 

Além disto, veja que você utiliza no seu application.ini o seguinte:

 

appnamespace = "Application"

Então, não há necessidade de utilizar Application_* no nome das classes.

 

Outra sugestão que eu faço, já que você está fazendo com Mapper, é utilizar uma classe Pai (AbstractMapper) que vai abstrair os métodos getDbTable e setDbTable, já que eles serão exatamente iguais em qualquer Mapper que você fizer, sendo diferente somente o nome da classe que será instanciada. Para isto, eu passaria o nome em uma propriedade $_dbTableName, definida na classe filha.

 

Carlos Eduardo

Compartilhar este post


Link para o post
Compartilhar em outros sites

Fala ae Carlos, cara muito obrigado pelas dicas e ajuda que está me dando! Estou muito grato mesmo.

 

Experimentei fazer da forma como tu falou, no entanto não sei o que acontece de errado.

 

Primeiramente, deixei o método fetchAll() da seguinte forma:

 

 

       $select = $this->getDbTable()->select()
               ->from(array('cat' => 'categorias'),array('nome'))
               ->joinInner(array('sub' => 'subcategorias'),array('cat.id = sub.categoria_id'));

       $resultado = $this->getDbTable()->fetchAll($select);

       return $resultado;

 

 

Desta forma, retorna a seguinte msg:

Exception information:

Message: Select query cannot join with another table

 

 

Se eu tirar o $this->getDbTable() da var $select e deixar apenas $this->select() retorna o erro:

Fatal error: Call to undefined method Application_Model_SubCategoriasMapper::select() in C:\wamp\www\loja\application\models\SubCategoriasMapper.php on line 40

 

Ou seja, ele não acha o método select() dentro de Model_SubCategoriasMapper.

 

Então, resolvi fazer da seguinte forma:

 

 

       $db = $this->getDbTable()->getDefaultAdapter();
       $select = $db->select()
               ->from(array('cat' => 'categorias'),array('nome'))
               ->join(array('sub' => 'subcategorias'),array('cat.id = sub.categoria_id'));

       $resultado = $this->getDbTable()->fetchAll($select);
       return $resultado;

 

 

Mas isso me retorna um erro de SQL:

Message: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1

Compartilhar este post


Link para o post
Compartilhar em outros sites
Fala ae Carlos, cara muito obrigado pelas dicas e ajuda que está me dando! Estou muito grato mesmo.

:joia:

 

Sobre o seu problema, o primeiro código é o mais correto, mas o Zend Framework tem um bug (não vou achar agora o bug tracing, mas depois você procura). Para que queries com join funcionem, você deve fazer assim:

 

$select = $this->getDbTable()->select()->setIntegrityCheck(false)
               ->from(array('cat' => 'categorias'),array('nome'))
               ->joinInner(array('sub' => 'subcategorias'),array('cat.id = sub.categoria_id'));

       $resultado = $this->getDbTable()->fetchAll($select);

       return $resultado;

 

Veja se assim funciona.

 

Carlos Eduardo

Compartilhar este post


Link para o post
Compartilhar em outros sites

E ae Carlos,

 

Na verdade não funcionou, mas era um erro de sintaxe. Vou colocar aqui pra alertar o pessoal:

 

 

$select = $this->getDbTable()->select()->setIntegrityCheck(false)
	->from(array('cat' => 'categorias'),array('nome'))
	->joinInner(array('sub' => 'subcategorias'),array('cat.id = sub.categoria_id'));

$resultado = $this->getDbTable()->fetchAll($select);

return $resultado;

 

 

O correto é não ter o ultimo array() - array('cat.id = sub.categoria_id'), deve ficar apenas desta forma:

$select = $this->getDbTable()->select()->setIntegrityCheck(false)
	->from(array('cat' => 'categorias'),array('nome'))
	->joinInner(array('sub' => 'subcategorias'), 'cat.id = sub.categoria_id');

$resultado = $this->getDbTable()->fetchAll($select);

return $resultado;

 

Dai funcionou.

 

Estava tentando recuperar o NOME da categoria associada à subcategoria, então meu select ficou desta forma:

 

 

$select = $this->getDbTable()->select()
                  	->from(array('cat' => 'categorias'))
                       ->join(array('sub' => 'subcategorias'),
                          	'sub.categoria_id = cat.id',
                          	array ('categoria_nome' => 'cat.nome',
                              	'categoria_id' => 'cat.id',
                              	'subcategoria_nome' => 'sub.nome',
                              	'subcategoria_id' => 'sub.id'))
                       ->setIntegrityCheck(false);
       $resultado = $this->getDbTable()->fetchAll($select);

 

 

Porém, ele me retorna este resultado:

array
 0 => 
array
  'id' => string '7' (length=1)
  'nome' => string 'Bijuteria' (length=9)
  'categoria_nome' => string 'Bijuteria' (length=9)
  'categoria_id' => string '7' (length=1)
  'subcategoria_nome' => string 'Anel' (length=4)
  'subcategoria_id' => string '4' (length=1)

 

 

Se reparar, a posição id e nome são a mesma de categoria_nome e categoria_id. Tu sabe porque isso ocorre? Isso é detalhe, mas é curiosidade.Fiz desta forma de acordo com a documentação http://framework.zen....db.select.html , se tiver uma dica, ela é muito bem vinda.

Mais uma vez, muito obrigado pela força.

Abraço,

Compartilhar este post


Link para o post
Compartilhar em outros sites

Então... O objeto Select tem um método __toString(), que é chamado ao se tratar o objeto como uma string. Este método imprime a query como ela está no momento. Faça um teste:

 

$select = $this->getDbTable()->select()
                       ->from(array('cat' => 'categorias'))
                       ->join(array('sub' => 'subcategorias'),
                               'sub.categoria_id = cat.id',
                               array ('categoria_nome' => 'cat.nome',
                               'categoria_id' => 'cat.id',
                               'subcategoria_nome' => 'sub.nome',
                               'subcategoria_id' => 'sub.id'))
                       ->setIntegrityCheck(false);
       echo $select;
       exit;
       $resultado = $this->getDbTable()->fetchAll($select);

 

Isto é muito útil quando estamos fazendo debug e para analisar as querys enviadas, buscando melhorar a performance.

 

No seu caso, isto ocorre porque você não define quais campos quer buscar da tabela no from, então ele busca *. Caso não queira nenhum campo, coloque array().

 

Carlos Eduardo

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.