programação,

SQL queries com Zend_Db_Select

Diogo Matheus Diogo Matheus Seguir 30/05/2011 · 11 minutos de leitura
SQL queries com Zend_Db_Select
Compartilhar

Neste artigo iremos introduzir o uso da classe Zend_Db_Select, que é utilizada para abstrair a criação de select query. A classe oferece métodos adicionais que permitem compor o comando select por partes, deixando que a classe fique responsável por montar a query corretamente, após terminar a construção, basta trabalhar como se fosse uma string.

echo $db->select()
        ->from('product');
 
// resultado: select 'product'.* from 'product'

Vantagens de usar Zend_Db_Select

  • Métodos orientados a objeto para construir consultas pedaço por pedaço
  • Abstração do banco de dados independente de algumas partes da consulta
  • Quoting automático, reduzindo o risco de ataques por SQL injection

Criando uma instância da classe Zend_Db_Select

Para começar a construir seu comando select é preciso ter seu banco de dados configurado, confira abaixo algumas alternativas para criar uma instância da classe Zend_Db_Select.

// criando objeto da classe Zend_Db_Select
$db = Zend_Db::factory( ...options... );
$select = $db->select();
 
// Instância direta da classe Zend_Db_Table
$db = Zend_Db::factory( ...options... );
$select = new Zend_Db_Select($db);
 
// Usando método estático da classe Zend_Db_Table
$db = Zend_Db_Table::getDefaultAdapter();
$select = $db->select();
 
// Zend_Db_Select na classe Zend_Db_Table
public function metodo() {
    $select = $this->select();
}

Principais métodos da classe Zend_Db_Select

select() – Método utilizado para inicializar a construção do comando select.

from([array] $table, array $columns) – Método utilizado para informar a tabela no qual o select será realizado, passando o nome da tabela e caso seja necessário os campos de retorno, você pode usar alias(apelido, para renomear o campo) tanto para o nome da tabela quanto para os campos de retorno usando array(chave=>valor), onde a chave será o alias e o valor a tabela/campo.

// resgata todos os produtos, retornando o campo name
$select = $db->select()
             ->from(array('p'=>'product'), array('name'));

columns(array $columns, $table) – Método utilizado para adicionar campos de retorno, caso você não queira especificar ou não tenha especificado seus campos de retorno no método from.

// resgata todos os produtos, retornando os campos id, name e value
$select = $db->select()
             ->from(array('p'=>'product'), array('id'=>'product_id', 'name'));
$select->columns(array('value'), 'p');

where($condition) – Método utilizado para adicionar condições ao comando select, caso você use mais de uma vez na mesma query a classe irá adicionar os seguintes usando o operador AND.

// resgata todos os produtos com valor maior que R$50,00
$select = $db->select()
             ->from('product')
             ->where('value > ?', 50.00);

orWhere($condition) – Parecido com o método where, mas nesse método o operador utilizado será OR.

// resgata todos os produtos
// com valor menor que R$20,00 ou maior que R$50,00
$select = $db->select()
             ->from('product')
             ->where('value < ?', 20.00)
             ->orWhere('value > ?', 50,00);

order($order) – Método utilizado para especificar um tipo de ordenação para os resultados, onde deve ser informado o campo e o tipo de ordenação.

// resgata todos os produtos
// ordenados pelo campo name em ordem decrescente
$select = $db->select()
             ->from('product')
             ->order('name desc');

Para esse artigo, os métodos apresentados acima são suficientes, no próximo artigo no qual iremos falar sobre o uso de join no zend framework, veremos outros métodos da classe Zend_Db_Select.

Estrutura para criar um select simples

// inicializa a criação do comando select
$select = $db->select();
 
// especifica a tabela e as colunas que deseja de retorno
$select->from('product', array('product_id', 'name'));
 
// adiciona uma condição
$price = 50.00;
$select->where('value > ?', $price);
 
// especifica um tipo de ordenação para os resultados
$select->order('product_id desc');

Projeto Usando Zend_Db_Select

Agora que vimos um pouco sobre a classe Zend_Db_Select e suas vantagens, vamos criar um projeto para trabalhar com métodos usando Zend_Db_Select, baseado na estrutura apresentada no tópico Preparando o ambiente para desenvolvimento com Zend Framework, crie um projeto com nome de example-select.

Estrutura do projeto

No exemplo que será visto agora, iremos utilizar o banco apresentado no artigo Mapeando relacionamentos nos modelos, para criar nossos métodos usando Zend_Db_Select, confira o diagrama do nosso banco de dados:

Modelo de entidade relacionamento

Visualize ou efetue o download do script sql, no script além dos comandos de criação das tabelas, contém comandos para inserir valores nas tabelas para que o exemplo no final do artigo funcione corretamente.

Acesse o phpmyadmin, crie o banco “zf-order” e execute o script sql acima para criar e preencher as tabelas do banco. Após criar o banco edite o arquivo application.ini com as informações do banco de dados, caso tenha dúvida, visualize o artigo Entendendo modelos no zend framework.

Criando modelos e métodos usando Zend_Db_Select

Com o banco devidamente criado, crie os arquivos das abas abaixo na pasta “application/models”, para configurar nossos modelos e criar métodos usando Zend_Db_Select.

No modelo User, além das configurações padrões e de mapeamento, criamos dois métodos, o método findByPartialName($name), no qual criamos uma consulta personalizada para selecionar os usuários pelo nome e o método findByEmail($email), no qual criamos uma consulta para selecionar um usuário através do seu email de cadastro.

