diff --git a/framework/yii/base/ErrorHandler.php b/framework/yii/base/ErrorHandler.php index 8dc3fce..7bf9e7e 100644 --- a/framework/yii/base/ErrorHandler.php +++ b/framework/yii/base/ErrorHandler.php @@ -255,7 +255,7 @@ class ErrorHandler extends Component if (isset($_SERVER['SERVER_SOFTWARE'])) { foreach ($serverUrls as $url => $keywords) { foreach ($keywords as $keyword) { - if (stripos($_SERVER['SERVER_SOFTWARE'], $keyword) !== false ) { + if (stripos($_SERVER['SERVER_SOFTWARE'], $keyword) !== false) { return '' . $this->htmlEncode($_SERVER['SERVER_SOFTWARE']) . ''; } } diff --git a/framework/yii/base/Formatter.php b/framework/yii/base/Formatter.php index e62039e..545f570 100644 --- a/framework/yii/base/Formatter.php +++ b/framework/yii/base/Formatter.php @@ -12,7 +12,6 @@ use DateTime; use yii\helpers\HtmlPurifier; use yii\helpers\Html; - /** * Formatter provides a set of commonly used data formatting methods. * diff --git a/framework/yii/base/InvalidCallException.php b/framework/yii/base/InvalidCallException.php index 9a146d4..73cb4b9 100644 --- a/framework/yii/base/InvalidCallException.php +++ b/framework/yii/base/InvalidCallException.php @@ -23,4 +23,3 @@ class InvalidCallException extends Exception return \Yii::t('yii', 'Invalid Call'); } } - diff --git a/framework/yii/base/InvalidConfigException.php b/framework/yii/base/InvalidConfigException.php index c617381..0a6b4c5 100644 --- a/framework/yii/base/InvalidConfigException.php +++ b/framework/yii/base/InvalidConfigException.php @@ -23,4 +23,3 @@ class InvalidConfigException extends Exception return \Yii::t('yii', 'Invalid Configuration'); } } - diff --git a/framework/yii/base/InvalidParamException.php b/framework/yii/base/InvalidParamException.php index 0262051..44430a8 100644 --- a/framework/yii/base/InvalidParamException.php +++ b/framework/yii/base/InvalidParamException.php @@ -23,4 +23,3 @@ class InvalidParamException extends Exception return \Yii::t('yii', 'Invalid Parameter'); } } - diff --git a/framework/yii/base/InvalidRouteException.php b/framework/yii/base/InvalidRouteException.php index a573636..fbcc087 100644 --- a/framework/yii/base/InvalidRouteException.php +++ b/framework/yii/base/InvalidRouteException.php @@ -23,4 +23,3 @@ class InvalidRouteException extends UserException return \Yii::t('yii', 'Invalid Route'); } } - diff --git a/framework/yii/base/Jsonable.php b/framework/yii/base/Jsonable.php index 4a3f7d9..e9425a6 100644 --- a/framework/yii/base/Jsonable.php +++ b/framework/yii/base/Jsonable.php @@ -18,5 +18,5 @@ interface Jsonable /** * @return string the JSON representation of this object */ - function toJson(); + public function toJson(); } diff --git a/framework/yii/base/Module.php b/framework/yii/base/Module.php index 5f5c376..cc7c849 100644 --- a/framework/yii/base/Module.php +++ b/framework/yii/base/Module.php @@ -1,667 +1,667 @@ - configuration). - * @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. - * - * @author Qiang Xue - * @since 2.0 - */ -abstract class Module extends Component -{ - /** - * @event ActionEvent an event raised before executing a controller action. - * You may set [[ActionEvent::isValid]] to be false to cancel the action execution. - */ - const EVENT_BEFORE_ACTION = 'beforeAction'; - /** - * @event ActionEvent an event raised after executing a controller action. - */ - const EVENT_AFTER_ACTION = 'afterAction'; - /** - * @var array custom module parameters (name => value). - */ - public $params = array(); - /** - * @var array the IDs of the components that should be preloaded when this module is created. - */ - public $preload = array(); - /** - * @var string an ID that uniquely identifies this module among other modules which have the same [[module|parent]]. - */ - public $id; - /** - * @var Module the parent module of this module. Null if this module does not have a parent. - */ - public $module; - /** - * @var string|boolean the layout that should be applied for views within this module. This refers to a view name - * relative to [[layoutPath]]. If this is not set, it means the layout value of the [[module|parent module]] - * will be taken. If this is false, layout will be disabled within this module. - */ - public $layout; - /** - * @var array mapping from controller ID to controller configurations. - * Each name-value pair specifies the configuration of a single controller. - * A controller configuration can be either a string or an array. - * If the former, the string should be the class name or path alias of the controller. - * If the latter, the array must contain a 'class' element which specifies - * the controller's class name or path alias, and the rest of the name-value pairs - * in the array are used to initialize the corresponding controller properties. For example, - * - * ~~~ - * array( - * 'account' => '@app/controllers/UserController', - * 'article' => array( - * 'class' => '@app/controllers/PostController', - * 'pageTitle' => 'something new', - * ), - * ) - * ~~~ - */ - public $controllerMap = array(); - /** - * @var string the namespace that controller classes are in. If not set, - * it will use the "controllers" sub-namespace under the namespace of this module. - * For example, if the namespace of this module is "foo\bar", then the default - * controller namespace would be "foo\bar\controllers". - * If the module is an application, it will default to "app\controllers". - */ - public $controllerNamespace; - /** - * @return string the default route of this module. Defaults to 'default'. - * The route may consist of child module ID, controller ID, and/or action ID. - * For example, `help`, `post/create`, `admin/post/create`. - * If action ID is not given, it will take the default value as specified in - * [[Controller::defaultAction]]. - */ - public $defaultRoute = 'default'; - /** - * @var string the root directory of the module. - */ - private $_basePath; - /** - * @var string the root directory that contains view files for this module - */ - private $_viewPath; - /** - * @var string the root directory that contains layout view files for this module. - */ - private $_layoutPath; - /** - * @var string the directory containing controller classes in the module. - */ - private $_controllerPath; - /** - * @var array child modules of this module - */ - private $_modules = array(); - /** - * @var array components registered under this module - */ - private $_components = array(); - - /** - * Constructor. - * @param string $id the ID of this module - * @param Module $parent the parent module (if any) - * @param array $config name-value pairs that will be used to initialize the object properties - */ - public function __construct($id, $parent = null, $config = array()) - { - $this->id = $id; - $this->module = $parent; - parent::__construct($config); - } - - /** - * Getter magic method. - * This method is overridden to support accessing components - * like reading module properties. - * @param string $name component or property name - * @return mixed the named property value - */ - public function __get($name) - { - if ($this->hasComponent($name)) { - return $this->getComponent($name); - } else { - return parent::__get($name); - } - } - - /** - * Checks if a property value is null. - * This method overrides the parent implementation by checking - * if the named component is loaded. - * @param string $name the property name or the event name - * @return boolean whether the property value is null - */ - public function __isset($name) - { - if ($this->hasComponent($name)) { - return $this->getComponent($name) !== null; - } else { - return parent::__isset($name); - } - } - - /** - * Initializes the module. - * This method is called after the module is created and initialized with property values - * given in configuration. The default implement will create a path alias using the module [[id]] - * and then call [[preloadComponents()]] to load components that are declared in [[preload]]. - */ - public function init() - { - $this->preloadComponents(); - if ($this->controllerNamespace === null) { - if ($this instanceof Application) { - $this->controllerNamespace = 'app\\controllers'; - } else { - $class = get_class($this); - if (($pos = strrpos($class, '\\')) !== false) { - $this->controllerNamespace = substr($class, 0, $pos) . '\\controllers'; - } - } - } - } - - /** - * Returns an ID that uniquely identifies this module among all modules within the current application. - * Note that if the module is an application, an empty string will be returned. - * @return string the unique ID of the module. - */ - public function getUniqueId() - { - if ($this instanceof Application) { - return ''; - } elseif ($this->module) { - return $this->module->getUniqueId() . '/' . $this->id; - } else { - return $this->id; - } - } - - /** - * Returns the root directory of the module. - * It defaults to the directory containing the module class file. - * @return string the root directory of the module. - */ - public function getBasePath() - { - if ($this->_basePath === null) { - $class = new \ReflectionClass($this); - $this->_basePath = dirname($class->getFileName()); - } - return $this->_basePath; - } - - /** - * Sets the root directory of the module. - * This method can only be invoked at the beginning of the constructor. - * @param string $path the root directory of the module. This can be either a directory name or a path alias. - * @throws InvalidParamException if the directory does not exist. - */ - public function setBasePath($path) - { - $path = Yii::getAlias($path); - $p = realpath($path); - if ($p !== false && is_dir($p)) { - $this->_basePath = $p; - if ($this instanceof Application) { - Yii::setAlias('@app', $p); - } - } else { - throw new InvalidParamException("The directory does not exist: $path"); - } - } - - /** - * Returns the directory that contains the controller classes. - * Defaults to "[[basePath]]/controllers". - * @return string the directory that contains the controller classes. - */ - public function getControllerPath() - { - if ($this->_controllerPath !== null) { - return $this->_controllerPath; - } else { - return $this->_controllerPath = $this->getBasePath() . DIRECTORY_SEPARATOR . 'controllers'; - } - } - - /** - * Sets the directory that contains the controller classes. - * @param string $path the directory that contains the controller classes. - * This can be either a directory name or a path alias. - * @throws Exception if the directory is invalid - */ - public function setControllerPath($path) - { - $this->_controllerPath = Yii::getAlias($path); - } - - /** - * Returns the directory that contains the view files for this module. - * @return string the root directory of view files. Defaults to "[[basePath]]/view". - */ - public function getViewPath() - { - if ($this->_viewPath !== null) { - return $this->_viewPath; - } else { - return $this->_viewPath = $this->getBasePath() . DIRECTORY_SEPARATOR . 'views'; - } - } - - /** - * Sets the directory that contains the view files. - * @param string $path the root directory of view files. - * @throws Exception if the directory is invalid - */ - public function setViewPath($path) - { - $this->_viewPath = Yii::getAlias($path); - } - - /** - * Returns the directory that contains layout view files for this module. - * @return string the root directory of layout files. Defaults to "[[viewPath]]/layouts". - */ - public function getLayoutPath() - { - if ($this->_layoutPath !== null) { - return $this->_layoutPath; - } else { - return $this->_layoutPath = $this->getViewPath() . DIRECTORY_SEPARATOR . 'layouts'; - } - } - - /** - * Sets the directory that contains the layout files. - * @param string $path the root directory of layout files. - * @throws Exception if the directory is invalid - */ - public function setLayoutPath($path) - { - $this->_layoutPath = Yii::getAlias($path); - } - - /** - * Defines 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. - * For example, - * - * ~~~ - * array( - * '@models' => '@app/models', // an existing alias - * '@backend' => __DIR__ . '/../backend', // a directory - * ) - * ~~~ - */ - public function setAliases($aliases) - { - foreach ($aliases as $name => $alias) { - Yii::setAlias($name, $alias); - } - } - - /** - * Checks whether the named module exists. - * @param string $id module ID - * @return boolean whether the named module exists. Both loaded and unloaded modules - * are considered. - */ - public function hasModule($id) - { - return isset($this->_modules[$id]); - } - - /** - * Retrieves the named module. - * @param string $id module ID (case-sensitive) - * @param boolean $load whether to load the module if it is not yet loaded. - * @return Module|null the module instance, null if the module - * does not exist. - * @see hasModule() - */ - public function getModule($id, $load = true) - { - if (isset($this->_modules[$id])) { - if ($this->_modules[$id] instanceof Module) { - return $this->_modules[$id]; - } elseif ($load) { - Yii::trace("Loading module: $id", __METHOD__); - return $this->_modules[$id] = Yii::createObject($this->_modules[$id], $id, $this); - } - } - return null; - } - - /** - * Adds a sub-module to this module. - * @param string $id module ID - * @param Module|array|null $module the sub-module to be added to this module. This can - * be one of the followings: - * - * - a [[Module]] object - * - a configuration array: when [[getModule()]] is called initially, the array - * will be used to instantiate the sub-module - * - null: the named sub-module will be removed from this module - */ - public function setModule($id, $module) - { - if ($module === null) { - unset($this->_modules[$id]); - } else { - $this->_modules[$id] = $module; - } - } - - /** - * Returns the sub-modules in this module. - * @param boolean $loadedOnly whether to return the loaded sub-modules only. If this is set false, - * then all sub-modules registered in this module will be returned, whether they are loaded or not. - * Loaded modules will be returned as objects, while unloaded modules as configuration arrays. - * @return array the modules (indexed by their IDs) - */ - public function getModules($loadedOnly = false) - { - if ($loadedOnly) { - $modules = array(); - foreach ($this->_modules as $module) { - if ($module instanceof Module) { - $modules[] = $module; - } - } - return $modules; - } else { - return $this->_modules; - } - } - - /** - * Registers sub-modules in the current module. - * - * 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()]] - * 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. - * - * The following is an example for registering two sub-modules: - * - * ~~~ - * array( - * 'comment' => array( - * 'class' => 'app\modules\comment\CommentModule', - * 'db' => 'db', - * ), - * 'booking' => array( - * 'class' => 'app\modules\booking\BookingModule', - * ), - * ) - * ~~~ - * - * @param array $modules modules (id => module configuration or instances) - */ - public function setModules($modules) - { - foreach ($modules as $id => $module) { - $this->_modules[$id] = $module; - } - } - - /** - * Checks whether the named component exists. - * @param string $id component ID - * @return boolean whether the named component exists. Both loaded and unloaded components - * are considered. - */ - public function hasComponent($id) - { - return isset($this->_components[$id]); - } - - /** - * 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 component instance, null if the component does not exist. - * @see hasComponent() - */ - public function getComponent($id, $load = true) - { - if (isset($this->_components[$id])) { - if ($this->_components[$id] instanceof Object) { - return $this->_components[$id]; - } elseif ($load) { - Yii::trace("Loading component: $id", __METHOD__); - return $this->_components[$id] = Yii::createObject($this->_components[$id]); - } - } - return null; - } - - /** - * Registers a component with this module. - * @param string $id component ID - * @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 via [[Yii::createObject()]]. - * - null: the named component will be removed from the module - */ - public function setComponent($id, $component) - { - if ($component === null) { - unset($this->_components[$id]); - } else { - $this->_components[$id] = $component; - } - } - - /** - * 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 components (indexed by their IDs) - */ - public function getComponents($loadedOnly = false) - { - if ($loadedOnly) { - $components = array(); - foreach ($this->_components as $component) { - if ($component instanceof Component) { - $components[] = $component; - } - } - return $components; - } else { - return $this->_components; - } - } - - /** - * Registers a set of components in this module. - * - * 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()]] - * 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. - * - * The following is an example for setting two components: - * - * ~~~ - * array( - * 'db' => array( - * 'class' => 'yii\db\Connection', - * 'dsn' => 'sqlite:path/to/file.db', - * ), - * 'cache' => array( - * 'class' => 'yii\caching\DbCache', - * 'db' => 'db', - * ), - * ) - * ~~~ - * - * @param array $components components (id => component configuration or instance) - */ - public function setComponents($components) - { - foreach ($components as $id => $component) { - if (isset($this->_components[$id]['class']) && !isset($component['class'])) { - $component['class'] = $this->_components[$id]['class']; - } - $this->_components[$id] = $component; - } - } - - /** - * Loads components that are declared in [[preload]]. - */ - public function preloadComponents() - { - foreach ($this->preload as $id) { - $this->getComponent($id); - } - } - - /** - * 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 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()) - { - $result = $this->createController($route); - if (is_array($result)) { - /** @var $controller Controller */ - list($controller, $actionID) = $result; - $oldController = Yii::$app->controller; - Yii::$app->controller = $controller; - $status = $controller->runAction($actionID, $params); - Yii::$app->controller = $oldController; - return $status; - } else { - throw new InvalidRouteException('Unable to resolve the request "' . trim($this->getUniqueId() . '/' . $route, '/') . '".'); - } - } - - /** - * Creates a controller instance based on the controller ID. - * - * The controller is created within this 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 $route the route consisting of module, controller and action IDs. - * @return array|boolean If the controller is created successfully, it will be returned together - * with the requested action ID. Otherwise false will be returned. - * @throws InvalidConfigException if the controller class and its file do not match. - */ - public function createController($route) - { - if ($route === '') { - $route = $this->defaultRoute; - } - $route = trim($route, '/'); - if (($pos = strpos($route, '/')) !== false) { - $id = substr($route, 0, $pos); - $route = substr($route, $pos + 1); - } else { - $id = $route; - $route = ''; - } - - $module = $this->getModule($id); - if ($module !== null) { - return $module->createController($route); - } - - if (isset($this->controllerMap[$id])) { - $controller = Yii::createObject($this->controllerMap[$id], $id, $this); - } elseif (preg_match('/^[a-z0-9\\-_]+$/', $id)) { - $className = str_replace(' ', '', ucwords(implode(' ', explode('-', $id)))) . 'Controller'; - $classFile = $this->controllerPath . DIRECTORY_SEPARATOR . $className . '.php'; - if (!is_file($classFile)) { - return false; - } - $className = ltrim($this->controllerNamespace . '\\' . $className, '\\'); - Yii::$classMap[$className] = $classFile; - if (is_subclass_of($className, 'yii\base\Controller')) { - $controller = new $className($id, $this); - } elseif (YII_DEBUG) { - throw new InvalidConfigException("Controller class must extend from \\yii\\base\\Controller."); - } - } - - return isset($controller) ? array($controller, $route) : false; - } - - /** - * 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)); - } -} + configuration). + * @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. + * + * @author Qiang Xue + * @since 2.0 + */ +abstract class Module extends Component +{ + /** + * @event ActionEvent an event raised before executing a controller action. + * You may set [[ActionEvent::isValid]] to be false to cancel the action execution. + */ + const EVENT_BEFORE_ACTION = 'beforeAction'; + /** + * @event ActionEvent an event raised after executing a controller action. + */ + const EVENT_AFTER_ACTION = 'afterAction'; + /** + * @var array custom module parameters (name => value). + */ + public $params = array(); + /** + * @var array the IDs of the components that should be preloaded when this module is created. + */ + public $preload = array(); + /** + * @var string an ID that uniquely identifies this module among other modules which have the same [[module|parent]]. + */ + public $id; + /** + * @var Module the parent module of this module. Null if this module does not have a parent. + */ + public $module; + /** + * @var string|boolean the layout that should be applied for views within this module. This refers to a view name + * relative to [[layoutPath]]. If this is not set, it means the layout value of the [[module|parent module]] + * will be taken. If this is false, layout will be disabled within this module. + */ + public $layout; + /** + * @var array mapping from controller ID to controller configurations. + * Each name-value pair specifies the configuration of a single controller. + * A controller configuration can be either a string or an array. + * If the former, the string should be the class name or path alias of the controller. + * If the latter, the array must contain a 'class' element which specifies + * the controller's class name or path alias, and the rest of the name-value pairs + * in the array are used to initialize the corresponding controller properties. For example, + * + * ~~~ + * array( + * 'account' => '@app/controllers/UserController', + * 'article' => array( + * 'class' => '@app/controllers/PostController', + * 'pageTitle' => 'something new', + * ), + * ) + * ~~~ + */ + public $controllerMap = array(); + /** + * @var string the namespace that controller classes are in. If not set, + * it will use the "controllers" sub-namespace under the namespace of this module. + * For example, if the namespace of this module is "foo\bar", then the default + * controller namespace would be "foo\bar\controllers". + * If the module is an application, it will default to "app\controllers". + */ + public $controllerNamespace; + /** + * @return string the default route of this module. Defaults to 'default'. + * The route may consist of child module ID, controller ID, and/or action ID. + * For example, `help`, `post/create`, `admin/post/create`. + * If action ID is not given, it will take the default value as specified in + * [[Controller::defaultAction]]. + */ + public $defaultRoute = 'default'; + /** + * @var string the root directory of the module. + */ + private $_basePath; + /** + * @var string the root directory that contains view files for this module + */ + private $_viewPath; + /** + * @var string the root directory that contains layout view files for this module. + */ + private $_layoutPath; + /** + * @var string the directory containing controller classes in the module. + */ + private $_controllerPath; + /** + * @var array child modules of this module + */ + private $_modules = array(); + /** + * @var array components registered under this module + */ + private $_components = array(); + + /** + * Constructor. + * @param string $id the ID of this module + * @param Module $parent the parent module (if any) + * @param array $config name-value pairs that will be used to initialize the object properties + */ + public function __construct($id, $parent = null, $config = array()) + { + $this->id = $id; + $this->module = $parent; + parent::__construct($config); + } + + /** + * Getter magic method. + * This method is overridden to support accessing components + * like reading module properties. + * @param string $name component or property name + * @return mixed the named property value + */ + public function __get($name) + { + if ($this->hasComponent($name)) { + return $this->getComponent($name); + } else { + return parent::__get($name); + } + } + + /** + * Checks if a property value is null. + * This method overrides the parent implementation by checking + * if the named component is loaded. + * @param string $name the property name or the event name + * @return boolean whether the property value is null + */ + public function __isset($name) + { + if ($this->hasComponent($name)) { + return $this->getComponent($name) !== null; + } else { + return parent::__isset($name); + } + } + + /** + * Initializes the module. + * This method is called after the module is created and initialized with property values + * given in configuration. The default implement will create a path alias using the module [[id]] + * and then call [[preloadComponents()]] to load components that are declared in [[preload]]. + */ + public function init() + { + $this->preloadComponents(); + if ($this->controllerNamespace === null) { + if ($this instanceof Application) { + $this->controllerNamespace = 'app\\controllers'; + } else { + $class = get_class($this); + if (($pos = strrpos($class, '\\')) !== false) { + $this->controllerNamespace = substr($class, 0, $pos) . '\\controllers'; + } + } + } + } + + /** + * Returns an ID that uniquely identifies this module among all modules within the current application. + * Note that if the module is an application, an empty string will be returned. + * @return string the unique ID of the module. + */ + public function getUniqueId() + { + if ($this instanceof Application) { + return ''; + } elseif ($this->module) { + return $this->module->getUniqueId() . '/' . $this->id; + } else { + return $this->id; + } + } + + /** + * Returns the root directory of the module. + * It defaults to the directory containing the module class file. + * @return string the root directory of the module. + */ + public function getBasePath() + { + if ($this->_basePath === null) { + $class = new \ReflectionClass($this); + $this->_basePath = dirname($class->getFileName()); + } + return $this->_basePath; + } + + /** + * Sets the root directory of the module. + * This method can only be invoked at the beginning of the constructor. + * @param string $path the root directory of the module. This can be either a directory name or a path alias. + * @throws InvalidParamException if the directory does not exist. + */ + public function setBasePath($path) + { + $path = Yii::getAlias($path); + $p = realpath($path); + if ($p !== false && is_dir($p)) { + $this->_basePath = $p; + if ($this instanceof Application) { + Yii::setAlias('@app', $p); + } + } else { + throw new InvalidParamException("The directory does not exist: $path"); + } + } + + /** + * Returns the directory that contains the controller classes. + * Defaults to "[[basePath]]/controllers". + * @return string the directory that contains the controller classes. + */ + public function getControllerPath() + { + if ($this->_controllerPath !== null) { + return $this->_controllerPath; + } else { + return $this->_controllerPath = $this->getBasePath() . DIRECTORY_SEPARATOR . 'controllers'; + } + } + + /** + * Sets the directory that contains the controller classes. + * @param string $path the directory that contains the controller classes. + * This can be either a directory name or a path alias. + * @throws Exception if the directory is invalid + */ + public function setControllerPath($path) + { + $this->_controllerPath = Yii::getAlias($path); + } + + /** + * Returns the directory that contains the view files for this module. + * @return string the root directory of view files. Defaults to "[[basePath]]/view". + */ + public function getViewPath() + { + if ($this->_viewPath !== null) { + return $this->_viewPath; + } else { + return $this->_viewPath = $this->getBasePath() . DIRECTORY_SEPARATOR . 'views'; + } + } + + /** + * Sets the directory that contains the view files. + * @param string $path the root directory of view files. + * @throws Exception if the directory is invalid + */ + public function setViewPath($path) + { + $this->_viewPath = Yii::getAlias($path); + } + + /** + * Returns the directory that contains layout view files for this module. + * @return string the root directory of layout files. Defaults to "[[viewPath]]/layouts". + */ + public function getLayoutPath() + { + if ($this->_layoutPath !== null) { + return $this->_layoutPath; + } else { + return $this->_layoutPath = $this->getViewPath() . DIRECTORY_SEPARATOR . 'layouts'; + } + } + + /** + * Sets the directory that contains the layout files. + * @param string $path the root directory of layout files. + * @throws Exception if the directory is invalid + */ + public function setLayoutPath($path) + { + $this->_layoutPath = Yii::getAlias($path); + } + + /** + * Defines 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. + * For example, + * + * ~~~ + * array( + * '@models' => '@app/models', // an existing alias + * '@backend' => __DIR__ . '/../backend', // a directory + * ) + * ~~~ + */ + public function setAliases($aliases) + { + foreach ($aliases as $name => $alias) { + Yii::setAlias($name, $alias); + } + } + + /** + * Checks whether the named module exists. + * @param string $id module ID + * @return boolean whether the named module exists. Both loaded and unloaded modules + * are considered. + */ + public function hasModule($id) + { + return isset($this->_modules[$id]); + } + + /** + * Retrieves the named module. + * @param string $id module ID (case-sensitive) + * @param boolean $load whether to load the module if it is not yet loaded. + * @return Module|null the module instance, null if the module + * does not exist. + * @see hasModule() + */ + public function getModule($id, $load = true) + { + if (isset($this->_modules[$id])) { + if ($this->_modules[$id] instanceof Module) { + return $this->_modules[$id]; + } elseif ($load) { + Yii::trace("Loading module: $id", __METHOD__); + return $this->_modules[$id] = Yii::createObject($this->_modules[$id], $id, $this); + } + } + return null; + } + + /** + * Adds a sub-module to this module. + * @param string $id module ID + * @param Module|array|null $module the sub-module to be added to this module. This can + * be one of the followings: + * + * - a [[Module]] object + * - a configuration array: when [[getModule()]] is called initially, the array + * will be used to instantiate the sub-module + * - null: the named sub-module will be removed from this module + */ + public function setModule($id, $module) + { + if ($module === null) { + unset($this->_modules[$id]); + } else { + $this->_modules[$id] = $module; + } + } + + /** + * Returns the sub-modules in this module. + * @param boolean $loadedOnly whether to return the loaded sub-modules only. If this is set false, + * then all sub-modules registered in this module will be returned, whether they are loaded or not. + * Loaded modules will be returned as objects, while unloaded modules as configuration arrays. + * @return array the modules (indexed by their IDs) + */ + public function getModules($loadedOnly = false) + { + if ($loadedOnly) { + $modules = array(); + foreach ($this->_modules as $module) { + if ($module instanceof Module) { + $modules[] = $module; + } + } + return $modules; + } else { + return $this->_modules; + } + } + + /** + * Registers sub-modules in the current module. + * + * 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()]] + * 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. + * + * The following is an example for registering two sub-modules: + * + * ~~~ + * array( + * 'comment' => array( + * 'class' => 'app\modules\comment\CommentModule', + * 'db' => 'db', + * ), + * 'booking' => array( + * 'class' => 'app\modules\booking\BookingModule', + * ), + * ) + * ~~~ + * + * @param array $modules modules (id => module configuration or instances) + */ + public function setModules($modules) + { + foreach ($modules as $id => $module) { + $this->_modules[$id] = $module; + } + } + + /** + * Checks whether the named component exists. + * @param string $id component ID + * @return boolean whether the named component exists. Both loaded and unloaded components + * are considered. + */ + public function hasComponent($id) + { + return isset($this->_components[$id]); + } + + /** + * 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 component instance, null if the component does not exist. + * @see hasComponent() + */ + public function getComponent($id, $load = true) + { + if (isset($this->_components[$id])) { + if ($this->_components[$id] instanceof Object) { + return $this->_components[$id]; + } elseif ($load) { + Yii::trace("Loading component: $id", __METHOD__); + return $this->_components[$id] = Yii::createObject($this->_components[$id]); + } + } + return null; + } + + /** + * Registers a component with this module. + * @param string $id component ID + * @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 via [[Yii::createObject()]]. + * - null: the named component will be removed from the module + */ + public function setComponent($id, $component) + { + if ($component === null) { + unset($this->_components[$id]); + } else { + $this->_components[$id] = $component; + } + } + + /** + * 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 components (indexed by their IDs) + */ + public function getComponents($loadedOnly = false) + { + if ($loadedOnly) { + $components = array(); + foreach ($this->_components as $component) { + if ($component instanceof Component) { + $components[] = $component; + } + } + return $components; + } else { + return $this->_components; + } + } + + /** + * Registers a set of components in this module. + * + * 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()]] + * 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. + * + * The following is an example for setting two components: + * + * ~~~ + * array( + * 'db' => array( + * 'class' => 'yii\db\Connection', + * 'dsn' => 'sqlite:path/to/file.db', + * ), + * 'cache' => array( + * 'class' => 'yii\caching\DbCache', + * 'db' => 'db', + * ), + * ) + * ~~~ + * + * @param array $components components (id => component configuration or instance) + */ + public function setComponents($components) + { + foreach ($components as $id => $component) { + if (isset($this->_components[$id]['class']) && !isset($component['class'])) { + $component['class'] = $this->_components[$id]['class']; + } + $this->_components[$id] = $component; + } + } + + /** + * Loads components that are declared in [[preload]]. + */ + public function preloadComponents() + { + foreach ($this->preload as $id) { + $this->getComponent($id); + } + } + + /** + * 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 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()) + { + $result = $this->createController($route); + if (is_array($result)) { + /** @var $controller Controller */ + list($controller, $actionID) = $result; + $oldController = Yii::$app->controller; + Yii::$app->controller = $controller; + $status = $controller->runAction($actionID, $params); + Yii::$app->controller = $oldController; + return $status; + } else { + throw new InvalidRouteException('Unable to resolve the request "' . trim($this->getUniqueId() . '/' . $route, '/') . '".'); + } + } + + /** + * Creates a controller instance based on the controller ID. + * + * The controller is created within this 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 $route the route consisting of module, controller and action IDs. + * @return array|boolean If the controller is created successfully, it will be returned together + * with the requested action ID. Otherwise false will be returned. + * @throws InvalidConfigException if the controller class and its file do not match. + */ + public function createController($route) + { + if ($route === '') { + $route = $this->defaultRoute; + } + $route = trim($route, '/'); + if (($pos = strpos($route, '/')) !== false) { + $id = substr($route, 0, $pos); + $route = substr($route, $pos + 1); + } else { + $id = $route; + $route = ''; + } + + $module = $this->getModule($id); + if ($module !== null) { + return $module->createController($route); + } + + if (isset($this->controllerMap[$id])) { + $controller = Yii::createObject($this->controllerMap[$id], $id, $this); + } elseif (preg_match('/^[a-z0-9\\-_]+$/', $id)) { + $className = str_replace(' ', '', ucwords(implode(' ', explode('-', $id)))) . 'Controller'; + $classFile = $this->controllerPath . DIRECTORY_SEPARATOR . $className . '.php'; + if (!is_file($classFile)) { + return false; + } + $className = ltrim($this->controllerNamespace . '\\' . $className, '\\'); + Yii::$classMap[$className] = $classFile; + if (is_subclass_of($className, 'yii\base\Controller')) { + $controller = new $className($id, $this); + } elseif (YII_DEBUG) { + throw new InvalidConfigException("Controller class must extend from \\yii\\base\\Controller."); + } + } + + return isset($controller) ? array($controller, $route) : false; + } + + /** + * 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)); + } +} diff --git a/framework/yii/base/NotSupportedException.php b/framework/yii/base/NotSupportedException.php index 8a93e14..33f936f 100644 --- a/framework/yii/base/NotSupportedException.php +++ b/framework/yii/base/NotSupportedException.php @@ -23,4 +23,3 @@ class NotSupportedException extends Exception return \Yii::t('yii', 'Not Supported'); } } - diff --git a/framework/yii/base/Theme.php b/framework/yii/base/Theme.php index ca1efcd..91c32dc 100644 --- a/framework/yii/base/Theme.php +++ b/framework/yii/base/Theme.php @@ -73,7 +73,7 @@ class Theme extends Component */ public function init() { - parent::init(); + parent::init(); if (empty($this->pathMap)) { if ($this->basePath !== null) { $this->basePath = Yii::getAlias($this->basePath); diff --git a/framework/yii/base/UnknownClassException.php b/framework/yii/base/UnknownClassException.php index e4a682a..7b893d4 100644 --- a/framework/yii/base/UnknownClassException.php +++ b/framework/yii/base/UnknownClassException.php @@ -23,4 +23,3 @@ class UnknownClassException extends Exception return \Yii::t('yii', 'Unknown Class'); } } - diff --git a/framework/yii/base/UnknownMethodException.php b/framework/yii/base/UnknownMethodException.php index d8cea34..3b33659 100644 --- a/framework/yii/base/UnknownMethodException.php +++ b/framework/yii/base/UnknownMethodException.php @@ -23,4 +23,3 @@ class UnknownMethodException extends Exception return \Yii::t('yii', 'Unknown Method'); } } - diff --git a/framework/yii/base/UnknownPropertyException.php b/framework/yii/base/UnknownPropertyException.php index b8e93c5..682fdfa 100644 --- a/framework/yii/base/UnknownPropertyException.php +++ b/framework/yii/base/UnknownPropertyException.php @@ -23,4 +23,3 @@ class UnknownPropertyException extends Exception return \Yii::t('yii', 'Unknown Property'); } } - diff --git a/framework/yii/bootstrap/Button.php b/framework/yii/bootstrap/Button.php index 104e700..856c420 100644 --- a/framework/yii/bootstrap/Button.php +++ b/framework/yii/bootstrap/Button.php @@ -6,9 +6,8 @@ */ namespace yii\bootstrap; -use yii\base\InvalidConfigException; -use yii\helpers\Html; +use yii\helpers\Html; /** * Button renders a bootstrap button. diff --git a/framework/yii/bootstrap/ButtonDropdown.php b/framework/yii/bootstrap/ButtonDropdown.php index 4168bd5..fec042e 100644 --- a/framework/yii/bootstrap/ButtonDropdown.php +++ b/framework/yii/bootstrap/ButtonDropdown.php @@ -6,8 +6,8 @@ */ namespace yii\bootstrap; -use yii\helpers\Html; +use yii\helpers\Html; /** * ButtonDropdown renders a group or split button dropdown bootstrap component. diff --git a/framework/yii/bootstrap/ButtonGroup.php b/framework/yii/bootstrap/ButtonGroup.php index f50d6a8..e5bf4e9 100644 --- a/framework/yii/bootstrap/ButtonGroup.php +++ b/framework/yii/bootstrap/ButtonGroup.php @@ -10,7 +10,6 @@ namespace yii\bootstrap; use yii\helpers\base\ArrayHelper; use yii\helpers\Html; - /** * ButtonGroup renders a button group bootstrap component. * diff --git a/framework/yii/bootstrap/Collapse.php b/framework/yii/bootstrap/Collapse.php index a7929e3..fdcaae1 100644 --- a/framework/yii/bootstrap/Collapse.php +++ b/framework/yii/bootstrap/Collapse.php @@ -130,4 +130,4 @@ class Collapse extends Widget return implode("\n", $group); } -} \ No newline at end of file +} diff --git a/framework/yii/bootstrap/Dropdown.php b/framework/yii/bootstrap/Dropdown.php index 2bee0ff..827e6cc 100644 --- a/framework/yii/bootstrap/Dropdown.php +++ b/framework/yii/bootstrap/Dropdown.php @@ -11,7 +11,6 @@ use yii\base\InvalidConfigException; use yii\helpers\ArrayHelper; use yii\helpers\Html; - /** * Dropdown renders a Bootstrap dropdown menu component. * diff --git a/framework/yii/bootstrap/Nav.php b/framework/yii/bootstrap/Nav.php index 6c091a4..8e35010 100644 --- a/framework/yii/bootstrap/Nav.php +++ b/framework/yii/bootstrap/Nav.php @@ -118,7 +118,7 @@ class Nav extends Widget $url = Html::url(ArrayHelper::getValue($item, 'url', '#')); $linkOptions = ArrayHelper::getValue($item, 'linkOptions', array()); - if(ArrayHelper::getValue($item, 'active')) { + if (ArrayHelper::getValue($item, 'active')) { $this->addCssClass($options, 'active'); } diff --git a/framework/yii/bootstrap/Progress.php b/framework/yii/bootstrap/Progress.php index 708c0fe..7c0473e 100644 --- a/framework/yii/bootstrap/Progress.php +++ b/framework/yii/bootstrap/Progress.php @@ -11,7 +11,6 @@ use yii\base\InvalidConfigException; use yii\helpers\ArrayHelper; use yii\helpers\Html; - /** * Progress renders a bootstrap progress bar component. * diff --git a/framework/yii/bootstrap/Widget.php b/framework/yii/bootstrap/Widget.php index a2e6d77..48b0331 100644 --- a/framework/yii/bootstrap/Widget.php +++ b/framework/yii/bootstrap/Widget.php @@ -11,7 +11,6 @@ use Yii; use yii\base\View; use yii\helpers\Json; - /** * \yii\bootstrap\Widget is the base class for all bootstrap widgets. * diff --git a/framework/yii/caching/DbCache.php b/framework/yii/caching/DbCache.php index 7e5f12d..7571a42 100644 --- a/framework/yii/caching/DbCache.php +++ b/framework/yii/caching/DbCache.php @@ -170,7 +170,7 @@ class DbCache extends Cache } else { return $this->addValue($key, $value, $expire); } - } + } /** * Stores a value identified by a key into cache if the cache does not contain this key. diff --git a/framework/yii/caching/XCache.php b/framework/yii/caching/XCache.php index 91f483b..1f12f23 100644 --- a/framework/yii/caching/XCache.php +++ b/framework/yii/caching/XCache.php @@ -86,4 +86,3 @@ class XCache extends Cache return true; } } - diff --git a/framework/yii/console/Exception.php b/framework/yii/console/Exception.php index 9e9003e..f272bde 100644 --- a/framework/yii/console/Exception.php +++ b/framework/yii/console/Exception.php @@ -25,4 +25,3 @@ class Exception extends UserException return \Yii::t('yii', 'Error'); } } - diff --git a/framework/yii/console/controllers/AssetController.php b/framework/yii/console/controllers/AssetController.php index cd8710e..dcd1667 100644 --- a/framework/yii/console/controllers/AssetController.php +++ b/framework/yii/console/controllers/AssetController.php @@ -220,7 +220,8 @@ class AssetController extends Controller * @param array $result already loaded bundles list. * @throws \yii\console\Exception on failure. */ - protected function loadBundleDependency($name, $bundle, &$result) { + protected function loadBundleDependency($name, $bundle, &$result) + { if (!empty($bundle->depends)) { $assetManager = $this->getAssetManager(); foreach ($bundle->depends as $dependencyName) { @@ -572,7 +573,7 @@ EOD; $inputFileRelativePathParts = explode('/', $inputFileRelativePath); $outputFileRelativePathParts = explode('/', $outputFileRelativePath); - $callback = function($matches) use ($inputFileRelativePathParts, $outputFileRelativePathParts) { + $callback = function ($matches) use ($inputFileRelativePathParts, $outputFileRelativePathParts) { $fullMatch = $matches[0]; $inputUrl = $matches[1]; diff --git a/framework/yii/console/controllers/MessageController.php b/framework/yii/console/controllers/MessageController.php index 715fb5c..44cf1b1 100644 --- a/framework/yii/console/controllers/MessageController.php +++ b/framework/yii/console/controllers/MessageController.php @@ -179,8 +179,7 @@ class MessageController extends Controller } ksort($translated); foreach ($translated as $message => $translation) { - if (!isset($merged[$message]) && !isset($todo[$message]) && !$removeOld) - { + if (!isset($merged[$message]) && !isset($todo[$message]) && !$removeOld) { if (substr($translation, 0, 2) === '@@' && substr($translation, -2) === '@@') { $todo[$message]=$translation; } else { diff --git a/framework/yii/console/controllers/MigrateController.php b/framework/yii/console/controllers/MigrateController.php index d3eb257..eca7787 100644 --- a/framework/yii/console/controllers/MigrateController.php +++ b/framework/yii/console/controllers/MigrateController.php @@ -1,635 +1,635 @@ - - * @link http://www.yiiframework.com/ - * @copyright Copyright (c) 2008 Yii Software LLC - * @license http://www.yiiframework.com/license/ - */ - -namespace yii\console\controllers; - -use Yii; -use yii\console\Exception; -use yii\console\Controller; -use yii\db\Connection; -use yii\db\Query; -use yii\helpers\ArrayHelper; - -/** - * This command manages application migrations. - * - * A migration means a set of persistent changes to the application environment - * that is shared among different developers. For example, in an application - * backed by a database, a migration may refer to a set of changes to - * the database, such as creating a new table, adding a new table column. - * - * This command provides support for tracking the migration history, upgrading - * or downloading with migrations, and creating new migration skeletons. - * - * The migration history is stored in a database table named - * as [[migrationTable]]. The table will be automatically created the first time - * this command is executed, if it does not exist. You may also manually - * create it as follows: - * - * ~~~ - * CREATE TABLE tbl_migration ( - * version varchar(255) PRIMARY KEY, - * apply_time integer - * ) - * ~~~ - * - * Below are some common usages of this command: - * - * ~~~ - * # creates a new migration named 'create_user_table' - * yii migrate/create create_user_table - * - * # applies ALL new migrations - * yii migrate - * - * # reverts the last applied migration - * yii migrate/down - * ~~~ - * - * @author Qiang Xue - * @since 2.0 - */ -class MigrateController extends Controller -{ - /** - * The name of the dummy migration that marks the beginning of the whole migration history. - */ - const BASE_MIGRATION = 'm000000_000000_base'; - - /** - * @var string the default command action. - */ - public $defaultAction = 'up'; - /** - * @var string the directory storing the migration classes. This can be either - * a path alias or a directory. - */ - public $migrationPath = '@app/migrations'; - /** - * @var string the name of the table for keeping applied migration information. - */ - public $migrationTable = 'tbl_migration'; - /** - * @var string the template file for generating new migrations. - * This can be either a path alias (e.g. "@app/migrations/template.php") - * or a file path. - */ - public $templateFile = '@yii/views/migration.php'; - /** - * @var boolean whether to execute the migration in an interactive mode. - */ - public $interactive = true; - /** - * @var Connection|string the DB connection object or the application - * component ID of the DB connection. - */ - public $db = 'db'; - - /** - * Returns the names of the global options for this command. - * @return array the names of the global options for this command. - */ - public function globalOptions() - { - return array('migrationPath', 'migrationTable', 'db', 'templateFile', 'interactive'); - } - - /** - * This method is invoked right before an action is to be executed (after all possible filters.) - * It checks the existence of the [[migrationPath]]. - * @param \yii\base\Action $action the action to be executed. - * @return boolean whether the action should continue to be executed. - * @throws Exception if the migration directory does not exist. - */ - public function beforeAction($action) - { - if (parent::beforeAction($action)) { - $path = Yii::getAlias($this->migrationPath); - if (!is_dir($path)) { - throw new Exception("The migration directory \"{$this->migrationPath}\" does not exist."); - } - $this->migrationPath = $path; - - if($action->id!=='create') { - if (is_string($this->db)) { - $this->db = Yii::$app->getComponent($this->db); - } - if (!$this->db instanceof Connection) { - throw new Exception("The 'db' option must refer to the application component ID of a DB connection."); - } - } - - $version = Yii::getVersion(); - echo "Yii Migration Tool (based on Yii v{$version})\n\n"; - return true; - } else { - return false; - } - } - - /** - * Upgrades the application by applying new migrations. - * For example, - * - * ~~~ - * yii migrate # apply all new migrations - * yii migrate 3 # apply the first 3 new migrations - * ~~~ - * - * @param integer $limit the number of new migrations to be applied. If 0, it means - * applying all available new migrations. - */ - public function actionUp($limit = 0) - { - $migrations = $this->getNewMigrations(); - if (empty($migrations)) { - echo "No new migration found. Your system is up-to-date.\n"; - Yii::$app->end(); - } - - $total = count($migrations); - $limit = (int)$limit; - if ($limit > 0) { - $migrations = array_slice($migrations, 0, $limit); - } - - $n = count($migrations); - if ($n === $total) { - echo "Total $n new " . ($n === 1 ? 'migration' : 'migrations') . " to be applied:\n"; - } else { - echo "Total $n out of $total new " . ($total === 1 ? 'migration' : 'migrations') . " to be applied:\n"; - } - - foreach ($migrations as $migration) { - echo " $migration\n"; - } - echo "\n"; - - if ($this->confirm('Apply the above ' . ($n === 1 ? 'migration' : 'migrations') . "?")) { - foreach ($migrations as $migration) { - if (!$this->migrateUp($migration)) { - echo "\nMigration failed. The rest of the migrations are canceled.\n"; - return; - } - } - echo "\nMigrated up successfully.\n"; - } - } - - /** - * Downgrades the application by reverting old migrations. - * For example, - * - * ~~~ - * yii migrate/down # revert the last migration - * yii migrate/down 3 # revert the last 3 migrations - * ~~~ - * - * @param integer $limit the number of migrations to be reverted. Defaults to 1, - * meaning the last applied migration will be reverted. - * @throws Exception if the number of the steps specified is less than 1. - */ - public function actionDown($limit = 1) - { - $limit = (int)$limit; - if ($limit < 1) { - throw new Exception("The step argument must be greater than 0."); - } - - $migrations = $this->getMigrationHistory($limit); - if (empty($migrations)) { - echo "No migration has been done before.\n"; - return; - } - $migrations = array_keys($migrations); - - $n = count($migrations); - echo "Total $n " . ($n === 1 ? 'migration' : 'migrations') . " to be reverted:\n"; - foreach ($migrations as $migration) { - echo " $migration\n"; - } - echo "\n"; - - if ($this->confirm('Revert the above ' . ($n === 1 ? 'migration' : 'migrations') . "?")) { - foreach ($migrations as $migration) { - if (!$this->migrateDown($migration)) { - echo "\nMigration failed. The rest of the migrations are canceled.\n"; - return; - } - } - echo "\nMigrated down successfully.\n"; - } - } - - /** - * Redoes the last few migrations. - * - * This command will first revert the specified migrations, and then apply - * them again. For example, - * - * ~~~ - * yii migrate/redo # redo the last applied migration - * yii migrate/redo 3 # redo the last 3 applied migrations - * ~~~ - * - * @param integer $limit the number of migrations to be redone. Defaults to 1, - * meaning the last applied migration will be redone. - * @throws Exception if the number of the steps specified is less than 1. - */ - public function actionRedo($limit = 1) - { - $limit = (int)$limit; - if ($limit < 1) { - throw new Exception("The step argument must be greater than 0."); - } - - $migrations = $this->getMigrationHistory($limit); - if (empty($migrations)) { - echo "No migration has been done before.\n"; - return; - } - $migrations = array_keys($migrations); - - $n = count($migrations); - echo "Total $n " . ($n === 1 ? 'migration' : 'migrations') . " to be redone:\n"; - foreach ($migrations as $migration) { - echo " $migration\n"; - } - echo "\n"; - - if ($this->confirm('Redo the above ' . ($n === 1 ? 'migration' : 'migrations') . "?")) { - foreach ($migrations as $migration) { - if (!$this->migrateDown($migration)) { - echo "\nMigration failed. The rest of the migrations are canceled.\n"; - return; - } - } - foreach (array_reverse($migrations) as $migration) { - if (!$this->migrateUp($migration)) { - echo "\nMigration failed. The rest of the migrations migrations are canceled.\n"; - return; - } - } - echo "\nMigration redone successfully.\n"; - } - } - - /** - * Upgrades or downgrades till the specified version. - * - * This command will first revert the specified migrations, and then apply - * them again. For example, - * - * ~~~ - * yii migrate/to 101129_185401 # using timestamp - * yii migrate/to m101129_185401_create_user_table # using full name - * ~~~ - * - * @param string $version the version name that the application should be migrated to. - * This can be either the timestamp or the full name of the migration. - * @throws Exception if the version argument is invalid - */ - public function actionTo($version) - { - $originalVersion = $version; - if (preg_match('/^m?(\d{6}_\d{6})(_.*?)?$/', $version, $matches)) { - $version = 'm' . $matches[1]; - } else { - throw new Exception("The version argument must be either a timestamp (e.g. 101129_185401)\nor the full name of a migration (e.g. m101129_185401_create_user_table)."); - } - - // try migrate up - $migrations = $this->getNewMigrations(); - foreach ($migrations as $i => $migration) { - if (strpos($migration, $version . '_') === 0) { - $this->actionUp($i + 1); - return; - } - } - - // try migrate down - $migrations = array_keys($this->getMigrationHistory(-1)); - foreach ($migrations as $i => $migration) { - if (strpos($migration, $version . '_') === 0) { - if ($i === 0) { - echo "Already at '$originalVersion'. Nothing needs to be done.\n"; - } else { - $this->actionDown($i); - } - return; - } - } - - throw new Exception("Unable to find the version '$originalVersion'."); - } - - /** - * Modifies the migration history to the specified version. - * - * No actual migration will be performed. - * - * ~~~ - * yii migrate/mark 101129_185401 # using timestamp - * yii migrate/mark m101129_185401_create_user_table # using full name - * ~~~ - * - * @param string $version the version at which the migration history should be marked. - * This can be either the timestamp or the full name of the migration. - * @throws Exception if the version argument is invalid or the version cannot be found. - */ - public function actionMark($version) - { - $originalVersion = $version; - if (preg_match('/^m?(\d{6}_\d{6})(_.*?)?$/', $version, $matches)) { - $version = 'm' . $matches[1]; - } else { - throw new Exception("The version argument must be either a timestamp (e.g. 101129_185401)\nor the full name of a migration (e.g. m101129_185401_create_user_table)."); - } - - // try mark up - $migrations = $this->getNewMigrations(); - foreach ($migrations as $i => $migration) { - if (strpos($migration, $version . '_') === 0) { - if ($this->confirm("Set migration history at $originalVersion?")) { - $command = $this->db->createCommand(); - for ($j = 0; $j <= $i; ++$j) { - $command->insert($this->migrationTable, array( - 'version' => $migrations[$j], - 'apply_time' => time(), - ))->execute(); - } - echo "The migration history is set at $originalVersion.\nNo actual migration was performed.\n"; - } - return; - } - } - - // try mark down - $migrations = array_keys($this->getMigrationHistory(-1)); - foreach ($migrations as $i => $migration) { - if (strpos($migration, $version . '_') === 0) { - if ($i === 0) { - echo "Already at '$originalVersion'. Nothing needs to be done.\n"; - } else { - if ($this->confirm("Set migration history at $originalVersion?")) { - $command = $this->db->createCommand(); - for ($j = 0; $j < $i; ++$j) { - $command->delete($this->migrationTable, array( - 'version' => $migrations[$j], - ))->execute(); - } - echo "The migration history is set at $originalVersion.\nNo actual migration was performed.\n"; - } - } - return; - } - } - - throw new Exception("Unable to find the version '$originalVersion'."); - } - - /** - * Displays the migration history. - * - * This command will show the list of migrations that have been applied - * so far. For example, - * - * ~~~ - * yii migrate/history # showing the last 10 migrations - * yii migrate/history 5 # showing the last 5 migrations - * yii migrate/history 0 # showing the whole history - * ~~~ - * - * @param integer $limit the maximum number of migrations to be displayed. - * If it is 0, the whole migration history will be displayed. - */ - public function actionHistory($limit = 10) - { - $limit = (int)$limit; - $migrations = $this->getMigrationHistory($limit); - if (empty($migrations)) { - echo "No migration has been done before.\n"; - } else { - $n = count($migrations); - if ($limit > 0) { - echo "Showing the last $n applied " . ($n === 1 ? 'migration' : 'migrations') . ":\n"; - } else { - echo "Total $n " . ($n === 1 ? 'migration has' : 'migrations have') . " been applied before:\n"; - } - foreach ($migrations as $version => $time) { - echo " (" . date('Y-m-d H:i:s', $time) . ') ' . $version . "\n"; - } - } - } - - /** - * Displays the un-applied new migrations. - * - * This command will show the new migrations that have not been applied. - * For example, - * - * ~~~ - * yii migrate/new # showing the first 10 new migrations - * yii migrate/new 5 # showing the first 5 new migrations - * yii migrate/new 0 # showing all new migrations - * ~~~ - * - * @param integer $limit the maximum number of new migrations to be displayed. - * If it is 0, all available new migrations will be displayed. - */ - public function actionNew($limit = 10) - { - $limit = (int)$limit; - $migrations = $this->getNewMigrations(); - if (empty($migrations)) { - echo "No new migrations found. Your system is up-to-date.\n"; - } else { - $n = count($migrations); - if ($limit > 0 && $n > $limit) { - $migrations = array_slice($migrations, 0, $limit); - echo "Showing $limit out of $n new " . ($n === 1 ? 'migration' : 'migrations') . ":\n"; - } else { - echo "Found $n new " . ($n === 1 ? 'migration' : 'migrations') . ":\n"; - } - - foreach ($migrations as $migration) { - echo " " . $migration . "\n"; - } - } - } - - /** - * Creates a new migration. - * - * This command creates a new migration using the available migration template. - * After using this command, developers should modify the created migration - * skeleton by filling up the actual migration logic. - * - * ~~~ - * yii migrate/create create_user_table - * ~~~ - * - * @param string $name the name of the new migration. This should only contain - * letters, digits and/or underscores. - * @throws Exception if the name argument is invalid. - */ - public function actionCreate($name) - { - if (!preg_match('/^\w+$/', $name)) { - throw new Exception("The migration name should contain letters, digits and/or underscore characters only."); - } - - $name = 'm' . gmdate('ymd_His') . '_' . $name; - $file = $this->migrationPath . DIRECTORY_SEPARATOR . $name . '.php'; - - if ($this->confirm("Create new migration '$file'?")) { - $content = $this->renderFile(Yii::getAlias($this->templateFile), array( - 'className' => $name, - )); - file_put_contents($file, $content); - echo "New migration created successfully.\n"; - } - } - - /** - * Upgrades with the specified migration class. - * @param string $class the migration class name - * @return boolean whether the migration is successful - */ - protected function migrateUp($class) - { - if ($class === self::BASE_MIGRATION) { - return true; - } - - echo "*** applying $class\n"; - $start = microtime(true); - $migration = $this->createMigration($class); - if ($migration->up() !== false) { - $this->db->createCommand()->insert($this->migrationTable, array( - 'version' => $class, - 'apply_time' => time(), - ))->execute(); - $time = microtime(true) - $start; - echo "*** applied $class (time: " . sprintf("%.3f", $time) . "s)\n\n"; - return true; - } else { - $time = microtime(true) - $start; - echo "*** failed to apply $class (time: " . sprintf("%.3f", $time) . "s)\n\n"; - return false; - } - } - - /** - * Downgrades with the specified migration class. - * @param string $class the migration class name - * @return boolean whether the migration is successful - */ - protected function migrateDown($class) - { - if ($class === self::BASE_MIGRATION) { - return true; - } - - echo "*** reverting $class\n"; - $start = microtime(true); - $migration = $this->createMigration($class); - if ($migration->down() !== false) { - $this->db->createCommand()->delete($this->migrationTable, array( - 'version' => $class, - ))->execute(); - $time = microtime(true) - $start; - echo "*** reverted $class (time: " . sprintf("%.3f", $time) . "s)\n\n"; - return true; - } else { - $time = microtime(true) - $start; - echo "*** failed to revert $class (time: " . sprintf("%.3f", $time) . "s)\n\n"; - return false; - } - } - - /** - * Creates a new migration instance. - * @param string $class the migration class name - * @return \yii\db\Migration the migration instance - */ - protected function createMigration($class) - { - $file = $this->migrationPath . DIRECTORY_SEPARATOR . $class . '.php'; - require_once($file); - return new $class(array( - 'db' => $this->db, - )); - } - - /** - * Returns the migration history. - * @param integer $limit the maximum number of records in the history to be returned - * @return array the migration history - */ - protected function getMigrationHistory($limit) - { - if ($this->db->schema->getTableSchema($this->migrationTable, true) === null) { - $this->createMigrationHistoryTable(); - } - $query = new Query; - $rows = $query->select(array('version', 'apply_time')) - ->from($this->migrationTable) - ->orderBy('version DESC') - ->limit($limit) - ->createCommand() - ->queryAll(); - $history = ArrayHelper::map($rows, 'version', 'apply_time'); - unset($history[self::BASE_MIGRATION]); - return $history; - } - - /** - * Creates the migration history table. - */ - protected function createMigrationHistoryTable() - { - echo 'Creating migration history table "' . $this->migrationTable . '"...'; - $this->db->createCommand()->createTable($this->migrationTable, array( - 'version' => 'varchar(255) NOT NULL PRIMARY KEY', - 'apply_time' => 'integer', - ))->execute(); - $this->db->createCommand()->insert($this->migrationTable, array( - 'version' => self::BASE_MIGRATION, - 'apply_time' => time(), - ))->execute(); - echo "done.\n"; - } - - /** - * Returns the migrations that are not applied. - * @return array list of new migrations - */ - protected function getNewMigrations() - { - $applied = array(); - foreach ($this->getMigrationHistory(-1) as $version => $time) { - $applied[substr($version, 1, 13)] = true; - } - - $migrations = array(); - $handle = opendir($this->migrationPath); - while (($file = readdir($handle)) !== false) { - if ($file === '.' || $file === '..') { - continue; - } - $path = $this->migrationPath . DIRECTORY_SEPARATOR . $file; - if (preg_match('/^(m(\d{6}_\d{6})_.*?)\.php$/', $file, $matches) && is_file($path) && !isset($applied[$matches[2]])) { - $migrations[] = $matches[1]; - } - } - closedir($handle); - sort($migrations); - return $migrations; - } -} + + * @link http://www.yiiframework.com/ + * @copyright Copyright (c) 2008 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +namespace yii\console\controllers; + +use Yii; +use yii\console\Exception; +use yii\console\Controller; +use yii\db\Connection; +use yii\db\Query; +use yii\helpers\ArrayHelper; + +/** + * This command manages application migrations. + * + * A migration means a set of persistent changes to the application environment + * that is shared among different developers. For example, in an application + * backed by a database, a migration may refer to a set of changes to + * the database, such as creating a new table, adding a new table column. + * + * This command provides support for tracking the migration history, upgrading + * or downloading with migrations, and creating new migration skeletons. + * + * The migration history is stored in a database table named + * as [[migrationTable]]. The table will be automatically created the first time + * this command is executed, if it does not exist. You may also manually + * create it as follows: + * + * ~~~ + * CREATE TABLE tbl_migration ( + * version varchar(255) PRIMARY KEY, + * apply_time integer + * ) + * ~~~ + * + * Below are some common usages of this command: + * + * ~~~ + * # creates a new migration named 'create_user_table' + * yii migrate/create create_user_table + * + * # applies ALL new migrations + * yii migrate + * + * # reverts the last applied migration + * yii migrate/down + * ~~~ + * + * @author Qiang Xue + * @since 2.0 + */ +class MigrateController extends Controller +{ + /** + * The name of the dummy migration that marks the beginning of the whole migration history. + */ + const BASE_MIGRATION = 'm000000_000000_base'; + + /** + * @var string the default command action. + */ + public $defaultAction = 'up'; + /** + * @var string the directory storing the migration classes. This can be either + * a path alias or a directory. + */ + public $migrationPath = '@app/migrations'; + /** + * @var string the name of the table for keeping applied migration information. + */ + public $migrationTable = 'tbl_migration'; + /** + * @var string the template file for generating new migrations. + * This can be either a path alias (e.g. "@app/migrations/template.php") + * or a file path. + */ + public $templateFile = '@yii/views/migration.php'; + /** + * @var boolean whether to execute the migration in an interactive mode. + */ + public $interactive = true; + /** + * @var Connection|string the DB connection object or the application + * component ID of the DB connection. + */ + public $db = 'db'; + + /** + * Returns the names of the global options for this command. + * @return array the names of the global options for this command. + */ + public function globalOptions() + { + return array('migrationPath', 'migrationTable', 'db', 'templateFile', 'interactive'); + } + + /** + * This method is invoked right before an action is to be executed (after all possible filters.) + * It checks the existence of the [[migrationPath]]. + * @param \yii\base\Action $action the action to be executed. + * @return boolean whether the action should continue to be executed. + * @throws Exception if the migration directory does not exist. + */ + public function beforeAction($action) + { + if (parent::beforeAction($action)) { + $path = Yii::getAlias($this->migrationPath); + if (!is_dir($path)) { + throw new Exception("The migration directory \"{$this->migrationPath}\" does not exist."); + } + $this->migrationPath = $path; + + if ($action->id !== 'create') { + if (is_string($this->db)) { + $this->db = Yii::$app->getComponent($this->db); + } + if (!$this->db instanceof Connection) { + throw new Exception("The 'db' option must refer to the application component ID of a DB connection."); + } + } + + $version = Yii::getVersion(); + echo "Yii Migration Tool (based on Yii v{$version})\n\n"; + return true; + } else { + return false; + } + } + + /** + * Upgrades the application by applying new migrations. + * For example, + * + * ~~~ + * yii migrate # apply all new migrations + * yii migrate 3 # apply the first 3 new migrations + * ~~~ + * + * @param integer $limit the number of new migrations to be applied. If 0, it means + * applying all available new migrations. + */ + public function actionUp($limit = 0) + { + $migrations = $this->getNewMigrations(); + if (empty($migrations)) { + echo "No new migration found. Your system is up-to-date.\n"; + Yii::$app->end(); + } + + $total = count($migrations); + $limit = (int)$limit; + if ($limit > 0) { + $migrations = array_slice($migrations, 0, $limit); + } + + $n = count($migrations); + if ($n === $total) { + echo "Total $n new " . ($n === 1 ? 'migration' : 'migrations') . " to be applied:\n"; + } else { + echo "Total $n out of $total new " . ($total === 1 ? 'migration' : 'migrations') . " to be applied:\n"; + } + + foreach ($migrations as $migration) { + echo " $migration\n"; + } + echo "\n"; + + if ($this->confirm('Apply the above ' . ($n === 1 ? 'migration' : 'migrations') . "?")) { + foreach ($migrations as $migration) { + if (!$this->migrateUp($migration)) { + echo "\nMigration failed. The rest of the migrations are canceled.\n"; + return; + } + } + echo "\nMigrated up successfully.\n"; + } + } + + /** + * Downgrades the application by reverting old migrations. + * For example, + * + * ~~~ + * yii migrate/down # revert the last migration + * yii migrate/down 3 # revert the last 3 migrations + * ~~~ + * + * @param integer $limit the number of migrations to be reverted. Defaults to 1, + * meaning the last applied migration will be reverted. + * @throws Exception if the number of the steps specified is less than 1. + */ + public function actionDown($limit = 1) + { + $limit = (int)$limit; + if ($limit < 1) { + throw new Exception("The step argument must be greater than 0."); + } + + $migrations = $this->getMigrationHistory($limit); + if (empty($migrations)) { + echo "No migration has been done before.\n"; + return; + } + $migrations = array_keys($migrations); + + $n = count($migrations); + echo "Total $n " . ($n === 1 ? 'migration' : 'migrations') . " to be reverted:\n"; + foreach ($migrations as $migration) { + echo " $migration\n"; + } + echo "\n"; + + if ($this->confirm('Revert the above ' . ($n === 1 ? 'migration' : 'migrations') . "?")) { + foreach ($migrations as $migration) { + if (!$this->migrateDown($migration)) { + echo "\nMigration failed. The rest of the migrations are canceled.\n"; + return; + } + } + echo "\nMigrated down successfully.\n"; + } + } + + /** + * Redoes the last few migrations. + * + * This command will first revert the specified migrations, and then apply + * them again. For example, + * + * ~~~ + * yii migrate/redo # redo the last applied migration + * yii migrate/redo 3 # redo the last 3 applied migrations + * ~~~ + * + * @param integer $limit the number of migrations to be redone. Defaults to 1, + * meaning the last applied migration will be redone. + * @throws Exception if the number of the steps specified is less than 1. + */ + public function actionRedo($limit = 1) + { + $limit = (int)$limit; + if ($limit < 1) { + throw new Exception("The step argument must be greater than 0."); + } + + $migrations = $this->getMigrationHistory($limit); + if (empty($migrations)) { + echo "No migration has been done before.\n"; + return; + } + $migrations = array_keys($migrations); + + $n = count($migrations); + echo "Total $n " . ($n === 1 ? 'migration' : 'migrations') . " to be redone:\n"; + foreach ($migrations as $migration) { + echo " $migration\n"; + } + echo "\n"; + + if ($this->confirm('Redo the above ' . ($n === 1 ? 'migration' : 'migrations') . "?")) { + foreach ($migrations as $migration) { + if (!$this->migrateDown($migration)) { + echo "\nMigration failed. The rest of the migrations are canceled.\n"; + return; + } + } + foreach (array_reverse($migrations) as $migration) { + if (!$this->migrateUp($migration)) { + echo "\nMigration failed. The rest of the migrations migrations are canceled.\n"; + return; + } + } + echo "\nMigration redone successfully.\n"; + } + } + + /** + * Upgrades or downgrades till the specified version. + * + * This command will first revert the specified migrations, and then apply + * them again. For example, + * + * ~~~ + * yii migrate/to 101129_185401 # using timestamp + * yii migrate/to m101129_185401_create_user_table # using full name + * ~~~ + * + * @param string $version the version name that the application should be migrated to. + * This can be either the timestamp or the full name of the migration. + * @throws Exception if the version argument is invalid + */ + public function actionTo($version) + { + $originalVersion = $version; + if (preg_match('/^m?(\d{6}_\d{6})(_.*?)?$/', $version, $matches)) { + $version = 'm' . $matches[1]; + } else { + throw new Exception("The version argument must be either a timestamp (e.g. 101129_185401)\nor the full name of a migration (e.g. m101129_185401_create_user_table)."); + } + + // try migrate up + $migrations = $this->getNewMigrations(); + foreach ($migrations as $i => $migration) { + if (strpos($migration, $version . '_') === 0) { + $this->actionUp($i + 1); + return; + } + } + + // try migrate down + $migrations = array_keys($this->getMigrationHistory(-1)); + foreach ($migrations as $i => $migration) { + if (strpos($migration, $version . '_') === 0) { + if ($i === 0) { + echo "Already at '$originalVersion'. Nothing needs to be done.\n"; + } else { + $this->actionDown($i); + } + return; + } + } + + throw new Exception("Unable to find the version '$originalVersion'."); + } + + /** + * Modifies the migration history to the specified version. + * + * No actual migration will be performed. + * + * ~~~ + * yii migrate/mark 101129_185401 # using timestamp + * yii migrate/mark m101129_185401_create_user_table # using full name + * ~~~ + * + * @param string $version the version at which the migration history should be marked. + * This can be either the timestamp or the full name of the migration. + * @throws Exception if the version argument is invalid or the version cannot be found. + */ + public function actionMark($version) + { + $originalVersion = $version; + if (preg_match('/^m?(\d{6}_\d{6})(_.*?)?$/', $version, $matches)) { + $version = 'm' . $matches[1]; + } else { + throw new Exception("The version argument must be either a timestamp (e.g. 101129_185401)\nor the full name of a migration (e.g. m101129_185401_create_user_table)."); + } + + // try mark up + $migrations = $this->getNewMigrations(); + foreach ($migrations as $i => $migration) { + if (strpos($migration, $version . '_') === 0) { + if ($this->confirm("Set migration history at $originalVersion?")) { + $command = $this->db->createCommand(); + for ($j = 0; $j <= $i; ++$j) { + $command->insert($this->migrationTable, array( + 'version' => $migrations[$j], + 'apply_time' => time(), + ))->execute(); + } + echo "The migration history is set at $originalVersion.\nNo actual migration was performed.\n"; + } + return; + } + } + + // try mark down + $migrations = array_keys($this->getMigrationHistory(-1)); + foreach ($migrations as $i => $migration) { + if (strpos($migration, $version . '_') === 0) { + if ($i === 0) { + echo "Already at '$originalVersion'. Nothing needs to be done.\n"; + } else { + if ($this->confirm("Set migration history at $originalVersion?")) { + $command = $this->db->createCommand(); + for ($j = 0; $j < $i; ++$j) { + $command->delete($this->migrationTable, array( + 'version' => $migrations[$j], + ))->execute(); + } + echo "The migration history is set at $originalVersion.\nNo actual migration was performed.\n"; + } + } + return; + } + } + + throw new Exception("Unable to find the version '$originalVersion'."); + } + + /** + * Displays the migration history. + * + * This command will show the list of migrations that have been applied + * so far. For example, + * + * ~~~ + * yii migrate/history # showing the last 10 migrations + * yii migrate/history 5 # showing the last 5 migrations + * yii migrate/history 0 # showing the whole history + * ~~~ + * + * @param integer $limit the maximum number of migrations to be displayed. + * If it is 0, the whole migration history will be displayed. + */ + public function actionHistory($limit = 10) + { + $limit = (int)$limit; + $migrations = $this->getMigrationHistory($limit); + if (empty($migrations)) { + echo "No migration has been done before.\n"; + } else { + $n = count($migrations); + if ($limit > 0) { + echo "Showing the last $n applied " . ($n === 1 ? 'migration' : 'migrations') . ":\n"; + } else { + echo "Total $n " . ($n === 1 ? 'migration has' : 'migrations have') . " been applied before:\n"; + } + foreach ($migrations as $version => $time) { + echo " (" . date('Y-m-d H:i:s', $time) . ') ' . $version . "\n"; + } + } + } + + /** + * Displays the un-applied new migrations. + * + * This command will show the new migrations that have not been applied. + * For example, + * + * ~~~ + * yii migrate/new # showing the first 10 new migrations + * yii migrate/new 5 # showing the first 5 new migrations + * yii migrate/new 0 # showing all new migrations + * ~~~ + * + * @param integer $limit the maximum number of new migrations to be displayed. + * If it is 0, all available new migrations will be displayed. + */ + public function actionNew($limit = 10) + { + $limit = (int)$limit; + $migrations = $this->getNewMigrations(); + if (empty($migrations)) { + echo "No new migrations found. Your system is up-to-date.\n"; + } else { + $n = count($migrations); + if ($limit > 0 && $n > $limit) { + $migrations = array_slice($migrations, 0, $limit); + echo "Showing $limit out of $n new " . ($n === 1 ? 'migration' : 'migrations') . ":\n"; + } else { + echo "Found $n new " . ($n === 1 ? 'migration' : 'migrations') . ":\n"; + } + + foreach ($migrations as $migration) { + echo " " . $migration . "\n"; + } + } + } + + /** + * Creates a new migration. + * + * This command creates a new migration using the available migration template. + * After using this command, developers should modify the created migration + * skeleton by filling up the actual migration logic. + * + * ~~~ + * yii migrate/create create_user_table + * ~~~ + * + * @param string $name the name of the new migration. This should only contain + * letters, digits and/or underscores. + * @throws Exception if the name argument is invalid. + */ + public function actionCreate($name) + { + if (!preg_match('/^\w+$/', $name)) { + throw new Exception("The migration name should contain letters, digits and/or underscore characters only."); + } + + $name = 'm' . gmdate('ymd_His') . '_' . $name; + $file = $this->migrationPath . DIRECTORY_SEPARATOR . $name . '.php'; + + if ($this->confirm("Create new migration '$file'?")) { + $content = $this->renderFile(Yii::getAlias($this->templateFile), array( + 'className' => $name, + )); + file_put_contents($file, $content); + echo "New migration created successfully.\n"; + } + } + + /** + * Upgrades with the specified migration class. + * @param string $class the migration class name + * @return boolean whether the migration is successful + */ + protected function migrateUp($class) + { + if ($class === self::BASE_MIGRATION) { + return true; + } + + echo "*** applying $class\n"; + $start = microtime(true); + $migration = $this->createMigration($class); + if ($migration->up() !== false) { + $this->db->createCommand()->insert($this->migrationTable, array( + 'version' => $class, + 'apply_time' => time(), + ))->execute(); + $time = microtime(true) - $start; + echo "*** applied $class (time: " . sprintf("%.3f", $time) . "s)\n\n"; + return true; + } else { + $time = microtime(true) - $start; + echo "*** failed to apply $class (time: " . sprintf("%.3f", $time) . "s)\n\n"; + return false; + } + } + + /** + * Downgrades with the specified migration class. + * @param string $class the migration class name + * @return boolean whether the migration is successful + */ + protected function migrateDown($class) + { + if ($class === self::BASE_MIGRATION) { + return true; + } + + echo "*** reverting $class\n"; + $start = microtime(true); + $migration = $this->createMigration($class); + if ($migration->down() !== false) { + $this->db->createCommand()->delete($this->migrationTable, array( + 'version' => $class, + ))->execute(); + $time = microtime(true) - $start; + echo "*** reverted $class (time: " . sprintf("%.3f", $time) . "s)\n\n"; + return true; + } else { + $time = microtime(true) - $start; + echo "*** failed to revert $class (time: " . sprintf("%.3f", $time) . "s)\n\n"; + return false; + } + } + + /** + * Creates a new migration instance. + * @param string $class the migration class name + * @return \yii\db\Migration the migration instance + */ + protected function createMigration($class) + { + $file = $this->migrationPath . DIRECTORY_SEPARATOR . $class . '.php'; + require_once($file); + return new $class(array( + 'db' => $this->db, + )); + } + + /** + * Returns the migration history. + * @param integer $limit the maximum number of records in the history to be returned + * @return array the migration history + */ + protected function getMigrationHistory($limit) + { + if ($this->db->schema->getTableSchema($this->migrationTable, true) === null) { + $this->createMigrationHistoryTable(); + } + $query = new Query; + $rows = $query->select(array('version', 'apply_time')) + ->from($this->migrationTable) + ->orderBy('version DESC') + ->limit($limit) + ->createCommand() + ->queryAll(); + $history = ArrayHelper::map($rows, 'version', 'apply_time'); + unset($history[self::BASE_MIGRATION]); + return $history; + } + + /** + * Creates the migration history table. + */ + protected function createMigrationHistoryTable() + { + echo 'Creating migration history table "' . $this->migrationTable . '"...'; + $this->db->createCommand()->createTable($this->migrationTable, array( + 'version' => 'varchar(255) NOT NULL PRIMARY KEY', + 'apply_time' => 'integer', + ))->execute(); + $this->db->createCommand()->insert($this->migrationTable, array( + 'version' => self::BASE_MIGRATION, + 'apply_time' => time(), + ))->execute(); + echo "done.\n"; + } + + /** + * Returns the migrations that are not applied. + * @return array list of new migrations + */ + protected function getNewMigrations() + { + $applied = array(); + foreach ($this->getMigrationHistory(-1) as $version => $time) { + $applied[substr($version, 1, 13)] = true; + } + + $migrations = array(); + $handle = opendir($this->migrationPath); + while (($file = readdir($handle)) !== false) { + if ($file === '.' || $file === '..') { + continue; + } + $path = $this->migrationPath . DIRECTORY_SEPARATOR . $file; + if (preg_match('/^(m(\d{6}_\d{6})_.*?)\.php$/', $file, $matches) && is_file($path) && !isset($applied[$matches[2]])) { + $migrations[] = $matches[1]; + } + } + closedir($handle); + sort($migrations); + return $migrations; + } +} diff --git a/framework/yii/db/Connection.php b/framework/yii/db/Connection.php index 3a4d0ad..0dd47d8 100644 --- a/framework/yii/db/Connection.php +++ b/framework/yii/db/Connection.php @@ -305,8 +305,7 @@ class Connection extends Component $this->pdo = $this->createPdoInstance(); $this->initConnection(); Yii::endProfile($token, __METHOD__); - } - catch (\PDOException $e) { + } catch (\PDOException $e) { Yii::endProfile($token, __METHOD__); Yii::error("Failed to open DB connection ({$this->dsn}): " . $e->getMessage(), __METHOD__); $message = YII_DEBUG ? 'Failed to open DB connection: ' . $e->getMessage() : 'Failed to open DB connection.'; @@ -508,7 +507,7 @@ class Connection extends Component { $db = $this; return preg_replace_callback('/(\\{\\{([%\w\-\. ]+)\\}\\}|\\[\\[([\w\-\. ]+)\\]\\])/', - function($matches) use($db) { + function ($matches) use ($db) { if (isset($matches[3])) { return $db->quoteColumnName($matches[3]); } else { diff --git a/framework/yii/debug/Module.php b/framework/yii/debug/Module.php index 3421d95..a680f53 100644 --- a/framework/yii/debug/Module.php +++ b/framework/yii/debug/Module.php @@ -14,4 +14,4 @@ namespace yii\debug; class Module extends \yii\base\Module { public $controllerNamespace = 'yii\debug\controllers'; -} \ No newline at end of file +} diff --git a/framework/yii/debug/controllers/DefaultController.php b/framework/yii/debug/controllers/DefaultController.php index 4d686ee..f1160b1 100644 --- a/framework/yii/debug/controllers/DefaultController.php +++ b/framework/yii/debug/controllers/DefaultController.php @@ -31,4 +31,4 @@ class DefaultController extends Controller echo "Unable to find debug data tagged with '$tag'."; } } -} \ No newline at end of file +} diff --git a/framework/yii/helpers/Json.php b/framework/yii/helpers/Json.php index 5e77c3f..117db1f 100644 --- a/framework/yii/helpers/Json.php +++ b/framework/yii/helpers/Json.php @@ -14,5 +14,4 @@ namespace yii\helpers; */ class Json extends base\Json { - } diff --git a/framework/yii/helpers/base/Console.php b/framework/yii/helpers/base/Console.php index 6ad0b7b..e3acbd9 100644 --- a/framework/yii/helpers/base/Console.php +++ b/framework/yii/helpers/base/Console.php @@ -286,7 +286,7 @@ class Console * You can pass any of the FG_*, BG_* and TEXT_* constants and also [[xtermFgColor]] and [[xtermBgColor]]. * @return string */ - public static function ansiFormat($string, $format=array()) + public static function ansiFormat($string, $format = array()) { $code = implode(';', $format); return "\033[0m" . ($code !== '' ? "\033[" . $code . "m" : '') . $string . "\033[0m"; @@ -589,11 +589,10 @@ class Console if (static::isRunningOnWindows()) { $output = array(); exec('mode con', $output); - if(isset($output) && strpos($output[1], 'CON')!==false) { + if (isset($output) && strpos($output[1], 'CON') !== false) { return $size = array((int)preg_replace('~[^0-9]~', '', $output[3]), (int)preg_replace('~[^0-9]~', '', $output[4])); } } else { - // try stty if available $stty = array(); if (exec('stty -a 2>&1', $stty) && preg_match('/rows\s+(\d+);\s*columns\s+(\d+);/mi', implode(' ', $stty), $matches)) { diff --git a/framework/yii/helpers/base/Html.php b/framework/yii/helpers/base/Html.php index 9a0001c..47385e2 100644 --- a/framework/yii/helpers/base/Html.php +++ b/framework/yii/helpers/base/Html.php @@ -1479,5 +1479,4 @@ class Html $name = strtolower(static::getInputName($model, $attribute)); return str_replace(array('[]', '][', '[', ']', ' '), array('', '-', '-', '', '-'), $name); } - } diff --git a/framework/yii/helpers/base/Inflector.php b/framework/yii/helpers/base/Inflector.php index cc5d33f..f500c4c 100644 --- a/framework/yii/helpers/base/Inflector.php +++ b/framework/yii/helpers/base/Inflector.php @@ -50,7 +50,7 @@ class Inflector '/(ax|cris|test)is$/i' => '\1es', '/s$/' => 's', '/^$/' => '', - '/$/' => 's', + '/$/' => 's', ); /** * @var array the rules for converting a word into its singular form. @@ -94,7 +94,7 @@ class Inflector '/(n)ews$/i' => '\1\2ews', '/eaus$/' => 'eau', '/^(.*us)$/' => '\\1', - '/s$/i' => '', + '/s$/i' => '', ); /** * @var array the special rules for converting a word between its plural form and singular form. @@ -468,7 +468,7 @@ class Inflector if (in_array(($number % 100), range(11, 13))) { return $number . 'th'; } - switch (($number % 10)) { + switch ($number % 10) { case 1: return $number . 'st'; case 2: return $number . 'nd'; case 3: return $number . 'rd'; diff --git a/framework/yii/i18n/MessageSource.php b/framework/yii/i18n/MessageSource.php index cf23338..90adbfb 100644 --- a/framework/yii/i18n/MessageSource.php +++ b/framework/yii/i18n/MessageSource.php @@ -118,4 +118,3 @@ class MessageSource extends Component } } } - diff --git a/framework/yii/jui/Accordion.php b/framework/yii/jui/Accordion.php index f36c981..898649e 100644 --- a/framework/yii/jui/Accordion.php +++ b/framework/yii/jui/Accordion.php @@ -125,7 +125,7 @@ class Accordion extends Widget $items[] = Html::tag($headerTag, $item['header'], $headerOptions); $options = array_merge($this->itemOptions, ArrayHelper::getValue($item, 'options', array())); $tag = ArrayHelper::remove($options, 'tag', 'div'); - $items[] = Html::tag($tag, $item['content'], $options);; + $items[] = Html::tag($tag, $item['content'], $options); } return implode("\n", $items); diff --git a/framework/yii/jui/Menu.php b/framework/yii/jui/Menu.php index d4e390c..83523e7 100644 --- a/framework/yii/jui/Menu.php +++ b/framework/yii/jui/Menu.php @@ -10,7 +10,6 @@ namespace yii\jui; use Yii; use yii\helpers\Json; - /** * Menu renders a menu jQuery UI widget. * diff --git a/framework/yii/jui/Widget.php b/framework/yii/jui/Widget.php index d34a8bd..5724919 100644 --- a/framework/yii/jui/Widget.php +++ b/framework/yii/jui/Widget.php @@ -10,7 +10,6 @@ namespace yii\jui; use Yii; use yii\helpers\Json; - /** * \yii\jui\Widget is the base class for all jQuery UI widgets. * diff --git a/framework/yii/rbac/DbManager.php b/framework/yii/rbac/DbManager.php index b7a5d4e..8d3bea2 100644 --- a/framework/yii/rbac/DbManager.php +++ b/framework/yii/rbac/DbManager.php @@ -493,8 +493,9 @@ class DbManager extends Manager 'bizRule' => $row['biz_rule'], 'data' => $data, )); - } else + } else { return null; + } } /** diff --git a/framework/yii/rbac/PhpManager.php b/framework/yii/rbac/PhpManager.php index 7a476e0..8ecc75c 100644 --- a/framework/yii/rbac/PhpManager.php +++ b/framework/yii/rbac/PhpManager.php @@ -468,7 +468,7 @@ class PhpManager extends Manager 'bizRule' => $assignment['bizRule'], 'data' => $assignment['data'], )); - } + } } } } diff --git a/framework/yii/requirements/requirements.php b/framework/yii/requirements/requirements.php index 63aa70d..670544d 100644 --- a/framework/yii/requirements/requirements.php +++ b/framework/yii/requirements/requirements.php @@ -45,4 +45,4 @@ return array( 'by' => 'Internationalization support', 'memo' => 'PHP Intl extension 1.0.2 or higher is required when you want to use IDN-feature of EmailValidator or UrlValidator or the yii\i18n\Formatter class.' ), -); \ No newline at end of file +); diff --git a/framework/yii/validators/CaptchaValidator.php b/framework/yii/validators/CaptchaValidator.php index dbc263e..01870d3 100644 --- a/framework/yii/validators/CaptchaValidator.php +++ b/framework/yii/validators/CaptchaValidator.php @@ -117,4 +117,3 @@ class CaptchaValidator extends Validator return 'yii.validation.captcha(value, messages, ' . json_encode($options) . ');'; } } - diff --git a/framework/yii/validators/DateValidator.php b/framework/yii/validators/DateValidator.php index 2f3ce2d..2f9e18b 100644 --- a/framework/yii/validators/DateValidator.php +++ b/framework/yii/validators/DateValidator.php @@ -73,4 +73,3 @@ class DateValidator extends Validator return DateTime::createFromFormat($this->format, $value) !== false; } } - diff --git a/framework/yii/validators/DefaultValueValidator.php b/framework/yii/validators/DefaultValueValidator.php index 185dbd4..20df5fd 100644 --- a/framework/yii/validators/DefaultValueValidator.php +++ b/framework/yii/validators/DefaultValueValidator.php @@ -40,4 +40,3 @@ class DefaultValueValidator extends Validator } } } - diff --git a/framework/yii/validators/ExistValidator.php b/framework/yii/validators/ExistValidator.php index 7c45491..9c74890 100644 --- a/framework/yii/validators/ExistValidator.php +++ b/framework/yii/validators/ExistValidator.php @@ -99,4 +99,3 @@ class ExistValidator extends Validator return $query->exists(); } } - diff --git a/framework/yii/validators/FilterValidator.php b/framework/yii/validators/FilterValidator.php index 72a9a9d..560feb1 100644 --- a/framework/yii/validators/FilterValidator.php +++ b/framework/yii/validators/FilterValidator.php @@ -6,6 +6,7 @@ */ namespace yii\validators; + use yii\base\InvalidConfigException; /** diff --git a/framework/yii/validators/RangeValidator.php b/framework/yii/validators/RangeValidator.php index a915275..90256df 100644 --- a/framework/yii/validators/RangeValidator.php +++ b/framework/yii/validators/RangeValidator.php @@ -35,7 +35,7 @@ class RangeValidator extends Validator * @var boolean whether to invert the validation logic. Defaults to false. If set to true, * the attribute value should NOT be among the list of values defined via [[range]]. **/ - public $not = false; + public $not = false; /** * Initializes the validator. diff --git a/framework/yii/validators/RegularExpressionValidator.php b/framework/yii/validators/RegularExpressionValidator.php index 417f2bc..72a5a74 100644 --- a/framework/yii/validators/RegularExpressionValidator.php +++ b/framework/yii/validators/RegularExpressionValidator.php @@ -32,7 +32,7 @@ class RegularExpressionValidator extends Validator * the regular expression defined via [[pattern]] should NOT match the attribute value. * @throws InvalidConfigException if the "pattern" is not a valid regular expression **/ - public $not = false; + public $not = false; /** * Initializes the validator. diff --git a/framework/yii/validators/StringValidator.php b/framework/yii/validators/StringValidator.php index abe4634..e06354b 100644 --- a/framework/yii/validators/StringValidator.php +++ b/framework/yii/validators/StringValidator.php @@ -174,4 +174,3 @@ class StringValidator extends Validator return 'yii.validation.string(value, messages, ' . json_encode($options) . ');'; } } - diff --git a/framework/yii/validators/UrlValidator.php b/framework/yii/validators/UrlValidator.php index 6cf12c1..18f2f45 100644 --- a/framework/yii/validators/UrlValidator.php +++ b/framework/yii/validators/UrlValidator.php @@ -99,7 +99,7 @@ class UrlValidator extends Validator } if ($this->enableIDN) { - $value = preg_replace_callback('/:\/\/([^\/]+)/', function($matches) { + $value = preg_replace_callback('/:\/\/([^\/]+)/', function ($matches) { return '://' . idn_to_ascii($matches[1]); }, $value); } diff --git a/framework/yii/validators/Validator.php b/framework/yii/validators/Validator.php index 6b103bf..2629002 100644 --- a/framework/yii/validators/Validator.php +++ b/framework/yii/validators/Validator.php @@ -179,7 +179,7 @@ abstract class Validator extends Component } foreach ($attributes as $attribute) { $skip = $this->skipOnError && $object->hasErrors($attribute) - || $this->skipOnEmpty && $this->isEmpty($object->$attribute); + || $this->skipOnEmpty && $this->isEmpty($object->$attribute); if (!$skip) { $this->validateAttribute($object, $attribute); } diff --git a/framework/yii/web/HeaderCollection.php b/framework/yii/web/HeaderCollection.php index 7a24854..c7e1462 100644 --- a/framework/yii/web/HeaderCollection.php +++ b/framework/yii/web/HeaderCollection.php @@ -11,7 +11,6 @@ use Yii; use yii\base\Object; use ArrayIterator; - /** * HeaderCollection is used by [[Response]] to maintain the currently registered HTTP headers. * diff --git a/framework/yii/web/PageCache.php b/framework/yii/web/PageCache.php index 2fe36b3..8b28e62 100644 --- a/framework/yii/web/PageCache.php +++ b/framework/yii/web/PageCache.php @@ -1,104 +1,104 @@ - - * @since 2.0 - */ -class PageCache extends ActionFilter -{ - /** - * @var boolean whether the content being cached should be differentiated according to the route. - * A route consists of the requested controller ID and action ID. Defaults to true. - */ - public $varyByRoute = true; - /** - * @var string the application component ID of the [[\yii\caching\Cache|cache]] object. - */ - public $cache = 'cache'; - /** - * @var integer number of seconds that the data can remain valid in cache. - * Use 0 to indicate that the cached data will never expire. - */ - public $duration = 60; - /** - * @var array|Dependency the dependency that the cached content depends on. - * This can be either a [[Dependency]] object or a configuration array for creating the dependency object. - * For example, - * - * ~~~ - * array( - * 'class' => 'yii\caching\DbDependency', - * 'sql' => 'SELECT MAX(lastModified) FROM Post', - * ) - * ~~~ - * - * would make the output cache depends on the last modified time of all posts. - * If any post has its modification time changed, the cached content would be invalidated. - */ - public $dependency; - /** - * @var array list of factors that would cause the variation of the content being cached. - * Each factor is a string representing a variation (e.g. the language, a GET parameter). - * The following variation setting will cause the content to be cached in different versions - * according to the current application language: - * - * ~~~ - * array( - * Yii::$app->language, - * ) - */ - public $variations; - /** - * @var boolean whether to enable the fragment cache. You may use this property to turn on and off - * the fragment cache according to specific setting (e.g. enable fragment cache only for GET requests). - */ - public $enabled = true; - - - public function init() - { - parent::init(); - if ($this->view === null) { - $this->view = Yii::$app->getView(); - } - } - - /** - * 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) - { - $properties = array(); - foreach (array('cache', 'duration', 'dependency', 'variations', 'enabled') as $name) { - $properties[$name] = $this->$name; - } - $id = $this->varyByRoute ? $action->getUniqueId() : __CLASS__; - return $this->view->beginCache($id, $properties); - } - - /** - * 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->view->endCache(); - } + + * @since 2.0 + */ +class PageCache extends ActionFilter +{ + /** + * @var boolean whether the content being cached should be differentiated according to the route. + * A route consists of the requested controller ID and action ID. Defaults to true. + */ + public $varyByRoute = true; + /** + * @var string the application component ID of the [[\yii\caching\Cache|cache]] object. + */ + public $cache = 'cache'; + /** + * @var integer number of seconds that the data can remain valid in cache. + * Use 0 to indicate that the cached data will never expire. + */ + public $duration = 60; + /** + * @var array|Dependency the dependency that the cached content depends on. + * This can be either a [[Dependency]] object or a configuration array for creating the dependency object. + * For example, + * + * ~~~ + * array( + * 'class' => 'yii\caching\DbDependency', + * 'sql' => 'SELECT MAX(lastModified) FROM Post', + * ) + * ~~~ + * + * would make the output cache depends on the last modified time of all posts. + * If any post has its modification time changed, the cached content would be invalidated. + */ + public $dependency; + /** + * @var array list of factors that would cause the variation of the content being cached. + * Each factor is a string representing a variation (e.g. the language, a GET parameter). + * The following variation setting will cause the content to be cached in different versions + * according to the current application language: + * + * ~~~ + * array( + * Yii::$app->language, + * ) + */ + public $variations; + /** + * @var boolean whether to enable the fragment cache. You may use this property to turn on and off + * the fragment cache according to specific setting (e.g. enable fragment cache only for GET requests). + */ + public $enabled = true; + + + public function init() + { + parent::init(); + if ($this->view === null) { + $this->view = Yii::$app->getView(); + } + } + + /** + * 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) + { + $properties = array(); + foreach (array('cache', 'duration', 'dependency', 'variations', 'enabled') as $name) { + $properties[$name] = $this->$name; + } + $id = $this->varyByRoute ? $action->getUniqueId() : __CLASS__; + return $this->view->beginCache($id, $properties); + } + + /** + * 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->view->endCache(); + } } diff --git a/framework/yii/web/Request.php b/framework/yii/web/Request.php index e73c3b1..7cec044 100644 --- a/framework/yii/web/Request.php +++ b/framework/yii/web/Request.php @@ -792,4 +792,3 @@ class Request extends \yii\base\Request } } } - diff --git a/framework/yii/web/User.php b/framework/yii/web/User.php index 5522bbb..005f987 100644 --- a/framework/yii/web/User.php +++ b/framework/yii/web/User.php @@ -221,7 +221,7 @@ class User extends Component if ($destroySession) { Yii::$app->getSession()->destroy(); } - $this->afterLogout($identity); + $this->afterLogout($identity); } } diff --git a/framework/yii/widgets/FragmentCache.php b/framework/yii/widgets/FragmentCache.php index 8445955..0fd8646 100644 --- a/framework/yii/widgets/FragmentCache.php +++ b/framework/yii/widgets/FragmentCache.php @@ -1,174 +1,174 @@ - - * @since 2.0 - */ -class FragmentCache extends Widget -{ - /** - * @var Cache|string the cache object or the application component ID of the cache object. - * After the FragmentCache object is created, if you want to change this property, - * you should only assign it with a cache object. - */ - public $cache = 'cache'; - /** - * @var integer number of seconds that the data can remain valid in cache. - * Use 0 to indicate that the cached data will never expire. - */ - public $duration = 60; - /** - * @var array|Dependency the dependency that the cached content depends on. - * This can be either a [[Dependency]] object or a configuration array for creating the dependency object. - * For example, - * - * ~~~ - * array( - * 'class' => 'yii\caching\DbDependency', - * 'sql' => 'SELECT MAX(lastModified) FROM Post', - * ) - * ~~~ - * - * would make the output cache depends on the last modified time of all posts. - * If any post has its modification time changed, the cached content would be invalidated. - */ - public $dependency; - /** - * @var array list of factors that would cause the variation of the content being cached. - * Each factor is a string representing a variation (e.g. the language, a GET parameter). - * The following variation setting will cause the content to be cached in different versions - * according to the current application language: - * - * ~~~ - * array( - * Yii::$app->language, - * ) - */ - public $variations; - /** - * @var boolean whether to enable the fragment cache. You may use this property to turn on and off - * the fragment cache according to specific setting (e.g. enable fragment cache only for GET requests). - */ - public $enabled = true; - /** - * @var array a list of placeholders for embedding dynamic contents. This property - * is used internally to implement the content caching feature. Do not modify it. - */ - public $dynamicPlaceholders; - - /** - * Initializes the FragmentCache object. - */ - public function init() - { - parent::init(); - - if (!$this->enabled) { - $this->cache = null; - } elseif (is_string($this->cache)) { - $this->cache = Yii::$app->getComponent($this->cache); - } - - if ($this->getCachedContent() === false) { - $this->view->cacheStack[] = $this; - ob_start(); - ob_implicit_flush(false); - } - } - - /** - * Marks the end of content to be cached. - * Content displayed before this method call and after {@link init()} - * will be captured and saved in cache. - * This method does nothing if valid content is already found in cache. - */ - public function run() - { - if (($content = $this->getCachedContent()) !== false) { - echo $content; - } elseif ($this->cache instanceof Cache) { - $content = ob_get_clean(); - array_pop($this->view->cacheStack); - if (is_array($this->dependency)) { - $this->dependency = Yii::createObject($this->dependency); - } - $data = array($content, $this->dynamicPlaceholders); - $this->cache->set($this->calculateKey(), $data, $this->duration, $this->dependency); - - if (empty($this->view->cacheStack) && !empty($this->dynamicPlaceholders)) { - $content = $this->updateDynamicContent($content, $this->dynamicPlaceholders); - } - echo $content; - } - } - - /** - * @var string|boolean the cached content. False if the content is not cached. - */ - private $_content; - - /** - * Returns the cached content if available. - * @return string|boolean the cached content. False is returned if valid content is not found in the cache. - */ - public function getCachedContent() - { - if ($this->_content === null) { - $this->_content = false; - if ($this->cache instanceof Cache) { - $key = $this->calculateKey(); - $data = $this->cache->get($key); - if (is_array($data) && count($data) === 2) { - list ($content, $placeholders) = $data; - if (is_array($placeholders) && count($placeholders) > 0) { - if (empty($this->view->cacheStack)) { - // outermost cache: replace placeholder with dynamic content - $content = $this->updateDynamicContent($content, $placeholders); - } - foreach ($placeholders as $name => $statements) { - $this->view->addDynamicPlaceholder($name, $statements); - } - } - $this->_content = $content; - } - } - } - return $this->_content; - } - - protected function updateDynamicContent($content, $placeholders) - { - foreach ($placeholders as $name => $statements) { - $placeholders[$name] = $this->view->evaluateDynamicContent($statements); - } - return strtr($content, $placeholders); - } - - /** - * Generates a unique key used for storing the content in cache. - * The key generated depends on both [[id]] and [[variations]]. - * @return mixed a valid cache key - */ - protected function calculateKey() - { - $factors = array(__CLASS__, $this->getId()); - if (is_array($this->variations)) { - foreach ($this->variations as $factor) { - $factors[] = $factor; - } - } - return $factors; - } -} + + * @since 2.0 + */ +class FragmentCache extends Widget +{ + /** + * @var Cache|string the cache object or the application component ID of the cache object. + * After the FragmentCache object is created, if you want to change this property, + * you should only assign it with a cache object. + */ + public $cache = 'cache'; + /** + * @var integer number of seconds that the data can remain valid in cache. + * Use 0 to indicate that the cached data will never expire. + */ + public $duration = 60; + /** + * @var array|Dependency the dependency that the cached content depends on. + * This can be either a [[Dependency]] object or a configuration array for creating the dependency object. + * For example, + * + * ~~~ + * array( + * 'class' => 'yii\caching\DbDependency', + * 'sql' => 'SELECT MAX(lastModified) FROM Post', + * ) + * ~~~ + * + * would make the output cache depends on the last modified time of all posts. + * If any post has its modification time changed, the cached content would be invalidated. + */ + public $dependency; + /** + * @var array list of factors that would cause the variation of the content being cached. + * Each factor is a string representing a variation (e.g. the language, a GET parameter). + * The following variation setting will cause the content to be cached in different versions + * according to the current application language: + * + * ~~~ + * array( + * Yii::$app->language, + * ) + */ + public $variations; + /** + * @var boolean whether to enable the fragment cache. You may use this property to turn on and off + * the fragment cache according to specific setting (e.g. enable fragment cache only for GET requests). + */ + public $enabled = true; + /** + * @var array a list of placeholders for embedding dynamic contents. This property + * is used internally to implement the content caching feature. Do not modify it. + */ + public $dynamicPlaceholders; + + /** + * Initializes the FragmentCache object. + */ + public function init() + { + parent::init(); + + if (!$this->enabled) { + $this->cache = null; + } elseif (is_string($this->cache)) { + $this->cache = Yii::$app->getComponent($this->cache); + } + + if ($this->getCachedContent() === false) { + $this->view->cacheStack[] = $this; + ob_start(); + ob_implicit_flush(false); + } + } + + /** + * Marks the end of content to be cached. + * Content displayed before this method call and after {@link init()} + * will be captured and saved in cache. + * This method does nothing if valid content is already found in cache. + */ + public function run() + { + if (($content = $this->getCachedContent()) !== false) { + echo $content; + } elseif ($this->cache instanceof Cache) { + $content = ob_get_clean(); + array_pop($this->view->cacheStack); + if (is_array($this->dependency)) { + $this->dependency = Yii::createObject($this->dependency); + } + $data = array($content, $this->dynamicPlaceholders); + $this->cache->set($this->calculateKey(), $data, $this->duration, $this->dependency); + + if (empty($this->view->cacheStack) && !empty($this->dynamicPlaceholders)) { + $content = $this->updateDynamicContent($content, $this->dynamicPlaceholders); + } + echo $content; + } + } + + /** + * @var string|boolean the cached content. False if the content is not cached. + */ + private $_content; + + /** + * Returns the cached content if available. + * @return string|boolean the cached content. False is returned if valid content is not found in the cache. + */ + public function getCachedContent() + { + if ($this->_content === null) { + $this->_content = false; + if ($this->cache instanceof Cache) { + $key = $this->calculateKey(); + $data = $this->cache->get($key); + if (is_array($data) && count($data) === 2) { + list ($content, $placeholders) = $data; + if (is_array($placeholders) && count($placeholders) > 0) { + if (empty($this->view->cacheStack)) { + // outermost cache: replace placeholder with dynamic content + $content = $this->updateDynamicContent($content, $placeholders); + } + foreach ($placeholders as $name => $statements) { + $this->view->addDynamicPlaceholder($name, $statements); + } + } + $this->_content = $content; + } + } + } + return $this->_content; + } + + protected function updateDynamicContent($content, $placeholders) + { + foreach ($placeholders as $name => $statements) { + $placeholders[$name] = $this->view->evaluateDynamicContent($statements); + } + return strtr($content, $placeholders); + } + + /** + * Generates a unique key used for storing the content in cache. + * The key generated depends on both [[id]] and [[variations]]. + * @return mixed a valid cache key + */ + protected function calculateKey() + { + $factors = array(__CLASS__, $this->getId()); + if (is_array($this->variations)) { + foreach ($this->variations as $factor) { + $factors[] = $factor; + } + } + return $factors; + } +} diff --git a/framework/yii/widgets/ListPager.php b/framework/yii/widgets/ListPager.php index 699126d..30371d3 100644 --- a/framework/yii/widgets/ListPager.php +++ b/framework/yii/widgets/ListPager.php @@ -91,5 +91,4 @@ class ListPager extends Widget '{page}' => $page + 1, )); } - }