Cake CursoORIG

90
Curso de CakePHP Página 1 /90 Curso de CakePHP 1 – Introdução . . . . . . . . . . . . . . . . 2 2 – Configurações . . . . . . . . . . . . . . . 6 3 – Convenções . . . . . . . . . . . . . . . 8 4 – Bake (Gerando aplicativos pela console) . . . . . . . . 12 5 – Model . . . . . . . . . . . . . . . . . 20 6 – Controller . . . . . . . . . . . . . . . . 22 7 – View . . . . . . . . . . . . . . . . . 25 8 – Action . . . . . . . . . . . . . . . . . 29 9 – Scaffold . . . . . . . . . . . . . . . . 33 10 – Validações . . . . . . . . . . . . . . . 37 11 – MVC . . . . . . . . . . . . . . . . . 40 12 – Menus . . . . . . . . . . . . . . . . 43 13 – CSS . . . . . . . . . . . . . . . . . 44 14 – JavaScript . . . . . . . . . . . . . . . 47 15 – Helpers . . . . . . . . . . . . . . . . 48 16 – Componentes . . . . . . . . . . . . . . . 51 17 – Routes . . . . . . . . . . . . . . . . 53 18 – Vendors . . . . . . . . . . . . . . . . 61 19 – Plugins . . . . . . . . . . . . . . . . 62 20 – Relacionamentos . . . . . . . . . . . . . . 67 21 – Dicas . . . . . . . . . . . . . . . . . 68 22 - Aplicativos de Exemplo 22.1 - Aplicativo Livros . . . . . . . . . . . . 69 22.2 - Aplicativo cake_olamundo . . . . . . . . . . 81 22.3 - Outros Exemplos . . . . . . . . . . . . 87 22 – Referências . . . . . . . . . . . . . . . 88 Ribamar FS – http://cursos.ribafs.org

Transcript of Cake CursoORIG

Page 1: Cake CursoORIG

Curso de CakePHP Página 1 /90

Curso de CakePHP

1 – Introdução . . . . . . . . . . . . . . . . 2 2 – Configurações . . . . . . . . . . . . . . . 6 3 – Convenções . . . . . . . . . . . . . . . 8 4 – Bake (Gerando aplicativos pela console) . . . . . . . . 12 5 – Model . . . . . . . . . . . . . . . . . 20 6 – Controller . . . . . . . . . . . . . . . . 22 7 – View . . . . . . . . . . . . . . . . . 25 8 – Action . . . . . . . . . . . . . . . . . 29 9 – Scaffold . . . . . . . . . . . . . . . . 33 10 – Validações . . . . . . . . . . . . . . . 37 11 – MVC . . . . . . . . . . . . . . . . . 40 12 – Menus . . . . . . . . . . . . . . . . 43 13 – CSS . . . . . . . . . . . . . . . . . 44 14 – JavaScript . . . . . . . . . . . . . . . 47 15 – Helpers . . . . . . . . . . . . . . . . 48 16 – Componentes . . . . . . . . . . . . . . . 51 17 – Routes . . . . . . . . . . . . . . . . 53 18 – Vendors . . . . . . . . . . . . . . . . 61 19 – Plugins . . . . . . . . . . . . . . . . 62 20 – Relacionamentos . . . . . . . . . . . . . . 67 21 – Dicas . . . . . . . . . . . . . . . . . 68 22 - Aplicativos de Exemplo

22.1 - Aplicativo Livros . . . . . . . . . . . . 69 22.2 - Aplicativo cake_olamundo . . . . . . . . . . 81 22.3 - Outros Exemplos . . . . . . . . . . . . 87

22 – Referências . . . . . . . . . . . . . . . 88

Ribamar FS – http://cursos.ribafs.org

Page 2: Cake CursoORIG

Curso de CakePHP Página 2 /90

Cake - Introdução

O que é CakePHP?

CakePHP é um framework de desenvolvimento rápido para PHP que fornece uma arquitetura extensível para desenvolvimento, manutenção e implantação de aplicativos. Usando padrões de projeto conhecidos como MVC e ORM com o paradigma das convenções sobre configurações, CakePHP reduz os custos de desenvolvimento e ajuda os desenvolvedores a escrever menos código.

Site oficial - http://cakephp.org

Desde que Ruby on Rails se tornou um popular framework, equipes de desenvolvedores tem criado clones do framework Rails ou Rails em várias linguagens: TurboGears para Python; Zend, Symfony, e muitos outros para PHP; Catalyst para Perl; e assim por diante. Com tantas opções, por que escolher CakePHP para seu projeto web?

Framework

Um framework pode ser definido como a planta baixa de onde todos os sistemas serão construídos, ou como uma forma que bolos, que padroniza a forma e o volume de todos os bolos criados com ela.

O framework enxerga cada tabela como uma classe, e cada registro da tabela como um objeto específico da classe

Alguns softwares como os CMS são muito simples de instalar e usar, até mesmo sem nenhuma documentação, como é o caso dos CMS.Já os frameworks, a exemplo do CakePHP, requerem que tomemos conhecimento de pelo menos algumas convenções que ele traz.Caso não sigamos essas convenções ele não fará muito por nós.Sem contar que os frameworks são softwares de um tipo que exigem mais conhecimento que os CMS.

Características do Cake

Cake tem como objetivo simplificar o processo de desenvolvimento para a construção de aplicações web provendo um método geral para organizar o banco de dados e outros recursos que reduzem a codificação. Embora esta abordagem geral da programação web seja em si uma característica importante do Cake, o seu repositório de outros recursos poderosos como validação embutida, listas de controle de acesso (ACLs), sanitização de dados, segurança e componentes de manipulação de sessão e cache de View fazem o Cake vale a pena para qualquer desenvolvedor sério.

Ribamar FS – http://cursos.ribafs.org

Page 3: Cake CursoORIG

Curso de CakePHP Página 3 /90

Características Principais

- Sem Configuração (com convenções) – Configure o banco e deixe a mágica iniciar- Extremamente Simples – Apenas veja o nome...Ele chama-se Cake/Bolo- Ativa e Amigável Comunidade – Junte-se a nós no #cakephp (IRC). Adoraríamos ajudar você a começar - Licença Flexível – Distribuído sob a licença MIT- Clean IP – Toda linha de código foi escrita pela equipe de desenvolvimento do CakePHP - Melhores Práticas – cobrindo segurança, autenticação e manipulação de session, além de muitas outras características- OO – Caso seja um programador OO experiente ou novato se sentirá confortável - Compatível com as versões 4 e 5 do PHP - CRUD Integrado para interação com o banco de dados- Aplicação scaffolding - Geração de código- Arquitetura MVC- Requisição de dispatcher com URL limpa, personalizada e rotas/routes - Validação embutida- Rápidos e flexíveis templates (Sintaxe PHP, com helpers) - View Helpers para AJAX, JavaScript, Forms HTML e mais- Email, Cookie, Security, Session e Request Handling Components - Flexível ACL - Sanitização de Dados- Flexível Caching - Localização- Trabalha a partir de qualquer diretório do site, com pouca ou nenhuma configuração do Apache envolvidas

Requisitos

PHP 4.3.2 ou superiorServidor Web Apache com o mod_rewrite

Tecnicamente um banco de dados não é obrigatório, mas nós imaginamos que a maioria das aplicações irão utilizar um. CakePHP suporta uma variedade de banco de dados:

- MySQL (4 ou superior) - PostgreSQL - Firebird DB2 - Microsoft SQL Server - Oracle - SQLite - ODBC - ADOdb

Como pode mudar de versão para versão (a atual é a 1.2.4.8284), confira no diretório: cake/libs/model/datasources/dbo:

Ribamar FS – http://cursos.ribafs.org

Page 4: Cake CursoORIG

Curso de CakePHP Página 4 /90

dbo_db2.php, dbo_firebird.php, dbo_mssql.php, dbo_mysql.php, dbo_mysqli.php, dbo_odbc.php, dbo_oracle.php, dbo_postgres.php, dbo_sqlite.php, dbo_sybase.php.

Estrutura original do diretório do cake:

cake/appcake/cakecake/vendorscake/index.phpcake/index_webroot.txtcake/README

Estrutura original do diretório app:

cake/app/configcake/app/controllerscake/app/localecake/app/modelscake/app/pluginscake/app/testscake/app/tmpcake/app/vendorscake/app/viewscake/app/webrootcake/app/index.php

A pasta app do CakePHP é onde normalmente você colocará sua aplicação em desenvolvimento. Vamos dar uma olhada mais de perto dentro desta pasta.

config Contém os arquivos de configuração. Detalhes das conexões ao banco de dados, bootstrapping, arquivos de configuração do núcleo e outros devem ser armazenados aqui.

controllers Contém os controladores da sua aplicação e seus componentes.

locale Guarda os arquivos com as strings para internacionalização.

models Contém os modelos, behaviors e datasources da sua aplicação.

plugins Contém os pacotes de plugins.

tmp Aqui é onde o CakePHP armazena os arquivos temporários. Os dados atuais são armazenados onde

Ribamar FS – http://cursos.ribafs.org

Page 5: Cake CursoORIG

Curso de CakePHP Página 5 /90

você tenha configurado o CakePHP, mas esta

pasta normalmente é usada para guardar a descrição dos modelos, logs e outras informações, como as das sessões.

vendors Qualquer classe ou biblioteca de terceiro deve ser armazenada aqui. Para fazer um acesso rápido e fácil, use a função vendors(). Você pode achar

que esta pasta é redundante, já que existe uma pasta com mesmo nome no nível superior da estrutura. Nós vamos ver diferenças entre estas duas pastas quando discutirmos sobre manipulação de múltiplas aplicações e sistemas mais complexos.

views Arquivos de apresentação devem vir aqui: elementos, páginas de erro, ajudantes, layouts e arquivos de visões.

webroot No modo de produção, esta pasta deve servir como a pasta raiz da sua aplicação. Dentro desta pasta são guardados os arquivos públicos, como

estilos CSS, imagens e arquivos de JavaScript.

cake - bolobaker - padeiro

Ribamar FS – http://cursos.ribafs.org

Page 6: Cake CursoORIG

Curso de CakePHP Página 6 /90

Cake - Configurações

Mesmo sendo focado em convenções ao invés de configurações, o Cake pode ter seu comportamento alterado através de alguns arquivos de configuração, que encontram-se na pasta config:

databasecorerouterdebugtraduçãotestesetc.

Vários Aplicativos num único CorePodemos configurar para que várias aplicações usem um único core do Cake.

- Todos os aplicativos devem ficar assim:

cakeapp1app2app3...

E cada um deles deve ter seu arquivo webroot/index.php alterado na linha com CAKE_CORE_INCLUDE_PATH, mudando para:define('CAKE_CORE_INCLUDE_PATH', dirname(dirname(dirname(__FILE__))));

Debug

O debug nas fases de desenvolvimento e de testes é muito importante, mas após a conclusão e entrega para o cliente devemos setar o debug para zero.

O Debug pode ser alterado manualmente no script config/core.php, na linha:Configure::write('debug', 0);O default é 2. Zero é sem debug (sem exibir as mensagens de erro ou alerta).

ou via código da nossa aplicação com:Configure::write('debug', '0');

Os possíveis são:0 = Production mode. No output. debug 1 = Show errors and warnings. 2 = Show errors, warnings, and SQL. 3 = Show errors, warnings, SQL, and complete controller dump.

Ribamar FS – http://cursos.ribafs.org

Page 7: Cake CursoORIG

Curso de CakePHP Página 7 /90

Tradução

Também podemos traduzir algumas coisas do CakePHP, como as mensagens de erro

Download:http://souagil.com.br/cake_i18n/pt_br.tar.gz

Adicionar linha ao final de config/core.php:Configure::write('Config.language', 'pt-br');

Adicionar Testes com SimpleTest

Download - http://www.simpletest.org/Descompacte e copie a pasta simpletest para a subpasta vendor do seu aplicativo.

Formatar Data e Hora

Trocar:<?php echo $cliente['Cliente']['created'] ?>

por:<?php echo $time->niceShort($cliente['Cliente']['created']) ?>

Ribamar FS – http://cursos.ribafs.org

Page 8: Cake CursoORIG

Curso de CakePHP Página 8 /90

Cake - Convenções

O Cake previlegia convenções ao invés de configurações.O que significa que seguindo as convenções estabelecidas o cake fará muito por nós.Não somos obrigados a seguir as convenções, mas perderemos muito com isso, pois teremos que fazer muito.

Apesar de tomar um pouco de tempo para aprender as convenções do CakePHP, você ganha tempo em um longo processo: seguindo as convenções, você ganha funcionalidades gratuitamente e livra-se de madrugadas de manutenção de arquivos de configuração. Convenções também fazem com que o sistema fique uniformemente desenvolvido, permitindo que outros desenvolvedores o ajudem mais facilmente, já que segue um padrão de trabalho.

Convenções no CakePHP têm sido produzidas por anos de experiência em desenvolvimento web e boas práticas. Apesar de sugerirmos que você use essas convenções enquanto desenvolve em CakePHP, devemos mencionar que muitos desses princípios são facilmente sobrescritos - algo que especialmente acontece quando trabalha-se com sistemas legados.

Convenções de arquivos e nome de classes

Em geral, nome dos arquivos são sublinhados, enquanto nome de classes são CamelCased, ou seja, primeiras letras das palavras em maiúsculo. A classe KissesAndHugsController pode ser encontrada no arquivo kisses_and_hugs_controller.php, por exemplo.

Porém, o nome da class e seu tipo não são necessariamente encontrados no nome do arquivo. A classe EmailComponent é encontrada no arquivo chamado email.php e a classe HtmlHelper é encontrada no arquivo html.php.

Convenções de modelo

Nome das classes de modelo devem ser no singular e CamelCased. Person, BigPerson e ReallyBigPerson são exemplos de nomes convencionados para modelos. Os nomes das tabelas correspondentes a modelos do CakePHP devem estar no plural e sublinhados. As tabelas para os modelos mencioados anteriormente devem ser people, big_people e really_big_people, respectivamente.

Chaves estrangeiras em relacionamentos do tipo temMuitos (hasMany), pertenceA (belongsTo) ou temUm (hasOne) são reconhecidos por padrão como o nome (no singular) do modelo relacionado, seguido por _id. Assim, se um padeiro temMuitos bolos, a tabela bolos referenciará a um padeiro na

tabela padeiros através da chave estrangeira padeiro_id.

Tabelas associativas, usadas em relações temEPertenceAMuitos (hasAndBelongsToMany) entre modelos, devem ser nomeadas depois dos modelos das tabelas que a compõem, em ordem alfabética (apples_zebras em vez de zebras_apples).

Todas as tabelas com as quais os modelos CakePHP interagem (exceto as tabelas associativas) exigem uma única chave primária para identificar unicamente cada linha. Se você deseja modelar

Ribamar FS – http://cursos.ribafs.org

Page 9: Cake CursoORIG

Curso de CakePHP Página 9 /90

uma tabela que não tem uma chave primária de um único campo, como as linhas de nossa tabela associativa posts_tags, a convenção do CakePHP é de que uma chave primária de um único campo deve ser adicionada à tabela.

CakePHP não suporta chaves primárias compostas. No caso de você querer manipular diretamente os dados das tabelas associativas, isso significa que você precisa usar chamadas a consultas diretas, ou adicionar um campo como chave primária para ser capaz de atuar nela como em um modelo normal. Por exemplo:

CREATE TABLE posts_tags ( id INT(10) NOT NULL AUTO_INCREMENT, post_id INT(10) NOT NULL, tag_id INT(10) NOT NULL, PRIMARY KEY(id));

Convenções de controlador

O nome das classes de controladores são no plural, CamelCased e no final 'Controller'. PeopleController, BigPeopleController e ReallyBigPeopleController são todos os exemplos convencionais para nome de controladores.

A primeira função que você deve escrever em um controlador deve ser o método index(). Quando alguém requisita um controlador sem ação, o behavior padrão é renderizar o método index() do controlador. Por exemplo, a requisição para http://www.exemplo.com.br/apples/ mapeia para a chamada da função index() do ApplesController, assim como

http://www.exemplo.com.br/apples/view

mapeia para a chamada da função view() no ApplesController.

Você também pode alterar a visibilidade das funções do controlador em CakePHP colocando sublinhados na frente do nome das funções. Se a função do controlador estiver com sublinhado na frente, a função não será disponibilizada para acesso da web através do dispatcher, mas estará disponível para uso interno.Por exemplo:

<?php class NewsController extends AppController { function latest() { $this->_findNewArticles(); } function _findNewArticles() { //Logic to find latest news articles } } ?>

Apesar da página

http://www.example.com/news/latest/

possa ser acessada pelo usuário normalmente, alguém que tente acessar a página

http://www.example.com/news/_findNewArticles/

Ribamar FS – http://cursos.ribafs.org

Page 10: Cake CursoORIG

Curso de CakePHP Página 10 /90

receberá um erro porque a função é precedida de um sublinhado.

Considerações sobre URLs para Nomes de Controladores

Como você acabou de ver, controladores de uma única palavra são mapeados facilmente para uma URL simples em letras minúsculas. Por exemplo, ApplesController (que seria definida em um arquivo de nome 'apples_controller.php') é acessada a partir de http://example.com/apples. Controladores de múltiplas palavras mapeados para URLs em camelBacked mantendo a forma plural. Por exemplo, RedApplesController (red_apples_controller.php) seria mapeada para

http://example.com/redApples

e OperatingSystemsController

(operating_systems_controller.php)

seria mapeada para

http://example.com/operatingSystems.

Convenções de visão

Os arquivos de template de visões são nomeados depois das funções de controladores que mostram esses arquivos de template, na forma com sublinhados. A função getReady() da classe PeopleController irá procurar pelo template da visão em /app/views/people/get_ready.ctp. O modelo básico é /app/views/controller/underscored_function_name.ctp. Nomeando os pedaços da aplicação usando as convenções do CakePHP, você ganha funcionalidades sem luta e sem amarras de configuração. Aqui o exemplo final que vincula as associações:

Tabela no banco de dados: 'people' Classe do Modelo: 'Person', encontrada em /app/models/person.php Classe do Controlador: 'PeopleController', encontrado em /app/controllers/people_controller.php Template da Visão: encontrado em /app/views/people/index.ctp

Usando estas convenções, CakePHP sabe que a requisição para http://www.exemplo.com.br/people/

mapeia para a chamada da função index() do PeopleController, onde o modelo Person é automaticamente disponibilizado (e automaticamente associado à tabela 'people' no banco de dados), e renderiza isso para o arquivo. Nenhuma destas relações foram configuradas por qualquer meio que não seja através da criação de classes e arquivos que você precise criar em algum lugar. Agora que você leu os fundamentos do CakePHP, você pode tentar seguir o tutorial de como fazer um Blog em CakePHP, para ver como as coisas são feitas juntas.

Resumo

- bancos de dados – minúsculas e singular- tabelas – minúsculas e plural

Ribamar FS – http://cursos.ribafs.org

Page 11: Cake CursoORIG

Curso de CakePHP Página 11 /90

- chave primária de todas as tabelas deve ser chamada de id (opcionalmente)- chaves estrangeiras devem ser chamadas de tabelanome_id, exemplo blog_id (nome tabela no singular)- nomes de modelos CamelCase e arquivos em minúsculas e singular e sublinhado para separar palavras compostas: meu_post.php e MeuPost - controladores – arquivo: minúsculas e plural. Classe CamelCase com Controller anexado, como: PostsController. Nomes de arquivos com sublinhado em palavras compostas: posts_controller.php

Associações entre Tabelas (relacionamentos)hasOne: possui um hasMany: possui muitos belongsTo: pertence a hasAndBelongsToMany: tem e pertence a muitos

O Cake automaticamente adiciona o tempo para campos que são do timo datetime e são nomeados 'created' ou 'modified'.

Ribamar FS – http://cursos.ribafs.org

Page 12: Cake CursoORIG

Curso de CakePHP Página 12 /90

Criar Aplicativos em Cake com o Bake

Operações de CRUD com o script bake.

Após a utilização do bake temos um "esqueleto" de aplicação. Agora podemos customizar os códigos gerados para criarmos a aplicação final.

- Copiar a pasta appPrimeiro vamos copiar a pasta app para estoque

- Criar o bancoDepois vamos criar um banco chamado estoque (MySQL), no phpMydmin importe este script aqui.O banco coterá cinco tabelas: clientes, funcionarios, produtos, pedidos e pedido_itens

- RelacionamentosA tabela pedidos está relacionada com clientes e fun cionarios, portanto tem dois campos: cliente_id e funcionario_idA tabela pedido_itens se relaciona com pedidos pelo campo pedido_id.

- Criar aplicativo com BakeVamos usar o bake para criar o aplicativo através da console.

- Configurar para usar vários aplicativos com um único coreConfigurar estoque/webroot/index.php mudar a linha com define('CAKE_CORE_INCLUDE_PATH' para:define('CAKE_CORE_INCLUDE_PATH', dirname(dirname(dirname(__FILE__))));

- Acessar a pasta consolecd /home/ribafs/public_html/cake/cake/console

ou

cd c:\xampplite\htdocs\cake\cake\console

1) Criar uma Configuração de banco

./cake bake -app estoque

Receberá a tela:

Welcome to CakePHP v1.2.4.8284 Console

Ribamar FS – http://cursos.ribafs.org

Page 13: Cake CursoORIG

Curso de CakePHP Página 13 /90

---------------------------------------------------------------App : estoquePath: /home/ribafs/backup/public_html/cake/estoque---------------------------------------------------------------Your database configuration was not found. Take a moment to create one.---------------------------------------------------------------Database Configuration:---------------------------------------------------------------Name: [default] >

Obs.: As opções entre colchetes como [default] acima são as opções sugeridas e default, basta teclar Enter se queremos aceitá-la.

Tecle Enter para aceitar default como o nome da configuração do banco.

2) Selecionar o SGDBDriver: (db2/firebird/mssql/mysql/mysqli/odbc/oracle/postgres/sqlite/sybase) [mysql] >

Apenas tecle Enter para aceitar o mysql

3) Tipo de conexãoPersistent Connection? (y/n) [n] >

Enter para aceitar não persistente

4) Host do BancoDatabase Host: [localhost] >

Enter para aceitar localhost ou digite o nome do seu host

5) PortaPort? [n] >

Enter para aceitar a porta default

6) UsuárioUser: [root] >

Enter para aceitar

7) SenhaPassword:

Ribamar FS – http://cursos.ribafs.org

Page 14: Cake CursoORIG

Curso de CakePHP Página 14 /90

>

Enter para aceitar sem senha ou digite a senha

8) Nome do bancoDatabase Name: [cake] >

Digite estoque e tecle Enter

9) Prefixo das tabelasTable Prefix? [n] >

Enter para aceitar sem prefixo ou digite o prefixo

10) Codificação das tabelasTable encoding? [n] > Enter para aceitar a default ou entre com a codificação (exemplo: utf8)

Então aparece o relatório:

---------------------------------------------------------------The following database configuration will be created:---------------------------------------------------------------Name: defaultDriver: mysqlPersistent: falseHost: localhostUser: rootPass: ******Database: estoqueEncoding: utf8---------------------------------------------------------------Look okay? (y/n) [y] >

Tecle enter para aceitar.

11) Outra configuração de banco?Do you wish to add another database configuration? [n] >

Enter para encerrar.

Então ele criará o arquivo:Creating file /home/ribafs/public_html/cake/estoque/config/database.php

Ribamar FS – http://cursos.ribafs.org

Page 15: Cake CursoORIG

Curso de CakePHP Página 15 /90

Wrote /home/ribafs/public_html/cake/estoque/config/database.php

Ao executar novamente o comando:./cake bake -app estoque

Aparecerá o menu:

Welcome to CakePHP v1.2.4.8284 Console---------------------------------------------------------------App : estoquePath: /home/ribafs/backup/public_html/cake/estoque---------------------------------------------------------------Interactive Bake Shell---------------------------------------------------------------[D]atabase Configuration[M]odel[V]iew[C]ontroller[P]roject[Q]uitWhat would you like to Bake? (D/M/V/C/P/Q) >

Vamos criar na seguinte ordem para cada tabela: model, controller e view

Criar o Model para a tabela Clientes

1) Tecle m e Enter (Model)

Bake ModelPath: /home/ribafs/backup/public_html/cake/estoque/models/---------------------------------------------------------------Possible Models based on your current database:1. Cliente2. Funcionario3. PedidoIten4. Pedido5. ProdutoEnter a number from the list above, type in the name of another model, or 'q' to exit [q] >

2) Tecle 1 e Enter

Would you like to supply validation criteria for the fields in your model? (y/n) [y] >

3) Validação

Ribamar FS – http://cursos.ribafs.org

Page 16: Cake CursoORIG

Curso de CakePHP Página 16 /90

Tecle n e Enter (não vamos validar agora)

4) Nome do campo chaveWhat is the primaryKey? [cliente] >

No nosso caso está correto, apenas tecle Enter

5) RelacionamentosWould you like to define model associations (hasMany, hasOne, belongsTo, etc.)? (y/n) [y] >

n e Enter

6) Correto?---------------------------------------------------------------The following Model will be created:---------------------------------------------------------------Name: ClientePrimary Key: clienteAssociations:---------------------------------------------------------------Look okay? (y/n) [y] >

Enter

7) Baking model class for Cliente...

Creating file /home/ribafs/backup/public_html/cake/estoque/models/cliente.phpWrote /home/ribafs/backup/public_html/cake/estoque/models/cliente.php

Baking test fixture for Cliente...

Creating file /home/ribafs/backup/public_html/cake/estoque/tests/fixtures/cliente_fixture.phpWrote /home/ribafs/backup/public_html/cake/estoque/tests/fixtures/cliente_fixture.php

Baking unit test for Cliente...

Creating file /home/ribafs/backup/public_html/cake/estoque/tests/cases/models/cliente.test.phpWrote /home/ribafs/backup/public_html/cake/estoque/tests/cases/models/cliente.test.php

Criando o Model para FuncionariosAgora de forma mais resumida

1) m e Enter

Ribamar FS – http://cursos.ribafs.org

Page 17: Cake CursoORIG

Curso de CakePHP Página 17 /90

2) 2 para funcionarios e Enter

3) n e Enter (sem validação)

4) Chave primária - Enter para funcionario

5) Relacionamentos - n e Enter

6) Tudo OK? - Enter

Criar o Model para ProdutosDe forma semelhante crie o model para produtos.

Criar o Model para Pedidos

Esse é diferente, pois tem relacionamentos com cliente e funcionários

1) m e Enter

2) 4 e Enter para pedido

3) n e Enter para validação

4) pedido como chave

5) RelacionamentoWould you like to define model associations (hasMany, hasOne, belongsTo, etc.)? (y/n) [y] >

Enter para sim.

One moment while the associations are detected.---------------------------------------------------------------Please confirm the following associations:---------------------------------------------------------------Pedido belongsTo Cliente? (y/n) [y] >

Enter para aceitar a relação com Cliente

Pedido belongsTo Funcionario? (y/n) [y] >

Enter para aceitar a relação com funcionario.

n para PedidoIten nas duas sugestões.

Ribamar FS – http://cursos.ribafs.org

Page 18: Cake CursoORIG

Curso de CakePHP Página 18 /90

Enter para não adicionais relações.

Relato:---------------------------------------------------------------The following Model will be created:---------------------------------------------------------------Name: PedidoPrimary Key: pedidoAssociations:Pedido belongsTo ClientePedido belongsTo Funcionario---------------------------------------------------------------Look okay? (y/n) [y] >

Enter para aceitar.

Criar o modelo da tabela pedido_itensQue se relaciona apenas com pedidos.

Criar o Controller para Clientes

1) c e Enter

2) 1 e Enter

Would you like to build your controller interactively? (y/n) [y] > n

3) n para controller interativo

4) Incluir métodos básicosWould you like to include some basic class methods (index(), add(), view(), edit())? (y/n) [y] >

Enter para aceitar

5) Would you like to create the methods for admin routing? (y/n) [y] >

n e Enter

6) Relato:---------------------------------------------------------------The following controller will be created:---------------------------------------------------------------Controller Name: Clientes

Ribamar FS – http://cursos.ribafs.org

Page 19: Cake CursoORIG

Curso de CakePHP Página 19 /90

---------------------------------------------------------------Look okay? (y/n) [y] >

Enter para aceitar

Criar os Controllers Funcionarios, PedidoItens, Pedidos e Produtos de forma semelhante

Criar a view para a tabela Clientes

1) v e Enter

2) 1 e Enter

3) Criar scaffolds para a view:Would you like to create some scaffolded views (index, add, view, edit) for this controller?NOTE: Before doing so, you'll need to create your controller and model classes (including associated models). (y/n) [n] >

y e Enter

n para não criar admin

De forma semenlhante criar as demais.

Procurando ID e sobrescrevendo pelas respectivas chaves primárias nas views.

Editar a views cake/estoque/views/clientes/index.ctp

Procurar por id e sobrescrever com cliente.

Assim com as demais views.

Com isso temos um aplicativo com muitos bons recursos: CRUD, paginação, CSS, etc.

Para criar um novo projeto com bake use:./cake bake -p nomeprojeto

Para ir direto para model, controller ou view:

./cake bake -app nomeapp model

./cake bake -app nomeapp controller

Ribamar FS – http://cursos.ribafs.org

Page 20: Cake CursoORIG

Curso de CakePHP Página 20 /90

./cake bake -app nomeapp view

Cake - Models

Os models formam a camada da letra M do MVC, aquele que vai ao banco e conversa com os controllers atendendo as suas solicitações e devolvendo o resultado recebido do banco de dados.

Modelo simples:

cake/ola/models/cliente.php

<?php class Cliente extends AppModel { var $name = 'Cliente'; } ?>

Todos os models em Cake tem a função find() usada para buscar os registros da tabela do model.Passando parâmetros para essa função nós podemos controlar os registros a buscar.

Um Model com validação dos campos (gerado pelo Bake):

<?phpclass Produto extends AppModel {

var $name = 'Produto';var $primaryKey = 'produto';var $validate = array('produto' => array('numeric'),'descricao' => array('notempty'),'unidade' => array('notempty'),'data_cadastro' => array('date'));

}?>

Model com relacionamento com clientes e funcionarios:

<?phpclass Pedido extends AppModel {

var $name = 'Pedido';var $primaryKey = 'pedido';

//The Associations below have been created with all possible keys, those that are not needed can be

Ribamar FS – http://cursos.ribafs.org

Page 21: Cake CursoORIG

Curso de CakePHP Página 21 /90

removed

var $belongsTo = array('Cliente' => array('className' => 'Cliente','foreignKey' => 'cliente_id','conditions' => '','fields' => '','order' => ''),'Funcionario' => array('className' => 'Funcionario','foreignKey' => 'funcionario_id','conditions' => '','fields' => '','order' => ''));

}?>

Uma boa pedida para aprender sobre os Models na prática é criar aplicativos com o Bake na linha de comando e depois analisar o código gerado.

Ribamar FS – http://cursos.ribafs.org

Page 22: Cake CursoORIG

Curso de CakePHP Página 22 /90

Cake - Controllers

O controller representa a letra C do VMC e é a camada de processamento em PHP, onde existem os for, if, while, etc. Ele recebe as requisições de uma View e manda para o respectivo Model. Ao receber o resultado do Model ele devolve para a Views que pediu.

Em um aplicativo de posts...

Cada ação do controller deve pegar os posts no banco e retornar para a view.A view deve então exibir todos os posts como lista.

Controllers simples:

cake/ola/controllers/clientes_controller.php

<?phpclass ClientesController extends AppController{var $name = 'Clientes'; }?>

Action

Toda função pública dentro da classe controller é chamada de action.Esta action visualizará todos os clientes com a view index.ctp

<?phpclass ClientesController extends AppController{var $name = 'Clientes';

function index() {$this->set('clientes', $this->Cliente->find('all'));}}?>

Controllers e ViewsUm controller pode ter muitos actions e cada action tem sua view. Portanto um controller pode ter muitas views.Cake guarda todas as views de um controller em um diretório separado (do mesmo nome do controller).

Agora um controller mais sofisticado:

<?php

Ribamar FS – http://cursos.ribafs.org

Page 23: Cake CursoORIG

Curso de CakePHP Página 23 /90

class PedidosController extends AppController {

var $name = 'Pedidos';var $helpers = array('Html', 'Form');

function index() {$this->Pedido->recursive = 0;$this->set('pedidos', $this->paginate());}

function view($id = null) {if (!$id) {$this->Session->setFlash(__('Invalid Pedido.', true));$this->redirect(array('action'=>'index'));}$this->set('pedido', $this->Pedido->read(null, $id));}

function add() {if (!empty($this->data)) {$this->Pedido->create();if ($this->Pedido->save($this->data)) {$this->Session->setFlash(__('The Pedido has been saved', true));$this->redirect(array('action'=>'index'));} else {$this->Session->setFlash(__('The Pedido could not be saved. Please, try again.', true));}}$clientes = $this->Pedido->Cliente->find('list');$funcionarios = $this->Pedido->Funcionario->find('list');$this->set(compact('clientes', 'funcionarios'));}

function edit($id = null) {if (!$id && empty($this->data)) {$this->Session->setFlash(__('Invalid Pedido', true));$this->redirect(array('action'=>'index'));}if (!empty($this->data)) {if ($this->Pedido->save($this->data)) {$this->Session->setFlash(__('The Pedido has been saved', true));$this->redirect(array('action'=>'index'));} else {$this->Session->setFlash(__('The Pedido could not be saved. Please, try again.', true));}}if (empty($this->data)) {$this->data = $this->Pedido->read(null, $id);

Ribamar FS – http://cursos.ribafs.org

Page 24: Cake CursoORIG

Curso de CakePHP Página 24 /90

}$clientes = $this->Pedido->Cliente->find('list');$funcionarios = $this->Pedido->Funcionario->find('list');$this->set(compact('clientes','funcionarios'));}

function delete($id = null) {if (!$id) {$this->Session->setFlash(__('Invalid id for Pedido', true));$this->redirect(array('action'=>'index'));}if ($this->Pedido->del($id)) {$this->Session->setFlash(__('Pedido deleted', true));$this->redirect(array('action'=>'index'));}}

}?>

Ribamar FS – http://cursos.ribafs.org

Page 25: Cake CursoORIG

Curso de CakePHP Página 25 /90

Cake - Views

View representa a letra V do MVC.

As views são responsáveis por receber as requisições do cliente e mandar para o controller. O controller manda para o model que devolve ao controller. Então o controller devolve para a view, que renderiza o resultado para o cliente.

Lembrando que a view não deve ter nenhum contato direto com o model mas sempre passar pelo controller.

Convenção - Todo action dos controllers e sua correspondente view tem o mesmo nome.Quando o action finaliza a execução a view é renderizada.

View simples:

cake/ola/views/clientes/index.ctp

<h2>Clientes</h2><?php if(empty($clientes)): ?>Nenum cliente encontrado<?php else: ?><table><tr><th>ID</th><th>Nome</th><th>Ações</th></tr><?php foreach ($clientes as $cliente): ?><tr><td><?php echo $cliente['Cliente']['id'] ?></td><td><?php echo $cliente['Cliente']['nome'] ?></td><td><!-- actions on tasks will be added later --></td></tr><?php endforeach; ?></table><?php endif; ?>

Agora chamar no navegador assim:

http://localhost/cake/ola/clientes

Ribamar FS – http://cursos.ribafs.org

Page 26: Cake CursoORIG

Curso de CakePHP Página 26 /90

Adicionar Registro

Adicionar view views/clientes/add.ctp correspondente ao action add:

Adicionar a view:cake/ola/views/clientes/add.ctp

<?php echo $form->create('Cliente');?><fieldset><legend>Adicionar novo Cliente</legend><?phpecho $form->input('ID');echo $form->input('Nome');?></fieldset><?php echo $form->end('Adicionar');?>

Agora chame com o navegador:

http://localhost/cake/ola/clientes/add

As views sempre tem a extensão ctp (Cake Template Pages).

Link para Edição (adicionado logo após o comentário <!-- actions on tasks will be added later -->)

<h2>Clientes</h2><?php if(empty($clientes)): ?>Nenum cliente encontrado<?php else: ?><table><tr><th>ID</th><th>Nome</th><th>Ações</th></tr><?php foreach ($clientes as $cliente): ?><tr><td><?php echo $cliente['Cliente']['id'] ?></td><td><?php echo $cliente['Cliente']['nome'] ?></td><td><!-- actions on tasks will be added later --><?php echo $html->link('Editar', array('action'=>'edit', $cliente['Cliente']['id'])); ?></td>

Ribamar FS – http://cursos.ribafs.org

Page 27: Cake CursoORIG

Curso de CakePHP Página 27 /90

</tr><?php endforeach; ?></table><?php endif; ?>

<?php echo $html->link('Adicionar Cliente', array('action'=>'add')); ?>

Uma view mais sofisticada (gerada pelo Bake):

<div class="clientes index"><h2><?php __('Clientes');?></h2><p><?phpecho $paginator->counter(array('format' => __('Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%', true)));?></p><table cellpadding="0" cellspacing="0"><tr><th><?php echo $paginator->sort('cliente');?></th><th><?php echo $paginator->sort('cpf');?></th><th><?php echo $paginator->sort('nome');?></th><th><?php echo $paginator->sort('credito_liberado');?></th><th><?php echo $paginator->sort('data_nasc');?></th><th><?php echo $paginator->sort('email');?></th><th class="actions"><?php __('Actions');?></th></tr><?php$i = 0;foreach ($clientes as $cliente):$class = null;if ($i++ % 2 == 0) {$class = ' class="altrow"';}?><tr<?php echo $class;?>><td><?php echo $cliente['Cliente']['cliente']; ?></td><td><?php echo $cliente['Cliente']['cpf']; ?></td><td><?php echo $cliente['Cliente']['nome']; ?></td>

Ribamar FS – http://cursos.ribafs.org

Page 28: Cake CursoORIG

Curso de CakePHP Página 28 /90

<td><?php echo $cliente['Cliente']['credito_liberado']; ?></td><td><?php echo $cliente['Cliente']['data_nasc']; ?></td><td><?php echo $cliente['Cliente']['email']; ?></td><td class="actions"><?php echo $html->link(__('View', true), array('action' => 'view', $cliente['Cliente']['cliente'])); ?><?php echo $html->link(__('Edit', true), array('action' => 'edit', $cliente['Cliente']['cliente'])); ?><?php echo $html->link(__('Delete', true), array('action' => 'delete', $cliente['Cliente']['cliente']), null, sprintf(__('Are you sure you want to delete # %s?', true), $cliente['Cliente']['cliente'])); ?></td></tr><?php endforeach; ?></table></div><div class="paging"><?php echo $paginator->prev('<< '.__('previous', true), array(), null, array('class'=>'disabled'));?>| <?php echo $paginator->numbers();?><?php echo $paginator->next(__('next', true).' >>', array(), null, array('class' => 'disabled'));?></div><div class="actions"><ul><li><?php echo $html->link(__('New Cliente', true), array('action' => 'add')); ?></li><li><?php echo $html->link(__('List Pedidos', true), array('controller' => 'pedidos', 'action' => 'index')); ?> </li><li><?php echo $html->link(__('New Pedido', true), array('controller' => 'pedidos', 'action' => 'add')); ?> </li></ul></div>

Ribamar FS – http://cursos.ribafs.org

Page 29: Cake CursoORIG

Curso de CakePHP Página 29 /90

Cake - Actions

Os Actions como o nome sugere, representam ações do usuário, que as emitem pelas views e são processadas nos controllers.

Cada ação do usuário é representada por uma função no controller e esta função deve ter o mesmo nome da view.

Exemplo: index.ctp é a view que é atendida pelo action index() no controller.

Actions são funções públicas nas classes dos Controllers.

Exemplo da action index() que corresponde à view de nome semelhante (index.ctp):

<?phpclass ClientesController extends AppController{var $name = 'Clientes';

function index() {$this->set('clientes', $this->Cliente->find('all'));}}?>

Action para adicionar registros

Para isso precisaremos adicionar uma variável (array $helpers) e uma função add() ao controller, como também adicionar uma view à pastaclientes, de nome add.ctp.

var $helpers = array('Html', 'Form');

function add() {if (!empty($this->data)) {$this->Cliente->create();if ($this->Cliente->save($this->data)) {$this->Session->setFlash('Cliente foi adicionado');$this->redirect(array('action'=>'index'), null, true);} else {$this->Session->setFlash('Cliente não adicionado. Tente novamente.');}}}

Adicionando Registros

Ribamar FS – http://cursos.ribafs.org

Page 30: Cake CursoORIG

Curso de CakePHP Página 30 /90

Para isso precisamos adicionar um action (edit) ao controller e uma view para este action (views/clientes/edit.ctp).

function edit($id = null) {if (!$id) {$this->Session->setFlash('Cliente Inválido');$this->redirect(array('action'=>'index'), null, true);}if (empty($this->data)) {$this->data = $this->Cliente->find(array('id' => $id));} else {if ($this->Cliente->save($this->data)) {$this->Session->setFlash('O Cliente foi salvo!');$this->redirect(array('action'=>'index'), null, true);} else {$this->Session->setFlash('O Cliente não pôde ser salvo. Favor tentar novamente.');}}}

Excluindo Registros

Para isso devemos adicionar um action ao controle chamado delete() correspondente e uma linha na view index.ctp

function delete($id = null) {if (!$id) {$this->Session->setFlash(__('Invalid id for Cliente', true));$this->redirect(array('action'=>'index'));}if ($this->Cliente->del($id)) {$this->Session->setFlash(__('Cliente deleted', true));$this->redirect(array('action'=>'index'));}}

Editar a view index.ctp e adicionar a linha com o delete:

<td class="actions"><?php echo $html->link(__('View', true), array('action' => 'view', $cliente['Cliente']['cliente'])); ?><?php echo $html->link(__('Edit', true), array('action' => 'edit', $cliente['Cliente']['cliente'])); ?><?php echo $html->link(__('Delete', true), array('action' => 'delete', $cliente['Cliente']['cliente']), null, sprintf(__('Are you sure you want to delete # %s?', true), $cliente['Cliente']['cliente'])); ?></td>

Ou seja, neste caso, não criamos mais uma views, mas apenas uma linha para o action delete().

Ribamar FS – http://cursos.ribafs.org

Page 31: Cake CursoORIG

Curso de CakePHP Página 31 /90

Veja agora todos os actions comuns para a tabela clientes, no controller clientes.php e classe Clientes:

<?php

