大家好,

我已经为这个问题苦苦挣扎了一个多星期,最后决定寻求帮助,希望有人知道答案。

我正在开发一个应用程序,它正在使用 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)

因为这将确保这是其他听众检查的内容。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top