Relacionamentos entre Models.

No final do artigo anterior deixei um relacionamento entre os models Autor e Receita assim como o seguinte.

Veja o post anterior nesse link Views, FormHelper e Actions - Introdução ao CakePHP.

Listagem 1: relacionamento entre Receita e Autor


public $hasOne = array(
        'Autor' => array(
            'className'  => 'Autor',
        )
    );

A Listagem 1 não faz nada mais do que mapear o relacionamento que já existe no banco de dados.

Assim como, na modelagem, Receita tem um Autor devemos também indicar para o model que existe esse relacionamento.

O mapeamento dos relacionamentos nos permite economizar bastante código das consultas em SQL, também nos dá acesso a um objeto do model relacionado tanto dentro do próprio model ou de um controller que o mesmo pertença.

No Cake podemos mapear os seguintes tipos de relacionamentos:

1 para 1 hasOne Uma Receita tem um Autor
1 para muitos hasMany Uma Receita tem muitos Autores
Muitas para 1 belongsTo Muitas Receitas pertencem a um Autor
Muitos para Muitas hasAndBelongsToMany Receita tem, e pertencem a muitos Autores.

Um model pode conter mais de um relacionamento, do mesmo tipo ou não. Aqui, como sempre, estamos usando as normalizações do Cake, isso vai diminuir ainda mais a quantidade de escrita de código.

As configurações dos relacionamentos seguem o mesmo padrão para todos os tipos. Veja os exemplos:

Listagem 2: Relacionamento do tipo hasOne


<?php
class Usuario extends AppModel {    
/*
O trecho de código abaixo está relacionando o model Usuario ao 
model  Perfil e com a condição do campo ativo do perfil seja igual a 1
*/
    public $hasOne = array(
	//Alias do relacionamento, geralmente usamos o nome do model
        'Perfil' => array(
	//nome do model a ser relacionado
            'className'    => 'Perfil',
	//condições para a recuperação 
            'conditions'   => array('Perfil.ativo' => '1'),
	//quando setado para true e o metodo delete() é chamado com 
	//cascaded igual a true todas as dependências serão excluídas também
	'dependent ' => false,
	//Array com o nome dos campos que deve ser recuperados 
	'fields' => array('Perfil.nome','Perfil.ativo'),
	//campo da chave estrangeira, por padrão esse campo deve ser o 	
         //model mais _id
	'foreignkey' => “perfil_id”,
	//array com a ordem 
	'order' => array('Perfil.nome'=>'asc')	
        )
    );
}
?>

Listagem 3: Relacionamento do tipo belongsTo


	<?php
class Perfil extends AppModel {
	/*
	Relacionamento onde um perfil pertence a um usuario
*/
    public $belongsTo = array(
        'Usuario' => array(
            'className'    => 'Usuario',
	//chave que representa o campo do outro model
            'foreignKey'   => 'usuario_id',
	//tipo de join, left é o padrão
	'type'  => 'left'
        )
    );
}
	

As mesmas opções do relacionamento hasOne estão presentes no belongsTo acrescidas de type, counterCache, counterScope, essas duas ultimas não são interessantes para essa serie de introdução.

Vejamos agora os relacionamentos hasMany e hasAndBelongsToMany.

Listagem 4: Relacionamentos de tipo hasMany e hasAndBelongsToMany.


<?php
class Receita extends AppModel {
       public $hasMany = array(
        'Receita' => array(
	
            'className'     => 'Receita',
	//	limite de linhas que serão retornadas.
            'limit'         => '5',
        ) 
    );
                  public $hasAndBelongsToMany = array(
        'Ingrediente' =>
            array(
                'className'              => 'Ingrediente',
		//tabela do relacionamento
                'joinTable'              => 'ingredientes_receitas',
                'foreignKey'             => 'receita_id',
	        //chave de associação	
                'associationForeignKey'  => 'ingrediente_id',
            )
    );
}
?>

Nesses dois relacionamentos as opções são também praticamente as mesmas, na listagem 4 destaquei aquelas que na minha opinião são as mais importantes, as outras veremos nos próximos posts. E estivermos usando as normas “cakerianas” só precisaremos mudar alguma coisa aqui quando a regra de negócios exigir.

Agora vamos dar continuidade ao nosso CRUD.

Novas Actions para o CRUD

Nós já temos nosso cadastro pronto e acredito que vocês devem ter cadastrado algumas receitas. Vamos fazer agora uma função listagem e uma para deletar.

Voltemos ao nosso Controlador de Receita