<?php
class User extends Zend_Db_Table_Abstract {
  /**
  * The default table name
  */
  protected $_name = 'user';

  /**
  * Dependent tables
  */
  protected $_dependentTables = array('Product', 'Order');

  /**
  * findByPartialName
  *
  * @param string $name
  */
  public function findByPartialName($name) {
    $select = $this->select()
                  ->from($this->_name)
                  ->where('name like ?', "%{$name}%")
                  ->order('name ASC');

    return $this->fetchAll($select);
  }

  /**
  * findByEmail
  *
  * @param string $email
  */
  public function findByEmail($email) {
    $select = $this->select()
                    ->from($this->_name)
                    ->where('email = ?', $email);

    return $this->fetchRow($select);
  }
}
?>

No modelo Product, além das configurações padrões e do mapeamento, criamos dois métodos, o primeiro findByPriceRange($minimumPrice, $maximumPrice), utilizamos uma consulta personalizada para selecionar os produtos entre dois valores, ambos passados por parâmetro, no segundo método, getLatest($limit), criamos uma consulta personalizada para selecionar os últimos produtos adicionados, ordenando pelo id em decrescente e limitando o numero de resultado, o limite é passado por parametro.

<?php
class Product extends Zend_Db_Table_Abstract {
  /**
  * The default table name
  */
  protected $_name = 'product';

  /**
  * Dependent tables
  */
  protected $_dependentTables = array('OrderItem');

  /**
  * Reference map
  */
  protected $_referenceMap = array(
    array(
      'refTableClass' => 'User',
      'refColumns' => 'user_id',
      'columns' => 'user_id',
    )
  );

  /**
  * findByPriceRange
  *
  * @param float $minimumPrice
  * @param float $maximumPrice
  */
  public function findByPriceRange($minimumPrice, $maximumPrice) {
    $select = $this->select()
                    ->from($this->_name)
                    ->where('value > ?', $minimumPrice)
                    ->where('value < ?', $maximumPrice)
                    ->order('value ASC');

    return $this->fetchAll($select);
  }

  /**
  * getLatest
  *
  * @param int $limit
  */
  public function getLatest($limit) {
    $select = $this->select()
                    ->from($this->_name)
                    ->order('product_id DESC')
                    ->limit($limit);

    return $this->fetchAll($select);
  }
}
?>

No modelo Order, realizamos a configuração e o mapeamento do modelo, apenas para representar o diagrama apresentado, pois não iremos utilizar no exemplo.

<?php
class Order extends Zend_Db_Table_Abstract {
  /**
  * The default table name
  */
  protected $_name = 'order';

  /**
  * Dependent tables
  */
  protected $_dependentTables = array('OrderItem');

  /**
  * Reference map
  */
  protected $_referenceMap = array(
    array(
      'refTableClass' => 'User',
      'refColumns' => 'user_id',
      'columns' => 'user_id',
    )
  );
}
?>

No modelo OrderItem, realizamos a configuração e o mapeamento do modelo, apenas para representar o diagrama apresentado, pois não iremos utilizar no exemplo.

<?php
class OrderItem extends Zend_Db_Table_Abstract {
  /**
  * The default table name
  */
  protected $_name = 'order_item';

  /**
  * Reference map
  */
  protected $_referenceMap = array(
    array(
      'refTableClass' => 'Order',
      'refColumns' => 'order_id',
      'columns' => 'order_id',
    ),
    array(
      'refTableClass' => 'Product',
      'refColumns' => 'product_id',
      'columns' => 'product_id',
    )
  );
}
?>

Trabalhando com Zend_Db_Select

Com os nossos modelos criados e nossos métodos usando Zend_Db_Select prontos, vamos trabalhar com esses métodos, para isso vamos utilizar o IndexController.php e sua view, index.phtml.

IndexController.php

<?php
class IndexController extends Zend_Controller_Action {
  public function indexAction() {
    // modelos
    $user = new User();
    $product = new Product();

    // restaga os 3 últimos produtos cadastrados
    $latestProducts = $product->getLatest(3);
    $this->view->assign('latestProducts', $latestProducts);

    // restaga os produtos de R$20,00 até R$50,00
    $productsByPrice = $product->findByPriceRange(20.00, 50.00);
    $this->view->assign('productsByPrice', $productsByPrice);

    // resgata usuários que contenha 'Diogo' no nome
    $usersByName = $user->findByPartialName('Diogo');
    $this->view->assign('usersByName', $usersByName);

    // resgata um usuário pelo email
    $userByEmail = $user->findByEmail('thiago@gmail.com');
    $this->view->assign('userByEmail', $userByEmail);
  }
}
?>

index.phtml

<h3>Últimos 3 produtos adicionados</h3>
<?php foreach($this->latestProducts as $product): ?>
<p><?php echo $product->name; ?></p>
<?php endforeach; ?>
 
<h3>Produtos com valor maior que R$20,00 e menor que R$50,00</h3>
<?php foreach($this->productsByPrice as $product): ?>
<p><?php echo $product->name; ?></p>
<?php endforeach; ?>
 
<h3>Procurar usuários pelo nome</h3>
<?php foreach($this->usersByName as $user): ?>
<p><?php echo $user->name; ?></p>
<?php endforeach; ?>
 
<h3>Procurar usuário pelo email</h3>
<p><?php echo $this->userByEmail->name; ?></p>

Estrutura final do nosso projeto:

Estrutura final do projeto

Resultado

Ao executar nossa aplicação iremos obter o seguinte resultado:

Resultado da execução

Confira o código-fonte do exemplo no GitHub.