Partea 7 – WordPress și programare orientată pe obiecte: un exemplu WordPress – Implementare: gestionarea cârligelor WordPress

Publicat: 2022-02-04

Până în acest moment, interacțiunea cu API-ul Plugin a însemnat apelarea add_action() și add_filters() în constructorul fiecărei clase.

Până acum această abordare a fost suficient de bună, deoarece a păstrat lucrurile simple și ne-a permis să ne concentrăm pe a afla mai multe despre programarea orientată pe obiecte cu WordPress. Cu toate acestea, nu este ideal.

Dacă un obiect își înregistrează toate cârligele atunci când este creat, lucruri precum testarea unitară devin complicate.

NOTĂ: Testele unitare ar trebui să testeze fiecare „unitate” în mod izolat. Chiar dacă nu scrieți teste unitare în acest moment, scrierea codului testabil vă va economisi mult timp de refactorizare mai târziu, dacă vă decideți vreodată să scrieți teste.

Managerul Hooks

Să facem acest lucru cu un pas mai departe și să introducem o nouă clasă pentru a ne gestiona cârligele, o vom numi Hooks_Manager . Această clasă va fi responsabilă pentru înregistrarea tuturor cârligelor noastre. Deci, vom crea o nouă clasă cu o metodă 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 } }

Avem nevoie de o interfață pentru fiecare clasă care trebuie să înregistreze cârlige pentru a le implementa.

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

Vă puteți gândi la o interfață ca la un contract , în care o clasă care implementează acea interfață este „legată contractual” să implementeze toate metodele definite în acea interfață.

De exemplu, o clasă Login_Error care se conectează la acțiunea login_head , trebuie să implementeze metoda get_actions() a interfeței noastre Hooks .

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

Metoda register() a Hooks_Manager acceptă un obiect, îi apelează metoda get_actions() și înregistrează toate acțiunile sale.

 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 ); } }

Să adăugăm o metodă get_filters() la interfața noastră, astfel încât să putem înregistra atât acțiuni, cât și filtre.

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

Înapoi la clasa noastră Login_Error , trebuie să implementăm această nouă metodă 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 ), ); } }

Vom redenumi metoda register() a Hooks_Manager -ului nostru în register_actions() . Vom adăuga, de asemenea, o metodă register_filters() . Aceste două metode vor fi responsabile pentru înregistrarea acțiunilor și, respectiv, a filtrelor.

 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 ); } } }

Acum putem adăuga din nou o metodă register() , care pur și simplu va apela atât register_actions() cât și register_filters() .

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

Ce se întâmplă dacă o clasă nu trebuie să înregistreze atât acțiunile, cât și filtrele? Interfața Hooks conține două metode: get_actions() și get_filters() . Toate clasele care implementează acea interfață vor fi forțate să implementeze ambele metode.

 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(); } }

De exemplu, clasa Cookie_Login trebuie să înregistreze doar acțiuni, dar acum este forțată să implementeze metoda get_filters() doar pentru a returna o matrice goală.

Principiul de segregare a interfeței (ISP) , „I” în SOLID, afirmă:

„Niciun client nu ar trebui să fie forțat să depindă de metodele pe care nu le folosește.”

Înseamnă că ceea ce facem acum este exact ceea ce nu ar trebui să facem.

Segregarea interfeței

Putem remedia acest lucru împărțind interfața noastră în altele mai mici, mai specifice, astfel încât clasele noastre vor trebui să cunoască doar metodele care sunt de interes pentru ele.

 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(); }

Nu mai avem nevoie atât get_actions() cât și get_filters() , putem implementa doar interfața Actions și scăpăm 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 ), ); } }

Pe de altă parte, Login_Error , care are nevoie de acțiuni și filtre, trebuie doar să implementeze ambele interfețe. Clasele pot implementa mai multe interfețe, separându-le cu o virgulă.

 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 ), ); } }

Acum că ne-am separat interfața, trebuie doar să actualizăm metoda register() a Hooks_Manager pentru a reflecta modificările noastre.

 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 ); } } // ...

În acest fel, apelăm condiționat numai register_actions() , numai register_filters() sau ambele, pe baza interfețelor pe care obiectul specificat le implementează.

Pentru a utiliza efectiv managerul de cârlige:

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

Asta e! Acum putem folosi acel obiect pentru a gestiona cârlige în întreaga bază de cod.

Concluzie

Desigur, există mai multe moduri de a vă gestiona cârligele într-un mod orientat pe obiecte, tocmai v-am arătat una dintre ele. Ar trebui să experimentați și să găsiți unul care să se potrivească nevoilor dvs.

Rămâneți cu noi pentru ultima parte a acestei serii, unde vom vedea cum să gestionăm opțiunile într-un mod orientat pe obiecte, vom vorbi despre încapsulare, abstracție și cum să vă decuplăm clasele pentru a crea un plugin flexibil, ușor de extins!

Faceți clic aici pentru a citi Partea 8 din seria noastră de programare orientată pe obiecte

Vezi si

  • WordPress și programarea orientată pe obiecte – O prezentare generală
  • Partea 2 – WordPress și programarea orientată pe obiecte: un exemplu din lumea reală
  • Partea 3 – WordPress și programare orientată pe obiecte: Un exemplu WordPress – Definirea domeniului de aplicare
  • Partea 4 – WordPress și programare orientată pe obiecte: Un exemplu WordPress – Design
  • Partea 5 – WordPress și programare orientată pe obiecte: Un exemplu WordPress – Implementare: Meniul de administrare
  • Partea 6 – WordPress și programare orientată pe obiecte: un exemplu WordPress – Implementare: înregistrarea secțiunilor