在 ZF2 模块中定义自定义 ExceptionStrategy
-
12-12-2019 - |
题
大家好,
我已经为这个问题苦苦挣扎了一个多星期,最后决定寻求帮助,希望有人知道答案。
我正在开发一个应用程序,它正在使用 Google 的协议缓冲区 作为数据交换格式。我正在使用 DrSlump 的 PHP 执行, ,它允许您用数据填充类实例,然后将它们序列化为二进制字符串(或将二进制字符串解码为 PHP 对象)。
我已经成功实现了我的自定义 ProtobufStrategy
谁的 selectRenderer(ViewEvent $e)
返回一个实例 ProtobufRenderer
如果事件包含一个实例 ProtobufModel
. 。然后渲染器通过调用从模型中提取我的自定义参数 $model->getOptions()
确定需要发送回客户端的消息,序列化数据并将二进制字符串输出到 php://输出.
为了让它更有意义,让我们看一下以下示例消息:
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
的第二个参数, $选项, ,告知需要序列化哪条消息。然后,如前所述,可以通过调用将其提取到渲染器内部 $model->getOptions()
.
到目前为止,一切都很好。我的控制器操作按预期输出二进制数据。
但是,我在处理异常时遇到问题。我的计划是捕获所有异常并用我的实例响应客户 例外 消息,看起来像这样:
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
, ,这显然不包含额外的 $选项 我需要的信息。
它还返回 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
类并将其别名为现有的 异常策略 服务,但 Zend 抱怨具有此类名称的服务已经存在。
我怀疑我的自定义策略扩展走在正确的道路上,但我找不到一种方法来覆盖默认策略。
我注意到默认的 ExceptionStrategy
并且控制台已注册 Zend/Mvc/View/Http/ViewManager
. 。我希望我不必添加自定义视图管理器来实现如此简单的事情,但如果我错了,请纠正我。
任何帮助将不胜感激!
解决方案
最简单的方法就是做一些捏造。
首先,注册您的侦听器以比 ExceptionStrategy 更高的优先级运行;由于它以默认优先级注册,这意味着任何高于 1 的优先级。
然后,在您的侦听器中,在返回之前,请确保将 MvcEvent 中的“错误”设置为虚假值:
$e->setError(false);
完成此操作后,默认的 ExceptionStrategy 会说“这里没什么可做的,继续前进”并在对 ViewModel 执行任何操作之前提前返回。
当您执行此操作时,您还应该确保更改事件中的结果实例:
$e->setResult($yourProtobufModel)
因为这将确保这是其他听众检查的内容。