Laravel Blade: come creare direttive personalizzate

Lavorando quasi ogni giorno su Laravel, ho imparato ad apprezzare Blade e le sue direttive che all’inizio, lo confesso, trovavo in alcuni casi inutili e scomode.

Laravel: gestire le traduzioni (in modo SEO friendly)

Eppure, giorno dopo giorno, mi sono ritrovato a utilizzarle sempre più spesso, tanto che nei pochi casi in cui non è prevista una direttiva, ho lentamente iniziato a sentirne la mancanza e a desiderare di crearne di nuove, anche solamente per uniformità stilistica del codice.

Ma andiamo con ordine. Per prima cosa…

siteground-banner

Che cosa sono le direttive di Laravel Blade?

In poche parole, una direttiva è una funzione che ritorna una porzione di codice, solitamente in base a una o più condizioni.

La loro sintassi prevede l’utilizzo di una @ seguita dal nome della direttiva e, come per le normali funzioni PHP, una lista di parametri che possiamo passare tra parentesi tonde separati da una virgola.

@nomeDirettiva( $parametro1, $parametro)

In questo caso la direttiva non ha contenuto, ma puoi tranquillamente trovarle in una forma diversa, che prevede il contenuto. Un esempio piuttosto comune:

@section('nomeSezione') <!-- Contenuto HTML --> @show

Ciò che devi sempre tenere presente è che anche se con una direttiva non apri esplicitamente i tag PHP, quando ti trovi tra le parentesi tonde, devi scrivere direttamente codice PHP. Ti ci abituerai con un po’ di pratica.

Se hai familiarità con il mondo WordPress, comunque, potremmo dire che una direttiva è concettualmente molto simile a uno shortcode.

Laravel Blade: le direttive che mi sono mancate

Personalmente non amo particolarmente la sintassi PHP che ci permette di rilasciare attributi HTML o i loro valori in modo dinamico. Se ad esempio volessimo impostare il valore off per l’attributo autocomplete basandoci sul valore di una variabile PHP dovremmo utilizzare una sintassi di questo tipo:

<input type="text" <?php if($condition): echo 'autocomplete="off"'; endif; ?> ...>

oppure

<input type="text" <?= ($condition ? 'autocomplete="off"' : '') ?> ...>

In entrambi i casi trovo molto poco leggibile il codice. Sarebbe molto meglio poter utilizzare una direttiva. La sintassi diventerebbe dunque questa:

<input type="text" @autocompleteOff($condition) ...>

Molto meglio, non credi?

Creare una direttiva per Laravel Blade

Creare una nuova direttiva per Blade è veramente molto semplice e abbiamo a disposizione due strade. La prima, più rapida, è quella di utilizzare la classe App\Providers\AppServiceProvider. La seconda, sicuramente più pulita ed elegante è quella di creare un nuovo ServiceProvider e registrarlo tra quelli utilizzati dalla tua app Laravel.

Per creare un nuovo ServiceProvider puoi utilizzare Artisan:

php artisan make:provider BladeServiceProvider

Una volta creato, devi inserirlo all’interno dei provider utilizzati dalla app nel file config/app.php. Nel nostro esempio, alla chiave ‘providers’ aggiungeremo:

'providers' => [
   ...
   App\Providers\BladeServiceProvider::class,
],

Scrivere il codice della direttiva

È arrivato ora il momento di scrivere il codice che gestisce la nostra direttiva e dovremo inserirlo all’interno del metodo boot() del provider appena creato. Utilizziamo la facade Blade e aggiungiamo il codice che segue:

Blade::directive( 'autocompleteOff', function ( ?string $arg ) {
    if ( json_decode( $arg ) === true ) {
        return "<?php echo 'autocomplete=\"off\"'?>";
    }
} );

Come puoi vedere, il metodo directive accetta come primo parametro una stringa contenente il nome della direttiva e come secondo la callback che restituisce il codice necessario.

Devi assolutamente prestare attenzione a una cosa: sia l’argomento della callback, sia il dato restituito sono stringhe. Torneremo tra poco sul parametro in ingresso. Per il momento soffermiamoci su ciò che viene ritornato.

Come vedi, pur essendo all’interno dei tag PHP, ritorniamo comunque una stringa che apre e chiude di nuovo gli stessi tag. Questo perché il testo ritornato dalla callback sarà sostituito da Blade al testo utilizzato per richiamare la direttiva e siccome la chiamata avviene in HTML, dobbiamo aprire i tag di PHP.

Come detto, abbiamo anche un parametro, che a sua volta viene passato come stringa. Se la condizione della direttiva autocomplete è vera riceveremo ‘true’, mentre se è falsa otterremo ‘false’. Dobbiamo tenerne conto nel momento in cui facciamo controlli all’interno della callback:

if( $arg === 'true') // OK
if( json_decode($arg) === true) //OK
if($arg === true) // Condizione sempre falsa

Creare una direttiva con due parametri

Cosa facciamo normalmente quando dobbiamo scrivere qualcosa solo se una condizione è vera?

<input <?php if(!empty($attributeValue) echo "attribute='$attributeValue'"; ?> ...>
//oppure
<input <?= (!empty($attributeValue) : "attribute='$attributeValue'" : '') ?> ...>

o ancora, sfruttando meglio Blade:

<input @unless(empty($attributeValue)) echo "attribute='$attributeValue'" @endunless

Ancora una volta non amo particolarmente la leggibilità. Vorrei poter utilizzare una direttiva in questo modo:

<input @echoIf("attribute='$attributeValue'", !empty($attributeValue)) ... >
//oppure
<input @echoUnless("attribute='$attributeValue'", empty($attributeValue)) ... >

Come vedi, in questo caso abbiamo la necessità di utilizzare due parametri. Nel primo passiamo ciò che deve essere stampato, nel secondo la condizione che determina se l’azione deve essere portata a termine oppure no.

Vediamo subito il codice della direttiva:

Blade::directive( 'echoIf', function ( ?string $args ) {
    $args = explode( ',', $args );
    return "<?php if({$args[1]}){ echo {$args[0]};} ?>";
} );

Come vedi in questo caso dobbiamo affrontare un piccolo problema. Nonostante la direttiva utilizzi due valori, la callback ha solamente un parametro in ingresso e questo sarà una stringa contenente tutto ciò che abbiamo scritto tra le parentesi tonde della direttiva.

Nell’esempio di echoIf riceveremo dunque:

'"attribute='$attributeValue'", empty($attributeValue)'

ed è esattamente per questo motivo che dovremo per prima cosa utilizzare la funzione explode sulla stringa e poi utilizzare i due elementi dell’array risultante per costruire la stringa di codice che verrà ritornata dalla callback.

emoji_objects

Nota che il separatore che utilizzi per explode deve essere esattamente quello che utilizzi per separare i parametri della direttiva, spazi compresi!

Un ultimo passaggio: pulire la cache delle viste

Questo è un passaggio su cui, quando ho creato la mia prima direttiva, ho perso parecchio tempo! Ricorda che Laravel ha una cache specifica per le viste, quindi quando crei una nuova direttiva o ne modifichi una creata in precedenza, per riuscire a vedere gli effetti delle modifiche apportate devi pulire la cache. Puoi farlo utilizzando Artisan e il comando è:

php artisan view:clear

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. Tutti i campi sono obbligatori.