Qualche giorno fa, lavorando ad alcuni progetti, mi sono ritrovato ad avere la necessità di usare uno switch in alcune view.
Ho dato uno sguardo alla documentazione ufficiale: niente. Ho fatto così una ricerca leggermente più approfondita, per trovare questa request di qualche mese fa. Con una risposta abbastanza lapidaria, Taylor liquidava temporaneamente la cosa con un “Not going to implement at this time”.
Più chiaro di così…
Certo, prima di continuare c’è qualche osservazione da fare: non sempre lo switch è sinonimo di codice elegante. Ricordando uno dei primi capitoli di “Laravel Testing Decoded“, di Jeffrey Way, quando ci sono troppi switch la cosa comincia a puzzare. C’è poco isolamento delle responsabilità, e così via.
Ad ogni modo nella vita di tutti i giorni, magari per una demo o per un qualcosa da realizzare velocemente, uno switch può sempre servire. Inoltre, da un punto di vista personale estetico, preferisco uno switch ad un if (else if, else if…), else.
Detto questo, vediamo come implementare lo switch per Blade.
Estendere Blade
Personalizzare Blade per i propri bisogni è davvero semplice. Come probabilmente già sai, Laravel “compila” le view realizzate con Blade in view elaborate e pronte ad essere usate.
Per creare un’estensione basta lavorare con il metodo Blade::extend().
Blade::extend(function($view, $compiler)
{
// la view contiene il codice, appunto, della view
return $view;
});
Il meccanismo di base è molto semplice. Il metodo extend prende in input una closure, che a sua volta presenta due argomenti: il primo, $view, è il codice della $view attualmente in fase di elaborazione. L’oggetto $compiler, invece, è il compilatore di Blade.
Su $view si può fare ogni tipo di operazione del caso, da un semplice str_replace _fino al _preg_replace.
La closure deve ritornare l’oggetto $view elaborato.
Lo switch, questo sconosciuto
La base di partenza per “costruire” il nostro switch è sicuramente la sua pagina sulla documentazione ufficiale. La sintassi che userò sarà quella alternativa:
Non c’è un motivo particolare per questa scelta: preferenza personale e nulla di più. La cosa si può fare tranquillamente anche con la sintassi più tradizionale, con le parentesi graffe.
Dando un’occhiata alla pagina sulla sintassi alternativa delle strutture di controllo, inoltre, veniamo a sapere che un costrutto del genere
Non funzionerebbe. Lo switch ed il suo primo case, infatti, devono trovarsi nello stesso blocco.
Occorre qualcosa del genere:
Un elemento da tenere a mente.
Scrittura del codice
L’obiettivo è creare un costrutto per Blade di questo tipo:
Value:
@switch($value)
@case(1)
Il valore è uno.
@break
@case(2)
Il valore è due.
@break
@default
Il valore non è uno, ma neanche due.
@break
@endswitch
I “pezzi” del nostro switch, quindi, saranno:
* Il blocco @switch (più il primo @case);
* Il singolo @case;
* Il @break;
* Il @default;
* L’@endswitch conclusivo;
Con le idee chiare in testa possiamo scrivere il codice:
Blade::extend(function($value, $compiler)
{
$value = preg_replace(‘/(?<=s)@switch((.))(s)@case((.*))(?=s)/’, ‘‘, $value);
$value = preg_replace(‘/(?<=s)@endswitch(?=s)/’, ‘‘, $value);
$value = preg_replace(‘/(?<=s)@case((.*))(?=s)/’, ‘‘, $value);
$value = preg_replace(‘/(?<=s)@default(?=s)/’, ‘‘, $value);
$value = preg_replace(‘/(?<=s)@break(?=s)/’, ‘‘, $value);
return $value;
});
Et voilà!
Per concludere, ecco alcune osservazioni riguardo possibili domande che ci si può porre:
* Non ho usato l’oggetto $compiler perché ho preferito lavorare direttamente sulla $view, senza passare per un altro oggetto. Ho voluto fare tutto tramite preg_replace, direttamente;
* I vari blocchi (s*) sono stati messi ai loro posti per rilevare eventuali spazi e ritorni a capo. In questo modo il codice rimane ordinato anche quando compilato da Blade a PHP vero e proprio;
* Ogni miglioramento è ben accetto. Se hai qualche suggerimento lascia pure un commento e ne parliamo insieme!
Edit: Grazie a kylekatarnis su Github per il feedback.