2012-10-02 156 views
9

大家在自定義ExceptionStrategy,定義ZF2模塊

我一直在這個問題掙扎了一個多星期,最後決定求助,希望有人知道答案。

我正在開發一個應用程序,它使用Google's Protocol Buffers作爲數據交換格式。我使用DrSlump的PHP implementation,讓我們用數據填充類實例,然後將它們序列化爲二進制字符串(或將二進制字符串解碼爲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的實例,顯然它不包含我需要的其他$ 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登記。我希望我不需要添加自定義視圖管理器來實現這樣一個簡單的事情,但請,請糾正我,如果我錯了。

任何幫助將不勝感激!

+0

恭喜你撰寫了一篇寫得很好,經過深入研究的問題! – markus

回答

10

最簡單的方法是做一點小事。

首先,註冊偵聽器以比ExceptionStrategy更高的優先級運行;因爲它註冊在默認的優先級,這意味着超過1

更高的任何優先權然後,在你的聽衆,你回來之前,請確保您設置在該MvcEvent的「錯誤」的falsy值:

$e->setError(false); 

一旦你這樣做了,默認的ExceptionStrategy將會說:「這裏沒有任何事情可以做,隨着」ViewModel做任何事情之前都會提前返回。

當你在這,你還應該確保你改變的結果的實例事件:

$e->setResult($yourProtobufModel) 

,因爲這將確保這是被其他聽衆檢查。

+1

非常感謝!完美工作! – Andris