Você está na página 1de 67

Sobre o Autor

Elton Luís Minetto possui graduação em Ciência de Computação


pela Unochapecó e especialização em Ciência da Computação
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 é sócio 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
Introdução!..............................................................5
Instalando o Zend Framework!.............................6
Definindo o projeto!...............................................7
Modelagem!................................................................................7

Estrutura do projeto !.................................................................9

Configurando o Apache!...........................................................9

Bootstrap!.............................................................10
Controladores!......................................................13
Modelos!................................................................14
Trabalhando com modelos e queries!...................................17

Layout e visões!...................................................20
Formulários!.........................................................23
Enviando arquivos!.................................................................26

Herança de formulários !.........................................................29

Subforms !................................................................................30

Criando um CRUD!...............................................31
Desafio !....................................................................................34

Organizando a aplicação!....................................34
Roteamento!.........................................................37
Autenticação!........................................................38
Controle de acesso!.............................................42
Navegação!...........................................................47
Paginação!............................................................49
Cache!...................................................................52
Traduções!............................................................57
Enviando e-mails!.................................................59
Diagnóstico da aplicação!...................................63
Zend_log!..................................................................................63

Zend_Db_Profiler!....................................................................65

Conclusão!............................................................67
Introdução

Como a idéia deste livro é ir direto ao ponto, vou fazer isso já na


introdução.
A idéia desse livro não é explicar a teoria e filosofia do PHP, da
orientação 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 Profissional. Alexandre Altair de Melo / Mauricio G. F.
Nascimento. Editora Novatec
• PHP Programando com Orientação a Objetos. Pablo
Dall’Oglio. Editora Novatec
• Zend Framework Componentes Poderosos para PHP. Flávio
Gomes da Silva Lisboa. Editora Novatec
• Zend Framework em Ação. Rob Allen, Nick Lo, Steven
Brown. Editora Alta Books.
Os três primeiros são escritos por autores brasileiros e são livros
de grande importância e didática. O último é um clássico e
também 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 três
ou quatro anos, então é algo que venho testando e alterando
continuamente.
Esta é a segunda edição deste e-book. Nesta edição procurei
fazer uma atualização nos códigos e melhoria na explicação 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 é verificar os seus requisitos básicos: 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 configuração do Apache basta adicionar as linhas
abaixo, ou alterá-las para refletir 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 módulo que


permite a reescrita de URLs (mais exemplos nos próximos
tópicos) e permite o uso de configurações em arquivos especiais.

Agora basta fazer o download do framework, no site

http://framework.zend.com

No momento da escrita deste livro a versão mais atual era a


1.11.11. No site é possível escolher entre três opções para
download: a versão com o Zend Server, a versão Full e a versão
Minimal do framework. A primeira é indicada se você quer a
solução completa, com um servidor Apache e o MySQL já
configurados. A versão full possui, além do framework,
documentação, testes e demos. E a versão minimal é formada
apenas pelo framework. Geralmente a versão minimal é a mais
indicada.
Depois de descompactar o arquivo é possível visualizar a seguinte
estrutura (para a versão Minimal):

bin/ – scripts para a criação de projetos


LICENSE.txt - uma cópia da licença usada pelo framework
README.txt - instruções sobre instalação e documentação
VERSION.txt – texto sobre a versão do framework
library/ - neste diretório encontra-se o framework
INSTALL.txt - instruções de instalação
O diretório library deve ser copiado para o diretório htdocs de seu
servidor Apache. E pronto! O Zend Framework está pronto para
uso.

Definindo o projeto
Na minha opinião 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 construção de um aplicativo: um
blog.
Mas um blog? Por alguns motivos:
• é um problema fácil de se entender. Todo mundo sabe como
um blog funciona, seus requisitos e funcionalidades. Então a
fase de requisitos do projeto é fácil de completar
• um blog apresenta um grande número de funcionalidades
comuns a vários outros sites, como módulos, controle de
acesso e permissões, upload de arquivos, tratamento de
formulários, cache, traduções, integração com serviços
externos, etc.
• a grande maioria dos frameworks possui um exemplo “como
desenvolver um blog usando X”, então fica mais fácil para
comparação se você já estudou algum outro framework
como CakePHP, CodeIgniter ou mesmo Ruby on Rails

Modelagem

Agora que o convenci (ou não) 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, é possível 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 geração de projetos do Zend


