Académique Documents
Professionnel Documents
Culture Documents
www.4linux.com.br
-2
Sumrio
Captulo 1 Introduo......................................................................................................................................6 1.1. MVC: Model View Controller .......................................................................................7 1.2. Object Relational Map........................................................................................................9 1.3. AJAX: Asynchronous Javascript And XML.......................................................................10 1.4. Symfony: Framework de desenvolvimento em PHP.......................................................11 1.5. Eclipse: Integrated Development Environment..............................................................12 Captulo 2 Instalando o ambiente de desenvolvimento...............................................................................13 2.1. Gerenciando pacotes com o apt-get................................................................................13 2.2. Instalando servidores e aplicativos bsicos....................................................................14 2.3. Instalando a IDE Eclipse com o EasyEclipse..................................................................15 Captulo 3 Instalando o Symfony..................................................................................................................16 3.1. Configurando um domnio virtual para a aplicao........................................................16 3.2. Porque tudo to complicado?.......................................................................................18 Captulo 4 Criando uma aplicao rpida com o Symfony..........................................................................19 4.1. Preparando o banco de dados.........................................................................................20 4.2. Criando o projeto no Symfony.........................................................................................21 4.3. Criando uma aplicao....................................................................................................21 4.4. Lendo o banco de dados e criando classes de acesso....................................................22 4.5. Configurando o Doctrine para o scaffolding...................................................................23 4.6. Ajustando rtulo de chaves estrangeiras........................................................................25 4.7. Criando um menu para navegao..................................................................................27 4.8. Criando uma pgina inicial..............................................................................................30 Captulo 5 Entendendo o Symfony................................................................................................................32 5.1. Introduo terica............................................................................................................32 5.2. Estrutura de diretrios....................................................................................................32 5.3. O MVC do Symfony..........................................................................................................34 5.4. Camada Model..................................................................................................................35 5.5. Camada View....................................................................................................................35
-3
5.6. Camada Controller...........................................................................................................36 5.7. Aplicaes, Mdulos e Aes...........................................................................................37 5.8. Ambientes e Handlers......................................................................................................38 5.9. Configurando Ambientes.................................................................................................39 5.10. A URL no Symfony.........................................................................................................42 Captulo 6 Usando o EasyEclipse..................................................................................................................45 6.1. Introduo terica............................................................................................................45 6.2. Iniciando um projeto........................................................................................................45 6.3. Criando um projeto..........................................................................................................46 6.4. Viso Geral da ferramenta...............................................................................................46 6.5. Configuraes teis.........................................................................................................47 Captulo 7 Camada Controller: controlando as requisies e respostas.....................................................48 7.1. Aes (Actions)................................................................................................................49 7.2. Trmino da ao...............................................................................................................52 7.3. Redirecionamento............................................................................................................53 7.4. ilizando sesses de usurio..............................................................................................57 7.5. Atributos Flash variveis de sesso descartveis........................................................57 7.6. Repassando variveis para a View..................................................................................58 Captulo 8 Camada Model: acesso ao banco de dados................................................................................59 8.1. Introduo terica............................................................................................................59 8.2. Classes de Tabelas...........................................................................................................62 8.3. Acessando dados atravs do Model.................................................................................62 8.4. Utilizando critrios no Doctrine......................................................................................62 8.5. Mtodos personalizados...................................................................................................63
8.5.1. Mtodo especial __toString.....................................................................................................63
8.6. Sobrescrita de mtodos...................................................................................................64 Captulo 9 Camada View: Apresentao.......................................................................................................66 9.1. Introduo terica............................................................................................................66 9.2. A montagem da View.......................................................................................................66 9.3. Partials (Parciais).............................................................................................................69 9.4. Variveis do Symfony.......................................................................................................70 9.5. Helpers.............................................................................................................................71
-4
Captulo 10 Forms: criando formulrios.........................................................................................................73 10.1. Introduo terica..........................................................................................................74 10.2. Gerando formulrios automaticamente........................................................................74 10.3. Widgets...........................................................................................................................77 10.4. Validators.......................................................................................................................79 10.5. Labels.............................................................................................................................82 10.6. Controlando o formulrio...............................................................................................83 10.7. Exibindo o formulrio....................................................................................................87
10.7.1. Mtodo automatizado...........................................................................................................87 10.7.2. Mtodo detalhado.................................................................................................................90
Captulo 11 AJAX.............................................................................................................................................92 11.1. Introduo terica..........................................................................................................92 11.2. Incluindo Javascript.......................................................................................................93 11.3. Criando um link para uma funo.................................................................................94 11.4. Alterado o contedo de um elemento HTML................................................................94 11.5. Chamando uma funo remota......................................................................................95
11.5.1. Atualizaes Peridicas........................................................................................................98 11.5.2. Formulrios AJAX..................................................................................................................99 11.5.3. Callbacks.............................................................................................................................101
Apndices...................................................................................................................................103 Captulo 12 Apndice Banco de dados "livraria"..........................................................................................................104 Captulo 13 Apndice sfDoctrineGuard plugin.............................................................................................................111
13.1.1. Implementando segurana em sua aplicao....................................................................112 13.1.2. Administrando seus usurios, permisses e grupos..........................................................114 13.1.3. Personalizando os templates do mdulo sfGuardAuth......................................................114 13.1.4. Personalizando os templates do mdulo sfGuardAuth......................................................115 13.1.5. Classe sfGuardSecurityUser...............................................................................................115 13.1.6. Flag superadministrador....................................................................................................116 13.1.7. Validators (Validadores).....................................................................................................116 13.1.8. Personalizando o Model sfGuardUser................................................................................117 13.1.9. Checar a senha do usurio com um mtodo externo.........................................................118
-5
13.1.10. Alterar o algoritmo utilizado para armazenar senhas.....................................................119 13.1.11. Alterando o nome ou o perodo de expirao do cookie "Remember Me"......................119 13.1.12. Personalizando a manipulao de redirecionamento de sfGuardAuth...........................120 13.1.13. Configurando o formulrio de login.................................................................................120
Captulo 1 Introduo - 6
Captulo 1 Introduo
Objetivo do Curso Este curso de Advanced Web Developer PHP e MySQL - 444 - visa dar bases slidas ao aluno para a construo de sistemas Web modernos, robustos, seguros e fundamentados em tcnicas dedesenvolvimento atuais e produtivas. Cabe lembrar que este nao um curso de Webdesign no h preocupao com a apresentao visual (layout) das paginas criadas, e sim com sua funcionalidade. No obstante, os arquivos so criados obedecendo os padres da W3C (World Wide Web Consortium) em XHTML vlido ou muito prximo disso, possibilitando uma ampla liberdade de criao de padres visuais (templates) com o uso de folhas de estilo em cascata (CSS). Isto sem que a funcionalidade seja abalada em qualquer momento. O curso vai trabalhar com os seguintes conceitos, tecnologia, framework e IDE: MVC - Model-View-Controller ORM - Object-Relational Mapping
Captulo 1 Introduo - 7 AJAX - Asynchronous Javascript And XML Symfony - Framework de desenvolvimento em PHP Eclipse - Integrated Development Environment
Captulo 1 Introduo - 8
Captulo 1 Introduo - 9
Captulo 1 Introduo - 10
Captulo 1 Introduo - 11
Captulo 1 Introduo - 12
1.
2.
Instalando o PHP 5
3.
4.
5.
6.
# /etc/init.d/apache2 restart
Captulo 2 Instalando o ambiente de desenvolvimento - 15 2.3. Instalando a IDE Eclipse com o EasyEclipse O Eclipse tem vrias formas de instalao: download direto, instalao via pacotes, etc. A forma mais simples de ter um ambiente rapidamente configurado e ainda poder levar aonde se quiser, fazer uso dos pacotes pr-configurados do EasyEclipse, encontrados em: http://www.easyeclipse.org A grande vantagem que os pacotes vem prontos, com a verso do Java necessria e um conjunto de plugins afins de cada linguagem de programao. Ele no muda o Eclipse, apenas o distribui com diferentes conjuntos de plugins. 1.Baixando o EasyEclipse Acesse: http://www.easyeclipse.org/site/distributions/php.html E realize o download conforme o sistema operacional desejado (em nosso caso, verso Linux). 2.Instalando o EasyEclipse O EasyEclipse um pacote compactado pronto. Basta descompactar num diretrio e rodar o executvel. Para facilitar, vamos criar um atalho para seu acesso (chamado no Gnome de Lanador). cd /opt Tar -xvzf /home/aluno/Downloads/easyeclipse-php-1.2.2.2.tar.gz
Para criar o atalho/lanador, clique com o boto direto na rea de Trabalho e selecione Criar Lanador.
O mtodo utilizado ser a instalao via php-pear, que nos permite economizar espao e facilita atualizaes do Symfony alm de backups das aplicaes. 1. Atualizando canal do Symfony no PEAR pear channel-discover pear.symfony-project.com 2. Instalando o Symfony atravs do PEAR pear install symfony/symfony-1.4.4
Captulo 3 Instalando o Symfony - 17 DirectoryIndex index.php # Permisses do diretrio dos arquivos <Directory /home/aluno/livraria444/web/> AllowOverride All Allow from All </Directory> </VirtualHost> Agora ativamos o domnio virtual com o comando a2ensite livraria444 O Symfony faz uso do mdulo rewrite do Apache para criar URLs amigveis (endereos sem .php, ponto de interrogao ou E Comercial). Para ativ-lo, faz-se uso do comando: a2enmod rewrite Agora podemos recarregar o Apache para que estas alteraes tenham efeito: /etc/init.d/apache2 reload Feito isso, vamos criar a estrutura de diretrios padro do nosso aplicativo: mkdir /home/aluno/livraria444 mkdir /home/aluno/livraria444/web Para que seja possvel a navegao, precisamos ajustar nosso arquivo hosts: echo 127.0.0.1 livraria.local>>/etc/hosts
Uma das capacidades de um framework a possibilidade de criao de aplicaes rapidamente, em especial com integrao com o banco de dados. Sistemas que interagem com banco de dados possuem uma caracterstica interessante: a maioria das tabelas acessada para quatro operaes bsicas: Criar um registro na tabela Recuperar um registro (ou vrios) da tabela Atualizar um registro da tabela Excluir um registro da tabela
Estas operaes so conhecidas pela sigla em ingls CRUD: Create, Retrieve, Update, Delete. A grande maioria dos frameworks permite criar telas automaticamente para
Captulo 4 Criando uma aplicao rpida com o Symfony - 20 utilizao destas operaes. O Symfony no diferente, e sem a necessidade de nenhuma linha de programao possvel criar um mdulo para navegar em todas as tabelas de um banco de dados.
projero(/home/aluno/livraria444)
Captulo 4 Criando uma aplicao rpida com o Symfony - 22 A opo csrf-secret=SenhaQualquer proteje a aplicao contra ataques de CSRF (Cross-site request forgery) e pode ser adicionada antes do nome da aplicao admin o nome da aplicao criada
Informaes sobre estes tipos de ataques a sites web: http://pt.wikipedia.org/wiki/Cross-site_scripting http://en.wikipedia.org/wiki/CSRF J possvel acessar o projeto atravs do endereo: http://livraria.local O ambiente de desenvolvimento fica disponvel em: http://livraria.local/admin_dev.php Veja a barra de debug que aparece no canto superior direito.
all: doctrine: class: sfDoctrineDatabase param: dsn: mysql:host=localhost;dbname=livraria444 username: livraria444 password: senha444
O Doctrine utiliza um arquivo XML para criar as classes de acesso a dados. Para facilitar nosso trabalho, o Symfony cria este arquivo a partir do banco de dados com o comando a seguir: symfony doctrine:build-schema Model so classes de acesso a dados. O Symfony cria as classes para todas as tabelas no banco de dados incluindo relacionamentos atravs do comando: symfony doctrine:build-model
Captulo 4 Criando uma aplicao rpida com o Symfony - 24 O Symfony tambm cria as classes de formulrios para todas as tabelas do banco de dados. Isto facilita a criao de formulrios com validao, mensagens de erro, etc. Para criar os formulrios com o Symfony, usamos o comando: symfony doctrine:build-forms
Os formulrios ficam disponveis em lib/form/doctrine Os mdulos seriam equivalentes, a grosso modo, a arquivos .php que recebem parmetros e realizaes baseadas neles. Os mdulos so criados dentro de uma aplicao, e so diretrios dentro do diretrio da aplicao. Como o Symfony trabalha com MVC, e o Model j foi criado, no mdulo ficam o Controller (action) e a View (templates). Para gerar um mdulo, fazemos uso do cdigo abaixo: symfony doctrine:generate-module admin categoria Categoria Onde: admin: a aplicao, residente em apps/admin categoria: o nome do mdulo a ser criado, em
importante perceber que o nome do Model tem a inicial maiscula, como foi gerado pelo Symfony. Uma vez que o comando termine, j possvel navegar na tabela categoria dentro do Symfony atravs da url: http://livraria.local/categoria
Captulo 4 Criando uma aplicao rpida com o Symfony - 25 Tambm possvel navegar em modo de desenvolvimento (debug): http://livraria.local/admin_dev.php/categoria Pode-se criar os mdulos para cada tabela do banco de dados que seja necessria symfony doctrine:generate-module admin cliente Cliente symfony doctrine:generate-module admin livro Livro symfony doctrine:generate-module admin pedido Pedido symfony doctrine:generate-module admin pedidoitem Pedidoitem symfony doctrine:generate-module admin usuario Usuario E tambm podemos navegar nestas tabelas pelos respectivos links: http://livraria.local/admin_dev.php/cliente http://livraria.local/admin_dev.php/livro http://livraria.local/admin_dev.php/pedido http://livraria.local/admin_dev.php/pedidoitem http://livraria.local/admin_dev.php/usuario
Captulo 4 Criando uma aplicao rpida com o Symfony - 26 Por exemplo, para a tabela cliente temos: lib/model/doctrine/base/BaseCliente.class.php lib/model/doctrine/Cliente.class.php As tabelas que possuem este tipo de relacionamento so: O primeiro arquivo no deve ser alterado, pois numa atualizao do Model ser sobrescrito. Toda a nossa personalizao ser realizada no segundo, que uma classe extendida da primeira. Para preencher os rtulos dos comboboxes criamos um mtodo __toString que retorna um dos campos da tabela. Neste momento apenas criaremos mecanicamente; mas adiante entenderemos como so feitas as chamadas aos campos. categoria (estrangeira para livro) cliente (estrangeira para pedido) pedido (estrangeira para pedidoitem)
Ento vamos alterar estes arquivos como segue: <?php // lib/model/doctrine/Categoria.class.php class Categoria extends BaseCategoria { public function __toString() { return $this->getNome(); } }
<?php
Captulo 4 Criando uma aplicao rpida com o Symfony - 27 // lib/model/doctrine/Cliente.class.php class Cliente extends BaseCliente { public function __toString() { return $this->getNome(); } }
<?php // lib/model/doctrine/Pedido.class.php class Pedido extends BasePedido { public function __toString() { return $this->getStatus(); } } Apesar de no ser perfeito ainda ( o formulrio para tabela livro no exibe o ISBN, mas corrigiremos isso mais adiante), nos falta apenas um menu para navegar nestas tabelas.
Captulo 4 Criando uma aplicao rpida com o Symfony - 28 O arquivo possui o cabealho e rodap da pgina, e inclui o contedo gerado pelos templates de cada mdulo da aplicao. Ele criado em HTML com os trechos em PHP includos, pois faz parte da View do MVC. <!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" xml:lang="en" lang="en"> <head> <?php include_http_metas() ?> <?php include_metas() ?> <?php include_title() ?> <link rel="shortcut icon" href="/favicon.ico" /> <?php include_stylesheets() ?> <?php include_javascripts() ?> </head> <body> <?php echo $sf_content ?> </body> </html>
Captulo 4 Criando uma aplicao rpida com o Symfony - 29 Para criarmos um menu modificamos seu cdigo como segue: <!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" xml:lang="en" lang="en"> <head> <?php include_http_metas() ?> <?php include_metas() ?> <?php include_title() ?> <link rel="shortcut icon" href="/favicon.ico" /> <?php include_stylesheets() ?> <?php include_javascripts() ?> </head> <body> <div id=menu> <a href=<?php echo url_for('categoria/index');?>>Categoria</a> <a href=<?php echo url_for('cliente/index');?>>Cliente</a> <a href=<?php echo url_for('livro/index');?>>Livro</a> <a href=<?php echo url_for('pedido/index');?>>Pedido</a> <a href=<?php echo url_for('pedidoitem/index');?>>Pedido Item</a> <a href=<?php echo url_for('usuario/index');?>>Usuário</a> </div> <?php echo $sf_content ?> </body> </html> A funo url_for cria os links no formato do Symfony para o par mdulo/ao. Mais tarde, compreendendo melhor as aes, ficar mais clara sua utilizao. No momento, sabemos que ela criar de forma organizada, respeitando inclusive o ambiente (de produo ou de desenvolvimento).
Nos falta uma index para carregarmos automaticamente. Para no misturarmos com os mdulos criados para cada tabela, criaremos um mdulo sem vnculo com tabela nenhuma, chamado index. symfony generate:module admin index Se navegamos agora para: Http://livraria.local/index Veremos a pgina padro do Symfony para novos mdulos criados. Isto facilmente alterado, como esta prpria pgina explica, retirando o forward (redirecionamento) que feito na ao padro deste novo mdulo, no arquivo: <?php // apps/modules/index/actions/action.class.php class indexActions extends sfActions { public function executeIndex(sfWeRequest $request) { } } Qualquer contedo que queiramos colocar nele, alm do menu que j estar como padro da aplicao, s alterar em seu template que se encontra em: apps/admin/modules/index/templates/indexSuccess.php Ele est criado vazio. Podemos alter-lo para: <h1>Bem vindo Livraria do TUX</h1> <h2>Utilize o menu para navegar</h2>
Mas para ele tornar-se padro preciso alterar o arquivo de configurao do mdulo e direcionar para o par (modulo/ao) desde mdulo criado. apps/admin/config/routing.yml
#default rules homepage: url: / param: { module: index, action: index } default_index: url: /:module param: { action: index } default: url: /:module/:action/* Foi alterado em homepage, param, module de default (mdulo padro do Symfony) para index (mdulo recm-criado). Neste momento descobrimos uma funcionalidade do Symfony que nos atrapalha neste momento: o Cache. Todos os arquivos de configurao, para maior velocidade, so verificados em sua primeira utilizao e ento o Symfony cria arquivos otimizados em Cache. Isto excelente, mas quando alteramos um arquivo de configurao ou mudamos a localizao de algum arquivo de classe ele no encontrado enquanto no zeramos o cache. Isto feito com o comando: symfony cc Agora podemos acessar a pgina index diretamente: http://livraria.local Podemos tambm acessar o modo de desenvolvimento e debug: http://livraria.local/admin_dev.php
Captulo 5 Entendendo o Symfony - 33 apps: Cada aplicao corresponde a um diretrio dentro de apps; cache: Cache criado pelo Symfony, para otimizao de desempenho; config: Arquivos de configurao global do projeto; data: Diretrio com dados que podem ser importados no banco de dados, ou outras formas de dados variveis que sero gravados (por exemplo, um banco de dados SQLite); doc: Reservado para documentao do projeto; lib: Localizao de Models, Forms e no caso do SandBox, as bibliotecas do Symfony; log: Registro de atividades do projeto. til para debug e rastreio; plugins: Reservado para plugins que expandem as funcionalidades do Symfony; test: Diretrio de testes personalizados; web: Pasta pblica que contm arquivos acessados via navegador. Especialmente aqui esto imagens, css, javascript alm dos arquivos pblicos do prprio Symfony;
A implementao do MVC do Symfony utiliza-se de vrios arquivos, o que inicialmente pode parecer confuso: Camada Model: Abstrao de Banco de Dados (Database abstraction) Acesso a Dados (Data access) Camada View: Layout Lgica de Apresentao Template Camada Controller: Controle Frontal (Front controller) Ao (Action)
Entretanto, na prtica, com o uso dos geradores de cdigo (em especial as opes dos comandos symfony doctrine:? ) a maioria desses arquivos j fica disposio do desenvolvedor, seja de forma permanente, seja como base para personalizaes.
Os arquivos criados pelo Symfony atravs dos comandos symfony doctrine:? Sero guardados dentro de lib/model/map e lib/model/om. So classes abstratas (no caso de classes de tabelas) que servem de base para as classes extendidas que se encontram em lib/model. Estas sim so classes disponveis ao desenvolvedor, e onde pode-se incluir novos mtodos conforme sua necessidade. Esta estrutura permite que o Symfony recrie os arquivos base sem afetar as personalizaes do desenvolvedor.
Captulo 5 Entendendo o Symfony - 36 locais de layouts e templates. No Symfony, o termo templates referncia a arquivos chamados por aes do mdulo para compor o corpo da pgina. O layout geralmente os inclui em seu corpo. Localizam-se nos diretrios dos mdulos, pe no formato templates apps/aplicao/modules/modulo/templates. parciais (partials). A Lgica de Apresentao consiste na montagem desde quebra cabeas que resulta na pgina final exibida para o usurio. Isto envolve processos automatizados do Symfony mas tambm personalizaes que o desenvolvedor queira fazer diretamente no cdigo dos templates e layouts. Os arquivos de templates e layouts so arquivos em XHTML (por padro, mas fica a cargo da necessidade do desenvolvedor) e PHP comuns, com acesso a variveis especiais do Symfony para gerao de contedo de forma dinmica. Tambm possvel
Ao abrirmos o Diretrio ADMIN, nos encontramos com a seguinte estrutura de diretrios. Config: Arquivos de configurao da aplicao, em formato YAML (um simplificador do formato XML); i18n: Arquivos de traduo para aplicativos multilnguas; lib: Classes exclusivas do aplicativo; modules: Mdulos da aplicao; template: Layouts da aplicao (templates disponveis para todos os mdulos); actions: Controllers do mdulo. Normalmente s necessrio um arquivo, action.class.php; templates: Diretrio de templates do mdulo;
importante ter acesso a ferramentas de debuf, verificar variveis em execuo, realizadas banco dados, requisies, etc; tambm comum existir um banco de dados em teste e um banco de dados em produo; No Primeiro caso so praticamente dois sistemas diferentes (ou mais...) acessando o mesmo banco de dados com regras de requisio e resposta diferentes, apresentao diferente, mas com as mesmas regras de negcio de acesso ao banco. No segundo caso os desenvolvedores possuem um trabalho muito grande de ligar e desligar debugs, ter cpia de ambientes diferentes, com acesso a banco de dados diferentes, manter sincronizados estes dois ambientes, ou ento, mesmo que somente em sua mquina de desenvolvimento, h muita mo-de-obra para testar a viso do usurio final. O Symfony, para facilitar a vida do desenvolvedor, permite a criao de vrios ambientes dentro de um projeto, e para isto, utiliza os handlers. Handlers so arquivos em PHP que fazem o primeiro trabalho da Camada Controller, que definir qual aplicao, mdulo e ao sero executados.
all: doctrine: class: sfDoctrineDatabase param: dsn: mysql:host=localhost;dbname=livraria444 username: livraria444 password: senha444
Captulo 5 Entendendo o Symfony - 40 Ento temos os ambientes dev, test, alm do prod, que padro e est omitido por no possuir personalizaes na configurao inicial. Alm deles temos o all que determina valores padro para todos os ambientes (que podem ser sobrescritos individualmente). prod: Ambiente de produo, com cache ativado e com apenas alertas de erros(sem debug); dev: Ambiente de desenvolvimento, com cache desativado, erros em nvel mximo(com debug); test: Ambiente especial semelhante ao de produo, mas que s executado em linha de comando para rodar testes automatizados; ??: possvel configurar outros ambientes personalizados.
Muito comum o ambiente de desenvolvimento utilizar outro banco de dados; ou ento, um ambiente intermedirio, com uma cpia do banco de produo criado para testes, mas com debug. Quando uma nova aplicao criada, por padro so criados dois handlers: web/minhaaplicacao.php: corresponde ao ambiente de produo; web/minhaaplicacao_dev.php; desenvolvimento; corresponde ao ambiente de
Se a aplicao a primeira a ser criada, seu ambiente de produo ter como handler web/index.php, e torna-se o aplicativo padro do projeto. Uma ferramenta importante do Symfony a barra de Debug, uma barra flutuante que aparece em todas as pginas, fornecendo informaes valiosas sobre varveis e consultas a banco de dados.
Captulo 5 Entendendo o Symfony - 41 Essa barra de debug ativada dentro do handler: <?php if(!in_array(@$_SERVER['REMOTE_ADDR'], array('127.0.0.1','::1'))) { die('You are not allowed to access this file. Check '. basename(__FILE__).' for more information.'); } require_once(dirname(__FILE__). '/../config/ProjectConfiguration.class.php'); $configuration = ProjectConfiguration::getApplicationConfiguration ('admin', 'dev', true); sfContext:createInstance($configuration)->dispatch(); ?> A ateno especial dada aos parmetros do mtodo esttico: ProjectConfiguration::getApplicationConfiguration('admin', 'dev', true); Ele recebe trs parmetros: aplicao: no exemplo 'admin'; ambiente: no exemplo 'dev'. Podendo ainda ser 'prod' (oque o caso do ambiente de produo) ou outro ambiente que tennha sido configurado no arquivo config/databases.yml webdebug: no exemplo true, ou seja, ativo(no ambiente de produo, false);
() // APLICAO = admin, AMBIENTE = prod, DEBUG = false $configuration () J o mdulo e a ao so os definidos no arquivo: apps/minhaaplicacao/config/routing.yml dentro da opo homepage, param () homepage: url: / param: {module: default, action: index} () = ProjectConfiguration::getApplicationConfiguration ('admin', 'prod', 'false');
Captulo 5 Entendendo o Symfony - 43 2. Situao 2 Um handler diferentes http://livraria.local/admin_dev.php Se o primeiro parmetro um handler, ento executado este handler, que estar no diretrio web, que define a aplicao. J o mdulo e a ao seguem a mesma situao acima, sendo definidos no arquivo: apps/minhaaplicacao/config/routing.yml 3. Situao 3 mdulo http://livraria.local/categoria http://livraria.local/admin_dev.php/categoria Se o primeiro parmetro no um handler, ou ento um handler seguido de uma barra mais uma palavra, ento esta ltima informao um mdulo (no exemplo acima, categoria). A ao definida no arquivo: apps/minhaaplicacao/config/routing.yml dentro da opo default_index, param (valor padro index). () default_index: url: /:module param: {action: index} () 4. Situao 4 mdulo/ao http://livraria.local/categoria/new http://livraria.local/admin_dev.php/categoria/new
Captulo 5 Entendendo o Symfony - 44 Se o primeiro parmetro no um handler, ou ento um handler seguido de uma barra mais uma palavra e de outra barra e palavra, ento esta ltima informao uma ao (no exemplo acima, new) e a penltima um mdulo (no exemplo acima, categoria). 5. Situao 5 mdulo/ao/variavel/valor http://livraria.local/categoria/edit/cat_id/1 http://livraria.local/admin_dev.php/categoria/edit/cat_id/1 Se j esto identificados aplicao, mdulo e ao, ento o que segue so sempre pares de varivel/valor, que sero enviados via GET. No exemplo acima, a ao edit do mdulo categoria receber a varivel cat_id com o valor 1. Seria o equivalente a: http://livraria.local/categoria/edit?cat_id=1 http://livraria.local/admin_dev.php/categoria/edit?cat_id=1 no PHP natural, o que equivaleria no script de destino a varivel: $_GET['cat_id'] = 1 apesar de que utiliza-se um mtodo prprio no Symfony para recuperar esta varivel, como ser visto mais adiante. Se houverem mais pares de varivel/valor, seguiro as mesmas regras: http://livraria.local/categoria/edit/cat_id/1/descricao/Romance http://livraria.local/admin_dev.phpcategoria/edit/cat_id/1/descricao/Romanc e equivale s variveis no destino: $_GET['cat_id'] = 1 $_GET['descricao'] = 'Romance'
Captulo 6 Usando o EasyEclipse - 47 De moro geral, alguns atalhos de teclado so teis em todos os editores: CTRL+espao: sugere complementao de comandos ou parmetros; TAB: identa o cdigo vlido para vrias linhas selecionadas; SHIFT+TAB: selecionadas; CTRL+PGUP, CTRL+PGDN: navega pelas abas do editor(arquivos abertos); A lista completa de atalhos de teclado est disponvel no menu Help/ Key Assist... O EasyEclipse guarda a ltima janela encerrada; ou seja, quando se abrir novamente o EasyEclipse ele vai abrir exatamente como foi encerrado. Uma janela muito til do EasyEclipse o Outline, que permite a navegao dentro de um arquivo por exemplo, numa classe so listados os mtodos; num arquivo CSS, cada uma das entradas, etc. desidenta o cdigo vlido para vrias linhas
Pelo padro MVC o Controller oque faz a interconexo entre a lgica de negcio (Model) e a apresentao (View). Basicamente o Symfony separa o Controller nos seguintes componentes: Front Controller (Controle frontal): ponto de entrada nico da aplicao; carrega a configurao e determinao de qual ao ser executada; Actions(Aes): lgica da aplicao, verifica a integridade da requisio e prepara os dados necessrios para a camada de apresentao; Objetos Request, Response, Session: do acesso aos parmetros requisitados, cabealhos de resposta e aos dados persistentes.
Captulo 7 Camada Controller: controlando as requisies e respostas - 50 exist (%s).', $request->getParameter('id'))); $this->form = new PessoaForm($pessoa); } public function executeUpdate(sfWebRequest $request) { $this->forward404Unless($request->isMethod(sfRequest::POST) || $requ est->isMethod(sfRequest::PUT)); $this->forward404Unless($pessoa = Doctrine::getTable('Pessoa')>find(array($request->getParameter('id'))), sprintf('Object pessoa does not exist (%s).', $request->getParameter('id'))); $this->form = new PessoaForm($pessoa); $this->processForm($request, $this->form); $this->setTemplate('edit'); } public function executeDelete(sfWebRequest $request) { $request->checkCSRFProtection(); $this->forward404Unless($pessoa = Doctrine::getTable('Pessoa')>find(array($request->getParameter('id'))), sprintf('Object pessoa does not exist (%s).', $request->getParameter('id'))); $pessoa->delete(); $this->redirect('pessoa/index'); } protected function processForm(sfWebRequest $request, sfForm $form) { $form->bind($request->getParameter($form->getName()), $request>getFiles($form->getName())); if ($form->isValid())
Captulo 7 Camada Controller: controlando as requisies e respostas - 51 { $pessoa = $form->save(); $this->redirect('pessoa/edit?id='.$pessoa->getId()); } } } As aes devem manter o seguinte padro de nomenclatura para o mtodo: Iniciar com a palavra execute toda em minscula; Continuar com o nome da ao, com a primeira letra em maiscula;
Mtodos que no seguem este padro no so aes, no podem ser acessadas pelo Front Controller, apesar de ser possvel seu uso internamente pela classe, conforme a necessidade.
7.2. Trmino da ao
As aes ao seu trmino, por padro, chamam um template de mesmo nome e sufixo Success. Portanto, a ao executeIndex chamar o template indexSucess.php, a ao executeList chamar o template listSuccess.php, e assim por diante. Na realidade existe um return implcito ao final de cada ao chamando a View padro, que : // Ambas aes chamam a View Success correspondente a cada ao public function executeIndex(sfWebRequest $request) { $this->pessoas = Doctrine::getTable('Pessoa') ->createQuery('a') ->execute(); } Para chamar uma View personalizada, a ao deve terminar assim: // O Symfony va procurar o template actionNameMeuTemplate.php public function executeIndex(){ return 'MeuTemplate'; } Mas possvel no chamar nenhum template. Este o caso, por exemplo, para funes que sero executadas em modo batch, ou em agendamentos no cron, ou seja, no tero sada. // O Symfony no vai executar nenhum template public function executeAgendamento(){ return sfView::NONE; }
7.3. Redirecionamento
O Symfony permite dois tipos de redirecionamento: Para outra ao: algo interno, e no interfere na URL exibida para o usurio, que nem percebe que isto aconteceu; public function executeList(){ $this->forward('meumodulo','index'); } Para outra URL (Redirect) public function executeList(){ $this->redirect('meumodulo/index'); $this->redirect('http://www.terra.com.br');
O forward e o redirect functionam como o return, ou seja, o cdigo aps eles nunca ser executado. Existe um tipo de redirecionamento bastante comum, que o da pgina no encontrada (erro 404 do Apache). Seu uso exemplificado a seguir: $this->forward404Unless($pessoa = Doctrine::getTable('Pessoa')>find(array($request->getParameter('id'))), sprintf('Object pessoa does not exist (%s).', $request->getParameter('id'))); $this->form = new PessoaForm($pessoa);
A pgina de erro pode ser personalizada. Basta criar um template em um mdulo, uma ao e alterar a configurao no arquivo config/settings.yml da aplicao:
Captulo 7 Camada Controller: controlando as requisies e respostas - 54 all: .actions: error_404_module: default error_404_actions: error404 Entretanto comum necessitarmos realizar redirecionamento aps um teste lgico. Para isto o Symfony dispe de mais alguns mtodos: forwardIf() forwardUnless() forward404If() forward404Unless() redirectIf() redirectUnless()
$this->forward404Unless($pessoa = Doctrine::getTable('Pessoa')>find(array($request->getParameter('id'))), sprintf('Object pessoa does not exist (%s).', $request->getParameter('id'))); $this->form = new PessoaForm($pessoa); Quando o cliente envia uma requisio, uma srie de informaes so recebidas pelo servidor Web, como dados sobre navegador, URL, GET e POST. O Symfony dispe de todas estas informaes ao Controller atravs do objeto sfWebRequest Informaes da Requisio ------------------------------------------------------------------------------------------------------------------Nome Funo =>Exemplo ------------------------------------------------------------------------------------------------------------------isMethod($method) POST ou GET => true or false
Captulo 7 Camada Controller: controlando as requisies e respostas - 55 getMethod()Nome do mtodo de requisio => 'POST' getHttpHeader('Server') HTTP header => 'Apache/2.0.59 (Unix) DAV/2PHP/5.1.6'
getCookie('teste') Valor do nome do cookie => 'testando' isXmlHttpRequest() uma requisio Ajax? => true isSecure() uma requisio SSL? => true hasParameter('teste')Parmetro presente na requisio => true getParameter('teste') Valor de um parmetro => 'testando' getParameterHolder()->getAll() requisio ------------------------------------------------------------------------------------------------------------------Informaes da URI ------------------------------------------------------------------------------------------------------------------getUri() URI completa => 'http://localhost/mymodule/myaction' getPathInfo()Informao do caminho => 'mymodule/myaction' getReferer() Referer Array com todos os parmetros de
Captulo 7 Camada Controller: controlando as requisies e respostas - 56 => 'http://localhost/' getHost()Nome do Host => 'localhost'
getScriptName()Nome do Front Controller => 'index.php' ------------------------------------------------------------------------------------------------------------------Informao do navegador do cliente ------------------------------------------------------------------------------------------------------------------getLanguages() Array com as lnguas disponveis => Array( [0] => en_US [1] => en ) getCharsets() Array com os charsets disponveis => Array( [0] => UTF-8 [1] => ISO-8859-1 ) getAcceptableContentTypes() Array com os content types disponveis => Array( [0] => text/xml [1] => text/html ) O primeiro parmetro recebido pela ao o objeto sfWebRequest, ento, comumente recebido como uma varivel: $this->pessoas = Doctrine::getTable('Pessoa')->find(array($request>getParameter('id'))) ->createQuery('a') ->execute();
Captulo 7 Camada Controller: controlando as requisies e respostas - 58 Para resolver este tipo de situao, o Symfony possui uma varivel de sesso descartvel, chamada flash. O importante lembrar: o valor do atributo flash s est disponvel dentro de uma mesma requisio. // Definindo o valor numa ao $this->getUser()->setFlash('mensagem','Registro Salvo'); // () // Recuperando o valor em outra ao $mensagem = $this->getUser()->getFlash('mensagem'); Tambm pode ser til recuperar o atributo flash num template. Para isto, s utilizar o objeto $sf_user: <?php if($sf_user->hasFlash('mensagem')): ?> <?php echo $sf_user->getFlash('mensagem') ?> <?php endif; ?>
Captulo 8 Camada Model: acesso ao banco de dados - 60 Exemplo: public function getPrimeiroNome() public function getSobrenome() public function getNomeCompleto() O mtodo getNomeCompleto utiliza os dois mtodos anteriores para apresentar o nome completo de um cliente, por exemplo. Independente de mudanas nos nomes dos campos ou at em qual banco (MySQL, Postgres, Oracle, etc) ser acessado, este mtodo estar sempre disponvel e consistente. Informaes mais complexas como o total de uma nota fiscal tambm podem ser criadas desta forma e acessando outras tabelas atravs de suas classes respectivas. Outra imensa vantagem no preocupar-se com as variaes nas sintaxes SQL entre diferentes bancos de dados. Padres de nomes de campos, tabelas e chaves estrangeiras, no so obrigatrios, mas facilita na posterior utilizao dos mtodos das classes. Nomes de tabelas sem hifens ou underscore (sublinhado vazio); Nomes de tabelas em minsculas; Nomes de campo em minsculas, com underscore (sublinhado vazio) separando campos grandes; O Doctrine ORM principal do Symfony em sua verso 1.4.4 converte campos como nome_funcionario para um mtodo como getNomeFuncionario, oque bastante claro e legvel. Os nomes de tabela so convertids de cliente para classe Cliente. muito importante definir chaves estrangeiras, pois o Doctrine vasculha os relacionamentos e cria os devidos mtodos de acesso.
Captulo 8 Camada Model: acesso ao banco de dados - 61 O Doctrine ORM baseia a construo dos modelos num arquivo schema.yml que possui uma estrutura como no exemplo a seguir: Pessoa: connection: doctrine tableName: pessoa columns: id: type: integer(4) fixed: false unsigned: false primary: true autoincrement: true nome: type: string() fixed: false unsigned: false primary: false notnull: true autoincrement: false sobre_nome: type: string() fixed: false unsigned: false primary: false notnull: true autoincrement: false email: type: string(45) fixed: false unsigned: false primary: false notnull: true autoincrement: false
Captulo 8 Camada Model: acesso ao banco de dados - 62 Neste curso no abordaremos esta forma de criao de Models, mas com a varredura do banco para criao deste esquema (como visto no captulo Criando uma aplicao rpida com o Symfony). Tambm j foi citado que na criao dos Models h dois tipos de arquivos: mapeamento, classes das tabelas. Vamos detalhar um pouco os ltimos dois, que so os utilizados na prtica.
WHERE column <> value => where(colum <> value); ------------------------------------------------------------------------------------------------------------------DQL ------------------------------------------------------------------------------------------------------------------http://www.doctrine-project.org/documentation/manual/1_2/en/dql-doctrinequery-language ------------------------------------------------------------------------------------------------------------------Outras Sintaxes ------------------------------------------------------------------------------------------------------------------ORDER BY column ->addAscendingOrderByColumn(column); LIMIT limit ->limit(limit);
Captulo 8 Camada Model: acesso ao banco de dados - 64 // lib/model/Pessoas.php class Pessoa extends BasePessoa{ public function __toString(){ return $this->getCodigo().'-'.$this->getNome(); } } foi determinado como legenda a concatenao entre Cdigo e Nome da Pessoa. Poderia ser qualquer outro formato necessrio.
Captulo 8 Camada Model: acesso ao banco de dados - 65 if ($this->nome !== $v) { // Colocando todas as letras em maisculas $this->nome = strtoupper($v); } return $this; } // setNome() } ?> Uma pequena alterao: o nome ser convertido todo para maisculas antes de ser gravado.
Captulo 9 Camada View: Apresentao - 66 de programao, importante compreendermos onde vamos colocar nosso cdigo.
Captulo 9 Camada View: Apresentao - 67 <!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" xml:lang="en" lang="en"> <head> <meta HTTP-EQUIV="content-type" CONTENT="text/html; charset=utf-8" /> <meta name="title" CONTENT="symfony project" /> <meta name="robots" CONTENT="index, follow" /> <meta name="description" CONTENT="symfony project" /> <meta name="keywords" CONTENT="symfony, project" /> <title>symfony project</title> <link REL="stylesheet" TYPE="text/css" HREF="/css/main.css" /> <link REL="shortcut icon" HREF="/favicon.ico"> </head> <body> <h1>Ol, Mundo</h1> </body> </html> Ento percebe-se que o trecho de cdigo: <?php echo $sf_content ?> inclui o template. Conforme a distribuio do layout da pgina (com cabealho, menu, rodap, etc), ento posicionamos este cdigo adequadamente. Existem tambm trs funes especiais (include_http_metas(),
include_metas(), include_title()). Elas geram os headers do XHTML/HMTL baseados na configurao da View na aplicao e no mdulo requisitado. Para a aplicao, encontramos esta configurao em: apps/aplicacao/config/view.yml
default:
Captulo 9 Camada View: Apresentao - 68 http_metas: content-type: text/html metas: #title: symfony project #description: symfony project #keywords: symfony, project #language: en #robots: index, follow stylesheets: [main.css] javascripts: [] has_layout: on layout:layout Para o mdulo, no h um arquivo criado. Se criado, ele vai ser lido em cascata, ou seja, o que estiver na configurao lido primeiro, e depois ele lido e sobrescreve as informaes. apps/aplicacao/modulo/config/view.yml
editSuccess: metas: title: Editando Pessoa listSuccess: metas: title: Listagem de Pessoas printSuccess: metas: title: Imprimir registro
Captulo 9 Camada View: Apresentao - 69 stylesheets: [print.css] all: metas: title: Cadastro de Pessoas No exemplo acima, a palavra chave all representa um padro para o mdulo, e cada template referenciado possui informaes personalizadas. Isto uma forma muito simples de incluir arquivos javascript onde so necessrios, por exemplo.
Captulo 9 Camada View: Apresentao - 70 Entretanto, os partials no tem acesso s variveis disponveis.
9.5. Helpers
Helpers so funes em PHP que retornam algum tipo de trecho em HTML. O Symfony possui vrios pr-definidos e possvel tambm criar Helpers personalizados. Existem vrios grupos de Helpers, e nem todos esto ativos por padro. Para carregar um que no esteja ativo, utiliza-se: <?php use_helper('HelperName') ?> <?php use_helper('HelperName1', 'HelperName2', 'HelperName3') ?>
Abaixo uma lista dos mais utilizados. // Grupo Tag // ========= <?php echo tag('input', array('name' => 'endereco', 'type' => 'text')) ?>
Captulo 9 Camada View: Apresentao - 71 // ou <?php echo tag('input', 'name=endereco type=text') ?> => <input name="endereco" TYPE="text" /> <?php echo content_tag('textarea', 'Texto livre', 'name=texto') ?> => <textarea name="texto">Texto livre</textarea>
// Grupo Url // ========= // Link para a ao de criao de novo registro no mdulo pessoa // Importante: o link ser gerado considerando o roteamento, // o front controller atual, etc. <?php echo link_to('Nova Pessoa', 'pessoa/new') ?> => <a HREF="/pessoa/new">Nova Pessoa</a>
// Grupo Asset // =========== // Tag IMG <?php echo image_tag('logo.png', 'alt=Logotipo size=200x100') ?> => <img SRC="/images/logo.png" ALT="Logotipo" WIDTH="200" height="100"/> // Incluindo Javascript <?php echo javascript_include_tag('atualizar') ?> => <script language="JavaScript" TYPE="text/javascript" src="/js/atualizar.js"></script> // Incluindo CSS <?php echo stylesheet_tag('formatacao') ?> => <link HREF="/stylesheets/formatacao.css" MEDIA="screen" rel="stylesheet"type="text/css" />
Captulo 10 Forms: criando formulrios - 74 mensagem informativa, confirmando ou no a gravao. Estas tarefas se tornam ainda mais tediosas e de complexa manuteno conforme aumenta o nmero de tabelas e campos nestas tabelas. O Symfony prope uma abordagem muito eficiente para centralizar tanto a criao como a validao dos formulrios. Veremos agora como utilizar de forma bsica seus recursos.
<?php class BaseLivroForm extends BaseFormDoctrine { public function setup() { $this->setWidgets(array( 'isbn' => new sfWidgetFormInputHidden(), 'autor'=> new sfWidgetFormInput(), 'titulo' => new sfWidgetFormInput(), 'cat_id' => new sfWidgetFormDoctrineChoice( array('model' => 'Categoria', 'add_empty' => true)), 'preco'=> new sfWidgetFormInput(),
Captulo 10 Forms: criando formulrios - 75 'sumario' => new sfWidgetFormInput(), )); $this->setValidators(array( 'isbn' => new sfValidatorDoctrineChoice( array('model' => 'Livro', 'column' => 'isbn', 'required' => false)), 'autor'=> new sfValidatorString( array('max_length' => 80, 'required' => false)), 'titulo' => new sfValidatorString( array('max_length' => 100, 'required' => false)), 'cat_id' => new sfValidatorDoctrineChoice( array('model' => 'Categoria', 'column' => 'cat_id', 'required' => false)), 'preco'=> new sfValidatorNumber(), 'sumario' => new sfValidatorString( array('max_length' => 1000, 'required' => false)), )); $this->widgetSchema->setNameFormat('livro[%s]'); $this->errorSchema = new sfValidatorErrorSchema( $this->validatorSchema); parent::setup(); } public function getModelName() { return 'Livro';
Captulo 10 Forms: criando formulrios - 76 } } ?> Lembrando que ele no deve ser alterado ou acessado diretamente, mas sim a classe extendida LivroForm que est em: lib/form/doctrine/LivroForm.class.php
O que for implementado dentro do mtodo configure() sobrescreve o que foi definido na classe Base. Podemos identificar na classe Base quatro trechos bsicos que so: $this->setWidgets: define os widgets (elementos de formulrio) para cada campo da tabela; $this->setValidators: define os validadores para cada campo da tabela; $this->widgetSchema->setNameFormat: define um padro para os nomes de campos (o padro criar um array com o nome da tabela, onde cada chave do array o nome de um campo);
Os dois ltimos so padronizados e raramente til personaliz-los. Os dois primeiros so a alma do esquema de formulrios do Symfony, e ento vamos conhec-los um pouco mais.
10.3. Widgets
Na criao da classe BaseLivroForm vemos que ela uma classe extendida de BaseFormDoctrine - que por sua vez uma classe extendida de sfForm. A classe BaseFormDoctrine uma "verso para o ORM Doctrine" da classe padro de manipulao de formulrios do Symfony. A classe sfForm manipula todas as operaes de formulrio e seus campos, chamados Widgets. Cada Widgets uma extenso da classe base sfWidget, e possui um funcionalidade especfica. Quando vamos criar um formulrio Web existem vrias dificuldades, incluindo tamanho dos campos, o rtulo (label), o tipo de input (text, password, radio, checkbox, alm das opes de select e textarea), e muitas vezes ainda necessrio pegar informaes de listagem ou de outras tabelas para criar listagens.
Isto no Symfony fica muito simples: existem Widgets para cada situao corriqueira. Se olhamos o cdigo especfico de criao dos Widgets, temos: $this->setWidgets(array( 'isbn' => new sfWidgetFormInputHidden(), 'autor'=> new sfWidgetFormInput(), 'titulo' => new sfWidgetFormInput(), 'cat_id' => new sfWidgetFormDoctrineChoice( array('model' => 'Categoria', 'add_empty' => true)), 'preco'=> new sfWidgetFormInput(), 'sumario' => new sfWidgetFormInput(), )); vemos, por exemplo, que o campo isbn est como hidden, sendo exibido assim:
Captulo 10 Forms: criando formulrios - 78 <input type="hidden" name="livro[isbn]" id="livro_isbn" /> Os campos tipo input so gerados de forma simples: <input type="text" name="livro[autor]" id="livro_autor" /> <input type="text" name="livro[titulo]" id="livro_titulo" /> <input type="text" name="livro[preco]" id="livro_preco" /> <input type="text" name="livro[sumario]" id="livro_sumario" /> Mas o poder do Symfony visto no campo cat_id, que select montado na tabela categoria: <select name="livro[cat_id]" id="livro_cat_id"> <option value="" selected="selected"></option> <option value="1">Informtica</option> <option value="2">Auto Ajuda</option> <option value="4">Administrao</option> <option value="5">Fico</option> </select>
No captulo Criando uma aplicao rpida com o Symfony vimos que para esta funcionalidade ser efetiva preciso criar um mtodo __toString que retorna um dos campos da tabela. Isto feito no Model, pois ele que chamado neste momento para preencher o select. Existem diversos Widgets, e cada um possui seus atributos. No cabe estudar um a um, mas conforme for necessrio, se detalhando em cada um que se utilizar. Uma lista completa de referncia dos Widgets encontrada em: http://www.symfony-project.org/api/1_4/widget
10.4. Validators
Uma vez que temos os Widgets podemos anexar a eles Validators
Captulo 10 Forms: criando formulrios - 79 (validadores), que so regras para aceitar os valores enviados pelo formulrio. Os Validators, preciso deixar claro, sempre testam TODOS os campos; portanto, mesmo que no seja necessrio validar um campo, preciso definir uma validao "vazia", ou no obrigatria. Vejamos os ... gerados automaticamente pelo Doctrine: $this->setValidators(array( 'isbn' => new sfValidatorDoctrineChoice( array('model' => 'Livro', 'column' => 'isbn', 'required' => false)), 'autor'=> new sfValidatorString( array('max_length' => 80, 'required' => false)), 'titulo' => new sfValidatorString( array('max_length' => 100, 'required' => false)), 'cat_id' => new sfValidatorDoctrineChoice( array('model' => 'Categoria', 'column' => 'cat_id', 'required' => false)), 'preco'=> new sfValidatorNumber(), 'sumario' => new sfValidatorString( array('max_length' => 1000, 'required' => false)), )); Cada Validator j possui regras pr-definidas e aceita um ou dois arrays como parmetro: primeiro: opes segundo: mensagens
Se no h o segundo array, ento as mensagens sero padro. Mas veremos logo a seguir como personaliz-las.
Captulo 10 Forms: criando formulrios - 80 Novamente, h muitas opes, que variam conforme o Validator. Alguns so muito usados e comuns: max_length: tamanho mximo de caracteres min_length: tamanho mnimo de caracteres required: campo obrigatrio ou no default: valor padro para o campo label: rtulo para o campo
No exemplo acima, sfValidatorDoctrineChoice exige model e column, ou seja, vai checar se o valor enviado est dentro dos possveis desta tabela e campo (ou seja, checa a integridade referencial antes de salvar no banco, o que evita erros de SQL). As mensagens de erro so definidas no segundo array, e existem duas mensagens bsicas: required: quando o campo de preenchimento obrigatrio ('Required') invalid: quando a regra de validao no foi atendida ('Invalid')
Outros so comuns para max_lenght e min_lenght, que informam o tamanho mximo e mnimo necessrios. Para personalizar as mensagens, envia-se o segundo array como parmetro do Validator: // (...) 'email'=> new sfValidatorEmail( array('required' => true), array('required' => 'Email obrigatrio', 'invalid' => 'Email invlido') ), // (...) Opcionalmente possvel definir uma mensagem padro de required e invalid
Captulo 10 Forms: criando formulrios - 81 para os Validators informando: <?php class LivroForm extends BaseLivroForm { public function configure() { $this->setRequiredMessage('Campo obrigatrio'); $this->setInvalidMessage('Valor invlido - corrija'); } } ?> sem, entretanto, perder a funcionalidade de criar mensagens personalizadas para cada campo. H vrios Validators, e da mesma forma que os Widgets mais interessante estud-los quando necessitamos deles. Uma lista com os Validators disponveis encontrada em:
http://www.symfony-project.org/api/1_4/validator
10.5. Labels
O Symfony cria automaticamente rtulos (labels) para os campos baseado em seu nome. De forma simples, ele tenta manter o seguinte padro: data_nascimento => Data Nascimento codigo_area => Codigo Area
Apesar de ser interessante, este padro no muito til em portugus, pois temos acentuao e isto no gravado com o nome do campo (pelo menos no por administradores e projetistas de banco com o um mnimo de bom senso). Podemos personalizar os rtulos atravs do prprio Widget com a opo label
Captulo 10 Forms: criando formulrios - 82 como utilizando um mtodo especfico: <?php class LivroForm extends BaseLivroForm { public function configure() { $this->widgetSchema->setLabels(array( 'isbn' => 'ISBN', 'autor'=> 'Autor', 'titulo' => 'Ttulo', 'cat_id' => 'Categoria', 'preco'=> 'Preo', 'sumario' => 'Sumrio', )); } } ?>
Captulo 10 Forms: criando formulrios - 83 // (...) // Mtodo para criao de novo registro public function executeNew(sfWebRequest $request) { // Cria uma nova instncia de LivroForm // e o disponibiliza para a View. // // Como no est vinculado a um registro pr-existente, // quando for chamado $form->getObject()->isNew() // resultar "true", e ento as opes para novo registro // sero exibidas na View, como no caso de para qual ao // ser enviada o formulrio $this->form = new LivroForm(); } // Mtodo que processa a criao de um novo registro public function executeCreate(sfWebRequest $request) { // Se no foi recebido um POST, redireciona para // pgina no encontrada (erro 404) $this->forward404Unless($request->isMethod('post')); // Cria uma nova instncia de LivroForm $this->form = new LivroForm(); // Processa o formulrio atravs do mtodo // processForm desta classe (mais adiante) $this->processForm($request, $this->form); // Define o template como newSuccess.php // (o padro seria createSuccess.php)
Captulo 10 Forms: criando formulrios - 84 $this->setTemplate('new'); } // Mtodo para edio de registro public function executeEdit(sfWebRequest $request) { // Se no conseguir recuperar um parmetro "isbn" e com ele // recuperar um registro do banco de dados, retorna // pgina no encontrada (erro 404) com a mensagem: // Object livro does not exist $this->forward404Unless( $livro=Doctrine::getTable('Livro')->find(array($request>getParameter('isbn'))), sprintf('Object livro does not exist (%s).', $request->getParameter('isbn'))); // Cria uma nova instncia de LivroForm // mas agora com dados do livro recuperado do banco de dados $this->form = new LivroForm($livro); } // Mtodo que processa a atualizao do registro public function executeUpdate(sfWebRequest $request) { // Se no foi recebido um POST ou um PUT, redireciona para // pgina no encontrada (erro 404) // (ver informao sobre o PUT na seo sobre a apresentao // do formulrio mais adiante. $this->forward404Unless($request->isMethod('post') || $request->isMethod('put')); // Se no conseguir recuperar um parmetro "isbn" e com ele // recuperar um registro do banco de dados, retorna // pgina no encontrada (erro 404) com a mensagem:
Captulo 10 Forms: criando formulrios - 85 // Object livro does not exist $this->forward404Unless( $livro=Doctrine::getTable('Livro')->find(array($request>getParameter('isbn'))), sprintf('Object livro does not exist (%s).', $request->getParameter('isbn'))); // Cria uma nova instncia de LivroForm // mas agora com dados do livro recuperado do banco de dados $this->form = new LivroForm($livro); // Processa o formulrio atravs do mtodo // processForm desta classe (mais adiante) $this->processForm($request, $this->form); // Define o template como editSuccess.php // (o padro seria updateSuccess.php) $this->setTemplate('edit'); } // Mtodo que processa o envio do formulrio // em separado para evitar duplicidade de cdigo protected function processForm(sfWebRequest $request, sfForm $form) { // O mtodo bind do formulrio recupera os dados enviados // no $request para poder validar os dados $form->bind($request->getParameter( $form->getName()), $request->getFiles($form->getName())); // Realiza a validao do formulrio if ($form->isValid()) { // Se o formulrio foi validado, salva o registro
Captulo 10 Forms: criando formulrios - 86 $livro = $form->save(); // e ento redireciona para a tela edio, evitando // o problema de recarregar a pgina (F5) gerar um novo // envio do formulrio $this->redirect('livro/edit?isbn='.$livro->getIsbn()); } // Se o formulrio no foi validado, ento na exibio do // formulrio as mensagens de erro aparecero } } ?>
A gerao automtica que realizamos no captulo Criando uma aplicao rpida com o Symfony nos d uma idia simples de como criar a parte visual do formulrio. O arquivo um partial que pode ser utilizado em qualquer lugar da aplicao. O arquivo segue comentado para melhor compreenso. apps/admin/modules/livro/templates/_form.php
<!-Incluso de CSS e Javascript para o formulrio, se houver --> <?php include_stylesheets_for_form($form) ?> <?php include_javascripts_for_form($form) ?> <!-Tag "form" Algumas condies so includas para num nico arquivo trabalhar tanto edio quanto criao de registro. O objeto $form, criado pela ao, pode verificar se o objeto novo ou no (ou seja, ainda no foi salvo), e ento optar por montar o link com a ao create ou update. De mesmo modo, se no for novo, coloca a chave primria como parmetro (este um modo de fazer isto). --> <form action="<?php echo url_for('livro/'. ($form->getObject()->isNew() ? 'create' : 'update'). (!$form->getObject()->isNew() ? '? isbn='.$form->getObject()->getIsbn() : '')) ?>" method="post" <?php $form->isMultipart() and print 'enctype="multipart/form-data" ' ?>> <!-Novamente se for no for um objeto novo, o Symfony inclui um campo oculto para simular o mtodo PUT do HTTP (algo ainda pouco utilizado, e por isto simulado pelo Symfony para aumentar a segurana)
Captulo 10 Forms: criando formulrios - 88 --> <?php if (!$form->getObject()->isNew()): ?> <input type="hidden" name="sf_method" value="put" /> <?php endif; ?> <!-Montando a tabela base --> <table> <!-Utilizando a tag tfoot, ou rodap da tabela. Mesmo sendo informada aqui no incio, ser exibida ao final da tabela --> <tfoot> <td colspan="2"> <!-O boto de cancelar retorna para a listagem de registros --> <a href="<?php echo url_for('livro/index') ?>"> Cancel</a> <!-Se o registro no novo, ento exibe um boto para excluir. Como o uso do helper link_to montado o link, enviando a chave primria e ainda fazendo uso de um recurso de javascript para exibir uma janela de confirmao de excluso (Are you sure? Tem certeza?) --> <?php if (!$form->getObject()->isNew()): ?> <?php echo link_to('Delete', 'livro/delete?isbn='. $form->getObject()->getIsbn(), array('method' => 'delete',
Captulo 10 Forms: criando formulrios - 89 'confirm' => 'Are you sure?')) ?> <?php endif; ?> <!-Boto de envio --> <input type="submit" value="Save" /> </td> </tfoot> <tbody> <!-A renderizao do form propriamente dito --> <?php echo $form ?> </tbody> </table> </form>
<?php echo $form['email']->render() ?> // HTML <input type="text" name="pessoa[email]" id="pessoa_email" />
Mensagens
de
erro:
renderError()
(exibido
apenas
se
<?php echo $form['email']->renderError() ?> // HTML <ul class="error_list"> <li>Email invlido</li> </ul> possvel gerar tambm a linha de tabela inteira: // Gerando uma linha de tabela // No h diferena da linha gerada pelo // echo $form <?php echo $form['email']->renderRow() ?>
Captulo 11 AJAX - 92
Captulo 11 AJAX
Isto uma realidade muito em funo da quantidade de Javascript que necessrio escrever adicionalmente ao cdigo gerado no servidor. Entretando, com o Symfony, pouco se utiliza o Javascript - a no ser que se necessite de uma funcionalidade muitssimo especfica. Utilizando por padro o framework para AJAX Prototype possvel ter diversas funcionalidades com nenhuma ou pouca escrita de Javascript.
Captulo 11 AJAX - 93
No captulo Camada View: Apresentao conhecemos os Helpers. Existe um grupo de Helpers para Javascript. Seu uso bsico num layout ou template : <?php // Inclundo o Helper use_helper('Javascript') ; ?> <?php // Utilizando o Helper para criar uma funo echo javascript_tag(" function alterarNome() { ... } ") ?> <!-HTML Gerado: Para validar em XHTML gerado dentro da declarao CDATA --> <script type="text/javascript"> //<![CDATA[ function alterarNome() { ... } //]]> </script>
Captulo 11 AJAX - 94
Captulo 11 AJAX - 95
<?php class livroActions extends sfActions { // (...) // Mtodo para devolver um valor via AJAX public function executeAjax($request) { // Testando se uma requisio AJAX vlida if($this->getRequest()->isXmlHttpRequest()) { // Retornando um texto concatenado com o parmetro enviado return $this->renderText('Ok, recebi uma requisio: ' . $request->getParameter('valor')); } else { // Se a requisio no AJAX, ento envia uma mensage de erro return $this->renderText('Requisio mal formatada'); } } ?>
Captulo 11 AJAX - 96 Agora vamos adicionar um cdigo index do mdulo livro para aprendermos como fazer a requisio e recuperar o valor em um elemento do HTML: apps/admin/modules/livro/templates/indexSuccess.php
<?php // Inclundo o Helper use_helper('Javascript') ; // (...) ?> <!-- div que recebe o retorno da requisio AJAX --> <div id="retorno"></div> <?php /* A funo link_to_remote */ echo link_to_remote('Teste de Ajax', array( 'update' => 'retorno', 'url' => 'livro/ajax?valor=TESTANDO', )) ?> <?php /* A funo link_to_remote com confirmao */ echo link_to_remote('Teste de Ajax', array( 'update' => 'retorno',
Captulo 11 AJAX - 97 'url' => 'livro/ajax?valor=TESTANDO', 'confirm' => 'Tem certeza?', )) ?> <?php /* A funo link_to_remote com mtodo GET */ echo link_to_remote('Teste de Ajax', array( 'update' => 'retorno', 'url' => 'livro/ajax?valor=TESTANDO', 'method' => 'get', )) ?> Se a inteno que a funo seja executada imediatamente no carregamento da pgina, ento utilziada o helper remote_function: <?php // Inclundo o Helper use_helper('Javascript') ; // (...) ?> <!-- div que recebe o retorno da requisio AJAX --> <div id="retorno"></div> <?php /* A funo remote_function */
Captulo 11 AJAX - 98 echo remote_function('Teste de Ajax', array( 'update' => 'retorno', 'url' => 'livro/ajax?valor=TESTANDO', )) ?>
Este tipo de chamada AJAX realizada para atualizar constantemente uma pgina, como por exemplo para checar o recebimento de novos emails. <div id="retorno"></div> <?php // "frequency" o tempo em segundos // "with" permite passar como parmetro o valor de algum elemento // do HTML (utilizando a syntaxe do Prototype) echo periodically_call_remote(array( 'frequency' => 60, 'update' => 'retorno', 'url' => 'modulo/acao', 'with'=> "'param=' + \$F('mycontent')", )) ?>
Captulo 11 AJAX - 99
Captulo 11 AJAX - 100 } else { // Devolve uma mensagem via AJAX - erro return $this->renderText('Erro ao salvar registro'); } } else { // Se no uma requisio AJAX ou no um POST // devolve uma mensagem de erro return $this->renderText('Requisio mal formatada'); } } } ?>
11.5.3. Callbacks
Callbacks so aes que so executadas durante a requisio AJAX. O uso mais comum delas dar ao usurio uma noo de que o "servidor est trabalhando" enquanto ele aguarda uma requisio - os famosos "Carregando" ou imagem com animao. Os callbacks so os seguintes: before: Antes da requisio ser iniciada after: Imediatamente aps a requisio ser inicia e antes de carregar loading: Quando a resposta remota est sendo carregada pelo navegador loaded: Quando o navegador terminou de carregar a resposta remota interactive: quando o usurio pode interagir com a resposta remota, mesmo que ainda no tenha terminado
Captulo 11 AJAX - 101 success: Quando o XMLHttpRequest est completo, e o status HTTP est na faixa 2xx failure: Quando o XMLHttpRequest est completo, e o status HTTP no est na faixa 2xx 404: Quando a requisio retorna o status 404 complete: Quando XMLHttpRequest est completo (gerado logo aps success ou failure, se ocorrerem) O exemplo clssico: um "Carregando": <div id="retorno"></div> <div id="carregando">Carregando algo...</div> <?php echo link_to_remote('Vamos pegar algo', array( 'update'=> 'retorno', 'url'=> 'modulo/acao', 'loading' => "Element.show('carregando')", 'complete' => "Element.hide('carregando')", )) ?>
Apndices
USE `livraria444`;
SET FOREIGN_KEY_CHECKS=0;
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
SET
SET
Captulo 12 ApndiceBanco de dados "livraria" - 105 /*!40101 @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; SET
DROP TABLE IF EXISTS `categoria`; CREATE TABLE IF NOT EXISTS `categoria` ( `cat_id` int(10) unsigned NOT NULL auto_increment, `descricao` char(60) collate utf8_unicode_ci NOT NULL, PRIMARY KEY (`cat_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
DROP TABLE IF EXISTS `cliente`; CREATE TABLE IF NOT EXISTS `cliente` ( `cliente_id` int(10) unsigned NOT NULL auto_increment,
Captulo 12 ApndiceBanco de dados "livraria" - 106 `nome` char(60) collate utf8_unicode_ci NOT NULL, `endereco` char(80) collate utf8_unicode_ci NOT NULL, `cidade` char(30) collate utf8_unicode_ci NOT NULL, `uf` char(20) collate utf8_unicode_ci default NULL, `cep` char(9) collate utf8_unicode_ci default NULL, PRIMARY KEY (`cliente_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
DROP TABLE IF EXISTS `livro`; CREATE TABLE IF NOT EXISTS `livro` ( `isbn` char(13) collate utf8_unicode_ci NOT NULL, `autor` char(80) collate utf8_unicode_ci default NULL, `titulo` char(100) collate utf8_unicode_ci default NULL, `cat_id` int(10) unsigned default NULL, `preco` float(10,2) NOT NULL, `sumario` varchar(1000) collate utf8_unicode_ci default NULL, PRIMARY KEY (`isbn`), KEY `cat_id` (`cat_id`)
DROP TABLE IF EXISTS `pedido`; CREATE TABLE IF NOT EXISTS `pedido` ( `pedido_id` int(10) unsigned NOT NULL auto_increment, `cliente_id` int(10) unsigned NOT NULL, `total` float(6,2) default NULL, `data_pedido` date NOT NULL, `status` char(10) collate utf8_unicode_ci default NULL, `entrega_nome` char(60) collate utf8_unicode_ci NOT NULL, `entrega_endereco` char(80) collate utf8_unicode_ci NOT NULL, `entrega_cidade` char(30) collate utf8_unicode_ci NOT NULL, `entrega_uf` char(20) collate utf8_unicode_ci default NULL, `entrega_cep` char(9) collate utf8_unicode_ci default NULL, `forma_pagto` enum('BOLETO','DEPSITO','CARTO') collate utf8_unicode_ci NOT NULL, PRIMARY KEY (`pedido_id`), KEY `cliente_id` (`cliente_id`)
DROP TABLE IF EXISTS `pedidoitem`; CREATE TABLE IF NOT EXISTS `pedidoitem` ( `peditem_id` int(10) unsigned NOT NULL auto_increment, `pedido_id` int(10) unsigned NOT NULL, `isbn` char(13) collate utf8_unicode_ci NOT NULL, `preco` float(10,2) NOT NULL, `quantidade` tinyint(3) unsigned NOT NULL, PRIMARY KEY (`peditem_id`), KEY `pedido_id` (`pedido_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ;
Captulo 12 ApndiceBanco de dados "livraria" - 109 `login` char(16) collate utf8_unicode_ci NOT NULL, `nome` char(16) collate utf8_unicode_ci NOT NULL, `senha` char(40) collate utf8_unicode_ci NOT NULL, `perfil` enum('admin','gerente','despacho') collate utf8_unicode_ci NOT NULL, PRIMARY KEY (`login`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
--- Restries para a tabela `livro` -ALTER TABLE `livro` ADD CONSTRAINT `livro_ibfk_1` FOREIGN KEY (`cat_id`) REFERENCES `categoria` (`cat_id`);
Captulo 12 ApndiceBanco de dados "livraria" - 110 ADD CONSTRAINT `pedido_ibfk_1` FOREIGN KEY (`cliente_id`) REFERENCES `cliente` (`cliente_id`);
--- Restries para a tabela `pedidoitem` -ALTER TABLE `pedidoitem` ADD CONSTRAINT `pedidoitem_ibfk_1` FOREIGN KEY (`pedido_id`) REFERENCES `pedido` (`pedido_id`);
SET FOREIGN_KEY_CHECKS=1;
http://www.symfony-project.org/plugins/sfDoctrineGuardPlugin
sfDoctrineGuardPlugin um plugin do Symfony que fornece capacidade autenticao e autorizao sobre o padro de segurana do Symfony. Lhe d um Model (objetos usurio, grupo e permisso) e mdulos
(backend/retaguarda e frontend/frente) para implementar segurana em sua aplicao Symfony em um minuto num plugin configurvel Para instalar o plugin: symfony plugin:install sfDoctrineGuardPlugin Reconstrua seu Model: symfony doctrine:build-model symfony doctrine:build-sql symfony doctrine:build-forms symfony doctrine:build-filters Atualize as tabelas de seu banco de dados reiniciando-as (isto vai excluir todas as tabelas e recri-las symfony doctrine:insert-sql
Captulo 13 ApndicesfDoctrineGuard plugin - 112 Ative um ou mais mdulos no seu settings.yml (opcional) Para sua aplicao backend/retaguarda: sfGuardUser, sfGuardGroup,
sfGuardPermission Para sua aplicao frontend/frente: sfGuardAuth all: .settings: enabled_modules:[default, sfGuardGroup, sfGuardUser, sfGuardPermission] Limpe seu cache symfony cc Opcionalmente crie um usurio padro symfony guard:create-user fabien $secret Opcionalmente ative o filtro "Remember Me" em filters.yml security: class: sfGuardBasicSecurityFilter
Altere a classe pai em myUser.class.php class myUser extends sfGuardSecurityUser { } Adicionamente altere as regras de forward em routing.yml sf_guard_signin: url:/login param: { module: sfGuardAuth, action: signin } sf_guard_signout: url:/logout param: { module: sfGuardAuth, action: signout } sf_guard_password: url:/request_password param: { module: sfGuardAuth, action: password } Voc pode personalizar o parmetro url em cada rota. Voc deve ter uma regra de roteamento @homepage (utilizado quando o usurio faz logout). Estas rotas so automativamente registradas pelo plugin se o mdulo sfGuardAuth ativado, a no ser que voc defina sf_guard_plugin_routes_register para falso no arquivo de configurao app.yml all: sf_guard_plugin: routes_register: false Ative a segurana para alguns mdulos ou para a aplicao inteira em security.yml default:
Captulo 13 ApndicesfDoctrineGuard plugin - 114 is_secure: on Est feito. Agora, se voc tentar acessar uma pgina segura, ser
redirecionado para a pgina de login. Se voc carregou o arquivo padro de dados do plugin, tente logar com o usurio admin com a senha admin.
Se voc quer personalizar um destes templates: Crie o mdulo sfGuardAuth em sua aplicao (no utilize a tarefa initmodule, apenas crie o diretrio sfGuardAuth) Crie um template com o nome do template que voc quer personalizar no diretrio sfGuardAuth/templates O Symfony agora monta seu template ao invs do padro.
Captulo 13 ApndicesfDoctrineGuard plugin - 116 sfGuardSecurityUser adiciona alguns mtodos: signIn() and signOut() getGuardUser() que retorna o objeto sfGuardUser Um conjunto de mtodos "proxy" para acessar diretamente o objeto sfGuardUser Por exemplo, para recuperar o nome de usurio atual: $this->getUser()->getGuardUser()->getUsername() // ou via proxy method $this->getUser()->getUsername()