120
Advanced Web Developer PHP e MySQL www.4linux.com.br

Apostila Simfony

Embed Size (px)

DESCRIPTION

Apostila Simfony

Citation preview

Page 1: Apostila Simfony

Advanced Web DeveloperPHP e MySQL

www.4linux.com.br

Page 2: Apostila Simfony

- 2

SumárioCapítulo 1 Introdução......................................................................................................................................6

1.1. MVC: Model – View – Controller .......................................................................................71.2. Object Relational Map........................................................................................................91.3. AJAX: Asynchronous Javascript And XML.......................................................................101.4. Symfony: Framework de desenvolvimento em PHP.......................................................111.5. Eclipse: Integrated Development Environment..............................................................12

Capítulo 2 Instalando o ambiente de desenvolvimento...............................................................................13

2.1. Gerenciando pacotes com o apt-get................................................................................132.2. Instalando servidores e aplicativos básicos....................................................................142.3. Instalando a IDE Eclipse com o EasyEclipse..................................................................15

Capítulo 3 Instalando o Symfony..................................................................................................................16

3.1. Configurando um domínio virtual para a aplicação........................................................163.2. Porque é tudo tão complicado?.......................................................................................18

Capítulo 4 Criando uma aplicação rápida com o Symfony..........................................................................19

4.1. Preparando o banco de dados.........................................................................................204.2. Criando o projeto no Symfony.........................................................................................214.3. Criando uma aplicação....................................................................................................214.4. Lendo o banco de dados e criando classes de acesso....................................................224.5. Configurando o Doctrine para o scaffolding...................................................................234.6. Ajustando rótulo de chaves estrangeiras........................................................................254.7. Criando um menu para navegação..................................................................................274.8. Criando uma página inicial..............................................................................................30

Capítulo 5 Entendendo o Symfony................................................................................................................32

5.1. Introdução teórica............................................................................................................325.2. Estrutura de diretórios....................................................................................................325.3. O MVC do Symfony..........................................................................................................345.4. Camada Model..................................................................................................................355.5. Camada View....................................................................................................................35

Page 3: Apostila Simfony

- 3

5.6. Camada Controller...........................................................................................................365.7. Aplicações, Módulos e Ações...........................................................................................375.8. Ambientes e Handlers......................................................................................................385.9. Configurando Ambientes.................................................................................................395.10. A URL no Symfony.........................................................................................................42

Capítulo 6 Usando o EasyEclipse..................................................................................................................45

6.1. Introdução teórica............................................................................................................456.2. Iniciando um projeto........................................................................................................456.3. Criando um projeto..........................................................................................................466.4. Visão Geral da ferramenta...............................................................................................466.5. Configurações Úteis.........................................................................................................47

Capítulo 7 Camada Controller: controlando as requisições e respostas.....................................................48

7.1. Ações (Actions)................................................................................................................497.2. Término da ação...............................................................................................................527.3. Redirecionamento............................................................................................................537.4. ilizando sessões de usuário..............................................................................................577.5. Atributos Flash – variáveis de sessão descartáveis........................................................577.6. Repassando variáveis para a View..................................................................................58

Capítulo 8 Camada Model: acesso ao banco de dados................................................................................59

8.1. Introdução teórica............................................................................................................598.2. Classes de Tabelas...........................................................................................................628.3. Acessando dados através do Model.................................................................................628.4. Utilizando critérios no Doctrine......................................................................................628.5. Métodos personalizados...................................................................................................63

8.5.1. Método especial __toString.....................................................................................................638.6. Sobrescrita de métodos...................................................................................................64

Capítulo 9 Camada View: Apresentação.......................................................................................................66

9.1. Introdução teórica............................................................................................................669.2. A montagem da View.......................................................................................................669.3. Partials (Parciais).............................................................................................................699.4. Variáveis do Symfony.......................................................................................................709.5. Helpers.............................................................................................................................71

Page 4: Apostila Simfony

- 4

Capítulo 10 Forms: criando formulários.........................................................................................................73

10.1. Introdução teórica..........................................................................................................7410.2. Gerando formulários automaticamente........................................................................7410.3. Widgets...........................................................................................................................7710.4. Validators.......................................................................................................................7910.5. Labels.............................................................................................................................8210.6. Controlando o formulário...............................................................................................8310.7. Exibindo o formulário....................................................................................................87

10.7.1. Método automatizado...........................................................................................................8710.7.2. Método detalhado.................................................................................................................90

Capítulo 11 AJAX.............................................................................................................................................92

11.1. Introdução teórica..........................................................................................................9211.2. Incluindo Javascript.......................................................................................................9311.3. Criando um link para uma função.................................................................................9411.4. Alterado o conteúdo de um elemento HTML................................................................9411.5. Chamando uma função remota......................................................................................95

11.5.1. Atualizações Periódicas........................................................................................................9811.5.2. Formulários AJAX..................................................................................................................9911.5.3. Callbacks.............................................................................................................................101

Apêndices...................................................................................................................................103

Capítulo 12 ApêndiceBanco de dados "livraria"..........................................................................................................104

Capítulo 13 ApêndicesfDoctrineGuard plugin.............................................................................................................111

13.1.1. Implementando segurança em sua aplicação....................................................................11213.1.2. Administrando seus usuários, permissões e grupos..........................................................11413.1.3. Personalizando os templates do módulo sfGuardAuth......................................................11413.1.4. Personalizando os templates do módulo sfGuardAuth......................................................11513.1.5. Classe sfGuardSecurityUser...............................................................................................11513.1.6. Flag superadministrador....................................................................................................11613.1.7. Validators (Validadores).....................................................................................................11613.1.8. Personalizando o Model sfGuardUser................................................................................11713.1.9. Checar a senha do usuário com um método externo.........................................................118

Page 5: Apostila Simfony

- 5

13.1.10. Alterar o algoritmo utilizado para armazenar senhas.....................................................11913.1.11. Alterando o nome ou o período de expiração do cookie "Remember Me"......................11913.1.12. Personalizando a manipulação de redirecionamento de sfGuardAuth...........................12013.1.13. Configurando o formulário de login.................................................................................120

Page 6: Apostila Simfony

Capítulo 1 Introdução - 6

Capítulo 1

Introdução

Objetivo do Curso

Este curso de Advanced Web Developer PHP e MySQL - 444 - visa dar bases sólidas ao aluno para a construção de sistemas Web modernos, robustos, seguros e fundamentados em técnicas dedesenvolvimento atuais e produtivas.

Cabe lembrar que este nao é um curso de Webdesign não há preocupação com

a apresentação visual (layout) das páaginas criadas, e sim com sua funcionalidade. Não obstante, os arquivos são criados obedecendo os padrões da W3C (World Wide Web Consortium) em XHTML válido ou muito próximo disso, possibilitando uma ampla liberdade de criação de padrões 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

Page 7: Apostila Simfony

Capítulo 1 Introdução - 7

• AJAX - Asynchronous Javascript And XML

• Symfony - Framework de desenvolvimento em PHP

• Eclipse - Integrated Development Environment

1.1. MVC: Model – View – Controller

Model-View-Controller (MVC) é um padrão de arquitetura de software. Sua intenção é facilitar o desenvolvimento e manutenção de códigos em projetos de médio e grande porte, separando os dados(Model) e o layout, apresentação (View) da lógica de interação com o usuário final.

Deste modo facilita também o trabalho entre equipes mistas de DBA (administradores de Banco de Dados), programadores e webdesigners, no caso aplicações web.

• Model: Lógica de acesso a dados. Esta camada encapsula em classes toda lógica de acesso a dados. Normalmente a persistência de uma aplicação é feita num banco de dados, mas a camada Model não obrigatoriamente é específica para banco de dados, ela se ocupa de manter consistente a interação com uma base de persistência que normalmente é um banco de dados.

• View: Lógica de Apresentação. Representa a parte a apresentação visual das informações. E também onde o usuário interage com o sistema. Geralmente trata de apresentar os dados do Model.

• Controller: Lógica da aplicação. Recebe as ações do usuário, processa, valida dados e realiza operações no Model. No sentido contrário, devolve informações a serem visualizadas através da View.

Page 8: Apostila Simfony

Capítulo 1 Introdução - 8

Figura1.1 :Exemplo de Funcionamento do MVC

Page 9: Apostila Simfony

Capítulo 1 Introdução - 9

1.2. Object Relational Map

ORM é uma metodologia de acesso a banco de dados relacionais através de orientação a objeto. É feito um mapeamento entre as tabelas do banco de dados e classes que a acessam de forma transparente os dados destas tabelas.

Geralmente a utilização do ORM implica alguma forma de “varredura” no banco de dados para reconstruir todas as tabelas e suas relações em forma de classes. Uma vez realizada, a linguagem SQL é praticamente eliminada da programação, apesar de ainda ser possível na maioria dos casos. Desta forma a abstração de base de dados (um código, multiplos bancos de dados possíveis) chega a um nível bastante elevado.

O Symfony em sua versão 1.4 utiliza o Doctrine (http://www.doctrine-project.org) como ORM principal, que é um projeto baseado no Hibernate do Java, mas ainda dispõe a opção de utilizar o Propel como ORM (http://propel.phpdb.org).

Page 10: Apostila Simfony

Capítulo 1 Introdução - 10

1.3. AJAX: Asynchronous Javascript And XML

AJAX (Asynchronous Javascript And XML) é uma metodologia de uso de HTML ou XHTML, Cascading Style Sheets, Javascript, Document Object Model, XML, XSLT e o objeto XMLHttpRequest, providas por navegadores, para tornar páginas mais interativas com o usuário, utilizando-se de solicitações assíncronas de informações.

O AJAX não é um modelo, não é uma tecnologia, mas um conjunto de tecnologias que juntas criam para aplicativos web um novo padrão de usabilidade, muitas vezes semelhante a aplicativos desktop.

Curiosamente o AJAX nasceu de uma violação de padrões que a Microsoft costuma fazer em seus produtos. Em 1998 ela introduziu uma biblioteca que permitia fazer consultas usando o protocolo HTTP de maneira autônoma e assíncrona ( XMLHttpRequest). Inicialmente não houve utilidade para este recurso, que ficou um pouco esquecido.

Tempos depois é que se percebeu que em conjunto com outras tecnologias podia prover uma experiência mais rica ao usuário Web.

Inicialmente o AJAX era implementado “na mão grande”, com dificuldades para ser executado em vários navegadores. Atualmente existem vários frameworks que são utilizados em conjunto com linguagens de programação no lado do servidor, como jQuery, Prototype, Dojo, Mootools, ExtJs. O Symfony possui plugins para alguns deles.

Page 11: Apostila Simfony

Capítulo 1 Introdução - 11

1.4. Symfony: Framework de desenvolvimento em PHP

É um conjunto de classes que cooperam entre si, fornecendo soluções integradas para problemas comuns no desenvolvimento de software.

As linguagens de programação utilizadas simplesmente com seus recursos básicos não fornecem capacidade de solução imediata de diversos problemas corriqueiros de programação – aplicações multibanco, telas básicas de CRUD ( Create, Retrieve, Update, Delete), etc.

O uso de soluções avulsas rapidamente cria uma “colcha de retalhos”, e o framework se propõe a resolver isto.

Um framework necessita das seguintes características:

• Reutilização: possibilidade de reuso de componente.

• Extensibilidade: possibilidade de ampliar recursos.

• Segurança: confiabilidade de execução e implementação

• Completude: atender todas as necessidades dentro de um escopo de atuação.

Um framework não precisa reinventar a roda, ainda mais se tratando de software livre. É muito mais interessante atuar com uma “cola” que junta tecnologias já sedimentadas e as reune sob ma metodologia unificada de trabalho.

Symfony é um framework web escrito em PHP5 que segue o paradigma MVC. Tem como objetivo acelerar a criação e manutenção de aplicações web. Utiliza-se de várias tecnologias sedimentadas em sua base ( como os ORMs Doctrine e Propel, entre outras), extrai muitas de suas ideias do consagrado framework Ruby-On-Rails.

Além de ser um dos mais robustos, eficientes e documentados frameworks em PHP da atualidade, conta com um desenvolvimento e comunidade muito ativos. Poderia-se dizer que juntamente com o CakePHP e o ZendFramework são os três mais influentes frameworks em PHP no momento.

Page 12: Apostila Simfony

Capítulo 1 Introdução - 12

1.5. Eclipse: Integrated Development Environment

Eclipse é uma IDE de código aberto para o desenvolvimento de softwares.

O projeto Eclipse foi patrocinado pela IBM que desenvolveu a primeira versão do produto e doou-o como software livre para a comunidade. Hoje o Eclipse é a IDE Java mais utilizada no mundo.

Entretanto, o Eclipse é uma IDE altamente customizável e expansível. Assim não só aplicativos Java podem ser desenvolvidos utilizando o Eclipse, mas diversas outras linguagens. O PHP possui atualmente dois plugins livres para o Eclipse ( PHPEclipse e PDT), além da versão do consagrado Zend Studio( a Zend é a empresa que coordena o projeto PHP, fundada por dois de seus principais desenvolvedores).

Page 13: Apostila Simfony

Capítulo 2 Instalando o ambiente de desenvolvimento - 13

Capítulo 2

Instalando o ambiente de

desenvolvimento

2.1. Gerenciando pacotes com o apt-get

Nosso curso será realizado numa plataforma GNU/Linux utilizando a distribuição Debian 5 ( Lenny).O gerenciador de pacotes a ser utilizado é o apt-get. Para o utilizarmos, precisamos inicialmente configurar os repositórios no arquivo /etc/apt/sources.list. No nosso caso, para agilizar a instalação e evitar o tráfego intenso para o link externo, usaremos um repositório interno.

1. Configurando as fontes

1. Logamos como root

su root

2. Entramos no editor VIM

vim /etc/apt/sources.list

3. Adicionamos as seguintes linhas no arquivo

deb http://192.168.1.1/debian lenny main contrib non-freedeb http://packages.dotdeb.org lenny all

4. Agora atualizaremos a base de dados local

apt-get update

Page 14: Apostila Simfony

Capítulo 2 Instalando o ambiente de desenvolvimento - 14

2.2. Instalando servidores e aplicativos básicos

1. Instalando o servidor web Apache2

# apt-get install apache2

2. Instalando o PHP 5

# apt-get install php5 php5-cli

3. Instalando o SGDB MySQL

# apt-get install mysql-server

4. Instalando o suporte XSL no PHP 5

# apt-get install php5-xsl

5. Instalando um gerenciador Web para o MySQL

# apt-get install phpmyadmin

6. Reiniciando o servidor web

# /etc/init.d/apache2 restart

Page 15: Apostila Simfony

Capítulo 2 Instalando o ambiente de desenvolvimento - 15

2.3. Instalando a IDE Eclipse com o EasyEclipse

O Eclipse tem várias formas de instalação: download direto, instalação 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 versão do Java necessária e um conjunto de plugins afins de cada linguagem de programação. Ele não 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, versão Linux).

