2013-06-24 129 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