大家好,
我已经为这个问题苦苦挣扎了一个多星期,最终决定寻求帮助,希望有人知道答案。
我正在开发一个使用Google's Protocol Buffers作为数据交换格式的应用程序。我正在使用DrSlump的PHP implementation,它使您可以用数据填充类实例,然后将它们序列化为二进制字符串(或将二进制字符串解码为PHP对象)。
我已经成功实现了我的自定义ProtobufStrategy
,如果事件包含selectRenderer(ViewEvent $e)
实例,则其ProtobufRenderer
返回ProtobufModel
实例。然后,渲染器通过调用$model->getOptions()
从模型中提取我的自定义参数,以确定需要将哪些消息发送回客户端,序列化数据并将二进制字符串输出到php://output。
为了使它更有意义,让我们看下面的示例消息:
message SearchRequest {
required string query = 1;
optional int32 page_number = 2;
optional int32 result_per_page = 3;
}
如果我想用此消息响应客户端,我将从操作中返回类似以下内容:
public function getSearchRequestAction()
{
[..]
$data = array(
'query' => 'my query',
'page_number' => 3,
'result_per_page' => 20,
);
return new ProtobufModel($data, array(
'message' => 'MyNamespace\Protobuf\SearchRequest',
));
}
如您所见,我正在使用
ViewModel
的第二个参数$ options来告诉需要序列化的消息。然后,如前所述,可以通过调用$model->getOptions()
将其提取到渲染器中。到现在为止还挺好。我的 Controller 操作按预期输出二进制数据。
但是,我在处理异常时遇到问题。我的计划是捕获所有异常,并用我的Exception消息的实例响应客户端,如下所示:
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;
}
从理论上讲,它应该是开箱即用的,但事实并非如此。问题是
Zend\Mvc\View\Http\ExceptionStrategy::prepareExceptionViewModel(MvcEvent $e)
返回了ViewModel
的实例,该实例显然不包含我需要的其他$ options信息。它还返回
ViewModel
而不是ProtobufModel
,这意味着Zend调用默认的ViewPhpRenderer
并将异常输出为HTML页面。我想要做的是用我自己的类替换默认的
ExceptionStrategy
(以及最终的RouteNotFoundStrategy
),这将返回如下内容:$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',
));
...而且我找不到办法...
我尝试创建自己的
ExceptionStrategy
类,并将其别名为现有的ExceptionStrategy服务,但Zend提示称已存在具有该名称的服务。我怀疑自定义策略扩展在正确的路径上,我找不到覆盖默认方法的方法。
我注意到默认的
ExceptionStrategy
和一个控制台已在Zend/Mvc/View/Http/ViewManager
中注册。我希望我不必添加自定义 View 管理器即可实现如此简单的操作,但是如果我错了,请纠正我。任何帮助将不胜感激!
最佳答案
最简单的方法是进行一些伪造。
首先,注册您的监听器以使其比ExceptionStrategy具有更高的优先级;因为它以默认优先级注册,所以这意味着任何高于1的优先级。
然后,在您的监听器中,在返回之前,请确保将MvcEvent中的“错误”设置为虚假值:
$e->setError(false);
完成此操作后,默认的ExceptionStrategy将对ViewModel进行任何操作,然后说:“什么都不做,继续前进”并提早返回。
在进行此操作时,还应确保在事件中更改结果实例:
$e->setResult($yourProtobufModel)
因为这将确保其他听众会检查此内容。
关于php - 在ZF2模块中定义自定义ExceptionStrategy,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12693762/