Yii: Захват всех исключений для конкретного контроллера - программирование
Подтвердить что ты не робот

Yii: Захват всех исключений для конкретного контроллера

Я работаю над проектом, который включает компонент REST API. У меня есть контроллер, предназначенный для обработки всех вызовов API REST.

Есть ли способ уловить все исключения для этого конкретного контроллера, чтобы я мог выполнить другое действие для этих исключений, чем остальные контроллеры приложений?

IE: Я хотел бы ответить либо отформатированным ответом API XML/JSON, содержащим сообщение об исключении, а не по умолчанию в виде системного представления/стека (что не очень полезно в контексте API). Предпочитал бы, чтобы не обертывать каждый вызов метода в контроллере в свой собственный try/catch.

Спасибо за любой совет заранее.

4b9b3361

Ответ 1

Вы можете полностью обойти механизм отображения ошибок по умолчанию Yii, зарегистрировав onError и onException прослушиватели событий.

Пример:

class ApiController extends CController
{
  public function init()
  {
    parent::init();

    Yii::app()->attachEventHandler('onError',array($this,'handleError'));
    Yii::app()->attachEventHandler('onException',array($this,'handleError'));
  }

  public function handleError(CEvent $event)
  {        
    if ($event instanceof CExceptionEvent)
    {
      // handle exception
      // ...
    }
    elseif($event instanceof CErrorEvent)
    {
      // handle error
      // ...
    }

    $event->handled = TRUE;
  }

  // ...
}

Ответ 2

Мне не удалось подключить события в контроллере, и я сделал это путем переопределения класса CWebApplication:

class WebApplication extends CWebApplication
{
protected function init()
{
    parent::init();

    Yii::app()->attachEventHandler('onError',array($this, 'handleApiError'));
    Yii::app()->attachEventHandler('onException',array($this, 'handleApiError'));
}

/**
 * Error handler
 * @param CEvent $event
 */
public function handleApiError(CEvent $event)
{
    $statusCode = 500;

    if($event instanceof CExceptionEvent)
    {
        $statusCode = $event->exception->statusCode;
        $body = array(
            'code' => $event->exception->getCode(),
            'message' => $event->exception->getMessage(),
            'file' => YII_DEBUG ? $event->exception->getFile() : '*',
            'line' => YII_DEBUG ? $event->exception->getLine() : '*'
        );
    }
    else
    {
        $body = array(
            'code' => $event->code,
            'message' => $event->message,
            'file' => YII_DEBUG ? $event->file : '*',
            'line' => YII_DEBUG ? $event->line : '*'
        );
    }

    $event->handled = true;

    ApiHelper::instance()->sendResponse($statusCode, $body);
}
}

В index.php:

require_once(dirname(__FILE__) . '/protected/components/WebApplication.php');
Yii::createApplication('WebApplication', $config)->run();

Ответ 3

Вы можете написать собственную функцию actionError() для каждого контроллера. Существует несколько способов сделать это, описанное здесь

Ответ 4

Я использую следующий базовый контроллер для API, это не API без апатии, заметьте, но он может служить так же хорошо.

класс BaseJSONController расширяет CController {

        public $data = array();

        public $layout;

        public function filters()
        {
                return array('mainLoop');
        }

        /**
         * it all starts here
         * @param unknown_type $filterChain
         */
        public function filterMainLoop($filterChain){
                $this->data['Success'] = true;
                $this->data['ReturnMessage'] = "";
                $this->data['ReturnCode'] = 0;
                try{
                        $filterChain->run();

                }catch (Exception $e){
                        $this->data['Success'] = false;
                        $this->data['ReturnMessage'] = $e->getMessage();
                        $this->data['ReturnCode'] = $e->getCode(); 
                }

                echo json_encode($this->data);
        }
}

Вы также можете поймать dbException и отправить их по электронной почте, так как они несколько критичны и могут показать основную проблему в дизайне кода/db.

Ответ 5

Добавьте это на свой контроллер:

Yii::app()->setComponents(array(
    'errorHandler'=>array(
        'errorAction'=>'error/error'
    )
));