To accomplish custom error handling, we’re trying to come up with an approach allowing us to throw a PHP ErrorException when some errors (warnings & notices) are raised.
I believe the reason I’m finding this more difficult than expected has to do with how the lifecycle works upon an error raise:
[indent]From CApplication docs : "Starting from lifecycle 3, if a PHP error or an uncaught exception occurs, the application will switch to its error handling logic and jump to step 6 afterwards." (where step 6 is onEndRequest post processing)[/indent]
[indent]
For more see notes on lifecycle : h t t p s://github.com/yiisoft/yii/blob/1.1.13/framework/base/CApplication.php#L445.[/indent]
So far, we’ve found several ways to accomplish this, but none achieve the larger goal of returning execution control/flow back to the calling action to catch and handle the ErrorException on a per-action basis. (return to the processRequest lifecycle step rather than performing the error routine & then skipping to onEndRequest/ post processing)
This idea is very similar to the discussion here : h t t p ://www.yiiframework.com/forum/index.php/topic/22553-error-handling (starting w/ #9 post in discussion) started by @samdark except at a more granular level.
[size="3"]What is a solid, non-hacky approach for accomplishing this?[/size]
Let me illustrate the question in another way by giving a specific example of one of the approaches we’ve used that falls short of accomplishing the goal.
Made up Scenario: two actions that need to report back to the end user with different messages when a file they’ve requested isn’t found (where part of this process triggers a php warning)
Controller
/**
* Custom error handler to intercept default error handling behavior
* YII considers errors PHP warnings and notices only
* http://www.yiiframework.com/doc/guide/1.1/en/topics.error
* " By default, handleError will raise an onError event. If the error is not handled by any event handler,
* it will call for help from the errorHandler application component."
*/
public function init()
{
parent::init();
Yii::app()->attachEventHandler('onError',array($this,'handleError'));
}
public function handleError(CEvent $event)
{
//either level warning or notice
if($event instanceof CErrorEvent)
{
//not sure if code param is error level or error code ....
throw new ErrorException($event->message, 0, 0, $event->file, $event->line);
$event->handled = TRUE;
}
}
/**
* Lets the user download an art file.
*/
public function actionDownloadArt($art_id){
//find the art $file given the $art_id
try{
//something in try block throws a warning or notice - in this case 'file_get_contents'
$fileContents = file_get_contents(Yii::app()->basePath . $file);
} catch(ErrorException $e){ //This point is never reached but is where we'd want the request to continue processing
Yii::log('error exception caught ', CLogger::LEVEL_ERROR, 'application.controllers.job');
Yii::log('Request to download art file ' .$file . ' failed with the following exception : '. $e->getMessage() . 'code : ' . $e->getCode(), CLogger::LEVEL_ERROR, 'application.controllers.job');
}
if($fileContents != false){
Yii::log('send art file attempt ', CLogger::LEVEL_INFO, 'application.controllers.job');
Yii::app()->request->sendFile($name, $fileContents);
}
//only reaches this point if file not successfully found + sent
//this is key, we don't want errors to change the flow or the resulting view - we just want to set the flash or something similar,
//but the message to the end user needs to be helpful, and non-generic
Yii::app()->user->setFlash('failure','Failed to download art. Art file may be missing or blank.');
}
/**
* Lets the user download an document file.
*/
public function actionDownloadDocument($doc_id){
//find the document $file given the $doc_id
try{
//something in try block throws a warning or notice - in this case 'file_get_contents'
$fileContents = file_get_contents(Yii::app()->basePath . $file);
} catch(ErrorException $e){ //This point is never reached but is where we'd want the request to continue processing
//maybe do some logging here
}
if($fileContents != false){
Yii::log('send doc file attempt ', CLogger::LEVEL_INFO, 'application.controllers.job');
Yii::app()->request->sendFile($name, $fileContents);
}
//only reaches this point if file not successfully found + sent
//this is key, we don't want errors to change the flow or the resulting view - we just want to set the flash or something similar,
//but the message to the end user needs to be helpful, and non-generic
Yii::app()->user->setFlash('failure','Failed to download document. Document may be missing or blank.');
}
Again, this approach falls short because when the ErrorException is thrown by handleError(), post processing is done & the request ends rather than returning control flow to the action(s). (so we just get the exception thrown all the way up to the user rather than the Flash failure message at the top of the view)
What are other general approaches not tied to the specific ‘download art , download document’ code example I gave that would accomplish what I’ve outlined? Or … what are tweaks to this approach?