Assando Sites Relacionamentos, Validação, Consultas e Páginas Dinâmicas Módulo 4
Dê adeus aos JOINs 1 Relações entre Models
1.1 Definição Relações O CakePHP te dá quatro formas de relacionar (ligar) os seus Models, possibilitando a criação de sistemas complexos e, ao mesmo tempo, bem organizados Usuário tem um Perfil Notícia pertence à Usuário Notícia pertence à Categoria Categoria contém muitas Notícias Notícia contém e pertence à muitas Tags Com pequenas mudanças no banco de dados você já economiza horas de trabalho!
1.2 Tipos de relações Relações Relação hasone hasmany belongsto hasandbelongstomany HABTM Descrição Um registro de um model está diretamente ligado ao registro de outro model (1:1) Um registro de um model contém (é pai de) mais de um registro de outro model (1:N) Um registro de um model pertence (é filho) de um registro de outro model (1:N) Relação de muitos para muitos (N:N)
1.2.1 hasone Relações O hasone acontece quando um registro de um model está diretamente ligado ao registro de um outro model e vice-e-versa: Usuario hasone Perfil
1.2.1 hasone Relações <?php class Usuario extends AppModel { public $hasone = array('perfil'); } app/model/usuario.php Usuario hasone (contém um) Perfil Sempre que buscarmos um Usuário, seu Perfil virá junto O relacionamento dos dados é feito através de uma coluna usuario_id na tabela do model Perfil.
1.2.2 hasmany Relações O hasmany acontece quando um registro de um model contém (é pai de) um ou mais registros de um outro model: Categoria hasmany Noticia Categoria hasmany Categoria
1.2.2 hasmany Relações app/model/categoria.php <?php class Categoria extends AppModel { public $hasmany = array('categoria', 'Noticia'); } Categoria hasmany (contém muitas) Categoria Categoria hasmany (contém muitas) Noticia Sempre que buscarmos uma Categoria, toda as categorias filhas e todas s notícias (da categoria buscada) virão junto O relacionamento dos dados é feito através de uma coluna categoria_id nas tabelas filhas (noticias e categorias).
1.2.3 belongsto Relações O belongsto é a relação inversa ao hasmany, e acontece quando um registro de um model é filho de (pertence à) um registro de um outro model: Noticia belongsto Categoria Categoria belongsto Categoria
1.2.3 belongsto Relações <?php class Noticia extends AppModel { public $belongsto = array('categoria'); } app/model/noticia.php Noticia belongsto (percente à) Categoria Sempre que buscarmos uma Noticia, os dados da Categoria virão junto O relacionamento dos dados é feito através de uma coluna categoria_id na tabela do model Noticia
1.2.4 hasandbelongstomany Relações O hasandbelongstomany é uma relação rara e complexa, acontece quando muitos registros de um model estão ligados à muitos de outro model: Noticia hasandbelongstomany Tag
1.2.4 hasandbelongstomany Relações app/model/noticia.php <?php class Noticia extends AppModel { public $hasandbelongstomany = array('tag'); } Noticia hasandbelongstomany Tag Sempre que buscarmos uma Noticia, todas as suas Tags virão junto O relacionamento dos dados é feito através de uma nova tabela (noticias_tags), com colunas apontando pra chave primária dos models relacionados
Ex1 Palestras e Palestrantes Exercícios a. Crie um model para Palestras Nome, descrição, início (hora) e fim (hora) b. Crie um model para Palestrantes Nome, descrição e endereço do site c. Relacione os models de forma que: Um palestrante pode realizar várias palestras Cada palestra é dada por apenas um palestrante
Garantindo a qualidade dos seus dados 2 Validação de dados
2.1 Validação de dados Validação A validação dos dados é uma das mais importantes partes de qualquer aplicação, elas fazem com que os dados do Model respeitem as regras da aplicação. Por exemplo: você pode estar querendo que as senhas tenham no mínimo oito caracteres, ou garantir que os usernames sejam únicos. O CakePHP possui várias regras de validação prontas pra você usar, mas se você não estiver satisfeito pode criar as suas regras...
2.2 Exemplo de validação Validação <?php class Noticia extends AppModel { public $validate = array( 'titulo' => array( 'rule' => 'notempty', // Nome da regra 'message' => 'Preencha o título' app/model/noticia.php Noticia ), hasandbelongstomany Tag Sempre 'texto' que buscarmos => array( uma Noticia, todas as suas Tags virão junto 'rule' => array('minlength', 100), 'message' => 'Digite no mínimo 100 caracteres' O relacionamento ) dos dados é feito através de uma nova tabela );(noticias_tags), com colunas apontando pra chave primária } dos models relacionados
2.2 Exemplo de validação Validação app/model/noticia.php <?php class Noticia extends AppModel { public $validate = array( 'titulo' => array( array( 'rule' => 'notempty', // Não vazio 'message' => 'Preencha o título' ), array( 'rule' => 'isunique', // Único 'message' => 'Este título já está em uso' ) ) ); }
2.3 Métodos nativos de validação Validação Validação Valores válidos alphanumeric Valores alfa-numéricos between(min,max) Tamanho entre X e Y (caracteres) blank Valores vazios boolean 1 ou 0 / true ou false cc Número de cartão de crédito comparison(op,val) Comparação numérica (>= 18) date(format) Data datetime(format) Data e hora decimal(places) Números decimais (reais) email(check) Emails válidos
2.3 Métodos nativos de validação Validação Validação Valores válidos equalto(int str) Valores iguais ao especificado extension(array) Extensão de um arquivo/url file Se é um nome de arquivo ip(type) IPs (valida IPv4 e IPv6) isunique Valor único (bom pra usuários) minlength(int) Tamanho mínimo maxlength(int) Tamanho máximo money(position) Número com simbolo monetário multiple(option) Valores múltiplos
2.3 Métodos nativos de validação Validação Validação inlist(array) numeric naturalnumber notempty phone postal range(x,t) ssn url luhn(deep) Valores válidos Valor pertence à uma lista Valores numéricos Valores numéricos naturais (inteiros) Campo não está vazio Telefone com formato válido (US) CEP válido (US, CA, UK, IT, DE) Número entre X e Y, exclusive Número de segurança (US, UK) URL válida Números de identificação (SSN)
2.4 Criando uma regra da validação Validação <?php class Usuario extends AppModel { public $validate = array( ); 'twitter' => array( ) 'rule' => 'validatwitter', // Nome do método 'message' => 'Perfil do Twitter inválido' app/model/usuario.php } public function validatwitter($data) { // Novo método $valor = array_shift($data); // Extraímos o valor $formato = '/@([A-Za-z0-9_]+)/'; return preg_match($formato, $valor); }
2.5 Validação com expressão regular Validação Também podemos validar os dados utilizando apenas expressão regular, sem precisar criar um método: <?php class Usuario extends AppModel { public $validate = array( } ); 'twitter' => array( ) 'rule' => '/@([A-Za-z0-9_]+)/', // RegExp 'message' => 'Perfil do Twitter inválido' app/model/usuario.php
2.6 Opções extras de validação Validação Além de rule e message, você pode definir mais algumas opções pra cada regra de validação: Opção required bool allowempty bool Descrição O campo deve estar presente no array que será usado no save/update Permite que o campo seja salvo ou atualizado para vazio Com o required o campo deve estar presente, e com o allowempty o campo pode ser salvo vazio
Ex2 Validando os dados Exercícios a. Criar a validação do model Inscricao: Nome preenchido Email preenchido, com formato válido e único Telefone preenchido, apenas números Endereco preenchido, no mínimo 10 caracteres b. Criar validação para o model Palestrante: Nome preenchido Descrição preenchida URL válida mas não obrigatória c. Criar validação para o model Palestra: Nome preenchido e único Horários preenchidos com formato valido (HH:HH)
Buscas, filtros e condições 3 Consultando Dados
3.1 Método find Consulta A forma mais comum de buscar dados é utilizando o método Model::find(tipo[, parametros]) <?php app/controller/noticiascontroller.php class NoticiasController extends AppController { public function index() { // Busca todas as notícias $ultimas = $this->noticia->find('all'); } } // Manda para a View $this->set('noticias', $ultimas);
3.1.2 Tipos de find Consulta Existem seis tipos nativos de find() Opção first count all list threaded neighbors Descrição Apenas o primeiro registro Conta o total de registros Todos os registros encontrados Lista (ID e displayfield) dos registros Pais e filhos, como comentários Como o first, so que lista os vizinhos
3.1.3 Parâmetros do find Consulta Veja alguns parâmetros que o find() aceita: Opção Descrição SQL fields Colunas à serem buscadas SELECT conditions Condições de busca WHERE recursive Busca recursiva? [-1;2] JOIN order Ordem do resultado ORDER BY group Agrupamento de resultados GROUP BY limit Limite de resultados LIMIT page Número da página LIMIT offset Limite inferior de resultados LIMIT
3.1.4 Exemplo de consulta com find Consulta Busca as últimas cinco notícias criadas e ativas: $params = array( 'conditions' => array('noticia.active' => true), 'order' => array('noticia.created' => 'DESC'), 'limit' => 5 ); $noticias = $this->noticia->find('all', $params); SELECT Noticia.* FROM `noticias` AS Noticia WHERE Noticia.`active` = 1 ORDER BY Noticia.`created` DESC LIMIT 5
3.1.4 Exemplo de consulta com find Consulta $email = 'contato@thiagobelem.net'; $params = array( 'conditions' => array( 'Usuario.email' => $email, 'Usuario.idade >=' => 18 ), 'order' => array('usuario.nome') ); $usuario = $this->usuario->find('first', $params); SELECT Usuario.* FROM `usuarios` AS Usuario WHERE Usuario.`email` = 'contato@thiagobelem.net' AND Usuario.`idade` >= 18 ORDER BY Usuario.nome ASC LIMIT 1
3.1.5 Exemplo de consulta com find Consulta $params = array( 'conditions' => array( 'OR' => array( 'Usuario.estado' => 'SP', 'Usuario.cidade' => 'São Paulo', ), 'Usuario.sexo' => 'M' ) ); $usuario = $this->usuario->find('all', $params); SELECT Usuario.* FROM `usuarios` AS Usuario WHERE ((Usuario.`estado` = 'SP') OR (Usuario.`cidade` = 'São Paulo')) AND (Usuario.`sexo` = 'M')
3.1.6 Exemplo de consulta com find Consulta $params = array( 'fields' => array('usuario.nome', 'Usuario.email'), 'conditions' => array( 'Usuario.estado' => array('sp', 'RJ'), 'Usuario.sexo' => 'M' ), 'limit' => 3 ); $usuario = $this->usuario->find('all', $params); SELECT Usuario.`nome`, Usuario.`email` FROM `usuarios` AS Usuario WHERE Usuario.`estado` IN ('SP', 'RJ') AND Usuario.`sexo` = 'M' LIMIT 3
3.1.7 Conditions complexas Consulta array( 'OR' => array( array('company.name' => 'Future Holdings'), array('company.city' => 'CA') ), 'AND' => array( array( 'OR' => array( array('company.status' => 'active'), 'NOT' => array( array('company.status' => array('inactive', 'suspended')) ) ) ) ) )
3.2 Método field Consulta O método Model::field(coluna, cond., ordem) te ajuda a buscar a coluna de um único registro: // Busca o título da noticia #22 $this->noticia->id = 22; $titulo = $this->noticia->field('titulo'); // Busca o nome de um usuário ativo $cond = array('usuario.active' => true); $ordem = array('usuario.nome' => 'ASC'); $nome = $this->usuario->field('nome', $cond, $ordem);
3.3 Método read Consulta O método Model::read(coluna(s), id) te ajuda a buscar uma ou mais colunas de um único registro: // Busca o título da noticia #22 $dados = $this->noticia->read('titulo', 22); // Busca o nome e a idade do usuário #123 $this->usuario->id = 123; $dados = $this->usuario->read(array('nome', 'idade')); // Busca TODOS os dados de um produto (muito usado) $this->produto->id = 5; $dados = $this->produto->read();
Ex3 Consultando dados Exercícios a. Adicione dados manualmente ou crie telas de inserção de Palestra e Palestrante (assim como você fez na inscrição) b. Crie uma página para listar as Palestras Liste-as ordenando pela hora de inicio ASC Mostre o título, horário e descrição de cada palestra c. Crie uma página para listar os Palestrantes Liste-os ordenando pelo nome ASC Mostre o nome e a descrição dos palestrantes
URLs dinâmicas, actions e consulta à banco 4 Páginas Dinâmicas
4.1 URLs dinâmicas Pág. Dinâmicas URLs dinâmicas servem para mostrar diferentes conteúdos via uma mesma action: Router::connect('/noticia/:titulo/:id', array( )); 'controller' => 'noticias', 'action' => 'view'), array( 'pass' => array('id'), // Passa o ID pra action 'titulo' => '[a-z0-9-]+', 'id' => '[0-9]+' http://site.com/noticia/novo-presidente/123/ http://site.com/noticia/outra-noticia-muito-longa/517/ http://site.com/noticia/palhaço-mata-cinco/123/
4.2 Actions dinâmicas Pág. Dinâmicas Feita a URL, podemos criar a action definida na rota, para receber os dados dinâmicos: public function view($id) { $this->noticia->id = $id; $dados = $this->noticia->read(); } $this->set('noticia', $dados); E assim podemos usar $noticia dentro da view, que terá todos os dados da notícia! <?php echo $noticia['noticia']['titulo']?>
Ex4 Seu primeiro Controller Exercícios a. Crie uma página exibir os dados do Palestrante Mostre o nome, descrição e um link para o site dele A rota dessa página pode ser: /palestrante/:nome/:id b. Na listagem de palestras, crie um link para a página com os dados do palestrante Use o HtmlHelper::link() pra criar o link Use o Inflector::slug() para gerar um slug: $slug = strtolower(inflector::slug('olá Mundo', '-')); // Resultado: ola-mundo
Assando Sites Obrigado por participar! :) Módulo 4