Un mod simplu de a implementa „Open-Closed principle” în WordPress

OCP este unul dintre principiile SOLID despre care am mai scris și aici. Vreau să-ți arăt o modalitate simplă prin care poți implementa asta chiar dacă nu ești fan OOP: folosind filtre! Sigur, nu este foarte încapsulată toată povestea, dar cred că este un compromis care merită făcut în majoritatea cazurilor.

La proiectul la care lucrez zilele astea am o chestie care m-a făcut să mă gândesc la treaba asta. Am o listă de vreo 30-40 meta-fields, iar la câteva vreau să aplic câteva transformări, în funcție de tipul lor (e.g. dată, formatare text, galerie etc).

Prima soluție la care te gândești este, probabil, un switch/case:

switch( $key ) {
  case 'description':
    $value = wpautop($value);
    break;
  case 'date':
    $value = \DateTime::createFromFormat(/*...*/);
    break;
  case 'gallery':
    $value = formatMyGalleryField($content);
    break;
  // .....
}

Vezi deja unde ne îndreptăm: pentru fiecare caz în parte avem de adăugat o condiție. Lucrurile încep să se complice și mai mult când vrem să aplicăm două sau mai multe transformări sau când vrem o ordine diferită a transformărilor în funcție de $key.

Filtre!

Toată condiția de mai sus s-ar putea rescrie mai simplu

$value = apply_filters("ntz/transformations/key={$key}", $value, $key ... )

Unul din lucrurile care cred că sunt prea puțin folosite în lumea WP este posibilitatea de a folosi orice caractere în numele filtrelor, motiv pentru care vedem filtre ceva mai greu de citit (decât ar putea fi). De ce ai folosi underscore în loc de slash?

Simplu, nu?

Următorul pas este să adaugi toate filtrele de care ai nevoie:

add_filter('ntz/transformation/key=description', 'wpautop');
add_filter('ntz/transformation/key=date', 'myDateFormatter');
// ....

Vrei să adaugi mai multe transformări pentru același filtru? Nici o problemă!

add_filter('ntz/transformation/key=description', 'myDateFormatter');
add_filter('ntz/transformation/key=description', 'wpautop');
// ....

Ordinea nici măcar nu e foarte importantă, având în vedere că al treila parametru poate fi un integer ce reprezintă ordinea (sau prioritatea) de execuție.

img src

Principii SOLID în practică

Am fost întrebat mai deunăzi dacă pot îmbunătăți codul de mai jos:

class Tooltip
{
  protected $dataIsProcessed = false;

  public function __construct(array $data) {
    $this->data = $data;  
  }

  protected function processData() {
    if($this->dataIsProcessed) {
      return;
    }

    $this->dataIsProcessed = true;

    $this->data = array_merge([
      'title' => '',
      'body' => '',
      'meta' => ''
    ], $this->data);

    $this->data['body'] = stripslashes($this->data['body']);
    $this->data['title'] = do_some_stuff_with_the_title($this->data['title']);
    $this->data['meta'] = do_some_other_stuff_with_meta($this->data['meta']);
  }

  protected function getAttribute($attribute) {
    $this->processData();
    return $this->data[$attribute] ?? '';
  }

  public function style1() {
    return sprintf('<h2>%s</h2>',
      $this->getAttribute('title')
    );
  }

  public function style2() {
    printf('<h2>%s</h2><p>%s</p>',
      $this->getAttribute('body')
    );
  }

  public function style3() {
    return sprintf('<p>%s</p><div>%s</div>',
      $this->getAttribute('body'),
      $this->getAttribute('meta')
    );
  }
}


$tooltip = new Tooltip([
  'title' => 'Hello World!',
  'body' => 'Nice to meet you.',
  'meta' => 'Last update: last year'
])

echo $tooltip->style1();
echo $tooltip->style2();
echo $tooltip->style3();

Continuă să citești Principii SOLID în practică