Agosto 7th 2007 02:58 am

Zend Framework - Não estenda. Plugue!

Utilizando o plugin Zend_Controller_Plugin_ErrorHandler

PHP:
  1. $oFrontController = Zend_Controller_Front::getInstance();
  2. $oFrontController->setControllerDirectory('/caminho/para/controllers');
  3.  
  4. $oErrorHandler = new Zend_Controller_Plugin_ErrorHandler();
  5. //seta o controller que ira manipular o erro
  6. $oErrorHandler->setErrorHandlerController('Error');
  7. //seta a action que ira manipular o erro
  8. $oErrorHandler->setErrorHandlerAction('handler');
  9. //adiciona o plugin ao front controller
  10. $oFrontController->registerPlugin($oErrorHandler);
  11.  
  12. $oFrontController->dispatch();

A partir deste código dizemos que nosso front controller irá redirecionar as exceções para o controller ErrorController::handlerAction().

Ao redirecionar o erro ocorrido para a action o plugin adiciona uma variável no request chamada 'error_handler', a qual o valor é um objeto do tipo ArrayObject com as propriedades:

  • type: tipo do erro ocorrido.
  • request: requisição feita no momento do erro.
  • exception: exceção lançada no erro.

Controller para manipular os erros

PHP:
  1. <?php
  2.  
  3. class ErrorController extends Zend_Controller_Action {
  4.  
  5.     public function handlerAction() {
  6.         $oRequest = $this->getRequest();
  7.  
  8.         //pega o objeto que contém o erro
  9.         $oErrors = $oRequest->getParam('error_handler');
  10.  
  11.         //testa o tipo de erro
  12.         switch ($oErrors->type) {
  13.             case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
  14.             case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:
  15.                 $this->getResponse()->setRawHeader('HTTP/1.1 404 Not Found');
  16.                 break;
  17.             default: //Zend_Controller_Plugin_ErrorHandler::EXCEPTION_OTHER
  18.                 break;
  19.         }
  20.  
  21.         //pega a exceção lançada no erro
  22.         $oException = $oErrors->exception;
  23.  
  24.         //loga o erro
  25.         $oLog = new Zend_Log(
  26.                 new Zend_Log_Writer_Stream('/tmp/application.log')
  27.         );
  28.  
  29.         $oLog->debug($oException->getMessage() . "\r\n"
  30.                      . "Request: " . $oErrors->request->getControllerName()
  31.                      . "/" . $oErrors->request->getActionName() . "\r\n"
  32.                      . $oException->getTraceAsString());
  33.  
  34.         $this->getResponse()->appendBody("Ocorreu um erro inesperado! :-)");
  35.     }
  36. }

No exemplo acima, criamos uma action para manipular o tratamento das exceções, primeiramente pegamos o erro setado no parametro error_handler.

PHP:
  1. $oErrors = $oRequest->getParam('error_handler');

Logo após isso, verificamos qual o tipo de erro, através da variável type da instância do ArrayObject.

PHP:
  1. switch ($oErrors->type)

Aqui tratamos os erros do tipo Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER e Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION, enviando um header para o browser indicando que a página não foi encontrada. Estes dois tipos de erros, ocorrem caso o controller ou a action roteados pelo router, não forem encontrados. Caso não seja este o motivo do erro (seja lançada uma exceção qualquer), o typo será Zend_Controller_Plugin_ErrorHandler::EXCEPTION_OTHER.

Abaixo logamos o erro ocorrido, e enviamos ao browser do usuário uma "amigável" mensagem explicando que ocorreu um erro não esperado.

Testando o tratamento de erros

Agora para testar o tratamento de erros basta lançar uma exceção qualquer na action e ver o resultado. Ou então entar acessar um controller/action não disponível.

Compartilhe:
  • del.icio.us
  • Google
  • Digg
  • Sphinn
  • Facebook
  • Mixx
  • LinkedIn
  • Live
  • Rec6
  • Technorati
  • TwitThis
1 Estrela2 Estrela3 Estrela4 Estrela5 Estrela (2 votos, média: 4 de 5)
Loading ... Loading ...

Páginas: 1 2 3 4

14 Comments »

