2014-08-28 2 views
6

Ich denke, das ist eher eine allgemeine Frage (also nicht php eingeschränkt) in Bezug auf ddd und das Befehlsmuster.Befehlsmuster in PHP-Anwendungen: Wie gehen Sie mit Controller-Aktionen um?

Angenommen, ich führe CreatePostCommand aus der create-Aktion meines Controllers aus, der Befehl wird verarbeitet und schließlich erfolgreich ausgeführt. Was ist der geeignete Weg, um dem Controller mitzuteilen, welche Antwort auf die Rückgabe für den Fall, dass der Befehl fehlgeschlagen oder erfolgreich war? Wenn der Command-Handler ein domänenspezifisches Ereignis auslöst, könnte ich den Controller mit dem Event verbinden, aber das erscheint ziemlich umständlich, auch nicht für jede Situation geeignet (zB könnte ein Post irgendwo anders erstellt werden und der Controller nicht weiß darüber :)).

public function createAction($title, $content) 
{ 
    $this->commandBus->execute(new CreatePostCommand($title, $content); 

    $this->render('…'); // what if the command execution failed? 
} 

Irgendwelche Gedanken dazu?

+0

Wenn die Ausführung fehlschlug, wurde eine Ausnahme ausgelöst, was bedeutet, dass die von Ihnen kommentierte Zeile nicht ausgeführt wurde. –

+2

Ja sicher. Ich hätte hier genauer sein sollen.Nehmen wir an, der Befehl wurde erfolgreich ausgeführt, und ich möchte zu/post/edit/{$ id} umleiten. Der Controller würde die Post-ID nicht kennen, es sei denn, sowohl der Controller als auch der Befehlshandler teilen z. das Post-Repository. Macht das mehr Sinn? – iwyg

+0

Das Zurückgeben von Werten aus einem Befehl unterbricht das Muster. Sie haben also Recht, dass sowohl der Controller als auch der Command-Handler über das Repo Bescheid wissen müssen. Aber wenn Sie etwas von einem Befehl zurückgeben müssen, werfen Sie einen Blick auf das Funktor-Muster. –

Antwort

1

Ich denke, wenn Sie wirklich versuchen, dem DDD-Befehlsmuster zu folgen, müssen Sie den Befehlsbus als ein Feuer behandeln und asynchronen Prozess vergessen, der eine lange Zeit dauern kann, um abzuschließen.

Sie können sofort zu einem Befehlsüberprüfungscontroller umleiten. Es liegt an der Befehlsüberprüfungsfunktion, den Status des Befehls aktiv zu überprüfen und festzustellen, ob es funktioniert hat.

In den meisten Fällen ist der Befehl erfolgreich beendet und Ihr Prüfer kann dann erneut umleiten, um den normalen Ablauf fortzusetzen.

Wenn der Befehl fehlschlägt, gibt der Prüfer eine entsprechende Fehlermeldung aus.

Wenn der Befehl ausgeführt wird, können Sie eine Umleitungsschleife erstellen, während Sie den Benutzer darüber informieren, dass der Befehl ausgeführt wird.

Etwas wie:

// Execute the command 
$command = new CreatePostCommand($title, $content); 
$this->commandBus->execute($command); 

return redirect '/command-verifier/' . $command->getId(); 

// The verification action 
public function verifyCommandAction($commandId) 

$commandStatus = $this->commandBus->getStatus($commandId); 

if ($commandStatus == SUCCESS) redirect to all is well; 

if ($commandStatus == FAILED) then oops; 

if ($commandStatus == IN_PROGRESS) then maybe pause a bit and redirect again while keeping the user informed. 

Offensichtlich gibt es ziemlich viel Handbewegung los ist, aber ich denke, das ist die allgemeinste Ansatz ist besonders mit PHP, wo jede Anfrage vom Boden Null beginnt.

+0

Vielleicht missverstehe ich Sie, aber das würde bedeuten, dass das $ -Befehlsobjekt zu einem späteren Zeitpunkt einen ID-Wert zugewiesen hat? Das würde bedeuten, dass es nicht unveränderlich ist. Ein Teil der Kraft dieser Technik besteht darin, dass Ihr Befehl eine Absicht, nicht einen Zustand oder ein Verhalten signalisiert - dieser Ansatz bricht dieses Paradigma. – Oddman

+0

Und die Alternative ist? Wenn Sie einen Post erstellen möchten, wie würden Sie dann signalisieren, ob der Post erstellt wurde oder nicht? – Cerad

+0

Es gibt mehrere Möglichkeiten - einer davon ist, dass der Befehlshandler die erfolgreiche Nacherstellung zurückgibt (Standardverhalten), aber bei einem Fehler (etwas kniffliger) können Sie entweder eine Ausnahme auslösen oder einen Dienst schreiben, der diese Erwartungen mit dem Controller verwaltet als Beobachterabhängigkeit injiziert, die basierend auf dem Ergebnis der Befehlsausführung die richtige Antwort formulieren kann. – Oddman

0

Die Art, wie ich es gerade mache, ist wie folgt (Entschuldigung lange Post).

public function createAction($title, $content) { 
    try { 
     $post = $this->commandBus->execute(new CreatePostCommand($title, $content); 
    } 
    catch (Exception $e) { 
     return $this->render('some error template file', $e); 
    } 

    return $this->render('successful creation template file', $post); 
} 

Auf diese Weise sind Sie einen Beitrag erstellen und wenn alles wie geplant läuft, bringen Sie das $ post-Objekt und das zu Ihrer Ansicht senden. Wenn eine Ausnahme während der Ausführung ausgelöst wird, fangen Sie diesen Fehler jedoch auf und senden ihn an eine Ansicht.

Mein bevorzugter Weg ist, den Controller Aufruf ein Verfahren für einen Dienst zu haben, der dieses Verhalten verwaltet und hat den Controller als Zuhörer injizierte, die die Antworten verwaltet, das heißt:

public function createAction($title, $content) { 
    $service = new CreateActionService($title, $content); 

    return $service->create($this); 
} 

public function onError(Exception $e) { 
    return $this->render('some error template file', $e); 
} 

public function onSuccess($post) { 
    return $this->render('success', $post); 
} 

Dann in Ihren Diensten. ..

public function create($listener) 
{ 
    try { 
     $this->commandBus->execute(new CreatePostCommand($title, $content); 
    } 
    catch (Exception $e) { 
     return $this->listener->onError($e); 
    } 

    return $this->listener->onSuccess($post); 
} 

auf diese Weise Ihre Dienstleistung ist, die verschiedenen Ergebnisse der Verwaltung, dass die Befehls-Handler zurückgeben kann, und der Controller wird einfach die Antworten verwalten links, dass Sie Ihre Präsentationsschicht zurück wünschen.

+0

Das ist in Ordnung, wenn der Controller auf den Abschluss des Befehls warten kann. Aber im Land der DDD haben wir die Vorstellung einer möglichen Konsistenz, wo es Minuten, Stunden oder sogar Tage dauern kann, bis eine Operation abgeschlossen ist. Zwei völlig verschiedene Probleme. – Cerad

+0

Dies gilt insbesondere, wenn Sie über Dinge wie CQRS-Systeme sprechen. In jedem Fall können und können Probleme auftreten - und auf diese Weise zu managen, bedeutet, dass Sie sorgfältig alle Probleme behandeln, die aufgrund unvorhergesehener Umstände auftreten können. – Oddman