Heim  >  Artikel  >  Backend-Entwicklung  >  Erstellen fokussierter Domänenanwendungen. Ein Symfony-Ansatz (Teil 1)

Erstellen fokussierter Domänenanwendungen. Ein Symfony-Ansatz (Teil 1)

Patricia Arquette
Patricia ArquetteOriginal
2024-11-03 10:52:29662Durchsuche

Einführung

Dies ist der erste Beitrag einer Reihe, die ich erstellt habe, um zu erklären, wie ich meine Symfony-Anwendungen organisiere und wie ich versuche, Code so domänenorientiert wie möglich zu schreiben.
Unten finden Sie das Flussdiagramm, das ich in allen Teilen der Serie verwenden werde. In jedem Beitrag werde ich mich auf einen konkreten Teil des Diagramms konzentrieren und versuchen, die beteiligten Prozesse zu analysieren und herauszufinden, welche Teile zu unserer Domäne gehören würden und wie man sich mithilfe externer Ebenen von den anderen Teilen entkoppeln kann.

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

Aufschlüsselung der Datenverarbeitung

In diesem ersten Teil konzentrieren wir uns auf die Datenextraktions- und Validierungsprozesse. Für den Datenextraktionsprozess gehen wir davon aus, dass die Anforderungsdaten im JSON-Format vorliegen.

Extrahieren der Daten

Aufgrund der Tatsache, dass wir wissen, dass die Anforderungsdaten in der JSON-Anforderungsnutzlast enthalten sind, wäre das Extrahieren der Anforderungsnutzlast (in diesem Fall bedeutet Extrahieren das Erhalten eines Arrays aus der JSON-Nutzlast) genauso einfach wie die Verwendung der PHP-Funktion 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
    }
}

Validierung der Daten

Um die Daten zu validieren, benötigen wir drei Elemente:

  • Eine zum Definieren der Validierungsregeln.
  • Eine zum Umwandeln der angeforderten Daten in ein validierbares Objekt.
  • Eine zum Validieren der extrahierten Daten basierend auf diesen Regeln.

Definieren der Validierungsregeln

Für das erste erstellen wir ein DTO (Data Transfer Object), das die eingehenden Daten darstellt, und verwenden die Symfony-Validierungseinschränkungsattribute, um anzugeben, wie diese Daten validiert werden müssen.

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
    ){}
}

Wie Sie sehen können, haben wir unsere Eingabedatenvalidierungsregeln innerhalb des kürzlich erstellten DTO definiert. Diese Regeln sind die folgenden:

  • E-Mail: Darf nicht leer sein und muss eine gültige E-Mail sein
  • Vorname: Darf nicht leer sein
  • Nachname: Darf nicht leer sein
  • Geburtsdatum (Geburtsdatum): Darf nicht leer sein und muss ein gültiges Datum sein.

Denormalisierung der Anforderungsdaten in das DTO

Für die zweite Variante verwenden wir die Symfony-Normalisierungskomponente, mit der wir die eingehenden Anforderungsdaten unserem DTO zuordnen können.

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);
    }
}

Wie oben gezeigt, erledigt die Methode denormalize das Zeug und mit einer einzigen Codezeile füllen wir unser DTO mit den eingehenden Daten.

Validierung des DTO

Zur Validierung der Daten verlassen wir uns schließlich auf den Symfony-Validierungsdienst, der eine Instanz unseres kürzlich denormalisierten DTO empfängt (das die eingehenden Daten überträgt) und die Daten gemäß den DTO-Regeln validiert.

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
    }
}

Identifizieren der Domäne

Bisher haben wir den Prozess des Extrahierens und Validierens von Daten in vier Teile unterteilt:

  • Extrahieren Sie ein Array aus der JSON-Anfragenutzlast.
  • Erstellen Sie ein DTO, um die eingehenden Daten und ihre Validierungsregeln darzustellen.
  • Denormalisieren Sie das Array in ein DTO, das die Validierungsregeln enthält.
  • Validieren Sie das DTO.

Die Frage ist nun: Welche dieser Teile gehören zu unserer Domäne?
Um die Frage zu beantworten, analysieren wir die beteiligten Prozesse:

1.- Daten extrahieren: Dieser Teil verwendet nur die Funktion „json_decode“, um die eingehenden Daten von JSON in ein Array umzuwandeln. Es fügt keine Geschäftslogik hinzu, sodass diese nicht zur Domäne gehören würde.

2.- Das DTO: Das DTO enthält die mit den Eingabedaten verbundenen Eigenschaften und wie sie validiert werden. Das bedeutet, dass das DTO Geschäftsregeln (die Validierungsregeln) enthält, sodass es zur Domäne gehören würde.

3.- Daten denormalisieren: Dieser Teil verwendet einfach einen Infrastrukturdienst (eine Framework-Komponente), um die Daten in ein Objekt zu denormalisieren. Dies enthält keine Geschäftsregeln, daher würde es nicht zu unserer Domain gehören.

4.- Daten validieren: Genauso wie der Prozess Daten denormalisieren nutzt auch der Datenvalidierungsprozess einen Infrastrukturdienst (eine Framework-Komponente), um die eingehenden Daten zu validieren . Dies enthält keine Geschäftsregeln, da diese im DTO definiert sind und daher auch nicht Teil unserer Domäne wären.

Nach der Analyse der letzten Punkte können wir schlussfolgern, dass nur das DTO Teil unserer Domäne sein wird. Was machen wir dann mit dem Rest des Codes?

Erstellen eines Anwendungsdienstes

Ich persönlich mag es, diese Art von Prozessen (Extrahieren, Denormalisieren und Validieren von Daten) in die Anwendungsschicht oder Serviceschicht einzubeziehen. Warum? Lassen Sie uns die Anwendungsschicht vorstellen.

Die Anwendungsschicht

Kurz gesagt ist die Anwendungsschicht für die Orchestrierung und Koordination verantwortlich und überlässt die Geschäftslogik der Domänenschicht. Darüber hinaus fungiert es als Vermittler zwischen der Domänenschicht und externen Schichten wie der Präsentationsschicht (UI) und der Infrastrukturschicht.
Ausgehend von der obigen Definition könnten wir die Prozesse Extrahieren, Denormalisieren und Validieren in einen Dienst in der Anwendungsschicht einbeziehen, da:

  • Es koordiniert die eingehenden Datenprozesse.
  • Es nutzt die Infrastrukturdienste (PHP JSON-Funktion, Symfony-Normalisierungskomponente und Symfony-Validierungskomponente), um die eingehenden Daten zu verarbeiten.
  • Es wendet die Domänenregeln an, indem es das DTO an den Validierungsinfrastrukturdienst übergibt.

Perfekt, wir werden einen Anwendungsdienst erstellen, um diese Prozesse zu verwalten. Wie machen wir das? Wie werden wir mit den Verantwortlichkeiten umgehen?

Analyse der Verantwortlichkeiten

Das Single-Responsibility-Prinzip (SRP) besagt, dass jede Klasse nur für einen Teil des Verhaltens der Anwendung verantwortlich sein sollte. Wenn eine Klasse mehrere Verantwortlichkeiten hat, wird es schwieriger, sie zu verstehen, zu warten und zu ändern.

Welche Auswirkungen hat das auf uns? Lass es uns analysieren.
Bisher wissen wir, dass unser Anwendungsdienst die eingehenden Daten extrahieren, denormalisieren und validieren muss. Wenn man das weiß, ist es leicht, die folgenden Verantwortlichkeiten abzuleiten:

  • Daten extrahieren
  • Daten denormalisieren
  • Daten validieren

Sollten wir diese Verantwortlichkeiten auf drei verschiedene Dienste aufteilen? Das glaube ich nicht. Lass es mich erklären.

Wie wir gesehen haben, wird jede Verantwortung von einer Infrastrukturfunktion oder -komponente verwaltet:

  • Verantwortung extrahieren: PHP json_decode-Funktion
  • Datenverantwortung denormalisieren: Symfony-Normalisierungskomponente
  • Datenverantwortung validieren: Symfony-Validierungskomponente

Da der Anwendungsdienst diese Verantwortlichkeiten an die Infrastrukturdienste delegieren kann, können wir eine abstraktere Verantwortung (Prozessdaten) erstellen und diese dem Anwendungsdienst zuweisen.

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
    }
}

Wie oben gezeigt, verwendet der Anwendungsdienst DataProcessor die Funktion json_decode und den Normalisierungs- und Validierungsdienst von Symfony, um die Eingabeanforderung zu verarbeiten und ein neues und validiertes DTO zurückzugeben. Wir können also sagen, dass der DataProcessor-Dienst:

  • Koordiniert alle Aufgaben im Zusammenhang mit der Verarbeitung von Eingabedaten.
  • Kommuniziert die Außenwelt (Infrastrukturdienste) mit den Domain Business Rules (DTO).

Wie Sie vielleicht bemerkt haben, löst der DataProcessor-Dienst eine Symfony ValidationException aus, wenn der Validierungsprozess einen Fehler findet. Im nächsten Beitrag dieser Serie erfahren wir, wie wir unsere Geschäftsregeln anwenden, um die Fehler zu strukturieren und sie schließlich dem Kunden zu präsentieren.

Ich weiß, dass wir den DataProcessor-Dienst entfernen und MapRequestPayload als Dienstanwendungsschicht zum Extrahieren, Denormalisieren und Validieren der Daten verwenden könnten, aber angesichts des Kontexts dieses Artikels hielt ich es für praktischer schreibe es so.

Abschluss

In diesem ersten Artikel haben wir uns auf das Extrahieren und Validieren von Datenprozessen aus dem Flussdiagramm konzentriert. Wir haben die mit diesem Prozess verbundenen Aufgaben aufgelistet und gelernt, wie wir erkennen können, welche Teile zur Domäne gehören.
Da wir wissen, welche Teile zur Domäne gehören, haben wir einen Dienst auf Anwendungsebene geschrieben, der die Infrastrukturdienste verbindet, die die Domäne regiert, und den Prozess der Datenextraktion und -validierung koordiniert.
Im nächsten Artikel werden wir uns mit der Definition unserer Geschäftsregeln zum Verwalten von Ausnahmen befassen und außerdem einen Domänendienst erstellen, der für die Umwandlung des Eingabe-DTO in eine dauerhafte Einheit verantwortlich ist.

Das obige ist der detaillierte Inhalt vonErstellen fokussierter Domänenanwendungen. Ein Symfony-Ansatz (Teil 1). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn