Yii: Захват всех исключений для конкретного контроллера
Я работаю над проектом, который включает компонент REST API. У меня есть контроллер, предназначенный для обработки всех вызовов API REST.
Есть ли способ уловить все исключения для этого конкретного контроллера, чтобы я мог выполнить другое действие для этих исключений, чем остальные контроллеры приложений?
IE: Я хотел бы ответить либо отформатированным ответом API XML/JSON, содержащим сообщение об исключении, а не по умолчанию в виде системного представления/стека (что не очень полезно в контексте API). Предпочитал бы, чтобы не обертывать каждый вызов метода в контроллере в свой собственный try/catch.
Спасибо за любой совет заранее.
Ответы
Ответ 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'
)
));