14 Responses to “Zend Framework - Não estenda. Plugue!”

  1. felipe tonello on 10 Ago 2007 at 19:03 #

    achei bem legal essa abordagem de plugin..
    eu sabia que podia fazer e tals mas nunca cheguei a utilizar mesmo..

    Uma dúvida que tive, foi pq você usou o routeShutdown() ao invez do preDispatch() por exemplo?
    Porque você precisa do route né? para saber qual é o controller usado para ver se não está usando o controller login?!

    Intendi, mas sei lá, não fica 100% seguro dessa maneira… porque por exemplo o Zend_Controller_Action::__construct() é rodado, juntamente com os inits() e etc.. aí alguma informação pode ser usada sem necessiade..
    A solução seria você utilizar os inits() e etc de acordo a sua lógica de plugin.

    Parabéns!

  2. diegotremper on 11 Ago 2007 at 04:55 #

    Exato, você esta certo, também pensei nisso quando utilizei, mas ainda sim, gosto da idéia de utlizar os plugins para fazer o trabalho que sugeri de segurança, basta tomar alguns cuidados. Cheguei a progurar algo na lista de MVC do Zend para ver se ninguem tinha pensado algo parecido, mas não encontrei, acho que vou postar lá essa situação e ver o que o pessoal acha.

    Valeu.

  3. felipe tonello on 11 Ago 2007 at 16:20 #

    Eu vi um modo de segurança igual a esse, com plugins mesmo, mas só que usando Acl.
    Lá no devzone da zend mesmo, só que está em versão do ZF atrasada. Eu estou fazendo um aqui versão atualizada e usando para testes também..

    Até mais diego,
    Felipe

  4. Aziz on 13 Out 2007 at 10:53 #

    eu usei esse esquema de plugin em um sistema que estou desenvolvendo para renderizar cabeçalho e rodapé das paginas, mas acabei desfazendo o plugin pq não consegui fazer o titulo ficar customizado para cada pagina, a solução que arrangei foi extender a classe Zend_Controller_Action sobrescrevendo o metodo render().
    fazendo algo assim:
    public function render($action = null, $name = null, $noController = false)
    {
    #renderiza topo
    $this->getResponse()->prepend(’topo’, $this->view->render(’topo.phtml’));

    parent::render($action,$name,$noController);

    #renderiza o rodape
    $this->getResponse()->append(’rodape’, $this->view->render(’rodape.phtml’));
    }

    ta funfando blz, mas gostaria de saber se vc tem alguma ideia melhor?

    Falow

  5. Diego Tremper on 15 Out 2007 at 00:02 #

    hum…

    uma forma de fazer o que você fez é colocar dentro de cada view sua o seguinte código:

    < ?php echo $this->render(’topo.phtml’); ?>

    ….

    < ?php echo $this->render(’rodape.phtml’); ?>

    []’s

  6. lamonato on 15 Nov 2007 at 16:20 #

    Acabei fazendo como o diego, colocando dentro das views.
    Parabéns pelo blog

  7. Leonildo on 28 Abr 2008 at 16:15 #

    Qual o diretório mais indicado para se colocar os plugins ?

  8. Bruno on 14 Jul 2008 at 16:44 #

    Ótimo, agradeço muito ao Diego, Felipe e Flavio Gomes por serem pioneiros aq no Brasil com esse Know-how sobre ZendFramework…me ajudaram muito….valeu mesmo…logo, logo quem sabe eu tambm naum ajude o pessoal!

  9. links for 2008-08-02 [delicious.com] « sySolution on 02 Ago 2008 at 13:00 #

    […] Blog do Tremper » Zend Framework - Não estenda. Plugue! (tags: zend) […]

  10. Blog do Tremper » Injeção de dependência com Zend Framework on 29 Nov 2008 at 03:50 #

    […] Porém, existem maneiras mais fáceis (e mais elegantes) de fazer isso. Injeção de Dependência é uma delas. Com o Zend Framework existem alguns pontos onde podemos aplicar este tipo de abordagem, utilizando Action Helpers, View Helpers e Plugins. Já expliquei aqui no blog como utilizar plugins, no post Não estenda. Plugue!. […]

  11. Luiz on 23 Jan 2009 at 14:53 #

    Olá,

    Parabéns pelo blog, você já me ajudou e ensinou muita coisa com suas publicações.. obrigado mesmo…

    Olha só ,lí seu tópico umas 50 vezes, mas não estou conseguindo adaptar para meu problema, e gostaria de uma ajudinha se possível…

    Meu problema:

    Estou iniciando no Zend e estou montando um menu dinâmico, ou seja, o usuário escolhe o módulo que deseja trabalhar e o Zend acessa o banco de dados e restagada somente os menus referente ao módúlo escolhido… até aí tudo em ordem…

    Meu problema é que tenho um controller chamado MenuController.php e ModuloController.php, sendo que respectivamente o Menu acessa a tabela Menu e o Modulo a tabela de módulos disponíveis (exemplo: Compras, Viagens, Requisição de Compras…etc)

    A idéia é que quando o usuário acessar uma página (qualquer controller) o Zend faça uma espécie de require_once no controller chamado “montamenu” para que se crie o menu com as opções…..

    Tentei quase de tudo, require_once, render, include, _forward, _redirect… e nada funcionou, tirando o _forward que deu certo mas não ficou uma programação dinâmica…. e sim muito manual…

    Quando de muita pesquisa acabei batendo neste post que achei que seria minha solução, mas não estou conseguindo criar meu plugin para apenas carregar e montar o menu do banco de dados..

    Para usar o plugin no zend tenho que registar ele no sistema, o registro se faz no bootstrap ? o plugin deve ser salvo dentro da pasta Controller ?

    Segui se exemplo mas ele dá Class not Found… (hehehehe)

    Terias por acaso um exemplo voltado para menus ?

    Obrigado pela ajuda,

    Luiz

  12. Arian Maykon (Dead_Thinker) on 07 Fev 2009 at 20:46 #

    @Aziz - Cara, acho que se tu estudar e usar o Zend_Layout resolve teu problema de uma forma mais elegante. Dá uma olhada.

    @Luiz - acho que pro teu caso mano seria melhor um View_Helper não? E nele tu poderia pegar dados da requisição/sessão e montar o menu conforme desejado. Dá uma sakada, uso um View_Helper pra renderizar os menus.

  13. Thiago Colares on 09 Out 2009 at 12:14 #

    Muito bom o post, parabéns pelo blog :)

  14. Luís Filipe on 10 Jun 2010 at 16:07 #

    Fala Diego, eu trabalho com ZF há algum tempo e gostaria de saber como eu posso tratar erros de falhas em conexões de banco, que geram erros fatais e não são tratadas por plugins como este que você informou.

    Se puder me ajudar, ficarei agradecido :)

    Abraço e parabens pelo blog e pelo ZFBrasil.

Trackback URI | Comments RSS

Leave a Reply

« Dez itens para que os geeks trabalhem em paz. Você acrescentaria mais algum? | Hackers conseguem desbloquear o iPhone »