Les accesseurs et mutateurs sont des concepts connus en programmation objet qui trouvent leur équivalent dans Laravel.
En anglais, dans le monde de la programmation objet, on parlera de getters et de setters. En Laravel, on parlera d'accessors et de mutators.
Un accesseur est une méthode dont le rôle est de fournir la valeur d'un champ pour un enregistrement. La valeur du champ peut être donnée telle quelle, subir une transformation avant d'être retournée ou encore être calculée à partir de la valeur d'autres champs pour ce même enregistrement.
Par exemple, si on a un champ longueur dont la valeur est en pieds et que l'usager a configuré son application en métrique, il suffira de diviser la valeur du champ par 3,28084 pour qu'on ait l'impression que la valeur était stockée en mètres.
Voici un autre exemple, qui donne l'impression qu'une information est stockée dans un champ alors qu'elle est calculée à partir de la valeur d'autres champs. Il s'agit d'un accesseur qui donne le code d'un produit suivi de deux points puis de sa desription, une combinaison qui est souvent utilisée dans l'application :
// ******************************************************************
// Accesseurs et mutateurs.
// La fonction doit s'appeler get ou set suivi du nom à donner à la propriété puis du mot Attribute.
// Sera toujours utilisée comme s'il s'agissait d'une propriété dynamique.
// Ex : pour getCodeDescriptionAttribute : $produit->codeDescription
// ******************************************************************
/**
* Retrouve le code et la description du produit sous la forme code : description.
*
* @return string
*/
public function getCodeDescriptionAttribute()
{
return $this->code . ' : ' . $this->description;
}
Il est désormais facile d'obtenir le code et la description d'unp roduit :
{{ $produit->codeDescription }}
Remarquez que lors de la déclaration de la fonction, on utilisait une majuscule après le mot get mais que lors de l'appel, on utilisera une minuscule.
Un accesseur peut être utilisé lors des manipulations d'un enregistrement au même titre qu'un champ... ou presque.
Ce qu'il faut garder en tête, c'est que l'accesseur n'existe pas dans la base de données. Il existe seulement dans le modèle. On pourra donc utiliser l'accesseur lorsqu'une instruction travaille avec une instance du modèle ou avec une collection d'instances du modèle mais pas si elle travaille dans la base de données.
Dans cet exemple, la méthode pluck() est appliquée à un objet de type Builder. Cette méthode recherche donc directement dans la base de données. Ceci générera une erreur du genre « SQLSTATE[42S22]: Column not found: 1054 Unknown column 'codeDescription' in 'field list' ».
$produits = Produit::orderBy('code')->pluck('
', 'id');Il existe une autre version de pluck(), définie dans la classe Collection. On sait que lorsqu'on a en main une collection d'instances du modèle, on pourra utiliser les accesseurs sans problème. Il faut donc transformer le Builder en Collection.
L'astuce pour y parvenir consiste à exécuter la requête à l'aide de la méthode terminale get(). On aura alors en main une collection d'instances du modèle, à laquelle on pourra appliquer la méthode pluck() :
$produits = Produit::orderBy('code')->get()->pluck('codeDescription', 'id');
Prenon l'exemple de l'accesseur qui retourne le code et la description du produit. Il pourrait être intéressant d'ajouter un espace insécable avant les deux points afin d'assurer qu'à l'affichage, il n'y ait jamais de saut de ligne avant les deux points.
return $this->code . ' : ' . $this->description;
Depuis Laravel 5.6, la directive Blade {{ $produit->codeDescription }} fera en sorte que l'espace insécable sera doublement encodé, si bien que le navigateur affichera .
Pour éviter ceci, il est possible d'éviter le double encodage à l'aide d'une instruction placée dans la fonction boot() de la classe AppServiceProvider.
Ex :
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
// Pour éviter le double encodage dans Blade. Ceci était le comportement par défaut avant Laravel 5.6.
// Par exemple, si l'accesseur codeDescription retourne code : description, on veut que dans
// {{ $objet->codeDescription }}, l'espace insécable soit correctement interprété.
\Blade::withoutDoubleEncoding();
}
...
}
Il faudra ensuite prendre soin de vider le cache des vues pour que Laravel regénère les vues en prenant compte de la nouvelle directive.
php artisan view:clear
En programmation objet, un mutateur est une méthode dont le rôle est de modifier la valeur d'un champ de la classe. Sous Laravel, il est possible de faire subir une transformation à la valeur avant de la stocker dans le champ.
Ex :
/**
* Stocke le code du produit entièrement en lettres minuscules.
*
* @param $value
*/
public function setCodeAttribute($value)
{
// important : ne pas utiliser strtolower mais plutôt mb_strtolower sinon les accents sont convertis en caractères bizarres
$this->attributes['code'] = mb_strtolower($value);
}
Vous êtes maintenant assurés que le code d'un produit sera toujours en lettres minuscules et ce, même si on tente de lui mettre des majuscules :
$produit->code = 'ABC';
Si un champ contient une barre de soulignement dans son nom (casse_serpent), la partie centrale du mutateur qui permet de le transformer devra être en CassePascal.
Ex :
/**
* Stocke le nom de famille en assurant que la première lettre soit majuscule et que les autres soient minuscules.
*
* @param $value
*/
public function setNomFamilleAttribute($value)
{
$this->attributes['nom_famille'] = ucfirst(mb_strtolower($value));
}
Grâce à ce mutateur, dès qu'on enregistre un nom de famille, on est assuré qu'il sera dans le bon format.
Ex :
...
$client->nom_famille = 'COURTOIS'; // sera automatiquement converti au format spécifié dans le mutateur
$client->save();
« Eloquent: Mutators ». Laravel. https://laravel.com/docs/master/eloquent-mutators
« Using lists() in Laravel with custom attribute accessors ». Neon Tsunami. https://www.neontsunami.com/posts/using-lists()-in-laravel-with-custom-attribute-accessors (attention : ce tutoriel utilise la méthode lists() qui est désormais remplacée par pluck())
« Laravel Accessors and Mutators ». Bosnadev Code Factory. https://bosnadev.com/2015/12/17/laravel-accessors-mutators/
« Laravel Eloquent Accessors & Mutators: Why would I need them? ». Javier Núñez Fernández. http://www.javiernunez.com/laravel-eloquent-accessors-mutators
▼Publicité