2014-08-28 1 views
6

Penso che questa sia più di una domanda generale (quindi non limitata al php) per quanto riguarda ddd e lo schema di comando.Schema di comando nelle applicazioni php: come gestire le azioni del controller?

Diciamo che eseguo CreatePostCommand dall'azione di creazione del mio controller, il comando verrà gestito ed eventualmente eseguito correttamente. Qual è il modo appropriato per notificare al controller quale risposta restituire nel caso in cui il comando abbia avuto esito negativo o negativo? Dato che il gestore di comandi attiverà un evento specifico del dominio, potrei collegare il controller all'evento, ma ciò sembra abbastanza difficile, anche non appropriato per ogni situazione (ad esempio un post potrebbe essere creato da qualche altra parte e il controller in realtà non lo fa sapere di questo :)).

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

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

Qualche idea su questo?

+0

Se l'esecuzione non è riuscita, sarebbe stata generata un'eccezione, ovvero la riga che hai commentato non sarebbe stata eseguita. –

+2

Sì sicuro. Avrei dovuto essere più specifico qui.Diciamo che il comando è stato eseguito con successo e voglio reindirizzare a/post/edit/{$ id}, il controller non sarebbe a conoscenza dell'id post a meno che entrambi, il controller e il gestore comandi condividano per es. il repository dei post. Questo ha più senso. – iwyg

+0

La restituzione di valori da un comando interromperà il modello. Quindi sì, sei corretto nel fatto che sia il controller che il gestore di comandi dovranno conoscere il repository. Ma se hai bisogno di avere qualcosa che ritorna da un comando, dai un'occhiata al pattern del functor. –

risposta

1

Penso che se si sta veramente cercando di seguire il modello di comando DDD, è necessario considerare il bus di comando come un incendio e dimenticare il processo asincrono che potrebbe richiedere molto tempo per il completamento.

Considerare il reindirizzamento immediato a un controller di verifica comandi. Spetta al verificatore dei comandi controllare attivamente lo stato del comando e vedere se ha funzionato.

Nella maggior parte dei casi, il comando è terminato correttamente e il verificatore può quindi reindirizzare ancora una volta per continuare il flusso normale.

Se il comando non riesce, il verificatore visualizza un messaggio di errore appropriato.

Se il comando è in corso, è possibile eseguire l'intero ciclo di reindirizzamento informando l'utente che il comando è in corso.

Qualcosa di simile:

// 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. 

Chiaramente c'è un po 'di mano agitando in corso, ma penso che questo sia l'approccio più generale, in particolare con php in cui ogni richiesta parte da ground zero.

+0

Forse ti fraintendo, ma ciò significherebbe che l'oggetto $ command in un secondo momento ha un valore id assegnato ad esso? Ciò significherebbe che non è immutabile. Parte del potere di questa tecnica è che il tuo comando sta segnalando un intento, non uno stato o un comportamento: questo approccio rompe quel paradigma. – Oddman

+0

E l'alternativa è? Se l'intento è quello di creare un post, come faresti a segnalare se il post è stato creato o no? – Cerad

+0

Ci sono un paio di modi: uno è quello di far sì che il gestore comandi restituisca la creazione post riuscita (comportamento standard), ma in caso di errore (un po 'più complicato) puoi lanciare un'eccezione o scrivere un servizio che gestisce quelle aspettative con il controller iniettato come dipendenza da osservatore in grado di formulare la risposta corretta in base al risultato dell'esecuzione del comando. – Oddman

0

Il modo in cui lo sto facendo attualmente è il seguente (scusa post lungo).

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

In questo modo, si sta creando un post e, se tutto va come previsto, restituire l'oggetto $ postale e inviare tale alla vista. D'altra parte, quando viene lanciata un'eccezione durante l'esecuzione, si cattura l'errore e lo si invia a una vista.

mio modo preferito è quello di avere il controllo chiamata un metodo su un servizio che gestisce tale comportamento, e che il controllore iniettato come un ascoltatore che gestisce le risposte, ossia:

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

Poi nel servizio. ..

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

In questo modo il vostro servizio gestisce i vari risultati che il gestore di comandi può restituire, e il controller si lascia semplicemente per gestire le risposte che si potrebbe desiderare restituiti al vostro livello di presentazione.

+0

Che va bene per quando il controller può attendere il completamento del comando. Ma nella terra del DDD abbiamo la nozione di coerenza finale in cui può richiedere minuti, ore o persino giorni per completare un'operazione. Due problemi completamente diversi. – Cerad

+0

Questo è vero, soprattutto se stai parlando di cose come i sistemi CQRS. In entrambi i casi, i problemi possono e devono accadere e gestirli in questo modo significa che ci si prende cura di qualsiasi problema che possa verificarsi a causa di circostanze impreviste. – Oddman