Listagem 5: Action de listagem dos registros.


	<?php 
		class ReceitaController extends AppController(){
			/* outros métodos aqui em cima */
			public function lista(){
/*
chamamos o métodos find('all') do model para retornar todos os registros
*/
$receitas = $this->Receita->find('all');
/*	
enviamos a variável receitas para a view pelo metodo set do controller
*/
$this->set('receitas',$receitas);
}
}
?>

Na Listagem 5 fizemos uso do método find($type,$options) do model, desta vez com o tipo “all”, para recuperar todos os registros previamente cadastrados, depois usamos o método set($one,$two) para enviarmos para a view a variável $receitas.

Espera aí que agente já faz a view, vamos contruir nossa action para deletar aí agente já faz tudo de uma vez.

Listagem 6: Action para deletar


<?php 
class ReceitaController extends AppController(){
		/* outros métodos aqui em cima */
		public function deletar($id = null){
		/* 
verificamos se o id é igual a null e caso ele seja chamamos 
o método redirect do controller para redirecionar a requisição 
junto com uma mensagem de aviso.
*/
			if(!isset($id))
/*Uso do component Session, coisa de outros posts*/
			   $this->Session->setFlash('Erro!');
			 /*redireciona para a acton listar*/
			   $this->redirect->(“/receitas/listar”);
 				/*
Criamos um novo objeto do tipo receita Isso é necessário 
aqui porquê vamos setar propriedades para o objeto manipular.
*/
                                             $this->Receita->create();
                                         /*setamos o id da receita*/
$this->Receita->id = $id
/*chamamos a função delete do model que retorna true ou false*/
if($this->Receita->delete())
/*Uso do component Session, coisa de outros posts*/
			   $this->Session->setFlash('Arquivo deletado!');			 
}else{
  $this->Session->setFlash('Não foi possível deletar!');	 	
}
/*redireciona para a acton listar*/
			   $this->redirect->(“/receitas/listar”); 

}
?>

Note que a action delete termina com um redirecionamento, dessa forma ela nunca vai renderizar uma action própria, isso significa que não precisaremos criar uma view para essa action, o que é muito natural.

View da action listar.

Para essa view temos o array que enviamos da action, então faremos um foreach para varrermos o seu conteúdo, e para esse exemplo usaremos uma table HTML.

Listagem 7: View listar


	<table>
	<tr>
	<th>id</th>
	<th>titulo</th>
	<th>texto</th>
	<th>autor</th>
	</tr>
	<?php foreach($receitas as $receita){ ?>
	<tr>
	<td><?php echo $receita['Receita']['id'] ?></td>
	<td><?php echo $receita['Receita']['title'] ?></td>
	<td><?php echo $receita['Receita']['texto'] ?></td>
	<td><?php echo $receita['Autor']['name'] ?></td>
</tr>
<?php } ?>
	</table>

O padrão de arrays é o padrão do cake [Model][campo] dessa forma sempre temos uma forma intuitiva e organizada de recuperar os dados, todas as funções que recuperam dados retornam dessa forma.

Vamos implementar na listagem anterior um link para chamar na action delete, utilizando o HtmlHelper que já vem habilitado por padrão.

Listagem 7: implementação de link para a action delete


	<table>
	<tr>
	<th>id</th>
	<th>titulo</th>
	<th>texto</th>
	<th>autor</th>
	<th>ação</th>
	</tr>
	<?php foreach($receitas as $receita){ ?>
	<tr>
	<td><?php echo $receita['Receita']['id'] ?></td>
	<td><?php echo $receita['Receita']['title'] ?></td>
	<td><?php echo $receita['Receita']['texto'] ?></td>
	<td><?php echo $receita['Autor']['name'] ?></td>
<td><?php 
	/* Html:link($string,$url,$options), similar a uma tag <a></a>
A url pode ser passada como um array com o controlador, a action e as 
variáveis que ficaram acessíveis como parametro ou uma string da 
seguinte forma /controller/action/variavel   
Vamos usar o array no exemplo
 */
echo 
$this->Html->link('delelar',
array('controller'=>”receitas”,”action”=>”delete”,$receita['Receita']['id'])) ?>
</td>
</tr>
<?php } ?>
	</table>

Bem pessoal por aqui terminamos nossa serie de introdução ao CakePHP. Tem muita coisa que ele faz que vai facilitar muito nossas vidas, mas o intuito desses posts foi o de deixar claro a divisão das camadas do Bolo(Cake) , das responsabilidade de cada uma delas.

Nos próximos posts daremos focos a coisas mais especificas do cotidiano do programador que quiser enveredar-se no mundo do CakePHP.

Forte abraço e até a próxima.