Você está na página 1de 67

Sobre o Autor

Elton Lus Minetto possui graduao em Cincia de Computao pela Unochapec e especializao em Cincia da Computao pela UFSC/UNOESC. Trabalha com PHP/MySQL desde 2000, com Linux desde 1997 e com MacOSX desde 2007. autor do livro Frameworks para Desenvolvimento em PHP, da editora Novatec e co-autor do livro Grid Computing in Research and Education, publicado pela editora IBM/Redbooks, EUA. Atualmente scio da Coderockr (http://www.coderockr.com), empresa de desenvolvimento de aplicativos para iOS e Web, trabalhando com consultoria, treinamento e desenvolvimento. Pode ser encontrado no http://eminetto.me

Introduo ! ..............................................................5 Instalando o Zend Framework!.............................6 Denindo o projeto !...............................................7


Modelagem! ................................................................................7 Estrutura do projeto ! .................................................................9 Congurando o Apache ! ...........................................................9

Bootstrap!.............................................................10 Controladores ! ......................................................13 Modelos ! ................................................................14


Trabalhando com modelos e queries !...................................17

Layout e vises !...................................................20 Formulrios !.........................................................23


Enviando arquivos !.................................................................26 Herana de formulrios !.........................................................29 Subforms !................................................................................30

Criando um CRUD!...............................................31
Desao !....................................................................................34

Organizando a aplicao !....................................34 Roteamento !.........................................................37 Autenticao ! ........................................................38 Controle de acesso !.............................................42 Navegao !...........................................................47

Paginao !............................................................49 Cache !...................................................................52 Tradues !............................................................57 Enviando e-mails ! .................................................59 Diagnstico da aplicao !...................................63
Zend_log ! ..................................................................................63 Zend_Db_Proler!....................................................................65

Concluso !............................................................67

Introduo
Como a idia deste livro ir direto ao ponto, vou fazer isso j na introduo. A idia desse livro no explicar a teoria e losoa do PHP, da orientao a objetos, as maravilhas dos design patterns, etc. Existem timos livros e sites que podem lhe ajudar a entender todos os conceitos envolvidos aqui. Entre os livros eu posso indicar:

PHP Prossional. Alexandre Altair de Melo / Mauricio G. F. Nascimento. Editora Novatec PHP Programando com Orientao a Objetos. Pablo DallOglio. Editora Novatec Zend Framework Componentes Poderosos para PHP. Flvio Gomes da Silva Lisboa. Editora Novatec Zend Framework em Ao. Brown. Editora Alta Books. Rob Allen, Nick Lo, Steven

Os trs primeiros so escritos por autores brasileiros e so livros de grande importncia e didtica. O ltimo um clssico e tambm muito bom. O foco desde livro ser um guia de desenvolvimento das principais funcionalidades do Zend Framework. Ele iniciou como uma apostila para cursos que venho ministrando nos ltimos trs ou quatro anos, ento algo que venho testando e alterando continuamente. Esta a segunda edio deste e-book. Nesta edio procurei fazer uma atualizao nos cdigos e melhoria na explicao de alguns conceitos. Espero que lhe seja til como tem sido para mim.

Instalando o Zend Framework


Instalar o Zend Framework uma tarefa simples. O primeiro passo vericar os seus requisitos bsicos: um servidor web com suporte a reescrita de URLs (Apache ser usado nestes exemplos) e o PHP 5.2.4 ou superior. No arquivo de congurao do Apache basta adicionar as linhas abaixo, ou alter-las para reetir o seguinte:
LoadModule rewrite_module modules/mod_rewrite.so AddModule mod_rewrite.c AllowOverride all

https://gist.github.com/987319

Isto indica ao servidor que ele deve carregar o mdulo que permite a reescrita de URLs (mais exemplos nos prximos tpicos) e permite o uso de conguraes em arquivos especiais. Agora basta fazer o download do framework, no site
http://framework.zend.com

No momento da escrita deste livro a verso mais atual era a 1.11.11. No site possvel escolher entre trs opes para download: a verso com o Zend Server, a verso Full e a verso Minimal do framework. A primeira indicada se voc quer a soluo completa, com um servidor Apache e o MySQL j congurados. A verso full possui, alm do framework, documentao, testes e demos. E a verso minimal formada apenas pelo framework. Geralmente a verso minimal a mais indicada. Depois de descompactar o arquivo possvel visualizar a seguinte estrutura (para a verso Minimal):
bin/ scripts para a criao de projetos LICENSE.txt - uma cpia da licena usada pelo framework README.txt - instrues sobre instalao e documentao VERSION.txt texto sobre a verso do framework library/ - neste diretrio encontra-se o framework INSTALL.txt - instrues de instalao

O diretrio library deve ser copiado para o diretrio htdocs de seu servidor Apache. E pronto! O Zend Framework est pronto para uso.

Denindo o projeto
Na minha opinio a nica forma de aprender uma nova ferramenta, linguagem, sistema operacional, quando voc realmente precisa resolver algum problema com ela. Pensando nisso, esse livro baseado na construo de um aplicativo: um blog. Mas um blog? Por alguns motivos: um problema fcil de se entender. Todo mundo sabe como um blog funciona, seus requisitos e funcionalidades. Ento a fase de requisitos do projeto fcil de completar um blog apresenta um grande nmero de funcionalidades comuns a vrios outros sites, como mdulos, controle de acesso e permisses, upload de arquivos, tratamento de formulrios, cache, tradues, integrao com servios externos, etc. a grande maioria dos frameworks possui um exemplo como desenvolver um blog usando X, ento ca mais fcil para comparao se voc j estudou algum outro framework como CakePHP, CodeIgniter ou mesmo Ruby on Rails

Modelagem
Agora que o convenci (ou no) de como desenvolver um blog pode lhe ajudar a entender o Zend Framework, vamos mostrar a modelagem das tabelas:

Simples, como deveria ser. Usando alguma ferramenta, como o PHPMyAdmin, SequelPro, ou o bom e velho terminal, possvel criar a estrutura do banco usando os comandos SQL abaixo:
CREATE DATABASE blog; GRANT ALL privileges ON blog.* TO zend@localhost IDENTIFIED BY 'zend'; USE blog; CREATE !TABLE IF NOT EXISTS `users` ( ! `id` INT NOT NULL AUTO_INCREMENT , ! `username` VARCHAR(200) NOT NULL , ! `password` VARCHAR(250) NOT NULL , ! `name` VARCHAR(200) NULL , ! `valid` TINYINT NULL , ! `role` VARCHAR(20) NULL , ! PRIMARY KEY (`id`) ) ENGINE = InnoDB;

CREATE !TABLE IF NOT EXISTS `posts` ( ! `id` INT NOT NULL AUTO_INCREMENT , ! `title` VARCHAR(250) NOT NULL , ! `description` TEXT NOT NULL , ! `post_date` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP , ! PRIMARY KEY (`id`) ) ENGINE = InnoDB;

CREATE !TABLE IF NOT EXISTS `comments` ( ! `id` INT NOT NULL AUTO_INCREMENT , ! `post_id` INT NOT NULL , ! `description` TEXT NOT NULL , ! `name` VARCHAR(200) NOT NULL , ! `email` VARCHAR(250) NOT NULL ,

! `webpage` VARCHAR(200) NOT NULL , ! `comment_date` TIMESTAMP NULL , ! PRIMARY KEY (`id`, `post_id`) , ! INDEX `fk_comments_posts` (`post_id` ASC) , ! CONSTRAINT `fk_comments_posts` ! ! FOREIGN KEY (`post_id` ) ! ! REFERENCES `posts` (`id` ) ! ! ON DELETE NO ACTION ! ! ON UPDATE NO ACTION) ENGINE = InnoDB;

https://gist.github.com/987325

Estrutura do projeto
Vamos agora usar a ferramenta de gerao de projetos do Zend Framework. No diretrio bin do framework existem os arquivo zf.bat (Windows) e zf.sh (Linux/Mac OS X). preciso que este arquivo e o executvel do PHP estejam no caminho dos executveis (PATH) do seu sistema operacional, ou execut-lo pelo caminho onde voc salvou o framework. Para criar o projeto vamos executar:
./ZendFramework-1.11.11-minimal/bin/zf.sh create project blog

O diretrio blog foi criado com o contedo:


application - diretrio da aplicao Bootstrap.php - bootstrap da aplicao configs - arquivos de configurao controllers - controladores models - modelos views - vises docs - documentaes library - aqui devemos copiar o framework public - diretrio de arquivos pblicos tests - testes unitrios

Congurando o Apache

Vamos tambm congurar um VirtualHost no Apache para facilitar os testes da aplicao. No arquivo httpd.conf (ou apache.conf) adicionar o seguinte (procure no arquivo docs/README.txt do projeto)
<VirtualHost *:80> DocumentRoot "/caminho_htdocs/blog/public" ServerName blog.local

# This should be omitted in the production environment SetEnv APPLICATION_ENV development

<Directory "caminho_htdocs/blog/public"> Options Indexes MultiViews FollowSymLinks AllowOverride All Order allow,deny Allow from all </Directory> </VirtualHost>

necessrio alterar os caminhos nas opes DocumentRoot e Directory para reetirem o caminho correto em sua mquina. preciso tambm alterar o arquivo hosts do sistema operacional para adicionar o endereo do blog.local. No Linux e Mac OS X, alterar o /etc/hosts e adicionar a linha:
127.0.0.1 blog.local

No Windows o arquivo que deve ser alterado o c:\windows \system32\drivers\etc\hosts e a linha a ser adicionada igual a citada acima.

Bootstrap
No Zend Framework, existe um componente importante, chamado de Bootstrap que responsvel por receber todas as requisies,

congurar o necessrio (por exemplo: sesses, conexo com banco de dados, cache, etc) e invocar o controlador especicado pela URL que o usurio solicitou. Vou tentar explicar isso na forma de uma imagem:

O usurio faz uma requisio ao Apache, que invoca o Bootstrap (na imagem o index.php). Este por sua vez faz a congurao necessria e passa a execuo para o controlador. O controlador faz seu trabalho especco, podendo usar cdigos contidos nos modelos e formatar vises que sero mostradas ao usurio. Ao nal do processo do controlador, o Bootstrap volta a assumir e naliza a requisio. Esta forma como o Zend Framework trabalha muito interessante pois nos permite diversas exibilidades e conguraes. Se determinada congurao ou varivel deve ser acessvel a todos os pontos de nossa aplicao (controladores, modelos e vises) ela pode ser escrita no Bootstrap, pois sabemos que toda execuo ir obrigatoriamente passar por ela. Outra vantagem que se caso ocorra alguma exceo (Exceptions da linguagem PHP) que no for tratada por um controlador o Bootstrap ir receb-la e podemos ter um ponto nico no sistema para capturar e tratar erros. Todo este processo funciona da seguinte forma: o arquivo index.php cria uma instncia da classe Zend_Application que usa a classe Bootstrap contida no Bootstrap.php. Ao ser inicializada, a

aplicao ir executar todos os mtodos cujo nome iniciem com _init. Podemos criar nosso Bootstrap inicial da seguinte forma:
<?php class Bootstrap extends Zend_Application_Bootstrap_Bootstrap { !!!!/** * Salva o config no registry * @return void * @author Elton Minetto */ !!!!public function _initConfig() !!!!{ !!!!!!!!$config = new Zend_Config($this->getApplication()>getOptions(), true); !!!!!!!!Zend_Registry::set('config', $config); !!!!} !!!!/** * Inicializa a sesso *" * @return void * @author Elton Minetto */ !!!!public function _initSession() !!!!{ !!!!!!!!$session = new Zend_Session_Namespace('Blog'); !!!!!!!!Zend_Registry::set('session', $session); !!!!} !!!!/** * Inicializa o banco de dados. Somente necessrio se desejado salvar a conexo no Registry * * @return void * @author Elton Minetto */ !!!!public function _initDb() !!!!{ !!!!!!!!$db = $this->getPluginResource('db')->getDbAdapter(); !!!!!!!!Zend_Db_Table::setDefaultAdapter($db); !!!!!!!!Zend_Registry::set('db', $db); !!!!}" }

https://gist.github.com/1449311

Nos prximos tpicos vamos adicionando tens ao Bootstrap. Um novo conceito apresentado no cdigo acima o Zend_Registry. O registro uma forma de armazenarmos objetos ou variveis para que estes estejam acessveis em toda a aplicao. um mecanismo elegante para substituir o uso de variveis globais e o Zend Framework faz uso extenso dele.

Controladores
Mas como o Bootstrap sabe qual o controlador a ser executado? Isso detectado pela URL que o usurio invocou. Funciona da seguinte forma:
http://BASE_URL/modulo/controlador/action/parametro/valor/

Exemplos:
http://blog.local/index/show/id/1 http://blog.local/admin/index/show/id/1

O primeiro link vai acessar o controlador IndexController dentro do mdulo default (que o mdulo padro, caso exista) e tentar invocar um mtodo chamado showAction (a action) passando um parmetro chamado id, com valor 1. O segundo link vai acessar o controlador IndexController dentro do mdulo admin (que especicado na url) e tentar invocar um mtodo chamado showAction (a action) passando um parmetro chamado id, com valor 1. Todos os controladores so classes que extendem uma classe chamada Zend_Controller_Action e devem estar em um arquivo cujo nome termine em Controller.php. Exemplo. Para criarmos os arquivos que atendam os exemplos acima, precisamos criar:
application/controllers/IndexController.php

application/modules/admin/controllers/IndexController.php

O contedo do primeiro seria:

<?php class IndexController extends Zend_Controller_Action { ! ! ! ! public function showAction() { ! ! ! ! ! ! } }

https://gist.github.com/987343

e o contedo do segundo:
<?php class Admin_IndexController extends Zend_Controller_Action { ! ! ! ! public function showAction() { ! ! ! ! ! ! } }

https://gist.github.com/987345

Note que o caminho do primeiro arquivo no est dentro de modules/default pois este o mdulo padro, no sendo necessrio criar desta forma caso estejamos usando apenas um mdulo. Se estivermos usando mais de um mdulo recomendado criarmos o diretrio, para ajudar na organizao. Algumas observaes sobre os cdigos. A funo showAction() deve ter o suxo Action ou no ser acessvel ao usurio. Isto uma forma de proteo do seu cdigo. A classe Admin_IndexController indica que ela pertence ao mdulo admin e obrigatrio ser denida desta forma. A classe IndexController no precisa indicar o nome do mdulo pois o mdulo default o principal.

Modelos
Antes de iniciarmos a criao dos controladores e das vises precisamos criar a primeira camada da nossa aplicao MVC: os modelos. Para isso deve-se criar um arquivo para cada tabela e

estes devem ser armazenados no diretrio models. Todos os modelos so classes PHP que extendem a classe Zend_Db_Table_Abstract. O primeiro passo congurarmos nosso projeto para acessar o banco de dados. Para isso vamos executar
zf configure dbadapter "adapter=Pdo_Mysql&host=localhost&username=zend&password=zend&dbname= blog"

preciso alterar os dados de username, password e nome do database, caso sejam diferentes Agora vamos criar o primeiro model, o arquivo models/Users.php Users.php
<?php /** * Modelo da tabela users * */ class Application_Model_Users extends Zend_Db_Table_Abstract { // nome da tabela no banco de dados ! !protected!$_name!=!'users'; }

https://gist.github.com/987350

Posts.php
<?php /** * Modelo da tabela posts * */ class Application_Model_Posts extends Zend_Db_Table_Abstract { ! protected!$_name!=!'posts'; ! ! protected $_dependentTables = array('Comments');! }

https://gist.github.com/987354

Comments.php
<?php /** * Modelo da tabela comments * */ class Application_Model_Comments extends Zend_Db_Table_Abstract { ! !protected!$_name!=!'comments'; ! !protected $_referenceMap = array( ! ! 'Post' => array ( ! ! ! ! 'columns' => array('post_id'), ! ! ! ! 'refTableClass' => 'Posts', ! ! ! ! 'refColumns' => array('id') ! ! ) ! !); }

https://gist.github.com/987356

Nos modelos Posts e Comments podemos ver o uso de um recurso interessante do Zend_Db_Table, os relacionamentos entre tabelas. Analisando a imagem da modelagem vemos que um post possui muitos comentrios e que cada comentrio pertence a um post (relacionamento um para muitos). No modelo Posts indicamos a relao das tabelas que dependem dela, usando o cdigo:
protected $_dependentTables = array('Comments');!

E no modelo Comments os detalhes da tabela relacionada, com o cdigo:


!protected $_referenceMap = array( ! ! 'Post' => array ( ! ! ! ! 'columns' => array('post_id'), ! ! ! ! 'refTableClass' => 'Posts', ! ! ! ! 'refColumns' => array('id') ! ! ) ! !);

Caso a tabela possua mais relacionamentos basta adicionar novos sub-arrays dentro do array $_referenceMap usando o mesmo modelo.

Com essa funcionalidade podemos facilmente, a partir de um blog recuperar seus comentrios. Por exemplo, podemos usar um cdigo similar ao abaixo, em um controlador, para recuperar os comentrios (vamos ver mais exemplos sobre o uso dos models e dos controllers nos prximos tpicos)
//cria uma instncia do modelo Posts $posts = new Application_Model_Posts; //busca detalhes do post com id = 1 $post = $posts->fetchRow("id = 1"); //busca todos os comentrios deste post $comments = $post->findDependentRowset('Comments');

Tambm possvel realizar o processo inverso. Digamos que eu precise buscar os dados do post relacionado a um determinado comentrio:
//cria uma instncia do modelo Comments $comments = new Application_Model_Comments; //busca detalhes do comentrio com id = 1 $comment = $comments->fetchRow('id = 1'); //busca os dados do post relacionado a este comentrio $post = $comment->findParentRow('Posts');

O framework tambm fornece o suporte a relacionamentos muitos para muitos, que no faz parte do nosso exemplo, mas pode ser visto na documentao ocial (mtodo ndManyToManyRowset):
http://framework.zend.com/manual/en/zend.db.table.relationships.html

Trabalhando com modelos e queries


O Zend Framework fornece trs formas de acessarmos os dados de uma base de dados: usando models, usando o Zend_Db_Select para gerar queries ou escrevendo a query sem o uso de objetos.

Exemplos usando Models Para recuperarmos todos os registros na tabela Posts:

$posts = new Application_Model_Posts; $data = $posts->fetchAll();

Para recuperarmos apenas o registro com id = 1


$posts = new Application_Model_Posts; $data = $posts->fetchRow("id = 1")

Para fazermos insert de um registro


$posts = new Application_Model_Posts; $data = array ( ! ! ! ! 'title' => 'Ttulo do post', ! ! ! ! 'description' => 'Texto do post' ); //insere e retorna o novo Id gerado pelo mysql $id = $posts->insert($data);

Para fazermos update de um registro


$posts = new Application_Model_Posts; $data = array ( ! ! ! ! 'title' => 'Novo ttulo do post', ); $posts->update($data, "id = $id"); //update do post com id especfico

Para fazermos delete de um registro


$posts = new Application_Model_Posts; $posts->delete("id = $id");

Criando consultas SQL com Zend_Db_Select O uso da classe Zend_Db_Select muito simples, o intuito dela proporcionar ao desenvolvedor a possibilidade de fazer consultas complexas sem a necessidade de escrever cdigo SQL, e sim utilizando objetos. O construtor do Zend_Db_Select necessita uma conexo com um banco de dados. Podemos buscar a conexo com a base de dados que criamos no Bootstrap.php:
$db = Zend_Registry::get('db'); $select = new Zend_Db_Select($db);

Exemplos de uso Consulta simples, como um SELECT * FROM 'users'


$select = new Zend_Db_Select($db); $select->from('users'); $select->limit(10); $select->order('id desc'); $rs = $select->query(); $data = $rs->fetchAll()

Consulta com insero de clausula WHERE, como um SELECT * FROM 'users' WHERE 'id' > 10:
$select = new Zend_Db_Select($db); $select->from('users'); $select->where('id > ?', 10); $rs = $select->query(); $data = $rs->fetchAll()

Consulta com seleo de campos e clusula WHERE, como um SELECT id, name FROM 'users' WHERE id > 10:
$select = new Zend_Db_Select($db); $select->from('users'); $select->columns('id, name'); $select->where('id > ?', 10); $rs = $select->query(); $data = $rs->fetchAll()

Consulta com seleo de campos e clusula WHERE e INNER JOIN, como um SELECT 'users'. 'id', 'users'. 'name', 'pictures'. 'address' FROM `users` INNER JOIN `pictures` ON `pictures`.`user_id` = `users`.`id` WHERE users.id > 10:
$select = new Zend_Db_Select($db); $select->from('users'); $select->columns('users.id, users.name, pictures.address'); $select->joinInner('picures', 'picures.user_id = user.id'); $select->where('users.id > ?', 10); $rs = $select->query(); $data = $rs->fetchAll()

Em qualquer momento possvel imprimir a consulta que foi gerada. til para ns de debug
echo $select;

Executando consultas SQL Para executar consultas SQL simples:


$sql = "select * from posts"; $stmt = $db->query($sql); $this->view->data = $stmt->fetchAll();

Layout e vises
No contexto de uma aplicao desenvolvida com o Zend Framework, uma viso uma poro de cdigo que ser visualizada pelo usurio. HTML, CSS, JavaScript, imagens, etc. papel do controlador acessar e processar dados (como os vindos da camada de modelo) e prepar-los para serem visualizados pelo usurio, atravs da viso. Um arquivo de viso nada mais do que um arquivo PHP com a extenso .phtml e cuja funo bsica imprimir (usando echo por exemplo) os dados enviados pelo controlador. No nosso exemplo, vamos analisar o cdigo do controlador IndexController, cujo contedo est no arquivo
application/controllers/IndexController.php <?php class IndexController extends Zend_Controller_Action { ! ! ! ! public function indexAction() { ! ! ! ! //cria uma varivel a ser mostrada na view ! ! ! ! $this->view->msg = 'Hello!'; ! ! } }

https://gist.github.com/987360

Vamos analisar o cdigo. Na linha $this->view->msg = 'Hello!'; o controlador est salvando para a viso uma varivel chamada msg, com o contedo Hello!. Ao nal da execuo do mtodo

indexAction() a classe ir tentar encontrar um arquivo de viso, chamado index.phtml (este um comportamento herdado da classe Zend_Controller_Action) em um diretrio especco, o
views/scripts/index/index.phtml

Todos os arquivos de viso do controlador IndexController devem ser criados no diretrio index dentro do views/scripts. O contedo do arquivo index.phtml simplesmente
<?php echo $this->msg; ?>

Agora vamos trabalhar com um novo conceito, os layouts. Para isso vamos analisar o wireframe do nosso blog:

Em todas as pginas iremos ter um ttulo, uma imagem e um rodap, com informaes sobre o autor, copyright, etc. A nica informao que ir mudar o contedo das pginas. Na pgina inicial teremos os ltimos posts do blog, opes de incluir e excluir, posts, etc. Mas o cabealho e o rodap permanecem os mesmos. Para facilitar este tipo de construo o Zend Framework possui o conceito de layouts. Precisamos ativar o recurso de layouts no nosso projeto, digitando o comando:

zf enable layout

Isto indica ao framework que o arquivo de layout chama-se default.phtml e encontra-se no diretrio do projeto: application/layouts/scripts/layout.phtml Seu contedo :
<html> <head> " <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8" /> <title>Blog</title> </head> <body> <?php !!!//mensagens de erro !!!$session = Zend_Registry::get('session'); !!!if(isset($session->erro)) " echo "<p> $session->erro </p>"; " unset($session->erro); !!!?> //mostra o contedo da pgina echo $this->layout()->content; ?> </body> </html>

https://gist.github.com/1473182

A linha mais importante deste arquivo a


echo $this->layout()->content;

que ir gerar o contedo das vises sendo executadas. No exemplo anterior, o contedo da viso views/scripts/index/ index.phtml gerada por esta linha. No arquivo default.phtml onde deve ser adicionada toda a parte de CSS, e onde iramos colocar nosso cabealho e rodap para ser apresentado por toda a aplicao. O resultado pode ser visto ao acessar a URL http://blog.local/

Uma observao. Se no especicarmos qual o controlador na URL o Bootstrap vai automaticamente procurar o controlador IndexController e a action indexAction. Ento acessar http://blog.local equivalente a acessar http://blog.local/index/index

Formulrios
O Zend_Form um componente que permite que formulrios sejam criados e mantidos usando-se objetos, aumentando produtividade e mantendo um padro de desenvolvimento. possvel tambm com o Zend_Form, a implementao de formulrios com herana, ou seja, voc tem um formulrio genrico (ex: Application_Form_Usuario) que pode ser utilizado para criao de outros (ex: Application_Form_UsuarioAdmin) que possuiriam apenas alguns campos adicionais alm do form padro. Ele tambm possui componentes que permitem a utilizao de todos os Filters e Validators do Zend, bem como a implementao de Componentes personalizados. Teremos inicialmente dois formulrios, o de login e o de cadastro/ alterao de novos posts (que ser usado pelo administrador). Neste captulo iremos denir e mostrar na viso os formulrios, deixando a lgica da manipulao dos mesmos para os tpicos posteriores. Vamos criar o primeiro formulrio, o de login com o comando:
zf create form Login

O arquivo forms/Login.php:
<?php

class Application_Form_Login extends Zend_Form { !!!!public function init() !!!!{ !!!!!!!!//nome do formulrio !!!!!!!!$this->setName('Login'); !!!!!!!!//elemento para o campo username !!!!!!!!$username = new Zend_Form_Element_Text('username'); !!!!!!!!//configurar o label, dizer q obrigatrio, adicionar um filtro e um validador !!!!!!!!$username->setLabel('Login') !!!!!!!!!!!!->setRequired(true) !!!!!!!!!!!!->addFilter('StripTags') !!!!!!!!!!!!->addValidator('NotEmpty'); !!!!!!!!//elemento para a senha !!!!!!!!$password = new Zend_Form_Element_Password('password'); !!!!!!!!$password->setLabel('Senha') !!!!!!!!!!!!->setRequired(true) !!!!!!!!!!!!->addFilter('StripTags') !!!!!!!!!!!!->addValidator('NotEmpty'); !!!!!!!!//boto de submit !!!!!!!!$submit = new Zend_Form_Element_Submit('submit'); !!!!!!!!$submit->setLabel('Entrar'); !!!!!!!!$submit->setAttrib('id', 'Entrar') " " ->setIgnore(true); !!!!!!!! !!!!!!!!//exemplo de class css !!!!!!!!//$submit->setAttrib('class', 'verde buttonBar'); !!!!!!!!//adicionar os campos ao formulrio !!!!!!!!$this->addElements(array($username, $password, $submit)); !!!!!!!!//action e method !!!!!!!!$this->setAction('/auth/index')->setMethod('post'); !!!!}

https://gist.github.com/1455143

Todos os formulrios so classes PHP que extendem a classe Zend_Form. Aps criarmos os campos $username e $password fazemos a congurao dos mesmo, indicando o label, se so obrigatrios (setRequired), adicionamos ltros (addFilter, no exemplo o ltro StripTags que remove tags html do contedo) e

validadores (o NotEmpty garante que o campo no vai ser aceito se estiver vazio). Precisamos agora alterar o controlador para que ele faa a instanciao do novo objeto de formulrio. Para realizarmos um teste vamos alterar o controlador IndexController.php e adicionamos as linhas abaixo, no mtodo indexAction.
//cria um novo formulrio $this->view->form = new Application_Form_Login;

No nosso arquivo de viso (views/index/index.phtml) iremos mostrar o nosso formulrio:


<?php echo $this->form; ?>

Basta imprimir o formulrio na view, e todo o HTML ser gerado, de acordo com as conguraes do arquivo forms/Login.php. Podemos fazer a mesma coisa com o formulrio de cadastro de posts. Vamos criar a classe do formulrio de insero/alterao de posts. O arquivo forms/Post.php cou da seguinte maneira:
zf create form Post <?php class Application_Form_Post extends Zend_Form { !!!!public function init() !!!!{ !!!!!!!!$this->setName('Post'); !!!!!!!!$id = new Zend_Form_Element_Hidden('id'); !!!!!!!! !!!!!!!!$titulo = new Zend_Form_Element_Text('title'); !!!!!!!!$titulo->setLabel('Ttulo')->setRequired(true)>addFilter('StripTags')->addValidator('NotEmpty'); !!!!!!!!$texto = new Zend_Form_Element_Textarea('description'); !!!!!!!!$texto->setAttrib('rows', '20'); !!!!!!!!$texto->setAttrib('cols', '100'); !!!!!!!!$texto->setLabel('Texto')->setRequired(true) >addFilter('StripTags') ->addValidator('NotEmpty'); !!!!!!!!$submit = new Zend_Form_Element_Submit('submit');

!!!!!!!!$submit->setLabel('Adicionar')->setIgnore(true); !!!!!!!!$this->addElements(array($id, $titulo, $texto, $submit)); !!!!!!!!//action e method !!!!!!!!$this->setAction('/post/create')->setMethod('post'); !!!!}

https://gist.github.com/1335179

A nica novidade neste formulrio so os elementos textarea e hidden, que geram os seus correspondentes em html. Mais adiante iremos voltar a trabalhar com estes formulrios, o de login e o responsvel por criar novos posts no blog.

Enviando arquivos
Outra funcionalidade comum a necessidade de enviar arquivos via formulrios. Apesar de no fazer parte do nosso blog, vamos fazer um exemplo usando o Zend_Form. Vamos criar um novo form:
zf create form Album

O contedo do arquivo forms/Album.php:


<?php class Application_Form_Album extends Zend_Form { !!!!public function init() !!!!{ " " $this->setName('Foto'); " " $title = new Zend_Form_Element_Text('title'); " " $title->setLabel('Ttulo')->setRequired(true)>addFilter('StripTags')->addValidator('NotEmpty'); " " " " " " " " " " " " $file = new Zend_Form_Element_File('arq'); $file->setLabel('Escolha uma imagem:'); // limite de tamanho $file->addValidator('Size', false, 1024000); // extenses: JPEG, PNG, GIFs $file->addValidator('Extension', false, 'jpg,png,gif');

" " " " "

" " " " "

$submit = new Zend_Form_Element_Submit('submit'); $submit->setLabel('Enviar'); $submit->setName('submit'); //exemplo de class css $this->addElements(array($title, $file, $submit)); //action e method $this->setAction('/album')->setMethod('post'); $this->setAttrib('enctype', 'multipart/form-data');

" " " " " " !!!!} }

https://gist.github.com/1468851

Neste formulrio demonstrado o uso da classe Zend_Form_Element_File, com seus validadores especcos, denindo o tamanho mximo do arquivo e suas extenses permitidas. Para podermos usar este form vamos criar o controlador AlbumController.php (zf create controller Album) com o contedo abaixo:
<?php /** * Album * * @package default * @author Elton Minetto **/ class AlbumController extends Zend_Controller_Action { !!!! !!!!/** * Album * * @return void * @author Elton Minetto **/ !!!!public function indexAction() { !!!!!!!!$form = new Application_Form_Album; !!!!!!!!//verifica se foram enviados dados via post !!!!!!!!if ($this->_request->isPost()) { !!!!!!!!!!!!//pega os dados enviados !!!!!!!!!!!!$formData = $this->_request->getPost(); !!!!!!!!

!!!!!!!!!!!!//verifica se o formulrio est vlido !!!!!!!!!!!!//de acordo com os validadores do Zend_Form !!!!!!!!!!!!if ($form->isValid($formData)) { !!!!!!!!!!!!!!!!$adapter = $form->arq->getTransferAdapter(); !!!!!!!!!!!!!!!!//indica o destino dos arquivos temporrios !!!!!!!!!!!!!!!!$adapter->setDestination('/tmp'); !!!!!!!!!!!!!!!!try { !!!!!!!!!!!!!!!!!!!!//recebe o arquivo !!!!!!!!!!!!!!!!!!!!$adapter->receive(); !!!!!!!!!!!!!!!!} catch (Zend_File_Transfer_Exception $e) { !!!!!!!!!!!!!!!!!!!!echo $e->getMessage(); !!!!!!!!!!!!!!!!} !!!!!!!!!!!!!!!!//nome do arquivo !!!!!!!!!!!!!!!!$name = $adapter->getFileName(); !!!!!!!!!!!!!!!!//tamanho !!!!!!!!!!!!!!!!$size = $adapter->getFileSize(); !!!!!!!!!!!!!!!!//tipo !!!!!!!!!!!!!!!!$mimeType = $adapter->getMimeType(); !!!!!!!!!!!!!!!!// somenete mostra os detalhes do arquivo !!!!!!!!!!!!!!!!echo "Nome do arquivo enviado: $name", "<br>"; !!!!!!!!!!!!!!!!echo "Tamanho do arquivo: $size", "<br>"; !!!!!!!!!!!!!!!!echo "Tipo: $mimeType", "<br>"; !!!!!!!!!!!!!!!!// Novo nome do arquivo !!!!!!!!!!!!!!!!$renameFile = 'NovoNome.jpg'; !!!!!!!!!!!!!!!!$fullFilePath = '/tmp/'.$renameFile; !!!!!!!!!!!!!!!!// renomeia usando o Zend Framework !!!!!!!!!!!!!!!!$filterFileRename = new Zend_Filter_File_Rename(array('target' => $fullFilePath, 'overwrite' => true)); !!!!!!!!!!!!!!!!$filterFileRename->filter($name); !!!!!!!!!!!!}//se o formulrio est invlido !!!!!!!!!!!!else { !!!!!!!!!!!!!!!!// Mostra os erros e popula o form com os dados corretos !!!!!!!!!!!!!!!!$form->populate($formData); !!!!!!!!!!!!} !!!!!!!!} !!!!!!!!else { !!!!!!!!!!!!//ainda no foi submetido dados !!!!!!!!} !!!!!!!!$this->view->form = $form; !!!!} !!!!

https://gist.github.com/1468878

E nalmente, a viso views/scripts/album/index.phtml:


<?php echo $this->form; ?>

Nesse exemplo possvel visualizar a facilidade de uso e do Zend Framework para tratar arquivos enviados pelo usurio.

Herana de formulrios
possvel criarmos heranas de formulrios. Vamos denir um formulrio base, chamado PessoaForm. Esta classe possui os campos bsicos, que todos os formulrios tero. Ao denirmos esta classe como abstrata garantimos que o desenvolvedor precisa extend-la antes de usar algum formulrio, pois classes abstratas no podem ser instanciadas.
<?php abstract class Application_Form_Pessoa extends Zend_Form { !!!!public function init() { !!!!!!!!$this->setName('Login'); !!!!!!!!$username = new Zend_Form_Element_Text('username'); !!!!!!!!$username->setLabel('Login')->setRequired(true)>addFilter('StripTags')->addValidator('NotEmpty'); !!!!!!!!$password = new Zend_Form_Element_Password('password'); !!!!!!!!$password->setLabel('Senha')->setRequired(true)>addFilter('StripTags')->addValidator('NotEmpty'); !!!!!!!!$this->addElements(array($username, $password)); !!!!} }

https://gist.github.com/1468916

Vamos agora denir duas classes que especializam a classe Application_Form_Pessoa, a Application_Form_Aluno e a Application_Form_Professor:

<?php class Application_Form_Aluno extends Application_Form_Pessoa { !!!public function init() { " " parent::init(); !!!!!!!!$matricula = new Zend_Form_Element_Text('matricula'); !!!!!!!!$matricula->setLabel('Matrcula')->setRequired(true)>addFilter('StripTags')->addValidator('NotEmpty'); !!!!!!!!$submit = new Zend_Form_Element_Submit('submit'); !!!!!!!!$submit->setLabel('Entrar'); !!!!!!!!$submit->setAttrib('id', 'Entrar'); !!!!!!!!$this->addElements(array($matricula,$submit)); !!!!!!!!//action e method !!!!!!!!$this->setAction('/index/index')->setMethod('post'); !!!!} }

https://gist.github.com/1468943
<?php class Application_Form_Professor extends Application_Form_Pessoa { !" public function init() { " " parent::init(); !!!!!!!!$disciplina = new Zend_Form_Element_Text('disciplina'); !!!!!!!!$disciplina->setLabel('Disciplina')->setRequired(true)>addFilter('StripTags')->addValidator('NotEmpty'); !!!!!!!!$submit = new Zend_Form_Element_Submit('submit'); !!!!!!!!$submit->setLabel('Entrar'); !!!!!!!!$submit->setAttrib('id', 'Entrar'); !!!!!!!!$this->addElements(array($disciplina,$submit)); !!!!!!!!//action e method !!!!!!!!$this->setAction('/professor/index')->setMethod('post'); !!!!} }

https://gist.github.com/1468947

Subforms
Tambm podemos criar subforms. Adicionando o cdigo abaixo ao mtodo init() do forms/Pessoa.php podemos visualizar um novo formulrio dentro do formulrio original. Os dados sero enviados juntamente com o formulrio principal.

$endereco = new Zend_Form_SubForm(); $endereco->addElements(array( ! ! new Zend_Form_Element_Text('cidade', array( ! ! 'required' ! => true, ! ! 'label' ! ! !=> 'Cidade:', ! ! 'filters' ! !=> array('StringTrim', 'StringToLower'), ! ! 'validators' => array( ! ! 'Alnum', ! ! array('Regex', ! ! ! ! false, ! ! ! ! array('/^[a-z][a-z0-9]{2,}$/')) ! ! ) ! ! )), ! ! new Zend_Form_Element_Text('estado', array( ! ! ! ! ! ! ! !'required' ! => true, ! ! ! ! ! ! ! !'label' ! ! !=> 'Estado:', ! ! ! ! ! ! ! !'filters' ! !=> array('StringTrim'), ! ! ! ! ! ! ! !'validators' => array( ! ! ! ! ! ! ! ! ! !'NotEmpty', ! ! ! ! ! ! ! ! ! !array('StringLength', false, array(6)) ! ! ! ! ! ! ! !) ! ! ! ! ! !)), ! ! ! !) ); $this->addSubForms(array('endereco' => $endereco));

https://gist.github.com/987377

Criando um CRUD
Vamos agora usar o que aprendemos para criar o CRUD (Create, Replace, Update, Delete) de um post. O primeiro passo criamos o controller PostController e as actions. Para isso podemos usar os comandos:
zf zf zf zf zf create create create create create controller Post action create Post action retrieve Post action update Post action delete Post

Agora vamos criar cdigo da primeira action, o retrieveAction(), que vai nos mostrar os posts cadastrados. O cdigo :

public function retrieveAction() { $posts = new Application_Model_Posts(); $this->view->posts = $posts->fetchAll(); }

E o arquivo views/scripts/post/retrieve.phtml:
<h1>Posts</h1> <a href="/post/create">Adicionar</a> <?php foreach($this->posts as $p) {?> " <h3><?php echo $p['title']; ?></h3> " <p><?php echo nl2br($p['description']); ?></p> " <p><a href="/post/update/id/<?php echo $p['id'];?>">Editar</ a></p> " <p><a href="/post/delete/id/<?php echo $p['id'];?>">Excluir</ a></p> <?php } ?>

https://gist.github.com/1335234

Outra mudana que podemos fazer na action indexAction() para que seja automaticamente redirecionado para o retrieve:
public function indexAction() { $this->_forward('retrieve'); }

Assim, vamos testar usando a url:


http://blog.local/post

Agora vamos criar o cdigo do createAction() para usarmos o formulrio e salvarmos um novo post:
public { " " " " " function createAction() $form = new Application_Form_Post(); $post = new Application_Model_Posts(); //tem dados if ($this->_request->isPost()) { " //form valido

" " " " "

" " " " " dados " " " " "

" " " " " " " " " }

" " " " "

if ($form->isValid($this->_request->getPost())) { " $id = $post->insert($form->getValues()); " $this->_redirect('post/retrieve'); }//form invalido else { // Mostra os erros e popula o form com os

" " $form->populate($form->getValues()); " } } $this->view->form = $form;

https://gist.github.com/1335245

E e o views/scripts/post/create/phtml:
<?php echo $this->form;?>

Vamos agora reutilizar o Application_Form_Post para realizarmos a atualizao de um post. Para isso criamos o seguinte cdigo no updateAction() :
public function updateAction() { " $form = new Application_Form_Post(); " $form->setAction('/post/update'); " $form->submit->setLabel('Alterar'); " $posts = new Application_Model_Posts();

" " " " " " " //tem dados " " if ($this->_request->isPost()) { " " " //form valido " " " if ($form->isValid($this->_request->getPost())) { " " " " $values = $form->getValues(); " " " " $posts->update($values, 'id = ' . $values['id']); " " " " $this->_redirect('post/retrieve'); " " " }//form invalido " " " else { // Mostra os erros e popula o form com os dados " " " " $form->populate($form->getValues()); " " " } " " } " " else { //no tem dados " " " $id = $this->_getParam('id'); " " " $post = $posts->fetchRow("id =$id")->toArray();

" " " }

" " "

" $form->populate($post); } $this->view->form = $form;

https://gist.github.com/1335264

O views/scripts/post/update.phtml exatamente igual ao create.phtml. Com esse cdigo podemos ver o re-aproveitamento de um formulrio, somente mudando alguns comportamentos. E o mtodo nal, o deleteAction:
public function deleteAction() { " $posts = new Application_Model_Posts(); " $id = $this->_getParam('id'); " $posts->delete("id = $id"); " $this->_redirect('post/retrieve'); }

" " " "

Desao
Fazer o CRUD das tabelas users e comments

Organizando a aplicao
Agora que j conhecemos alguns conceitos importantes do Zend Framework vamos organizar melhor nossa aplicao. O primeiro passo pensarmos na estrutura dos nossos controllers e no uxo da aplicao:

IndexController:indexAction Redirect

PostController:retrieveAction Link

AuthController:indexAction

Redirect

PostController:retrieveAction

O IndexController::indexAction vai somente nos direcionar para a action retrieve do controller PostController, que nos mostra todos os posts cadastrados na base de dados. Na view post/ retrieve.phtml vamos ter um link para a action index do AuthController, que vai ser responsvel pela autenticao, usando o Application_Form_Login criado anteriormente. Aps a autenticao ser feita com sucesso vamos retornar ao retrieveAction do PostController, onde vamos ter acesso aos outros mtodos do CRUD. Vamos ento alterar o mtodo indexAction do IndexController:
public function indexAction() { " $this->_redirect('/post/retrieve'); }

Vamos tambm adicionar o link para o AuthController no nosso arquivo post/retrieve.phtml:


<p><a href="/auth">Fazer login</a></p>

No prximo tpico iremos criar o AuthController para fazer a autenticao dos nossos usurios. Outro ponto que podemos melhorar a criao de um controlador base para a nossa aplicao, de onde todos os outros controladores (IndexController, PostController e AuthController) vo herdar. Isso uma prtica comum e muito til pois podemos criar mtodos que sero vistos por todos os controladores na nossa aplicao. Inicialmente vamos precisar criar um diretrio chamado Blog dentro do library e dentro dele um novo diretrio chamado Controller. Dentro deste vamos criar o Action.php. A estrutura deve car da seguinte forma:

O contedo do arquivo Action.php :


<?php class Blog_Controller_Action extends Zend_Controller_Action { }

Nos prximos captulos vamos adicionar contedos a este arquivo. Precisamos registrar na nossa aplicao o novo conjunto de classes. Para isso vamos adicionar o cdigo abaixo no Bootstrap.php:
/* Adiciona as classes do pacote Blog_ ao loader de classes * * @return void * @author Elton Minetto */

public function _initLoader() { " $loader = Zend_Loader_Autoloader::getInstance(); " $loader->registerNamespace('Blog_'); }

Agora precisamos mudar os nossos controllers para herdarem o Blog_Controller_Action:


class IndexController extends Blog_Controller_Action class PostController extends Blog_Controller_Action

Roteamento
Roteamento o processo de converter uma URL em uma ao a ser executada. A rota default traduz URLs no formato citado anteriormente. Rotas adicionais podem ser criadas, geralmente para disponibilizar URLs mais fceis de serem compreendidas ou mais curtas. Por exemplo, poderamos criar uma rota para que a URL atualizar/142 fosse mapeada da mesma forma que post/ update/id/142. Para fazer isso podemos adicionar as linhas abaixo no application.ini
;routes resources.router.routes.update.route = /atualizar/:id resources.router.routes.update.defaults.controller = post resources.router.routes.update.defaults.action = update resources.router.routes.excluir.route = /excluir/:id resources.router.routes.excluir.defaults.controller = post resources.router.routes.excluir.defaults.action = delete

Tambm podemos fazer de outra forma, criando um mtodo _initRoutes() no Bootstrap.php. Algo como:
/** * Inicializa as rotas * * @return void * @author Elton Minetto */

public function _initRoutes() { " $updateRoute = new Zend_Controller_Router_Route( " " 'atualizar/:id', " " array( " " " 'controller' => 'post', " " " 'action' => 'update' " " ) " ); " $deleteRoute = new Zend_Controller_Router_Route( " " 'excluir/:id', " " array( " " " 'controller' => 'post', " " " 'action' => 'delete' " " ) " ); " " $router = Zend_Controller_Front::getInstance()->getRouter(); " $router->addRoute('updateRoute', $updateRoute);" " $router->addRoute('deleteRoute', $deleteRoute);" }

https://gist.github.com/1469916

Podemos criar diversas rotas especiais, usando expresses regulares e outras opes avanadas. No site da documentao do framework existem diversos exemplos, mas na maioria das vezes as rotas simples como mostrada neste exemplo so sucientes

Autenticao
Nosso blog vai ter trs tipos de usurios, o visitante normal, um redator e um tipo especial, o administrador. Os administradores podem adicionar novos posts no blog, alter-los e exclu-los (o CRUD de Post que fizemos no captulo anterior). O redator vai poder adicionar e alterar posts, mas no exclu-los. Para isso precisamos determinar uma forma de identificar o usurio, para sabermos se ele vlido, e no prximo tpico iremos ver como controlar seu nvel de acesso (administrador ou redator). Iremos usar o formulrio Application_Form_Login criado

anteriormente, em conjunto com um componente do framework chamado Zend_Auth. O Zend_Auth fornece uma API para autenticao e inclui adaptadores para os cenrios de uso mais comuns: LDAP, banco de dados, HTTP, OpenID. E o desenvolvedor pode criar seus prprios adaptadores extendendo os j existentes. Vamos criar o AuthController usando o Zend Tool.
zf create controller Auth

O cdigo nal:
<?php class AuthController extends Blog_Controller_Action { !!!!public function init() !!!!{ !!!!!!!!/* Initialize action controller here */ !!!!} !!!!public function indexAction() !!!!{ !!!!!!!!//adiciona o formulario " " $form = new Application_Form_Login(); " " //verifica se tem dados enviados " " if ($this->_request->isPost()) { " " " $formData = $this->_request->getPost(); " " " //se o formulrio est vlido " " " if ($form->isValid($formData)) { " " " " //pega uma instancia e cria caso no exista " " " " $auth = Zend_Auth::getInstance(); " " " " //conexao com a base de dados " " " " $db = Zend_Registry::get('db'); " " " " " " senha " " " " " " " " antes " " " " $authAdapter = new Zend_Auth_Adapter_DbTable( " " " $db,//conexao com o banco " " " 'users', //nome da tabela " " " 'username', //campo com o login " " " 'password', //campo com a senha " " " 'MD5(?)' //tratamento a ser dado a de comparar " " ); " " //configura o usurio/senha

" " " " $authAdapter>setIdentity($formData['username'])>setCredential($formData['password']); " " " " //tenta fazer a autenticao " " " " $result = $auth->authenticate($authAdapter); " " " " //verifica o resultado " " " " $session = Zend_Registry::get('session'); " " " " switch ($result->getCode()) { " " " " " case Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND: " " " " " " $session->erro = 'Usurio invlido'; " " " " " " $form->populate($formData); " " " " " " break; " " " " " case Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID: " " " " " " $session->erro = 'Senha invlida'; " " " " " " $form->populate($formData); " " " " " " break; " " " " " case Zend_Auth_Result::SUCCESS: " " " " " " $data = $authAdapter>getResultRowObject(); " " " " " " $session->role = $data->role; // guarda a role do usurio " " " " " " $this->_redirect('/post/ retrieve'); " " " " " " break; " " " " " default: " " " " " " /** em caso de outro tipo de falhas **/ " " " " " " break; " " " " } " " " } " " " else { // Mostra os erros e popula o form com os dados " " " " $form->populate($formData); " " " } " " } " " $this->view->form = $form; !!!!}

https:// gist.github.com/ 1449550

O Zend_Auth simples de ser usado, como possvel ver no cdigo acima. Com poucas linhas congurada a forma de autenticao (com uma tabela do banco de dados) e faz-se a validao. Caso a validao tenha ocorrido com sucesso as credenciais do usurio so automaticamente armazenadas na sesso. Tambm armazenamos na sesso a role do usurio, para usarmos posteriormente. Precisamos alterar o cdigo da nossa viso, o arquivo views/ scripts/auth/index.phtml, adicionando o cdigo abaixo:
<?php echo $this->form;?>

Vamos aproveitar tambm e mudar o nosso layout, para mostrarmos uma opo para o usurio fazer logout do sistema. O arquivo layouts/scripts/layout.phtml cou da seguinte forma:
<html> <head> !!!!<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <h2>Blog do Minetto</h2> <?php //mensagens de erro $session = Zend_Registry::get('session'); if(isset($session->erro)) " echo "<p> $session->erro </p>"; " unset($session->erro); ?> <?php echo $this->layout()->content; ?> <?php //usuario logado? $auth = Zend_Auth::getInstance(); if ($auth->hasIdentity()) {" ?> " <p><a href="/auth/logout">Sair</a></p> " <?php } else { " ?> " <p><a href="/auth">Fazer login</a></p> " <?php }

?> <p>Copyleft @eminetto</p> </body> </html>

https:// gist.github.com/ 1449567

Vamos agora adicionar a funo de logout() no AuthController:


public function logoutAction() { " Zend_Auth::getInstance()->clearIdentity(); " $this->_redirect('/'); }

Como o layout agora controla se deve mostrar ou no o link para realizar o login podemos remover o link que colocamos no views/ scripts/post/retrieve.phtml (refatorar bom!)

Controle de acesso
Ns vimos anteriormente o uso do componente Zend_Auth. Este componente responsvel apenas pela autenticao dos usurios, sendo que ele no permite o controle de permisses aos recursos do aplicativo. Esse papel responsabilidade do componente Zend_Acl. ACL (Access Control List - lista de controle de acesso) uma soluo simples e exvel para realizar o controle do acesso a determinados recursos. Alguns conceitos so usados pelo Zend_Acl:

papel (role): um grupo de usurios recurso (resource): algo a ser protegido privilgio (privilege): o tipo de acesso exigido

O primeiro passo o planejamento dos tens citados acima. No nosso projeto, do blog, vamos usar trs roles:

visitante: pessoas que no zeram o login no sistema

redator: usurios que podem publicar e editar posts, mas no apag-los admin: usurios com todas as permisses de acesso

Vamos ter tambm trs recursos a proteger:


index: controlador IndexController post: controlador PostController auth: controlador AuthController

Os privilgios que iremos controlar so os mtodos dos controladores citados. O primeiro passo descrever os papis, recursos e privilgios no nosso arquivo de congurao, o application.ini:
;roles acl.roles.visitante = null acl.roles.redator = visitante acl.roles.admin = redator acl.resources[] = index acl.resources[] = post acl.resources[] = auth ;definir as acls no formato acl.permissao.role[] = controller.action acl.allow.visitante[] = index.index acl.allow.visitante[] = post.retrieve acl.allow.visitante[] = auth.index acl.allow.visitante[] = auth.logout acl.allow.redator[] = post.create acl.allow.redator[] = post.update acl.allow.admin[] = post.delete

https:// gist.github.com/ 1449742

Uma caracterstica interessante do Zend_Acl a possibilidade das roles terem herana. Da forma como conguramos o redator herda as conguraes do visitante e o admin herda as conguraes do redator. Isso facilita bastante a congurao. As linhas acl.resources[] e acl.allow.visitante[], por exemplo, vo ser transformadas em Arrays de objetos pelo Zend_Cong. Podemos

tambm usar acl.deny.permissao.role[] caso queiramos negar o acesso a determinado recurso. No nosso Bootstrap.php vamos adicionar as seguintes linhas de cdigo, que so responsveis por ler o arquivo de congurao e gerar as ACLs:
/** * inicializa a acl * * @return void * @author Elton Minetto **/ protected function _initAcl() { " $acl = new Zend_Acl; " $config = Zend_Registry::get('config'); " foreach($config->acl->roles as $role => $parent) { " " if($parent) " " " $acl->addRole(new Zend_Acl_Role($role), $parent); " " else " " " $acl->addRole(new Zend_Acl_Role($role)); " } " foreach($config->acl->resources as $r) { " " $acl->add(new Zend_Acl_Resource($r)); " } " if(isset($config->acl->allow)) { " " foreach($config->acl->allow as $role => $privilege) { " " " foreach($privilege as $p) { " " " " $privilege = explode('.', $p); " " " " $acl->allow($role, $privilege[0], $privilege[1]); " " " } " " } " } " if(isset($config->acl->deny)) { " " foreach($config->acl->deny as $role => $privilege) { " " " foreach($privilege as $p) { " " " " $privilege = explode('.', $p); " " " " $acl->deny($role, $privilege[0], $privilege[1]); " " " } " " } " } " Zend_Registry::set('acl',$acl); }

https:// gist.github.com/ 1449750

Agora vamos usar a nossa classe Blog_Controller_Action. Como sabemos que todos os controllers herdam dela vamos criar o mecanismo de autenticao/autorizao neste local. O cdigo do arquivo cou:
<?php class { " " " " " " " " " Blog_Controller_Action extends Zend_Controller_Action public function init() { " $session = Zend_Registry::get('session'); " //verifica ACL " if(Zend_Registry::isRegistered('acl')) { " " $request = $this->getRequest(); " " //pega o nome do modulo, controlador e action " " $controller = $request->getControllerName(); " " $action = $request->getActionName(); //monta o nome do resource e do privilege. exemplo: $resource = $controller; $privilege = $action; $auth = Zend_Auth::getInstance(); //se o usurio fez login usa a role que est na if($auth->hasIdentity()) { " $role = $session->role; } else { " $role = 'visitante'; } //faz a verificao da permisso $acl = Zend_Registry::get('acl'); if(!$acl->isAllowed($role, $resource, $privilege)) " " } $session->erro = 'ACL invlida'; $this->_redirect('/');

" " " default_index " " " " " " " " " " sesso " " " " " " " " " " " " " " " " " " { " " " " " " " " " } } " " " " " " " " " " " " " " }

https:// gist.github.com/ 1449759

Desta forma todos os nossos controllers conhecem o controle de acesso. Uma observao. Caso algum controller precise denir algo em seu mtodo init() necessrio sempre invocar tambm o init() da classe pai (Blog_Controller_Action), como no exemplo:
public function init() { parent::init(); $this->posts = new Application_Model_Posts(); }

"

Assim as ACLs so respeitadas. Vamos agora criar alguns usurios de teste na tabela, indicando qual o papel (redator, visitante ou admin) que cada usurio exerce no sistema. possvel fazer isso usando o phpMyAdmin, outra ferramenta grca ou com os comandos SQL abaixo:
INSERT INTO users (username, password, name, valid, ROLE) VALUES ('eminetto',md5('teste'),'Elton Minetto', 1, 'admin'); INSERT INTO users (username, password, name, valid, ROLE) VALUES ('steve',md5('teste'),'Steve Jobs', 1, 'redator'); INSERT INTO users (username, password, name, valid, ROLE) VALUES ('bill',md5('teste'),'Bill Gates', 1, 'visitante');

https:// gist.github.com/ 987391

Podemos assim fazer testes e vericar que o acesso aos mtodos controlado de maneira muito rpida e fcil. O uso de ACLs permite um controle fcil de ser desenvolvido e com grande versatilidade.

Navegao
O Zend Framework fornece um componente para facilitar a criao de menus, o Zend_Navigation. Podemos usar o Zend_Navigation para gerar facilmente menus e tens de navegao. Exemplo: No bootstrap adicionar:
/** * inicializa a navegao * * @return void * @author Elton Minetto **/ public function _initNavigation() { " /* " * navegacao " */ " $container = new Zend_Navigation(array( " array( " 'label' => 'Home', " " " 'controller' => 'post', " 'action' => 'retrieve', " ), " array( " 'label' => 'Adicionar Post', " 'controller' => 'post', " 'action' => 'create', " ), " array( " 'label' => 'Sair', " 'controller' => 'auth', " 'action' => 'logout', " ), " )); " Zend_Registry::set('Zend_Navigation', $container);" }

"

https:// gist.github.com/ 1449791

No layout (ou em alguma view) basta adicionar a seguinte linha:

<?php echo $this->navigation(); ?>

Podemos tambm integrar o Zend_Navigation com o Zend_Acl, para que o menu de opes seja renderizado de acordo com as permisses do usurio. Para isso vamos reescrever as linhas que adicionamos agora a pouco no Bootstrap (OBS: preciso vericar se elas esto aps a criao do Zend_Acl):
/** * inicializa a navegao * * @return void * @author Elton Minetto **/ public function _initNavigation() { " /* " * navegacao " */ " $container = new Zend_Navigation(array( " array( " 'label' => 'Home', " " 'controller' => 'post', " 'action' => 'retrieve', " " 'resource' => 'post', " " 'privilege' => 'retrieve' " ), " array( " 'label' => 'Adicionar Post', " 'controller' => 'post', " 'action' => 'create', " " 'resource' => 'post', " " 'privilege' => 'create' " ), " array( " 'label' => 'Sair', " 'controller' => 'auth', " 'action' => 'logout', " " 'resource' => 'auth', " " 'privilege' => 'logout' " ), " )); " } Zend_Registry::set('Zend_Navigation', $container);" "

https:// gist.github.com/ 1449909

E no nal do metodo init() do Blog_Controller_Action:


Zend_Layout::getMvcInstance() " ->getView() " ->navigation() " ->setAcl($acl) " ->setRole($role);

O Zend_Acl vai conversar com o Zend_Navigation e decidir quais opes do menu devem aparecer, dependendo da role do usurio. Esta uma das coisas legais do Zend Framework. Apesar de ser formado por uma srie de componentes que podem ser usados em separado, a maioria deles integra-se de uma maneira muito til.

Paginao
Usando o componente Zend_Paginator facilita uma das necessidades mais comuns em aplicaes web, a paginao de dados. O componente Zend_Paginator possibilita ao programador congurar uma srie de opes am de tornar a paginao mais intuitiva. Atualmente o Zend_Paginator nos permite paginar quatro tipos de dados:

Array DbSelect DbTableSelect Iterator

Vamos modicar nosso sistema de blog para que ele use paginao na pgina inicial.

Primeiro vamos fazer uma alterao no mtodo retrieveAction() do PostController.php. Vamos comentar a linha:
$result = $posts->fetchAll(); //pega todos os posts

e adicionar as seguintes:
//criando a paginaao Zend_Paginator::setDefaultScrollingStyle('Sliding'); ! ! ! ! ! ! ! ! ! ! ! ! Zend_View_Helper_PaginationControl::setDefaultViewPartial('partials/ paginator.phtml'); //manda o paginador usar os dados vindos do banco $paginator = Zend_Paginator::factory($posts->fetchAll()); //pagina atual. Se nao vier nenhuma pagina, mostra a primeira $currentPage = $this->_getParam('page', 1); //5 tens por pgina $paginator->setCurrentPageNumber($currentPage)>setItemCountPerPage(5); //manda para a view $this->view->data = $paginator;

https:// gist.github.com/ 987415

Neste momento apresentado o conceito de partials. Partials so trechos de cdigos de viso (html, js, css) que podem ser reutilizados por diversas views. Neste exemplo criado o tem que ir mostrar o nmero de pginas que o paginador gerou. Ele ser reutilizado em todas as pginas que precisarem de paginao. O cdigo do arquivo views/scripts/partials/paginator.phtml :
<?php if ($this->pageCount): ?> <div class="paginationControl"> <!-- Previous page link --> <?php if (isset($this->previous)): ?> <a href="<?php echo $this->url(array('page' => $this->previous)); ? >"> < Previous </a> | <?php else: ?> <span class="disabled">< Previous</span> | <?php endif; ?>

<!-- Numbered page links --> <?php foreach ($this->pagesInRange as $page): ?> <?php if ($page != $this->current): ?> <a href="<?php echo $this->url(array('page' => $page)); ?>"> <?php echo $page; ?> </a> | <?php else: ?> <?php echo $page; ?> | <?php endif; ?> <?php endforeach; ?> <!-- Next page link --> <?php if (isset($this->next)): ?> <a href="<?php echo $this->url(array('page' => $this->next)); ?>"> Next > </a> <?php else: ?> <span class="disabled">Next ></span> <?php endif; ?> </div> <?php endif; ?>

https:// gist.github.com/ 987416

E nalmente vamos mudar a viso para usar o nosso componente de paginao. O novo contedo do arquivo views/scripts/post/ retrieve.phtml :
<?php if (count($this->data) > 0): ?> " <?php foreach($this->data as $d):?> " " <h3><?php echo $d['title'];?></h3> " " <p><?php echo $d['description'];?></p> " " <a href="/post/update/id/<?php echo $d['id'];? >">Atualizar</a><br> " " <a href="/post/delete/id/<?php echo $d['id'];? >">Excluir</a><br> " <?php endforeach;?> " <?php echo $this->data;?> <?php endif;?> <a href="/post/create">Criar novo post</a>

https:// gist.github.com/ 1469762

Cache
A tcnica de cache muito usada para melhorar a performance de sites, sejam eles de grande trfego ou no. Teoricamente quase tudo pode ser armazenado em cache: resultados de consultas, imagens, arquivos css, arquivos js, trechos de cdigo html, etc. No Zend Framework o cache fornecido usando-se a classe Zend_Cache. O cacheamento fornecido ao programador atravs de frontends, enquanto que o armazenamento em si feito com classes de backends. Isso torna o processo exvel no quesito armazenamento e fcil para a manipulao. O frontend mais usado o Core, padro do Framework. Este pode ser extendido para atender as necessidades do usurio, mas na maioria das vezes isso no necessrio. Os principais backends disponveis so:

File: os dados do cache so armazenados em arquivos no sistema operacional Sqlite: salvos em um banco de dados Sqlite Memcached: os dados sero salvos no Memcached, um servidor especco para cache, usado por grandes arquiteturas como o Facebook Apc: usa o cache em memria fornecido pela extenso APC (Alternative PHP Cache) do PHP Xcache: usa a extenso do PHP, Xcache para armazenar os dados em memria ZendPlatform: usa a soluo proprietria da Zend para armazenar o cache

Vamos ver alguns exemplos de uso. O primeiro passo criarmos entradas no nosso arquivo de conguraes, no application.ini:
;cache cache.compression = true

cache.frontend.lifetime = 7200 cache.frontend.automatic_serialization = true ;adaptador: File, Memcached ; APC cache.backend.adapter = File ;cache em memcached ;cache.backend.options.srv1.host = localhost ;cache.backend.options.srv1.port = 11211 ;cache.backend.options.srv1.persistent = true ;cache em arquivo cache.backend.options.cache_dir = "/tmp"

https:// gist.github.com/ 1469557

Agora vamos adicionar as seguintes linhas ao Bootstrap.php:


/** * Inicializa o cache * * @return void * @author Elton Minetto */ public function _initCache() { " $config = Zend_Registry::get('config')->cache; " $frontendOptions = array( " 'lifetime' => $config->frontend->lifetime, // tempo de vida " 'automatic_serialization' => $config->frontend>automatic_serialization " " ); " $backendOptions = $config->backend->options->toArray(); " " // criando uma instancia do cache $cache = Zend_Cache::factory('Core',//frontend $config->backend->adapter, //backend $frontendOptions, $backendOptions); /* * Salva o cache no Registry para ser usado posteriormente

" "

" " " " " " }

*/ Zend_Registry::set('cache', $cache); /* * cache para metadados das tabelas */ Zend_Db_Table_Abstract::setDefaultMetadataCache($cache);

https:// gist.github.com/ 1469560

Agora vamos alterar o retrieveAction do PostController.php para usar o cache. Onde havia estas linhas:
//busca os posts $posts = new Application_Model_Posts; $this->view->data = $posts->fetchAll();

Vamos substitu-las por:


$cache = Zend_Registry::get('cache'); //busca os posts $posts = new Application_Model_Posts; //cria um novo objeto Posts //verifica se j est no cache o resultado if(!$result = $cache->load('cachePosts')) { " //no existe no cache, processar e salvar " $result = $posts->fetchAll();//pega todos os posts " $cache->save($result, 'cachePosts'); } $this->view->data = $result;

https:// gist.github.com/ 1469573

Desta forma a consulta no ser realizada novamente enquanto o cache no expire. No exemplo est congurado para durar 2 horas (congurado no application.ini). Podemos indicar tambm o tempo de vida de um tem em especco (em segundos):
$cache->save($result, 'cachePosts', array(), 60); //1 min

O terceiro parmetro, o array(), usado para atribuir uma tag para a varivel do cache. Tags servem para agruparmos os tens do cache, assim ca mais fcil manipularmos conjuntos de tens. A qualquer momento podemos remover um tem do cache:
$result = $cache->remove('cachePosts');

Ou remover todos os tens do cache:


// limpa todos os registros $cache->clean(Zend_Cache::CLEANING_MODE_ALL); // limpa somente os que esto vencidos $cache->clean(Zend_Cache::CLEANING_MODE_OLD);

Tambm podemos usar o recurso de Cache para acelerar a renderizao de formulrios. Usar o Zend_Form para gerar formulrios aumenta a produtividade do desenvolvimento, mas seu desempenho pode deixar a desejar quando comparado com formulrios gerados a moda antiga, direto em HTML. Usando-se cache podemos melhorar isso. Exemplo:
$cache = Zend_Registry::get('cache'); if(!$form = $cache->load('Application_Form_Login')) { ! ! ! ! $form = new Application_Form_Login; ! ! ! ! //salva o form renderizado no cache ! ! ! ! $cache->save($form->render(), 'Application_Form_Login'); } $this->view->form = $form;

https:// gist.github.com/ 1469589

Outros usos do Zend_Cache:


/* !* cache para metadados das tabelas. Usado pelos Models para salvar os detalhes da tabela (campos,chaves) */ Zend_Db_Table_Abstract::setDefaultMetadataCache($cache); /*

!* Configura o cache para a traducao !*/ Zend_Translate::setCache($cache); /* coloca o zend_date e o zend_locale em cache */ Zend_Locale::setCache($cache); Zend_Date::setOptions(array('cache' => $cache));

https:// gist.github.com/ 987409

Tambm possvel usar o Zend_Cache para armazenar as sesses, algo til quando usado para salvar as sesses de usurios, se usado com Memcached por exemplo (salvar sesses em cache usando o Backend File no muita vantagem, mas com Memcached ou APC muito mais rpido). Assim possvel usar vrios servidores para guardar a informao e ela ca independente do servidor Web (no caso do Memcached). Para isso preciso implementar a interface Zend_Session_SaveHandler_Interface, conforme o exemplo abaixo:
<?php class Blog_Session_Handler implements Zend_Session_SaveHandler_Interface{ !!!!!!!!private $maxlifetime = 3600; !!!!!!!!public $cache = ''; !!!!!!!! !!!!!!!!public function __construct($cacheHandler) { !!!!!!!!!!!!!!!!$this->cache = $cacheHandler; !!!!!!!!} !!!!!!!!public function open($save_path, $name) { !!!!!!!!!!!!!!!!return true; !!!!!!!!} !!!!!!!!public function close() { !!!!!!!!!!!!!!!!return true; !!!!!!!!} !!!!!!!!public function read($id) { !!!!!!!!!!!!!!!!if(!($data = $this->cache->load($id))) { !!!!!!!!!!!!!!!!!!!!!!!!return ''; !!!!!!!!!!!!!!!!} !!!!!!!!!!!!!!!!else { !!!!!!!!!!!!!!!!!!!!!!!!return $data;

!!!!!!!!!!!!!!!!} !!!!!!!!} !!!!!!!!public function write($id, $sessionData) { !!!!!!!!!!!!!!!!$this->cache->save($sessionData, $id, array(), $this>maxlifetime); !!!!!!!!!!!!!!!!return true; !!!!!!!!} !!!!!!!!public function destroy($id) { !!!!!!!!!!!!!!!!$this->cache->remove($id); !!!!!!!!!!!!!!!!return true; !!!!!!!!} !!!!!!!!public function gc($notusedformemcache) { !!!!!!!!!!!!!!!!return true; !!!!!!!!} }

https:// gist.github.com/ 1469654

Aps salvar contedo acima no arquivo library/Blog/Session/ Handler.php necessrio congurar o handler da sesso, no bootstrap, antes da inicializao da sesso :
Zend_Session::setSaveHandler(new Blog_Session_Handler($cache));

Tradues
Nos exemplos anteriores vimos a utilizao dos validadores do Zend Framework para vericar se os campos obrigatrios de um formulrio foram digitados ou se possuam valores corretos. Mas as mensagens de erro e validao so apresentadas por padro na lngua inglesa. Para facilitar o uso das mensagens em outras lnguas vamos usar o componente Zend_Translate. Para fazer uso do componente vamos inicialmente criar um diretrio no projeto onde iremos armazenar os arquivos das tradues. Vamos chamar este diretrio de application/languages. Vamos adicionar as linhas abaixo no application.ini:
resources.locale.default = "pt_BR"

resources.translate.adapter = "csv" resources.translate.data = APPLICATION_PATH "/languages"

E no Bootstrap.php vamos criar o mtodo _initTranslate:


/** * Inicializa o translate * * @return void * @author Elton Minetto */ public function _initTranslate() { " $config = Zend_Registry::get('config'); " $translate = $config->resources->translate; " $locale = $config->resources->locale; " $zend_translate = new Zend_Translate($translate->adapter, $translate->data, $locale->default); " Zend_Registry::set('Zend_Translate', $zend_translate); }

Nas linhas acima criamos um objeto Zend_Translate, indicando que o formato do arquivo CSV e a linguagem padro a pt_BR (portugus Brasil). Outros formatos so permitidos: Array, ini, gettext, tbx, etc. O objeto tambm registrado pelo Bootstrap usando o Zend_Registry, facilitando sua utilizao no restante do projeto. O arquivo de tradues inicial cou da seguinte forma:
isEmpty;O campo deve ser preenchido stringLengthTooShort;O valor do campo deve ter no minimo %min% caracteres stringLengthTooLong;O valor do campo deve ter no mximo %max% caracteres notSame;Os valores fornecidos so diferentes missingToken;Nenhuma senha foi fornecida emailAddressInvalid;Endereo de e-mail invlido hostnameInvalidHostname;Endereo invlido notDigits;Valor invlido hostnameUnknownTld;'%value%' um domnio desconhecido hostnameLocalNameNotAllowed;'%value%' um domnio no permitido emailAddressInvalidHostname;'%value%' no um email invlido emailAddressInvalidFormat;'%value%' no um email invlido dateInvalid;Data invlida

https:// gist.github.com/ 987413

O formato do arquivo : chave;Traduo. Mais informaes sobre as mensagens de validao podem ser encontradas neste link:
http://framework.zend.com/manual/en/zend.validate.messages.html

Tambm podemos usar o Zend_Translate para internacionalizar todas as mensagens do sistema. Por exemplo, na viso views/ scritps/post/create.phtml usamos o seguinte cdigo:
<h2> <?php echo Zend_Registry::get('Zend_Translate')->_('Novo Post');?> </h2>

Caso precisemos alterar o sistema para ingls (mudando o parmetro pt_BR para en_US no application.ini), o framework ir procurar no arquivo application/languages/en_US.csv a linha:
Novo Post;New post

Caso esta linha no exista o texto Novo Post ser apresentado, caso contrrio ir apresentar o texto New post. Usando o Zend_Translate muito fcil criar aplicativos para mltiplas lnguas.

Enviando e-mails
Enviar e-mails uma funo recorrente em diversos tipos de aplicao Web. Neste tpico apresentado um controlador com alguns exemplos de como enviar e-mails usando o componente Zend_Mail.
<?php class EmailController extends Zend_Controller_Action { ! ! ! ! //configurao do exemplo ! ! ! ! private $smtp = 'smtp.gmail.com';

! ! ! ! private $conta = 'eminetto@gmail.com'; ! ! ! ! private $senha = 'senha'; ! ! ! ! private $de = 'eminetto@gmail.com'; ! ! ! ! private $para = 'eminetto@coderockr.com'; ! ! ! ! ! ! ! ! //envio de e-mail texto ! ! ! ! public function indexAction() { ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! $assunto = "Teste de envio de email "; ! ! ! ! ! ! ! ! $mensagem = "Isso apenas um teste de envio utilizando o Zend_Mail()."; ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! try { $config ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! );

= array ( 'auth' => 'login', 'username' => $this->conta, 'password' => $this->senha, 'ssl' => 'ssl', 'port' => '465'

! ! ! ! ! ! ! ! $mailTransport = new Zend_Mail_Transport_Smtp($this>smtp, $config); ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! $mail = new Zend_Mail('UTF-8'); $mail->setFrom($this->de); $mail->addTo($this->para); $mail->setBodyText($mensagem); $mail->setSubject($assunto); $mail->send($mailTransport);

! ! ! ! ! ! ! ! echo "Email enviado com SUCESSSO!"; ! ! ! ! ! ! ! ! } catch (Exception $e){ ! ! ! ! ! ! ! ! ! ! ! ! echo ($e->getMessage()); ! ! ! ! ! ! ! ! } ! ! ! ! ! ! ! ! exit; ! ! ! ! } ! ! ! ! ! ! ! ! //envio de e-mail html ! ! ! ! public function htmlAction() { ! ! ! ! ! ! ! ! $assunto = "Teste de envio de email em HTML"; ! ! ! ! ! ! ! ! $mensagem = "Isso apenas um teste de envio utilizando o <b>Zend_Mail()</b>.<br><br>At mais, <br>Elton Minetto<br><i>Coderockr</i>"; ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! try ! ! ! ! ! ! { ! ! $config = array ( ! ! ! ! ! ! 'auth' => 'login', ! ! ! ! ! ! 'username' => $this->conta,

! ! ! !

! ! ! !

! ! ! !

! ! ! !

! ! ! !

! ! ! !

! ! ! !

! ! ! !

! ! ! !

! ! ! !

! ! ! !

! ! ! !

! ! ! ! 'password' => $this->senha, ! ! ! ! 'ssl' => 'ssl', ! ! ! ! 'port' => '465' );

! ! ! ! ! ! ! ! $mailTransport = new Zend_Mail_Transport_Smtp($this>smtp, $config); ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! } ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! $mail = new Zend_Mail('UTF-8'); $mail->setFrom($this->de); $mail->addTo($this->para); $mail->setBodyHtml($mensagem); $mail->setSubject($assunto); $mail->send($mailTransport); echo "Email enviado com SUCESSSO!"; } catch (Exception $e){ ! ! ! ! echo ($e->getMessage()); } exit;

//envio de e-mail com anexo public function anexoAction() { ! ! ! ! /** ! ! ! ! * verifica se o formulrio foi enviado ! ! ! ! */ ! ! ! ! if($_POST) {

! ! ! ! ! ! ! ! ! ! ! ! /** ! ! ! ! ! ! ! ! ! ! ! ! * Recebe os campos do formulrio ! ! ! ! ! ! ! ! ! ! ! ! */ ! ! ! ! ! ! ! ! ! ! ! ! $arqTmp = $_FILES["file"]["tmp_name"]; ! ! ! ! ! ! ! ! ! ! ! ! $arqName =$_FILES["file"]["name"]; ! ! ! ! ! ! ! ! ! ! ! ! $arqType = $_FILES["file"]["type"]; ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! $assunto = "Teste de envio de email com Anexo"; ! ! ! ! ! ! ! ! ! ! ! ! $mensagem = "Isso apenas um teste de envio utilizando o <b>Zend_Mail()</b>.<br><br>At mais, <br>Elton Minetto<br><i>Coderockr</i>"; ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! try ! ! ! ! ! ! ! ! ! ! ! ! { ! ! ! ! ! !

! ! ! ! ! !

$config ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !

= array ( 'auth' => 'login', 'username' => $this->conta, 'password' => $this->senha, 'ssl' => 'ssl', 'port' => '465'

! ! ! ! ! ! ! ! ! ! ! ! ); ! ! ! ! ! ! ! ! ! ! ! ! $mailTransport = new Zend_Mail_Transport_Smtp($this->smtp, $config); ! ! ! ! ! ! ! ! ! ! ! ! $mail = new Zend_Mail('UTF-8'); ! ! ! ! ! ! ! ! ! ! ! ! $mail->setFrom($this->de); ! ! ! ! ! ! ! ! ! ! ! ! $mail->addTo($this->para); ! ! ! ! ! ! ! ! ! ! ! ! $mail->setBodyHtml($mensagem); ! ! ! ! ! ! ! ! ! ! ! ! $mail->setSubject($assunto); ! ! ! ! ! ! ! ! ! ! ! ! $mail>createAttachment(file_get_contents($arqTmp), $arqType, Zend_Mime::DISPOSITION_INLINE, Zend_Mime::ENCODING_BASE64, $arqName); ! ! ! ! ! ! ! ! ! ! ! ! $mail->send($mailTransport); ! ! ! ! ! ! ! } ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! } ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! } ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! echo "Email enviado com SUCESSSO!"; } catch (Exception $e){ ! ! ! ! echo ($e->getMessage()); } ! ! ! ! ! ! ! !

https:// gist.github.com/ 987420

Foi criada uma viso para mostrar o formulrio de envio do arquivo. views/scripts/email/anexo.phtml:
<form method="post" enctype="multipart/form-data" name="form" action="anexo"> Arquivo: <input type="file" name="file" size="30" /> <br /> <input name="Enviar" type="submit" id="Enviar" value="Enviar" /> </form>

https:// gist.github.com/ 987421

Com algumas alteraes no exemplo acima possvel adapt-lo ao seu projeto

Diagnstico da aplicao
O Zend Framework fornece algumas ferramentas para facilitar a localizao de bugs e erros nos sistemas desenvolvidos. Uma destas ferramentas o Zend_Debug. O seu funcionamento simples:
Zend_Debug::dump($var);

Zend_log
Outra ferramenta o Zend_Log. Com ele possvel realizar logs em diversos backends, tais como arquivos e bancos de dados. Vamos criar um log em nosso bootstrap para podermos usar em qualquer parte do projeto:
/** * inicializa o log * * @return void * @author Elton Minetto **/ public function _initLog() { " $writer = new Zend_Log_Writer_Stream('/tmp/zf_log.txt'); " $log = new Zend_Log($writer); " Zend_Registry::set('log', $log); }

Agora podemos gerar logs nos nossos controllers ou models, usando:


$log = Zend_Registry::get(log); $log->log(Mensagem a ser salva, Zend_Log::INFO);

O segundo parmetro da funo log() a prioridade da mensagem. As opes disponveis so:

Nome Zend_L og::EM ERG

Uso Emerg ncia: sistema no pode ser usado Alerta: ao deve ser tomada Crtico

Zend_L og::AL ERT

Zend_L og::CRI T Zend_L og::ER R Zend_L og::WA RN Zend_L og::NO TICE Zend_L og::INF O Zend_L og::DE BUG

Erro

Aviso

Observ aes Informa tivo Mensa gens de debug

Para cada prioridade existe um mtodo especco do objeto Zend_Log. Ento as duas linhas abaixo tem a mesma funo:
$log->log(Erro crtico,Zend_Log::CRIT); $log->crit(Erro crtico)

Alm de salvar o log em arquivos podemos usar outros formatos como o Zend_Log_Writer_Db (salva em bancos de dados) e o

Zend_Log_Writer_Firebug( envia a mensagem para ser mostrada pelo Firebug/FirePHP). No exemplo abaixo criamos o log usando o banco SQLite e arquivos:
/** * inicializa o log * * @return void * @author Elton Minetto **/ public function _initLog() { " $writer = new Zend_Log_Writer_Stream('/tmp/zf_log.txt'); " $db = Zend_Db::factory("pdo_sqlite", array('dbname'=>'/tmp/ zf_log.db')); " $columnMapping = array('pri' => 'priority', 'msg' => 'message'); " $dbWriter = new Zend_Log_Writer_Db($db, 'log', $columnMapping); " $log = new Zend_Log(); " $log->addWriter($writer); " $log->addWriter($dbWriter); " Zend_Registry::set('log', $log); }

necessrio criar o banco de dados caso este no exista:


sqlite3 zf_log.db create table log(pri int, msg text);

Zend_Db_Proler
O Zend Framework possui um componente chamado Zend_Db_Proler que nos permite realizar o proling dos acessos ao banco que pode ser utilizado em conjunto com o componente Zend_Db_Proler_Firebug. Primeiramente, preciso ter os complementos do Firefox Firebug (https://addons.mozilla.org/pt-BR/refox/addon/1843) e FirePHP (http://www.rephp.org/) instalados, ou seja, s possvel usar este recurso com o Firefox (no z testes com as verses do Firebug para Chrome, ento no sei como essa feature se comporta neste navegador).

preciso tambm adicionar as linhas abaixo no Bootstrap, no mtodo _initDb():


/** * Inicializa o banco de dados. Somente necessrio se desejado salvar a conexo no Registry * * @return void * @author Elton Minetto */ public function _initDb() { " $db = $this->getPluginResource('db')->getDbAdapter(); " // Configuring Profiler " $profiler = new Zend_Db_Profiler_Firebug('db-profiling'); " $profiler->setEnabled(true); " $db->setProfiler($profiler); " Zend_Db_Table::setDefaultAdapter($db); " Zend_Registry::set('db', $db); }

O resultado pode ser visto na imagem abaixo

Todas as consultas SQL que foram geradas pela pgina corrente so apresentadas no console do Firebug. Com isso fcil vericar quais consultas esto sendo executadas, quanto tempo demoraram e quantas linhas foram retornadas. Essas informaes so de extrema utilidade para realizar uma melhoria de performance das pginas baseadas em resultados vindos de bancos de dados.

Concluso
Certamente no consegui aqui englobar todas as funcionalidades do Zend Framework, mas esse no era exatamente o objetivo deste livro. A idia aqui era apresentar as principais caractersticas e como us-las em uma aplicao comum e espero ter atingido esse modesto objetivo. Uma das vantagens de ser um e-book que esse livro pode ser vivo, coisa que mais difcil para um livro impresso. Todos os trechos de cdigos do PDF possuem links para uma verso online, o que facilita a cpia para o seu editor de programao favorito, mas que principalmente facilita alguma possvel correo que venha a acontecer. Ento acompanhe o site ocial deste livro, o http://www.zfnapratica.com.br para acompanhar qualquer melhoria ou correo nos cdigos ou textos. E caso tenha alguma sugesto caria feliz em receb-la e publicar no site. Meus dados de contato esto na introduo deste livro. isso. Happy coding para voc!