2.Instalando o EasyEclipse

O EasyEclipse é um pacote compactado pronto. Basta descompactar num diretório e rodar o executável. Para facilitar, vamos criar um atalho para seu acesso (chamado no Gnome de Lançador).

cd /optTar -xvzf /home/aluno/Downloads/easyeclipse-php-1.2.2.2.tar.gz

Para criar o atalho/lançador, clique com o botão direto na Área de Trabalho e selecione Criar Lançador.

Page 16: Apostila Simfony

Capítulo 3 Instalando o Symfony - 16

Capítulo 3

Instalando o Symfony

O método utilizado será a instalação via php-pear, que nos permite economizar espaço e facilita atualizações do Symfony além de backups das aplicações.

1. Atualizando canal do Symfony no PEAR

pear channel-discover pear.symfony-project.com

2. Instalando o Symfony através do PEAR

pear install symfony/symfony-1.4.4

3.1. Configurando um domínio virtual para a aplicação

Primeiro vamos criar um domínio virtal no Apache criando o arquivo:

/etc/apache2/sites-available/livraria444

Estre arquivo terá o seguinte conteúdo (o arquivo está comentado para melhor entendimento)

<VirtualHost *> # Nome do domínio virtual ServerName livraria.local # Diretório dos arquivos do domínio virtual DocumentRoot “/home/aluno/livraria444/web” # Padrão do índice de diretório (apenas o index.php)

Page 17: Apostila Simfony

Capítulo 3 Instalando o Symfony - 17

DirectoryIndex index.php # Permissões do diretório dos arquivos <Directory “/home/aluno/livraria444/web/”> AllowOverride All Allow from All </Directory></VirtualHost>

Agora ativamos o domínio virtual com o comando

a2ensite livraria444

O Symfony faz uso do módulo rewrite do Apache para criar URLs amigáveis (endereços sem .php, ponto de interrogação ou “E” Comercial).

Para ativá-lo, faz-se uso do comando:

a2enmod rewrite

Agora podemos recarregar o Apache para que estas alterações tenham efeito:

/etc/init.d/apache2 reload

Feito isso, vamos criar a estrutura de diretórios padrão do nosso aplicativo:

mkdir /home/aluno/livraria444mkdir /home/aluno/livraria444/web

Para que seja possível a navegação, precisamos ajustar nosso arquivo “hosts”:

echo “127.0.0.1 livraria.local”>>/etc/hosts

Para testar nosso novo “endereço” podemos acessar a URL:

http://livraria.local

Page 18: Apostila Simfony

Capítulo 3 Instalando o Symfony - 18

3.2. Porque é tudo tão complicado?

A instalação do Symfony é detalhada porque se destina a aplicações PROFISSIONAIS, que irão rodar em ambientes empresariais, websites de médio e grande porte.

Todos os passos garantem a segurança, portabilidade e facilidade na criação de aplicações.

Outras formas de instalação – inclusive pelo código fonte ou no Windows – podem ser encontradas no site do Symfony:

http://www.symfony-project.org

Page 19: Apostila Simfony

Capítulo 3 Instalando o Symfony - 19

Capítulo 4

Criando uma aplicação rápida com o

Symfony

Uma das capacidades de um framework é a possibilidade de criação de aplicações rapidamente, em especial com integração com o banco de dados.

Sistemas que interagem com banco de dados possuem uma característica interessante: a maioria das tabelas é acessada para quatro operações básicas:

• Criar um registro na tabela

• Recuperar um registro (ou vários) da tabela

• Atualizar um registro da tabela

• Excluir um registro da tabela

Estas operações são conhecidas pela sigla em inglês CRUD: Create, Retrieve, Update, Delete.

A grande maioria dos frameworks permite criar telas automaticamente para

Page 20: Apostila Simfony

Capítulo 4 Criando uma aplicação rápida com o Symfony - 20

utilização destas operações.

O Symfony não é diferente, e sem a necessidade de nenhuma linha de programação é possível criar um módulo para navegar em todas as tabelas de um banco de dados.

4.1. Preparando o banco de dados

No curso “PHP & MySQL Essentials (412)”, é utilizado o exemplo de uma livraria virtual. Neste curso usaremos o mesmo exemplo, mas de modo mais avançado.

Entretanto, haverá uma diferença: usaremos a integridade referencial (chaves estrangeiras) na modelagem do banco, pois o Symfony trata inteligentemente as relações entre as tabelas.

1. Criando o banco de dados

mysql -u root -p < livraria444.sql

2. Criando um usuário com permissões de acesso

grant select, insert, update, delete on livraria444.* to livraria444@localhost identified by 'senha444';

Page 21: Apostila Simfony

Capítulo 4 Criando uma aplicação rápida com o Symfony - 21

4.2. Criando o projeto no Symfony

Conforme o método utilizado na instalação (PEAR ou outros) a forma de criação de um projeto será levemente diferente.

Para criarmos o projeto, devemos digitar os comandos:

cd /home/aluno/livraria444symfony generate:project livraria444

Agora podemos começar a criar nossa aplicação, inicialmente do lado administrativo com CRUD para todas as tabelas.

• Todos os comandos serão executados no diretório do projero(/home/aluno/livraria444)

4.3. Criando uma aplicação

A aplicação criada receberá o nome de admin

symfony generate:app admin

• A tarefa generate:app cria uma aplicação dentro do projeto

• A opção –escaping-strategy=on proteje a aplicação contra ataques XSS( Cross-site scripting) e pode ser adicionada antes do nome da aplicação

Page 22: Apostila Simfony

Capítulo 4 Criando uma aplicação rápida com o Symfony - 22

• A opção –csrf-secret=SenhaQualquer proteje a aplicação contra ataques de CSRF (Cross-site request forgery) e pode ser adicionada antes do nome da aplicação

• admin é o nome da aplicação criada

Informações sobre estes tipos de ataques a sites web:

http://pt.wikipedia.org/wiki/Cross-site_scriptinghttp://en.wikipedia.org/wiki/CSRF

Já é possível acessar o projeto através do endereço:

http://livraria.local

O ambiente de desenvolvimento fica disponível em:

http://livraria.local/admin_dev.phpVeja a barra de debug que aparece no canto superior direito.

4.4. Lendo o banco de dados e criando classes de acesso

Em aplicativos MVC (Model-View-Controler: termo explicado detalhadamente mais adiante), existe um recurso chamado scaffolding, que consiste em ler o conteúdo de um banco de dados e criar classes de acesso a ele, e também criar um aplicativo de backend (retaguarda ou administrativo) contendo o acesso básico à tabela – o CRUD, já comentado.

O Symfony dispõe de recursos para realizar o scaffolding de modo muito mais simples, mas é preciso seguir os passos adequadamente. Quem realiza esse trabalho é o Doctrine, uma camada de ORM (Object-Relational Mapping: também explicado mais adiante) que é incorporada ao Symfony.

Page 23: Apostila Simfony

Capítulo 4 Criando uma aplicação rápida com o Symfony - 23

4.5. Configurando o Doctrine para o scaffolding

Vamos editar o arquivo databases.yml afim de configurar o acesso ao banco.

vim /var/www/livraria444/config/databases.yml

Em arquivos yml, a identação é feita através de espaço e não backspace

all: doctrine: class: sfDoctrineDatabase param:dsn: mysql:host=localhost;dbname=livraria444username: livraria444password: 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 são classes de acesso a dados. O Symfony cria as classes para todas as tabelas no banco de dados incluindo relacionamentos através do comando:

symfony doctrine:build-model

Os Models ficam disponíveis no diretório lib/model/doctrine

Page 24: Apostila Simfony

Capítulo 4 Criando uma aplicação rápida com o Symfony - 24

O Symfony também cria as classes de formulários para todas as tabelas do banco de dados. Isto facilita a criação de formulários com validação, mensagens de erro, etc.

Para criar os formulários com o Symfony, usamos o comando:

symfony doctrine:build-forms

Os formulários ficam disponíveis em lib/form/doctrine

Os módulos seriam equivalentes, a grosso modo, a arquivos .php que recebem parâmetros e realizações baseadas neles.

Os módulos são criados dentro de uma aplicação, e são diretórios dentro do diretório da aplicação.

Como o Symfony trabalha com MVC, e o Model já foi criado, no módulo ficam o Controller (action) e a View (templates).

Para gerar um módulo, fazemos uso do código abaixo:

symfony doctrine:generate-module admin categoria Categoria

Onde:

• admin: é a aplicação, residente em apps/admin

• categoria: é o nome do módulo a ser criado, em apps/admin/modules/categoria

• Categoria: é o nome do Model, em lib/model/doctrine

É importante perceber que o nome do Model tem a inicial maiúscula, como foi gerado pelo Symfony.

Uma vez que o comando termine, já é possível navegar na tabela categoria dentro do Symfony através da url:

http://livraria.local/categoria

Page 25: Apostila Simfony

Capítulo 4 Criando uma aplicação rápida com o Symfony - 25

Também é possível navegar em modo de desenvolvimento (debug):

http://livraria.local/admin_dev.php/categoria

Pode-se criar os módulos para cada tabela do banco de dados que seja necessária

symfony doctrine:generate-module admin cliente Clientesymfony doctrine:generate-module admin livro Livrosymfony doctrine:generate-module admin pedido Pedidosymfony doctrine:generate-module admin pedidoitem Pedidoitemsymfony doctrine:generate-module admin usuario Usuario

E também podemos navegar nestas tabelas pelos respectivos links:

http://livraria.local/admin_dev.php/clientehttp://livraria.local/admin_dev.php/livrohttp://livraria.local/admin_dev.php/pedidohttp://livraria.local/admin_dev.php/pedidoitemhttp://livraria.local/admin_dev.php/usuario

4.6. Ajustando rótulo de chaves estrangeiras

Até agora não alteramos um único arquivo em PHP. Mas, para que os formulários que representam tabelas que possuem chaves estrangeiras (por exemplo, pedido que tem vínculo com a tabela cliente) é preciso especificar que campo da tabela estrangeira que será rótulo nos comboboxes.

Nas novas versões do Symfony, fazendo uso do Doctrine, o Symfony nos cria os formulários com os combox de chave estrangeira automaticamente, porém podemos nos defrontar com outras versões que não nos oferecem isso, por isso vamos ver como setar manualmente afim de ter conhecimentos em versões que não nos oferecem isso.

Page 26: Apostila Simfony

Capítulo 4 Criando uma aplicação rápida com o Symfony - 26

Por exemplo, para a tabela cliente temos:

lib/model/doctrine/base/BaseCliente.class.phplib/model/doctrine/Cliente.class.php

As tabelas que possuem este tipo de relacionamento são:

