Back-End

20 abr, 2010

CakePHP – Models

Publicidade

Olá, Pessoal!

Este artigo tem como objetivo apresentar uma das camada do da arquitetura MVC, o Model.

O que é um Model?

O model implementa o modelo representando a estrutura de baixo nível do projeto, podendo ser o modelo objeto-relacional que implementa a camada de dados, e ou num caso de MVC de Interface, poderia guardar informações de estado dos controles [by wikipédia].

Trazendo para o mundo real, o que seria o model? Nada mais é que os dados que vêm do banco de dados, mas ele representaria uma linha por vez, por isso que escrevemos o nome do model sempre no singular.

Por exemplo, se no banco de dados temos um campo chamado “idade”, em nosso model ficaria representado assim “NomeDoModel.idade”. Bem simples, né?

O que mais podemos fazer com o model?

  • Definir relacionamentos (Joins);
  • Realizar pesquisas no banco de dados;
  • Restringir dados;
  • Efetuar filtros em dados antes e depois de gravar/pesquisar no banco de dados;
  • Criar funções personalizadas. Ex.: Uma função de criptografia.;

O cakePHP já implementa algumas funções básicas, como Find, Save e Del. A maioria dessas funções você vai utilizar na camada controller. Em outro artigo, entraremos em detalhes sobre a camada de controle. Mesmo assim, vou detalhar um pouco mais sobre o método que vamos utilizar com freqüência, o Find.

Utilizando os métodos Find

O método find com certeza será um dos métodos que você mais vai utilizar em seu controller para pesquisas.

Mas vamos querer apenas resultados de acordo com nossos critérios. Então vamos implementar as conditions para nossa busca.

Vamos a um exemplo prático. No artigo anterior tínhamos a seguinte função em nosso controller:

function listar() {
// coloca um titulo em nossa página, ou seja passa para o template a variavel title
$this->set('title', 'Listar');
//aqui vamos buscar todos nossos registros no banco de dados
$tarefas = $this->Tarefa->findAll();
//Aqui estamos enviando para o template os registros encontrados.
$this->set('tarefas', $tarefas);
}

Tínhamos um campo chamado status que era um BOOLEAN, e vamos querer listar apenas tarefas que estejam com status igual a 1. Para fazer isso, vamos passar como parâmetro para a função findAll as condições de busca, é como se estivéssemos colocando uma cláusula WHERE em uma pesquisa SQL.

Vamos criar uma variável local na função mesmo. Essa variável vai receber um um array associativo. Fica assim:

$conditions = array("Tarefa.status" => 1);

Vamos ramificar para explicar isso:

  • Tarefa: é o nome do model (sempre no singular);
  • Status: é o nome do campo que quero adicionar um WHERE;
  • 1: é o valor que queremos.

Isso é equivalente ao seguinte SQL:

SELECT * FROM tarefas WHERE status = '1';

Nossa função ficou assim então:

function listar() {
$conditions = array("Tarefa.status"=>1);
// coloca um titulo em nossa página, ou seja passa para o template a variavel title
$this->set('title', 'Listar');
//aqui vamos buscar todos nossos registros no banco de dados
$tarefas = $this->Tarefa->findAll($conditions);
//Aqui estamos enviando para o template os registros encontrados.
$this->set('tarefas', $tarefas);
}

Então, agora sabemos como definir critérios para a pesquisa. Podemos adicionar diversos itens como critérios basta ir adicionando no array.

As conditions funcionam do mesmo jeito para todas as outras funções finds.

As funções mágicas

Bom, o cakePHP ainda não vai fazer todo o trabalho para você em um passe de mágica, mas pode quebrar seu galho para buscas. Com as funções mágicas dele, podemos fazer uma busca em um determinado campo da tabela sem precisar ficar usando conditions é o findAllBy<nome_do_campo>, então podemos usar em nosso controller uma busca nas Tarefas pelo autor.

$this->Tarefa->findAllByAutor("Breno Oliveira");

Isso irá nos retornar todos os resultados onde o campo autor esteja preenchido com Breno Oliveira. De maneira bem simples e produtiva, o cakePHP nos ajuda com tarefas rotineiras. O findAllBy<nome_campo> vai retorna um array com várias possibilidades. Você também pode querer buscar somente com o findBy<nome_do_campo> que iria retorna uma única linha.

