Relacionamento entre tabelas com Zend Framework
O Zend Framework possui uma camada de modelo, composta por algumas classes como Zend_Db, Zend_Db_Table, Zend_Db_Table_Rowset, entre outras, e é muito simples criar uma classe que representa uma determinada tabela, basta herdar da classe Zend_Db_Table_Abstract que você terá todos os métodos principais de acesso à dados, como insert, update, etc.
Porém as tabelas possuem relacionamentos e uma entidade em uma tabela pode ser ligada a uma ou mais entidades em outra tabela utilizando integridade referencial, e o Zend Framework permite que você faça isso tudo no nível de objeto através de métodos específicos da classe Zend_Db_Table_Row.
Para demonstrar isso, vou usar como exemplo uma relação bem simples. Supondo que existam as seguintes tabelas:
UF
id - INT - PRIMARY KEY
nome - Varchar(100)
CIDADE
id - INT - PRIMARY KEY
nome - Varchar(100)
uf_id - INT - FOREIGN KEY
Se criarmos duas classes no Zend Framework para representar essas tabelas, nós faríamos o seguinte:
class UF extends Zend_Db_Table_Abstract
{
protected $_name = "uf";
}
class Cidade extends Zend_Db_Table_Abstract
{
protected $_name = "cidade";
}
Com essas duas classes nós já possuímos os métodos necessários para inserir, alterar, excluir e recuperar os dados delas, porém, de maneira independente. Para recuperarmos todas as cidades de um determinado estado por exemplo, nós poderíamos fazer o seguinte:
Primeiro, uma pequena alteração nas classes:
class UF extends Zend_Db_Table_Abstract
{
protected $_name = "uf";
protected $_dependentTables = array('Cidade');
}
class Cidade extends Zend_Db_Table_Abstract
{
protected $_name = "cidade";
protected $_referenceMap = array(
'UF' => array(
'columns' => 'uf_id',
'refTableClass' => 'UF',
'refColumns' => 'id'
)
);
}
Calma, já vou explicar:
Na propriedade da classe UF $_dependantTables, eu defino quais tabelas/classes que são dependentes da tabela UF, passando simplesmente o nome da classe como um elemento de um array. Pode-se passar quantos nomes de tabelas/classes forem necessárias, desde que cada um seja um elemento distinto.
Na propriedade da classe Cidade $_referenceMap, nós fazemos o mapeamento entre as duas classes, onde a coluna uf_id da tabela Cidade é uma referência ao campo id da tabela UF. Simples demais!
Vamos testar?
Eu vou mostrar duas maneiras diferentes para retornar todas as cidades de uma determinada UF, a primeira segue abaixo:
PS: Eu vou criar um IndexController para executar este exemplo.
include_once 'UF.php';
include_once 'Cidade.php';
class IndexController extends Base_Controller_Action
{
public function indexAction()
{
// Cria instância da classe UF
$tabelaUF = new UF();
// Pesquisa pelo UF 1 (1 é o ID do UF na tabela UF)
$ufRows = $tabelaUF->find(1);
// Retorna o Zend_Db_Table
$uf = $ufRows->current();
// Pesquisa pelas cidades referentes ao UF consultado acima
$cidadesPorUF = $uf->findDependentRowset(’Cidade’);
// Mostra resultado
echo ‘<pre>’;
print_r($cidadesPorUF);
echo ‘</pre>’;
}
}
Simples não?
O Outro exemplo terá o mesmo resultado porém a maneira como consultaremos as cidades por dada UF será um pouco diferente.
Se você está acostumado com PHP 5, você já conhece os chamados ‘métodos mágicos’ como __call(), __set(), __get() certo? pois então, agora nós vamos usar um método mágico chamado FindCidadeByUF() só que esse método não existe em nossa classe, então de onde que ele veio? O Zend Framework possui um mecanismo que nos permite consultar tabelas dependentes utilizando métodos mágicos no seguinte formato: Find<Tabela>By<Tabela>, então ele dinamicamente saberá onde consultar os dados, basta substituirmos a primeira <Tabela> pelo nome da classe Cidade e a segunda tabela pela classe UF que ele se encarrega do resto.
Veja o exemplo:
include_once 'UF.php';
include_once 'Cidade.php';
class IndexController extends Base_Controller_Action
{
public function indexAction()
{
$tabelaUF = new UF();
$ufRows = $tabelaUF->find(1);
$uf = $ufRows->current();
$cidadesPorUF = $uf->findCidadeByUF();
echo ‘<pre>’;
print_r($cidadesPorUF);
}
}
Interessante não é? Veja o resultado:
Considerações finais
Espero ter conseguido demonstrar este mecanismo interessante do Zend Framework. Espero que da mesma forma com que ele tem auxiliado o trabalho ele também auxilie o seu.
O que que você achou? Deixe aqui seu comentário.
A propósito, nos últimos dias alguns colegas me perguntaram bastante coisa sobre o Zend Framework, muitos queria fazer um hello world para entender o padrão dele, outros queriam algo mais avançado, então eu pensei: Porque não escrever uma série de tutoriais no meu blog? Isso pode ser útil para muito mais pessoas. Então gostaria de sua opinião. Deixe seu comentário.
Eu estou pensando em fazer uma série de artigos simples e diretos ao assunto sobre Zend Framework, abordando desde o básico até o mais avançado. Então, espero começar na próxima semana.
abraço.
Tags: zend framework

