[PHP] [Laravel] Repository (Convertir Eloquent en stdClass)

Catégorie: Web (Mis à jour le 18-06-2014 17:43:00)

Le RepositoryPattern est souvent présenté comme la solution de découplage entre les modéles et le controlleur. Ce patron de conception est souvent évoqué sur les sites comme laravel.io.

Malheureusement, l'appliquer correctement est légérement plus complexe qu'il n'y parait.

Le problème

Interposer un Repository entre son modéle et son controlleur est une bonne pratique pour une application maintenable sur le long terme. Ce découpage permet en effet de séparer totalement le controlleur du modele. Ainsi, si plus tard dans la vie de l'application vous désirez utiliser un autre systeme de stockage comme Redis, il n'y aurai qu'a adapter le Repository et tous vos Controlleurs et Vues fonctionnerons sans aucun changement.

La plupart du temps, les implémentations proposées font abstraction de la partie creation du modéle. C'est exactement le role de ces Repository. Par contre, elles retournent directement les modeles Eloquent au controlleur, ce qui casse totalement leur interet. Votre controlleur se retrouve alors dépendant d'Eloquent, et un simple appel à une méthode de cet ORM risque de casser toute votre application.

Comment découpler totalement Eloquent

Pour cela, il faut imaginer le Repository comme une barriére. Du coté de votre Controlleur, aucune référence a Eloquent ne doit pouvoir être trouvée. Au moment du passage, le Repository doit donc extraire les informations du modéle et les retourner via un autre objet (indépendant d'Eloquent).

Bien sur sur github il existe des packages pour creer des objets indépendants d'Eloquent. On trouve notamment stidges/laravel-db-normalizer qui normalise automatiquement les modeles Eloquent en un format générique.

Ces packages sont complets et fonctionnent. Mais a t'on vraiment besoin d'un tel déployement de force pour ça?

La solution

Une solution simplissime consiste à s'inspirer des fonctions proposées nativement par laravel. En effet, les modeles proposent déjà deux fonctions d'export, respectivement toArray et toJson. Ces deux fonctions retournent un objet qui contient toutes les données du modéle, mais sans aucune référence à Eloquent. L'objectif est donc accompli (en partie).

Le gros probléme avec un repository qui apelle toArray avant chaque retour réside dans le format de retour. En effet, actuellement avec Eloquent, nos vues font des appels qui ressemblent a:

{{ $user->username }}

Or, avec toArray, il va falloir réécrire toutes ces lignes comme cela:

{{ $user['username'] }}

Si c'est le début d'un projet, ça peux être jouable, mais comme la syntaxe de l'array est moins ergonomique que celle de l'objet, il va donc falloir retourner nos array sous forme d'objets. Php dispose d'un objet spécialement conçu pour ça: le stdClass.

Ainsi donc on va créer une méthode toObject dans nos modeles qui va renvoyer un stdClass contenant les valeurs telles que toArray les renvoie (pour rester consistant).

La suite consiste à creer un type de Collection qui implemente une méthode toObject() qui renverra un array contenant la représentation via toObject des modeles contenus.

Le code

Pour simplifier, j'ai implémenté les deux fonctions dans la même méthode, à placer dans un helper quelconque (votre repository par exemple).

N'hésitez pas à suggerer des améliorations dans les commentaires!

Aller plus loin

Afin de standardiser cette aproche dans mes projets, j'ai découplé cette fonctionnalitée à travers un package. Ce package est disponible sur github

A lire aussi:

[PHP] [Laravel] Changer le format de date Eloquent

[Web] Voici un petit bout de code bien utile qui permet de changer le format de date retourné par défaut par les modeles Eloquent. Utile pour localiser simplement les dates de son site dynamiquement par exemple.
Suite...

Boostez les performances de PHP avec memcache

[Web] Memcache est un serveur de cache en RAM. Découvrez ce qu'apporte cette solution par rapport à une solution de cache disque classique.
Suite...