Docsity
Docsity

Prepare-se para as provas
Prepare-se para as provas

Estude fácil! Tem muito documento disponível na Docsity


Ganhe pontos para baixar
Ganhe pontos para baixar

Ganhe pontos ajudando outros esrudantes ou compre um plano Premium


Guias e Dicas
Guias e Dicas

Zend Framework na pratica, Notas de estudo de Análise de Sistemas de Engenharia

Zend Framework

Tipologia: Notas de estudo

2013

Compartilhado em 15/07/2013

joabe-anderson-7
joabe-anderson-7 🇧🇷

5

(3)

6 documentos

Pré-visualização parcial do texto

Baixe Zend Framework na pratica e outras Notas de estudo em PDF para Análise de Sistemas de Engenharia, somente na Docsity! Zend Framework Jr prática 2º edição Elton Luís Minetto =" 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 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: 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 estes devem ser armazenados no diretório models. Todos os mode los são c lasses PHP que ex tendem a c lasse 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: 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/ 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 Nes te f o rmu lá r i o é demons t rado o uso da c l asse 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();          <?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 Redirect PostController:retrieveAction IndexController:indexAction 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 */ $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 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: 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 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 i s s o é p r e c i s o i m p l e m e n t a r a i n t e r f a c e 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"         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 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ê!
Docsity logo



Copyright © 2024 Ladybird Srl - Via Leonardo da Vinci 16, 10126, Torino, Italy - VAT 10816460017 - All rights reserved