Disons que chaque fois que je fais une opération CRUD ou que je modifie une relation d'une manière spécifique, je veux aussi faire autre chose. Par exemple, chaque fois que quelqu'un publie un article, je souhaite également enregistrer quelque chose dans une table à des fins d'analyse. Peut-être pas le meilleur exemple, mais en général, il y a beaucoup de cette fonctionnalité "groupée".
Normalement, je vois ce type de logique mis dans les contrôleurs. C'est très bien jusqu'à ce que vous souhaitiez reproduire cette fonctionnalité dans de nombreux endroits. Lorsque vous commencez à entrer dans les partiels, à créer une API et à générer du contenu factice, il devient difficile de garder les choses au sec.
Les façons dont j'ai vu pour gérer cela sont les événements, les référentiels, les bibliothèques et l'ajout aux modèles. Voici ma compréhension de chacun:
Services: c'est là que la plupart des gens mettront probablement ce code. Mon principal problème avec les services est qu'il est parfois difficile d'y trouver des fonctionnalités spécifiques et j'ai l'impression qu'ils sont oubliés lorsque les gens se concentrent sur l'utilisation d'Eloquent. Comment saurais-je que j'ai besoin d'appeler une méthode publishPost()
dans une bibliothèque alors que je peux simplement le faire $post->is_published = 1
?
La seule condition dans laquelle je vois que cela fonctionne bien est si vous utilisez UNIQUEMENT des services (et si vous rendez Eloquent inaccessible d'une manière ou d'une autre à tous les contrôleurs).
En fin de compte, il semble que cela ne ferait que créer un tas de fichiers supplémentaires inutiles si vos demandes suivent généralement la structure de votre modèle.
Référentiels: d' après ce que je comprends, c'est fondamentalement comme un service mais il y a une interface pour que vous puissiez basculer entre les ORM, dont je n'ai pas besoin.
Evénements: Je vois cela comme le système le plus élégant dans un sens parce que vous savez que les événements de votre modèle seront toujours appelés sur des méthodes Eloquent, vous pouvez donc écrire vos contrôleurs comme vous le feriez normalement. Je peux cependant voir que cela devient compliqué et si quelqu'un a des exemples de grands projets utilisant des événements pour un couplage critique, j'aimerais le voir.
Modèles: Traditionnellement, j'avais des classes qui exécutaient CRUD et géraient également le couplage critique. Cela a en fait facilité les choses car vous saviez que toutes les fonctionnalités autour de CRUD +, tout ce qui devait être fait, était là.
Simple, mais dans l'architecture MVC, ce n'est normalement pas ce que je vois faire. Dans un sens, je préfère cela aux services car c'est un peu plus facile à trouver et il y a moins de fichiers à suivre. Cela peut cependant devenir un peu désorganisé. J'aimerais entendre les inconvénients de cette méthode et pourquoi la plupart des gens ne semblent pas le faire.
Quels sont les avantages / inconvénients de chaque méthode? Est-ce que je manque quelque chose?
la source
Réponses:
Je pense que tous les modèles / architectures que vous présentez sont très utiles tant que vous suivez les principes SOLID .
Pour savoir où ajouter la logique, je pense qu'il est important de se référer au principe de responsabilité unique . Aussi, ma réponse considère que vous travaillez sur un projet moyen / grand. S'il s'agit d'un projet de projection de quelque chose sur une page , oubliez cette réponse et ajoutez-le tout aux contrôleurs ou aux modèles.
La réponse courte est: là où cela a du sens pour vous (avec des services) .
La réponse longue:
Contrôleurs : quelle est la responsabilité des contrôleurs? Bien sûr, vous pouvez mettre toute votre logique dans un contrôleur, mais est-ce la responsabilité du contrôleur? Je ne pense pas.
Pour moi, le contrôleur doit recevoir une requête et renvoyer des données et ce n'est pas le lieu pour mettre des validations, appeler des méthodes db, etc.
Modèles : est-ce un bon endroit pour ajouter une logique comme l'envoi d'un e-mail de bienvenue lorsqu'un utilisateur s'inscrit ou mettre à jour le décompte des votes d'un message? Que faire si vous devez envoyer le même e-mail depuis un autre endroit de votre code? Créez-vous une méthode statique? Et si ces e-mails ont besoin d'informations d'un autre modèle?
Je pense que le modèle devrait représenter une entité. Avec Laravel, j'utiliser uniquement la classe de modèle pour ajouter des choses comme
fillable
,guarded
,table
et les relations (c'est parce que j'utilise le modèle du référentiel, sinon le modèle aurait également lessave
,update
,find
, méthodes , etc.).Repositories (Repository Pattern) : Au début, j'étais très confus par cela. Et, comme vous, je me suis dit "eh bien, j'utilise MySQL et c'est tout.".
Cependant, j'ai équilibré les avantages et les inconvénients de l'utilisation du modèle de référentiel et maintenant je l'utilise. Je pense que maintenant , en ce moment même, je n'aurai plus qu'à utiliser MySQL. Mais, si dans trois ans je dois passer à quelque chose comme MongoDB, la plupart du travail est terminé. Le tout au détriment d'une interface supplémentaire et d'un
$app->bind(«interface», «repository»)
.Événements ( modèle d'observateur ): les événements sont utiles pour les choses qui peuvent être lancées à n'importe quelle classe à tout moment. Pensez, par exemple, à envoyer des notifications à un utilisateur. Lorsque vous en avez besoin, vous déclenchez l'événement pour envoyer une notification à n'importe quelle classe de votre application. Ensuite, vous pouvez avoir une classe comme
UserNotificationEvents
celle qui gère tous vos événements déclenchés pour les notifications utilisateur.Services : Jusqu'à présent, vous avez le choix d'ajouter une logique aux contrôleurs ou aux modèles. Pour moi, il est tout à fait logique d'ajouter la logique dans les services . Avouons-le, Services est un nom sophistiqué pour les classes. Et vous pouvez avoir autant de cours que cela vous convient dans le cadre de votre application.
Prenons cet exemple: il y a peu de temps, j'ai développé quelque chose comme Google Forms. J'ai commencé avec
CustomFormService
et a fini avecCustomFormService
,CustomFormRender
,CustomFieldService
,CustomFieldRender
,CustomAnswerService
etCustomAnswerRender
. Pourquoi? Parce que cela avait du sens pour moi. Si vous travaillez avec une équipe, vous devez placer votre logique là où elle a du sens pour l'équipe.L'avantage d'utiliser les services par rapport aux contrôleurs / modèles est que vous n'êtes pas contraint par un seul contrôleur ou un seul modèle. Vous pouvez créer autant de services que nécessaire en fonction de la conception et des besoins de votre application. Ajoutez à cela l'avantage d'appeler un service dans n'importe quelle classe de votre application.
Cela prend du temps, mais j'aimerais vous montrer comment j'ai structuré ma candidature:
J'utilise chaque dossier pour une fonction spécifique. Par exemple, le
Validators
répertoire contient uneBaseValidator
classe responsable du traitement de la validation, basée sur le$rules
et$messages
de validateurs spécifiques (généralement un pour chaque modèle). Je pourrais aussi facilement mettre ce code dans un service, mais il me semble logique d'avoir un dossier spécifique pour cela même s'il n'est utilisé que dans le service (pour l'instant).Je vous recommande de lire les articles suivants, car ils pourraient vous expliquer un peu mieux les choses:
Breaking the Mold de Dayle Rees (auteur de CodeBright): C'est là que j'ai mis tout cela ensemble, même si j'ai changé certaines choses pour répondre à mes besoins.
Découpler votre code dans Laravel à l'aide de référentiels et de services par Chris Goosey: Cet article explique bien ce qu'est un service et le modèle de référentiel et comment ils s'articulent.
Les laracasts ont également les référentiels simplifiés et à responsabilité unique qui sont de bonnes ressources avec des exemples pratiques (même si vous devez payer).
la source
Je voulais poster une réponse à ma propre question. Je pourrais en parler pendant des jours, mais je vais essayer de mettre cela en ligne rapidement pour être sûr de le lire.
J'ai fini par utiliser la structure existante fournie par Laravel, ce qui signifie que j'ai conservé mes fichiers principalement en tant que modèle, vue et contrôleur. J'ai également un dossier Bibliothèques pour les composants réutilisables qui ne sont pas vraiment des modèles.
JE N'AI PAS EMBALLÉ MES MODÈLES DANS DES SERVICES / BIBLIOTHÈQUES . Toutes les raisons fournies ne m'ont pas convaincu à 100% des avantages de l'utilisation des services. Bien que je puisse me tromper, pour autant que je sache, ils entraînent simplement des tonnes de fichiers supplémentaires presque vides que je dois créer et basculer entre les deux lorsque vous travaillez avec des modèles et réduisent également vraiment l'avantage d'utiliser des modèles éloquents (en particulier lorsqu'il s'agit de récupérer des modèles. , par exemple, en utilisant la pagination, les portées, etc.).
J'ai mis la logique métier DANS LES MODÈLES et l'accès éloquent directement depuis mes contrôleurs. J'utilise un certain nombre d'approches pour m'assurer que la logique métier n'est pas contournée:
Répondre aux préoccupations des gens concernant l'utilisation de modèles:
Note supplémentaire: J'ai l'impression que le fait d'emballer vos modèles dans des services, c'est comme avoir un couteau suisse, avec beaucoup d'outils, et construire un autre couteau autour de lui qui fait essentiellement la même chose? Ouais, parfois vous voudrez peut-être scotcher une lame ou vous assurer que deux lames sont utilisées ensemble ... mais il existe généralement d'autres façons de le faire ...
QUAND UTILISER LES SERVICES : Cet article présente très bien de GRANDS exemples d'utilisation des services ( indice: ce n'est pas très souvent ). Il dit essentiellement que lorsque votre objet utilise plusieurs modèles ou modèles à des parties étranges de leur cycle de vie, cela a du sens. http://www.justinweiss.com/articles/where-do-you-put-your-code/
la source
Ce que j'utilise pour créer la logique entre les contrôleurs et les modèles est de créer une couche de service . En gros, voici mon flux pour toute action au sein de mon application:
Voici comment je fais:
Voici la méthode d'un contrôleur pour créer quelque chose:
C'est la classe de service qui fait la logique liée à l'opération:
Et voici mon modèle:
Pour plus d'informations sur cette façon dont j'utilise pour organiser mon code pour une application Laravel: https://github.com/rmariuzzo/Pitimi
la source
$congregation->save();
vous n'aurez peut-être pas besoin de référentiels. Cependant, vous pouvez voir vos besoins d'accès aux données augmenter avec le temps. Vous pouvez commencer à avoir des besoins pour$congregation->destroyByUser()
ou$congregationUsers->findByName($arrayOfSelectedFields);
et ainsi de suite. Pourquoi ne pas dissocier vos services des besoins d'accès aux données. Laissez le reste de votre application travailler avec des objets / tableaux renvoyés par les dépôts, et gérez simplement la manipulation / le formatage / etc ... Vos dépôts grandiront (mais les diviser en différents fichiers, en fin de compte, la complexité d'un projet doit résider quelque part).À mon avis, Laravel a déjà de nombreuses options pour stocker votre logique métier.
Réponse courte:
Request
objets de laravel pour valider automatiquement votre entrée, puis persistez les données dans la requête (créez le modèle). Étant donné que toutes les entrées des utilisateurs sont directement disponibles dans la demande, je pense qu'il est logique de l'exécuter ici.Job
objets de laravel pour effectuer des tâches qui nécessitent des composants individuels, puis envoyez-les simplement. Je pense que celaJob
englobe les classes de service. Ils exécutent une tâche, telle que la logique métier.Réponse longue (heu):
Utiliser les référentiels lorsque cela est nécessaire: les référentiels sont voués à être surchargés et, la plupart du temps, sont simplement utilisés comme un
accessor
modèle. J'ai l'impression qu'ils ont certainement une certaine utilité, mais à moins que vous ne développiez une application massive qui nécessite autant de flexibilité pour que vous puissiez abandonner complètement laravel, restez à l'écart des dépôts. Vous vous remercierez plus tard et votre code sera beaucoup plus simple.Demandez-vous s'il y a une possibilité que vous changiez les frameworks PHP ou un type de base de données que laravel ne prend pas en charge.
Si votre réponse est "Probablement pas", n'implémentez pas le modèle de référentiel.
En plus de ce qui précède, veuillez ne pas gifler un motif sur un superbe ORM comme Eloquent. Vous ajoutez simplement de la complexité qui n'est pas requise et qui ne vous sera d'aucune utilité.
Utilisez les services avec parcimonie: les classes de service ne sont pour moi qu'un endroit où stocker la logique métier pour effectuer une tâche spécifique avec ses dépendances données. Laravel les a prêts à l'emploi, appelés «Jobs», et ils ont beaucoup plus de flexibilité qu'une classe de service personnalisée.
J'ai l'impression que Laravel a une solution complète pour le
MVC
problème de logique. C'est juste une question ou une organisation.Exemple:
Demande :
Contrôleur :
Dans l'exemple ci-dessus, l'entrée de la requête est automatiquement validée, et tout ce que nous avons à faire est d'appeler la méthode persist et de transmettre un nouveau message. Je pense que la lisibilité et la maintenabilité devraient toujours l'emporter sur les modèles de conception complexes et inutiles.
Vous pouvez ensuite utiliser exactement la même méthode persistante pour mettre à jour les publications, car nous pouvons vérifier si la publication existe déjà ou non et effectuer une logique alternée si nécessaire.
la source
ShouldQueue
fourni par Laravel. Si vous souhaitez écrire la logique métier dans une commande ou un événement, lancez simplement le travail à l'intérieur de ces événements / commandes. Les emplois Laravels sont extrêmement flexibles, mais en fin de compte, ce ne sont que des classes de service simples.