Laravel 8.77.0 cover image

Laravel 8.77.0

alberto • December 27, 2021

release

I rilasci di Laravel vanno avanti imperterriti secondo la tabellina di marcia. Qualche giorno fa è stata rilasciata infatti la versione 8.77.0.

La novità piú importante arriva direttamente da Taylor e riguarda una caratteristica dei Model, ed in particolare gli Accessors e i Mutators.

Cosa sono?

Gli accessors e i mutators sono delle particolari funzioni che permettono di modificare il comportamento dei nostri modelli di business e permettono di incapsulare logica direttamente all'interno dei Model cosi da poterle riutilizzare in diversi punti della nostra applicazione.

Accessors

Gli Accessors permettono di trasformare un attributo di un modello nel momento in cui questo viene recuperato tramite la sintassi ->attributo. Per poter implementare un accessors è necessario definire all'interno dei nostri Model, un metodo dal nome get{Attributo}Attribute facendogli ritornare il valore appunto modificato.

Facciamo un esempio chiarificatore. Se nel nostro applicativo c'è la necessità di accedere spesso all'indirizzo completo di un cliente, componendo, per esempio, indirizzo, cap e città, potremmo implementare un metodo simile a questo:

class Customer extends Model {

    public function getCompleteAddressAttribute()
    {
        return $this->address . ' (' . $this->cap . ') - ' . $this->city;
    }
}

In questo modo, ogni volta che in un controller, in una view o in qualsiasi altro componente scriveremo $customer->complete_address, Laravel ci ritornerà una stringa composta da i tre elementi che compongono l'indirizzo completo.

Gli attributi creati non devono per forza essere nuovi: è anche possibile modificare, sempre con la stessa sintassi, attributi già presenti e magari mappati con una colonna del database.

Per esempio, qualora volessimo stampare sempre la mail di un utente in formato lowercase, potremmo scrivere:

class User extends Model {

    public function getEmailAttribute($originalValue)
    {
        return strtolower($originalValue);
    }
}

In questo caso, dato che il valore della property email è valorizzato, possiamo recuperare il parametro $originalValue e applicarci le nostre trasformazioni.

Mutators

I mutators sono l'altra faccia della medaglia, ovvero sono funzioni che permettono di modificare il valore di un attributo quando questo viene impostato all'esterno di un Model. Anche in questo caso, l'implementazione è triviale ed avviene tramite la definizione di un metodo dal nome set{Attributo}Attribute.

Pensiamo per esempio al caso in cui si voglia forzare il case di un particolare campo, ad esempio il cognome, impostando l'iniziale di ogni parola in maiuscolo. Potremmo semplicemente scrivere:

class Customer extends Model {

    public function setLastNameAttribute($originalValue)
    {
        $this->attributes['last_name'] = ucwords($originalValue);
    }
}

In questo caso, anche andando a scrivere $user->last_name = 'briganti vien dal mare', quello che ci ritroveremmo nella property è Briganti Vien Dal Mare. Da notare l'utilizzo della mappa attributes qualora volessimo modificare un attributo utile per evitare cicli infiniti di invocazione.

Cosa cambia in Laravel 8.77?

Quello che viene di fatto aggiunto è la possibilità di implementare accessors e mutators con un'altra modalità.

La modifica è comunque retrocompatibile e l'approccio precedente rimane perfettamente funzionante.

Tutto si basa su una nuova classe, Illuminate\Database\Eloquent\Casts\Attribute che racchiude al suo interno sia la logica di get che di set di, appunto, un attributo.

Riprendendo gli esempi di prima, possiamo riscriverli in questo modo:

class Customer extends Model {

    public function completeAddress() : Attribute
    {
        return new Attribute(
            get: fn($value) => $this->address . ' (' . $this->cap . ') - ' . $this->city;
        );
    }

    public function lastName() : Attribute
    {
        return new Attribute(
            set: fn($value) => ucwords($value);
        );
    }
}

Questo nuovo approccio presenta notevoli vantaggi rispetto all'implementazione precedente:

Ancora una volta, ben fatto Taylor!

Ma.. come fanno questi metodi a funzionare?

Senza entrare nei dettagli implementativi, sia accessors che mutators sfruttano una caratteristica degli oggetti in PHP, ovvero i magic methods, metodi particolari che vengono invocati automaticamente dall'engine all'accadere di qualcosa.

In particolare il magic method che viene in questo caso interpellato è __call. Probabilmente approfondiremo la questione in un ulteriore articolo.

Per i piú curiosi lascio un link alla documentazione ufficiale.