2012-10-02 16 views
9

Ciao a tutti,Definire un personalizzato ExceptionStrategy in un modulo ZF2

ho lottato con questo problema per più di una settimana e finalmente deciso di chiedere aiuto sperando che qualcuno conosce la risposta.

Sto sviluppando un'applicazione, che utilizza Google's Protocol Buffers come formato di scambio dati. Sto usando DrSlump's PHP implementation, che consente di popolare le istanze di classe con i dati e quindi serializzarli in una stringa binaria (o decodificare le stringhe binarie in oggetti PHP).

sono riuscito a realizzare il mio personalizzato ProtobufStrategy cui selectRenderer(ViewEvent $e) restituisce un'istanza di ProtobufRenderer nel caso in cui l'evento contiene un'istanza di ProtobufModel. Il renderer estrae i miei parametri personalizzati dal modello chiamando $model->getOptions() per determinare quale messaggio deve essere restituito al client, serializza i dati e restituisce la stringa binaria a php: // output.

Perché per rendere più senso, diamo un'occhiata al seguente messaggio di esempio:

message SearchRequest { 
    required string query = 1; 
    optional int32 page_number = 2; 
    optional int32 result_per_page = 3; 
} 

Se volessi rispondere al cliente con questo messaggio, vorrei restituire qualcosa come questo da mia azione:

public function getSearchRequestAction() 
{ 
    [..] 
    $data = array(
     'query'   => 'my query', 
     'page_number'  => 3, 
     'result_per_page' => 20, 
    ); 
    return new ProtobufModel($data, array(
     'message' => 'MyNamespace\Protobuf\SearchRequest', 
    )); 
} 

Come potete vedere sto utilizzando ViewModel 's secondo parametro, $ opzioni, per dire che il messaggio deve essere serializzato. Ciò può quindi, come detto in precedenza, essere estratto all'interno del renderer chiamando $model->getOptions().

Finora, tutto bene. Le azioni del mio controller generano dati binari come previsto.

Tuttavia, si verificano problemi con la gestione delle eccezioni. Il mio piano era quello di catturare tutte le eccezioni e rispondere al client con un'istanza del mio Exception messaggio, che assomiglia a questo:

message Exception { 
    optional string message = 1; 
    optional int32 code = 2; 
    optional string file = 3; 
    optional uint32 line = 4; 
    optional string trace = 5; 
    optional Exception previous = 6; 
} 

In teoria dovrebbe funzionare out of the box, ma non è così. Il problema è che Zend\Mvc\View\Http\ExceptionStrategy::prepareExceptionViewModel(MvcEvent $e) restituisce un'istanza di ViewModel, che ovviamente non contiene le ulteriori opzioni $ di informazioni che mi servono.

Inoltre restituisce ViewModel e non ProtobufModel, il che significa che Zend invoca il valore predefinito ViewPhpRenderer e restituisce l'eccezione come pagina HTML.

Quello che voglio fare è sostituire il default ExceptionStrategy (ed eventualmente anche la RouteNotFoundStrategy) con le mie classi, che sarebbe tornato o meno così:

$data = array(
    'message' => $e->getMessage(), 
    'code'  => $e->getCode(), 
    'file'  => $e->getFile(), 
    'line'  => $e->getLine(), 
    'trace' => $e->getTraceAsString(), 
    'previous' => $e->getPrevious(), 
); 
return new ProtobufModel($data, array(
    'message' => 'MyNamespace\Protobuf\Exception', 
)); 

... e posso' t trovare il modo per farlo ...

ho cercato di creare il mio ExceptionStrategy classe e l'alias esso al ExceptionStrategy servizio esistente ma Zend lamentato del fatto che un servizio con questo nome esiste già.

Ho il sospetto che sono sulla strada giusta con l'estensione della strategia personalizzata Non riesco a trovare un modo per ignorare quello predefinito.

Ho notato che il valore predefinito ExceptionStrategy e quello della console vengono registrati in Zend/Mvc/View/Http/ViewManager. Spero di non dover aggiungere view manager personalizzati per ottenere una cosa così semplice ma, per favore, correggimi se sbaglio.

Qualsiasi aiuto sarà apprezzato!

+0

Congratulazioni per una domanda ben scritta e ben studiata! – markus

risposta

10

Il modo più semplice è fare un po 'di confusione.

Innanzitutto, registrare l'ascoltatore in modo che venga eseguito con priorità più alta di ExceptionStrategy; dal momento che registra a priorità predefinita, questo significa che qualsiasi priorità più alta rispetto 1.

Poi, nel vostro ascoltatore, prima di tornare, assicurarsi di impostare l ' "errore" nel l'MvcEvent ad un valore falsy:

$e->setError(false); 

Una volta fatto, ExceptionStrategy di default dirà "niente da fare qui, andare avanti" e tornare presto, prima di fare qualsiasi cosa con ViewModel.

Mentre si è in esso, si dovrebbe anche fare in modo di cambiare l'istanza risultato nel caso:

$e->setResult($yourProtobufModel) 

in modo da assicurare che questo è ciò che è controllato da altri ascoltatori.

+1

Grazie mille! Ha funzionato perfettamente! – Andris

Problemi correlati