O primeiro arquivo não deve ser alterado, pois numa atualização do Model será sobrescrito. Toda a nossa personalização será realizada no segundo, que é uma classe extendida da primeira.

Para preencher os rótulos dos comboboxes criamos um método __toString que retorna um dos campos da tabela. Neste momento apenas criaremos mecanicamente; mas adiante entenderemos como são feitas as chamadas aos campos.

• categoria (estrangeira para livro)

• cliente (estrangeira para pedido)

• pedido (estrangeira para pedidoitem)

Então vamos alterar estes arquivos como segue:

<?php// lib/model/doctrine/Categoria.class.phpclass Categoria extends BaseCategoria{

public function __toString(){

return $this->getNome();}

}

<?php

Page 27: Apostila Simfony

Capítulo 4 Criando uma aplicação rápida com o Symfony - 27

// lib/model/doctrine/Cliente.class.phpclass Cliente extends BaseCliente{

public function __toString(){

return $this->getNome();}

}

<?php// lib/model/doctrine/Pedido.class.phpclass Pedido extends BasePedido{

public function __toString(){

return $this->getStatus();}

}

Apesar de não ser perfeito ainda ( o formulário para tabela livro não exibe o ISBN, mas corrigiremos isso mais adiante), nos falta apenas um menu para navegar nestas tabelas.

4.7. Criando um menu para navegação

Vamos alterar o template padrão do módulo para incluir um menu para todas as páginas do projeto.

O arquivo que possui o layout básico que é utilizado por todos os arquivos do módulo está em:

apps/admin/templates/layout.php

Page 28: Apostila Simfony

Capítulo 4 Criando uma aplicação rápida com o Symfony - 28

O arquivo possui o cabeçalho e rodapé da página, e inclui o conteúdo gerado pelos templates de cada módulo da aplicação. Ele é criado em HTML com os trechos em PHP incluídos, 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>

Page 29: Apostila Simfony

Capítulo 4 Criando uma aplicação rápida com o Symfony - 29

Para criarmos um menu modificamos seu código 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&aacute;rio</a> </div> <?php echo $sf_content ?> </body></html>

A função url_for cria os links no formato do Symfony para o par módulo/ação. Mais tarde, compreendendo melhor as ações, ficará mais clara sua utilização. No momento, sabemos que ela criar de forma organizada, respeitando inclusive o ambiente (de produção ou de desenvolvimento).

Page 30: Apostila Simfony

Capítulo 4 Criando uma aplicação rápida com o Symfony - 30

4.8. Criando uma página inicial

Nos falta uma “index” para carregarmos automaticamente. Para não misturarmos com os módulos criados para cada tabela, criaremos um módulo sem vínculo com tabela nenhuma, chamado index.

symfony generate:module admin index

Se navegamos agora para:

Http://livraria.local/index

Veremos a página padrão do Symfony para novos módulos criados. Isto é facilmente alterado, como esta própria página explica, retirando o forward (redirecionamento) que é feito na ação padrão deste novo módulo, no arquivo:

<?php// apps/modules/index/actions/action.class.phpclass indexActions extends sfActions{

public function executeIndex(sfWeRequest $request){}

}

Qualquer conteúdo que queiramos colocar nele, além do menu que já estará como padrão da aplicação, é 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>

Page 31: Apostila Simfony

Capítulo 4 Criando uma aplicação rápida com o Symfony - 31

Mas para ele tornar-se padrão é preciso alterar o arquivo de configuração do módulo e direcionar para o par (modulo/ação) desde módulo criado.

apps/admin/config/routing.yml

#default ruleshomepage:

url: /param: { module: index, action: index }

default_index:url: /:moduleparam: { action: index }

