Commit 3fa22483 by Qiang Xue

refactored logging.

MVC WIP
parent 77e0be5c
......@@ -121,8 +121,8 @@ class YiiBase
*
* To import a class or a directory, one can use either path alias or class name (can be namespaced):
*
* - `@app/components/GoogleMap`: importing the `GoogleMap` class with a path alias;
* - `@app/components/*`: importing the whole `components` directory with a path alias;
* - `@application/components/GoogleMap`: importing the `GoogleMap` class with a path alias;
* - `@application/components/*`: importing the whole `components` directory with a path alias;
* - `GoogleMap`: importing the `GoogleMap` class with a class name. [[autoload()]] will be used
* when this class is used for the first time.
*
......@@ -322,12 +322,12 @@ class YiiBase
* the class. For example,
*
* - `\app\components\GoogleMap`: fully-qualified namespaced class.
* - `@app/components/GoogleMap`: an alias
* - `@application/components/GoogleMap`: an alias
*
* Below are some usage examples:
*
* ~~~
* $object = \Yii::createObject('@app/components/GoogleMap');
* $object = \Yii::createObject('@application/components/GoogleMap');
* $object = \Yii::createObject(array(
* 'class' => '\app\components\GoogleMap',
* 'apiKey' => 'xyz',
......
......@@ -10,8 +10,8 @@
namespace yii\base;
use Yii;
use yii\util\FileHelper;
use yii\base\InvalidCallException;
use yii\util\StringHelper;
/**
* Application is the base class for all application classes.
......@@ -37,7 +37,7 @@ use yii\util\StringHelper;
* Yii framework messages. This application component is dynamically loaded when needed.</li>
* </ul>
*
* Application will undergo the following lifecycles when processing a user request:
* Application will undergo the following life cycles when processing a user request:
* <ol>
* <li>load application configuration;</li>
* <li>set up class autoloader and error handling;</li>
......@@ -50,28 +50,6 @@ use yii\util\StringHelper;
* 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.
*
* @property string $basePath Returns the root path of the application.
* @property CCache $cache Returns the cache component.
* @property CPhpMessageSource $coreMessages Returns the core message translations.
* @property CDateFormatter $dateFormatter Returns the locale-dependent date formatter.
* @property \yii\db\Connection $db Returns the database connection component.
* @property CErrorHandler $errorHandler Returns the error handler component.
* @property string $extensionPath Returns the root directory that holds all third-party extensions.
* @property string $id Returns the unique identifier for the application.
* @property string $language Returns the language that the user is using and the application should be targeted to.
* @property CLocale $locale Returns the locale instance.
* @property string $localeDataPath Returns the directory that contains the locale data.
* @property CMessageSource $messages Returns the application message translations component.
* @property CNumberFormatter $numberFormatter The locale-dependent number formatter.
* @property CHttpRequest $request Returns the request component.
* @property string $runtimePath Returns the directory that stores runtime files.
* @property CSecurityManager $securityManager Returns the security manager component.
* @property CStatePersister $statePersister Returns the state persister component.
* @property string $timeZone Returns the time zone used by this application.
* @property UrlManager $urlManager Returns the URL manager component.
* @property string $baseUrl Returns the relative URL for the application
* @property string $homeUrl the homepage URL
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
......@@ -134,7 +112,7 @@ class Application extends Module
$this->setBasePath($basePath);
$this->registerDefaultAliases();
$this->registerCoreComponents();
parent::__construct($id, $this, $config);
Component::__construct($config);
}
/**
......@@ -204,27 +182,6 @@ class Application extends Module
}
/**
* Runs a controller with the given route and parameters.
* @param string $route the route (e.g. `post/create`)
* @param array $params the parameters to be passed to the controller action
* @return integer the exit status (0 means normal, non-zero values mean abnormal)
* @throws InvalidRequestException if the route cannot be resolved into a controller
*/
public function runController($route, $params = array())
{
$result = $this->createController($route);
if ($result === false) {
throw new InvalidRequestException(Yii::t('yii', 'Unable to resolve the request.'));
}
$priorController = $this->controller;
$this->controller = $controllerObject;
$status = $controllerObject->run($action, $params);
$this->controller = $priorController;
return $status;
}
/**
* Returns the directory that stores runtime files.
* @return string the directory that stores runtime files. Defaults to 'protected/runtime'.
*/
......@@ -239,15 +196,15 @@ class Application extends Module
/**
* Sets the directory that stores runtime files.
* @param string $path the directory that stores runtime files.
* @throws InvalidCallException if the directory does not exist or is not writable
* @throws InvalidConfigException if the directory does not exist or is not writable
*/
public function setRuntimePath($path)
{
$p = Yii::getAlias($path);
if ($p === false || !is_dir($p) || !is_writable($path)) {
throw new InvalidCallException("Application runtime path \"$path\" is invalid. Please make sure it is a directory writable by the Web server process.");
} else {
$p = FileHelper::ensureDirectory($path);
if (is_writable($p)) {
$this->_runtimePath = $p;
} else {
throw new InvalidConfigException("Runtime path must be writable by the Web server process: $path");
}
}
......@@ -296,34 +253,61 @@ class Application extends Module
date_default_timezone_set($value);
}
/**
* Returns the locale instance.
* @param string $localeID the locale ID (e.g. en_US). If null, the {@link getLanguage application language ID} will be used.
* @return CLocale the locale instance
*/
public function getLocale($localeID = null)
{
return CLocale::getInstance($localeID === null ? $this->getLanguage() : $localeID);
}
/**
* @return CNumberFormatter the locale-dependent number formatter.
* The current {@link getLocale application locale} will be used.
*/
public function getNumberFormatter()
{
return $this->getLocale()->getNumberFormatter();
}
/**
* Returns the locale-dependent date formatter.
* @return CDateFormatter the locale-dependent date formatter.
* The current {@link getLocale application locale} will be used.
*/
public function getDateFormatter()
{
return $this->getLocale()->getDateFormatter();
}
// /**
// * Returns the security manager component.
// * @return SecurityManager the security manager application component.
// */
// public function getSecurityManager()
// {
// return $this->getComponent('securityManager');
// }
//
// /**
// * Returns the locale instance.
// * @param string $localeID the locale ID (e.g. en_US). If null, the {@link getLanguage application language ID} will be used.
// * @return CLocale the locale instance
// */
// public function getLocale($localeID = null)
// {
// return CLocale::getInstance($localeID === null ? $this->getLanguage() : $localeID);
// }
//
// /**
// * @return CNumberFormatter the locale-dependent number formatter.
// * The current {@link getLocale application locale} will be used.
// */
// public function getNumberFormatter()
// {
// return $this->getLocale()->getNumberFormatter();
// }
//
// /**
// * Returns the locale-dependent date formatter.
// * @return CDateFormatter the locale-dependent date formatter.
// * The current {@link getLocale application locale} will be used.
// */
// public function getDateFormatter()
// {
// return $this->getLocale()->getDateFormatter();
// }
//
// /**
// * Returns the core message translations component.
// * @return \yii\i18n\MessageSource the core message translations
// */
// public function getCoreMessages()
// {
// return $this->getComponent('coreMessages');
// }
//
// /**
// * Returns the application message translations component.
// * @return \yii\i18n\MessageSource the application message translations
// */
// public function getMessages()
// {
// return $this->getComponent('messages');
// }
/**
* Returns the database connection component.
......@@ -353,15 +337,6 @@ class Application extends Module
}
/**
* Returns the security manager component.
* @return SecurityManager the security manager application component.
*/
public function getSecurityManager()
{
return $this->getComponent('securityManager');
}
/**
* Returns the cache component.
* @return \yii\caching\Cache the cache application component. Null if the component is not enabled.
*/
......@@ -371,24 +346,6 @@ class Application extends Module
}
/**
* Returns the core message translations component.
* @return \yii\i18n\MessageSource the core message translations
*/
public function getCoreMessages()
{
return $this->getComponent('coreMessages');
}
/**
* Returns the application message translations component.
* @return \yii\i18n\MessageSource the application message translations
*/
public function getMessages()
{
return $this->getComponent('messages');
}
/**
* Returns the request component.
* @return Request the request component
*/
......@@ -417,15 +374,6 @@ class Application extends Module
'errorHandler' => array(
'class' => 'yii\base\ErrorHandler',
),
'request' => array(
'class' => 'yii\base\Request',
),
'response' => array(
'class' => 'yii\base\Response',
),
'format' => array(
'class' => 'yii\base\Formatter',
),
'coreMessages' => array(
'class' => 'yii\i18n\PhpMessageSource',
'language' => 'en_us',
......@@ -442,117 +390,4 @@ class Application extends Module
),
));
}
/**
* Performs a controller action specified by a route.
* This method parses the specified route and creates the corresponding controller and action
* instances under the context of the specified module. It then runs the created action
* with the given parameters.
* @param string $route the route that specifies the action.
* @param array $params the parameters to be passed to the action
* @param Module $module the module which serves as the context of the route
* @return integer the action
* @throws InvalidConfigException if the module's defaultRoute is empty or the controller's defaultAction is empty
* @throws InvalidRequestException if the requested route cannot be resolved into an action successfully
*/
public function runAction($route, $params = array(), $module = null)
{
if ($module === null) {
$module = $this;
}
$route = trim($route, '/');
if ($route === '') {
$route = trim($module->defaultRoute, '/');
if ($route == '') {
throw new InvalidConfigException(get_class($module) . '::defaultRoute cannot be empty.');
}
}
if (($pos = strpos($route, '/')) !== false) {
$id = substr($route, 0, $pos);
$route = substr($route, $pos + 1);
} else {
$id = $route;
$route = '';
}
$childModule = $module->getModule($id);
if ($childModule !== null) {
return $this->runAction($route, $params, $childModule);
}
$controller = $this->createController($id, $module);
if ($controller !== null) {
if ($route === '') {
$route = $controller->defaultAction;
if ($route == '') {
throw new InvalidConfigException(get_class($controller) . '::defaultAction cannot be empty.');
}
}
$action = $this->createAction($route, $controller);
if ($action !== null) {
return $action->runWithParams($params);
}
}
throw new InvalidRequestException("Unable to resolve the request: $route");
}
/**
* Creates a controller instance based on the controller ID.
*
* The controller is created within the given module. The method first attempts to
* create the controller based on the [[controllerMap]] of the module. If not available,
* it will look for the controller class under the [[controllerPath]] and create an
* instance of it.
*
* @param string $id the controller ID
* @param Module $module the module that owns the controller
* @return Controller the newly created controller instance
*/
public function createController($id, $module)
{
if (isset($module->controllerMap[$id])) {
return Yii::createObject($module->controllerMap[$id], $id, $module);
} elseif (preg_match('/^[a-z0-9\\-_]+$/', $id)) {
$className = StringHelper::id2camel($id) . 'Controller';
$classFile = $module->controllerPath . DIRECTORY_SEPARATOR . $className . '.php';
if (is_file($classFile)) {
$className = $module->controllerNamespace . '\\' . $className;
if (!class_exists($className, false)) {
require($classFile);
}
if (class_exists($className, false) && is_subclass_of($className, '\yii\base\Controller')) {
return new $className($id, $module);
}
}
}
return null;
}
/**
* Creates an action based on the given action ID.
* The action is created within the given controller. The method first attempts to
* create the action based on [[Controller::actions()]]. If not available,
* it will look for the inline action method within the controller.
* @param string $id the action ID
* @param Controller $controller the controller that owns the action
* @return Action the newly created action instance
*/
public function createAction($id, $controller)
{
if (isset($controller->actionMap[$id])) {
return Yii::createObject($controller->actionMap[$id], $id, $controller);
} elseif (preg_match('/^[a-z0-9\\-_]+$/', $id)) {
$methodName = 'action' . StringHelper::id2camel($id);
if (method_exists($controller, $methodName)) {
$method = new \ReflectionMethod($controller, $methodName);
if ($method->getName() === $methodName) {
return new InlineAction($id, $controller);
}
}
}
return null;
}
}
......@@ -9,6 +9,9 @@
namespace yii\base;
use Yii;
use yii\util\StringHelper;
/**
* Controller is the base class for classes containing controller logic.
*
......@@ -27,6 +30,10 @@ namespace yii\base;
*/
class Controller extends Component
{
const EVENT_AUTHORIZE = 'authorize';
const EVENT_BEFORE_ACTION = 'beforeAction';
const EVENT_AFTER_ACTION = 'afterAction';
/**
* @var string the ID of this controller
*/
......@@ -91,65 +98,138 @@ class Controller extends Component
}
/**
* Runs the controller with the specified action and parameters.
* @param Action|string $action the action to be executed. This can be either an action object
* or the ID of the action.
* Runs an action with the specified action ID and parameters.
* If the action ID is empty, the method will use [[defaultAction]].
* @param string $id the ID of the action to be executed.
* @param array $params the parameters (name-value pairs) to be passed to the action.
* If null, the result of [[getActionParams()]] will be used as action parameters.
* @return integer the exit status of the action. 0 means normal, other values mean abnormal.
* @see missingAction
* @return integer the status of the action execution. 0 means normal, other values mean abnormal.
* @throws InvalidRouteException if the requested action ID cannot be resolved into an action successfully.
* @see createAction
*/
public function run($action, $params = null)
public function runAction($id, $params = array())
{
if (is_string($action)) {
if (($a = $this->createAction($action)) !== null) {
$action = $a;
} else {
$this->missingAction($action);
return 1;
}
if ($id === '') {
$id = $this->defaultAction;
}
$priorAction = $this->action;
$action = $this->createAction($id);
if ($action !== null) {
$oldAction = $this->action;
$this->action = $action;
if ($this->authorize($action) && $this->beforeAction($action)) {
if ($params === null) {
$params = $this->getActionParams();
}
$status = $action->runWithParams($params);
$this->afterAction($action);
} else {
$status = 1;
}
$this->action = $priorAction;
$this->action = $oldAction;
return $status;
} else {
throw new InvalidRouteException('Unable to resolve the request: ' . $this->getUniqueId() . '/' . $id);
}
}
/**
* Creates the action instance based on the action ID.
* The action can be either an inline action or an object.
* The latter is created by looking up the action map specified in [[actions]].
* @param string $actionID ID of the action. If empty, it will take the value of [[defaultAction]].
* @return Action the action instance, null if the action does not exist.
* @see actions
* Runs a request specified in terms of a route.
* The route can be either an ID of an action within this controller or a complete route consisting
* of module IDs, controller ID and action ID. If the route starts with a slash '/', the parsing of
* the route will start from the application; otherwise, it will start from the parent module of this controller.
* @param string $route the route to be handled, e.g., 'view', 'comment/view', '/admin/comment/view'.
* @param array $params the parameters to be passed to the action.
* @return integer the status code returned by the action execution. 0 means normal, and other values mean abnormal.
* @see runAction
* @see forward
*/
public function createAction($actionID)
public function run($route, $params = array())
{
if ($actionID === '') {
$actionID = $this->defaultAction;
}
$actions = $this->actions();
if (isset($actions[$actionID])) {
return \Yii::createObject($actions[$actionID], $actionID, $this);
} elseif (method_exists($this, 'action' . $actionID)) {
return new InlineAction($actionID, $this);
$pos = strpos($route, '/');
if ($pos === false) {
return $this->runAction($route, $params);
} elseif ($pos > 0) {
return $this->module->runAction($route, $params);
} else {
return \Yii::$application->runAction($route, $params);
}
}
/**
* Forwards the current execution flow to handle a new request specified by a route.
* The only difference between this method and [[run()]] is that after calling this method,
* the application will exit.
* @param string $route the route to be handled, e.g., 'view', 'comment/view', '/admin/comment/view'.
* @param array $params the parameters to be passed to the action.
* @return integer the status code returned by the action execution. 0 means normal, and other values mean abnormal.
* @see run
*/
public function forward($route, $params = array())
{
$status = $this->run($route, $params);
exit($status);
}
/**
* Creates an action based on the given action ID.
* The method first checks if the action ID has been declared in [[actions()]]. If so,
* it will use the configuration declared there to create the action object.
* If not, it will look for a controller method whose name is in the format of `actionXyz`
* where `Xyz` stands for the action ID. If found, an [[InlineAction]] representing that
* method will be created and returned.
* @param string $id the action ID
* @return Action the newly created action instance. Null if the ID doesn't resolve into any action.
*/
public function createAction($id)
{
$actionMap = $this->actions();
if (isset($actionMap[$id])) {
return Yii::createObject($actionMap[$id], $id, $this);
} elseif (preg_match('/^[a-z0-9\\-_]+$/', $id)) {
$methodName = 'action' . StringHelper::id2camel($id);
if (method_exists($this, $methodName)) {
$method = new \ReflectionMethod($this, $methodName);
if ($method->getName() === $methodName) {
return new InlineAction($id, $this);
}
}
}
return null;
}
/**
* This method is invoked when checking the access for the action to be executed.
* @param Action $action the action to be executed.
* @return boolean whether the action is allowed to be executed.
*/
public function authorize($action)
{
$event = new ActionEvent($action);
$this->trigger(self::EVENT_AUTHORIZE, $event);
return $event->isValid;
}
/**
* 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 Action $action the action to be executed.
* @return boolean whether the action should continue to be executed.
*/
public function beforeAction($action)
{
$event = new ActionEvent($action);
$this->trigger(self::EVENT_BEFORE_ACTION, $event);
return $event->isValid;
}
/**
* This method is invoked right after an action is executed.
* You may override this method to do some postprocessing for the action.
* @param Action $action the action just executed.
*/
public function afterAction($action)
{
$this->trigger(self::EVENT_AFTER_ACTION, new ActionEvent($action));
}
/**
......@@ -217,67 +297,6 @@ class Controller extends Component
return $this->action !== null ? $this->getUniqueId() . '/' . $this->action->id : $this->getUniqueId();
}
/**
* Processes the request using another controller action.
* @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 array $params the parameters to be passed to the action.
* If null, the result of [[getActionParams()]] will be used as action parameters.
* Note that the parameters must be name-value pairs with the names corresponding to
* the parameter names as declared by the action.
* @param boolean $exit whether to end the application after this call. Defaults to true.
*/
public function forward($route, $params = array(), $exit = true)
{
if (strpos($route, '/') === false) {
$status = $this->run($route, $params);
} else {
if ($route[0] !== '/' && !$this->module instanceof Application) {
$route = '/' . $this->module->getUniqueId() . '/' . $route;
}
$status = \Yii::$application->runController($route, $params);
}
if ($exit) {
\Yii::$application->end($status);
}
}
/**
* This method is invoked when checking the access for the action to be executed.
* @param Action $action the action to be executed.
* @return boolean whether the action is allowed to be executed.
*/
public function authorize($action)
{
$event = new ActionEvent($action);
$this->trigger(__METHOD__, $event);
return $event->isValid;
}
/**
* 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 Action $action the action to be executed.
* @return boolean whether the action should continue to be executed.
*/
public function beforeAction($action)
{
$event = new ActionEvent($action);
$this->trigger(__METHOD__, $event);
return $event->isValid;
}
/**
* This method is invoked right after an action is executed.
* You may override this method to do some postprocessing for the action.
* @param Action $action the action just executed.
*/
public function afterAction($action)
{
$this->trigger(__METHOD__, new ActionEvent($action));
}
public function render($view, $params = array())
{
return $this->createView()->render($view, $params);
......
<?php
/**
* InvalidRouteException class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
/**
* InvalidRouteException represents an exception caused by an invalid route.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class InvalidRouteException extends \Exception
{
}
......@@ -16,13 +16,19 @@ use yii\util\FileHelper;
/**
* Module is the base class for module and application classes.
*
* Module mainly manages application components and sub-modules that belongs to a module.
* A module represents a sub-application which contains MVC elements by itself, such as
* models, views, controllers, etc.
*
* A module may consist of [[modules|sub-modules]].
*
* [[components|Components]] may be registered with the module so that they are globally
* accessible within the module.
*
* @property string $uniqueId An ID that uniquely identifies this module among all modules within
* the current application.
* @property string $basePath The root directory of the module. Defaults to the directory containing the module class.
* @property array $modules The configuration of the currently installed modules (module ID => configuration).
* @property array $components The application components (indexed by their IDs).
* @property array $components The components (indexed by their IDs) registered within this module.
* @property array $import List of aliases to be imported. This property is write-only.
* @property array $aliases List of aliases to be defined. This property is write-only.
*
......@@ -36,7 +42,7 @@ abstract class Module extends Component
*/
public $params = array();
/**
* @var array the IDs of the application components that should be preloaded when this module is created.
* @var array the IDs of the components that should be preloaded when this module is created.
*/
public $preload = array();
/**
......@@ -88,27 +94,27 @@ abstract class Module extends Component
/**
* @var string the root directory of the module.
*/
protected $_basePath;
private $_basePath;
/**
* @var string the root directory that contains view files for this module
*/
protected $_viewPath;
private $_viewPath;
/**
* @var string the root directory that contains layout view files for this module.
*/
protected $_layoutPath;
private $_layoutPath;
/**
* @var string the directory containing controller classes in the module.
*/
protected $_controllerPath;
private $_controllerPath;
/**
* @var array child modules of this module
*/
protected $_modules = array();
private $_modules = array();
/**
* @var array application components of this module
* @var array components registered under this module
*/
protected $_components = array();
private $_components = array();
/**
* Constructor.
......@@ -125,9 +131,9 @@ abstract class Module extends Component
/**
* Getter magic method.
* This method is overridden to support accessing application components
* This method is overridden to support accessing components
* like reading module properties.
* @param string $name application component or property name
* @param string $name component or property name
* @return mixed the named property value
*/
public function __get($name)
......@@ -142,7 +148,7 @@ abstract class Module extends Component
/**
* Checks if a property value is null.
* This method overrides the parent implementation by checking
* if the named application component is loaded.
* if the named component is loaded.
* @param string $name the property name or the event name
* @return boolean whether the property value is null
*/
......@@ -163,7 +169,7 @@ abstract class Module extends Component
*/
public function init()
{
\Yii::setAlias('@' . $this->id, $this->getBasePath());
Yii::setAlias('@' . $this->id, $this->getBasePath());
$this->preloadComponents();
}
......@@ -282,19 +288,19 @@ abstract class Module extends Component
/**
* Imports the specified path aliases.
* This method is provided so that you can import a set of path aliases when configuring a module.
* The path aliases will be imported by calling [[\Yii::import()]].
* The path aliases will be imported by calling [[Yii::import()]].
* @param array $aliases list of path aliases to be imported
*/
public function setImport($aliases)
{
foreach ($aliases as $alias) {
\Yii::import($alias);
Yii::import($alias);
}
}
/**
* Defines path aliases.
* This method calls [[\Yii::setAlias()]] to register the path aliases.
* This method calls [[Yii::setAlias()]] to register the path aliases.
* This method is provided so that you can define path aliases when configuring a module.
* @param array $aliases list of path aliases to be defined. The array keys are alias names
* (must start with '@') and the array values are the corresponding paths or aliases.
......@@ -302,7 +308,7 @@ abstract class Module extends Component
*
* ~~~
* array(
* '@models' => '@app/models', // an existing alias
* '@models' => '@application/models', // an existing alias
* '@backend' => __DIR__ . '/../backend', // a directory
* )
* ~~~
......@@ -310,7 +316,7 @@ abstract class Module extends Component
public function setAliases($aliases)
{
foreach ($aliases as $name => $alias) {
\Yii::setAlias($name, $alias);
Yii::setAlias($name, $alias);
}
}
......@@ -339,8 +345,8 @@ abstract class Module extends Component
if ($this->_modules[$id] instanceof Module) {
return $this->_modules[$id];
} elseif ($load) {
\Yii::trace("Loading \"$id\" module", __CLASS__);
return $this->_modules[$id] = \Yii::createObject($this->_modules[$id], $id, $this);
Yii::trace("Loading module: $id", __CLASS__);
return $this->_modules[$id] = Yii::createObject($this->_modules[$id], $id, $this);
}
}
return null;
......@@ -393,7 +399,7 @@ abstract class Module extends Component
*
* Each sub-module should be specified as a name-value pair, where
* name refers to the ID of the module and value the module or a configuration
* array that can be used to create the module. In the latter case, [[\Yii::createObject()]]
* array that can be used to create the module. In the latter case, [[Yii::createObject()]]
* will be used to create the module.
*
* If a new sub-module has the same ID as an existing one, the existing one will be overwritten silently.
......@@ -423,8 +429,8 @@ abstract class Module extends Component
/**
* Checks whether the named component exists.
* @param string $id application component ID
* @return boolean whether the named application component exists. Both loaded and unloaded components
* @param string $id component ID
* @return boolean whether the named component exists. Both loaded and unloaded components
* are considered.
*/
public function hasComponent($id)
......@@ -433,11 +439,10 @@ abstract class Module extends Component
}
/**
* Retrieves the named application component.
* @param string $id application component ID (case-sensitive)
* Retrieves the named component.
* @param string $id component ID (case-sensitive)
* @param boolean $load whether to load the component if it is not yet loaded.
* @return Component|null the application component instance, null if the application component
* does not exist.
* @return Component|null the component instance, null if the component does not exist.
* @see hasComponent()
*/
public function getComponent($id, $load = true)
......@@ -446,22 +451,22 @@ abstract class Module extends Component
if ($this->_components[$id] instanceof Component) {
return $this->_components[$id];
} elseif ($load) {
\Yii::trace("Loading \"$id\" application component", __CLASS__);
return $this->_components[$id] = \Yii::createObject($this->_components[$id]);
Yii::trace("Loading component: $id", __CLASS__);
return $this->_components[$id] = Yii::createObject($this->_components[$id]);
}
}
return null;
}
/**
* Registers an application component in this module.
* Registers a component with this module.
* @param string $id component ID
* @param Component|array|null $component the component to be added to the module. This can
* @param Component|array|null $component the component to be registered with the module. This can
* be one of the followings:
*
* - a [[Component]] object
* - a configuration array: when [[getComponent()]] is called initially for this component, the array
* will be used to instantiate the component
* will be used to instantiate the component via [[Yii::createObject()]].
* - null: the named component will be removed from the module
*/
public function setComponent($id, $component)
......@@ -474,11 +479,11 @@ abstract class Module extends Component
}
/**
* Returns the application components.
* Returns the registered components.
* @param boolean $loadedOnly whether to return the loaded components only. If this is set false,
* then all components specified in the configuration will be returned, whether they are loaded or not.
* Loaded components will be returned as objects, while unloaded components as configuration arrays.
* @return array the application components (indexed by their IDs)
* @return array the components (indexed by their IDs)
*/
public function getComponents($loadedOnly = false)
{
......@@ -496,11 +501,11 @@ abstract class Module extends Component
}
/**
* Registers a set of application components in this module.
* Registers a set of components in this module.
*
* Each application component should be specified as a name-value pair, where
* Each component should be specified as a name-value pair, where
* name refers to the ID of the component and value the component or a configuration
* array that can be used to create the component. In the latter case, [[\Yii::createObject()]]
* array that can be used to create the component. In the latter case, [[Yii::createObject()]]
* will be used to create the component.
*
* If a new component has the same ID as an existing one, the existing one will be overwritten silently.
......@@ -520,7 +525,7 @@ abstract class Module extends Component
* )
* ~~~
*
* @param array $components application components (id => component configuration or instance)
* @param array $components components (id => component configuration or instance)
*/
public function setComponents($components)
{
......@@ -530,7 +535,7 @@ abstract class Module extends Component
}
/**
* Loads application components that are declared in [[preload]].
* Loads components that are declared in [[preload]].
*/
public function preloadComponents()
{
......@@ -540,54 +545,47 @@ abstract class Module extends Component
}
/**
* Performs a controller action specified by a route.
* This method parses the specified route and creates the corresponding controller and action
* instances under the context of the specified module. It then runs the created action
* with the given parameters.
* Runs a controller action specified by a route.
* This method parses the specified route and creates the corresponding child module(s), controller and action
* instances. It then calls [[Controller::runAction()]] to run the action with the given parameters.
* If the route is empty, the method will use [[defaultRoute]].
* @param string $route the route that specifies the action.
* @param array $params the parameters to be passed to the action
* @return integer the action
* @throws InvalidConfigException if the module's defaultRoute is empty or the controller's defaultAction is empty
* @throws InvalidRequestException if the requested route cannot be resolved into an action successfully
* @return integer the status code returned by the action execution. 0 means normal, and other values mean abnormal.
* @throws InvalidRouteException if the requested route cannot be resolved into an action successfully
*/
public function runAction($route, $params = array())
{
$route = trim($route, '/');
if ($route === '') {
$route = trim($this->defaultRoute, '/');
if ($route == '') {
throw new InvalidConfigException(get_class($this) . '::defaultRoute cannot be empty.');
}
}
if (($pos = strpos($route, '/')) !== false) {
$id = substr($route, 0, $pos);
$route = substr($route, $pos + 1);
$route2 = substr($route, $pos + 1);
} else {
$id = $route;
$route = '';
$route2 = '';
}
$module = $this->getModule($id);
if ($module !== null) {
return $module->runAction($route, $params);
return $module->runAction($route2, $params);
}
$controller = $this->createController($id);
if ($controller !== null) {
if ($route === '') {
$route = $controller->defaultAction;
if ($route == '') {
throw new InvalidConfigException(get_class($controller) . '::defaultAction cannot be empty.');
}
}
$oldController = Yii::$application->controller;
Yii::$application->controller = $controller;
$action = $controller->createAction($route);
if ($action !== null) {
return $action->runWithParams($params);
}
}
$status = $controller->runAction($route2, $params);
throw new InvalidRequestException('Unable to resolve the request: ' . ltrim($this->getUniqueId() . '/' . $route, '/'));
Yii::$application->controller = $oldController;
return $status;
} else {
throw new InvalidRouteException('Unable to resolve the request: ' . $this->getUniqueId() . '/' . $route);
}
}
/**
......
......@@ -97,7 +97,7 @@ class View extends Component
* To determine which view file should be rendered, the method calls [[findViewFile()]] which
* will search in the directories as specified by [[basePath]].
*
* View name can be a path alias representing an absolute file path (e.g. `@app/views/layout/index`),
* View name can be a path alias representing an absolute file path (e.g. `@application/views/layout/index`),
* or a path relative to [[basePath]]. The file suffix is optional and defaults to `.php` if not given
* in the view name.
*
......
......@@ -80,7 +80,7 @@ class Widget extends Component
* To determine which view file should be rendered, the method calls [[findViewFile()]] which
* will search in the directories as specified by [[basePath]].
*
* View name can be a path alias representing an absolute file path (e.g. `@app/views/layout/index`),
* View name can be a path alias representing an absolute file path (e.g. `@application/views/layout/index`),
* or a path relative to [[basePath]]. The file suffix is optional and defaults to `.php` if not given
* in the view name.
*
......
......@@ -89,16 +89,17 @@ class DbTarget extends Target
}
/**
* Stores log [[messages]] to DB.
* @param boolean $final whether this method is called at the end of the current application
* Stores log messages to DB.
* @param array $messages the messages to be exported. See [[Logger::messages]] for the structure
* of each message.
*/
public function exportMessages($final)
public function export($messages)
{
$db = $this->getDb();
$tableName = $db->quoteTableName($this->tableName);
$sql = "INSERT INTO $tableName (level, category, log_time, message) VALUES (:level, :category, :log_time, :message)";
$command = $db->createCommand($sql);
foreach ($this->messages as $message) {
foreach ($messages as $message) {
$command->bindValues(array(
':level' => $message[1],
':category' => $message[2],
......
......@@ -39,13 +39,14 @@ class EmailTarget extends Target
public $headers = array();
/**
* Sends log [[messages]] to specified email addresses.
* @param boolean $final whether this method is called at the end of the current application
* Sends log messages to specified email addresses.
* @param array $messages the messages to be exported. See [[Logger::messages]] for the structure
* of each message.
*/
public function exportMessages($final)
public function export($messages)
{
$body = '';
foreach ($this->messages as $message) {
foreach ($messages as $message) {
$body .= $this->formatMessage($message);
}
$body = wordwrap($body, 70);
......
......@@ -65,19 +65,28 @@ class FileTarget extends Target
}
/**
* Sends log [[messages]] to specified email addresses.
* @param boolean $final whether this method is called at the end of the current application
* Sends log messages to specified email addresses.
* @param array $messages the messages to be exported. See [[Logger::messages]] for the structure
* of each message.
*/
public function exportMessages($final)
public function export($messages)
{
$text = '';
foreach ($messages as $message) {
$text .= $this->formatMessage($message);
}
$fp = @fopen($this->logFile, 'a');
@flock($fp, LOCK_EX);
if (@filesize($this->logFile) > $this->maxFileSize * 1024) {
$this->rotateFiles();
@flock($fp,LOCK_UN);
@fclose($fp);
@file_put_contents($this->logFile, $text, FILE_APPEND | LOCK_EX);
} else {
@fwrite($fp, $text);
@flock($fp,LOCK_UN);
@fclose($fp);
}
$messages = array();
foreach ($this->messages as $message) {
$messages[] = $this->formatMessage($message);
}
@file_put_contents($this->logFile, implode('', $messages), FILE_APPEND | LOCK_EX);
}
/**
......
......@@ -8,16 +8,13 @@
*/
namespace yii\logging;
use yii\base\Event;
use yii\base\Exception;
use yii\base\InvalidConfigException;
/**
* Logger records logged messages in memory.
*
* When [[flushInterval()]] is reached or when application terminates, it will
* call [[flush()]] to send logged messages to different log targets, such as
* file, email, Web.
* When the application ends or [[flushInterval]] is reached, Logger will call [[flush()]]
* to send logged messages to different log targets, such as file, email, Web.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
......@@ -25,15 +22,6 @@ use yii\base\Exception;
class Logger extends \yii\base\Component
{
/**
* @event Event an event that is triggered when [[flush()]] is called.
*/
const EVENT_FLUSH = 'flush';
/**
* @event Event an event that is triggered when [[flush()]] is called at the end of application.
*/
const EVENT_FINAL_FLUSH = 'finalFlush';
/**
* Error message level. An error message is one that indicates the abnormal termination of the
* application and may require developer's handling.
*/
......@@ -82,7 +70,7 @@ class Logger extends \yii\base\Component
*
* ~~~
* array(
* [0] => message (mixed)
* [0] => message (mixed, can be a string or some complex data, such as an exception object)
* [1] => level (integer)
* [2] => category (string)
* [3] => timestamp (float, obtained by microtime(true))
......@@ -90,6 +78,10 @@ class Logger extends \yii\base\Component
* ~~~
*/
public $messages = array();
/**
* @var Router the log target router registered with this logger.
*/
public $router;
/**
* Initializes the logger by registering [[flush()]] as a shutdown function.
......@@ -138,7 +130,9 @@ class Logger extends \yii\base\Component
*/
public function flush($final = false)
{
$this->trigger($final ? self::EVENT_FINAL_FLUSH : self::EVENT_FLUSH);
if ($this->router) {
$this->router->dispatch($this->messages, $final);
}
$this->messages = array();
}
......@@ -149,7 +143,7 @@ class Logger extends \yii\base\Component
* of [[YiiBase]] class file.
* @return float the total elapsed time in seconds for current request.
*/
public function getExecutionTime()
public function getElapsedTime()
{
return microtime(true) - YII_BEGIN_TIME;
}
......@@ -218,7 +212,7 @@ class Logger extends \yii\base\Component
if (($last = array_pop($stack)) !== null && $last[0] === $token) {
$timings[] = array($token, $category, $timestamp - $last[3]);
} else {
throw new Exception("Unmatched profiling block: $token");
throw new InvalidConfigException("Unmatched profiling block: $token");
}
}
}
......@@ -231,5 +225,4 @@ class Logger extends \yii\base\Component
return $timings;
}
}
......@@ -81,26 +81,21 @@ class Router extends Component
$this->targets[$name] = Yii::createObject($target);
}
}
Yii::getLogger()->on(Logger::EVENT_FLUSH, array($this, 'processMessages'));
Yii::getLogger()->on(Logger::EVENT_FINAL_FLUSH, array($this, 'processMessages'));
Yii::getLogger()->router = $this;
}
/**
* Retrieves and processes log messages from the system logger.
* This method mainly serves the event handler to the [[Logger::EVENT_FLUSH]] event
* and the [[Logger::EVENT_FINAL_FLUSH]] event.
* It will retrieve the available log messages from the [[Yii::getLogger()|system logger]]
* and invoke the registered [[targets|log targets]] to do the actual processing.
* @param \yii\base\Event $event event parameter
* Dispatches log messages to [[targets]].
* This method is called by [[Logger]] when its [[Logger::flush()]] method is called.
* It will forward the messages to each log target registered in [[targets]].
* @param array $messages the messages to be processed
* @param boolean $final whether this is the final call during a request cycle
*/
public function processMessages($event)
public function dispatch($messages, $final = false)
{
$messages = Yii::getLogger()->messages;
$final = $event->name === Logger::EVENT_FINAL_FLUSH;
foreach ($this->targets as $target) {
if ($target->enabled) {
$target->processMessages($messages, $final);
$target->collect($messages, $final);
}
}
}
......
......@@ -50,15 +50,6 @@ abstract class Target extends \yii\base\Component
*/
public $except = array();
/**
* @var boolean whether to prefix each log message with the current session ID. Defaults to false.
*/
public $prefixSession = false;
/**
* @var boolean whether to prefix each log message with the current user name and ID. Defaults to false.
* @see \yii\web\User
*/
public $prefixUser = false;
/**
* @var boolean whether to log a message containing the current user name and ID. Defaults to false.
* @see \yii\web\User
*/
......@@ -77,19 +68,18 @@ abstract class Target extends \yii\base\Component
public $exportInterval = 1000;
/**
* @var array the messages that are retrieved from the logger so far by this log target.
* @see autoExport
*/
public $messages = array();
private $_messages = array();
private $_levels = 0;
/**
* Exports log messages to a specific destination.
* Child classes must implement this method. Note that you may need
* to clean up [[messages]] in this method to avoid re-exporting messages.
* @param boolean $final whether this method is called at the end of the current application
* Child classes must implement this method.
* @param array $messages the messages to be exported. See [[Logger::messages]] for the structure
* of each message.
*/
abstract public function exportMessages($final);
abstract public function export($messages);
/**
* Processes the given log messages.
......@@ -99,45 +89,16 @@ abstract class Target extends \yii\base\Component
* of each message.
* @param boolean $final whether this method is called at the end of the current application
*/
public function processMessages($messages, $final)
public function collect($messages, $final)
{
$messages = $this->filterMessages($messages);
$this->messages = array_merge($this->messages, $messages);
$count = count($this->messages);
$this->_messages = array($this->_messages, $this->filterMessages($messages));
$count = count($this->_messages);
if ($count > 0 && ($final || $this->exportInterval > 0 && $count >= $this->exportInterval)) {
$this->prepareExport($final);
$this->exportMessages($final);
$this->messages = array();
}
}
/**
* Prepares the [[messages]] for exporting.
* This method will modify each message by prepending extra information
* if [[prefixSession]] and/or [[prefixUser]] are set true.
* It will also add an additional message showing context information if
* [[logUser]] and/or [[logVars]] are set.
* @param boolean $final whether this method is called at the end of the current application
*/
protected function prepareExport($final)
{
$prefix = array();
if ($this->prefixSession && ($id = session_id()) !== '') {
$prefix[] = "[$id]";
}
if ($this->prefixUser && ($user = \Yii::$application->getComponent('user', false)) !== null) {
$prefix[] = '[' . $user->getName() . ']';
$prefix[] = '[' . $user->getId() . ']';
}
if ($prefix !== array()) {
$prefix = implode(' ', $prefix);
foreach ($this->messages as $i => $message) {
$this->messages[$i][0] = $prefix . ' ' . $this->messages[$i][0];
}
if (($context = $this->getContextMessage()) !== '') {
$this->_messages[] = array($context, Logger::LEVEL_INFO, 'application', YII_BEGIN_TIME);
}
if ($final && ($context = $this->getContextMessage()) !== '') {
$this->messages[] = array($context, Logger::LEVEL_INFO, 'application', YII_BEGIN_TIME);
$this->export($this->_messages);
$this->_messages = array();
}
}
......
......@@ -10,6 +10,7 @@
namespace yii\util;
use yii\base\Exception;
use yii\base\InvalidConfigException;
/**
* Filesystem helper
......@@ -37,7 +38,7 @@ class FileHelper
* If the given path does not refer to an existing directory, an exception will be thrown.
* @param string $path the given path. This can also be a path alias.
* @return string the normalized path
* @throws Exception if the path does not refer to an existing directory.
* @throws InvalidConfigException if the path does not refer to an existing directory.
*/
public static function ensureDirectory($path)
{
......@@ -45,7 +46,7 @@ class FileHelper
if ($p !== false && ($p = realpath($p)) !== false && is_dir($p)) {
return $p;
} else {
throw new Exception('Directory does not exist: ' . $path);
throw new InvalidConfigException('Directory does not exist: ' . $path);
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment