Création d'applications de domaine ciblées. Une approche Symfony (Partie 1)

Patricia Arquette
Libérer: 2024-11-03 10:52:29
original
668 Les gens l'ont consulté

Introduction

C'est le premier article d'une série que j'ai décidé de créer afin d'expliquer comment j'organise mes applications symfony et comment j'essaie d'écrire du code le plus orienté domaine possible.
Ci-dessous, vous pouvez trouver l'organigramme que j'utiliserai pendant toutes les parties de la série. Dans chaque article, je me concentrerai sur une partie concrète du diagramme et j'essaierai d'analyser les processus impliqués et de détecter quelles parties appartiendraient à notre domaine et comment se découpler des autres parties à l'aide de couches externes.

Creating focused domain applications. A Symfony approach (Part 1)

Décomposer le traitement des données

Dans cette première partie, nous nous concentrerons sur les processus d'extraction et de validation des données. Pour le processus d'extraction des données, nous supposerons que les données de la demande sont formatées en JSON.

Extraire les données

Basé sur le fait que nous savons que les données de la requête font partie de la charge utile de la requête JSON, extraire la charge utile de la requête (dans ce cas, extraire signifie obtenir un tableau à partir de la charge utile JSON) serait aussi simple que d'utiliser la fonction php json_decode.

class ApiController extends AbstractController
{
    #[Route('/api/entity', name: 'api_v1_post_entity', methods: ['POST'])]
    public function saveAction(Request $request,): JsonResponse
    {
        $requestData = json_decode($request->getContent(), true);
        // validate data
    }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Valider les données

Pour valider les données, nous avons besoin de trois éléments :

  • Un pour définir les règles de validation.
  • Un pour transformer les données demandées en un objet validable.
  • Un pour valider les données extraites en fonction de ces règles.

Définir les règles de validation

Pour le premier, nous allons créer un DTO (Data Transfer Object) qui représentera les données entrantes et nous utiliserons les attributs de contraintes de validation Symfony pour préciser comment ces données doivent être validées.

readonly class UserInputDTO {
    public function __construct(
        #[NotBlank(message: 'Email cannot be empty')]
        #[Email(message: 'Email must be a valid email')]
        public string $email,
        #[NotBlank(message: 'First name cannot be empty')]
        public string $firstname,
        #[NotBlank(message: 'Last name cannot be empty')]
        public string $lastname,
        #[NotBlank(message: 'Date of birth name cannot be empty')]
        #[Date(message: 'Date of birth must be a valid date')]
        public string $dob
    ){}
}
Copier après la connexion

Comme vous pouvez le constater, nous avons défini nos règles de validation des données d'entrée au sein du DTO récemment créé. Ces règles sont les suivantes :

  • e-mail : ne peut pas être vide et doit être un e-mail valide
  • prénom : ne peut pas être vide
  • nom : ne peut pas être vide
  • dob (Date de naissance) : Ne peut pas être vide et doit être une date valide.

Dénormalisation des données de la requête dans le DTO

Pour le second, nous utiliserons le composant normaliseur Symfony grâce auquel nous pourrons mapper les données entrantes de la requête dans notre DTO.

class ApiController extends AbstractController
{
    #[Route('/api/entity', name: 'api_v1_post_entity', methods: ['POST'])]
    public function saveAction(Request $request, SerializerInterface $serializer): JsonResponse
    {
        $requestData = json_decode($request->getContent(), true);
        $userInputDTO = $serializer->denormalize($requestData, UserInputDTO::class);
    }
}
Copier après la connexion

Comme indiqué ci-dessus, la méthode denormalize fait le travail et avec une seule ligne de code, nous obtenons notre DTO rempli avec les données entrantes.

Validation du DTO

Enfin, pour valider les données nous nous appuierons sur le service validateur Symfony qui recevra une instance de notre DTO récemment dénormalisé (qui transportera les données entrantes) et validera les données selon les règles DTO.

class ApiController extends AbstractController
{
    #[Route('/api/entity', name: 'api_v1_post_entity', methods: ['POST'])]
    public function saveAction(Request $request,): JsonResponse
    {
        $requestData = json_decode($request->getContent(), true);
        // validate data
    }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Identifier le domaine

Jusqu'à présent, nous avons décomposé le processus d'Extraction et de Validation des données en quatre parties :

  • Extraire un tableau de la charge utile de la requête JSON.
  • Créez un DTO pour représenter les données entrantes et leurs règles de validation.
  • Dénormalisez le tableau en un DTO qui contient les règles de validation.
  • Validez le DTO.

La question est maintenant : laquelle de ces parties appartient à notre domaine ?
Pour répondre à la question, analysons les processus impliqués :

1.- Extraction des données : Cette partie utilise uniquement la fonction "json_decode" pour transformer les données entrantes de json en tableau. Il n'ajoute pas de logique métier, donc cela n'appartient pas au domaine.

2.- Le DTO : Le DTO contient les propriétés associées aux données d'entrée et comment elles seront validées. Cela signifie que le DTO contient des règles métier (les règles de validation) et qu'il appartiendrait donc au domaine.

3.- Dénormaliser les données : Cette partie utilise simplement un service d'infrastructure (un composant de framework) pour dénormaliser les données en un objet. Cela ne contient pas de règles commerciales, donc cela n'appartient pas à notre domaine.

4.- Validation des données : De la même manière que le processus Dénormaliser les données, le processus de validation des données utilise également un service d'infrastructure (un composant de framework) pour valider les données entrantes . Celui-ci ne contient pas de règles métier puisqu'elles sont définies dans le DTO donc cela ne ferait pas non plus partie de notre domaine.

Après avoir analysé les derniers points, nous pouvons conclure que seul le DTO fera partie de notre domaine. Alors, que fait-on du reste du code ?

Création d'un service applicatif

Personnellement, j'aime inclure ce genre de processus (extraction, dénormalisation et validation de données) dans la couche application ou la couche service. Pourquoi ?, introduisons la couche application.

La couche Application

En bref, la couche application est responsable de l'orchestration et de la coordination, laissant la logique métier à la couche domaine. De plus, il agit comme intermédiaire entre la couche domaine et les couches externes telles que la couche présentation (UI) et la couche infrastructure.
À partir de la définition ci-dessus, nous pourrions inclure les processus Extraction, Dénormalisation et Validation dans un service de la couche application puisque :

  • Il coordonne les processus de données entrantes.
  • Il utilise les services d'infrastructure (fonction PHP JSON, composant de normalisation Symfony et composant de validation Symfony) pour traiter les données entrantes.
  • Il applique les règles du domaine en passant le DTO au service d'infrastructure de validation.

Parfait, nous allons créer un service applicatif pour gérer ces processus. Comment allons-nous faire ? Comment allons-nous gérer les responsabilités ?

Analyser les responsabilités

Le principe de responsabilité unique (SRP) stipule que chaque classe ne doit être responsable que d'une partie du comportement de l'application. Si une classe a plusieurs responsabilités, elle devient plus difficile à comprendre, à maintenir et à modifier.

Comment cela nous affecte-t-il ? Analysons-le.
Jusqu’à présent, nous savons que notre service applicatif doit extraire, dénormaliser et valider les données entrantes. Sachant cela, il est facile d'extraire les responsabilités suivantes :

  • Extraire les données
  • Dénormaliser les données
  • Valider les données

Faut-il diviser ces responsabilités en 3 services différents ? Je ne pense pas. Laissez-moi vous expliquer.

Comme nous l'avons vu, chaque responsabilité est gérée par une fonction ou un composant de l'infrastructure :

  • Extraction de la responsabilité : fonction PHP json_decode
  • Dénormaliser la responsabilité des données : composant normalisateur Symfony
  • Valider la responsabilité des données : Composant de validation Symfony

Comme le service applicatif peut déléguer ces responsabilités aux services d'infrastructure, nous pouvons créer une responsabilité plus abstraite (Processus des données) et l'attribuer au service applicatif.

class ApiController extends AbstractController
{
    #[Route('/api/entity', name: 'api_v1_post_entity', methods: ['POST'])]
    public function saveAction(Request $request,): JsonResponse
    {
        $requestData = json_decode($request->getContent(), true);
        // validate data
    }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Comme indiqué ci-dessus, le service d'application DataProcessor utilise la fonction json_decode et le service de normalisation et de validation Symfony pour traiter la demande d'entrée et renvoyer un DTO frais et validé. On peut donc dire que le service DataProcessor :

  • Coordonne toutes les tâches liées au traitement des données d'entrée.
  • Communique avec le monde extérieur (services d'infrastructure) avec les règles métier du domaine (DTO).

Comme vous l'avez peut-être remarqué, le service DataProcessor renvoie une ValidationException Symfony lorsque le processus de validation trouve une erreur. Dans le prochain article de cette série, nous apprendrons comment appliquer nos règles métier pour structurer les erreurs et enfin les présenter au client.

Je sais que nous pourrions supprimer le service DataProcessor et utiliser MapRequestPayload comme couche d'application de service pour extraire, dénormaliser et valider les données mais, étant donné le contexte de cet article, j'ai pensé qu'il était plus pratique de écrivez-le de cette façon.

Conclusion

Dans ce premier article, nous nous sommes concentrés sur les processus d'extraction et de validation des données à partir du diagramme de flux. Nous avons répertorié les tâches impliquées dans ce processus et nous avons appris à détecter quelles parties appartiennent au domaine.
Sachant quelles parties appartiennent au domaine, nous avons écrit un service de couche d'application qui connecte les services d'infrastructure régis par le domaine et coordonne le processus d'extraction et de validation des données.
Dans le prochain article, nous explorerons comment définir nos règles métier pour gérer les exceptions et nous créerons également un service de domaine qui se chargera de transformer l'Input DTO en une entité persistante.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal