Controller.php 6.74 KB
<?php
/**
 * Controller is the customized base controller class.
 * All controller classes for this application should extend from this base class.
 */
class Controller extends /*WRestController*/ CController
{
    /**
     * 
     */
    private $_error = array();
    
    
    /**
     * Initializes the controller. This method is called by the application 
     * before the controller starts to execute.
     */
    public function init()
    {
        parent::init();
        
        // Let completely bypass Yii's default error displaying mechanism 
        // by registering onError and onException event listeners
        Yii::app()->attachEventHandler('onError',array($this,'handleError'));
        Yii::app()->attachEventHandler('onException',array($this,'handleError'));
    }
	
    
    /**
     * Handling all errors and exceptions for all controllers
     * To check if there was error or exception need use construction like
     * 
     * if ($event instanceof CExceptionEvent) { ... }
     * elseif($event instanceof CErrorEvent) { ... }
     * 
     * @param   {object} event
     */
    public function handleError(CEvent $event)
    {
        $error = ($event instanceof CExceptionEvent) ? $event->exception : $event;
        
        if($event instanceof CExceptionEvent) {
            if(($trace = $this->getExactTrace($error)) === null) {
                $fileName = $error->getFile();
                $errorLine = $error->getLine();
            }
            else {
                $fileName = $trace['file'];
                $errorLine = $trace['line'];
            }
            
            $trace = $error->getTrace();
            
            foreach($trace as $i => $t) {
                if(!isset($t['file'])) {
                    $trace[$i]['file']='unknown';
                }
                
                if(!isset($t['line'])) {
                    $trace[$i]['line']=0;
                }
                
                if(!isset($t['function'])) {
                    $trace[$i]['function']='unknown';
                }
                
                unset($trace[$i]['object']);
            }
        }
        elseif($event instanceof CErrorEvent) {
            $trace = debug_backtrace();
            // skip the first 3 stacks as they do not tell the error position
            if(count($trace) > 3) {
                $trace = array_slice($trace,3);
            }
            
            $traceString = '';
            
            foreach($trace as $i=>$t) {
                if(!isset($t['file'])) {
                    $trace[$i]['file']='unknown';
                }
                
                if(!isset($t['line'])) {
                    $trace[$i]['line']=0;
                }
                
                if(!isset($t['function'])) {
                    $trace[$i]['function']='unknown';
                }

                $traceString .= "#$i {$trace[$i]['file']}({$trace[$i]['line']}): ";
                if(isset($t['object']) && is_object($t['object'])) { 
                    $traceString.=get_class($t['object']).'->';
                }
                $traceString.="{$trace[$i]['function']}()\n";

                unset($trace[$i]['object']);
            }
            
            switch($error->code) {
                case E_WARNING:
                    $type = 'PHP warning';
                    break;
                case E_NOTICE:
                    $type = 'PHP notice';
                    break;
                case E_USER_ERROR:
                    $type = 'User error';
                    break;
                case E_USER_WARNING:
                    $type = 'User warning';
                    break;
                case E_USER_NOTICE:
                    $type = 'User notice';
                    break;
                case E_RECOVERABLE_ERROR:
                    $type = 'Recoverable error';
                    break;
                default:
                    $type = 'PHP error';
            }
        }
        else {
            return;
        }
        
        $this->_error =array(
            'code' => ($error instanceof CHttpException) ? $error->statusCode : 500,
            'type' => $type ? $type : get_class($error),   
            'message' => ($error instanceof CException) ? $error->getMessage() : $error->message,
            'file' => $fileName ? $fileName : $error->file,
            'line' => $errorLine ? $errorLine : $error->line,
            'trace' => ($error instanceof CException) ? $error->getTraceAsString() : $traceString,
            'traces' => $trace
        );
        
        if(YII_DEBUG) {
            $this->sendResponse($this->_error['code'], array(
                'success' => false,
                'error' => $this->_error
            ));
        }
        else {
            if(Yii::app()->user->isGuest) {
                $this->sendResponse(401, array(
                    'success' => false
                ));
            }
            else {
                $this->sendResponse($this->_error['code'], array(
                    'success' => false,
                    'error' =>  array(
                        'message' => $this->_error['message']
                    ))
                );
            }
        }
        
        // Stop rising error / exception
        $event->handled = true;
    }
    
    
    /**
     * Returns the exact trace where the problem occurs.
     * @param Exception $exception the uncaught exception
     * @return array the exact trace where the problem occurs
     */
    protected function getExactTrace($exception)
    {
        $traces = $exception->getTrace();

        foreach($traces as $trace)
        {
            // property access exception
            if(isset($trace['function']) && ($trace['function']==='__get' || $trace['function']==='__set'))
                return $trace;
        }
        return null;
    }
    
    
	/**
     * Access filter control
     */
    public function filters()
    {
        return array(
            array(
                'application.filters.AccessControl - index,authorize,error'
            )
        );
    }
    
    
    public function showJSON($params)
    {
    	$params = !is_array($params) || empty($params) ? array() : $params;
    	echo "(" . CJSON::encode($params) . ")";
    	Yii::app()->end();
    }
    
    /**
     * This is the action to handle external exceptions.
     */
    public function actionError()
    {
        if($error=Yii::app()->errorHandler->error)
        {
            if(Yii::app()->request->isAjaxRequest) {
                $this->showJSON(array(
                    "success" => false,
                    "error" => $error['code'], 
                    "message" => $error['message']
                ));
            }
            else {
                $this->render('error', $error);
            }
        }
    }
}