1

カスタム例外をスローするコントローラーと、基本的な例外レンダラーを拡張するカスタム例外レンダラー クラスがあります。

例外をスローすると、問題が発生したものをクリーンアップして、カスタムエラーページをレンダリングしたいと思います。

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

レンダリングは今のところうまく機能しています。しかし、クリーンアップのロジックはどこに置くべきでしょうか? 例外自体で?レンダラーで?例外をスローする前にコントローラーで?

4

1 に答える 1

1

猫の皮を剥ぐには多くの方法がありますが、テストを簡単にするためにDRYを維持し、推奨される脂肪モデルの概念に準拠するために、ロジックをモデル。

また、クリーンアップと例外処理を分離するために、たとえば、イベント システムを利用して、クリーンアップが必要な可能性のあるモデルをリスナーとしてアタッチできるようにすることができます (クリーンアップが必要かどうかを最もよく知っている必要があります)。カスタム エラー ハンドラーは適​​切なイベントをディスパッチします。これにより、例外ハンドラーはアプリの内部について知る必要がなくなります。

アイデアを説明するための非常に基本的な、テストされていないコード例を次に示します。

<?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
}
于 2013-06-24T20:25:12.533 に答える