2013-06-24 71 views
1

我有一個控制器,我拋出一個自定義的異常,我有一個自定義的異常渲染器類,它擴展了基本的異常渲染器。CakePHP異常邏輯

現在,當我拋出異常,我想做一些清理與東西,出錯了,之後,呈現自定義錯誤頁面。

class AppExceptionRenderer extends ExceptionRenderer { 

    public function invalidCall($error) { 
     $this->controller->render('/Errors/invalid_call'); 
     $this->controller->response->send(); 
    } 

    public function incompleteCall($error) { 
     $this->controller->render('/Errors/incomplete_call'); 
     $this->controller->response->send(); 
    } 
} 

到目前爲止渲染效果很好。但是我應該在哪裏放置清理事物的邏輯? 在例外本身?在渲染器中?在拋出異常之前在控制器中?

+0

究竟什麼是你的「清理」代碼在做什麼? – ndm

+0

@ndm:從數據庫中刪除一些「死」的條目。 – nahri

回答

1

好吧,因爲經常有許多方法去皮膚貓,但我會說爲了保持DRY,爲了方便測試,並且爲了保持符合the recommended fat model concept,你應該把邏輯放在模型。

並且爲了分離清理和異常處理,您可以使用event system,讓可能需要清理的模型將他們自己作爲聽衆(他們應該知道他們是否需要清理),並讓自定義錯誤處理程序調度適當的事件,這樣異常處理程序不需要知道應用程序內部。

這裏有一些非常基本的,未經測試示例代碼應該說明的想法:

<?php 
App::uses('CakeEventManager', 'Event'); 

class ExampleModel extends AppModel 
{ 
    public $name = 'Example'; 

    public function __construct($id = false, $table = null, $ds = null) 
    { 
     CakeEventManager::instance()->attach(array($this, 'cleanup'), 'AppErrorHandler.beforeHandleException'); 
     parent::__construct($id, $table, $ds); 
    } 

    public function cleanup() 
    { 
     // do some magic 
    } 
} 
?> 

<?php 
App::uses('CakeEvent', 'Event'); 
App::uses('CakeEventManager', 'Event'); 

class AppErrorHandler extends ErrorHandler 
{ 
    public static function handleException(Exception $exception) 
    { 
     CakeEventManager::instance()->dispatch(new CakeEvent('AppErrorHandler.beforeHandleException', get_called_class(), array($exception))); 
     parent::handleException($exception); 
    } 
} 
?> 

更新

爲了能夠到只有特定的異常反應,例如,您可以利用事件名稱中的例外類名稱,因此它會觸發像...beforeHandleFooBarException這樣的事件,您可以明確訂閱:

<?php 
class AppErrorHandler extends ErrorHandler 
{ 
    public static function handleException(Exception $exception) 
    { 
     CakeEventManager::instance()->dispatch(new CakeEvent('AppErrorHandler.beforeHandle' . get_class($exception), get_called_class(), array($exception))); 

     parent::handleException($exception); 
    } 
} 
?> 

<?php 
class ExampleModel extends AppModel 
{ 
    public $name = 'Example'; 

    public function __construct($id = false, $table = null, $ds = null) 
    { 
     $eventManager = CakeEventManager::instance(); 
     $callback = array($this, 'cleanup'); 

     $eventManager->attach($callback, 'AppErrorHandler.beforeHandleInvalidCallException'); 
     $eventManager->attach($callback, 'AppErrorHandler.beforeHandleIncompleteCallException'); 

     parent::__construct($id, $table, $ds); 
    } 

    public function cleanup() 
    { 
     // do some magic 
    } 
} 
?> 

如果你將與通用的異常事件堅守,那麼另一種選擇將是檢查的模型事件偵聽器回調的異常的類型:

public function __construct($id = false, $table = null, $ds = null) 
{ 
    CakeEventManager::instance()->attach(array($this, 'beforeHandleException'), 'AppErrorHandler.beforeHandleException', array('passParams' => true)); 
    parent::__construct($id, $table, $ds); 
} 

public function beforeHandleException($exception) 
{ 
    if($exception instanceof InvalidCallException || 
     $exception instanceof IncompleteCallException) 
    { 
     $this->cleanup(); 
    } 
} 

public function cleanup() 
{ 
    // do some magic 
} 
+0

這不會影響所有其他例外嗎?或者我還必須爲另一個編寫處理程序? – nahri

+0

沒錯,這個例子會觸發每個異常的偵聽器。如果只想綁定到特定的異常,您可以基於該異常構建事件名稱,或者可以在模型偵聽器回調中測試異常的類型。我會用說明這一點的例子更新我的答案。 – ndm