2012-10-02 20 views
9

Hola a todos,Definir una costumbre ExceptionStrategy en un módulo ZF2

He estado luchando con este problema desde hace más de una semana y finalmente decidí pedir ayuda esperanza de que alguien sabe la respuesta.

Estoy desarrollando una aplicación que usa Google's Protocol Buffers como formato de intercambio de datos. Estoy usando PHP implementation de DrSlump, que le permite poblar instancias de clase con datos y luego serializarlos en una cadena binaria (o decodificar cadenas binarias en objetos PHP).

he logrado poner en práctica mi costumbre ProtobufStrategy cuya selectRenderer(ViewEvent $e) devuelve una instancia de ProtobufRenderer en caso de que el evento contiene una instancia de ProtobufModel. El procesador extrae mis parámetros personalizados del modelo llamando al $model->getOptions() para determinar qué mensaje debe enviarse de vuelta al cliente, serializa los datos y envía la cadena binaria a php: // output.

para que tenga más sentido, vamos a ver el siguiente mensaje de muestra:

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

Si quería responder al cliente con este mensaje, volvería algo así de mi acción:

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

Como se puede ver que estoy utilizando ViewModel 's segundo parámetro, $ opciones , de decir qué mensaje tiene que ser serializado. Eso puede entonces, como se mencionó anteriormente, extraerse dentro del renderizador llamando al $model->getOptions().

Hasta ahora, todo bien. Mis acciones de controlador generan datos binarios como se esperaba.

Sin embargo, tengo problemas con el manejo de excepciones. Mi plan era capturar todas las excepciones y responder al cliente con una instancia de mi Excepción mensaje, que se ve así:

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

En teoría debería funcionar fuera de la caja, pero no es así. El problema es que Zend\Mvc\View\Http\ExceptionStrategy::prepareExceptionViewModel(MvcEvent $e) devuelve una instancia de ViewModel, que obviamente no contiene la información adicional $ options que necesito.

También devuelve ViewModel y no ProtobufModel, lo que significa que Zend invoca el valor predeterminado ViewPhpRenderer y emite la excepción como una página HTML.

Lo que quiero hacer es reemplazar el valor por defecto ExceptionStrategy (y eventualmente también el RouteNotFoundStrategy) con mis propias clases, que iban a regresar algo como esto:

$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', 
)); 

... y puedo' t encontrar la manera de hacerlo ...

intenté crear mi propia clase y un alias ExceptionStrategy a la servicio ExceptionStrategy existente, pero Zend se quejaron de que un servicio con ese nombre ya existe.

Tengo la sospecha de que estoy en el camino correcto con la extensión de estrategia personalizada. No puedo encontrar una manera de anular la predeterminada.

Me di cuenta de que el predeterminado ExceptionStrategy y la consola uno se registran en Zend/Mvc/View/Http/ViewManager. Espero no tener que agregar administradores de vistas personalizados para lograr algo tan simple, pero por favor, corríjanme si me equivoco.

¡Cualquier ayuda será apreciada!

+0

¡Felicitaciones por una pregunta bien escrita y bien investigada! – markus

Respuesta

10

La manera más fácil es hacer un poco de fudge.

Primero, registre su oyente para ejecutar con una prioridad más alta que ExceptionStrategy; ya que se registra en prioridad por defecto, esto significa cualquier prioridad mayor que 1.

Luego, en su oyente, antes de regresar, asegúrese de configurar el "error" en el la MvcEvent a un valor Falsy:

$e->setError(false); 

Una vez que haya hecho eso, la ExceptionStrategy predeterminada dirá, "no hay nada que hacer aquí, avance" y regrese antes de tiempo, antes de hacer nada con ViewModel.

Mientras estás en ello, también debe asegurarse de que cambie la instancia resultado en el evento:

$e->setResult($yourProtobufModel) 

ya que esto garantizará que esto es lo que está inspeccionado por otros oyentes.

+1

¡Muchas gracias! Funcionó a la perfección! – Andris

Cuestiones relacionadas