Parte 7 – WordPress e Programação Orientada a Objetos: Um Exemplo WordPress – Implementação: Gerenciando Ganchos do WordPress

Publicados: 2022-02-04

Até este ponto, interagir com a API do Plugin significava chamar add_action() e add_filters() no construtor de cada classe.

Até agora, essa abordagem foi boa o suficiente, pois manteve as coisas simples e nos permitiu focar em aprender mais sobre programação orientada a objetos com o WordPress. No entanto, não é o ideal.

Se um objeto registrar todos os seus ganchos quando for criado, coisas como teste de unidade se tornarão complicadas.

NOTA: Os testes unitários devem testar cada “unidade” isoladamente. Mesmo se você não estiver escrevendo testes de unidade no momento, escrever código testável economizará muito tempo refatorando mais tarde, se você decidir escrever testes.

O Gerenciador de Ganchos

Vamos dar um passo adiante e introduzir uma nova classe para gerenciar nossos ganchos, vamos chamá-la de Hooks_Manager . Esta classe será responsável pelo registro de todos os nossos ganchos. Então, vamos criar uma nova classe com um método register() .

 class Hooks_Manager { /** * Register the hooks of the given object. * * @param object $object */ public function register( $object ) { // Register the hooks the specified object needs } }

Precisamos de uma interface para cada classe que precisa registrar ganchos para implementar.

 interface Hooks { /** * Return the actions to register. * * @return array */ public function get_actions(); }

Você pode pensar em uma interface como um contrato , onde uma classe que implementa essa interface é “vinculada contratualmente” para implementar todos os métodos definidos nessa interface.

Por exemplo, uma classe Login_Error que se conecta à ação login_head deve implementar o método get_actions() de nossa interface Hooks .

 class Login_Error implements Hooks { public function get_actions() { return array( 'login_head' => array( 'add_errors', 10, 1 ), ); } }

O método register() de Hooks_Manager aceita um objeto, chama seu método get_actions() e registra todas as suas ações.

 public function register( $object ) { $actions = $object->get_actions(); foreach ( $actions as $action_name => $action_details ) { $method = $action_details[0]; $priority = $action_details[1]; $accepted_args = $action_details[2]; add_action( $action_name, array( $object, $method ), $priority, $accepted_args ); } }

Vamos adicionar um método get_filters() à nossa interface, para que possamos registrar ações e filtros.

 interface Hooks { /** * Return the actions to register. * * @return array */ public function get_actions(); /** * Return the filters to register. * * @return array */ public function get_filters(); }

De volta à nossa classe Login_Error , precisamos implementar este novo método get_filters() .

 class Login_Error implements Hooks { public function get_actions() { return array( 'login_head' => array( 'add_errors', 10, 1 ), ); } public function get_filters() { return array( 'authenticate' => array( 'track_credentials', 10, 3 ), 'shake_error_code' => array( 'add_error_code', 10, 1 ), 'login_errors' => array( 'format_error_message', 10, 1 ), ); } }

Vamos renomear o método register() do nosso Hooks_Manager para register_actions() . Também adicionaremos um método register_filters() . Esses dois métodos serão responsáveis ​​por registrar ações e filtros respectivamente.

 class Hooks_Manager { /** * Register the actions of the given object. * * @param object $object */ private function register_actions( $object ) { $actions = $object->get_actions(); foreach ( $actions as $action_name => $action_details ) { $method = $action_details[0]; $priority = $action_details[1]; $accepted_args = $action_details[2]; add_action( $action_name, array( $object, $method ), $priority, $accepted_args ); } } /** * Register the filters of the given object. * * @param object $object */ private function register_filters( $object ) { $filters = $object->get_filters(); foreach ( $filters as $filter_name => $filter_details ) { $method = $filter_details[0]; $priority = $filter_details[1]; $accepted_args = $filter_details[2]; add_filter( $filter_name, array( $object, $method ), $priority, $accepted_args ); } } }

Agora podemos adicionar um método register() novamente, que simplesmente chamará tanto register_actions() quanto register_filters() .

 class Hooks_Manager { /** * Register an object. * * @param object $object */ public function register( $object ) { $this->register_actions( $object ); $this->register_filters( $object ); } // ...

E se uma classe não precisar registrar ações e filtros? A interface Hooks contém dois métodos: get_actions() e get_filters() . Todas as classes que implementam essa interface serão forçadas a implementar ambos os métodos.

 class Cookie_Login implements Hooks { public function get_actions() { return array( 'auth_cookie_bad_username' => array( 'handle_bad_username', 10, 1 ), 'auth_cookie_bad_hash' => array( 'handle_bad_hash', 10, 1 ), 'auth_cookie_valid' => array( 'handle_valid', 10, 2 ), ); } public function get_filters() { return array(); } }

Por exemplo, a classe Cookie_Login precisa registrar apenas ações, mas agora é forçada a implementar o método get_filters() apenas para retornar um array vazio.

O Princípio de Segregação de Interface (ISP) , o “I” em SOLID, afirma:

“Nenhum cliente deve ser forçado a depender de métodos que não usa.”

Significando que o que estamos fazendo agora é exatamente o que não deveríamos estar fazendo.

Segregação de Interface

Podemos corrigir isso dividindo nossa interface em outras menores e mais específicas para que nossas classes tenham que saber apenas sobre os métodos que são de seu interesse.

 interface Actions { /** * Return the actions to register. * * @return array */ public function get_actions(); }
 interface Filters { /** * Return the filters to register. * * @return array */ public function get_filters(); }

Não precisamos mais de get_actions() e get_filters() , podemos implementar apenas a interface Actions e nos livrar de get_filters()

 class Cookie_Login implements Actions { public function get_actions() { return array( 'auth_cookie_bad_username' => array( 'handle_bad_username', 10, 1 ), 'auth_cookie_bad_hash' => array( 'handle_bad_hash', 10, 1 ), 'auth_cookie_valid' => array( 'handle_valid', 10, 2 ), ); } }

Por outro lado, Login_Error , que precisa de ações e filtros, só precisa implementar ambas as interfaces. As classes podem implementar mais de uma interface separando-as com uma vírgula.

 class Login_Error implements Actions, Filters { public function get_actions() { return array( 'login_head' => array( 'add_errors', 10, 1 ), ); } public function get_filters() { return array( 'authenticate' => array( 'track_credentials', 10, 3 ), 'shake_error_code' => array( 'add_error_code', 10, 1 ), 'login_errors' => array( 'format_error_message', 10, 1 ), ); } }

Agora que separamos nossa interface, precisamos apenas atualizar o método register() de Hooks_Manager para refletir nossas alterações.

 class Hooks_Manager { /** * Register an object. * * @param object $object */ public function register( $object ) { if ( $object instanceof Actions ) { $this->register_actions( $object ); } if ( $object instanceof Filters ) { $this->register_filters( $object ); } } // ...

Dessa forma, chamamos condicionalmente apenas register_actions() , apenas register_filters() , ou ambos, com base na(s) interface(s) que o objeto especificado implementa.

Para realmente usar o gerenciador de ganchos:

 $hooks_manager = new Hooks_Manager(); $hooks_manager->register( $login_error ); $hooks_manager->register( $cookie_login );

É isso! Agora podemos usar esse objeto para gerenciar ganchos em toda a base de código.

Conclusão

Claro, existem várias maneiras de gerenciar seus ganchos de forma orientada a objetos, acabamos de mostrar uma delas. Você deve experimentar e encontrar um que atenda às suas necessidades.

Fique conosco para a última parte desta série, onde veremos como lidar com opções de forma orientada a objetos, falar sobre encapsulamento, abstração e como desacoplar suas classes para criar um plugin flexível e fácil de estender!

Clique aqui para ler a Parte 8 em nossa Série de Programação Orientada a Objetos

Veja também

  • WordPress e programação orientada a objetos – uma visão geral
  • Parte 2 – WordPress e Programação Orientada a Objetos: Um Exemplo do Mundo Real
  • Parte 3 – WordPress e Programação Orientada a Objetos: Α Exemplo WordPress – Definindo o Escopo
  • Parte 4 – WordPress e Programação Orientada a Objetos: Um Exemplo WordPress – Design
  • Parte 5 – WordPress e Programação Orientada a Objetos: Um Exemplo WordPress – Implementação: O Menu de Administração
  • Parte 6 – WordPress e Programação Orientada a Objetos: Um Exemplo WordPress – Implementação: Registrando as Seções