Framework.
No diretório bin do framework existem os arquivo zf.bat (Windows)
e zf.sh (Linux/Mac OS X). É preciso que este arquivo e o
executável do PHP estejam no caminho dos executáveis (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 diretório blog foi criado com o conteúdo:

application - diretório da aplicação


Bootstrap.php - bootstrap da aplicação
configs - arquivos de configuração
controllers - controladores
models - modelos
views - visões
docs - documentações
library - aqui devemos copiar o framework
public - diretório de arquivos públicos
tests - testes unitários

Configurando o Apache
Vamos também configurar um VirtualHost no Apache para facilitar
os testes da aplicação. 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>

É necessário alterar os caminhos nas opções DocumentRoot e


Directory para refletirem o caminho correto em sua máquina.
É preciso também alterar o arquivo hosts do sistema operacional
para adicionar o endereço 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 é responsável por receber todas as requisições,
configurar o necessário (por exemplo: sessões, conexão com
banco de dados, cache, etc) e invocar o controlador especificado
pela URL que o usuário solicitou. Vou tentar explicar isso na forma
de uma imagem:

O usuário faz uma requisição ao Apache, que invoca o Bootstrap


(na imagem é o index.php). Este por sua vez faz a configuração
necessária e passa a execução para o controlador. O controlador
faz seu trabalho específico, podendo usar códigos contidos nos
modelos e formatar visões que serão mostradas ao usuário. Ao
final do processo do controlador, o Bootstrap volta a assumir e
finaliza a requisição.
Esta forma como o Zend Framework trabalha é muito interessante
pois nos permite diversas flexibilidades e configurações. Se
determinada configuração ou variável deve ser acessível a todos
os pontos de nossa aplicação (controladores, modelos e visões)
ela pode ser escrita no Bootstrap, pois sabemos que toda
execução irá obrigatoriamente passar por ela. Outra vantagem é
que se caso ocorra alguma exceção (Exceptions da linguagem
PHP) que não 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 instância da classe Zend_Application que usa
a classe Bootstrap contida no Bootstrap.php. Ao ser inicializada, a
aplicação irá executar todos os métodos 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 sessão
*
* @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 necessário se desejado
salvar a conexão 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 próximos tópicos vamos adicionando ítens ao Bootstrap.
Um novo conceito apresentado no código acima é o
Zend_Registry. O registro é uma forma de armazenarmos objetos
ou variáveis para que estes estejam acessíveis em toda a
aplicação. É um mecanismo elegante para substituir o uso de
variáveis 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 usuário 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


módulo default (que é o módulo padrão, caso exista) e tentar
invocar um método chamado showAction (a action) passando um
parâmetro chamado id, com valor 1.

O segundo link vai acessar o controlador IndexController dentro


do módulo admin (que é especificado na url) e tentar invocar um
método chamado showAction (a action) passando um parâmetro
chamado id, com valor 1.

Todos os controladores são 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

e
application/modules/admin/controllers/IndexController.php

O conteúdo do primeiro seria:


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

https://gist.github.com/987343

e o conteúdo 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 não está dentro de


modules/default pois este é o módulo padrão, não sendo
necessário criar desta forma caso estejamos usando apenas um
módulo. Se estivermos usando mais de um módulo é
recomendado criarmos o diretório, para ajudar na organização.
Algumas observações sobre os códigos. A função showAction()
deve ter o sufixo Action ou não será acessível ao usuário. Isto é
uma forma de proteção do seu código.
A classe Admin_IndexController indica que ela pertence ao
módulo admin e é obrigatório ser definida desta forma. A classe
IndexController não precisa indicar o nome do módulo pois o
módulo default é o principal.

Modelos
Antes de iniciarmos a criação dos controladores e das visões
precisamos criar a primeira camada da nossa aplicação MVC: os
modelos. Para isso deve-se criar um arquivo para cada tabela e
estes devem ser armazenados no diretório models. Todos os
modelos são classes PHP que extendem a classe
Zend_Db_Table_Abstract.
O primeiro passo é configurarmos 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 comentários e que cada comentário pertence a um
post (relacionamento um para muitos). No modelo Posts
indicamos a relação das tabelas que dependem dela, usando o
código:

protected $_dependentTables = array('Comments'); 

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


código:

 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 comentários. Por exemplo, podemos usar um
código similar ao abaixo, em um controlador, para recuperar os
comentários (vamos ver mais exemplos sobre o uso dos models e
dos controllers nos próximos tópicos)

//cria uma instância do modelo Posts


$posts = new Application_Model_Posts;
//busca detalhes do post com id = 1
$post = $posts->fetchRow("id = 1");
//busca todos os comentários deste post
$comments = $post->findDependentRowset('Comments');

Também é possível realizar o processo inverso. Digamos que eu


precise buscar os dados do post relacionado a um determinado
comentário:

//cria uma instância do modelo Comments


$comments = new Application_Model_Comments;
//busca detalhes do comentário com id = 1
$comment = $comments->fetchRow('id = 1');
//busca os dados do post relacionado a este comentário
$post = $comment->findParentRow('Posts');

O framework também fornece o suporte a relacionamentos


“muitos para muitos”, que não faz parte do nosso exemplo, mas
p o d e s e r v i s t o n a d o c u m e n t a ç ã o o fi c i a l ( m é t o d o
findManyToManyRowset):

http://framework.zend.com/manual/en/zend.db.table.relationships.html

Trabalhando com modelos e queries

O Zend Framework fornece três 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' => 'Título 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 título do post',
);
$posts->update($data, "id = $id"); //update do post com id específico

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 código SQL, e sim
utilizando objetos.
O construtor do Zend_Db_Select necessita uma conexão com um
banco de dados. Podemos buscar a conexão 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 inserção 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 seleção de campos e cláusula 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 seleção de campos e cláusula 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 é possível imprimir a consulta que foi
gerada. Útil para fins 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 visões
No contexto de uma aplicação desenvolvida com o Zend
Framework, uma visão é uma porção de código que será
visualizada pelo usuário. 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 usuário, através da visão. Um arquivo de visão
nada mais é do que um arquivo PHP com a extensão .phtml e cuja
função básica é imprimir (usando echo por exemplo) os dados
enviados pelo controlador. No nosso exemplo, vamos analisar o
código do controlador IndexController, cujo conteúdo está no
arquivo
application/controllers/IndexController.php

