Como usar Hooks no CodeIgniter

Imagine que você precise rodar uma função antes que seu sistema começasse a rodar. Ou então, rodar algum procedimento somente após todo o seu sistema já ter sido carregado. Ou ainda, rodar alguma verificação antes de algum método específico dentro de algum controller específico rodar.

Pra fazer isso do jeito POG(programação orientada a gambiarras), você iria nos arquivos do Core do CodeIgniter e colocaria as chamadas para as suas próprias funções.

Nem queira imaginar a dor de cabeça que isso traria no futuro. Bastaria uma simples atualização do Framework pra você perder tudo.

Felizmente existe uma funcionalidade do CodeIgniter chamada Hook, que basicamente é a maneira correta de você dar uma mexida nas entranhas do framework sem mexer nos arquivos do Core.

A tradução da palavra Hook nada mais é do que gancho, que demonstra exatamente como ele funciona, ou seja, seu código engancha em algum trecho do código do CI chamado a função que você criou. (que belo exemplo hein?)

Por exemplo: imagine que você precisasse rodar alguma função antes mesmo de qualquer controller ser carregado.

Para isto, bastaria criar um hook do tipo pre_controller.

Se você preciasasse rodar alguma função imediatamente após um controller ser carregado, então bastaria criar um hook do tipo: post_controller.

Veja abaixo uma lista dos tipos de hooks que você pode criar:

  • pre_system: Chamado imediatamente a cada inicialização do sistema durante a sua execução. Somente as classes de benchmarks e hooks foram carregadas até este ponto. Nenhum roteamento ou algum outro processo foi executado ainda.
  • pre_controller: Chamado imediatamente antes de qualquer um dos seus controller serem chamados. Todas as classes base, roteamento e verificações de segurança já foram executadas.
  • post_controller_constructor: Chamado imediatamente após seu controller ser instanciado, mas antes de qualquer chamada de método ser executada.
  • post_controller: Chamado imediatamente aós seu controller ser completamente executado.
  • display_override: Sobrescreve o método _display() usado para enviar uma página já finalizada para o navegador no final da execução do sistema. Isto lhe permite usar sua própria metodologia para mostrar suas páginas. Note que será necessário você referenciar o superobjeto do CodeIgniter assim: $this->CI =& get_instance() e então os dados já finalizados estarão disponíveis quando você chamar: $this->CI->output->get_output();
  • cache_override: Habilita a possibilidade de você chamar seu próprio método de _display_cache() na biblioteca Output. Isto lhe permite usar seu próprio mecanismo para mostrar a página.
  • post_system: Chamado depois que a página é renderizada é enviada ao navegador, no final da execução do sistema depois dos dados terem sido enviados ao navegador.

Como usar um Hook?

Todos os seus Hooks deverão ser definidos neste arquivo: application/config/hooks.php e devem seguir o seguinte formato:

O índice da array deve estar de acordo com o nome do hook que você deseja usar, ou seja, você deverá substituir o pre_controller pelo nome do hook que mencionei na lista logo acima.

No exemplo acima, o hook criado irá apontar para o nome pre_controller. Os seguintes itens devem ser definidos na sua array que irá criar o hook:

  • class: O nome da classe que você deseja acessar. Se você desejar usar uma função procedural em vez de uma classe, deixe este item em branco.
  • function: O nome da função (ou método) que você deseja chamar.
  • filename: O nome do arquivo que contém sua classe/função
  • filepath: O nome do diretório que contém o seu script. Nota: seu script deve estar localizado em um diretório DENTRO da pasta application, sendo assim, o caminho do seu arquivo é relativo a este diretório. Exemplo: se seus scripts estiverem localizados em: application/hooks, use “hooks” como seu caminho de arquivo (filepath). Se seu script estiver localizado em: application/hooks/utilities/ você irá usar “hooks/utilities” como seu filepath. Sem barras.
  • params: Qualquer parâmetro que você deseja passar para seu script. Este item é opcional.

Se você está rodando uma versão do PHP igual ou maior que a 5.3, você também poder usar as funções anônimas, ou closures como hooks, com esta simples sintaxe:

Múltiplas chamadas para o mesmo hook

Se você quiser usar o mesmo apontamento de hook com mais de um script, simplesmente crie uma array multidimensional, assim:

Note os colchetes depois de cada índice da array:

Isto lhe permite usar o mesmo hook para chamar vários scripts. A ordem que você definir seu array será a ordem de execução do código.

É isso, espero que isto lhe seja útil.

Abraços

Fábio

Fábio S. Reszko

Sou Programador PHP desde 2006 e eu acredito sinceramente que programar usando um Framework PHP é a solução para os problemas de códigos desorganizados, difíceis de entender e de dar manutenção no futuro. Se você também acredita nisto, então fique à vontade em explorar meu blog.

  • Marcus Vinicius

    Bem interessante. Fiquei pensando que poderiam ser utilizados o pre_system, o pre_controller e o post_controller_constructor para verificar se um usuário está dentro de um sistema (logado).

  • Olá Marcus

    Acredito que também seja possível. Mas particularmente acho mais interessante o método que mostrei no post sobre login, pois se você criar um hook dos tipos pre_system, pre_controller e post_controller_constructor, você vai simplesmente bloquear todas as páginas do CI, e isso não seria legal, pois a tela de login, por exemplo, não pode ser bloqueada.

    Fabio

  • Eu conseguiria usar Hooks para fazer o log de algumas querys em uma tabela no meu BD?

  • Daniel, acredito que sim. Basta você criar um controller e um método que gera o seu log e chamar este controller via hook escolhendo em que momento fazer isto através das opções do próprio hook.