default:url: /:module/:action/*

Foi alterado em homepage, param, module de default (módulo padrão do Symfony) para index (módulo recém-criado).

Neste momento descobrimos uma funcionalidade do Symfony que nos “atrapalha” neste momento: o Cache. Todos os arquivos de configuração, para maior velocidade, são verificados em sua primeira utilização e então o Symfony cria arquivos otimizados em Cache.

Isto é excelente, mas quando alteramos um arquivo de configuração ou mudamos a localização de algum arquivo de classe ele não é encontrado enquanto não zeramos o cache. Isto é feito com o comando:

symfony cc

Agora podemos acessar a página index diretamente:

http://livraria.local

Podemos também acessar o modo de desenvolvimento e debug:

http://livraria.local/admin_dev.php

Page 32: Apostila Simfony

Capítulo 5 Entendendo o Symfony - 32

Capítulo 5

Entendendo o Symfony

5.1. Introdução teórica

Para melhor entendimento de como o framework funciona, precisamos conhecer a fundo as “entranhas” do mesmo. Neste capítulo, iremos ver desde a organizção dos arquivos até conceitos de MVC.

5.2. Estrutura de diretórios

Ao criar um projeto, o Symfony cria a seguinte estrutura de arquivos:

livraria444->apps->cache->config->data->doc->lib->log->plugins->test->web->

Nos diretórios que vimos, podemos encontrar:

Page 33: Apostila Simfony

Capítulo 5 Entendendo o Symfony - 33

• apps: Cada aplicação corresponde a um diretório dentro de apps;

• cache: Cache criado pelo Symfony, para otimização de desempenho;

• config: Arquivos de configuração global do projeto;

• data: Diretório com dados que podem ser importados no banco de dados, ou outras formas de dados variáveis que serão gravados (por exemplo, um banco de dados SQLite);

• doc: Reservado para documentação do projeto;

• lib: Localização 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: Diretório de testes personalizados;

• web: Pasta pública que contém arquivos acessados via navegador. Especialmente aqui estão imagens, css, javascript além dos arquivos públicos do próprio Symfony;

Page 34: Apostila Simfony

Capítulo 5 Entendendo o Symfony - 34

5.3. O MVC do Symfony

A implementação do MVC do Symfony utiliza-se de vários arquivos, o que inicialmente pode parecer confuso:

• Camada Model:

◦ Abstração de Banco de Dados (Database abstraction)

◦ Acesso a Dados (Data access)

• Camada View:

◦ Layout

◦ Lógica de Apresentação

◦ Template

• Camada Controller:

◦ Controle Frontal (Front controller)

◦ Ação (Action)

Entretanto, na prática, com o uso dos geradores de código (em especial as opções dos comandos symfony doctrine:? ) a maioria desses arquivos já fica à disposição do desenvolvedor, seja de forma permanente, seja como base para personalizações.

Page 35: Apostila Simfony

Capítulo 5 Entendendo o Symfony - 35

5.4. Camada Model

Fica localizada no diretório lib/model. A abstração de Banco de Dados é realizada de forma transparente, mediante unicamente a configuração de acesso ( como visto no capítulo Criando uma aplicação rápida com o Symfony). São criados basicamente três tipos de arquivos:

• mapeamento: Utilizada internamente pelo ORM. Não é acessada diretamente pelo desenvolvedor.

• Classes das tabelas: Para instância de objetos representando registros da tabela e seus relacionamentos.

Os arquivos criados pelo Symfony através dos comandos symfony doctrine:?Serão guardados dentro de lib/model/map e lib/model/om. São classes abstratas (no caso de classes de tabelas) que servem de base para as classes extendidas que se encontram em lib/model.

Estas sim são classes disponíveis ao desenvolvedor, e onde pode-se incluir novos métodos conforme sua necessidade. Esta estrutura permite que o Symfony recrie os arquivos base sem afetar as personalizações do desenvolvedor.

5.5. Camada View

Primeiro, é preciso compreender o termo template: é um modelo de código para apresentação. No caso do Symfony, geralmente é criado em XHTML, com trechos de PHP para inclusão de informações dinâmicas.

Layouts são templates globais para cada aplicação, representando a apresentação final das páginas. Ficam armazenados no diretório apps/aplicação/templates, sendo que o padrão é a utilização do arquivo apps/aplicação/templates/layout.php

É comum (e necessário) que o layout padrão inclua o código dos templates gerados em cada ação de um módulo. Entretanto, para organização ou retulização, podem ser criados layouts parciais (partials) a serem incluídos em determinados

Page 36: Apostila Simfony

Capítulo 5 Entendendo o Symfony - 36

locais de layouts e templates.

No Symfony, o termo templates é referência a arquivos chamados por ações do módulo para compor o corpo da página. O layout geralmente os inclui em seu corpo. Localizam-se nos diretórios dos módulos, no formato apps/aplicação/modules/modulo/templates. Também pe possível templates parciais (partials).

A Lógica de Apresentação consiste na montagem desde “quebra cabeças” que resulta na página final exibida para o usuário. Isto envolve processos automatizados do Symfony mas também personalizações que o desenvolvedor queira fazer diretamente no código dos templates e layouts.

Os arquivos de templates e layouts são arquivos em XHTML (por padrão, mas fica a cargo da necessidade do desenvolvedor) e PHP comuns, com acesso a variáveis especiais do Symfony para geração de conteúdo de forma dinâmica.

5.6. Camada Controller

O Controle Frontal (Front controller) é quem gerencia as requisições realizadas pelo usuário final.

Encontra-se na raiz do diretório web. Podem existir vários Controles Frontais, conforme as aplicações e ambientes configurados. Veremos isto na próxima seção.

Ações (Actions) são arquivos actions.class.php residentes em cada módulo. São chamados pelo Controlador Frontal e não acessados diretamente, por isto não precisam estar disponíveis dentro do diretório web. Em Ações acontece a maior parte do desenvolvimento no Symfony.

Page 37: Apostila Simfony

Capítulo 5 Entendendo o Symfony - 37

5.7. Aplicações, Módulos e Ações

No exemplo do capítulo Criando uma aplicação rápida com o Symfony foi aprendido como criar aplicações e módulos no Symfony.

Agora aprofundaremos um pouco para compreender a estrutura destes elementos no Symfony.

Ao abrirmos o Diretório ADMIN, nos encontramos com a seguinte estrutura de diretórios.

• Config: Arquivos de configuração da aplicação, em formato YAML (um simplificador do formato XML);

• i18n: Arquivos de tradução para aplicativos multilínguas;

• lib: Classes exclusivas do aplicativo;

• modules: Módulos da aplicação;

• template: Layouts da aplicação (templates disponíveis para todos os módulos);

• actions: Controllers do módulo. Normalmente só é necessário um arquivo, action.class.php;

• templates: Diretório de templates do módulo;

Uma aplicação pode conter vários módulos, vinculados ou não a um Model.

Page 38: Apostila Simfony

Capítulo 5 Entendendo o Symfony - 38

5.8. Ambientes e Handlers

Existem dois problemas corriqueiros em aplicações web:

• Um projeto, múltiplos clientes: Num sistema web é bastante comum a necessidade de um portal administrativo ou restrito (backend) e um portal público ou para o usuário final (frontend);

• Ambiente de desenvolvimento: Para desenvolver a aplicação é importante ter acesso a ferramentas de debuf, verificar variáveis em tempo de execução, consultas realizadas no banco de dados, requisições, etc; também é comum existir um banco de dados em teste e um banco de dados em produção;

No Primeiro caso são praticamente dois sistemas diferentes (ou mais...) acessando o mesmo banco de dados com regras de requisição e resposta diferentes, apresentação diferente, mas com as mesmas regras de negócio de acesso ao banco.

No segundo caso os desenvolvedores possuem um trabalho muito grande de ligar e desligar debugs, ter cópia de ambientes diferentes, com acesso a banco de dados diferentes, manter sincronizados estes dois ambientes, ou então, mesmo que somente em sua máquina de desenvolvimento, há muita mão-de-obra para testar a visão do usuário final.

O Symfony, para facilitar a vida do desenvolvedor, permite a criação de vários ambientes dentro de um projeto, e para isto, utiliza os handlers. Handlers são arquivos em PHP que fazem o primeiro trabalho da Camada Controller, que é definir qual aplicação, módulo e ação serão executados.

Page 39: Apostila Simfony

Capítulo 5 Entendendo o Symfony - 39

5.9. Configurando Ambientes

O Symfony, para não dificultar as configurações utilizando o XML, ou retroagir utilizando o ultrapassado formato INI, ou ainda inventar um novo formato, optou por utilizar uma linguagem que é um “XML Simplificado”, chamado de YAML (YAML Ain't Markup Language – http://www.yaml.org/).

O YAML é muito simples de se escrever. Tem poucas regras, das quais resume-se abaixo as mais importantes:

• A hierarquia é mantida pela identação;

• A identação é com dois ESPAÇOS;

• Não se utliza TABULAÇÃO como identação;

• Cada chave é seguida de dois pontos;

• O valor depois dos dois pontos é atribuído à chave;

• É preciso um espaço entre os dois pontos e o valor;

• Texto com espaço é definido entre aspas SIMPLES;

• O que ficar após um “#” é um comentário na linha;

Para configurar ambientes no Symfony, utilizamos inicialmente o arquivo:

config/databases.yml

all: doctrine: class: sfDoctrineDatabase param: dsn: mysql:host=localhost;dbname=livraria444username: livraria444password: senha444

Page 40: Apostila Simfony

Capítulo 5 Entendendo o Symfony - 40

Então temos os ambientes dev, test, além do prod, que é padrão e está omitido por não possuir personalizações na configuração inicial. Além deles temos o all que determina valores padrão para todos os ambientes (que podem ser sobrescritos individualmente).

• prod: Ambiente de produção, com cache ativado e com apenas alertas de erros(sem debug);

• dev: Ambiente de desenvolvimento, com cache desativado, erros em nível máximo(com debug);

• test: Ambiente especial semelhante ao de produção, mas que só executado em linha de comando para rodar testes automatizados;

• ??: É possível configurar outros ambientes personalizados.

É Muito comum o ambiente de desenvolvimento utilizar outro banco de dados; ou então, um ambiente intermediário, com uma cópia do banco de produção criado para testes, mas com debug.

Quando uma nova aplicação é criada, por padrão são criados dois handlers:

• web/minhaaplicacao.php: corresponde ao ambiente de produção;

• web/minhaaplicacao_dev.php; corresponde ao ambiente de desenvolvimento;

Se a aplicação é a primeira a ser criada, seu ambiente de produção terá como handler web/index.php, e torna-se o aplicativo padrão do projeto.

Uma ferramenta importante do Symfony é a barra de Debug, uma barra flutuante que aparece em todas as páginas, fornecendo informações valiosas sobre varáveis e consultas a banco de dados.

Page 41: Apostila Simfony

Capítulo 5 Entendendo o Symfony - 41

Essa barra de debug é ativada dentro do handler:

<?phpif(!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 atenção especial é dada aos parâmetros do método estático:

ProjectConfiguration::getApplicationConfiguration('admin', 'dev', true);

Ele recebe três parâmetros:

• aplicação: no exemplo 'admin';

• ambiente: no exemplo 'dev'. Podendo ainda ser 'prod' (oque é o caso do ambiente de produção) ou outro ambiente que tennha sido configurado no arquivo config/databases.yml

• webdebug: no exemplo true, ou seja, ativo(no ambiente de produção, false);

Page 42: Apostila Simfony

Capítulo 5 Entendendo o Symfony - 42

5.10. A URL no Symfony

Na URL de uma aplicação Symfony, até os três primeiros parâmetros são determinadas a aplicação, o módulo e a ação a serem executadas.

1. Situação 1 – Homepage

http://livraria.local

Se não há parâmetros após o domínio, então subentende-se que a aplicação e o ambiente são os definidos no arquivo:

web/index.php

(…)// APLICAÇÃO = admin, AMBIENTE = prod, DEBUG = false$configuration = ProjectConfiguration::getApplicationConfiguration ('admin', 'prod', 'false');(…)

Já o módulo e a ação são os definidos no arquivo:

apps/minhaaplicacao/config/routing.yml

dentro da opção homepage, param

(…)homepage: url: / param: {module: default, action: index}(…)

Page 43: Apostila Simfony

Capítulo 5 Entendendo o Symfony - 43

2. Situação 2 – Um handler diferentes

http://livraria.local/admin_dev.php

Se o primeiro parâmetro é um handler, então é executado este handler, que estará no diretório web, que define a aplicação. Já o módulo e a ação seguem a mesma situação

acima, sendo definidos no arquivo:

apps/minhaaplicacao/config/routing.yml

3. Situação 3 – módulo

http://livraria.local/categoriahttp://livraria.local/admin_dev.php/categoria

Se o primeiro parâmetro não é um handler, ou então é um handler seguido de uma barra mais uma palavra, então esta última informação é um módulo (no exemplo acima, categoria).

A ação é definida no arquivo:

apps/minhaaplicacao/config/routing.yml

dentro da opção default_index, param (valor padrão é index).

(…)default_index: url: /:module param: {action: index}(…)

4. Situação 4 – módulo/ação

http://livraria.local/categoria/newhttp://livraria.local/admin_dev.php/categoria/new

Page 44: Apostila Simfony

Capítulo 5 Entendendo o Symfony - 44

Se o primeiro parâmetro não é um handler, ou então é um handler seguido de uma barra mais uma palavra e de outra barra e palavra, então esta última informação é uma ação (no exemplo acima, new) e a penúltima é um módulo (no exemplo acima, categoria).

5. Situação 5 – módulo/ação/variavel/valor

http://livraria.local/categoria/edit/cat_id/1http://livraria.local/admin_dev.php/categoria/edit/cat_id/1

Se já estão identificados aplicação, módulo e ação, então o que segue são sempre pares de variável/valor, que serão enviados via GET.

No exemplo acima, a ação edit do módulo categoria receberá a variável cat_id com o valor 1.

Seria o equivalente a:

http://livraria.local/categoria/edit?cat_id=1http://livraria.local/admin_dev.php/categoria/edit?cat_id=1

no PHP natural, o que equivaleria no script de destino a variável:

$_GET['cat_id'] = 1

apesar de que utiliza-se um método próprio no Symfony para recuperar esta variável, como será visto mais adiante.

Se houverem mais pares de variável/valor, seguirão as mesmas regras:

http://livraria.local/categoria/edit/cat_id/1/descricao/Romancehttp://livraria.local/admin_dev.phpcategoria/edit/cat_id/1/descricao/Romance

equivale às variáveis no destino:

$_GET['cat_id'] = 1$_GET['descricao'] = 'Romance'

Page 45: Apostila Simfony

Capítulo 6 Usando o EasyEclipse - 45

Capítulo 6

Usando o EasyEclipse

6.1. Introdução teórica

O EasyEclipse (http://eclipse.org) já foi instalado com o plugin PHPEclipse. Vamos aprender a utilizá-lo para gerenciar um projeto em PHP e compreender algumas de suas facilidades.

6.2. Iniciando um projeto

Apesar do EasyEclipse ter sido instalado e possuir uma opção de menu para iniciá-lo, temos um problema: o usuário da máquina não possui acesso para salvar o diretório /var/www/livraria444, pois foi criado pelo usuário root.

Portanto, para facilitar a utilização no desenvolvimento, é prático executar o EasyEclipse como superusuário. No Gnome é possível fazer iso pressionando ALT+F2 e digitando:

gksu /opt/easyeclipse-php-1.2.2.2/eclipse

Em seguida é solicitada a senha do superusuário, e então o EasyEclipse solicita que se defina a área de trabalho (workspace) padrão, que é um diretório dentro do diretório do usuárop onde, por padrão o EasyEclipse sugerirá que residam os projetos criados(mas não é obrigatório).

Page 46: Apostila Simfony

Capítulo 6 Usando o EasyEclipse - 46

6.3. Criando um projeto

Acione o menu File / New / Project / PHP / PHP Project.

Opcionalmente pode-se criar um novo projeto na área do Navegador, clicando com o botão direito do mouse e selecionando File / New / Project / PHP / PHP Project.

É solicitado em seguida o caminho um nome e um caminho até o projeto. Este pode ser vazio(novo), ou um já existente. Neste último caso, o EasyEclipse varre o diretório e “importa” todos os arquivos para o projeto.

Importante: o EasyEclipse mantém controle sobre as alterações dos arquivos – nãoé simplesmente uma navegação de um diretório. Se algum arquivo for criado no diretório por fora do EasyEclipse, ele não vai “enxergar”. Do mesmo modo, se algum arquivo for alterado por fora do EasyEclipse, ele vai acusar esta “inconsistências”;

No caso do Symfony, isto é bastante comum de acontecer com o uso das ferramentas de linha de comando que refazem os Models, por exemplo. Nestas situações, basta solicitar ao EasyEclipse que releia o diretório do projeto: clica-se com o botão direito em cima do nome do projeto e então em “Refresh” (Atualizar).

6.4. Visão Geral da ferramenta

O EasyEclippse tem como base o PHPEclipse, que é um plugin para desenvolvimento em PHP.

Ele, além do realce de sintaxe, trás outras facilidades como o auto-completar os comandos, sugestão de métodos de classes (muitíssimo útil no Symfony, que é 100% orientado a objeto), e incorpora recursos globais do Eclipse como navegação de classes, erros e tarefas(TODO).

Para usuários Windows é possível integrar com o XAMPP(ambiente de desenvolvimento apache/MySQL/PHP para Windows) através do menu PHP/Apache.

Como projetos em PHP envolvem invariavelmente em algum momento manipulação de arquivos XHTML/HTML, JavaScript, CSS e SQL, outros plugins incorporados abrem estes arquivos e apresentam facilidades para estas linguagens.

Page 47: Apostila Simfony

Capítulo 6 Usando o EasyEclipse - 47

De moro geral, alguns atalhos de teclado são úteis em todos os editores:

• CTRL+espaço: sugere complementação de comandos ou parâmetros;

• TAB: identa o código – válido para várias linhas selecionadas;

• SHIFT+TAB: “des”identa o código – válido para várias linhas selecionadas;

• CTRL+PGUP, CTRL+PGDN: navega pelas abas do editor(arquivos abertos);

A lista completa de atalhos de teclado está disponível 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 navegação dentro de um arquivo – por exemplo, numa classe são listados os métodos; num arquivo CSS, cada uma das entradas, etc.

6.5. Configurações Úteis

Um padrão importante nos projetos atuais é a quantidade de caracteres que são utilizados para identação. De modo geral o caracter TAB não é ,aos utilizado (para evitar diferentes interpretações por editores ou visualizadores), sendo utilizado o espaço (o padrão mais comum são 2 espaços). Entretanto, para facilitar, é possível automaticamente converter o pressionamento do TAB por espaços ( ou o contrário com o SHIFT+TAB).

Page 48: Apostila Simfony

Capítulo 7 Camada Controller: controlando as requisições e respostas - 48

Capítulo 7

Camada Controller: controlando as

requisições e respostas

Pelo padrão MVC o Controller é oque faz a interconexão entre a lógica de negócio (Model) e a apresentação (View).

Basicamente o Symfony separa o Controller nos seguintes componentes:

• Front Controller (Controle frontal): ponto de entrada único da aplicação; carrega a configuração e determinação de qual ação será executada;

• Actions(Ações): lógica da aplicação, verifica a integridade da requisição e prepara os dados necessários para a camada de apresentação;

• Objetos Request, Response, Session: dão acesso aos parâmetros requisitados, cabeçalhos de resposta e aos dados persistentes.

Page 49: Apostila Simfony

Capítulo 7 Camada Controller: controlando as requisições e respostas - 49

7.1. Ações (Actions)

O Front Controller determina qual o módulo e ação correspondente será executado através da leitura da URL – como já foi explicado anteriormente. Para que seja controlada a alçao correspondente, ela deve existir dentro da classe.

class pessoaActions extends sfActions{ public function executeIndex(sfWebRequest $request) { $this->pessoas = Doctrine::getTable('Pessoa') ->createQuery('a') ->execute(); }

public function executeNew(sfWebRequest $request) { $this->form = new PessoaForm(); }

public function executeCreate(sfWebRequest $request) { $this->forward404Unless($request->isMethod(sfRequest::POST));

$this->form = new PessoaForm();

$this->processForm($request, $this->form);

$this->setTemplate('new'); }

public function executeEdit(sfWebRequest $request) { $this->forward404Unless($pessoa = Doctrine::getTable('Pessoa')->find(array($request->getParameter('id'))), sprintf('Object pessoa does not

Page 50: Apostila Simfony

Capítulo 7 Camada Controller: controlando as requisições e respostas - 50

exist (%s).', $request->getParameter('id'))); $this->form = new PessoaForm($pessoa); }

public function executeUpdate(sfWebRequest $request) { $this->forward404Unless($request->isMethod(sfRequest::POST) || $request->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())

Page 51: Apostila Simfony

Capítulo 7 Camada Controller: controlando as requisições e respostas - 51

{ $pessoa = $form->save();

$this->redirect('pessoa/edit?id='.$pessoa->getId()); } }}

As ações devem manter o seguinte padrão de nomenclatura para o método:

• Iniciar com a palavra execute toda em minúscula;

• Continuar com o nome da ação, com a primeira letra em maiúscula;

Métodos que não seguem este padrão não são ações, não podem ser acessadas pelo Front Controller, apesar de ser possível seu uso internamente pela classe, conforme a necessidade.

Page 52: Apostila Simfony

Capítulo 7 Camada Controller: controlando as requisições e respostas - 52

7.2. Término da ação

As ações ao seu término, por padrão, chamam um template de mesmo nome e sufixo Success.

Portanto, a ação executeIndex chamará o template indexSucess.php, a ação executeList chamará o template listSuccess.php, e assim por diante.

Na realidade existe um return implícito ao final de cada ação chamando a View padrão, que é:

// Ambas ações chamam a View Success correspondente a cada açãopublic function executeIndex(sfWebRequest $request) { $this->pessoas = Doctrine::getTable('Pessoa') ->createQuery('a') ->execute(); }

Para chamar uma View personalizada, a ação deve terminar assim:

// O Symfony va procurar o template actionNameMeuTemplate.phppublic function executeIndex(){

return 'MeuTemplate';}

Mas é possível não chamar nenhum template. Este é o caso, por exemplo, para funções que serão executadas em modo “batch”, ou em agendamentos no cron, ou seja, não terão saída.

// O Symfony não vai executar nenhum templatepublic function executeAgendamento(){ return sfView::NONE;}

Page 53: Apostila Simfony

Capítulo 7 Camada Controller: controlando as requisições e respostas - 53

7.3. Redirecionamento

O Symfony permite dois tipos de redirecionamento:

• Para outra ação: é algo interno, e não interfere na URL exibida para o usuário, 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 código após eles nunca será executado.

Existe um tipo de redirecionamento bastante comum, que é o da “página não 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 página de erro pode ser personalizada. Basta criar um template em um módulo, uma ação e alterar a configuração no arquivo config/settings.yml da aplicação:

Page 54: Apostila Simfony

Capítulo 7 Camada Controller: controlando as requisições e respostas - 54

all:.actions: error_404_module: default error_404_actions: error404

Entretanto é comum necessitarmos realizar redirecionamento após um teste lógico. Para isto o Symfony dispõe de mais alguns métodos:

• 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 requisição, uma série de informações são recebidas pelo servidor Web, como dados sobre navegador, URL, GET e POST. O Symfony dispõe de todas estas informações ao Controller através do objeto sfWebRequest

Informações da Requisição-------------------------------------------------------------------------------------------------------------------Nome Função=>Exemplo-------------------------------------------------------------------------------------------------------------------isMethod($method) É POST ou GET=> true or false

Page 55: Apostila Simfony

Capítulo 7 Camada Controller: controlando as requisições e respostas - 55

getMethod()Nome do método de requisição=> '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 requisição Ajax?=> true

isSecure() É uma requisição SSL?=> true

hasParameter('teste')Parâmetro presente na requisição=> true

getParameter('teste') Valor de um parâmetro=> 'testando'

getParameterHolder()->getAll() Array com todos os parâmetros de requisição-------------------------------------------------------------------------------------------------------------------Informações da URI-------------------------------------------------------------------------------------------------------------------

getUri() URI completa=> 'http://localhost/mymodule/myaction'

getPathInfo()Informação do caminho=> 'mymodule/myaction'

getReferer() Referer

Page 56: Apostila Simfony

Capítulo 7 Camada Controller: controlando as requisições e respostas - 56

=> 'http://localhost/'

getHost()Nome do Host=> 'localhost'

getScriptName()Nome do Front Controller=> 'index.php'

-------------------------------------------------------------------------------------------------------------------Informação do navegador do cliente-------------------------------------------------------------------------------------------------------------------getLanguages() Array com as línguas disponíveis=> Array( [0] => en_US [1] => en )

getCharsets() Array com os charsets disponíveis=> Array( [0] => UTF-8 [1] => ISO-8859-1 )

getAcceptableContentTypes() Array com os content types disponíveis=> Array( [0] => text/xml [1] => text/html )

O primeiro parâmetro recebido pela ação é o objeto sfWebRequest, então, comumente é recebido como uma variável:

$this->pessoas = Doctrine::getTable('Pessoa')->find(array($request->getParameter('id'))) ->createQuery('a') ->execute();

Page 57: Apostila Simfony

Capítulo 7 Camada Controller: controlando as requisições e respostas - 57

7.4. ilizando sessões de usuário

O Symfony guarda as informações de sessão no objeto sfUser. Ele pode ser recuperado na ação através do método getUser. Apesar de seu nome, ele está disponível mesmo que não haja controle de usuários

// Armazenando valor na sessãopublic function executaEntrada(){ $this->getUser()->setAttribute('fone','3333.3333');}// Recuperando valor da sessão// O método permite um “valor padrão”, caso não exista// a variável na sessãopublic function executeSaida(){ $this->getUser->getAttribute('fone','não informado');}// Removendo uma variável da sessãopublic function executeRemovendo(){ $this->getUser->getAttributeHolder()->remove('fone');}// Limpando todas as variáveis de sessãopublic function executeLimpando(){ $this->getUser()->getAttributeHolder()->clear();}

7.5. Atributos Flash – variáveis de sessão descartáveis

Muitas vezes é necessário passar um valor de script para o outro dentro de um mesmo processamento. No PHP comum, isto geralmente força que um redirecionamento utilizando header('Location') necessite ser montado com passagem de parâmetros. Isto é muito comum para passar códigos de mensagens de erro, ou confirmação de gravação de registro, por exemplo.

Isto seria mais elegantemente resolvido com uma variável de sessão, mas depois ela seria inútil.

Page 58: Apostila Simfony

Capítulo 7 Camada Controller: controlando as requisições e respostas - 58

Para resolver este tipo de situação, o Symfony possui uma “variável de sessão descartável”, chamada flash.

O importante é lembrar: o valor do atributo flash só está disponível dentro de uma mesma requisição.

// Definindo o valor numa ação$this->getUser()->setFlash('mensagem','Registro Salvo');// (…)// Recuperando o valor em outra ação$mensagem = $this->getUser()->getFlash('mensagem');

Também 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; ?>

7.6. Repassando variáveis para a View

Uma funcionalidade muito importante é que a ação realiza a lógica da aplicação mas necessita repassar informações para a camada View. A forma que o Symfony faz isto é criando variáveis na ação que estarão disponíveis na View.

Se na ação temos o seguinte código:

public function executeShow(){ // Criando um atributo na ação // que ficará disponível na View$this->pessoa = Doctrine::getTable('Pessoa')->find(array($request->getParameter('id')));}

No layout ou template teremos a variável $pessoa, no caso um objeto Pessoa

<?php echo $pessoa->getNome() ?>

Page 59: Apostila Simfony

Capítulo 7 Camada Controller: controlando as requisições e respostas - 59

Capítulo 8

Camada Model: acesso ao banco de

dados

8.1. Introdução teórica

Bancos de dados são Relacionais. O PHP 5 e o Symfony são Orientado a Objetos. Para que se possa ser mais efetivo no uso da orientação a objeto.

É neste contexto que se encaixa a ORM. Toda lógica de acesso a dados é encapsulada pela ORM, mantendo todo o acesso a dados e suas regras de negócios num único local. O grande benefício é o reuso, pois é possível reutilizar um método de acesso que qualquer local do aplicativo, ou até de outro aplicativo. Além disso, uma regra de negócio ou uma chamada comum fica em um único lugar, facilitando o acesso e a manutenção.

Outra facilidade: como os registros são objetos, incluir novas funcionalidades não significa criar obrigatóriamente campos em uma tabela. Diferentes formas de visualizar um campo ou um conjunto de campos independe de qual banco de dados se está acessando.

Page 60: Apostila Simfony

Capítulo 8 Camada Model: acesso ao banco de dados - 60

Exemplo:

public function getPrimeiroNome()public function getSobrenome()public function getNomeCompleto()

O método getNomeCompleto utiliza os dois métodos anteriores para apresentar o nome completo de um cliente, por exemplo. Independente de mudanças nos nomes dos campos ou até em qual banco (MySQL, Postgres, Oracle, etc) será acessado, este método estará sempre disponível e consistente.

Informações mais complexas como o total de uma nota fiscal também podem ser criadas desta forma – e acessando outras tabelas através de suas classes respectivas.

Outra imensa vantagem é não preocupar-se com as variações nas sintaxes SQL entre diferentes bancos de dados.

Padrões de nomes de campos, tabelas e chaves estrangeiras, não são obrigatórios, mas facilita na posterior utilização dos métodos das classes.

• Nomes de tabelas sem hifens ou underscore (sublinhado vazio);

• Nomes de tabelas em minúsculas;

• Nomes de campo em minúsculas, com underscore (sublinhado vazio) separando campos grandes;

O Doctrine – ORM principal do Symfony em sua versão 1.4.4 – converte campos como nome_funcionario para um método como getNomeFuncionario, oque é bastante claro e legível.

Os nomes de tabela são convertids de cliente para classe Cliente.

É muito importante definir chaves estrangeiras, pois o Doctrine vasculha os relacionamentos e cria os devidos métodos de acesso.

Page 61: Apostila Simfony

Capítulo 8 Camada Model: acesso ao banco de dados - 61

O Doctrine ORM baseia a construção 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: falseunsigned: falseprimary: trueautoincrement: true nome:type: string()fixed: falseunsigned: falseprimary: falsenotnull: trueautoincrement: false sobre_nome:type: string()fixed: falseunsigned: falseprimary: falsenotnull: trueautoincrement: false email:type: string(45)fixed: falseunsigned: falseprimary: falsenotnull: trueautoincrement: false

Page 62: Apostila Simfony

Capítulo 8 Camada Model: acesso ao banco de dados - 62

Neste curso não abordaremos esta forma de criação de Models, mas com a varredura do banco para criação deste esquema (como visto no capítulo Criando uma aplicação rápida com o Symfony).

Também já foi citado que na criação dos Models há dois tipos de arquivos: mapeamento, classes das tabelas. Vamos detalhar um pouco os últimos dois, que são os utilizados na prática.

8.2. Classes de Tabelas

As classes de tabelas representam um registro na tabela. O Doctrine cria dois tipos: a classe Base e a Custom (personalizada). A classe Base é abstrata, não pode ser acessada diretamente, e é criada automaticamente pelo Doctrine. A classe Custom é criada pelo Doctrine, mas nunca é sobreescrita; ou seja, se houver alterações posteriores, somente serão realizadas na Base.Utiliza-se unicamente a Custom. Como herança da Base temos os getters(para recuperar valor dos campos) e setters (para alterar valor dos campos), métodos para salvar e excluir, entre outros.

8.3. Acessando dados através do Model

Considerando o exemplo da classe Pessoa, veremos algumas operações em seu arquivo “actions.class.php”.

8.4. Utilizando critérios no Doctrine

Para abstrair qualquer banco de dados, o Doctrine utiliza uma sintaxe própria de filtragem. A seguir tem-se um resumo das estruturas mais utilizadas.

Sintaxe Básica:-------------------------------------------------------------------------------------------------------------------Where column = value=> where(“column = value”);

Page 63: Apostila Simfony

Capítulo 8 Camada Model: acesso ao banco de dados - 63

WHERE column <> value=> where(“colum <> value”);

-------------------------------------------------------------------------------------------------------------------DQL-------------------------------------------------------------------------------------------------------------------http://www.doctrine-project.org/documentation/manual/1_2/en/dql-doctrine-query-language -------------------------------------------------------------------------------------------------------------------

Outras Sintaxes-------------------------------------------------------------------------------------------------------------------

ORDER BY column->addAscendingOrderByColumn(column);

LIMIT limit->limit(limit);

8.5. Métodos personalizados

8.5.1. Método especial __toStringJá vimos que a classe tabela é uma classe “Custom”, ou seja, pode ser

personalizada. Entretanto existe um método especial que pode ser adicionado e que é muito útil para tabelas que são “pai” em relacionamentos, ou seja, são tabelas estrangeiras: o método __toString

Este método é chamado automaticamente pelo Symfony quando da montagem de comboboxes em formulários para preencher a legenda. Deste modo, é possível determinar como será a legenda.

<?php

Page 64: Apostila Simfony

Capítulo 8 Camada Model: acesso ao banco de dados - 64

// lib/model/Pessoas.phpclass Pessoa extends BasePessoa{ public function __toString(){ return $this->getCodigo().'-'.$this->getNome(); }}

foi determinado como legenda a concatenação entre Código e Nome da Pessoa. Poderia ser qualquer outro formato necessário.

8.6. Sobrescrita de métodos

Muitas vezes é necessário um tratamento antes de alterar ou recuperar um campo, por exemplo. É possível alterar o comportamento padrão simplesmente sobrescrevendo o métodona classe extendida, como no exemplo:

<?php// lib/model/Pessoa.phpclass Pessoa extends BasePessoa{ /*** Set the value of [nome] column.* * @paramstring $v new value* @return Cliente The current object */ public function setNome($v) { if ($v !== null) {$v = (string) $v; }

Page 65: Apostila Simfony

Capítulo 8 Camada Model: acesso ao banco de dados - 65

if ($this->nome !== $v) {// Colocando todas as letras em maiúsculas$this->nome = strtoupper($v); }

return $this; } // setNome()

}?>