<?php
class IndexController extends Zend_Controller_Action {
   
    public function indexAction() {
        //cria uma variável a ser mostrada na view
        $this->view->msg = 'Hello!';
    }
}

https://gist.github.com/987360

Vamos analisar o código. Na linha $this->view->msg = 'Hello!'; o


controlador está salvando para a visão uma variável chamada
msg, com o conteúdo ‘Hello!’. Ao final da execução do método
indexAction() a classe irá tentar encontrar um arquivo de visão,
chamado index.phtml (este é um comportamento herdado da
classe Zend_Controller_Action) em um diretório específico, o

views/scripts/index/index.phtml

Todos os arquivos de visão do controlador IndexController devem


ser criados no diretório index dentro do views/scripts.
O conteúdo 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 páginas iremos ter um título, uma imagem e um


rodapé, com informações sobre o autor, copyright, etc. A única
informação que irá mudar é o conteúdo das páginas. Na página
inicial teremos os últimos posts do blog, opções de incluir e
excluir, posts, etc. Mas o cabeçalho e o rodapé permanecem os
mesmos. Para facilitar este tipo de construção 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 diretório do projeto:
application/layouts/scripts/layout.phtml

Seu conteúdo é:
<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 conteúdo da página
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 conteúdo das visões sendo executadas. No


exemplo anterior, o conteúdo da visão views/scripts/index/
index.phtml é gerada por esta linha.
No arquivo default.phtml é onde deve ser adicionada toda a parte
de CSS, e onde iríamos colocar nosso cabeçalho e rodapé para
ser apresentado por toda a aplicação.

O resultado pode ser visto ao acessar a URL

http://blog.local/
Uma observação. Se não especificarmos qual é o controlador na
URL o Bootstrap vai automaticamente procurar o controlador
IndexController e a action indexAction. Então acessar

http://blog.local

é equivalente a acessar

http://blog.local/index/index

Formulários
O Zend_Form é um componente que permite que formulários
sejam criados e mantidos usando-se objetos, aumentando
produtividade e mantendo um padrão de desenvolvimento. É
possível também com o Zend_Form, a implementação de
formulários com herança, ou seja, você tem um formulário
genérico (ex: Application_Form_Usuario) que pode ser utilizado
para criação de outros (ex: Application_Form_UsuarioAdmin) que
possuiriam apenas alguns campos adicionais além do form
padrão.
Ele também possui componentes que permitem a utilização de
todos os Filters e Validators do Zend, bem como a implementação
de Componentes personalizados.
Teremos inicialmente dois formulários, o de login e o de cadastro/
alteração de novos posts (que será usado pelo administrador).
Neste capítulo iremos definir e mostrar na visão os formulários,
deixando a lógica da manipulação dos mesmos para os tópicos
posteriores.

