CakePHP异常逻辑

时间:2013-06-24 11:47:17

标签: cakephp exception-handling

我有一个控制器,我在其中抛出一个自定义异常,并且我有一个自定义异常渲染器类,它扩展了基本的异常渲染器。

现在,当我抛出异常时,我想对这些东西进行一些清理,出错了,然后再渲染一个自定义错误页面。

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();
    }
}

到目前为止渲染效果很好。但是,我应该把清理的逻辑放在哪里呢? 在例外本身?在渲染器?在抛出异常之前的控制器中?

1 个答案:

答案 0 :(得分:1)

嗯,因为经常有许多方法可以给猫皮肤,但我会说为了便于测试而保持DRY,并且为了遵守the recommended fat model concept,你应该把逻辑放在模型中。

为了解除清理和异常处理,您可以使用event system并让可能需要清理的模型将自己作为听众附加(他们应该最清楚是否需要清理它们) up),让自定义错误处理程序调度一个适当的事件,这样异常处理程序就不需要知道app内部了。

这是一些非常基本的未经测试的示例代码,应该说明这个想法:

<?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
}