March 26th, 2008 at 10:01 am
E ai Adler blz?
Cara gostei muito desse artigo não sabia que o Zend tinha esse schema de relacionamento. Estou iniciando meu estudo no Zend e tenho certeza que seus artigos irão ser de bom aproveito para esse meu inicio. Abraço.
March 26th, 2008 at 1:45 pm
Beleza. E contigo, tudo certo?
Que bom que gostou. Espero poder fazer artigos diretos ao ponto a partir da semana que vem. Tomara que eles possam ajuda-lo em seu aprendizado.
Um abraço.
March 27th, 2008 at 9:47 am
Grande Adler,
Tava devendo esses arigos mesmo, to dando uma geral no Zend tb.
Seguinte dúvida, se eu já tiver o ID do UF e não quiser ir no banco de dados buscar, eu poderia fazer algo assim?
$cidadesPorUF = $tabelaCidade->findCidadeByUF($idUF);
Buscando pela tabela de Cidade e passando somente o ID?
Valeu cara!
March 27th, 2008 at 11:04 am
Boa Adler. Estou escrevendo um artigo pra executar as mesmas tarefas, mas com o Kohana Framework (rails-like). Bacana pra analisar diferentes implementações destas funcionalidades.
Rafael, creio que seja possível, mas você têm de especificar o nome real do campo no método: findCidadeByUfId().
March 27th, 2008 at 12:31 pm
[...] entre tabelas com ORM do Kohana Framework framework, PHP Achei o post do Adler sobre relacionamento entre tabelas com o Zend Framework bem bacana e did?tico. Estou me devendo uma olhada no ZF, que j? est? na vers?o 1.5.1 (enquanto [...]
March 27th, 2008 at 3:56 pm
Rafael, eu nunca tentei usar dessa maneira, eu sempre usei o objeto, no caso, da classe UF. Eu vou dar uma olhada e te digo assim que possível.
Newton, valeu. Espero que possamos trocar figurinhas e fazer estudos comparativos entre frameworks, não com o intuito de um querer derrubar o outro, mas apenas demonstrando funcionalidade mesmo. Olhei o seu tutorial sobre o kohana e achei bem bacana a implementação.
No final, quem ganha é a comunidade. Isso que é importante.
um abraço a vocês!
March 28th, 2008 at 3:39 pm
Muito bom seu artigo !
Parabéns mesmo!
Iniciei no ZF ontem, estou vendo bastante coisa boa!
Deixo uma pergunta,
Como faz a conexão com o Banco de dados utilizando o ZF? Aonde crio a conexão ? Ou uso uma classe pronta ? Porque senão este exemplo não vai funcionar né .. rsrs
Abraços,
e parabéns mais uma vez!
April 3rd, 2008 at 2:14 pm
[...] entre tabelas com ORM do Kohana Framework PHP, framework Achei o post do Adler sobre relacionamento entre tabelas com o Zend Framework bem bacana e didático. Estou me devendo uma olhada no ZF, que já está na versão 1.5.1 (enquanto [...]
April 4th, 2008 at 11:06 pm
Eaee Adler, beleza?
achei muito bacana as suas explicações, bem direta, bem explicada tambem e muito útil!
se vc continuar escrevendo coisas sobre o zend, vai ser uma maravilha, estou começando meus estudos no zend agora, estou aprendendo.
valeu aê!
May 4th, 2008 at 12:46 pm
Parabéns cara, ótimo tutorial!
July 21st, 2008 at 8:48 pm
MASSSSSSSSSSA!
flw.