Vamos criar o primeiro formulário, 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 formulário
        $this->setName('Login');
        //elemento para o campo username
        $username = new Zend_Form_Element_Text('username');
        //configurar o label, dizer q é obrigatório, 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');
        //botão 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 formulário
        $this->addElements(array($username, $password, $submit));
        //action e method
        $this->setAction('/auth/index')->setMethod('post');
    }

https://gist.github.com/1455143

Todos os formulários são classes PHP que extendem a classe


Zend_Form. Após criarmos os campos $username e $password
fazemos a configuração dos mesmo, indicando o label, se são
obrigatórios (setRequired), adicionamos filtros (addFilter, no
exemplo o filtro StripTags que remove tags html do conteúdo) e
validadores (o NotEmpty garante que o campo não vai ser aceito
se estiver vazio).
Precisamos agora alterar o controlador para que ele faça a
instanciação do novo objeto de formulário. Para realizarmos um
teste vamos alterar o controlador IndexController.php e
adicionamos as linhas abaixo, no método indexAction.

//cria um novo formulário


$this->view->form = new Application_Form_Login;

No nosso arquivo de visão (views/index/index.phtml) iremos


mostrar o nosso formulário:

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

Basta imprimir o formulário na view, e todo o HTML será gerado,


de acordo com as configurações do arquivo forms/Login.php.
Podemos fazer a mesma coisa com o formulário de cadastro de
posts.
Vamos criar a classe do formulário de inserção/alteração de posts.
O arquivo forms/Post.php ficou 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('Título')->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 formulário são os elementos textarea e


hidden, que geram os seus correspondentes em html. Mais
adiante iremos voltar a trabalhar com estes formulários, o de login
e o responsável por criar novos posts no blog.

Enviando arquivos

Outra funcionalidade comum é a necessidade de enviar arquivos


via formulários. Apesar de não fazer parte do nosso blog, vamos
fazer um exemplo usando o Zend_Form. Vamos criar um novo
form:

zf create form Album

O conteúdo 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('Título')->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);
// extensões: 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 formulário é demonstrado o uso da classe


Zend_Form_Element_File, com seus validadores específicos,
definindo o tamanho máximo do arquivo e suas extensões
permitidas.
Para podermos usar este form vamos criar o controlador
AlbumController.php (zf create controller Album) com o conteúdo
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 formulário está válido
            //de acordo com os validadores do Zend_Form
            if ($form->isValid($formData)) {
                $adapter = $form->arq->getTransferAdapter();
                //indica o destino dos arquivos temporários
                $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 formulário está inválido
            else {
                // Mostra os erros e popula o form com os dados
corretos
                $form->populate($formData);
            }
        }
        else {
            //ainda não foi submetido dados
        }
        $this->view->form = $form;
    }
    
}

https://gist.github.com/1468878

E finalmente, a visão views/scripts/album/index.phtml:

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

Nesse exemplo é possível visualizar a facilidade de uso e do Zend


Framework para tratar arquivos enviados pelo usuário.

Herança de formulários

É possível criarmos heranças de formulários.


Vamos definir um formulário base, chamado PessoaForm. Esta
classe possui os campos básicos, que todos os formulários terão.
Ao definirmos esta classe como abstrata garantimos que o
desenvolvedor precisa extendê-la antes de usar algum formulário,
pois classes abstratas não 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 definir 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('Matrícula')->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

Também podemos criar subforms. Adicionando o código abaixo ao


método init() do forms/Pessoa.php podemos visualizar um novo
formulário dentro do formulário original. Os dados serão enviados
juntamente com o formulário 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 create controller Post


zf create action create Post
zf create action retrieve Post
zf create action update Post
zf create action delete Post

Agora vamos criar código da primeira action, o retrieveAction(),


que vai nos mostrar os posts cadastrados. O código é:
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 mudança 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 código do createAction() para usarmos o