Uma pequena alteração: o nome será convertido todo para maiúsculas antes de ser gravado.

Capítulo 9

Camada View: Apresentação

9.1. Introdução teórica

Já vimos anteriormente que a Camada View é composta de Layouts e Templates. Como esta camada é responsável pelo resultado final de nosso trabalho

Page 66: Apostila Simfony

Capítulo 9 Camada View: Apresentação - 66

de programação, é importante compreendermos onde vamos colocar nosso código.

9.2. A montagem da View

De modo geral, a montagem da View é feita com a leitura de um layout (a nível de aplicação) e um template (a nível de módulo/ação).

Já vimos que o padrão de layout da aplicação é:

apps/aplicacao/templates/layout.php

enquanto os templates residem no diretório templates de cada módulo. No capítulo sobre Controllers vimos que cada ação, ao seu final, chama um template.Ainda temos a situação de utilizar trechos de templates, que são os partials.

Vamos conhecer o layout padrão do Symfony

<!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" /> </head> <body> <?php echo $sf_content ?> </body></html></comandoNumerado>

e considerando um template como segue:

<h1> Olá, Mundo </h1>

Teremos a seguinte página gerada:

Page 67: Apostila Simfony

Capítulo 9 Camada View: Apresentação - 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>

Então percebe-se que o trecho de código:

