Browse Source

...

tags/2.0.0-beta
Qiang Xue 13 years ago
parent
commit
165bb02a65
  1. 110
      framework/base/Action.php
  2. 75
      framework/base/ActionFilter.php
  3. 276
      framework/base/Application.php
  4. 490
      framework/base/Controller.php
  5. 38
      framework/base/ErrorHandler.php
  6. 53
      framework/base/InlineAction.php
  7. 61
      framework/base/InlineActionFilter.php
  8. 5
      framework/base/Module.php

110
framework/base/Action.php

@ -0,0 +1,110 @@
<?php
/**
* CAction class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008-2011 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
/**
* CAction is the base class for all controller action classes.
*
* CAction provides a way to divide a complex controller into
* smaller actions in separate class files.
*
* Derived classes must implement {@link run()} which is invoked by
* controller when the action is requested.
*
* An action instance can access its controller via {@link getController controller} property.
*
* @property CController $controller The controller who owns this action.
* @property string $id Id of this action.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @version $Id$
* @package system.web.actions
* @since 1.0
*/
abstract class CAction extends CComponent implements IAction
{
private $_id;
private $_controller;
/**
* Constructor.
* @param CController $controller the controller who owns this action.
* @param string $id id of the action.
*/
public function __construct($controller,$id)
{
$this->_controller=$controller;
$this->_id=$id;
}
/**
* @return CController the controller who owns this action.
*/
public function getController()
{
return $this->_controller;
}
/**
* @return string id of this action
*/
public function getId()
{
return $this->_id;
}
/**
* Runs the action with the supplied request parameters.
* This method is internally called by {@link CController::runAction()}.
* @param array $params the request parameters (name=>value)
* @return boolean whether the request parameters are valid
* @since 1.1.7
*/
public function runWithParams($params)
{
$method=new ReflectionMethod($this, 'run');
if($method->getNumberOfParameters()>0)
return $this->runWithParamsInternal($this, $method, $params);
else
return $this->run();
}
/**
* Executes a method of an object with the supplied named parameters.
* This method is internally used.
* @param mixed $object the object whose method is to be executed
* @param ReflectionMethod $method the method reflection
* @param array $params the named parameters
* @return boolean whether the named parameters are valid
* @since 1.1.7
*/
protected function runWithParamsInternal($object, $method, $params)
{
$ps=array();
foreach($method->getParameters() as $i=>$param)
{
$name=$param->getName();
if(isset($params[$name]))
{
if($param->isArray())
$ps[]=is_array($params[$name]) ? $params[$name] : array($params[$name]);
else if(!is_array($params[$name]))
$ps[]=$params[$name];
else
return false;
}
else if($param->isDefaultValueAvailable())
$ps[]=$param->getDefaultValue();
else
return false;
}
$method->invokeArgs($object,$ps);
return true;
}
}

75
framework/base/ActionFilter.php

@ -0,0 +1,75 @@
<?php
/**
* CFilter class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008-2011 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
/**
* CFilter is the base class for all filters.
*
* A filter can be applied before and after an action is executed.
* It can modify the context that the action is to run or decorate the result that the
* action generates.
*
* Override {@link preFilter()} to specify the filtering logic that should be applied
* before the action, and {@link postFilter()} for filtering logic after the action.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @version $Id$
* @package system.web.filters
* @since 1.0
*/
class CFilter extends CComponent implements IFilter
{
/**
* Performs the filtering.
* The default implementation is to invoke {@link preFilter}
* and {@link postFilter} which are meant to be overridden
* child classes. If a child class needs to override this method,
* make sure it calls <code>$filterChain->run()</code>
* if the action should be executed.
* @param CFilterChain $filterChain the filter chain that the filter is on.
*/
public function filter($filterChain)
{
if($this->preFilter($filterChain))
{
$filterChain->run();
$this->postFilter($filterChain);
}
}
/**
* Initializes the filter.
* This method is invoked after the filter properties are initialized
* and before {@link preFilter} is called.
* You may override this method to include some initialization logic.
* @since 1.1.4
*/
public function init()
{
}
/**
* Performs the pre-action filtering.
* @param CFilterChain $filterChain the filter chain that the filter is on.
* @return boolean whether the filtering process should continue and the action
* should be executed.
*/
protected function preFilter($filterChain)
{
return true;
}
/**
* Performs the post-action filtering.
* @param CFilterChain $filterChain the filter chain that the filter is on.
*/
protected function postFilter($filterChain)
{
}
}

