Relacionamento de tabelas no Zend Framework utilizando o Zend_Db_Table

Estou utilizando o Zend na sua versão mais recente, a 1.10.5, e o objetivo desse post é mostrar como relacionar tabelas com Zend_Db_Table e a utilidade do Zend_Db_Table_Row.

Apesar de não ser o objetivo do post, vou utilizar também o Zend_Loader para facilitar o carregamento das classes.

A estrutura de pastas será a seguinte:

| PastaRoot
  |-- Model
  |-- lib
     |-- Zend

Na pasta Model iremos colocar as classes referentes as tabelas do banco e na pasta lib/Zend ficará o Framework em si.

Como não é o objetivo do post, não irei implementar a estrutura de MVC do Zend, apenas o Zend_Db. Essa é uma das vantagens do Zend, a possibilidade de usar apenas uma parte do Framework sem depender das restantes.

Antes de tudo você deve criar um banco no seu MySQL, será o banco que utilizaremos no exemplo. Ele deve ter uma tabela “site” e uma tabela “pagina”.

Crie um arquivo no root do exemplo como o nome de index.php, será toda a nossa aplicação. Vamos começar incluindo a pasta de biblioteca e Model no include_path:

/**
 * Inclui a pasta lib e Model no include path
 */
define('ROOT_DIR', dirname(__FILE__));
set_include_path(
	get_include_path() . PATH_SEPARATOR .
    ROOT_DIR . '/lib/' . PATH_SEPARATOR .
    ROOT_DIR . '/Model/'
);

Logo depois iremos utilizar o Zend_Loader para não termos de chamar as classes separadamente:

/**
 * Inclui e instancia o Autoloader
 */
include('Zend/Loader/Autoloader.php');
$autoloader = Zend_Loader_Autoloader::getInstance();
$autoloader->setFallbackAutoloader(true);

Agora iremos realizar a conexão com o banco e registrarmos esse adaptador como default:

/**
 * Conecta ao banco e registra o adaptador
 */
$db = Zend_Db::factory('Pdo_Mysql', array(
    'host'     => 'localhost',
    'username' => 'root',
    'password' => '',
    'dbname'   => 'ZendDb'
));

Zend_Db_Table_Abstract::setDefaultAdapter($db);

Perfeito! Nesse momento temos a aplicação incluindo as pastas necessárias no include_path, instanciando o Autoloader e fazendo a conexão com o banco.

Agora vamos criar as classes de cada tabela na pasta Model. Vamos começar com a tabela “site”, para isso crie um arquivo Sites.php na pasta Model com o conteúdo:

class Sites extends Zend_Db_Table{
    /**
     * Define o nome da tabela
     */
    protected $_name = 'site';

    /**
     * Define a primary key
     */
    protected $_primary = 'id';

    /**
     * Define a classe que irá
     * lidar com cada linha
     */
    protected $_rowClass = 'Site';
}

No atributo $_name definimos o nome da tabela que a classe irá cuidar, no atributo $_primary definimos a primary key dessa tabela e no atributo $_rowClass definimos o nome da classe que irá cuidar de cada registro dessa tabela como objeto, a tabela “rowClass” é especialmente útil pois poderemos cuidar de cada registro separadamente, ou seja, se quisermos mostrar o nome do site já formatado não precisamos tratar esse atributo, apenas chamamos um método que fará essa formatação, e agora iremos criar essa classe.

Crie um arquivo com o nome Site.php também na pasta Model com o seguinte conteúdo:

class Site extends Zend_Db_Table_Row {
    /**
     * Formata o nome do site
     */
    public function nomeFormatado(){
        return "<b>" . $this->nome . "</b>";
    }
}

Agora todas as vezes que você estiver lidando com uma linha da tabela “site” e quiser mostrar o nome formatado, basta chamar o método nomeFormatado().

Vamos então criar a classe que cuidará da tabela “pagina”, para isso crie um arquivo com o nome de Paginas.php na pasta Model:

class Paginas extends Zend_Db_Table{
    /**
     * Define o nome da tabela
     */
    protected $_name = 'pagina';

    /**
     * Define a primary key
     */
    protected $_primary = 'id';

    /**
     * Define a classe que irá
     * lidar com cada linha
     */
    protected $_rowClass = 'Pagina';

    /**
     * Cria o relacionamento entre a
     * tabela "pagina" e a tabela "site"
     */
    protected $_referenceMap    = array(
        'SitePagina' => array(
            'columns'           => 'id_site',
            'refTableClass'     => 'Sites',
            'refColumns'        => 'id'
        ),
    );
}

Ela segue o mesmo padrão da classe da tabela “site”, com a diferença do atributo $_referenceMap, que será o responsável por criar o relacionamento entre as tabelas.

Esse atributo é um array com outro array dentro dele, onde o nome da posição do primeiro array é apenas um nome criado por nós que nomeará esse relacionamento, esse nome pode ser o que você quiser e nesse exemplo não influenciará em nada, dei o nome de “SitePagina”.

Dentro do array que ficará na posição “SitePagina” temos outras três posições:

  • columns: Especifica qual a coluna que fará referência com a outra tabela, nesse caso, será a coluna “id_site” da tabela “pagina” que fará referência ao “id” da tabela “site”;

  • refTableClass: Qual a classe responsável pela tabela de referência, nesse caso será a classe “Sites”;

  • refColumns: Qual a coluna na tabela de referência que deverá ser relacionada com essa tabela;