<?php echo $sf_content ?>

inclui o template. Conforme a distribuição do layout da página (com cabeçalho, menu, rodapé, etc), então posicionamos este código adequadamente.

Existem também três funções especiais (include_http_metas(), include_metas(), include_title()). Elas geram os headers do XHTML/HMTL baseados na configuração da View na aplicação e no módulo requisitado.

Para a aplicação, encontramos esta configuração em:

apps/aplicacao/config/view.yml

default:

Page 68: Apostila Simfony

Capítulo 9 Camada View: Apresentação - 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 módulo, não há um arquivo criado. Se criado, ele vai ser lido em cascata, ou seja, o que estiver na configuração é lido primeiro, e depois ele é lido e sobrescreve as informações.

apps/aplicacao/modulo/config/view.yml

editSuccess: metas: title: Editando Pessoa

listSuccess: metas: title: Listagem de Pessoas

printSuccess: metas: title: Imprimir registro

Page 69: Apostila Simfony

Capítulo 9 Camada View: Apresentação - 69

stylesheets: [print.css]

all: metas: title: Cadastro de Pessoas

No exemplo acima, a palavra chave all representa um padrão para o módulo, e cada template referenciado possui informações personalizadas. Isto é uma forma muito simples de incluir arquivos javascript onde são necessários, por exemplo.

9.3. Partials (Parciais)

Partials, como já foi visto anteriormente, são trechos de template que podem ser incluídos em determinados pontos do layout ou do template. Eles iniciam com um underscore ( _ ) e residem ou no diretório de layouts da aplicação (globais) ou no diretório de templates de cada módulo.

Para incluir partials, utiliza-se um dos três códigos abaixo, conforme a necessidade:

// Estando no mesmo módulo, é possível incluir o partial// apps/aplicacao/modules/meumodulo/templates/_parcial.php// sem citar o módulo<?php include_partial('parcial') ?> // Se quiser incluir em qualquer outro lugar fora do módulo// então é preciso informar o módulo<?php include_partial('meumodulo/parcial') ?>

// Um partial global como// apps/aplicacao/templates/_parcialGlobal.php// é incluído assim<?php include_partial('global/parcialGlobal') ?>

Page 70: Apostila Simfony

Capítulo 9 Camada View: Apresentação - 70

Entretanto, os partials não tem acesso às variáveis disponíveis.

9.4. Variáveis do Symfony

O Symfony dispõe algumas variáveis para que a View possa ser montada com informações provenientes de vários lugares. Já foi visto no capítulo sobre Controllers como as ações passam variáveis para a View, mas existem outras informações que estão disponíveis nas ações que também estão disponíveis na View.

• $sf_context: sfContext

• $sf_request: sfRequest

• $sf_params: Parâmetros do objeto Request

• $sf_use: sfUser

Os usos são semelhantes ao do Controller.

9.5. Helpers

Helpers são funções em PHP que retornam algum tipo de trecho em HTML. O Symfony possui vários pré-definidos e é possível também criar Helpers personalizados.

Existem vários grupos de Helpers, e nem todos estão ativos por padrão. Para carregar um que não 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')) ?>

Page 71: Apostila Simfony

Capítulo 9 Camada View: Apresentação - 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 ação de criação de novo registro no módulo 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" />

Page 72: Apostila Simfony

Capítulo 9 Camada View: Apresentação - 72

Page 73: Apostila Simfony

Capítulo 10 Forms: criando formulários - 73

Capítulo 10

Forms: criando formulários

10.1. Introdução teórica

Uma necessidade especial no trabalho com o aplicativos Web é a criação e manipulação de formulários. Isto envolve algumas tarefas recorrentes:

• Montar o formulário: através de tags XHTML/HTML, é preciso criar uma a uma cada tag de cada campo;

• Tratar o envio do formulário: definir na tag form como o formulário será enviado;

• Validar os campos do formulário: ao receber os valores, decidir se são ou não válidos;

• Exibir erros de validação: se algum campo não for validado, retornar erro;

• Armazenar os dados: se estiverem vinculados a alguma tabela de banco de dados;

• Retornar informação sobre gravação de registro: alguma

Page 74: Apostila Simfony

Capítulo 10 Forms: criando formulários - 74

mensagem informativa, confirmando ou não a gravação.

Estas tarefas se tornam ainda mais tediosas e de complexa manutenção conforme aumenta o número de tabelas e campos nestas tabelas.

O Symfony propõe uma abordagem muito eficiente para centralizar tanto a criação como a validação dos formulários. Veremos agora como utilizar de forma básica seus recursos.

10.2. Gerando formulários automaticamente

A maioria dos formulários num sistema são baseados em tabelas de um banco de dados. Para facilitar nosso estudo, começaremos com a visualização de um formulário criado no capítulo Criando uma aplicação rápida com o Symfony. Lembrando que ele foi criado com o uso de uma tarefa automatizada do Doctrine:

symfony doctrine:build-forms

Agora vamos conhecer o arquivo:

lib/form/doctrine/base/BaseLivroForm.class.php

<?phpclass 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(),

Page 75: Apostila Simfony

Capítulo 10 Forms: criando formulários - 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';

Page 76: Apostila Simfony

Capítulo 10 Forms: criando formulários - 76

}

}?>

Lembrando que ele não deve ser alterado ou acessado diretamente, mas sim a classe extendida LivroForm que está em:

lib/form/doctrine/LivroForm.class.php

<?phpclass LivroForm extends BaseLivroForm{ public function configure() { }}?>

O que for implementado dentro do método configure() sobrescreve o que foi definido na classe Base.

Podemos identificar na classe Base quatro trechos básicos que são:

• $this->setWidgets: define os widgets (elementos de formulário) para cada campo da tabela;

• $this->setValidators: define os validadores para cada campo da tabela;

• $this->widgetSchema->setNameFormat: define um padrão para os nomes de campos (o padrão é criar um array com o nome da tabela, onde cada chave do array é o nome de um campo);

Page 77: Apostila Simfony

Capítulo 10 Forms: criando formulários - 77

• $this->errorSchema: define o esquema de erros.

Os dois últimos são padronizados e raramente é útil personalizá-los. Os dois primeiros são a alma do esquema de formulários do Symfony, e então vamos conhecê-los um pouco mais.

10.3. Widgets

Na criação da classe BaseLivroForm vemos que ela é uma classe extendida de BaseFormDoctrine - que por sua vez é uma classe extendida de sfForm. A classe BaseFormDoctrine é uma "versão para o ORM Doctrine" da classe padrão de manipulação de formulários do Symfony.

A classe sfForm manipula todas as operações de formulário e seus campos, chamados Widgets. Cada Widgets é uma extensão da classe base sfWidget, e possui um funcionalidade específica.

Quando vamos criar um formulário Web existem várias dificuldades, incluindo tamanho dos campos, o rótulo (label), o tipo de input (text, password, radio, checkbox, além das opções de select e textarea), e muitas vezes ainda é necessário pegar informações de listagem ou de outras tabelas para criar listagens.

Isto no Symfony fica muito simples: existem Widgets para cada situação corriqueira. Se olhamos o código específico de criação 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:

Page 78: Apostila Simfony

Capítulo 10 Forms: criando formulários - 78

<input type="hidden" name="livro[isbn]" id="livro_isbn" />

Os campos tipo input são 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">Informática</option><option value="2">Auto Ajuda</option><option value="4">Administração</option><option value="5">Ficção</option></select>

No capítulo Criando uma aplicação rápida com o Symfony vimos que para esta funcionalidade ser efetiva é preciso criar um método __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. Não cabe estudar um a um, mas conforme for necessário, se detalhando em cada um que se utilizar. Uma lista completa de referência 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

Page 79: Apostila Simfony

Capítulo 10 Forms: criando formulários - 79

(validadores), que são regras para aceitar os valores enviados pelo formulário. Os Validators, é preciso deixar claro, sempre testam TODOS os campos; portanto, mesmo que não seja necessário validar um campo, é preciso definir uma validação "vazia", ou não obrigatória.

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 parâmetro:

• primeiro: opções

• segundo: mensagens

Se não há o segundo array, então as mensagens serão padrão. Mas veremos logo a seguir como personalizá-las.

Page 80: Apostila Simfony

Capítulo 10 Forms: criando formulários - 80

Novamente, há muitas opções, que variam conforme o Validator. Alguns são muito usados e comuns:

• max_length: tamanho máximo de caracteres

• min_length: tamanho mínimo de caracteres

• required: campo obrigatório ou não

• default: valor padrão para o campo

• label: rótulo para o campo

No exemplo acima, sfValidatorDoctrineChoice exige model e column, ou seja, vai checar se o valor enviado está dentro dos possíveis 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 são definidas no segundo array, e existem duas mensagens básicas:

• required: quando o campo é de preenchimento obrigatório ('Required')

• invalid: quando a regra de validação não foi atendida ('Invalid')

Outros são comuns para max_lenght e min_lenght, que informam o tamanho máximo e mínimo necessários.

Para personalizar as mensagens, envia-se o segundo array como parâmetro do Validator:

// (...)'email'=> new sfValidatorEmail( array('required' => true), array('required' => 'Email é obrigatório', 'invalid' => 'Email inválido') ),// (...)

Opcionalmente é possível definir uma mensagem padrão de required e invalid

Page 81: Apostila Simfony

Capítulo 10 Forms: criando formulários - 81

para os Validators informando:

<?phpclass LivroForm extends BaseLivroForm{ public function configure() { $this->setRequiredMessage('Campo obrigatório'); $this->setInvalidMessage('Valor inválido - corrija'); }}?>

sem, entretanto, perder a funcionalidade de criar mensagens personalizadas para cada campo.

Há vários Validators, e da mesma forma que os Widgets é mais interessante estudá-los quando necessitamos deles. Uma lista com os Validators disponíveis é encontrada em:

http://www.symfony-project.org/api/1_4/validator

10.5. Labels

O Symfony cria automaticamente rótulos (labels) para os campos baseado em seu nome. De forma simples, ele tenta manter o seguinte padrão:

• data_nascimento => Data Nascimento

• codigo_area => Codigo Area

Apesar de ser interessante, este padrão não é muito útil em português, pois temos acentuação e isto não é gravado com o nome do campo (pelo menos não por administradores e projetistas de banco com o um mínimo de bom senso).

Podemos personalizar os rótulos através do próprio Widget com a opção label

Page 82: Apostila Simfony

Capítulo 10 Forms: criando formulários - 82

como utilizando um método específico:

<?phpclass LivroForm extends BaseLivroForm{ public function configure() { $this->widgetSchema->setLabels(array('isbn' => 'ISBN','autor'=> 'Autor','titulo' => 'Título','cat_id' => 'Categoria','preco'=> 'Preço','sumario' => 'Sumário', )); }}?>

10.6. Controlando o formulário

Todo controle do formulário, como não poderia deixar de ser, é realizado nas ações (controller). Abaixo segue um arquivo actions.class.php do módulo livro, comentado para melhor compreensão do mecanismo. Os métodos não relacionados ao formulário foram excluídos para melhor didática

<?phpclass livroActions extends sfActions{

Page 83: Apostila Simfony

Capítulo 10 Forms: criando formulários - 83

// (...)

// Método para criação de novo registro public function executeNew(sfWebRequest $request) {// Cria uma nova instância de LivroForm// e o disponibiliza para a View.// // Como não está vinculado a um registro pré-existente,// quando for chamado $form->getObject()->isNew()// resultará "true", e então as opções para novo registro// serão exibidas na View, como no caso de para qual ação // será enviada o formulário

$this->form = new LivroForm(); }

// Método que processa a criação de um novo registro public function executeCreate(sfWebRequest $request) {

// Se não foi recebido um POST, redireciona para// página não encontrada (erro 404)

$this->forward404Unless($request->isMethod('post'));

// Cria uma nova instância de LivroForm $this->form = new LivroForm();