276
framework/base/Application.php

@ -73,7 +73,7 @@ use yii\base\Exception;
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */
abstract class Application extends Module class Application extends Module
{ {
/** /**
* @var string the application name. Defaults to 'My Application'. * @var string the application name. Defaults to 'My Application'.
@ -91,25 +91,16 @@ abstract class Application extends Module
public $sourceLanguage = 'en_us'; public $sourceLanguage = 'en_us';
public $preload = array('errorHandler'); public $preload = array('errorHandler');
public $localeDataPath = '@yii/i18n/data';
private $_runtimePath; private $_runtimePath;
private $_ended = false; private $_ended = false;
private $_language; private $_language;
/** /**
* Processes the request.
* This is the place where the actual request processing work is done.
* Derived classes should override this method.
*/
abstract public function processRequest();
/**
* Constructor. * Constructor.
* @param mixed $config application configuration. * @param string $basePath the base path of this application. This should point to
* If a string, it is treated as the path of the file that contains the configuration; * the directory containing all application logic, template and data.
* If an array, it is the actual configuration information.
* Please make sure you specify the {@link getBasePath basePath} property in the configuration,
* which should point to the directory containing all application logic, template and data.
* If not, the directory will be defaulted to 'protected'.
*/ */
public function __construct($basePath) public function __construct($basePath)
{ {
@ -169,6 +160,15 @@ abstract class Application extends Module
} }
/** /**
* Processes the request.
* This is the place where the actual request processing work is done.
* Derived classes should override this method.
*/
public function processRequest()
{
}
/**
* Raises the [[afterRequest]] event right AFTER the application processes the request. * Raises the [[afterRequest]] event right AFTER the application processes the request.
*/ */
public function afterRequest() public function afterRequest()
@ -306,24 +306,6 @@ abstract class Application extends Module
} }
/** /**
* Returns the directory that contains the locale data.
* @return string the directory that contains the locale data. It defaults to 'framework/i18n/data'.
*/
public function getLocaleDataPath()
{
return CLocale::$dataPath === null ? \Yii::getPathOfAlias('system.i18n.data') : CLocale::$dataPath;
}
/**
* Sets the directory that contains the locale data.
* @param string $value the directory that contains the locale data.
*/
public function setLocaleDataPath($value)
{
CLocale::$dataPath = $value;
}
/**
* @return CNumberFormatter the locale-dependent number formatter. * @return CNumberFormatter the locale-dependent number formatter.
* The current {@link getLocale application locale} will be used. * The current {@link getLocale application locale} will be used.
*/ */
@ -415,232 +397,6 @@ abstract class Application extends Module
} }
/** /**
* Handles uncaught PHP exceptions.
*
* This method is implemented as a PHP exception handler. It requires
* that constant YII_ENABLE_EXCEPTION_HANDLER be defined true.
*
* This method will first raise an `exception` event.
* If the exception is not handled by any event handler, it will call
* {@link getErrorHandler errorHandler} to process the exception.
*
* The application will be terminated by this method.
*
* @param Exception $exception exception that is not caught
*/
public function handleException($exception)
{
// disable error capturing to avoid recursive errors
restore_error_handler();
restore_exception_handler();
$category = 'exception.' . get_class($exception);
if ($exception instanceof \yii\web\HttpException) {
$category .= '.' . $exception->statusCode;
}
// php <5.2 doesn't support string conversion auto-magically
$message = $exception->__toString();
if (isset($_SERVER['REQUEST_URI'])) {
$message .= ' REQUEST_URI=' . $_SERVER['REQUEST_URI'];
}
\Yii::error($message, $category);
try
{
// TODO: do we need separate exception class as it was in 1.1?
//$event = new CExceptionEvent($this, $exception);
$event = new Event($this, array('exception' => $exception));
$this->onException($event);
if (!$event->handled) {
// try an error handler
if (($handler = $this->getErrorHandler()) !== null) {
$handler->handle($event);
} else
{
$this->displayException($exception);
}
}
}
catch (Exception $e)
{
$this->displayException($e);
}
try
{
$this->end(1);
}
catch (Exception $e)
{
// use the most primitive way to log error
$msg = get_class($e) . ': ' . $e->getMessage() . ' (' . $e->getFile() . ':' . $e->getLine() . ")\n";
$msg .= $e->getTraceAsString() . "\n";
$msg .= "Previous exception:\n";
$msg .= get_class($exception) . ': ' . $exception->getMessage() . ' (' . $exception->getFile() . ':' . $exception->getLine() . ")\n";
$msg .= $exception->getTraceAsString() . "\n";
$msg .= '$_SERVER=' . var_export($_SERVER, true);
error_log($msg);
exit(1);
}
}
/**
* Handles PHP execution errors such as warnings, notices.
*
* This method is implemented as a PHP error handler. It requires
* that constant YII_ENABLE_ERROR_HANDLER be defined true.
*
* This method will first raise an `error` event.
* If the error is not handled by any event handler, it will call
* {@link getErrorHandler errorHandler} to process the error.
*
* The application will be terminated by this method.
*
* @param integer $code the level of the error raised
* @param string $message the error message
* @param string $file the filename that the error was raised in
* @param integer $line the line number the error was raised at
*/
public function handleError($code, $message, $file, $line)
{
if ($code & error_reporting()) {
// disable error capturing to avoid recursive errors
restore_error_handler();
restore_exception_handler();
$log = "$message ($file:$line)\nStack trace:\n";
$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);
}
foreach ($trace as $i => $t)
{
if (!isset($t['file'])) {
$t['file'] = 'unknown';
}
if (!isset($t['line'])) {
$t['line'] = 0;
}
if (!isset($t['function'])) {
$t['function'] = 'unknown';
}
$log .= "#$i {$t['file']}( {$t['line']}): ";
if (isset($t['object']) && is_object($t['object'])) {
$log .= get_class($t['object']) . '->';
}
$log .= " {$t['function']}()\n";
}
if (isset($_SERVER['REQUEST_URI'])) {
$log .= 'REQUEST_URI=' . $_SERVER['REQUEST_URI'];
}
\Yii::error($log, 'php');
try
{
\Yii::import('CErrorEvent', true);
$event = new CErrorEvent($this, $code, $message, $file, $line);
$this->onError($event);
if (!$event->handled) {
// try an error handler
if (($handler = $this->getErrorHandler()) !== null) {
$handler->handle($event);
} else
{
$this->displayError($code, $message, $file, $line);
}
}
}
catch (Exception $e)
{
$this->displayException($e);
}
try
{
$this->end(1);
}
catch (Exception $e)
{
// use the most primitive way to log error
$msg = get_class($e) . ': ' . $e->getMessage() . ' (' . $e->getFile() . ':' . $e->getLine() . ")\n";
$msg .= $e->getTraceAsString() . "\n";
$msg .= "Previous error:\n";
$msg .= $log . "\n";
$msg .= '$_SERVER=' . var_export($_SERVER, true);
error_log($msg);
exit(1);
}
}
}
/**
* Displays the captured PHP error.
* This method displays the error in HTML when there is
* no active error handler.
* @param integer $code error code
* @param string $message error message
* @param string $file error file
* @param string $line error line
*/
public function displayError($code, $message, $file, $line)
{
if (YII_DEBUG) {
echo "<h1>PHP Error [$code]</h1>\n";
echo "<p>$message ($file:$line)</p>\n";
echo '<pre>';
$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);
}
foreach ($trace as $i => $t)
{
if (!isset($t['file'])) {
$t['file'] = 'unknown';
}
if (!isset($t['line'])) {
$t['line'] = 0;
}
if (!isset($t['function'])) {
$t['function'] = 'unknown';
}
echo "#$i {$t['file']}( {$t['line']}): ";
if (isset($t['object']) && is_object($t['object'])) {
echo get_class($t['object']) . '->';
}
echo " {$t['function']}()\n";
}
echo '</pre>';
} else
{
echo "<h1>PHP Error [$code]</h1>\n";
echo "<p>$message</p>\n";
}
}
/**
* Displays the uncaught PHP exception.
* This method displays the exception in HTML when there is
* no active error handler.
* @param Exception $exception the uncaught exception
*/
public function displayException($exception)
{
if (YII_DEBUG) {
echo '<h1>' . get_class($exception) . "</h1>\n";
echo '<p>' . $exception->getMessage() . ' (' . $exception->getFile() . ':' . $exception->getLine() . ')</p>';
echo '<pre>' . $exception->getTraceAsString() . '</pre>';
} else
{
echo '<h1>' . get_class($exception) . "</h1>\n";
echo '<p>' . $exception->getMessage() . '</p>';
}
}
/**
* Registers the core application components. * Registers the core application components.
* @see setComponents * @see setComponents
*/ */
@ -654,7 +410,7 @@ abstract class Application extends Module
'class' => 'yii\base\Request', 'class' => 'yii\base\Request',
), ),
'response' => array( 'response' => array(
'class' => 'yii\base\Request', 'class' => 'yii\base\Response',
), ),
'format' => array( 'format' => array(
'class' => 'yii\base\Formatter', 'class' => 'yii\base\Formatter',
@ -662,7 +418,7 @@ abstract class Application extends Module
'coreMessages' => array( 'coreMessages' => array(
'class' => 'yii\i18n\PhpMessageSource', 'class' => 'yii\i18n\PhpMessageSource',
'language' => 'en_us', 'language' => 'en_us',
'basePath' => YII_PATH . DIRECTORY_SEPARATOR . 'messages', 'basePath' => '@yii/messages',
), ),
'messages' => array( 'messages' => array(
'class' => 'yii\i18n\PhpMessageSource', 'class' => 'yii\i18n\PhpMessageSource',

490
framework/base/Controller.php

@ -0,0 +1,490 @@
<?php
/**
* Controller class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008-2012 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
/**
* Controller is the base class for {@link CController} and {@link CWidget}.
*
* It provides the common functionalities shared by controllers who need to render views.
*
* Controller also implements the support for the following features:
* <ul>
* <li>{@link CClipWidget Clips} : a clip is a piece of captured output that can be inserted elsewhere.</li>
* <li>{@link CWidget Widgets} : a widget is a self-contained sub-controller with its own view and model.</li>
* <li>{@link COutputCache Fragment cache} : fragment cache selectively caches a portion of the output.</li>
* </ul>
*
* To use a widget in a view, use the following in the view:
* <pre>
* $this->widget('path.to.widgetClass',array('property1'=>'value1',...));
* </pre>
* or
* <pre>
* $this->beginWidget('path.to.widgetClass',array('property1'=>'value1',...));
* // ... display other contents here
* $this->endWidget();
* </pre>
*
* To create a clip, use the following:
* <pre>
* $this->beginClip('clipID');
* // ... display the clip contents
* $this->endClip();
* </pre>
* Then, in a different view or place, the captured clip can be inserted as:
* <pre>
* echo $this->clips['clipID'];
* </pre>
*
* Note that $this in the code above refers to current controller so, for example,
* if you need to access clip from a widget where $this refers to widget itself
* you need to do it the following way:
*
* <pre>
* echo $this->getController()->clips['clipID'];
* </pre>
*
* To use fragment cache, do as follows,
* <pre>
* if($this->beginCache('cacheID',array('property1'=>'value1',...))
* {
* // ... display the content to be cached here
* $this->endCache();
* }
* </pre>
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
abstract class Controller extends Component implements Initable
{
/**
* @var string the name of the default action. Defaults to 'index'.
*/
public $defaultAction = 'index';
private $_id;
private $_action;
private $_module;
/**
* @param string $id id of this controller
* @param CWebModule $module the module that this controller belongs to.
*/
public function __construct($id, $module = null)
{
$this->_id = $id;
$this->_module = $module;
}
/**
* Initializes the controller.
* This method is called by the application before the controller starts to execute.
* You may override this method to perform the needed initialization for the controller.
*/
public function init()
{
}
/**
* Returns the filter configurations.
*
* By overriding this method, child classes can specify filters to be applied to actions.
*
* This method returns an array of filter specifications. Each array element specify a single filter.
*
* For a method-based filter (called inline filter), it is specified as 'FilterName[ +|- Action1, Action2, ...]',
* where the '+' ('-') operators describe which actions should be (should not be) applied with the filter.
*
* For a class-based filter, it is specified as an array like the following:
* <pre>
* array(
* 'FilterClass[ +|- Action1, Action2, ...]',
* 'name1'=>'value1',
* 'name2'=>'value2',
* ...
* )
* </pre>
* where the name-value pairs will be used to initialize the properties of the filter.
*
* Note, in order to inherit filters defined in the parent class, a child class needs to
* merge the parent filters with child filters using functions like array_merge().
*
* @return array a list of filter configurations.
* @see CFilter
*/
public function filters()
{
return array();
}
/**
* Returns a list of external action classes.
* Array keys are action IDs, and array values are the corresponding
* action class in dot syntax (e.g. 'edit'=>'application.controllers.article.EditArticle')
* or arrays representing the configuration of the actions, such as the following,
* <pre>
* return array(
* 'action1'=>'path.to.Action1Class',
* 'action2'=>array(
* 'class'=>'path.to.Action2Class',
* 'property1'=>'value1',
* 'property2'=>'value2',
* ),
* );
* </pre>
* Derived classes may override this method to declare external actions.
*
* Note, in order to inherit actions defined in the parent class, a child class needs to
* merge the parent actions with child actions using functions like array_merge().
*
* You may import actions from an action provider
* (such as a widget, see {@link CWidget::actions}), like the following:
* <pre>
* return array(
* ...other actions...
* // import actions declared in ProviderClass::actions()
* // the action IDs will be prefixed with 'pro.'
* 'pro.'=>'path.to.ProviderClass',
* // similar as above except that the imported actions are
* // configured with the specified initial property values
* 'pro2.'=>array(
* 'class'=>'path.to.ProviderClass',
* 'action1'=>array(
* 'property1'=>'value1',
* ),
* 'action2'=>array(
* 'property2'=>'value2',
* ),
* ),
* )
* </pre>
*
* In the above, we differentiate action providers from other action
* declarations by the array keys. For action providers, the array keys
* must contain a dot. As a result, an action ID 'pro2.action1' will
* be resolved as the 'action1' action declared in the 'ProviderClass'.
*
* @return array list of external action classes
* @see createAction
*/
public function actions()
{
return array();
}
/**
* Returns the access rules for this controller.
* Override this method if you use the {@link filterAccessControl accessControl} filter.
* @return array list of access rules. See {@link CAccessControlFilter} for details about rule specification.
*/
public function accessRules()
{
return array();
}
/**
* Runs the named action.
* Filters specified via {@link filters()} will be applied.
* @param string $actionID action ID
* @throws CHttpException if the action does not exist or the action name is not proper.
* @see filters
* @see createAction
* @see runAction
*/
public function run($actionID)
{
if (($action = $this->createAction($actionID)) !== null) {
if (($parent = $this->getModule()) === null) {
$parent = Yii::app();
}
if ($parent->beforeControllerAction($this, $action)) {
$this->runActionWithFilters($action, $this->filters());
$parent->afterControllerAction($this, $action);
}
}
else
{
$this->missingAction($actionID);
}
}
/**
* Runs an action with the specified filters.
* A filter chain will be created based on the specified filters
* and the action will be executed then.
* @param CAction $action the action to be executed.
* @param array $filters list of filters to be applied to the action.
* @see filters
* @see createAction
* @see runAction
*/
public function runActionWithFilters($action, $filters)
{
if (empty($filters)) {
$this->runAction($action);
}
else
{
$priorAction = $this->_action;
$this->_action = $action;
CFilterChain::create($this, $action, $filters)->run();
$this->_action = $priorAction;
}
}
/**
* Runs the action after passing through all filters.
* This method is invoked by {@link runActionWithFilters} after all possible filters have been executed
* and the action starts to run.
* @param CAction $action action to run
*/
public function runAction($action)
{
$priorAction = $this->_action;
$this->_action = $action;
if ($this->beforeAction($action)) {
if ($action->runWithParams($this->getActionParams()) === false) {
$this->invalidActionParams($action);
}
else
{
$this->afterAction($action);
}
}
$this->_action = $priorAction;
}
/**
* Returns the request parameters that will be used for action parameter binding.
* By default, this method will return $_GET. You may override this method if you
* want to use other request parameters (e.g. $_GET+$_POST).
* @return array the request parameters to be used for action parameter binding
* @since 1.1.7
*/
public function getActionParams()
{
return $_GET;
}
/**
* This method is invoked when the request parameters do not satisfy the requirement of the specified action.
* The default implementation will throw a 400 HTTP exception.
* @param CAction $action the action being executed
* @since 1.1.7
*/
public function invalidActionParams($action)
{
throw new CHttpException(400, Yii::t('yii', 'Your request is invalid.'));
}
/**
* Creates the action instance based on the action name.
* The action can be either an inline action or an object.
* The latter is created by looking up the action map specified in {@link actions}.
* @param string $actionID ID of the action. If empty, the {@link defaultAction default action} will be used.
* @return CAction the action instance, null if the action does not exist.
* @see actions
*/
public function createAction($actionID)
{
if ($actionID === '') {
$actionID = $this->defaultAction;
}
if (method_exists($this, 'action' . $actionID) && strcasecmp($actionID, 's')) // we have actions method
{
return new CInlineAction($this, $actionID);
}
else
{
$action = $this->createActionFromMap($this->actions(), $actionID, $actionID);
if ($action !== null && !method_exists($action, 'run')) {
throw new CException(Yii::t('yii', 'Action class {class} must implement the "run" method.', array('{class}' => get_class($action))));
}
return $action;
}
}
/**
* Creates the action instance based on the action map.
* This method will check to see if the action ID appears in the given
* action map. If so, the corresponding configuration will be used to
* create the action instance.
* @param array $actionMap the action map
* @param string $actionID the action ID that has its prefix stripped off
* @param string $requestActionID the originally requested action ID
* @param array $config the action configuration that should be applied on top of the configuration specified in the map
* @return CAction the action instance, null if the action does not exist.
*/
protected function createActionFromMap($actionMap, $actionID, $requestActionID, $config = array())
{
if (($pos = strpos($actionID, '.')) === false && isset($actionMap[$actionID])) {
$baseConfig = is_array($actionMap[$actionID]) ? $actionMap[$actionID] : array('class' => $actionMap[$actionID]);
return Yii::createComponent(empty($config) ? $baseConfig : array_merge($baseConfig, $config), $this, $requestActionID);
}
else {
if ($pos === false) {
return null;
}
}
// the action is defined in a provider
$prefix = substr($actionID, 0, $pos + 1);
if (!isset($actionMap[$prefix])) {
return null;
}
$actionID = (string)substr($actionID, $pos + 1);
$provider = $actionMap[$prefix];
if (is_string($provider)) {
$providerType = $provider;
}
else {
if (is_array($provider) && isset($provider['class'])) {
$providerType = $provider['class'];
if (isset($provider[$actionID])) {
if (is_string($provider[$actionID])) {
$config = array_merge(array('class' => $provider[$actionID]), $config);
}
else
{
$config = array_merge($provider[$actionID], $config);
}
}
}
else
{
throw new CException(Yii::t('yii', 'Object configuration must be an array containing a "class" element.'));
}
}
$class = Yii::import($providerType, true);
$map = call_user_func(array($class, 'actions'));
return $this->createActionFromMap($map, $actionID, $requestActionID, $config);
}
/**
* Handles the request whose action is not recognized.
* This method is invoked when the controller cannot find the requested action.
* The default implementation simply throws an exception.
* @param string $actionID the missing action name
* @throws CHttpException whenever this method is invoked
*/
public function missingAction($actionID)
{
throw new CHttpException(404, Yii::t('yii', 'The system is unable to find the requested action "{action}".',
array('{action}' => $actionID == '' ? $this->defaultAction : $actionID)));
}
/**
* @return CAction the action currently being executed, null if no active action.
*/
public function getAction()
{
return $this->_action;
}
/**
* @param CAction $value the action currently being executed.
*/
public function setAction($value)
{
$this->_action = $value;
}
/**
* @return string ID of the controller
*/
public function getId()
{
return $this->_id;
}
/**
* @return string the controller ID that is prefixed with the module ID (if any).
*/
public function getUniqueId()
{
return $this->_module ? $this->_module->getId() . '/' . $this->_id : $this->_id;
}
/**
* @return string the route (module ID, controller ID and action ID) of the current request.
* @since 1.1.0
*/
public function getRoute()
{
if (($action = $this->getAction()) !== null) {
return $this->getUniqueId() . '/' . $action->getId();
}
else
{
return $this->getUniqueId();
}
}
/**
* @return CWebModule the module that this controller belongs to. It returns null
* if the controller does not belong to any module
*/
public function getModule()
{
return $this->_module;
}
/**
* Processes the request using another controller action.
* This is like {@link redirect}, but the user browser's URL remains unchanged.
* In most cases, you should call {@link redirect} instead of this method.
* @param string $route the route of the new controller action. This can be an action ID, or a complete route
* with module ID (optional in the current module), controller ID and action ID. If the former, the action is assumed
* to be located within the current controller.
* @param boolean $exit whether to end the application after this call. Defaults to true.
* @since 1.1.0
*/
public function forward($route, $exit = true)
{
if (strpos($route, '/') === false) {
$this->run($route);
}
else
{
if ($route[0] !== '/' && ($module = $this->getModule()) !== null) {
$route = $module->getId() . '/' . $route;
}
Yii::app()->runController($route);
}
if ($exit) {
Yii::app()->end();
}
}
/**
* This method is invoked right before an action is to be executed (after all possible filters.)
* You may override this method to do last-minute preparation for the action.
* @param CAction $action the action to be executed.
* @return boolean whether the action should be executed.
*/
protected function beforeAction($action)
{
return true;
}
/**
* This method is invoked right after an action is executed.
* You may override this method to do some postprocessing for the action.
* @param CAction $action the action just executed.
*/
protected function afterAction($action)
{
}
}

38
framework/base/ErrorHandler.php

@ -12,9 +12,16 @@ namespace yii\base;
/** /**
* ErrorHandler handles uncaught PHP errors and exceptions. * ErrorHandler handles uncaught PHP errors and exceptions.
* *
* It displays these errors using appropriate views based on the * ErrorHandler displays these errors using appropriate views based on the
* nature of the error and the mode the application runs at. * nature of the errors and the mode the application runs at.
* It also chooses the most preferred language for displaying the error. *
* ErrorHandler does the following when the application encounters an error or exception:
*
* - If it is a PHP error, warning or notice, an ErrorException will be thrown which
* if not caught, will be handled in the next few steps
* - If it is an uncaught exception, it will invoke the action defined by [[errorAction]]
* to handle the exception;
* - If [[errorAction]] is not defined, it will
* *
* ErrorHandler uses two sets of views: * ErrorHandler uses two sets of views:
* <ul> * <ul>
@ -58,7 +65,6 @@ class ErrorHandler extends ApplicationComponent
* @var integer maximum number of source code lines to be displayed. Defaults to 25. * @var integer maximum number of source code lines to be displayed. Defaults to 25.
*/ */
public $maxSourceLines = 25; public $maxSourceLines = 25;
/** /**
* @var integer maximum number of trace source code lines to be displayed. Defaults to 10. * @var integer maximum number of trace source code lines to be displayed. Defaults to 10.
*/ */
@ -90,7 +96,7 @@ class ErrorHandler extends ApplicationComponent
/** /**
* Handles PHP execution errors such as warnings, notices. * Handles PHP execution errors such as warnings, notices.
* *
* This method is implemented as a PHP error handler. It requires * This method is used as a PHP error handler. It requires
* that constant YII_ENABLE_ERROR_HANDLER be defined true. * that constant YII_ENABLE_ERROR_HANDLER be defined true.
* *
* This method will first raise an `error` event. * This method will first raise an `error` event.
@ -135,19 +141,17 @@ class ErrorHandler extends ApplicationComponent
protected function render($exception) protected function render($exception)
{ {
if (\Yii::$application instanceof \yii\web\Application) { if ($this->errorAction !== null) {
if ($this->errorAction !== null) { \Yii::$application->runController($this->errorAction);
\Yii::$application->runController($this->errorAction); } elseif (\Yii::$application instanceof \yii\web\Application) {
if (!headers_sent()) {
$errorCode = $exception instanceof HttpException ? $exception->statusCode : 500;
header("HTTP/1.0 $errorCode " . get_class($exception));
}
if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest') {
$this->renderAsText($exception);
} else { } else {
if (!headers_sent()) { $this->renderAsHtml($exception);
$errorCode = $exception instanceof HttpException ? $exception->statusCode : 500;
header("HTTP/1.0 $errorCode " . get_class($exception));
}
if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest') {
$this->renderAsText($exception);
} else {
$this->renderAsHtml($exception);
}
} }
} else { } else {
$this->renderAsText($exception); $this->renderAsText($exception);

53
framework/base/InlineAction.php

@ -0,0 +1,53 @@
<?php
/**
* CInlineAction class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008-2011 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
/**
* CInlineAction represents an action that is defined as a controller method.
*
* The method name is like 'actionXYZ' where 'XYZ' stands for the action name.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @version $Id$
* @package system.web.actions
* @since 1.0
*/
class CInlineAction extends CAction
{
/**
* Runs the action.
* The action method defined in the controller is invoked.
* This method is required by {@link CAction}.
*/
public function run()
{
$method='action'.$this->getId();
$this->getController()->$method();
}
/**
* Runs the action with the supplied request parameters.
* This method is internally called by {@link CController::runAction()}.
* @param array $params the request parameters (name=>value)
* @return boolean whether the request parameters are valid
* @since 1.1.7
*/
public function runWithParams($params)
{
$methodName='action'.$this->getId();
$controller=$this->getController();
$method=new ReflectionMethod($controller, $methodName);
if($method->getNumberOfParameters()>0)
return $this->runWithParamsInternal($controller, $method, $params);
else
return $controller->$methodName();
}
}

61
framework/base/InlineActionFilter.php

@ -0,0 +1,61 @@
<?php
/**
* CInlineFilter class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008-2011 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
/**
* CInlineFilter represents a filter defined as a controller method.
*
* CInlineFilter executes the 'filterXYZ($action)' method defined
* in the controller, where the name 'XYZ' can be retrieved from the {@link name} property.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @version $Id$
* @package system.web.filters
* @since 1.0
*/
class CInlineFilter extends CFilter
{
/**
* @var string name of the filter. It stands for 'XYZ' in the filter method name 'filterXYZ'.
*/
public $name;
/**
* Creates an inline filter instance.
* The creation is based on a string describing the inline method name
* and action names that the filter shall or shall not apply to.
* @param CController $controller the controller who hosts the filter methods
* @param string $filterName the filter name
* @return CInlineFilter the created instance
* @throws CException if the filter method does not exist
*/
public static function create($controller,$filterName)
{
if(method_exists($controller,'filter'.$filterName))
{
$filter=new CInlineFilter;
$filter->name=$filterName;
return $filter;
}
else
throw new CException(Yii::t('yii','Filter "{filter}" is invalid. Controller "{class}" does not have the filter method "filter{filter}".',
array('{filter}'=>$filterName, '{class}'=>get_class($controller))));
}
/**
* Performs the filtering.
* This method calls the filter method defined in the controller class.
* @param CFilterChain $filterChain the filter chain that the filter is on.
*/
public function filter($filterChain)
{
$method='filter'.$this->name;
$filterChain->controller->$method($filterChain);
}
}

5
framework/base/Module.php

@ -136,10 +136,11 @@ abstract class Module extends Component implements Initable
*/ */
public function setBasePath($path) public function setBasePath($path)
{ {
if (($p = realpath($path)) === false || !is_dir($p)) { $p = \Yii::getAlias($path);
if ($p === false || !is_dir($p)) {
throw new Exception('Invalid base path: ' . $path); throw new Exception('Invalid base path: ' . $path);
} else { } else {
$this->_basePath = $p; $this->_basePath = realpath($p);
} }
} }

Loading…
Cancel
Save