formulário 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
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
dados
$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 atualização de um post. Para isso criamos o seguinte código 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 { //não 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 código podemos ver o re-aproveitamento de um
formulário, somente mudando alguns comportamentos.

E o método final, o deleteAction:

public function deleteAction()


{
$posts = new Application_Model_Posts();
$id = $this->_getParam('id');
$posts->delete("id = $id");
$this->_redirect('post/retrieve');
}

Desafio

Fazer o CRUD das tabelas users e comments

Organizando a aplicação
Agora que já conhecemos alguns conceitos importantes do Zend
Framework vamos organizar melhor nossa aplicação. O primeiro
passo é pensarmos na estrutura dos nossos controllers e no fluxo
da aplicação:
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 responsável pela autenticação, usando
o Application_Form_Login criado anteriormente. Após a
autenticação ser feita com sucesso vamos retornar ao
retrieveAction do PostController, onde vamos ter acesso aos
outros métodos do CRUD.

Vamos então alterar o método indexAction do IndexController:

public function indexAction()


{
$this->_redirect('/post/retrieve');
}
Vamos também adicionar o link para o AuthController no nosso
arquivo post/retrieve.phtml:

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

No próximo tópico iremos criar o AuthController para fazer a


autenticação dos nossos usuários.

Outro ponto que podemos melhorar é a criação de um controlador


base para a nossa aplicação, de onde todos os outros
controladores (IndexController, PostController e AuthController)
vão herdar. Isso é uma prática comum e muito útil pois podemos
criar métodos que serão vistos por todos os controladores na
nossa aplicação. Inicialmente vamos precisar criar um diretório
chamado Blog dentro do library e dentro dele um novo diretório
chamado Controller. Dentro deste vamos criar o Action.php. A
estrutura deve ficar da seguinte forma:

O conteúdo do arquivo Action.php é:

<?php
class Blog_Controller_Action extends Zend_Controller_Action
{

Nos próximos capítulos vamos adicionar conteúdos a este


arquivo.
Precisamos registrar na nossa aplicação o novo conjunto de
classes. Para isso vamos adicionar o código 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 ação a
ser executada. A rota default traduz URLs no formato citado
anteriormente. Rotas adicionais podem ser criadas, geralmente
para disponibilizar URLs mais fáceis de serem compreendidas ou
mais curtas. Por exemplo, poderíamos 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

Também podemos fazer de outra forma, criando um método


_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 expressões


regulares e outras opções avançadas. No site da documentação
do framework existem diversos exemplos, mas na maioria das
vezes as rotas simples como mostrada neste exemplo são
suficientes

Autenticação
Nosso blog vai ter três tipos de usuários, 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 capítulo anterior). O redator vai
poder adicionar e alterar posts, mas não excluí-los.
Para isso precisamos determinar uma forma de identificar o
usuário, para sabermos se ele é válido, e no próximo tópico
iremos ver como controlar seu nível de acesso (administrador ou
redator). Iremos usar o formulário Application_Form_Login criado
anteriormente, em conjunto com um componente do framework
chamado Zend_Auth.
O Zend_Auth fornece uma API para autenticação e inclui
adaptadores para os cenários de uso mais comuns: LDAP, banco
de dados, HTTP, OpenID. E o desenvolvedor pode criar seus
próprios adaptadores extendendo os já existentes.
Vamos criar o AuthController usando o Zend Tool.

zf create controller Auth

O código final:

<?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 formulário está válido
if ($form->isValid($formData)) {
//pega uma instancia e cria caso não exista
$auth = Zend_Auth::getInstance();
//conexao com a base de dados
$db = Zend_Registry::get('db');

$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
senha antes de comparar
);
//configura o usuário/senha
$authAdapter-
>setIdentity($formData['username'])-
>setCredential($formData['password']);
//tenta fazer a autenticação
$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 = 'Usuário
inválido';
$form->populate($formData);
break;
case
Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID:
$session->erro = 'Senha
inválida';
$form->populate($formData);
break;
case Zend_Auth_Result::SUCCESS:
$data = $authAdapter-
>getResultRowObject();
$session->role = $data->role; //
guarda a role do usuário
$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 é possível ver no
código acima. Com poucas linhas é configurada a forma de
autenticação (com uma tabela do banco de dados) e faz-se a
validação. Caso a validação tenha ocorrido com sucesso as
credenciais do usuário são automaticamente armazenadas na
sessão. Também armazenamos na sessão a role do usuário, para
usarmos posteriormente.
Precisamos alterar o código da nossa visão, o arquivo views/
scripts/auth/index.phtml, adicionando o código abaixo:

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

Vamos aproveitar também e mudar o nosso layout, para


mostrarmos uma opção para o usuário fazer logout do sistema. O
arquivo layouts/scripts/layout.phtml ficou 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 função de logout() no AuthController:

public function logoutAction() {


Zend_Auth::getInstance()->clearIdentity();
$this->_redirect('/');
}

Como o layout agora controla se deve mostrar ou não o link para


realizar o login podemos remover o link que colocamos no views/
scripts/post/retrieve.phtml (refatorar é bom!)

Controle de acesso
Nós vimos anteriormente o uso do componente Zend_Auth. Este
componente é responsável apenas pela autenticação dos
usuários, sendo que ele não permite o controle de permissões aos
recursos do aplicativo. Esse papel é responsabilidade do
componente Zend_Acl. ACL (Access Control List - lista de controle
de acesso) é uma solução simples e flexível para realizar o
controle do acesso a determinados recursos.
Alguns conceitos são usados pelo Zend_Acl:
• papel (role): um grupo de usuários
• recurso (resource): algo a ser protegido
• privilégio (privilege): o tipo de acesso exigido
O primeiro passo é o planejamento dos ítens citados acima. No
nosso projeto, do blog, vamos usar três roles:
• visitante: pessoas que não fizeram o login no sistema
• redator: usuários que podem publicar e editar posts, mas
não apagá-los
• admin: usuários com todas as permissões de acesso
Vamos ter também três recursos a proteger:
• index: controlador IndexController
• post: controlador PostController
• auth: controlador AuthController
Os privilégios que iremos controlar são os métodos dos
controladores citados.
O primeiro passo é descrever os papéis, recursos e privilégios no
nosso arquivo de configuração, 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 característica interessante do Zend_Acl é a possibilidade das


roles terem herança. Da forma como configuramos o redator
herda as configurações do visitante e o admin herda as
configurações do redator. Isso facilita bastante a configuração. As
linhas acl.resources[] e acl.allow.visitante[], por exemplo, vão ser
transformadas em Arrays de objetos pelo Zend_Config. Podemos
também usar acl.deny.permissao.role[] caso queiramos negar o
acesso a determinado recurso.
No nosso Bootstrap.php vamos adicionar as seguintes linhas de
código, que são responsáveis por ler o arquivo de configuração 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 autenticação/autorização neste local. O código do
arquivo ficou:

<?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:


default_index
$resource = $controller;
$privilege = $action;

$auth = Zend_Auth::getInstance();
//se o usuário fez login usa a role que está na
sessão
if($auth->hasIdentity()) {
$role = $session->role;
}
else {
$role = 'visitante';
}
//faz a verificação da permissão
$acl = Zend_Registry::get('acl');
if(!$acl->isAllowed($role, $resource, $privilege))
{
$session->erro = 'ACL inválida';
$this->_redirect('/');
}
}
}
}
https://
gist.github.com/
1449759