class ClientesController extends AppController {

var $name = 'Clientes';var $helpers = array('Html', 'Form');

function index() {$this->Cliente->recursive = 0;$this->set('clientes', $this->paginate());}

function view($id = null) {if (!$id) {$this->Session->setFlash(__('Invalid Cliente.', true));$this->redirect(array('action'=>'index'));}$this->set('cliente', $this->Cliente->read(null, $id));}

function add() {if (!empty($this->data)) {$this->Cliente->create();if ($this->Cliente->save($this->data)) {$this->Session->setFlash(__('The Cliente has been saved', true));$this->redirect(array('action'=>'index'));} else {$this->Session->setFlash(__('The Cliente could not be saved. Please, try again.', true));}}}

function edit($id = null) {if (!$id && empty($this->data)) {$this->Session->setFlash(__('Invalid Cliente', true));$this->redirect(array('action'=>'index'));}if (!empty($this->data)) {if ($this->Cliente->save($this->data)) {$this->Session->setFlash(__('The Cliente has been saved', true));$this->redirect(array('action'=>'index'));} else {$this->Session->setFlash(__('The Cliente could not be saved. Please, try again.', true));}}

Ribamar FS – http://cursos.ribafs.org

Page 32: Cake CursoORIG

Curso de CakePHP Página 32 /90

if (empty($this->data)) {$this->data = $this->Cliente->read(null, $id);}}

function delete($id = null) {if (!$id) {$this->Session->setFlash(__('Invalid id for Cliente', true));$this->redirect(array('action'=>'index'));}if ($this->Cliente->del($id)) {$this->Session->setFlash(__('Cliente deleted', true));$this->redirect(array('action'=>'index'));}}?>

Ribamar FS – http://cursos.ribafs.org

Page 33: Cake CursoORIG

Curso de CakePHP Página 33 /90

Cake - Scaffold

Usando Scaffold no CakePHP

O scaffold no cake cria um CRUD rapidamente para manipulação de uma tabela.

As ações do Scaffoldo são nomeadas como: index(), add(), edit(), view(), and delete().

Podemos deixar as ações de CRUD do scaffold quando não desejamos gerar código manualmente.

Copiar a pasta appVamos copiar a pasta app do cake para scaffold

Configurar o banco de dadosConfigurar scaffold/config/database.php

Configurar para vários aplicativos usarem o mesmo core do CakeConfigurar scaffold/webroot/index.php na linha com define('CAKE_CORE_INCLUDE_PATH' para:define('CAKE_CORE_INCLUDE_PATH', dirname(dirname(dirname(__FILE__))));

Criar tabelacreate table clientes(id int not null auto_increment primary key,nome char(45) not null);

INSERT INTO clientes (id, nome) VALUES (1,'Joao Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (2,'Roberto Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (3,'Antônio Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (4,'Carlos Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (5,'Otoniel Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (6,'Helena Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (7,'Flávio Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (8,'Joana Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (9,'Francisco Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (10,'Jorge Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (11,'Pedro Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (12,'Ribamar Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (13,'Tiago Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (14,'Elias Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (15,'Marcos Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (16,'Ricardo Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (17,'Rômulo Pereira Brito');

Ribamar FS – http://cursos.ribafs.org

Page 34: Cake CursoORIG

Curso de CakePHP Página 34 /90

INSERT INTO clientes (id, nome) VALUES (18,'Henrique Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (19,'Francis Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (20,'Otávio Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (21,'Rogério Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (22,'Jurandir Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (23,'Raquél Pereira Brito');

Criar o model:cake/scaffold/models/cliente.php

<?phpclass Cliente extends AppModel{var $name = 'Cliente';}?>

Criar o controller:cake/scaffold/controllers/clientes_controller.php

<?phpclass ClientesController extends AppController{var $scaffold;}?>

Apontar o Firefox para o controller:http://localhost/cake/scaffold/clientes

Pronto, temos um CRUD, com estilo e paginação.

Scaffold com tabelas relacionadas

Tabelas jogadores e equipes

create table equipes(id int not null auto_increment primary key,nome char(45) not null);

create table jogadores(id int not null auto_increment primary key,nome char(45) not null,

Ribamar FS – http://cursos.ribafs.org

Page 35: Cake CursoORIG

Curso de CakePHP Página 35 /90

posicao char(25) not null,equipe_id int);

Detalhe: na tabela jogadores devemos ter um campo para relacionar com a equipes, no caso temos equipe_id.Este campo segue a convenção do Cake: nometabelasingular_id

Criar os controllerscake/scaffold/controllers/jogadores_controller.php

<?phpclass JogadoresController extends AppController{var $scaffold;}?>

cake/scaffold/controllers/equipes_controller.php

<?phpclass EquipesController extends AppController{var $scaffold;}?>

Criando os Models

cake/scaffold/models/jogador.php

<?phpclass Jogador extends AppModel{var $name = 'Jogador';

var $belongTo = array('Equipe' =>array('className' => 'Equipe','conditions' => '','order' => '','foreignKey' => 'equipe_id'));}?>

cake/scaffold/models/equipe.php

Ribamar FS – http://cursos.ribafs.org

Page 36: Cake CursoORIG

Curso de CakePHP Página 36 /90

<?phpclass Equipe extends AppModel{var $name = 'Equipe';}?>

Abrir no navagador:http://localhost/cake/scaffold/equipes

e

http://localhost/cake/scaffold/jogadores

Original de W.Jason Gilmore - http://www.wjgilmore.com

Ribamar FS – http://cursos.ribafs.org

Page 37: Cake CursoORIG

Curso de CakePHP Página 37 /90

Cake - Validações

Validar como Não Vazio

Vamos validar o campo nome para não aceitar vazio.

Editar o model e adicionar:

var $validate = array('nome' => array('rule' => VALID_NOT_EMPTY));

A validação é por campo.Uma boa idéia é gerar um aplicativo com o bake e ver como ele gera o código da validação no model.

Agora uma validação que inclui relacionamento:

<?phpclass Pedido extends AppModel {

var $name = 'Pedido';var $primaryKey = 'pedido';

//The Associations below have been created with all possible keys, those that are not needed can be removed

var $belongsTo = array('Cliente' => array('className' => 'Cliente','foreignKey' => 'cliente_id','conditions' => '','fields' => '','order' => ''),'Funcionario' => array('className' => 'Funcionario','foreignKey' => 'funcionario_id','conditions' => '','fields' => '','order' => ''));

}?>

Ribamar FS – http://cursos.ribafs.org

Page 38: Cake CursoORIG

Curso de CakePHP Página 38 /90

Vejamos os vários tipos de validação embutida que o Cake oferece (via Bake):

Você deseja fornecer critérios de validação para os campos de seu model? (y/n) [y] > Qual é a primaryKey? [cliente] >

Field: clienteType: integer---------------------------------------------------------------Please select one of the following validation options:---------------------------------------------------------------1 - alphaNumeric2 - between3 - blank4 - boolean5 - cc6 - comparison7 - custom8 - date9 - decimal10 - email11 - equalTo12 - extension13 - file14 - inList15 - ip16 - maxLength17 - minLength18 - money19 - multiple20 - notEmpty21 - numeric22 - phone23 - postal24 - range25 - ssn26 - time27 - url28 - userDefined29 - Do not do any validation on this field.... or enter in a valid regex validation string.

[21] >

Veja que quando concordamos que queremos validar ele mostra o primeiro campo e já nos sugere um tipo de validação.

Ribamar FS – http://cursos.ribafs.org

Page 39: Cake CursoORIG

Curso de CakePHP Página 39 /90

No exemplo acima o campo cliente e integer e o Bake sugere validar como 21, que representa numeric.Claro que podemos mudar para outro da lista, mas isso já ajuda quando não sabemos o que fazer.

Ribamar FS – http://cursos.ribafs.org

Page 40: Cake CursoORIG

Curso de CakePHP Página 40 /90

Cake - MVC

CakePHP e MVC

O típico fluxo de um script em PHP (figura abaixo):1. O cliente envia uma requisição para um script PHP digitando uma URL ou clicando em um link de algum tipo.2. O script processa os dados e então envia a requisição do banco de dados diretamente para o banco de dadps.3. O script recebe qualquer saída do banco de dados e processa os dados.4. O script gera a saída e envia esta para o navegador do cliente.

Típico fluxo com MVC

MVC pode variar, dependendo do framework com que você está trabalhando, mas geralmente ele trabalha da seguinte maneira (veja figura abaixo):

1. O cliente envia uma requisição de página para o aplicativo, digitando a URL ou clicando em um link de algum tipo. Por convenção uma URL típica é estruturada assim:http://{Domain}.com/{Application}/{Controller}/{Action}/{Parameter 1, etc.}

2. O script expedidor/dispatcher analisa a estrutura da URL e determina qual controller executará. Ele também passa todas as ações e parâmetros para o controlador. 3. A função no controlador pode precisar lidar com mais dados do que apenas os parâmetros transmitida pelo expedidor/dispatcher. Ele vai enviar solicitações de dados para o script Model. 4. O script Model determina como interagir com o banco de dados usando as requisições submetidas pelo controller. Ele pode executar consultas ao banco de dados e enviar todo tipo de instrução ao banco de dados. 5. Uma vez que o Model tem puxado quaisquer dados ou enviado dados para o banco de dados, ele retorna a sua saída para o Controller.

Ribamar FS – http://cursos.ribafs.org

Page 41: Cake CursoORIG

Curso de CakePHP Página 41 /90

6. O Controller processa os dados e saídas para o arquivo da View.

7. A View adiciona alguma formatação ou exibe os dados vindos do Controller e envia essa saída para o navegador do cliente.

MVC no Cake (diagrama)

Ribamar FS – http://cursos.ribafs.org

Page 42: Cake CursoORIG

Curso de CakePHP Página 42 /90

Requisição Típica do CakePHP

Ribamar FS – http://cursos.ribafs.org

Page 43: Cake CursoORIG

Curso de CakePHP Página 43 /90

Cake - Menu

Após criar o código para cada tabela devemos adicionar um menu que integre todo o código.Uma forma simples e natural de fazer isso é adicionando o arquivo views/pages/home.ctp

Criando a Home Page do Projeto:

Criar appname/views/pages/home.ctp com o conteúdo:<h1>Bem vindo ao Bake</h1><p>Aqui podmeos fazer:</p><ul><li><?php echo $html->link('Lista de todos os clientes', array('controller' => 'clientes', 'action'=>'index')); ?></li><li><?php echo $html->link('Adicionar novo Cliente', array('controller' => 'clientes', 'action'=>'add')); ?></li><li>Editar Clientes</li><li>Excluir Clientes</li></ul>

Agora então podemos navegar no aplicativo como um todo assim:http://localhost/appname/

Caso exista outros itens os adicione ao arquivo home.ctp.

Ribamar FS – http://cursos.ribafs.org

Page 44: Cake CursoORIG

Curso de CakePHP Página 44 /90

Cake - CSS

CakePHP e CSS

Criando o CSS para o layout

Para mudar o template default do Cake precisamos alterar o arquivo:cake/cake/libs/view/layouts/default.ctp

Template padrão do Cake

Veja seu conteúdo, inclusive nele é onde se encontra aquela frase "CakePHP: the rapid development php framework:"caso queiramos remover, assim como a pequena imgem do rodapé.Observe que a frase está no title e no body.

<?php?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><?php echo $html->charset(); ?><title><?php __('CakePHP: the rapid development php framework:'); ?><?php echo $title_for_layout; ?></title><?phpecho $html->meta('icon');

echo $html->css('cake.generic');

echo $scripts_for_layout;?></head><body><div id="container"><div id="header"><h1><?php echo $html->link(__('CakePHP: the rapid development php framework', true), 'http://cakephp.org'); ?></h1></div><div id="content">

<?php $session->flash(); ?>

<?php echo $content_for_layout; ?>

Ribamar FS – http://cursos.ribafs.org

Page 45: Cake CursoORIG

Curso de CakePHP Página 45 /90

</div><div id="footer"><?php echo $html->link($html->image('cake.power.gif', array('alt'=> __("CakePHP: the rapid development php framework", true), 'border'=>"0")),'http://www.cakephp.org/',array('target'=>'_blank'), null, false);?></div></div><?php echo $cakeDebug; ?></body></html>

Mudando este arquivo podemos transformar automaticamente todas as aplicações geradas.

Personalizando o Template

Caso criemos um arquivo chamado:cake/app/views/layouts/default.ctp

O Cake o usará e ignorará o anterior.

O arquivo CSS default usado no aplicativo é este:/app/webroot/css/cake.generic.css

E é chamado nas views assim:<link rel="stylesheet" type="text/css" href="/ProjectPath/css/cake.generic.css" />

Personalizando o CSS existente, entrando com um novo script CSS:

Editar o script app/webroot/css/cake.generic.css e cole o código abaixo ao final:

* { font-family: "Lucida Grande",Lucida,sans-serif; } th { font-size: 14px; font-weight: bold; background-color: #e1e1e1; border-bottom: 1px solid #ccc; padding: 10px; } div.actions ul { list-style-type: none; }

Observe que adicionando nosso próprio estilo podemos controlar a aparência do site.

Ribamar FS – http://cursos.ribafs.org

Page 46: Cake CursoORIG

Curso de CakePHP Página 46 /90

Editar então o script app/views/layouts/default.ctp e alterar a linha 4 para:

<?php print $html->css('cake.generic');?>

Para que o CSS do Cake volte, mas agora um pouco personalizado por nós.

Observe que o layout não é o padrão do Cake, pois tem algumas diferenças.

Referência: http://letthemcodecake.com/learning-cakephp/4/

Ribamar FS – http://cursos.ribafs.org

Page 47: Cake CursoORIG

Curso de CakePHP Página 47 /90

Cake - JavaScript

Os arquivos .js (Javascript) caso existam devem ser salvos no diretório webroot/js/

Referências:

http://bakery.cakephp.org/articles/view/toggling-items-with-javascript

http://debuggable.com/posts/passing-controller-variables-to-your-javascript:48b4f0c6-c718-47b2-bca1-05794834cda3

http://netunno.com/2009/08/incluir-arquivos-javascript-e-css-pela-view-de-um-conteudo-no-cakephp/

http://ryan.ifupdown.com/2009/08/22/how-to-use-javascript-codeblock-in-cakephp/

Ribamar FS – http://cursos.ribafs.org

Page 48: Cake CursoORIG

Curso de CakePHP Página 48 /90

Cake - Helpers

Helpers são classes do tipo component para a camada de apresentação da sua aplicação. Eles contêm lógica de aprensentação que é compartilhada entre muitas views, elements ou layouts. Cada helper estende AppHelper (opcionalmente definido em /app/app_helper.php), uma classe que guarda qualquer lógica necessária para todos os helpers.

O propósito desse capítulo é mostrar a você como criar seus próprios helpers, destacar algumas tarefas básicas que os helpers do CakePHP podem ajudá-lo a realizar.

Você usa helpers em CakePHP tornando os controllers conscientes deles. Cada controller tem uma variável de classe especial chamada $helpers que mantém uma lista dos helpers disponíveis para todas as views que esse controller renderiza. Para disponibilizar um helper em sua view do controller, adicione o nome do helper no array $helpers desse controller.

<?php class PadeirosController extends AppController { var $helpers = array('Form', 'Html', 'Javascript', 'Time');} ?>Referência - http://manual.cakephp.com.br/doku.php?id=helpers

Helpers do CakePHPO CakePHP tem alguns helpers muito úteis na criação de views. Eles ajudam na criação de marcação bem formatada (incluindo formulários), ajudam na formatação de texto, datas e números, e pode até acelerar uma funcionalidade Ajax. Aqui está uma lista rápida dos helpers com um resumo das suas habilidades. Para mais informação sobre um helper particular, dê uma olhada em sua respectiva sessão no capítulo Helpers Internos.

Helper CakePHP

Descrição

AjaxUsado também com a biblioteca JavaScript Prototype para criar funcionalidade Ajax nas views. Contém métodos de atalho para arrastar/soltar, formulários ajax & links, observers, e mais.

Cache Usado internamente para para criar cache do conteúdo das views .

FormCria formulários HTML e elementos de formulários com habilidade de auto-popular e manipulam problemas de validação.

HtmlMétodos de conveniência para criação de marcação bem formatada. Imagens, links, tabelas, tags de cabeçalho e mais.

JavascriptUsado para escapar valores para uso em JavaScripts, escrever dados para objetos JSON, e formatar blocos de código.

Number Formatação de números e moedasPaginator Paginação de dados do model e organização.Rss Métodos de conveniência para exportar dados XML RSS

Ribamar FS – http://cursos.ribafs.org

Page 49: Cake CursoORIG

Curso de CakePHP Página 49 /90

Session Acesso para escrita de valores de sessão nas viewsText Links automáticos, destaques, e truncamento automático de palavras.

TimeDetecção de proximidade (é o ano quem vem?), formatação de strings (Hoje, 10:30 am) e conversão de zona de tempo.

Xml Métodos de conveniência para criar cabeçalhos e elementos XML.

Criando HelpersSe um helper interno (ou um mostrado em Cakeforge ou em Bakery) não se adapta a suas necessidades, helpers são fáceis de fazer.

Vamos dizer que nós queremos criar um helper que pode ser usado para imprimir um tipo específico de link CSS que você precisa em muitos lugares diferentes em sua aplicação. Para colocar sua lógica na estrutura de helpers dos CakePHP, você deve criar uma nova classe em /app/views/helpers. Vamos chamar nosso helper de LinkHelper. O arquivo de classe PHP atual vai se parecer com isso:

<?php/* /app/views/helpers/link.php */ class LinkHelper extends AppHelper { function editar($titulo, $caminho) { // Lógica para criar links especialmente formatados vai aqui... }} ?>

Existem alguns poucos métodos incluídos na classe Helper do CakePHP dos quais você pode tirar vantagem:

output(string $string)

Use essa função para enviar qualquer dado de volta para sua view.

function editar($titulo, $caminho) { // Use essa função para enviar qualquer dado formatado // de volta para sua view: return $this->output( "<div class=\"editarContainer\"> <a href=\"$caminho\" class=\"editar\">$titulo</a> </div>" );}

Incluíndo outros Helpers

Você pode querer usar alguma funcionalidade já existente em outro helper. Para tanto, você pode especificar os helpers que você deseja usar com o array $helper, formatado exatamente como você faria no controller.

// /app/views/helpers/link.php (usando outros helpers)

Ribamar FS – http://cursos.ribafs.org

Page 50: Cake CursoORIG

Curso de CakePHP Página 50 /90

class LinkHelper extends Helper { var $helpers = array('Html'); function editar($titulo, $caminho) { // Usando o helper HTML para criar // dados formatados: $link = $this->Html->link($titulo, $caminho, array('class' => 'editar')); return $this->output("<div class=\"editarContainer\">$link</div>"); }}

Usando um Helper personalizado

Uma vez que você criou seu helper e o colocou em /app/views/helpers/, você estará habilitado a usá-lo em seus controllers usando a variável especial $helpers.

Assim que seu controller estiver consciente de sua nova classe, você pode usá-la em suas views acessando uma variável com o nome do helper:

<!-- faz um link usando o novo helper --><?php $link->editar('Mudar esta receita', '/receitas/editar/5') ?>

Nota: lembre-se de incluir o HtmlHelper e/ou FormHelper em seu array $helpers se você planeja usá-los em qualquer lugar.

Cake vem com HTML padrão, AJAX, JavaScript e helpers/ajudantes que criam as Views mais facilmente. Sua saída HTML será muito facilitada por strings intuitivas do helper que auxiliam a renderizar o HTML para você.

Todos os helpers ficam no diretório app/views/helpers

Incluir o nome da classe do Helper na variável array $helpers.

Ribamar FS – http://cursos.ribafs.org

Page 51: Cake CursoORIG

Curso de CakePHP Página 51 /90

Cake - Components

Introdução

Componentes são pacotes com funções lógicas que são usadas para serem compartilhadas entre os controladores. Se você está querendo copiar e colar coisas entre os controladores, você pode criar funcionalidades em componentes para isso.

O CakePHP já vem com um conjunto de componentes para os mais diversos usos, por exemplo:

• Segurança• Sessões• Lista de controle de acessos (ACL)• E-mails• Cookies• Autenticação• Manipulação de requisições

Cada um dos componentes será explicado em outros capítulos. Por enquanto, mostraremos apenas como criar seus próprios componentes. Criando componentes ajuda a manter o código do controlador limpo e permite que você reuse o código entre os projetos ou controladores.

Construindo componentes personalizados

Suponha que sua aplicação online precisa utilizar funções complexas de matemática em diversas partes da aplicação. Poderíamos, então, criar um componente para que esta lógica seja compartilhada entre diversos controladores.

O primeiro passo é criar um arquivo para o componente e uma classe. Crie o arquivo em /app/controllers/components/math.php. A estrutura básica do arquivo do componente é similar a apresentada abaixo.

<?php class MathComponent extends Object { function doComplexOperation($amount1, $amount2) { return $amount1 + $amount2; }} ?>

Quando seu componente estiver criado, nós podemos utilizá-lo nos controladores da aplicação colocando o nome do componente no vetor da variável $components:

// Isso faz com que o novo componente possa ser acessado usando $this->Math var $components = ('Math', 'Session');

Ribamar FS – http://cursos.ribafs.org

Page 52: Cake CursoORIG

Curso de CakePHP Página 52 /90

Acessando classes do MVC de dentro dos componentes

Para ter acesso a instância do controlador dentro do seu novo componente, você precisa implementar o método startup(). Este é um método especial que trás a referência do controlador como primeiro parâmetro e esta função é chamada automaticamente depois da função beforeFilter() do controlador. Se por alguma razão você não quer que o método startup() seja executado quando o controlador é instanciado, defina o valor da variável $disableStartup para true.

Se você deseja inserir uma lógica antes que o controlador seja chamado, use o método initialize() no seu componente.

<?php class MathComponent extends Object { //chamado antes de Controller:beforeFilter() function initialize() { } //chamado depois de Controller::beforeFilter() function startup(&$controller) { } function doComplexOperation($amount1, $amount2) { return $amount1 + $amount2; }} ?>

Você pode também querer utilizar outros componentes dentro de um componente personalizado. Para isso, basta criar a variável $components na classe (assim como você faria em um controlador) como um array que contenha os nomes dos componentes que você deseja utilizar.

Ribamar FS – http://cursos.ribafs.org

Page 53: Cake CursoORIG

Curso de CakePHP Página 53 /90

Cake - Routes

São as rotas (URLs)

No diretório config vemos o arquivo de configuração routes.php onde a rota default é:

Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));

Exemplo:Router::connect('/articles/*', array('controller'=>'posts','action'=>'index'));

http://localhost/blog/posts/index/page:2/sort:id/direction:asc

Como o CakePHP resolve URLshttp://localhost/{Application}/{Controller}/{Action}/{Parameter 1}/ {Parameter 2, etc.}

As URLs no Cake tem este formato:http://nome_dominio/nome_pastacake/nome_controller/nome_action

Quando uma requisição é feita para para o action index, a seguinte linha será executada:$this->set('clientes', $this->Cliente->find('all'));

Do manual do Cake em:

http://book.cakephp.org/pt/complete/3/The-Manual

Configuração de rotas (routes)

• Editar • Visualizar apenas esta seção • Comentários (0) • Histórico • Compare com o conteúdo original

Rotas são funcionalidades que mapeiam URLs em ações do controller. Foi adicionado ao CakePHP para tornar URLs amigáveis, mais configuráveis e flexíveis. Não é obrigatório o uso do mod_rewrite para usar rotas, mas usando-o fará sua barra de endereços muito mais limpa e arrumada.

Rotas no CakePHP 1.2 foi ampliada e pode ser muito mais poderosa.

Ver comentários desta seção

Rota Padrão

• Editar • Visualizar apenas esta seção • Comentários (0)

Ribamar FS – http://cursos.ribafs.org

Page 54: Cake CursoORIG

Curso de CakePHP Página 54 /90

• Histórico • Compare com o conteúdo original

Antes de você aprender sobre como configurar suas próprias rotas, você deveria saber que o CakePHP vem configurado com um conjunto de rotas padrão. A configuração padrão de rotas do CakePHP deixará as URLs mais bonitas para qualquer aplicação. Você pode acessar diretamente uma ação via URL colocando seu nome na requisição. Você pode também passar paramêtros para suas ações no controller usando a própria URL.

URL para a rota padrão: http://example.com/controller/action/param1/param2/param3

1. URL para a rota padrão: 2. http://example.com/controller/action/param1/param2/param3

A URL /noticias/ler mapeia para a ação ler() do controller Noticias (NoticiasController), e /produtos/ver_informacoes mapeia para a ação verInformacoes() do controller Produto (ProdutosController). Se nenhuma ação é especificada na URL, a ação index() será chamada.

A rota padrão também permite passar parâmetros para as ações usando a URL. Uma requisição /noticias/ler/12 seria equivalente a chamar o método ler(12) no controller Noticias (NoticiasController), por exemplo.

Ver comentários desta seção

Parâmetros nomeados

• Editar • Visualizar apenas esta seção • Comentários (0) • Histórico • Compare com o conteúdo original

Uma novidade no CakePHP 1.2 é a possibilidade de usar parâmetros nomeados. Você pode nomear parâmetros e enviar seus valores usando a URL. Uma requisição /noticias/ler/titulo:primeira+noticia/categoria:esportes teria como resultado uma chamada a ação ler() do controller Noticias (NoticiasController). Nesta ação, você encontraria os valores dos parâmetros título e categoria dentro de $this->passedArgs['titulo'] e $this->passedArgs['categoria'] respectivamente.

Alguns exemplos para a rota padrão:

URL mapeadas para as ações dos controladores, usando rotas padrão: URL: /monkeys/jumpMapeado para: MonkeysController->jump(); URL: /productsMapeado para: ProductsController->index(); URL: /tasks/view/45Mapeado para: TasksController->view(45); URL: /donations/view/recent/2001Mapeado para: DonationsController->view('recent', '2001');

Ribamar FS – http://cursos.ribafs.org

Page 55: Cake CursoORIG

Curso de CakePHP Página 55 /90

URL: /contents/view/chapter:models/section:associationsMapeado para: ContentsController->view();$this->passedArgs['chapter'] = 'models';$this->passedArgs['section'] = 'associations';

URL mapeadas para as ações dos controladores, usando rotas padrão: Definindo Rotas

• Editar • Visualizar apenas esta seção • Comentários (0) • Histórico • Compare com o conteúdo original

Definindo suas próprias rotas permite você definir como sua aplicação irá responder a uma dada URL. Defina suas próprias rotas no arquivo /app/config/routes.php usando o método Router::connect().

O método connect() recebe três parâmetros: a URL que você deseja casar, o valor padrão para os elementos de rota, e regras de expressões regulares para ajudar a encontrar elementos na URL.

O formato básico para uma definição de rota é:

Router::connect( 'URL', array('paramName' => 'defaultValue'), array('paramName' => 'matchingRegex'))

1. Router::connect( 2. 'URL', 3. array('paramName' => 'defaultValue'), 4. array('paramName' => 'matchingRegex') 5. )

O primeiro parâmetro é usado para informar o router sobre que tipo de URL você está tentando controlar. A URL é uma string normal delimitada por barras, as que também pode conter um caracter curinga (*) ou elementos de rota (nomes de variáveis iniciados por dois-pontos). Usar um curinga indica para o roteador que tipo de URLs você quer casar, e especificar elementos de rota permite a você obter parâmetros para as ações de seu controller.

Once you've specified a URL, you use the last two parameters of connect() to tell CakePHP what to do with a request once it has been matched. The second parameter is an associative array. The keys of the array should be named after the route elements in the URL, or the default elements: :controller, :action, and :plugin. The values in the array are the default values for those keys. Let's look at some basic examples before we start using the third parameter of connect().

Router::connect( '/pages/*', array('controller' => 'pages', 'action' => 'display'));

Ribamar FS – http://cursos.ribafs.org

Page 56: Cake CursoORIG

Curso de CakePHP Página 56 /90

This route is found in the routes.php file distributed with CakePHP (line 40). This route matches any URL starting with /pages/ and hands it to the display() method of the PagesController();; The request /pages/products would be mapped to PagesController->display('products'), for example.

Router::connect( '/government', array('controller' => 'products', 'action' => 'display', 5));

This second example shows how you can use the second parameter of connect() to define default parameters. If you built a site that features products for different categories of customers, you might consider creating a route. This allows you link to /government rather than /products/display/5.

Another common use for the Router is to define an "alias" for a controller. Let's say that instead of accessing our regular URL at /users/someAction/5, we'd like to be able to access it by /cooks/someAction/5. The following route easily takes care of that:

Router::connect(r /> '/cooks/:action/*', array('controller' => 'users', 'action' => 'index'));

This is telling the Router that any url beginning with /cooks/ should be sent to the users controller.

When generating urls, routes are used too. Using array('controller' => 'users', 'action' => 'someAction', 5) as a url will output /cooks/someAction/5 if the above route is the first match found

If you are planning to use custom named arguments with your route, you have to make the router aware of it using the Router::connectNamed function. So if you want the above route to match urls like /cooks/someAction/type:chef we do:

Router::connectNamed(array('type'));/>Router::connect('/cooks/:action/*', array('controller' => 'users', 'action' =&gt; 'index'));

You can specify your own route elements, doing so gives you the power to define places in the URL where parameters for controller actions should lie. When a request is made, the values for these route elements are found in $this->params of the controller. This is different than named parameters are handled, so note the difference: named parameters (/controller/action/name:value) are found in $this->passedArgs, whereas custom route element data is found in $this->params. When you define a custom route element, you also need to specify a regular expression - this tells CakePHP how to know if the URL is correctly formed or not.

Router::connect(

Ribamar FS – http://cursos.ribafs.org

Page 57: Cake CursoORIG

Curso de CakePHP Página 57 /90

'/:controller/:id', array('action' => 'view'), array('id' => '[0-9]+'));

This simple example illustrates how to create a quick way to view models from any controller by crafting a URL that looks like /controllername/id. The URL provided to connect() specifies two route elements: :controller and :id. The :controller element is a CakePHP default route element, so the router knows how to match and identify controller names in URLs. The :id element is a custom route element, and must be further clarified by specifying a matching regular expression in the third parameter of connect(). This tells CakePHP how to recognize the ID in the URL as opposed to something else, such as an action name.

Once this route has been defined, requesting /apples/5 is the same as requesting /apples/view/5. Both would call the view() method of the ApplesController. Inside the view() method, you would need to access the passed ID at $this->params['id'].

One more example, and you'll be a routing pro.

Router::connect( '/:controller/:year/:month/:day', array('action' => 'index', 'day' => null), array( 'year' => '[12][0-9]{3}', 'month' => '(0[1-9]|1[012])', 'day' => '(0[1-9]|[12][0-9]|3[01])' ));

This is rather involved, but shows how powerful routes can really become. The URL supplied has four route elements. The first is familiar to us: it’s a default route element that tells CakePHP to expect a controller name.

Next, we specify some default values. Regardless of the controller, we want the index() action to be called. We set the day parameter (the fourth element in the URL) to null to flag it as being optional.

Finally, we specify some regular expressions that will match years, months and days in numerical form.

Once defined, this route will match /articles/2007/02/01, /posts/2004/11/16, and /products/2001/05 (remember that the day parameter is optional?), handing the requests to the index() actions of their respective controllers, with the custom date parameters in $this->params.

Ver comentários desta seção

Passando parâmetros para "action"

• Editar • Visualizar apenas esta seção • Comentários (0) • Histórico • Compare com o conteúdo original

Ribamar FS – http://cursos.ribafs.org

Page 58: Cake CursoORIG

Curso de CakePHP Página 58 /90

Assumindo que sua action foi definida como esta e você quer acessas os argumentos usando $articleID ao invés de $this->params['id'], somente adicione um array extra no terceiro parâmetro de Router::connect().

// some_controller.phpfunction view($articleID = null, $slug = null) { // algum código aqui}// routes.phpRouter::connect( // E.g. /blog/3-CakePHP_Rocks '/blog/:id-:slug', array('controller' => 'blog', 'action' => 'view'), array( //A ordem importa pois isto irá mapear ":id" para $articleID na sua action 'pass' => array('id', 'slug'), 'id' => '[0-9]+' ));

E agora, graças as funcionalidades de roteamento reverso, você pode passar na url um arra como o abaixo e o Cake saberá como formar a URL como definido nas rotas.

// view.ctp// Isto irá retornar um link para /blog/3-CakePHP_Rocks<?php echo $html->link('CakePHP Rocks', array( 'controller' => 'blog', 'action' => 'view', 'id' => 3, 'slug' => Inflector::slug('CakePHP Rocks'))); ?>

Roteando prefixos

• Editar • Visualizar apenas esta seção • Comentários (0) • Histórico • Compare com o conteúdo original

Várias aplicações necessitam de uma seção para usuários administradores com privilégios de alteração de dados. Muitas vezes isso é definido na url, como /admin/users/edit/5. No CakePHP é possível utilizar uma rota para administradores mapeando a nossa seção no arquivo de configuração para Routing.admin.

Configure::write('Routing.admin', 'admin');

1. Configure::write('Routing.admin', 'admin');

Você pode definir quais métodos do seu controller usarão a rota de administrador bastando iniciar o nome do método com o prefixo admin_. Usando o nosso exemplo para acessar uma url de

Ribamar FS – http://cursos.ribafs.org

Page 59: Cake CursoORIG

Curso de CakePHP Página 59 /90

administração usuários /admin/users/edit/5 deveremos ter o o método admin_edit em nosso UsersController informando que o primeiro parâmetro é o número 5.

Você pode mapear a url /admin para a sua ação inicial admin_index alterando o arquivo de configuração de rotas.

Router::connect('/admin', array('controller' => 'pages', 'action' => 'index', 'admin' => true));

Você pode configurar o seu arquivo de configuração para utilizar vários prefixos também:

Router::connect('/profiles/:controller/:action/*', array('prefix' => 'profiles', 'profiles' => true));

As ações(métodos) que pertençam à seção de profiles devem ter seus nomes iniciados com o prefixo profiles_. A estrutura da url do nosso exemplo da seção de profiles de usuários é /profiles/users/edit/5 que fará chamada ao método profiles_edit no nosso UsersController. É importante lembrar que usando o HTML Helper do cakePHP para montar nossos links já estaremos montando o nosso link de forma correta. Abaixo há um exemplo de como construir o nosso link utilizando o HTML helper.

echo $html->link('Edite seu perfil', array('profiles' => true, 'controller' => 'users', 'action' => 'edit', 'id' => 5));

Você pode setar vários prefixos no roteador do cakePHP criando uma estrutura flexível de URL's para a sua aplicação.

Ver comentários desta seção

Extensões de Arquivos

• Editar • Visualizar apenas esta seção • Comentários (0) • Histórico • Compare com o conteúdo original

Para fazer com que suas rotas manipulem diferentes extensões de arquivos, você precisa de uma linha a mais em seu arquivo de configuração de rotas:

Router::parseExtensions(array('html', 'rss'));

Isto vai informar ao router para desconsiderar as extensões que arquivos correspondentes e então processar o restante.

Se você quiser criar uma URL como /pagina/titulo-da-pagina.html, você deveria criar sua rota como mostrado abaixo:

Router::connect( '/pagina/:title', array('controller' => 'pages', 'action' => 'view'), array( 'pass' => array('title') )

Ribamar FS – http://cursos.ribafs.org

Page 60: Cake CursoORIG

Curso de CakePHP Página 60 /90

);

E então para criar links que utilizem esta rota, simplesmente use:

$html->link('Título do link', array('controller' => 'pages', 'action' => 'view', 'title' => Inflector::slug('titulo da pagina', '-'), 'ext' => 'html'))

Ribamar FS – http://cursos.ribafs.org

Page 61: Cake CursoORIG

Curso de CakePHP Página 61 /90

Cake - Verdors

São os scripts de terceiros, que não fazem parte do core do Cake, que ficam no diretório verdors.

Carregando arquivos de terceiros (vendors):

A tradicional forma é carregando arquivos da pasta "verdors" usando a função vendor() que está caindo em desuso.

Recebemos um warning se a usarmos.

A nova maneira de usar é com App:import().

Para carregar um arquivo de nome exemplo.php use o seguinte:

App::import('Vendor', 'exemplo');

Tem um pequeno problema aqui: só funciona se o nome do arquivo tiver todas as letras em minúsculas.

Caso o arquivo tenha a inicial maiúsculas ao invés use:

App::import('Vendor', 'exemplo', array('file' => 'Exemplo.php'));

O segundo parâmetro pode ser qualquer string, exceto varia ou null.

O mesmo se aplica para:

App::import('Vendor', 'example'.DS.'example'); // loads example/example.phpApp::import('Vendor', 'example', array('file' => 'Example'.DS.'example.php')); // loads Example/example.phpRefeência - http://cakebaker.42dh.com/2008/03/26/loading-vendor-files/

Referências:

http://lemoncake.wordpress.com/2007/08/08/vendors-in-cakephp/

Ribamar FS – http://cursos.ribafs.org

Page 62: Cake CursoORIG

Curso de CakePHP Página 62 /90

Cake - Plugins

Plugins

• Editar • Visualizar apenas esta seção • Comentários (0) • Histórico • Compare com o conteúdo original

O CakePHP permite que você defina uma combinação de controllers, models e views e os distribua como um plugin empacotado de aplicação que os outros poderão usar em suas aplicações CakePHP. Você tem um módulo de gerência de usuários legal, ou um blog simples, ou quem sabe um módulo de webservices em uma de suas aplicações? Empacote-o como um plugin do CakePHP para poder incorporá-lo em outras aplicações.

A principal fronteira entre um plugin e a aplicação na qual está instalado é a configuração da aplicação (conexão da base de dados, etc.). Por outro lado, ele funciona dentro de seu próprio espaço, se comportando como se fosse a própria aplicação.

Ver comentários desta seção

Criando um Plugin

• Editar • Visualizar apenas esta seção • Comentários (0) • Histórico • Compare com o conteúdo original

Como um exemplo funcional, vamos criar um novo plugin que peça uma pizza para você. Para começar, vamos ter de colocar os arquivos de nosso plugin dentro da pasta /app/plugins folder. O nome da subpasta em que os arquivos do plugin ficarão é importante e será usado em diversos locais, então escolha-o sabiamente. Para este plugin, vamos usar o nome 'pizza'. Aqui está como a configuração de nosso plugin deve se parecer:

/app /plugins /pizza /controllers <- os controllers do plugin vão aqui /models <- os models do plugin vão aqui /views <- as views do plugin views vão aqui /pizza_app_controller.php <- o AppController do plugin /pizza_app_model.php <- o AppModel do plugin

Se você quiser ser capaz de acessar seu plugin a partir de uma dada URL, torna-se obrigatório definir um AppController e um AppModel para o seu plugin. Estas duas classes especiais são nomeadas depois do plugin e estendem os respectivos AppController e AppModel da aplicação. Não há nenhuma novidade nos seus conteúdos, que para nosso plugin de pizza de exemplo, devem ser algos parecidos com:

Plain Text View

Ribamar FS – http://cursos.ribafs.org

Page 63: Cake CursoORIG

Curso de CakePHP Página 63 /90

// /app/plugins/pizza/pizza_app_controller.php:<?phpclass PizzaAppController extends AppController { //...}?>

// /app/plugins/pizza/pizza_app_model.php:<?phpclass PizzaAppModel extends AppModel { //...}?>

Se você se esquecer de definir estas classes especiais, o CakePHP irá dar um alerta sobre erros de "Missing Controller" enquanto você não os criar.

Ver comentários desta seção

Controllers de Plugin

• Editar • Visualizar apenas esta seção • Comentários (0) • Histórico • Compare com o conteúdo original

Os controllers de nosso plugin pizza serão armazenados em /app/plugins/pizza/controllers/. Como o propósito principal aqui é o pedido de pizzas, vamos precisar de um OrdersController para este plugin.

Ainda que não seja obrigatório, é recomendado que você dê nomes relativamente únicos para os controllers de seu plugin para evitar conflitos de namespaces com as aplicações residentes. Não é difícil de imaginar que a aplicação-pai possa ter um UsersController, OrdersController ou ProductsController; então você pode querer ser criativo com os nomes de controllers ou prefixar o nome do plugin ao nome da classe (PizzaOrdersController, neste caso).

Então, colocamos nosso PizzaOrdersController na pasta /app/plugins/pizza/controllers com um conteúdo semelhante a:

// /app/plugins/pizza/controllers/pizza_orders_controller.phpclass PizzaOrdersController extends PizzaAppController { var $name = 'PizzaOrders'; var $uses = array('Pizza.PizzaOrder'); function index() { //... }}

Este controller estende o AppController do plugin (chamado de PizzaAppController) ao invés do AppController da aplicação.

Ribamar FS – http://cursos.ribafs.org

Page 64: Cake CursoORIG

Curso de CakePHP Página 64 /90

Perceba também como o nome do model é prefixado com o nome do plugin. Essa linha de código é adicionada apenas para deixar as coisas mais claras, mas não é necessária neste exemplo.

Se você quiser visualizar o que estamos fazendo, acesse /pizza/pizza_orders. Se tudo estiver certo, neste ponto você deve receber uma mensagem de erro sobre “Missing Model”, uma vez que nosso model PizzaOrder ainda não está definido.

Ver comentários desta seção

Plugin Models

• Traduzir • Visualizar apenas esta seção • Comentários (0) • Histórico

There is no translation yet for this section. Please help out and translate this.. More information about translations

Models for the plugin are stored in /app/plugins/pizza/models. We've already defined a PizzaOrdersController for this plugin, so let's create the model for that controller, called PizzaOrder. PizzaOrder is consistent with our previously defined naming scheme of pre-pending all of our plugin classes with Pizza.

// /app/plugins/pizza/models/pizza_order.php:class PizzaOrder extends PizzaAppModel { var $name = 'PizzaOrder';}?>

Visiting /pizza/pizzaOrders now (given you’ve got a table in your database called ‘pizza_orders’) should give us a “Missing View” error. Let’s create that next.

If you need to reference a model within your plugin, you need to include the plugin name with the model name, separated with a dot.

For example:

// /app/plugins/pizza/models/pizza_order.php:class ExampleModel extends PizzaAppModel { var $name = 'ExampleModel'; var $hasMany = array('Pizza.PizzaOrder');}?>

If you would prefer that the array keys for the association not have the plugin prefix on them, use the alternative syntax:

Ribamar FS – http://cursos.ribafs.org

Page 65: Cake CursoORIG

Curso de CakePHP Página 65 /90

// /app/plugins/pizza/models/pizza_order.php:class ExampleModel extends PizzaAppModel { var $name = 'ExampleModel'; var $hasMany = array( 'PizzaOrder' => array( 'className' => 'Pizza.PizzaOrder' ) );}?>

Plugin Views

• Traduzir • Visualizar apenas esta seção • Comentários (0) • Histórico

There is no translation yet for this section. Please help out and translate this.. More information about translations

Views behave exactly as they do in normal applications. Just place them in the right folder inside of the /app/plugins/[plugin]/views/ folder. For our pizza ordering plugin, we'll need a view for our PizzaOrdersController::index() action, so let's include that as well:

// /app/plugins/pizza/views/pizza_orders/index.ctp:<h1>Order A Pizza</h1><p>Nothing goes better with Cake than a good pizza!</p><!-- An order form of some sort might go here....-->

Testando plugins

• Editar • Visualizar apenas esta seção • Comentários (0) • Histórico • Compare com o conteúdo original

Testes para plugins são criados em seu próprio diretório dentro da pasta plugins.

/app /plugins /pizza /tests /cases /fixtures /groups

Testes para plugins são como testes normais, exceto que você deve se lembrar de usar a convenção de nomenclatura para plugins ao importar as classes. Este é um exemplo de um caso de teste para o model PizzaOrder criado no capítulo de plugins deste manual. Uma diferença para os outros testes é a primeira linha que faz a importação de 'Pizza.PizzaOrder'. Você também precisa prefixar os

Ribamar FS – http://cursos.ribafs.org

Page 66: Cake CursoORIG

Curso de CakePHP Página 66 /90

fixtures de seu plugin com 'plugin.plugin_name.'.

<?php App::import('Model', 'Pizza.PizzaOrder');class PizzaOrderCase extends CakeTestCase { // Fixtures de plugin localizados em /app/plugins/pizza/tests/fixtures/ var $fixtures = array('plugin.pizza.pizza_order'); var $PizzaOrderTest; function testSomething() { // ClassRegistry faz com que o model use a conexão de teste da base de dados $this->PizzaOrderTest =& ClassRegistry::init('PizzaOrder'); // faz algum teste útil aqui $this->assertTrue(is_object($this->PizzaOrderTest)); }}?>

Se você quiser usar o fixtures de plugin nos testes da aplicação, você pode referenciá-los usando a sintaxe 'plugin.pluginName.fixtureName' no array $fixtures.

E isso é tudo!

Fonte: http://book.cakephp.org/pt/complete/3/The-Manual

Veja um tutorial do Felipe Theodoro ensinando a criar seus próprios plugins para o Cake.

http://blog.ftgoncalves.com/2009/03/criando-seus-proprios-plugins-para-o-cakephp/

Ribamar FS – http://cursos.ribafs.org

Page 67: Cake CursoORIG

Curso de CakePHP Página 67 /90

Cake - Relacionamentos

O cake detecta relacionamentos entre as tabelas, mas para isso precisamos atender a algumas das suas convenções.

Para isso a chave primária deve ser id ou criar com o Bake e indicar a chave primária.

O campo foreign key da tabela relacionada deve chamar-se obrigatoriamente

nometabelasingular_id

Exemplo:

cliente_id

Agora o Cake irá detectar os relacionamentos e adicionar uma combo nos campos foreign key das tabelas relacionadas que será preenchida com dados da outra tabela.

Ribamar FS – http://cursos.ribafs.org

Page 68: Cake CursoORIG

Curso de CakePHP Página 68 /90

Cake - Dicas

1) Padronização do aplicativo default

Como cada vez que vou criar um novo aplicativo no cake:

- Copio a pasta app com o nome do novo aplicativo (Exemplo: cad_livros)

- Depois então vou realizar as personalizações necessárias para começar:

- locales/pt-BR

- views/layout/default.ctp (faço uma cópia de cake/cake/libs/view/layouts/default.ctp para a pasta views/layout e personalizo)

- webroot/index.php (adapto para permitir que vários aplicativos usem o mesmo core)

- entre outros.

Como eu estou sempre fazendo isso, fica mais prático já efetuar todas essas alterações na pasta "app" do cake para que quando eu a copie já leve todas as minhas alterações.

Ribamar FS – http://cursos.ribafs.org

Page 69: Cake CursoORIG

Curso de CakePHP Página 69 /90

Cake – Aplicativos de Exemplo

Aplicativo Livros

Aplicativo gerado pelo Bake com a finalidade de mostrar um relacionamento entre as tabelas autores e livros e também mostrar o comportamento das validações.

Criar um aplicativo para apenas duas tabelas relacionadas usando o Bake

Banco - livro

tabelas

create table autores (

autor int auto_increment primary key, nome char(45) not null, email char(50)

);

create table livros (

isbn char(17) primary key, titulo char(45) not null, editora char(50) not null, autore_id int not null,

FOREIGN KEY (autore_id) REFERENCES autores(autor) ON DELETE RESTRICT );

insert into autores values (1, 'Alexandre Dumas Pai', '[email protected]'); insert into autores values (2, 'Camões', '[email protected]'); insert into autores values (3, 'Dante Alighieri', '[email protected]'); insert into autores values (4, 'Albert Camus', '[email protected]'); insert into autores values (5, 'Jean Paul Sartre', '[email protected]'); insert into autores values (6, 'Augusto Cury', '[email protected]');

insert into livros values ('978-0-470-03899-4', 'O Conde de Monte Cristo', 'Nova Data', 1); insert into livros values ('978-0-470-03899-5', 'Os Três Mosqueteiros', 'Nova Data', 1); insert into livros values ('978-0-470-03899-6', 'Os Lusíadas', 'Saraiva', 2); insert into livros values ('978-0-470-03899-7', 'A Divina Comédia', 'Moderna', 3); insert into livros values ('978-0-470-03899-8', 'O Estrangeiro', 'Moderna', 4); insert into livros values ('979-0-470-03899-4', 'A Idade da Razão', 'Novatec', 5); insert into livros values ('976-0-470-03899-4', 'Pais Brilhantes, Professores Fascinantes', 'Eldorado', 6);

Copiar a pasta app para livro. Configurar a webroot/index.php para que vários app usem o mesmo core.

Ribamar FS – http://cursos.ribafs.org

Page 70: Cake CursoORIG

Curso de CakePHP Página 70 /90

Agora usemos o bake para criar o aplicativo, com validação dos campos e relacionamento.

cd /var/www/cake/cake/console

./cake bake -app livro

1) Crie a configuração com o banco de dados livro. ./cake bake -app livro

2) Criar o model, o controller e a view para autores. 3) Depois criar o model, o controller e a view para livros (sempre nesta ordem).

Use diretamente

./cake bake -app livro model

./cake bake -app livro controller

./cake bake -app livro view

Au final vamos criar um simples menu para o Aplicativo:

Adicionar o arquivo views/pages/home.ctp

<h1>Aplicativo Livros</h1> <p>Tarefas</p> <ul> <li><?php echo $html->link('Lista de todos os Autores', array('controller' => 'autores', 'action'=>'index')); ?></li> <li><?php echo $html->link('Adicionar novo Autor', array('controller' => 'autores', 'action'=>'add')); ?></li> <li><?php echo $html->link('Lista de todos os Livros', array('controller' => 'livros', 'action'=>'index')); ?></li> <li><?php echo $html->link('Adicionar novo Livro', array('controller' => 'livros', 'action'=>'add')); ?></li> <li>Editar e Excluir Autores</li> <li>Editar e Excluir Livros</li> </ul>

Aí poderiamos adicionar editar, visualizar, excluir para ambos.

Chamar no navegador com: http://localhost/cake/livro/

Dar suporte a pt-BR

Após implementar o suporte a pt-BR as mensagens de erro serão traduzidas, os nomes das ações dentre outros.

Ribamar FS – http://cursos.ribafs.org

Page 71: Cake CursoORIG

Curso de CakePHP Página 71 /90

Código do Aplicativo Livro criado com o Cake Bake

models/autore.php <?php class Autore extends AppModel {

var $name = 'Autore'; var $primaryKey = 'autor'; var $validate = array(

'autor' => array('numeric'), 'nome' => array('notempty'), 'email' => array('email')

);

} ?>

models/livro.php <?php class Livro extends AppModel {

var $name = 'Livro'; var $primaryKey = 'isbn'; var $validate = array(

'isbn' => array('notempty'), 'titulo' => array('notempty'), 'editora' => array('notempty'), 'autore_id' => array('numeric')

);

//The Associations below have been created with all possible keys, those that are not needed can be removed

var $belongsTo = array( 'Autore' => array(

'className' => 'Autore', 'foreignKey' => 'autore_id', 'conditions' => '', 'fields' => '', 'order' => ''

) );

} ?>

controllers/autores_controller.php <?php class AutoresController extends AppController {

Ribamar FS – http://cursos.ribafs.org

Page 72: Cake CursoORIG

Curso de CakePHP Página 72 /90

var $name = 'Autores'; var $helpers = array('Html', 'Form');

function index() { $this->Autore->recursive = 0; $this->set('autores', $this->paginate());

}

function view($id = null) { if (!$id) {

$this->Session->setFlash(__('Invalid Autore.', true)); $this->redirect(array('action'=>'index'));

} $this->set('autore', $this->Autore->read(null, $id));

}

function add() { if (!empty($this->data)) {

$this->Autore->create(); if ($this->Autore->save($this->data)) {

$this->Session->setFlash(__('The Autore has been saved', true)); $this->redirect(array('action'=>'index'));

} else { $this->Session->setFlash(__('The Autore could not be saved. Please, try again.',

true)); }

} }

function edit($id = null) { if (!$id && empty($this->data)) {

$this->Session->setFlash(__('Invalid Autore', true)); $this->redirect(array('action'=>'index'));

} if (!empty($this->data)) {

if ($this->Autore->save($this->data)) { $this->Session->setFlash(__('The Autore has been saved', true)); $this->redirect(array('action'=>'index'));

} else { $this->Session->setFlash(__('The Autore could not be saved. Please, try again.',

true)); }

} if (empty($this->data)) {

$this->data = $this->Autore->read(null, $id); }

}

Ribamar FS – http://cursos.ribafs.org

Page 73: Cake CursoORIG

Curso de CakePHP Página 73 /90

function delete($id = null) {

if (!$id) { $this->Session->setFlash(__('Invalid id for Autore', true)); $this->redirect(array('action'=>'index'));

} if ($this->Autore->del($id)) {

$this->Session->setFlash(__('Autore deleted', true)); $this->redirect(array('action'=>'index'));

} }

} ?>

controllers/livros_controller.php <?php class LivrosController extends AppController {

var $name = 'Livros'; var $helpers = array('Html', 'Form');

function index() { $this->Livro->recursive = 0; $this->set('livros', $this->paginate());

}

function view($id = null) { if (!$id) {

$this->Session->setFlash(__('Invalid Livro.', true)); $this->redirect(array('action'=>'index'));

} $this->set('livro', $this->Livro->read(null, $id));

}

function add() { if (!empty($this->data)) {

$this->Livro->create(); if ($this->Livro->save($this->data)) {

$this->Session->setFlash(__('The Livro has been saved', true)); $this->redirect(array('action'=>'index'));

} else { $this->Session->setFlash(__('The Livro could not be saved. Please, try again.',

true)); }

} $autores = $this->Livro->Autore->find('list'); $this->set(compact('autores'));

Ribamar FS – http://cursos.ribafs.org

Page 74: Cake CursoORIG

Curso de CakePHP Página 74 /90

}

function edit($id = null) { if (!$id && empty($this->data)) {

$this->Session->setFlash(__('Invalid Livro', true)); $this->redirect(array('action'=>'index'));

} if (!empty($this->data)) {

if ($this->Livro->save($this->data)) { $this->Session->setFlash(__('The Livro has been saved', true)); $this->redirect(array('action'=>'index'));

} else { $this->Session->setFlash(__('The Livro could not be saved. Please, try again.',

true)); }

} if (empty($this->data)) {

$this->data = $this->Livro->read(null, $id); } $autores = $this->Livro->Autore->find('list'); $this->set(compact('autores'));

}

function delete($id = null) { if (!$id) {

$this->Session->setFlash(__('Invalid id for Livro', true)); $this->redirect(array('action'=>'index'));

} if ($this->Livro->del($id)) {

$this->Session->setFlash(__('Livro deleted', true)); $this->redirect(array('action'=>'index'));

} }

} ?>

views/autores/autores/add.ctp <div class="autores form"> <?php echo $form->create('Autore');?>

<fieldset> <legend><?php __('Add Autore');?></legend>

<?php echo $form->input('nome'); echo $form->input('email');

?> </fieldset>

<?php echo $form->end('Submit');?>

Ribamar FS – http://cursos.ribafs.org

Page 75: Cake CursoORIG

Curso de CakePHP Página 75 /90

</div> <div class="actions">

<ul> <li><?php echo $html->link(__('List Autores', true), array('action' => 'index'));?></li>

</ul> </div>

views/autores/autores/edit.ctp <div class="autores form"> <?php echo $form->create('Autore');?>

<fieldset> <legend><?php __('Edit Autore');?></legend>

<?php echo $form->input('autor'); echo $form->input('nome'); echo $form->input('email');

?> </fieldset>

<?php echo $form->end('Submit');?> </div> <div class="actions">

<ul> <li><?php echo $html->link(__('Delete', true), array('action' => 'delete', $form-

>value('Autore.autor')), null, sprintf(__('Are you sure you want to delete # %s?', true), $form->value('Autore.autor'))); ?></li>

<li><?php echo $html->link(__('List Autores', true), array('action' => 'index'));?></li> </ul>

</div>

views/autores/autores/index.ctp <div class="autores index"> <h2><?php __('Autores');?></h2> <p> <?php echo $paginator->counter(array( 'format' => __('Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%', true) )); ?></p> <table cellpadding="0" cellspacing="0"> <tr>

<th><?php echo $paginator->sort('autor');?></th> <th><?php echo $paginator->sort('nome');?></th> <th><?php echo $paginator->sort('email');?></th> <th class="actions"><?php __('Actions');?></th>

</tr> <?php $i = 0;

Ribamar FS – http://cursos.ribafs.org

Page 76: Cake CursoORIG

Curso de CakePHP Página 76 /90

foreach ($autores as $autore): $class = null; if ($i++ % 2 == 0) {

$class = ' class="altrow"'; }

?> <tr<?php echo $class;?>>

<td> <?php echo $autore['Autore']['autor']; ?>

</td> <td>

<?php echo $autore['Autore']['nome']; ?> </td> <td>

<?php echo $autore['Autore']['email']; ?> </td> <td class="actions">

<?php echo $html->link(__('View', true), array('action' => 'view', $autore['Autore']['autor'])); ?>

<?php echo $html->link(__('Edit', true), array('action' => 'edit', $autore['Autore']['autor'])); ?>

<?php echo $html->link(__('Delete', true), array('action' => 'delete', $autore['Autore']['autor']), null, sprintf(__('Tem certeza de que deseja excluir o autor # %s?', true), $autore['Autore']['autor'])); ?>

</td> </tr>

<?php endforeach; ?> </table> </div> <div class="paging">

<?php echo $paginator->prev('<< '.__('previous', true), array(), null, array('class'=>'disabled'));?> | <?php echo $paginator->numbers();?>

<?php echo $paginator->next(__('next', true).' >>', array(), null, array('class' => 'disabled'));?> </div> <div class="actions">

<ul> <li><?php echo $html->link(__('New Autore', true), array('action' => 'add')); ?></li>

</ul> </div>

views/autores/autores/view.ctp <div class="autores view"> <h2><?php __('Autore');?></h2>

<dl><?php $i = 0; $class = ' class="altrow"';?> <dt<?php if ($i % 2 == 0) echo $class;?>><?php __('Autor'); ?></dt> <dd<?php if ($i++ % 2 == 0) echo $class;?>>

<?php echo $autore['Autore']['autor']; ?>

Ribamar FS – http://cursos.ribafs.org

Page 77: Cake CursoORIG

Curso de CakePHP Página 77 /90

&nbsp; </dd> <dt<?php if ($i % 2 == 0) echo $class;?>><?php __('Nome'); ?></dt> <dd<?php if ($i++ % 2 == 0) echo $class;?>>

<?php echo $autore['Autore']['nome']; ?> &nbsp;

</dd> <dt<?php if ($i % 2 == 0) echo $class;?>><?php __('Email'); ?></dt> <dd<?php if ($i++ % 2 == 0) echo $class;?>>

<?php echo $autore['Autore']['email']; ?> &nbsp;

</dd> </dl>

</div> <div class="actions">

<ul> <li><?php echo $html->link(__('Edit Autore', true), array('action' => 'edit', $autore['Autore']

['autor'])); ?> </li> <li><?php echo $html->link(__('Delete Autore', true), array('action' => 'delete',

$autore['Autore']['autor']), null, sprintf(__('Are you sure you want to delete # %s?', true), $autore['Autore']['autor'])); ?> </li>

<li><?php echo $html->link(__('List Autores', true), array('action' => 'index')); ?> </li> <li><?php echo $html->link(__('New Autore', true), array('action' => 'add')); ?> </li>

</ul> </div>

livro/views/livros/add.ctp <div class="livros form"> <?php echo $form->create('Livro');?>

<fieldset> <legend><?php __('Add Livro');?></legend>

<?php echo $form->input('titulo'); echo $form->input('editora'); echo $form->input('autore_id');

?> </fieldset>

<?php echo $form->end('Submit');?> </div> <div class="actions">

<ul> <li><?php echo $html->link(__('List Livros', true), array('action' => 'index'));?></li> <li><?php echo $html->link(__('List Autores', true), array('controller' => 'autores', 'action'

=> 'index')); ?> </li> <li><?php echo $html->link(__('New Autore', true), array('controller' => 'autores', 'action'

=> 'add')); ?> </li> </ul>

</div>

Ribamar FS – http://cursos.ribafs.org

Page 78: Cake CursoORIG

Curso de CakePHP Página 78 /90

livro/views/livros/edit.ctp <div class="livros form"> <?php echo $form->create('Livro');?>

<fieldset> <legend><?php __('Edit Livro');?></legend>

<?php echo $form->input('isbn'); echo $form->input('titulo'); echo $form->input('editora'); echo $form->input('autore_id');

?> </fieldset>

<?php echo $form->end('Submit');?> </div> <div class="actions">

<ul> <li><?php echo $html->link(__('Delete', true), array('action' => 'delete', $form-

>value('Livro.isbn')), null, sprintf(__('Are you sure you want to delete # %s?', true), $form->value('Livro.isbn'))); ?></li>

<li><?php echo $html->link(__('List Livros', true), array('action' => 'index'));?></li> <li><?php echo $html->link(__('List Autores', true), array('controller' => 'autores', 'action'

=> 'index')); ?> </li> <li><?php echo $html->link(__('New Autore', true), array('controller' => 'autores', 'action'

=> 'add')); ?> </li> </ul>

</div>

livro/views/livros/index.ctp <div class="livros index"> <h2><?php __('Livros');?></h2> <p> <?php echo $paginator->counter(array( 'format' => __('Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%', true) )); ?></p> <table cellpadding="0" cellspacing="0"> <tr>

<th><?php echo $paginator->sort('isbn');?></th> <th><?php echo $paginator->sort('titulo');?></th> <th><?php echo $paginator->sort('editora');?></th> <th><?php echo $paginator->sort('autore_id');?></th> <th class="actions"><?php __('Actions');?></th>

</tr> <?php $i = 0;

Ribamar FS – http://cursos.ribafs.org

Page 79: Cake CursoORIG

Curso de CakePHP Página 79 /90

foreach ($livros as $livro): $class = null; if ($i++ % 2 == 0) {

$class = ' class="altrow"'; }

?> <tr<?php echo $class;?>>

<td> <?php echo $livro['Livro']['isbn']; ?>

</td> <td>

<?php echo $livro['Livro']['titulo']; ?> </td> <td>

<?php echo $livro['Livro']['editora']; ?> </td> <td>

<?php echo $html->link($livro['Autore']['autor'], array('controller' => 'autores', 'action' => 'view', $livro['Autore']['autor'])); ?>

</td> <td class="actions">

<?php echo $html->link(__('View', true), array('action' => 'view', $livro['Livro']['isbn'])); ?>

<?php echo $html->link(__('Edit', true), array('action' => 'edit', $livro['Livro']['isbn'])); ?>

<?php echo $html->link(__('Delete', true), array('action' => 'delete', $livro['Livro']['isbn']), null, sprintf(__('Are you sure you want to delete # %s?', true), $livro['Livro']['isbn'])); ?>

</td> </tr>

<?php endforeach; ?> </table> </div> <div class="paging">

<?php echo $paginator->prev('<< '.__('previous', true), array(), null, array('class'=>'disabled'));?> | <?php echo $paginator->numbers();?>

<?php echo $paginator->next(__('next', true).' >>', array(), null, array('class' => 'disabled'));?> </div> <div class="actions">

<ul> <li><?php echo $html->link(__('New Livro', true), array('action' => 'add')); ?></li> <li><?php echo $html->link(__('List Autores', true), array('controller' => 'autores', 'action'

=> 'index')); ?> </li> <li><?php echo $html->link(__('New Autore', true), array('controller' => 'autores', 'action'

=> 'add')); ?> </li> </ul>

</div>

Ribamar FS – http://cursos.ribafs.org

Page 80: Cake CursoORIG

Curso de CakePHP Página 80 /90

livro/views/livros/view.ctp <div class="livros view"> <h2><?php __('Livro');?></h2>

<dl><?php $i = 0; $class = ' class="altrow"';?> <dt<?php if ($i % 2 == 0) echo $class;?>><?php __('Isbn'); ?></dt> <dd<?php if ($i++ % 2 == 0) echo $class;?>>

<?php echo $livro['Livro']['isbn']; ?> &nbsp;

</dd> <dt<?php if ($i % 2 == 0) echo $class;?>><?php __('Titulo'); ?></dt> <dd<?php if ($i++ % 2 == 0) echo $class;?>>

<?php echo $livro['Livro']['titulo']; ?> &nbsp;

</dd> <dt<?php if ($i % 2 == 0) echo $class;?>><?php __('Editora'); ?></dt> <dd<?php if ($i++ % 2 == 0) echo $class;?>>

<?php echo $livro['Livro']['editora']; ?> &nbsp;

</dd> <dt<?php if ($i % 2 == 0) echo $class;?>><?php __('Autore'); ?></dt> <dd<?php if ($i++ % 2 == 0) echo $class;?>>

<?php echo $html->link($livro['Autore']['autor'], array('controller' => 'autores', 'action' => 'view', $livro['Autore']['autor'])); ?>

&nbsp; </dd>

</dl> </div> <div class="actions">

<ul> <li><?php echo $html->link(__('Edit Livro', true), array('action' => 'edit', $livro['Livro']

['isbn'])); ?> </li> <li><?php echo $html->link(__('Delete Livro', true), array('action' => 'delete', $livro['Livro']

['isbn']), null, sprintf(__('Are you sure you want to delete # %s?', true), $livro['Livro']['isbn'])); ?> </li>

<li><?php echo $html->link(__('List Livros', true), array('action' => 'index')); ?> </li> <li><?php echo $html->link(__('New Livro', true), array('action' => 'add')); ?> </li> <li><?php echo $html->link(__('List Autores', true), array('controller' => 'autores', 'action'

=> 'index')); ?> </li> <li><?php echo $html->link(__('New Autore', true), array('controller' => 'autores', 'action'

=> 'add')); ?> </li> </ul>

</div>

Ribamar FS – http://cursos.ribafs.org

Page 81: Cake CursoORIG

Curso de CakePHP Página 81 /90

Aplicativo de Exemplo – cake_olamundo

Criando Aplicativo no CakePHP de forma Simples e Rápida

Vamos copiar a pasta app do cake para ola_cake

Criar o banco cad_cliente

Configurar ola_cake/config/database.php

Configurar ola_cake/webroot/index.php na linha com define('CAKE_CORE_INCLUDE_PATH' para:

define('CAKE_CORE_INCLUDE_PATH', dirname(dirname(dirname(__FILE__))));

Criar tabela

create table clientes (

id int not null auto_increment primary key, nome char(45) not null

);

INSERT INTO clientes (id, nome) VALUES (1,'Joao Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (2,'Roberto Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (3,'Antônio Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (4,'Carlos Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (5,'Otoniel Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (6,'Helena Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (7,'Flávio Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (8,'Joana Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (9,'Francisco Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (10,'Jorge Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (11,'Pedro Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (12,'Ribamar Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (13,'Tiago Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (14,'Elias Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (15,'Marcos Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (16,'Ricardo Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (17,'Rômulo Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (18,'Henrique Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (19,'Francis Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (20,'Otávio Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (21,'Rogério Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (22,'Jurandir Pereira Brito'); INSERT INTO clientes (id, nome) VALUES (23,'Raquél Pereira Brito');

Passos para a criação de um aplicativo básico após as configurações: - Criar o model

Ribamar FS – http://cursos.ribafs.org

Page 82: Cake CursoORIG

Curso de CakePHP Página 82 /90

- Criar o controller - Adicionar o action index para o controller - Criar a view index.ctp

Model: cake/ola_cake/models/cliente.php

<?php class Cliente extends AppModel { var $name = 'Cliente'; } ?>

Controller: cake/ola_cake/controllers/clientes_controller.php

<?php class ClientesController extends AppController { var $name = 'Clientes'; } ?>

Toda função pública dentro da classe controller é chamada de action. Esta action visualizará todos os clientes com a view index.ctp

<?php class ClientesController extends AppController { var $name = 'Clientes';

// Para a view index.ctp function index() {

$this->set('clientes', $this->Cliente->find('all')); }

} ?>

View: cake/ola_cake/views/clientes/index.ctp

<h2>Clientes</h2> <?php if(empty($clientes)): ?> Nenum cliente encontrado <?php else: ?>

Ribamar FS – http://cursos.ribafs.org

Page 83: Cake CursoORIG

Curso de CakePHP Página 83 /90

<table> <tr> <th>ID</th> <th>Nome</th> <th>Ações</th> </tr> <?php foreach ($clientes as $cliente): ?> <tr> <td> <?php echo $cliente['Cliente']['id'] ?> </td> <td> <?php echo $cliente['Cliente']['nome'] ?> </td> <td> <!-- actions on tasks will be added later --> </td> </tr> <?php endforeach; ?> </table> <?php endif; ?>

Agora chamar no navegador assim:

http://localhost/cake/ola_cake/clientes

Aí temos a listagem dos registros da tabela praticamente sem programação, apenas algumas poucas linhas.

Adicionar Registros

Para isso precisaremos adicionar uma variável (array $helpers) e uma função add() ao controller, como também adicionar uma view à pasta clientes, de nome add.ctp.

var $helpers = array('Html', 'Form');

function add() { if (!empty($this->data)) { $this->Cliente->create(); if ($this->Cliente->save($this->data)) {

$this->Session->setFlash('Cliente foi adicionado'); $this->redirect(array('action'=>'index'), null, true);

} else { $this->Session->setFlash('Cliente não adicionado. Tente novamente.');

}

Ribamar FS – http://cursos.ribafs.org

Page 84: Cake CursoORIG

Curso de CakePHP Página 84 /90

} }

Que ficará assim: cake/ola_cake/controllers/clientes_controller.php

<?php class ClientesController extends AppController { var $name = 'Clientes';

var $helpers = array('Html', 'Form');

function index() { $this->set('clientes', $this->Cliente->find('all'));

}

function add() { if (!empty($this->data)) { $this->Cliente->create(); if ($this->Cliente->save($this->data)) {

$this->Session->setFlash('Cliente foi adicionado'); $this->redirect(array('action'=>'index'), null, true);

} else { $this->Session->setFlash('Cliente não adicionado. Tente novamente.');

} }

} } ?>

Adicionar a view: cake/ola_cake/views/clientes/add.ctp

<?php echo $form->create('Cliente');?> <fieldset> <legend>Adicionar novo Cliente</legend> <?php echo $form->input('ID'); echo $form->input('Nome'); ?> </fieldset> <?php echo $form->end('Adicionar');?>

Agora chame com o navegador:

http://localhost/cake/ola_cake/clientes/add

Ribamar FS – http://cursos.ribafs.org

Page 85: Cake CursoORIG

Curso de CakePHP Página 85 /90

Adicionar um link do form Add para a nossa view index.ctp (adicionar ao final):

<?php echo $html->link('Adicionar Cliente', array('action'=>'add')); ?>

Adicionar um link para a view index na view add.ctp (ao final):

<?php echo $html->link('Listar todos os Clientes', array('action'=>'index')); ?>

Editar Registros

Para isso precisamos adicionar um action (edit) ao controller e uma view para este action (views/clientes/edit.ctp).

cake/ola_cake/controllers/clientes_controller.php

<?php class ClientesController extends AppController { var $name = 'Clientes';

var $helpers = array('Html', 'Form');

function add() { if (!empty($this->data)) { $this->Cliente->create(); if ($this->Cliente->save($this->data)) {

$this->Session->setFlash('Cliente foi adicionado'); $this->redirect(array('action'=>'index'), null, true);

} else { $this->Session->setFlash('Cliente não adicionado. Tente novamente.');

} }

}

function edit($id = null) { if (!$id) {

$this->Session->setFlash('Cliente Inválido'); $this->redirect(array('action'=>'index'), null, true);

} if (empty($this->data)) {

$this->data = $this->Cliente->find(array('id' => $id)); } else {

if ($this->Cliente->save($this->data)) { $this->Session->setFlash('O Cliente foi salvo!');

Ribamar FS – http://cursos.ribafs.org

Page 86: Cake CursoORIG

Curso de CakePHP Página 86 /90

$this->redirect(array('action'=>'index'), null, true); } else { $this->Session->setFlash('O Cliente não pôde ser salvo. Favor tentar novamente.'); }

} }

} ?>

Adicionar o link para Edição na index.ctp, para que fique assim:

<h2>Clientes</h2> <?php if(empty($clientes)): ?> Nenum cliente encontrado <?php else: ?> <table> <tr> <th>ID</th> <th>Nome</th> <th>Ações</th> </tr> <?php foreach ($clientes as $cliente): ?> <tr> <td> <?php echo $cliente['Cliente']['id'] ?> </td> <td> <?php echo $cliente['Cliente']['nome'] ?> </td> <td> <!-- actions on tasks will be added later -->

<?php echo $html->link('Editar', array('action'=>'edit', $cliente['Cliente']['id'])); ?> </td> </tr> <?php endforeach; ?> </table> <?php endif; ?>

<?php echo $html->link('Adicionar Cliente', array('action'=>'add')); ?>

Agora adicionar o link para o edit.ctp:

<?php echo $html->link('Listar Todos os Clientes', array('action'=>'index')); ?><br /> <?php echo $html->link('Adicionar Cliente', array('action'=>'add')); ?>

Ribamar FS – http://cursos.ribafs.org

Page 87: Cake CursoORIG

Curso de CakePHP Página 87 /90

Criar um Menu de entrada

Adicionar o arquivo home.ctp em views/pages:

<h1>Bem vindo ao Bake</h1> <p>Aqui podmeos fazer:</p> <ul> <li><?php echo $html->link('Lista de todos os clientes', array('controller' => 'clientes', 'action'=>'index')); ?></li> <li><?php echo $html->link('Adicionar novo Cliente', array('controller' => 'clientes', 'action'=>'add')); ?></li> <li>Editar Clientes</li> <li>Excluir Clientes</li> </ul>

Agora basta chamar no navegador: http://localhost/cake/ola_cake/

Outros Aplicativos de Exemplo encontrados no Site:

– bake– blog– estoque– foreign– forum– ola_cake

Ribamar FS – http://cursos.ribafs.org

Page 88: Cake CursoORIG

Curso de CakePHP Página 88 /90

Cake - Referências

Site oficialhttp://cakephp.org

Site Brasileiro do CakePHPhttp://cakephp.com.br/

ManuaisManual do Cake - CookBook http://book.cakephp.org/pt/complete/3/The-Manual

Manual do Cake em Portuguêshttp://manual.cakephp.com.br/doku.php

Blog Tutorialhttp://book.cakephp.org/view/219/the-cakephp-blog-tutorial

Screencastshttp://cakephp.org/screencasts

CheatSheetshttp://cakephp.org/files/Resources/CakePHP-1.2-Cheatsheet.pdf

ListasFAQs da Lista internacionalhttp://groups.google.com/group/cake-php/web/faq?pli=1

Lista internacional (em processo de mudança para outro servidor)http://groups.google.com/group/cake-php/topics

Lista portuguesahttp://groups.google.com/group/cake-php-pt

Tutoriais

Tutorial da IBM em 5 partes somando mais de 130 páginas - Cook up Web sites fast with CakePHPhttps://www.ibm.com/developerworks/opensource/tutorials/os-php-cake1/

* Part 1 focuses on getting CakePHP up and running, and the basics of how to put together a simple application allowing users to register for an account and log in to the application.http://www.ibm.com/developerworks/opensource/tutorials/os-php-cake1/os-php-cake1-pdf.pdfCódigo fonte - http://www.ibm.com/developerworks/apps/download/index.jsp?contentid=390462&filename=os-php-cake1.source.zip&method=http&locale=worldwide

* Part 2 demonstrates how to use scaffolding and Bake to get a jump-start on your application, and using CakePHP's access control lists (ACLs).

Ribamar FS – http://cursos.ribafs.org

Page 89: Cake CursoORIG

Curso de CakePHP Página 89 /90

http://www.ibm.com/developerworks/opensource/tutorials/os-php-cake2/os-php-cake2-pdf.pdfCódigo fonte - http://www.ibm.com/developerworks/apps/download/index.jsp?contentid=390704&filename=os-php-cake2.source.zip&method=http&locale=worldwide

* Part 3 shows how to use Sanitize, a handy CakePHP class, which helps secure an application by cleaning up user-submitted data. It also covers the CakePHP security component, handling invalid requests, and other advanced request authentication.http://www.ibm.com/developerworks/opensource/library/os-php-cake3/Código fonte - http://www.ibm.com/developerworks/apps/download/index.jsp?contentid=184377&filename=os-php-cake3.source.zip&method=http&locale=worldwide

* Part 4 focuses primarily on the Session component of CakePHP, demonstrating three ways to save session data, as well as the Request Handler component to help you manage multiple types of requests (mobile browsers, requests containing XML or HTML, etc.).http://www.ibm.com/developerworks/opensource/tutorials/os-php-cake4/os-php-cake4-pdf.pdfCódigo fonte - http://www.ibm.com/developerworks/apps/download/index.jsp?contentid=390856&filename=os-php-cake4.source.zip&method=http&locale=worldwide

* Part 5 deals with caching, specifically view and layout caching, which can help reduce server resource consumption and speed up your application.http://www.ibm.com/developerworks/opensource/library/os-php-cake5/?S_TACT=105AGX44&S_CMP=TUT

Outro ótimo tutorial da IBMCreate an interactive production wiki using PHP

https://www6.software.ibm.com/developerworks/education/os-php-wiki1/os-php-wiki1-pdf.pdfCódigo fonte - https://www6.software.ibm.com/developerworks/education/os-php-wiki1/downloads.html

Livros

Livros impressos sobre CakePHP

http://astore.amazon.com/cakesoftwaref-20

Outros livros:

Cakephp Application Development - http://www.packtpub.com/cakephp-application-development/book Código fonte - http://www.packtpub.com/support (Selecionar Cakephp Application Development na lista e clicar em Go)Entrar com seu e-mail para receber o código fonteTabela de conteúdo - http://www.packtpub.com/article/cakephp-application-development-table-of-contents

Ribamar FS – http://cursos.ribafs.org

Page 90: Cake CursoORIG

Curso de CakePHP Página 90 /90

Beginning CakePHP: From Novice to Professional - http://www.apress.com/book/view/1430209771Código fonte - http://www.apress.com/book/downloadfile/4046Capítulo 1 (amostra) - http://www.apress.com/book/downloadfile/4066Tabela com conteúdo - http://www.apress.com/book/downloadfile/4067

Practical CakePHP Projects - http://www.apress.com/book/view/143021578xCapítulo 1 (amostra) - http://www.apress.com/resource/bookfile/4222Código fonte - http://www.apress.com/resource/bookfile/4182Tabela com conteúdo - http://www.apress.com/book/downloadfile/4223

Ribamar FS – http://cursos.ribafs.org