E agora como fizemos na tabela “site” vamos criar uma classe para a tabela “pagina” que cuidará de cada registro dela. Para isso crie um arquivo Pagina.php dentro da pasta Model:

class Pagina extends Zend_Db_Table_Row {
    /**
     * Formata o nome da página
     */
    public function nomeFormatado(){
        return "- " . $this->nome . "";
    }
}

Ela terá a mesma função da classe da tabela “site”, apenas formatará o nome quando chamarmos o método nomeFormatado().

Nesse momento já criamos todas as classes que cuidarão das tabelas do banco e farão seu relacionamento. Vamos continuar nosso arquivo index.php:

/**
 * Instancia a classe que lidará com a
 * tabela 'site'
 */
$tableSite = new Sites();

/**
 * Seleciona todas as linhas da tabela
 * ordenando por nome
 */
$siteRowSet = $tableSite->fetchAll(
	$tableSite->select()
    ->order('nome')
);

Agora instanciamos a classe que cuidará da tabela “site” e pedimos a ele um rowset com todos os registros ordenados por nome, e seguimos em frente:

/**
 * Passa linha por linha da lista de
 * registros da tabela 'site'
 */
foreach($siteRowSet as $rowSite){

Com a rowset em mãos, que não passa de um array com todos os objetos referentes a cada registro da tabela, iremos percorrê-lo:

   /**
    * Chama um método que devolve o nome formatado.
    * Esse já é um objeto da classe Site
    * ou seja, uma classe Zend_Db_Table_Row
    */
   echo $rowSite->nomeFormatado();

Como estamos percorrendo um rowset da tabela “site”, cada posição desse array é um objeto referente ao registro da tabela, e como definimos uma classe para cuidar disso, estamos lidando com um objeto dessa classe, ou seja, o método que formata o nome pode ser chamado, é o que fizemos.

Prosseguindo:

   /**
    * Chamamos um método do objeto que irá
    * retornar uma lista de objetos relacionados
    * da tabela páginas
    */
   $paginaRowSet = $rowSite->findDependentRowset('Paginas');

Agora chamamos o método findDependentRowset() do objeto da tabela “site” e esse método irá retornar todos os registros da tabela “pagina” que fazem referência a esse registro da tabela “site”. Ele retorna também um rowset. Agora vamos iterar ele e mostrar o nome da cada página referente ao site:

    /**
     * Para cada registro da lista de páginas
     * imprime o nome da página usando o objeto
     */
    foreach($paginaRowSet as $rowPagina){
        /**
         * Imprime o nome da página usando um
         * método da classe Pagina, uma
         * classe Zend_Db_Table_Row
         */
        echo $rowPagina->nomeFormatado();
    }
}

Pronto! Você acaba de mostrar uma lista de sites e suas referidas páginas utilizando o relacionamento do Zend_Db_Table. E o arquivo index.php completo deve ficar assim:

/**
 * Inclui a pasta lib e Model no include path
 */
define('ROOT_DIR', dirname(__FILE__));
set_include_path(
	get_include_path() . PATH_SEPARATOR .
    ROOT_DIR . '/lib/' . PATH_SEPARATOR .
    ROOT_DIR . '/Model/'
);

/**
 * Inclui e instancia o Autoloader
 */
include('Zend/Loader/Autoloader.php');
$autoloader = Zend_Loader_Autoloader::getInstance();
$autoloader->setFallbackAutoloader(true);

/**
 * Conecta ao banco e registra o adaptador
 */
$db = Zend_Db::factory('Pdo_Mysql', array(
    'host'     => 'localhost',
    'username' => 'root',
    'password' => '',
    'dbname'   => 'ZendDb'
));

Zend_Db_Table_Abstract::setDefaultAdapter($db);

/**
 * Instancia a classe que lidará com a
 * tabela 'site'
 */
$tableSite = new Sites();

/**
 * Seleciona todas as linhas da tabela
 * ordenando por nome
 */
$siteRowSet = $tableSite->fetchAll(
	$tableSite->select()
    ->order('nome')
);

/**
 * Passa linha por linha da lista de
 * registros da tabela 'site'
 */
foreach($siteRowSet as $rowSite){
    /**
     * Chama um método que devolve o nome formatado.
     * Esse já é um objeto da classe Site
     * ou seja, uma classe Zend_Db_Table_Row
     */
    echo $rowSite->nomeFormatado();

     /**
     * Chamamos um método do objeto que irá
     * retornar uma lista de objetos relacionados
     * da tabela páginas
     */
    $paginaRowSet = $rowSite->findDependentRowset('Paginas');

    /**
     * Para cada registro da lista de páginas
     * imprime o nome da página usando o objeto
     */
    foreach($paginaRowSet as $rowPagina){

        /**
         * Imprime o nome da página usando um
         * método da classe Pagina, uma
         * classe Zend_Db_Table_Row
         */
        echo $rowPagina->nomeFormatado();
    }
}

Espero que esse post te ajude a desenvolver aplicações Zend utilizando o máximo de recursos que esse Framework oferece!

comments powered by Disqus