Desta forma todos os nossos controllers conhecem o controle de


acesso.

Uma observação. Caso algum controller precise definir algo em


seu método init() é necessário sempre invocar também 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 são respeitadas.

Vamos agora criar alguns usuários de teste na tabela, indicando


qual é o papel (redator, visitante ou admin) que cada usuário
exerce no sistema. É possível fazer isso usando o phpMyAdmin,
outra ferramenta gráfica 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 verificar que o acesso aos métodos


é controlado de maneira muito rápida e fácil. O uso de ACLs
permite um controle fácil de ser desenvolvido e com grande
versatilidade.
Navegação
O Zend Framework fornece um componente para facilitar a
criação de menus, o Zend_Navigation.
Podemos usar o Zend_Navigation para gerar facilmente menus e
ítens de navegação.
Exemplo:
No bootstrap adicionar:
/**
* inicializa a navegação
*
* @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 também integrar o Zend_Navigation com o Zend_Acl,


para que o menu de opções seja renderizado de acordo com as
permissões do usuário. Para isso vamos reescrever as linhas que
adicionamos agora a pouco no Bootstrap (OBS: é preciso verificar
se elas estão após a criação do Zend_Acl):
/**
* inicializa a navegação
*
* @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 final 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 opções do menu devem aparecer, dependendo da role do
usuário.
Esta é uma das coisas legais do Zend Framework. Apesar de ser
formado por uma série de componentes que podem ser usados
em separado, a maioria deles integra-se de uma maneira muito
útil.

Paginação
Usando o componente Zend_Paginator facilita uma das
necessidades mais comuns em aplicações web, a paginação de
dados.
O componente Zend_Paginator possibilita ao programador
configurar uma série de opções afim de tornar a paginação mais
intuitiva. Atualmente o Zend_Paginator nos permite paginar quatro
tipos de dados:
• Array
• DbSelect
• DbTableSelect
• Iterator
Vamos modificar nosso sistema de blog para que ele use
paginação na página inicial.
Primeiro vamos fazer uma alteração no método retrieveAction() do
PostController.php. Vamos comentar a linha:
$result = $posts->fetchAll(); //pega todos os posts

e adicionar as seguintes:
//criando a paginaçao
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 página
$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


são trechos de códigos de visão (html, js, css) que podem ser
reutilizados por diversas views. Neste exemplo é criado o ítem que
irá mostrar o número de páginas que o paginador gerou. Ele será
reutilizado em todas as páginas que precisarem de paginação. O
código 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 finalmente vamos mudar a visão para usar o nosso componente


de paginação. O novo conteúdo 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 técnica de cache é muito usada para melhorar a performance de
sites, sejam eles de grande tráfego ou não.
Teoricamente quase tudo pode ser armazenado em cache:
resultados de consultas, imagens, arquivos css, arquivos js,
trechos de código html, etc.
No Zend Framework o cache é fornecido usando-se a classe
Zend_Cache. O cacheamento é fornecido ao programador através
de “frontends”, enquanto que o armazenamento em si é feito com
classes de “backends”. Isso torna o processo flexível no quesito
armazenamento e fácil para a manipulação.
O frontend mais usado é o Core, padrão do Framework. Este pode
ser extendido para atender as necessidades do usuário, mas na
maioria das vezes isso não é necessário.
Os principais backends disponíveis são:
• File: os dados do cache são armazenados em arquivos no
sistema operacional
• Sqlite: salvos em um banco de dados Sqlite
• Memcached: os dados serão salvos no Memcached, um
servidor específico para cache, usado por grandes
arquiteturas como o Facebook
• Apc: usa o cache em memória fornecido pela extensão APC
(Alternative PHP Cache) do PHP
• Xcache: usa a extensão do PHP, Xcache para armazenar os
dados em memória
• ZendPlatform: usa a solução proprietária da Zend para
armazenar o cache
Vamos ver alguns exemplos de uso. O primeiro passo é criarmos
entradas no nosso arquivo de configurações, 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')) {
//não 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 não será realizada novamente enquanto o


cache não expire. No exemplo está configurado para durar 2
horas (configurado no application.ini). Podemos indicar também o
tempo de vida de um ítem em específico (em segundos):
$cache->save($result, 'cachePosts', array(), 60); //1 min
O terceiro parâmetro, o array(), é usado para atribuir uma tag para
a variável do cache. Tags servem para agruparmos os ítens do
cache, assim fica mais fácil 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 estão vencidos
$cache->clean(Zend_Cache::CLEANING_MODE_OLD);

Também podemos usar o recurso de Cache para acelerar a


renderização de formulários. Usar o Zend_Form para gerar
formulários aumenta a produtividade do desenvolvimento, mas
seu desempenho pode deixar a desejar quando comparado com
formulários 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

Também é possível usar o Zend_Cache para armazenar as


sessões, algo útil quando usado para salvar as sessões de
usuários, se usado com Memcached por exemplo (salvar sessões
em cache usando o Backend File não é muita vantagem, mas com
Memcached ou APC é muito mais rápido). Assim é possível usar
vários servidores para guardar a informação e ela fica
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

Após salvar conteúdo acima no arquivo library/Blog/Session/


Handler.php é necessário configurar o handler da sessão, no
bootstrap, antes da inicialização da sessão :
Zend_Session::setSaveHandler(new Blog_Session_Handler($cache));

Traduções
Nos exemplos anteriores vimos a utilização dos validadores do
Zend Framework para verificar se os campos obrigatórios de um
formulário foram digitados ou se possuíam valores corretos. Mas
as mensagens de erro e validação são apresentadas por padrão
na língua inglesa. Para facilitar o uso das mensagens em outras
línguas vamos usar o componente Zend_Translate.
Para fazer uso do componente vamos inicialmente criar um
diretório no projeto onde iremos armazenar os arquivos das
traduções. Vamos chamar este diretório 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 método _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 padrão é a pt_BR
(português Brasil). Outros formatos são permitidos: Array, ini,
gettext, tbx, etc.
O objeto também é registrado pelo Bootstrap usando o
Zend_Registry, facilitando sua utilização no restante do projeto.

O arquivo de traduções inicial ficou 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 máximo %max%
caracteres
notSame;Os valores fornecidos são diferentes
missingToken;Nenhuma senha foi fornecida
emailAddressInvalid;Endereço de e-mail inválido
hostnameInvalidHostname;Endereço inválido
notDigits;Valor inválido
hostnameUnknownTld;'%value%' é um domínio desconhecido
hostnameLocalNameNotAllowed;'%value%' é um domínio não permitido
emailAddressInvalidHostname;'%value%' não é um email inválido
emailAddressInvalidFormat;'%value%' não é um email inválido
dateInvalid;Data inválida
https://
gist.github.com/
987413

O formato do arquivo é: chave;Tradução.

Mais informações sobre as mensagens de validação podem ser


encontradas neste link:

http://framework.zend.com/manual/en/zend.validate.messages.html

Também podemos usar o Zend_Translate para internacionalizar


todas as mensagens do sistema. Por exemplo, na visão views/
scritps/post/create.phtml usamos o seguinte código:

<h2>
<?php echo Zend_Registry::get('Zend_Translate')->_('Novo Post');?>
</h2>

Caso precisemos alterar o sistema para inglês (mudando o


parâmetro 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 não exista o texto ‘Novo Post’ será apresentado,
caso contrário irá apresentar o texto ‘New post’.
Usando o Zend_Translate é muito fácil criar aplicativos para
múltiplas línguas.

Enviando e-mails
Enviar e-mails é uma função recorrente em diversos tipos de
aplicação Web. Neste tópico é apresentado um controlador com
alguns exemplos de como enviar e-mails usando o componente
Zend_Mail.

<?php
class EmailController extends Zend_Controller_Action {
        //configuração 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 formulário foi enviado
                */
                if($_POST) {

                        /**
                        * Recebe os campos do formulário
                        */
                        $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 visão para mostrar o formulário 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 alterações no exemplo acima é possível adaptá-lo


ao seu projeto
Diagnóstico da aplicação

O Zend Framework fornece algumas ferramentas para facilitar a


localização 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 é possível 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 parâmetro da função log() é a prioridade da


mensagem. As opções disponíveis são:
Nome Uso

Zend_L Emergê
og::EM ncia:
ERG sistema
não
pode
ser
usado

Zend_L Alerta:
og::AL ação
ERT deve
ser
tomada

Zend_L Crítico
og::CRI
T

Zend_L Erro
og::ER
R

Zend_L Aviso
og::WA
RN

Zend_L Observ
og::NO ações
TICE

Zend_L Informa
og::INF tivo
O

Zend_L Mensa
og::DE gens
BUG de
debug

Para cada prioridade existe um método específico do objeto


Zend_Log. Então as duas linhas abaixo tem a mesma função:
$log->log(‘Erro crítico’,Zend_Log::CRIT);
$log->crit(‘Erro crítico’)

Além 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);
}