// Processa o formulário através do método// processForm desta classe (mais adiante) $this->processForm($request, $this->form);

// Define o template como newSuccess.php// (o padrão seria createSuccess.php)

Page 84: Apostila Simfony

Capítulo 10 Forms: criando formulários - 84

$this->setTemplate('new'); }

// Método para edição de registro public function executeEdit(sfWebRequest $request) {

// Se não conseguir recuperar um parâmetro "isbn" e com ele// recuperar um registro do banco de dados, retorna// página não 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 instância de LivroForm// mas agora com dados do livro recuperado do banco de dados $this->form = new LivroForm($livro); }

// Método que processa a atualização do registro public function executeUpdate(sfWebRequest $request) {// Se não foi recebido um POST ou um PUT, redireciona para// página não encontrada (erro 404)// (ver informação sobre o PUT na seção sobre a apresentação// do formulário mais adiante. $this->forward404Unless($request->isMethod('post') || $request->isMethod('put'));

// Se não conseguir recuperar um parâmetro "isbn" e com ele// recuperar um registro do banco de dados, retorna// página não encontrada (erro 404) com a mensagem:

Page 85: Apostila Simfony

Capítulo 10 Forms: criando formulários - 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 instância de LivroForm// mas agora com dados do livro recuperado do banco de dados $this->form = new LivroForm($livro);

// Processa o formulário através do método// processForm desta classe (mais adiante) $this->processForm($request, $this->form);

// Define o template como editSuccess.php// (o padrão seria updateSuccess.php) $this->setTemplate('edit'); }

// Método que processa o envio do formulário// em separado para evitar duplicidade de código protected function processForm(sfWebRequest $request, sfForm $form) {

// O método bind do formulário recupera os dados enviados// no $request para poder validar os dados $form->bind($request->getParameter( $form->getName()), $request->getFiles($form->getName()));

// Realiza a validação do formulário if ($form->isValid()) {// Se o formulário foi validado, salva o registro

Page 86: Apostila Simfony

Capítulo 10 Forms: criando formulários - 86

$livro = $form->save();

// e então redireciona para a tela edição, evitando// o problema de recarregar a página (F5) gerar um novo// envio do formulário$this->redirect('livro/edit?isbn='.$livro->getIsbn()); }

// Se o formulário não foi validado, então na exibição do // formulário as mensagens de erro aparecerão }}?>

10.7. Exibindo o formulário

Até o momento só estudamos a configuração do formulário, agora veremos como exibí-lo no template.

10.7.1. Método automatizado

A geração automática que realizamos no capítulo Criando uma aplicação rápida com o Symfony nos dá uma idéia simples de como criar a parte visual do formulário. O arquivo é um partial que pode ser utilizado em qualquer lugar da aplicação.

O arquivo segue comentado para melhor compreensão.

apps/admin/modules/livro/templates/_form.php

Page 87: Apostila Simfony

Capítulo 10 Forms: criando formulários - 87

<!--Inclusão de CSS e Javascript para o formulário, se houver--><?php include_stylesheets_for_form($form) ?><?php include_javascripts_for_form($form) ?>

<!--Tag "form"

Algumas condições são incluídas para num único arquivo trabalhar tanto edição quanto criação de registro.

O objeto $form, criado pela ação, pode verificar se o objeto é novo ou não (ou seja, ainda não foi salvo), e entãooptar por montar o link com a ação create ou update.

De mesmo modo, se não for novo, coloca a chave primária como parâmetro (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 não for um objeto novo, o Symfony inclui um campo oculto para simular o método PUT do HTTP (algo aindapouco utilizado, e por isto simulado pelo Symfony paraaumentar a segurança)

Page 88: Apostila Simfony

Capítulo 10 Forms: criando formulários - 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 início, será exibida ao final da tabela-->

<tfoot>

<td colspan="2"><!--O botão de cancelar retorna para a listagem de registros--> &nbsp;<a href="<?php echo url_for('livro/index') ?>"> Cancel</a>

<!--Se o registro não é novo, então exibe um botão para excluir.Como o uso do helper link_to é montado o link, enviando a chave primária e ainda fazendo uso de um recurso de javascriptpara exibir uma janela de confirmação de exclusão(Are you sure? Tem certeza?)--> <?php if (!$form->getObject()->isNew()): ?>&nbsp;<?php echo link_to('Delete', 'livro/delete?isbn='.$form->getObject()->getIsbn(), array('method' => 'delete',

Page 89: Apostila Simfony

Capítulo 10 Forms: criando formulários - 89

'confirm' => 'Are you sure?')) ?> <?php endif; ?><!--Botão de envio--> <input type="submit" value="Save" /> </td>

</tfoot> <tbody><!--A renderização do form propriamente dito--><?php echo $form ?> </tbody> </table></form>

10.7.2. Método detalhado

Vimos que com o comando:

<?php echo $form ?>

todos os campos são listados em forma de tabela. Mas é possível especificar o layout campo a campo.

O Symfony renderiza para cada campo três partes:

• Rótulo: renderLabel()

<?php echo $form['email']->renderLabel() ?>// HTML<label for="pessoa_email">Email</label>

Page 90: Apostila Simfony

Capítulo 10 Forms: criando formulários - 90

• Tag do formulário: render()

<?php echo $form['email']->render() ?>// HTML<input type="text" name="pessoa[email]" id="pessoa_email" />

• Mensagens de erro: renderError() (exibido apenas se o formulário foi validado e o campo não passou na validação)

<?php echo $form['email']->renderError() ?>// HTML<ul class="error_list"> <li>Email inválido</li></ul>

É possível gerar também a linha de tabela inteira:

// Gerando uma linha de tabela// Não há diferença da linha gerada pelo // echo $form<?php echo $form['email']->renderRow() ?>

Page 91: Apostila Simfony

Capítulo 10 Forms: criando formulários - 91

Page 92: Apostila Simfony

Capítulo 11 AJAX - 92

Capítulo 11

AJAX

11.1. Introdução teórica

Já estudamos na introdução o conceito de AJAX. A grande questão do AJAX é:

• AJAX deixa tudo muito legal, mas...

• ... AJAX dá muito trabalho!!

Isto é uma realidade muito em função da quantidade de Javascript que é necessário escrever adicionalmente ao código gerado no servidor.

Entretando, com o Symfony, pouco se utiliza o Javascript - a não ser que se necessite de uma funcionalidade muitíssimo específica. Utilizando por padrão o framework para AJAX Prototype é possível ter diversas funcionalidades com nenhuma ou pouca escrita de Javascript.

Page 93: Apostila Simfony

Capítulo 11 AJAX - 93

11.2. Incluindo Javascript

No capítulo Camada View: Apresentação conhecemos os Helpers. Existe um grupo de Helpers para Javascript. Seu uso básico num layout ou template é:

<?php // Incluíndo o Helperuse_helper('Javascript') ;?><?php // Utilizando o Helper para criar uma função

echo javascript_tag(" function alterarNome() { ... }") ?><!-- HTML Gerado:Para validar em XHTML é gerado dentro da declaração CDATA--><script type="text/javascript"> //<![CDATA[function alterarNome(){ ...} //]]> </script>

Page 94: Apostila Simfony

Capítulo 11 AJAX - 94

11.3. Criando um link para uma função

<?php echo link_to_function('Alterar Nome', "alterarNome()") ?><!--HTML Gerado:--><a href="#" onClick="alterarNome(); return none;">Alterar Nome</a>

Existe ainda o Helper button_to_function, que faz um link para uma função num botão, ou então é possível fazer uma imagem clicável que aciona uma função em javascript; basta mudar o primeiro parâmetro de link_to_function, para image_tag('imagem.png').

11.4. Alterado o conteúdo de um elemento HTML

<div id="processando">Iniciado processamento</div><?php echo javascript_tag( update_element_function('processando', array( 'content' => "Processamento completo", ))) ?>

// Colocando o conteúdo após o conteúdo atual// com "before" seria antes.update_element_function('processando', array( 'position' => 'after', 'content' => "Agora o conteúdo ficou depois",));

Page 95: Apostila Simfony

Capítulo 11 AJAX - 95

11.5. Chamando uma função remota

Aqui realmente começa a interação via AJAX.

Inicialmente precisamos confirmar se o acesso à biblioteca do AJAX está disponível.

symfony plugin:install sfProtoculousPlugin

Agora é só utilizar os recursos do AJAX. Vamos criar uma pequena ação para teste:

apps/admin/modules/livro/actions/action.class.php

<?phpclass livroActions extends sfActions{ // (...)

// Método para devolver um valor via AJAX public function executeAjax($request) {

// Testando se é uma requisição AJAX válida if($this->getRequest()->isXmlHttpRequest()) {

// Retornando um texto concatenado com o parâmetro enviadoreturn $this->renderText('Ok, recebi uma requisição: ' . $request->getParameter('valor')); } else {

// Se a requisição não é AJAX, então envia uma mensage de erroreturn $this->renderText('Requisição mal formatada'); } }?>

Page 96: Apostila Simfony

Capítulo 11 AJAX - 96

Agora vamos adicionar um código à index do módulo livro para aprendermos como fazer a requisição e recuperar o valor em um elemento do HTML:

apps/admin/modules/livro/templates/indexSuccess.php

<?php// Incluíndo o Helperuse_helper('Javascript') ;

// (...)

?>

<!-- div que recebe o retorno da requisição AJAX --><div id="retorno"></div>

<?php /*A função link_to_remote*/

echo link_to_remote('Teste de Ajax', array( 'update' => 'retorno', 'url' => 'livro/ajax?valor=TESTANDO',))?>

<?php /*A função link_to_remote com confirmação*/

echo link_to_remote('Teste de Ajax', array( 'update' => 'retorno',

Page 97: Apostila Simfony

Capítulo 11 AJAX - 97

'url' => 'livro/ajax?valor=TESTANDO', 'confirm' => 'Tem certeza?',))?>

<?php /*A função link_to_remote com método GET*/

echo link_to_remote('Teste de Ajax', array( 'update' => 'retorno', 'url' => 'livro/ajax?valor=TESTANDO', 'method' => 'get',))?>

Se a intenção é que a função seja executada imediatamente no carregamento da página, então é utilziada o helper remote_function:

<?php// Incluíndo o Helperuse_helper('Javascript') ;

// (...)

?>

<!-- div que recebe o retorno da requisição AJAX --><div id="retorno"></div>

<?php /*A função remote_function*/

Page 98: Apostila Simfony

Capítulo 11 AJAX - 98

echo remote_function('Teste de Ajax', array( 'update' => 'retorno', 'url' => 'livro/ajax?valor=TESTANDO',))?>

11.5.1. Atualizações Periódicas

Este tipo de chamada AJAX é realizada para atualizar constantemente uma página, como por exemplo para checar o recebimento de novos emails.

<div id="retorno"></div><?php // "frequency" é o tempo em segundos// "with" permite passar como parâmetro 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')",)) ?>

Page 99: Apostila Simfony

Capítulo 11 AJAX - 99

11.5.2. Formulários AJAX

Vamos fazer um exemplo com o formulário do módulo categoria. Primeiramente, criamos uma ação para tratar a requisição AJAX de envio do formulário:

<?phpclass categoriaActions extends sfActions{

// (...)

// Método que trata o formulário via AJAX public function executeCreateajax(sfWebRequest $request) {

// Verifica se é uma requisição AJAX e se é um // formulário enviado if($request->isXmlHttpRequest() && $request->isMethod('post')) {

// Cria uma nova instância de CategoriaForm$this->form = new CategoriaForm();

// O método bind do formulário recupera os dados enviados// no $request para poder validar os dados$this->form->bind($request->getParameter( $this->form->getName()), $request->getFiles($this->form->getName()));

// Realiza a validação do formulárioif ($this->form->isValid()){// Se o formulário foi validado, salva o registro $categoria = $this->form->save();

// Devolve uma mensagem via AJAX - ok return $this->renderText('Registro Salvo');

Page 100: Apostila Simfony

Capítulo 11 AJAX - 100

} else {// Devolve uma mensagem via AJAX - erro return $this->renderText('Erro ao salvar registro');}

} else {// Se não é uma requisição AJAX ou não é um POST// devolve uma mensagem de erro

return $this->renderText('Requisição mal formatada'); } }

}?>

11.5.3. Callbacks

Callbacks são ações que são executadas durante a requisição AJAX. O uso mais comum delas é dar ao usuário uma noção de que o "servidor está trabalhando" enquanto ele aguarda uma requisição - os famosos "Carregando" ou imagem com animação.

Os callbacks são os seguintes:

• before: Antes da requisição ser iniciada

• after: Imediatamente após a requisição 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 usuário pode interagir com a resposta remota, mesmo que ainda não tenha terminado

Page 101: Apostila Simfony

Capítulo 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 não está na faixa 2xx

• 404: Quando a requisição retorna o status 404