Antes de salvar, faça

Essa é uma das vantagens do cakePHP: nós podemos fazer alterações em nosso Model antes de salvar os dados no BD. Por exemplo: temos um algoritmo de criptografia de senhas e um Model referente a usuários. Podemos sempre pegar aquela senha digitada pelo usuário e aplicar o algoritmo de forma implícita, ou seja, o cakePHP vai criptografar a senha sem que você precise fazer isso. Essa é a função beforeSave que devemos implementar em nosso Model. Vamos fazer o exemplo da criptografia:

function crypto_password ( $username , $password ) {
return sha1 ( $username . "_" . $password );
}

function beforeSave ( ) {
$this->data["Usuario"]["hashed_password"] = $this->crypto_password( $this->data["uUsuario"]["username"] , $this->data["User"]["hashed_password"] );
return true;
}

A função crypto_password recebe 2 parâmetros e gera uma senha criptografada. No beforeSave vamos pegar os dados que vêm do formulário e aplicamos o nosso filtro. Assim, toda vez que formos salvar a senha de um novo usuário através desse Model, a lógica aplicada dentro da função beforeSave será aplicada.

Também há a função afterSave, que é após salvar. Ela vai fazer a mesma coisa que a beforeSave, porém será executada após salvar os dados.

Antes/Depois de buscar

Também podemos utilizar a função beforeFind e o afterFind. Elas funcionarão como os exemplos acima, porém serão executadas antes e após a consulta.

Antes/Depois de apagar

Há também mais dois métodos semelhantes aos já falados, mas para deletar dados. São os beforeDelete e afterDelete: um para executar comandos antes de excluir e outro após excluir respectivamente.

Relacionamentos entre Models

O cakePHP também facilita bastante os relacionamentos entre tabelas. Utilizando nomenclaturas como BelongsTo, hasMany e hasAndBelongsToMany, ele define os relacionamentos entre tabelas. Para definir os relacionamentos, precisamos apenas declarar qualquer uma das variáveis já citadas e passar como parâmetro uma array com os outros Models.

Por exemplo, suponha que temos uma outra tabela chamada autores onde ficam armazenadas informações sobre autores (nome, e-mail, rg, cpf, etc) de nossas tarefas. Na tabela tarefas é preciso ter um campo onde iríamos fazer os relacionamentos entre tarefas e autores. A estrutura de nossas tabelas ficaria assim:

CREATE TABLE autores (
id INT NOT NULL AUTO_INCREMENT,
nome VARCHAR(100),
email VARCHAR(100),
nascimento DATE,
PRIMARY KEY(id)
) TYPE=INNODB;

CREATE TABLE tarefas (
id INT NOT NULL AUTO_INCREMENT,
autor_id INT NOT NULL REFERENCES autores(id),
data_inicio DATETIME,
data_fim DATETIME,
tarefa VARCHAR (255),
status BOOL,
PRIMARY KEY ( id )
) TYPE=INNODB;

No SQL, o relacionamento entre as tabelas está bem claro. Agora vamos deixar esse relacionamento claro para o cakePHP, ou seja, quando trouxermos os dados de uma tarefa, ele já trará junto os dados do autor.

O Model de tarefas ficaria assim:

	class Tarefa extends AppModel {
var $name = "Tarefa";
var $belongsTo = array("Autor");
}

e o Model do autor:

	class Autor extends AppModel {
var $name = "Autor";

var $hasMany = array("Tarefa");
}

O que fizermos foi simples! informamos que o Model Tarefa vai pertencer ao Model Autor(belongsTo) e em Autor informamos que ele tem muitas tarefas(hasMany).

Agora quando realizarmos uma consulta um Tarefas o cakePHP irá trazer no resultado o autor também.

Conclusão

O CakePHP facilita muito o desenvolvimento e nos auxilia a deixar nosso código mais limpo e compreensível. Com a parte de Model podemos criar nossos Relacionamentos de maneira um pouco semelhante como o Hibernate faz, claro que dentro de suas particularidades de linguagem.