É necessário criar o banco de dados caso este não exista:


sqlite3 zf_log.db

create table log(pri int, msg text);

Zend_Db_Profiler

O Zend Framework possui um componente chamado


Zend_Db_Profiler que nos permite realizar o profiling dos acessos
ao banco que pode ser utilizado em conjunto com o componente
Zend_Db_Profiler_Firebug.
Primeiramente, é preciso ter os complementos do Firefox Firebug
(https://addons.mozilla.org/pt-BR/firefox/addon/1843) e FirePHP
(http://www.firephp.org/) instalados, ou seja, só é possível usar
este recurso com o Firefox (não fiz testes com as versões do
Firebug para Chrome, então não sei como essa feature se
comporta neste navegador).
É preciso também adicionar as linhas abaixo no Bootstrap, no
método _initDb():
/**
* Inicializa o banco de dados. Somente necessário se desejado salvar
a conexão 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 página corrente
são apresentadas no console do Firebug. Com isso é fácil verificar
quais consultas estão sendo executadas, quanto tempo
demoraram e quantas linhas foram retornadas. Essas informações
são de extrema utilidade para realizar uma melhoria de
performance das páginas baseadas em resultados vindos de
bancos de dados.

Conclusão
Certamente não consegui aqui englobar todas as funcionalidades
do Zend Framework, mas esse não era exatamente o objetivo
deste livro. A idéia aqui era apresentar as principais características
e como usá-las em uma aplicação 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 difícil para um livro impresso. Todos os
trechos de códigos do PDF possuem links para uma versão
online, o que facilita a cópia para o seu editor de programação
favorito, mas que principalmente facilita alguma possível correção
que venha a acontecer. Então acompanhe o site oficial deste livro,
o http://www.zfnapratica.com.br para acompanhar qualquer
melhoria ou correção nos códigos ou textos. E caso tenha alguma
sugestão ficaria feliz em recebê-la e publicar no site. Meus dados
de contato estão na introdução deste livro.
É isso. Happy coding para você!

Você também pode gostar