• complete: Quando XMLHttpRequest está completo (gerado logo após success ou failure, se ocorrerem)

O exemplo clássico: 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')",)) ?>

Page 102: Apostila Simfony

Capítulo 11 AJAX - 102

Page 103: Apostila Simfony

Capítulo 11 AJAX - 103

Apêndices

Page 104: Apostila Simfony

Capítulo 12 ApêndiceBanco de dados "livraria" - 104

Capítulo 12

Apêndice

Banco de dados "livraria"

--

-- Banco de Dados: `livraria444`

--

CREATE DATABASE `livraria444` DEFAULT CHARACTER SET utf8

COLLATE utf8_unicode_ci;

USE `livraria444`;

SET FOREIGN_KEY_CHECKS=0;

SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;

/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;

Page 105: Apostila Simfony

Capítulo 12 ApêndiceBanco de dados "livraria" - 105

/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;

/*!40101 SET NAMES utf8 */;

--

-- Estrutura da tabela `categoria`

--

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;

--

-- Estrutura da tabela `cliente`

--

DROP TABLE IF EXISTS `cliente`;

CREATE TABLE IF NOT EXISTS `cliente` (

`cliente_id` int(10) unsigned NOT NULL auto_increment,

Page 106: Apostila Simfony

Capítulo 12 ApêndiceBanco 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;

--

-- Estrutura da tabela `livro`

--

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`)

Page 107: Apostila Simfony

Capítulo 12 ApêndiceBanco de dados "livraria" - 107

) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

--

-- Estrutura da tabela `pedido`

--

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','DEPÓSITO','CARTÃO')

collate utf8_unicode_ci NOT NULL,

PRIMARY KEY (`pedido_id`),

KEY `cliente_id` (`cliente_id`)

Page 108: Apostila Simfony

Capítulo 12 ApêndiceBanco de dados "livraria" - 108

) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ;

--

-- Estrutura da tabela `pedidoitem`

--

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 ;

--

-- Estrutura da tabela `usuario`

--

DROP TABLE IF EXISTS `usuario`;

CREATE TABLE IF NOT EXISTS `usuario` (

Page 109: Apostila Simfony

Capítulo 12 ApêndiceBanco 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;

--

-- Restrições para as tabelas dumpadas

--

--

-- Restrições para a tabela `livro`

--

ALTER TABLE `livro`

ADD CONSTRAINT `livro_ibfk_1` FOREIGN KEY (`cat_id`)

REFERENCES `categoria` (`cat_id`);

--

-- Restrições para a tabela `pedido`

--

ALTER TABLE `pedido`

Page 110: Apostila Simfony

Capítulo 12 ApêndiceBanco de dados "livraria" - 110

ADD CONSTRAINT `pedido_ibfk_1` FOREIGN KEY (`cliente_id`)

REFERENCES `cliente` (`cliente_id`);

--

-- Restrições 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;

Page 111: Apostila Simfony

Capítulo 13 ApêndicesfDoctrineGuard plugin - 111

Capítulo 13

Apêndice

sfDoctrineGuard plugin

http://www.symfony-project.org/plugins/sfDoctrineGuardPlugin

sfDoctrineGuardPlugin é um plugin do Symfony que fornece capacidade autenticação e autorização sobre o padrão de segurança do Symfony.

Lhe dá um Model (objetos usuário, grupo e permissão) e módulos (backend/retaguarda e frontend/frente) para implementar segurança em sua aplicação Symfony em um minuto num plugin configurável

Para instalar o plugin:

symfony plugin:install sfDoctrineGuardPlugin

Reconstrua seu Model:

symfony doctrine:build-modelsymfony doctrine:build-sqlsymfony doctrine:build-formssymfony 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

Page 112: Apostila Simfony

Capítulo 13 ApêndicesfDoctrineGuard plugin - 112

Ative um ou mais módulos no seu settings.yml (opcional)

Para sua aplicação backend/retaguarda: sfGuardUser, sfGuardGroup, sfGuardPermission

Para sua aplicação frontend/frente: sfGuardAuth

all: .settings: enabled_modules:[default, sfGuardGroup, sfGuardUser, sfGuardPermission]

Limpe seu cache

symfony cc

Opcionalmente crie um usuário padrão

symfony guard:create-user fabien $secret

Opcionalmente ative o filtro "Remember Me" em filters.yml

security: class: sfGuardBasicSecurityFilter

13.1.1. Implementando segurança em sua aplicação

Para implementar a segurança em uma aplicação Symfony:

Ativando o módulo sfGuardAuth em settings.yml

all: .settings: enabled_modules: [..., sfGuardAuth]

Altere o padrão para os módulos de login e segurança em settings.yml

login_module:sfGuardAuthlogin_action:signinsecure_module: sfGuardAuthsecure_action: secure

Page 113: Apostila Simfony

Capítulo 13 ApêndicesfDoctrineGuard plugin - 113

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 parâmetro url em cada rota.

Você deve ter uma regra de roteamento @homepage (utilizado quando o usuário faz logout).

Estas rotas são automativamente registradas pelo plugin se o módulo sfGuardAuth é ativado, a não ser que você defina sf_guard_plugin_routes_register para falso no arquivo de configuração app.yml

all: sf_guard_plugin: routes_register: false

Ative a segurança para alguns módulos ou para a aplicação inteira em security.yml

default:

Page 114: Apostila Simfony

Capítulo 13 ApêndicesfDoctrineGuard plugin - 114

is_secure: on

Está feito. Agora, se você tentar acessar uma página segura, será redirecionado para a página de login.

Se você carregou o arquivo padrão de dados do plugin, tente logar com o usuário admin com a senha admin.

13.1.2. Administrando seus usuários, permissões e grupos

Para administrar seus usuários, permissões e grupos, o sfDoctrineGuardPlugin vem com 3 módulos que podem ser integrados á sua aplicação backend/retaguarda. Estes módulos são auto-gerados graças ao Symfony Admin Generator.

Ative os módulos em settings.yml

all: .settings: enabled_modules: [..., sfGuardGroup, sfGuardPermission, sfGuardUser]

Acesse os módulos com a rota padrão:

http://livraria.local/sfGuardUser

13.1.3. Personalizando os templates do módulo sfGuardAuth

Por padrão, o módulo sfGuardAuth vem com dois templates muito simples:

• signinSuccess.php

• secureSuccess.php

Se você quer personalizar um destes templates:

• Crie o módulo sfGuardAuth em sua aplicação (não utilize a tarefa init-module, apenas crie o diretório sfGuardAuth)

• Crie um template com o nome do template que você quer personalizar no diretório sfGuardAuth/templates

• O Symfony agora monta seu template ao invés do padrão.

Page 115: Apostila Simfony

Capítulo 13 ApêndicesfDoctrineGuard plugin - 115

13.1.4. Personalizando os templates do módulo sfGuardAuth

Se você quer personalizar ou adicionar métodos ao sfGuardAuth:

• Crie um módulo sfGuardAuth em sua aplicação

• Crie um arquivo actions.class.php em seu diretório actions que herde de BasesfGuardAuthActions (não esqueça de incluir BasesfGuardAuthActionspois ele não pode ser autocarregado pelo Symfony)

<?php

require_once(sfConfig::get('sf_plugins_dir').'/sfDoctrineGuardPlugin/modules/sfGuardAuth/lib/BasesfGuardAuthActions.class.php');

class sfGuardAuthActions extends BasesfGuardAuthActions{ public function executeNewAction() { return $this->renderText('This is a new sfGuardAuth action.'); }}?>

13.1.5. Classe sfGuardSecurityUser

Esta classe herda da classe sfBasicSecurityUser do Symfony e é utilizada pelo objeto user na sua aplicação Symfony (por que você modificou a classe base myUser anteriormente).

Então, para acessá-la, você pode utilzizar o padrão $this-;gt;getUser() em suas ações ou $sf_user em seus templates.

Page 116: Apostila Simfony

Capítulo 13 ApêndicesfDoctrineGuard plugin - 116

sfGuardSecurityUser adiciona alguns métodos:

• signIn() and signOut()

• getGuardUser() que retorna o objeto sfGuardUser

• Um conjunto de métodos "proxy" para acessar diretamente o objeto sfGuardUser

Por exemplo, para recuperar o nome de usuário atual:

$this->getUser()->getGuardUser()->getUsername()

// ou via proxy method

$this->getUser()->getUsername()

13.1.6. Flag superadministrador

O sfDoctrineGuardPlugin tem o conceito de super administrator. Um usuário que é superadministrador sobrepõem-se a todas as checagens de credencial.

A flag de superadministrador não pode ser definida via web, você deve definir esta flag diretamente no banco de dados ou através da tarefa de linha de comando:

symfony promote-super-admin adminsymfony guard:promote admin (versão 3.1.3)

13.1.7. Validators (Validadores)

O sfDoctrineGuardPlugin vem com um validador para você utilizar em seus módulos: sfGuardUserValidator.

Este validador é utilizado pelo módulo sfGuardAuth para validar o usuário e senha e automaticamente logar o usuário.

Page 117: Apostila Simfony

Capítulo 13 ApêndicesfDoctrineGuard plugin - 117

13.1.8. Personalizando o Model sfGuardUser

O Model sfGuardUser é muito simples. Não há colunas email ou first-name ou birthday. Como você não pode adicionar métodos à classe, o sfAuthPlugin possibilita definir uma classe com o perfil do usuário.

Por padrão, sfGuardUser procura a classe sfGuardUserProfile.

Aqui está um exemplo simples de uma classe sfGuardUserProfile que você pode adicionar ao schema.yml:

sf_guard_user_profile: _attributes: { phpName: sfGuardUserProfile } id: user_id: { type: integer, foreignTable: sf_guard_user, foreignReference: id, required: true, onDelete: cascade } first_name: varchar(20) last_name:varchar(20) birthday: date

Agora você pode acessar os dados do usuário através do objeto user:

$this->getUser()->getGuardUser()->getProfile()->getFirstName()// or via the proxy method$this->getUser()->getProfile()->getFirstName()

O métodogetProfile() recupera o objeto de perfil de usuário associado ou cria um novo se ainda não existe.

Quando você exclui um usuário, o perfil associado também é excluído.

Você pode mudar o nome da classe de perfil de usuário e o nome da chave estrangeira em app.yml:

all: sf_guard_plugin: profile_class:sfGuardUserProfile profile_field_name: user_id

Page 118: Apostila Simfony

Capítulo 13 ApêndicesfDoctrineGuard plugin - 118

13.1.9. Checar a senha do usuário com um método externo

Se você não pode armazenar a senha no banco de dados porque possui um servidor LDAP, um arquivo .htaccess ou você armazena sua suas senhas em outra tabela, você pode informar sua própria chamada checkPassword (método estático ou função) em app.uml

all: sf_guard_plugin: check_password_callable: [MyLDAPClass, checkPassword]

Quando o Symfony chama o método $this->getUser()->checkPassword(), irá chamar seu método ou função. Sua função deve receber dois parâmetros, o primeiro é o nome de usuário e o segundo é a senha. Deve retornar true ou false. Aqui segue um modelo para esta função:

function checkLDAPPassword($username, $password){ $user = LDAP::getUser($username); if ($user->checkPassword($password)) { return true; } else { return false; }}

Page 119: Apostila Simfony

Capítulo 13 ApêndicesfDoctrineGuard plugin - 119

13.1.10. Alterar o algoritmo utilizado para armazenar senhas

Por padrão, senhas são armazenadas num hash sha1(). Mas você pode modificar isto para qualquer chamada em app.yml:

all: sf_guard_plugin:algorithm_callable: [MyCryptoClass, MyCryptoMethod]

# or

all: sf_guard_plugin: algorithm_callable: md5

Como o algoritmo é armazenado para cada usuário, você pode mudar de idéia depois sem a necessidade de regerar todas as senhas atuais dos usuários.

13.1.11. Alterando o nome ou o período de expiração do cookie "Remember Me"

Por padrão, a funcionalide Remember Me cria um cookie chamado sfRemember vai permanecer por 15 dias. Você pode modificar este comportamente em app.yml:

all: sf_guard_plugin: remember_key_expiration_age: 2592000# 30 days in seconds remember_cookie_name: myAppRememberMe

Page 120: Apostila Simfony

Capítulo 13 ApêndicesfDoctrineGuard plugin - 120

13.1.12. Personalizando a manipulação de redirecionamento de sfGuardAuth

Se você deseja redirecionar o usuário para seu perfil após um login ou definir um destino de logout, você pode alterar os valores de redirecionamente em app.yml:

all: sf_guard_plugin: # the plugin use the referer as default success_signin_url:@my_route?param=value # the plugin use the referer as default success_signout_url: module/action

13.1.13. Configurando o formulário de login

Você pode modificar o formuário de login do módulo sfGuardAuth em app.yml:

all: sf_guard_plugin: signin_form: sfGuardFormSigninCustom