9

こんにちは、みんな、

私はこの問題に 1 週​​間以上悩まされてきましたが、最終的に誰かが答えを知っていることを願って助けを求めることにしました。

Google の Protocol Buffersをデータ交換フォーマットとして使用するアプリケーションを開発しています。DrSlump の PHP実装を使用しています。これにより、クラス インスタンスにデータを入力し、それらをバイナリ文字列にシリアル化できます (またはバイナリ文字列を PHP オブジェクトにデコードできます)。

イベントに のインスタンスが含まれている場合に のインスタンスProtobufStrategyselectRenderer(ViewEvent $e)返すカスタムを実装することができました。次にレンダラーは、どのメッセージをクライアントに送り返す必要があるかを決定するために呼び出して、モデルからカスタム パラメーターを抽出し、データをシリアル化し、バイナリ文字列をphp://outputに出力します。ProtobufRendererProtobufModel$model->getOptions()

理解を深めるために、次のサンプル メッセージを見てみましょう。

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、 の 2 番目のパラメーター$optionsを利用しています。その後、前述のように、 を呼び出すことでレンダラー内で抽出できます$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)、のインスタンスを返すことです。これには、必要な追加の$options情報ViewModelが含まれていません。

ViewModelまた、それはand notを返します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',
));

...そして、私はそれを行う方法を見つけることができません...

独自のクラスを作成し、それを既存のExceptionStrategyExceptionStrategyサービスにエイリアスしようとしましたが、Zend はそのような名前のサービスが既に存在すると不満を漏らしました。

カスタム戦略拡張機能を使用して正しい道を進んでいる疑いがあります。デフォルトのものをオーバーライドする方法が見つかりません。

ExceptionStrategyデフォルトとコンソールが に登録されていることに気付きましたZend/Mvc/View/Http/ViewManager。このような単純なことを達成するためにカスタム ビュー マネージャーを追加する必要がないことを願っていますが、間違っている場合は修正してください。

どんな助けでも大歓迎です!

4

1 に答える 1

10

最も簡単な方法は、少しごまかすことです。

まず、リスナーを登録して、ExceptionStrategy よりも高い優先度で実行します。デフォルトの優先度で登録されるため、これは 1 よりも高い任意の優先度を意味します。

次に、リスナーで、戻る前に、MvcEvent の「エラー」を偽の値に設定してください。

$e->setError(false);

それが完了すると、デフォルトの ExceptionStrategy は、ViewModel で何かを行う前に、「ここでは何もする必要はありません。先に進んでください」と言って、早期に戻ります。

その際、イベントの結果インスタンスを変更する必要もあります。

$e->setResult($yourProtobufModel)

これにより、これが他のリスナーによって検査されることが保証されます。

于 2012-10-02T16:16:38.427 に答える