Commit f4ebd91c by Carsten Brandt

Merge branch 'master' into redis

* master: (117 commits) More Model tests Better validation rules validity check Some tests for Model A bit more friendly behavior for unsetting a model attribute User WIP. Fixed Model::getFirstErrors() Finished AccessControl. Finished HttpCache. User WIP line ending fix. refactoring cache and db references. Fixed session bug. Finishes flash feature. refactored url creation shortcut method. HttpCache WIP. Finished AccessControl and HttpCache. Finished PageCache. finished fragment caching. fragment cache WIP bug fixes. ...
parents 0d2f5028 99238886
......@@ -300,7 +300,7 @@ foreach ($customers as $customer) {
~~~
How many SQL queries will be performed in the above code, assuming there are more than 100 customers in
the database? 101! The first SQL query brings back 100 customers. Then for each customer, another SQL query
the database? 101! The first SQL query brings back 100 customers. Then for each customer, a SQL query
is performed to bring back the customer's orders.
To solve the above performance problem, you can use the so-called *eager loading* by calling [[ActiveQuery::with()]]:
......@@ -318,7 +318,7 @@ foreach ($customers as $customer) {
}
~~~
As you can see, only two SQL queries were needed for the same task.
As you can see, only two SQL queries are needed for the same task.
Sometimes, you may want to customize the relational queries on the fly. It can be
......
Yii2 class loader
=================
Yii 2 class loader is PSR-0 compliant. That means it can handle most of the PHP
libraries and frameworks out there.
In order to autoload a library you need to set a root alias for it.
PEAR-style libraries
--------------------
```php
\Yii::setAlias('@Twig', '@app/vendors/Twig');
```
References
----------
- YiiBase::autoload
\ No newline at end of file
......@@ -204,7 +204,7 @@ doIt('a', array(
~~~
if ($event === null) {
return new Event($this);
return new Event();
} elseif ($event instanceof CoolEvent) {
return $event->instance();
} else {
......@@ -251,10 +251,8 @@ switch ($this->phpType) {
~~~
<?php
/**
* Component class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
~~~
......
<?php
/**
* YiiBase class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
use yii\base\Exception;
use yii\base\InvalidConfigException;
use yii\base\InvalidParamException;
use yii\logging\Logger;
/**
......@@ -63,9 +61,9 @@ class YiiBase
*/
public static $classPath = array();
/**
* @var yii\base\Application the application instance
* @var yii\console\Application|yii\web\Application the application instance
*/
public static $application;
public static $app;
/**
* @var array registered path aliases
* @see getAlias
......@@ -96,7 +94,7 @@ class YiiBase
*/
public static $objectConfig = array();
private static $_imported = array(); // alias => class name or directory
private static $_imported = array(); // alias => class name or directory
private static $_logger;
/**
......@@ -125,8 +123,8 @@ class YiiBase
*
* To import a class or a directory, one can use either path alias or class name (can be namespaced):
*
* - `@application/components/GoogleMap`: importing the `GoogleMap` class with a path alias;
* - `@application/components/*`: importing the whole `components` directory with a path alias;
* - `@app/components/GoogleMap`: importing the `GoogleMap` class with a path alias;
* - `@app/components/*`: importing the whole `components` directory with a path alias;
* - `GoogleMap`: importing the `GoogleMap` class with a class name. [[autoload()]] will be used
* when this class is used for the first time.
*
......@@ -161,9 +159,7 @@ class YiiBase
return self::$_imported[$alias] = $className;
}
if (($path = static::getAlias(dirname($alias))) === false) {
throw new Exception('Invalid path alias: ' . $alias);
}
$path = static::getAlias(dirname($alias));
if ($isClass) {
if ($forceInclude) {
......@@ -193,24 +189,30 @@ class YiiBase
*
* Note, this method does not ensure the existence of the resulting path.
* @param string $alias alias
* @param boolean $throwException whether to throw an exception if the given alias is invalid.
* If this is false and an invalid alias is given, false will be returned by this method.
* @return string|boolean path corresponding to the alias, false if the root alias is not previously registered.
* @see setAlias
*/
public static function getAlias($alias)
public static function getAlias($alias, $throwException = true)
{
if (!is_string($alias)) {
return false;
} elseif (isset(self::$aliases[$alias])) {
return self::$aliases[$alias];
} elseif ($alias === '' || $alias[0] !== '@') { // not an alias
return $alias;
} elseif (($pos = strpos($alias, '/')) !== false) {
$rootAlias = substr($alias, 0, $pos);
if (isset(self::$aliases[$rootAlias])) {
return self::$aliases[$alias] = self::$aliases[$rootAlias] . substr($alias, $pos);
if (is_string($alias)) {
if (isset(self::$aliases[$alias])) {
return self::$aliases[$alias];
} elseif ($alias === '' || $alias[0] !== '@') { // not an alias
return $alias;
} elseif (($pos = strpos($alias, '/')) !== false || ($pos = strpos($alias, '\\')) !== false) {
$rootAlias = substr($alias, 0, $pos);
if (isset(self::$aliases[$rootAlias])) {
return self::$aliases[$alias] = self::$aliases[$rootAlias] . substr($alias, $pos);
}
}
}
return false;
if ($throwException) {
throw new InvalidParamException("Invalid path alias: $alias");
} else {
return false;
}
}
/**
......@@ -238,10 +240,8 @@ class YiiBase
unset(self::$aliases[$alias]);
} elseif ($path[0] !== '@') {
self::$aliases[$alias] = rtrim($path, '\\/');
} elseif (($p = static::getAlias($path)) !== false) {
self::$aliases[$alias] = $p;
} else {
throw new Exception('Invalid path: ' . $path);
self::$aliases[$alias] = static::getAlias($path);
}
}
......@@ -262,6 +262,7 @@ class YiiBase
*
* @param string $className class name
* @return boolean whether the class has been loaded successfully
* @throws Exception if the class file does not exist
*/
public static function autoload($className)
{
......@@ -274,14 +275,14 @@ class YiiBase
// namespaced class, e.g. yii\base\Component
// convert namespace to path alias, e.g. yii\base\Component to @yii/base/Component
$alias = '@' . str_replace('\\', '/', ltrim($className, '\\'));
if (($path = static::getAlias($alias)) !== false) {
if (($path = static::getAlias($alias, false)) !== false) {
$classFile = $path . '.php';
}
} elseif (($pos = strpos($className, '_')) !== false) {
// PEAR-styled class, e.g. PHPUnit_Framework_TestCase
// convert class name to path alias, e.g. PHPUnit_Framework_TestCase to @PHPUnit/Framework/TestCase
$alias = '@' . str_replace('_', '/', $className);
if (($path = static::getAlias($alias)) !== false) {
if (($path = static::getAlias($alias, false)) !== false) {
$classFile = $path . '.php';
}
}
......@@ -297,7 +298,7 @@ class YiiBase
}
}
if (isset($classFile, $alias)) {
if (isset($classFile, $alias) && is_file($classFile)) {
if (!YII_DEBUG || basename(realpath($classFile)) === basename($alias) . '.php') {
include($classFile);
return true;
......@@ -322,12 +323,12 @@ class YiiBase
* the class. For example,
*
* - `\app\components\GoogleMap`: fully-qualified namespaced class.
* - `@application/components/GoogleMap`: an alias
* - `@app/components/GoogleMap`: an alias
*
* Below are some usage examples:
*
* ~~~
* $object = \Yii::createObject('@application/components/GoogleMap');
* $object = \Yii::createObject('@app/components/GoogleMap');
* $object = \Yii::createObject(array(
* 'class' => '\app\components\GoogleMap',
* 'apiKey' => 'xyz',
......@@ -507,9 +508,6 @@ class YiiBase
* i.e., the message returned will be chosen from a few candidates according to the given
* number value. This feature is mainly used to solve plural format issue in case
* a message has different plural forms in some languages.
* @param string $category message category. Please use only word letters. Note, category 'yii' is
* reserved for Yii framework core code use. See {@link CPhpMessageSource} for
* more interpretation about message category.
* @param string $message the original message
* @param array $params parameters to be applied to the message using <code>strtr</code>.
* The first parameter can be a number without key.
......@@ -517,62 +515,12 @@ class YiiBase
* an appropriate message translation.
* You can pass parameter for {@link CChoiceFormat::format}
* or plural forms format without wrapping it with array.
* @param string $source which message source application component to use.
* Defaults to null, meaning using 'coreMessages' for messages belonging to
* the 'yii' category and using 'messages' for the rest messages.
* @param string $language the target language. If null (default), the {@link CApplication::getLanguage application language} will be used.
* @return string the translated message
* @see CMessageSource
*/
public static function t($category, $message, $params = array(), $source = null, $language = null)
public static function t($message, $params = array(), $language = null)
{
// todo;
return $params !== array() ? strtr($message, $params) : $message;
if (self::$application !== null)
{
if ($source === null)
{
$source = $category === 'yii' ? 'coreMessages' : 'messages';
}
if (($source = self::$application->getComponent($source)) !== null)
{
$message = $source->translate($category, $message, $language);
}
}
if ($params === array())
{
return $message;
}
if (!is_array($params))
{
$params = array($params);
}
if (isset($params[0])) // number choice
{
if (strpos($message, '|') !== false)
{
if (strpos($message, '#') === false)
{
$chunks = explode('|', $message);
$expressions = self::$application->getLocale($language)->getPluralRules();
if ($n = min(count($chunks), count($expressions)))
{
for ($i = 0; $i < $n; $i++)
{
$chunks[$i] = $expressions[$i] . '#' . $chunks[$i];
}
$message = implode('|', $chunks);
}
}
$message = CChoiceFormat::format($message, $params[0]);
}
if (!isset($params['{n}']))
{
$params['{n}'] = $params[0];
}
unset($params[0]);
}
return $params !== array() ? strtr($message, $params) : $message;
return Yii::$app->getI18N()->translate($message, $params, $language);
}
}
<?php
/**
* Action class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -56,6 +54,15 @@ class Action extends Component
}
/**
* Returns the unique ID of this action among the whole application.
* @return string the unique ID of this action among the whole application.
*/
public function getUniqueId()
{
return $this->controller->getUniqueId() . '/' . $this->id;
}
/**
* Runs this action with the specified parameters.
* This method is mainly invoked by the controller.
* @param array $params the parameters to be bound to the action's run() method.
......@@ -67,36 +74,7 @@ class Action extends Component
if (!method_exists($this, 'run')) {
throw new InvalidConfigException(get_class($this) . ' must define a "run()" method.');
}
$method = new \ReflectionMethod($this, 'run');
$args = $this->bindActionParams($method, $params);
return (int)$method->invokeArgs($this, $args);
}
/**
* Binds the given parameters to the action method.
* The returned array contains the parameters that need to be passed to the action method.
* This method calls [[Controller::validateActionParams()]] to check if any exception
* should be raised if there are missing or unknown parameters.
* @param \ReflectionMethod $method the action method reflection object
* @param array $params the supplied parameters
* @return array the parameters that can be passed to the action method
*/
protected function bindActionParams($method, $params)
{
$args = array();
$missing = array();
foreach ($method->getParameters() as $param) {
$name = $param->getName();
if (array_key_exists($name, $params)) {
$args[] = $params[$name];
unset($params[$name]);
} elseif ($param->isDefaultValueAvailable()) {
$args[] = $param->getDefaultValue();
} else {
$missing[] = $name;
}
}
$this->controller->validateActionParams($this, $missing, $params);
return $args;
$args = $this->controller->bindActionParams($this, $params);
return (int)call_user_func_array(array($this, 'run'), $args);
}
}
<?php
/**
* ActionEvent class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
/**
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class ActionFilter extends Behavior
{
/**
* @var array list of action IDs that this filter should apply to. If this property is not set,
* then the filter applies to all actions, unless they are listed in [[except]].
*/
public $only;
/**
* @var array list of action IDs that this filter should not apply to.
*/
public $except = array();
/**
* Declares event handlers for the [[owner]]'s events.
* @return array events (array keys) and the corresponding event handler methods (array values).
*/
public function events()
{
return array(
'beforeAction' => 'beforeFilter',
'afterAction' => 'afterFilter',
);
}
/**
* @param ActionEvent $event
* @return boolean
*/
public function beforeFilter($event)
{
if ($this->isActive($event->action)) {
$event->isValid = $this->beforeAction($event->action);
}
return $event->isValid;
}
/**
* @param ActionEvent $event
* @return boolean
*/
public function afterFilter($event)
{
if ($this->isActive($event->action)) {
$this->afterAction($event->action);
}
}
/**
* 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)
{
return true;
}
/**
* This method is invoked right after an action is executed.
* You may override this method to do some postprocessing for the action.
* @param Action $action the action just executed.
*/
public function afterAction($action)
{
}
/**
* Returns a value indicating whether the filer is active for the given action.
* @param Action $action the action being filtered
* @return boolean whether the filer is active for the given action.
*/
protected function isActive($action)
{
return !in_array($action->id, $this->except, true) && (empty($this->only) || in_array($action->id, $this->only, true));
}
}
\ No newline at end of file
<?php
/**
* Behavior class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* Component class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -60,7 +58,7 @@ class Component extends \yii\base\Object
}
}
}
throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '.' . $name);
throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '::' . $name);
}
/**
......@@ -107,9 +105,9 @@ class Component extends \yii\base\Object
}
}
if (method_exists($this, 'get' . $name)) {
throw new InvalidCallException('Setting read-only property: ' . get_class($this) . '.' . $name);
throw new InvalidCallException('Setting read-only property: ' . get_class($this) . '::' . $name);
} else {
throw new UnknownPropertyException('Setting unknown property: ' . get_class($this) . '.' . $name);
throw new UnknownPropertyException('Setting unknown property: ' . get_class($this) . '::' . $name);
}
}
......@@ -424,7 +422,10 @@ class Component extends \yii\base\Object
$this->ensureBehaviors();
if (isset($this->_e[$name]) && $this->_e[$name]->getCount()) {
if ($event === null) {
$event = new Event($this);
$event = new Event;
}
if ($event->sender === null) {
$event->sender = $this;
}
$event->handled = false;
$event->name = $name;
......
<?php
/**
* Controller class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
use Yii;
use yii\util\StringHelper;
use yii\helpers\FileHelper;
use yii\helpers\StringHelper;
/**
* Controller is the base class for classes containing controller logic.
*
* @property string $route the route (module ID, controller ID and action ID) of the current request.
* @property string $uniqueId the controller ID that is prefixed with the module ID (if any).
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
......@@ -72,9 +68,9 @@ class Controller extends Component
*
* ~~~
* return array(
* 'action1' => '@application/components/Action1',
* 'action1' => '@app/components/Action1',
* 'action2' => array(
* 'class' => '@application/components/Action2',
* 'class' => '@app/components/Action2',
* 'property1' => 'value1',
* 'property2' => 'value2',
* ),
......@@ -139,8 +135,50 @@ class Controller extends Component
} elseif ($pos > 0) {
return $this->module->runAction($route, $params);
} else {
return \Yii::$application->runAction(ltrim($route, '/'), $params);
return \Yii::$app->runAction(ltrim($route, '/'), $params);
}
}
/**
* Binds the parameters to the action.
* This method is invoked by [[Action]] when it begins to run with the given parameters.
* This method will check the parameter names that the action requires and return
* the provided parameters according to the requirement. If there is any missing parameter,
* an exception will be thrown.
* @param Action $action the action to be bound with parameters
* @param array $params the parameters to be bound to the action
* @return array the valid parameters that the action can run with.
* @throws InvalidRequestException if there are missing parameters.
*/
public function bindActionParams($action, $params)
{
if ($action instanceof InlineAction) {
$method = new \ReflectionMethod($this, $action->actionMethod);
} else {
$method = new \ReflectionMethod($action, 'run');
}
$args = array();
$missing = array();
foreach ($method->getParameters() as $param) {
$name = $param->getName();
if (array_key_exists($name, $params)) {
$args[] = $params[$name];
unset($params[$name]);
} elseif ($param->isDefaultValueAvailable()) {
$args[] = $param->getDefaultValue();
} else {
$missing[] = $name;
}
}
if ($missing !== array()) {
throw new InvalidRequestException(Yii::t('yii|Missing required parameters: {params}', array(
'{params}' => implode(', ', $missing),
)));
}
return $args;
}
/**
......@@ -250,34 +288,51 @@ class Controller extends Component
*/
public function getRoute()
{
return $this->action !== null ? $this->getUniqueId() . '/' . $this->action->id : $this->getUniqueId();
return $this->action !== null ? $this->action->getUniqueId() : $this->getUniqueId();
}
/**
* Renders a view and applies layout if available.
*
* @param $view
* @param array $params
* @return string
* @param string $view the view name. Please refer to [[findViewFile()]] on how to specify a view name.
* @param array $params the parameters (name-value pairs) that should be made available in the view.
* These parameters will not be available in the layout.
* @return string the rendering result.
* @throws InvalidParamException if the view file or the layout file does not exist.
*/
public function render($view, $params = array())
{
return $this->createView()->render($view, $params);
}
public function renderContent($content)
{
return $this->createView()->renderContent($content);
$output = Yii::$app->getView()->render($view, $params, $this);
$layoutFile = $this->findLayoutFile();
if ($layoutFile !== false) {
return Yii::$app->getView()->renderFile($layoutFile, array('content' => $output), $this);
} else {
return $output;
}
}
/**
* Renders a view.
* This method differs from [[render()]] in that it does not apply any layout.
* @param string $view the view name. Please refer to [[findViewFile()]] on how to specify a view name.
* @param array $params the parameters (name-value pairs) that should be made available in the view.
* @return string the rendering result.
* @throws InvalidParamException if the view file does not exist.
*/
public function renderPartial($view, $params = array())
{
return $this->createView()->renderPartial($view, $params);
return Yii::$app->getView()->render($view, $params, $this);
}
public function createView()
/**
* Renders a view file.
* @param string $file the view file to be rendered. This can be either a file path or a path alias.
* @param array $params the parameters (name-value pairs) that should be made available in the view.
* @return string the rendering result.
* @throws InvalidParamException if the view file does not exist.
*/
public function renderFile($file, $params = array())
{
return new View($this);
return Yii::$app->getView()->renderFile($file, $params, $this);
}
/**
......@@ -290,4 +345,63 @@ class Controller extends Component
{
return $this->module->getViewPath() . DIRECTORY_SEPARATOR . $this->id;
}
/**
* Finds the applicable layout file.
*
* This method locates an applicable layout file via two steps.
*
* In the first step, it determines the layout name and the context module:
*
* - If [[layout]] is specified as a string, use it as the layout name and [[module]] as the context module;
* - If [[layout]] is null, search through all ancestor modules of this controller and find the first
* module whose [[Module::layout|layout]] is not null. The layout and the corresponding module
* are used as the layout name and the context module, respectively. If such a module is not found
* or the corresponding layout is not a string, it will return false, meaning no applicable layout.
*
* In the second step, it determines the actual layout file according to the previously found layout name
* and context module. The layout name can be
*
* - a path alias (e.g. "@app/views/layouts/main");
* - an absolute path (e.g. "/main"): the layout name starts with a slash. The actual layout file will be
* looked for under the [[Application::layoutPath|layout path]] of the application;
* - a relative path (e.g. "main"): the actual layout layout file will be looked for under the
* [[Module::viewPath|view path]] of the context module.
*
* If the layout name does not contain a file extension, it will use the default one `.php`.
*
* @return string|boolean the layout file path, or false if layout is not needed.
* @throws InvalidParamException if an invalid path alias is used to specify the layout
*/
protected function findLayoutFile()
{
$module = $this->module;
if (is_string($this->layout)) {
$view = $this->layout;
} elseif ($this->layout === null) {
while ($module !== null && $module->layout === null) {
$module = $module->module;
}
if ($module !== null && is_string($module->layout)) {
$view = $module->layout;
}
}
if (!isset($view)) {
return false;
}
if (strncmp($view, '@', 1) === 0) {
$file = Yii::getAlias($view);
} elseif (strncmp($view, '/', 1) === 0) {
$file = Yii::$app->getLayoutPath() . DIRECTORY_SEPARATOR . $view;
} else {
$file = $module->getLayoutPath() . DIRECTORY_SEPARATOR . $view;
}
if (FileHelper::getExtension($file) === '') {
$file .= '.php';
}
return $file;
}
}
<?php
/**
* Dictionary class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
use yii\util\ArrayHelper;
use yii\helpers\ArrayHelper;
/**
* Dictionary implements a collection that stores key-value pairs.
......@@ -150,7 +148,7 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co
* Defaults to false, meaning all items in the dictionary will be cleared directly
* without calling [[remove]].
*/
public function clear($safeClear = false)
public function removeAll($safeClear = false)
{
if ($safeClear) {
foreach (array_keys($this->_d) as $key) {
......@@ -166,7 +164,7 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co
* @param mixed $key the key
* @return boolean whether the dictionary contains an item with the specified key
*/
public function contains($key)
public function has($key)
{
return isset($this->_d[$key]) || array_key_exists($key, $this->_d);
}
......@@ -184,13 +182,13 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co
* Copies iterable data into the dictionary.
* Note, existing data in the dictionary will be cleared first.
* @param mixed $data the data to be copied from, must be an array or an object implementing `Traversable`
* @throws InvalidCallException if data is neither an array nor an iterator.
* @throws InvalidParamException if data is neither an array nor an iterator.
*/
public function copyFrom($data)
{
if (is_array($data) || $data instanceof \Traversable) {
if ($this->_d !== array()) {
$this->clear();
$this->removeAll();
}
if ($data instanceof self) {
$data = $data->_d;
......@@ -199,7 +197,7 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co
$this->add($key, $value);
}
} else {
throw new InvalidCallException('Data must be either an array or an object implementing Traversable.');
throw new InvalidParamException('Data must be either an array or an object implementing Traversable.');
}
}
......@@ -216,7 +214,7 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co
*
* @param array|\Traversable $data the data to be merged with. It must be an array or object implementing Traversable
* @param boolean $recursive whether the merging should be recursive.
* @throws InvalidCallException if data is neither an array nor an object implementing `Traversable`.
* @throws InvalidParamException if data is neither an array nor an object implementing `Traversable`.
*/
public function mergeWith($data, $recursive = true)
{
......@@ -240,7 +238,7 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co
}
}
} else {
throw new InvalidCallException('The data to be merged with must be an array or an object implementing Traversable.');
throw new InvalidParamException('The data to be merged with must be an array or an object implementing Traversable.');
}
}
......@@ -254,7 +252,7 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co
*/
public function offsetExists($offset)
{
return $this->contains($offset);
return $this->has($offset);
}
/**
......
<?php
/**
* DictionaryIterator class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
/**
* ErrorException represents a PHP error.
*
* @author Alexander Makarov <sam@rmcreative.ru>
* @since 2.0
*/
class ErrorException extends Exception
{
protected $severity;
/**
* Constructs the exception
* @link http://php.net/manual/en/errorexception.construct.php
* @param $message [optional]
* @param $code [optional]
* @param $severity [optional]
* @param $filename [optional]
* @param $lineno [optional]
* @param $previous [optional]
*/
public function __construct($message = '', $code = 0, $severity = 1, $filename = __FILE__, $lineno = __LINE__, \Exception $previous = null)
{
parent::__construct($message, $code, $previous);
$this->severity = $severity;
$this->file = $filename;
$this->line = $lineno;
}
/**
* Gets the exception severity
* @link http://php.net/manual/en/errorexception.getseverity.php
* @return int the severity level of the exception.
*/
final public function getSeverity()
{
return $this->severity;
}
/**
* Returns if error is one of fatal type
*
* @param array $error error got from error_get_last()
* @return bool if error is one of fatal type
*/
public static function isFatalErorr($error)
{
return isset($error['type']) && in_array($error['type'], array(E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING));
}
/**
* @return string the user-friendly name of this exception
*/
public function getName()
{
$names = array(
E_ERROR => \Yii::t('yii|Fatal Error'),
E_PARSE => \Yii::t('yii|Parse Error'),
E_CORE_ERROR => \Yii::t('yii|Core Error'),
E_COMPILE_ERROR => \Yii::t('yii|Compile Error'),
E_USER_ERROR => \Yii::t('yii|User Error'),
E_WARNING => \Yii::t('yii|Warning'),
E_CORE_WARNING => \Yii::t('yii|Core Warning'),
E_COMPILE_WARNING => \Yii::t('yii|Compile Warning'),
E_USER_WARNING => \Yii::t('yii|User Warning'),
E_STRICT => \Yii::t('yii|Strict'),
E_NOTICE => \Yii::t('yii|Notice'),
E_RECOVERABLE_ERROR => \Yii::t('yii|Recoverable Error'),
E_DEPRECATED => \Yii::t('yii|Deprecated'),
);
return isset($names[$this->getCode()]) ? $names[$this->getCode()] : \Yii::t('yii|Error');
}
}
<?php
/**
* ErrorHandler class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -18,7 +16,7 @@ namespace yii\base;
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
use yii\util\VarDumper;
use yii\helpers\VarDumper;
class ErrorHandler extends Component
{
......@@ -36,7 +34,7 @@ class ErrorHandler extends Component
public $discardExistingOutput = true;
/**
* @var string the route (eg 'site/error') to the controller action that will be used to display external errors.
* Inside the action, it can retrieve the error information by \Yii::$application->errorHandler->error.
* Inside the action, it can retrieve the error information by \Yii::$app->errorHandler->error.
* This property defaults to null, meaning ErrorHandler will handle the error display.
*/
public $errorAction;
......@@ -71,27 +69,27 @@ class ErrorHandler extends Component
protected function render($exception)
{
if ($this->errorAction !== null) {
\Yii::$application->runAction($this->errorAction);
} elseif (\Yii::$application instanceof \yii\web\Application) {
\Yii::$app->runAction($this->errorAction);
} elseif (\Yii::$app instanceof \yii\web\Application) {
if (!headers_sent()) {
$errorCode = $exception instanceof HttpException ? $exception->statusCode : 500;
header("HTTP/1.0 $errorCode " . get_class($exception));
}
if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest') {
\Yii::$application->renderException($exception);
\Yii::$app->renderException($exception);
} else {
$view = new View($this);
if (!YII_DEBUG || $exception instanceof Exception && $exception->causedByUser) {
$view = new View;
if (!YII_DEBUG || $exception instanceof UserException) {
$viewName = $this->errorView;
} else {
$viewName = $this->exceptionView;
}
echo $view->render($viewName, array(
'exception' => $exception,
));
), $this);
}
} else {
\Yii::$application->renderException($exception);
\Yii::$app->renderException($exception);
}
}
......@@ -239,7 +237,7 @@ class ErrorHandler extends Component
public function htmlEncode($text)
{
return htmlspecialchars($text, ENT_QUOTES, \Yii::$application->charset);
return htmlspecialchars($text, ENT_QUOTES, \Yii::$app->charset);
}
public function clearOutput()
......@@ -255,15 +253,10 @@ class ErrorHandler extends Component
*/
public function renderAsHtml($exception)
{
$view = new View($this);
if (!YII_DEBUG || $exception instanceof Exception && $exception->causedByUser) {
$viewName = $this->errorView;
} else {
$viewName = $this->exceptionView;
}
$view = new View;
$name = !YII_DEBUG || $exception instanceof HttpException ? $this->errorView : $this->exceptionView;
echo $view->render($name, array(
'exception' => $exception,
));
), $this);
}
}
<?php
/**
* Event class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -30,7 +28,8 @@ class Event extends \yii\base\Object
*/
public $name;
/**
* @var object the sender of this event
* @var object the sender of this event. If not set, this property will be
* set as the object whose "trigger()" method is called.
*/
public $sender;
/**
......@@ -40,21 +39,7 @@ class Event extends \yii\base\Object
*/
public $handled = false;
/**
* @var mixed extra data associated with the event.
* @var mixed extra custom data associated with the event.
*/
public $data;
/**
* Constructor.
*
* @param mixed $sender sender of the event
* @param mixed $data extra data associated with the event
* @param array $config name-value pairs that will be used to initialize the object properties
*/
public function __construct($sender = null, $data = null, $config = array())
{
$this->sender = $sender;
$this->data = $data;
parent::__construct($config);
}
}
<?php
/**
* Exception class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -18,16 +16,10 @@ namespace yii\base;
class Exception extends \Exception
{
/**
* @var boolean whether this exception is caused by end user's mistake (e.g. wrong URL)
*/
public $causedByUser = false;
/**
* @return string the user-friendly name of this exception
*/
public function getName()
{
return \Yii::t('yii', 'Exception');
return \Yii::t('yii|Exception');
}
}
}
\ No newline at end of file
<?php
/**
* HttpException class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -19,16 +17,12 @@ namespace yii\base;
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class HttpException extends Exception
class HttpException extends UserException
{
/**
* @var integer HTTP status code, such as 403, 404, 500, etc.
*/
public $statusCode;
/**
* @var boolean whether this exception is caused by end user's mistake (e.g. wrong URL)
*/
public $causedByUser = true;
/**
* Constructor.
......@@ -41,4 +35,73 @@ class HttpException extends Exception
$this->statusCode = $status;
parent::__construct($message, $code);
}
/**
* @return string the user-friendly name of this exception
*/
public function getName()
{
static $httpCodes = array(
100 => 'Continue',
101 => 'Switching Protocols',
102 => 'Processing',
118 => 'Connection timed out',
200 => 'OK',
201 => 'Created',
202 => 'Accepted',
203 => 'Non-Authoritative',
204 => 'No Content',
205 => 'Reset Content',
206 => 'Partial Content',
207 => 'Multi-Status',
210 => 'Content Different',
300 => 'Multiple Choices',
301 => 'Moved Permanently',
302 => 'Found',
303 => 'See Other',
304 => 'Not Modified',
305 => 'Use Proxy',
307 => 'Temporary Redirect',
310 => 'Too many Redirect',
400 => 'Bad Request',
401 => 'Unauthorized',
402 => 'Payment Required',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
406 => 'Not Acceptable',
407 => 'Proxy Authentication Required',
408 => 'Request Time-out',
409 => 'Conflict',
410 => 'Gone',
411 => 'Length Required',
412 => 'Precondition Failed',
413 => 'Request Entity Too Large',
414 => 'Request-URI Too Long',
415 => 'Unsupported Media Type',
416 => 'Requested range unsatisfiable',
417 => 'Expectation failed',
418 => 'I’m a teapot',
422 => 'Unprocessable entity',
423 => 'Locked',
424 => 'Method failure',
425 => 'Unordered Collection',
426 => 'Upgrade Required',
449 => 'Retry With',
450 => 'Blocked by Windows Parental Controls',
500 => 'Internal Server Error',
501 => 'Not Implemented',
502 => 'Bad Gateway ou Proxy Error',
503 => 'Service Unavailable',
504 => 'Gateway Time-out',
505 => 'HTTP Version not supported',
507 => 'Insufficient storage',
509 => 'Bandwidth Limit Exceeded',
);
if(isset($httpCodes[$this->statusCode]))
return $httpCodes[$this->statusCode];
else
return \Yii::t('yii|Error');
}
}
<?php
/**
* InlineAction class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -45,8 +43,7 @@ class InlineAction extends Action
*/
public function runWithParams($params)
{
$method = new \ReflectionMethod($this->controller, $this->actionMethod);
$args = $this->bindActionParams($method, $params);
return (int)$method->invokeArgs($this->controller, $args);
$args = $this->controller->bindActionParams($this, $params);
return (int)call_user_func_array(array($this->controller, $this->actionMethod), $args);
}
}
<?php
/**
* InvalidCallException class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -15,14 +13,14 @@ namespace yii\base;
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class InvalidCallException extends \Exception
class InvalidCallException extends Exception
{
/**
* @return string the user-friendly name of this exception
*/
public function getName()
{
return \Yii::t('yii', 'Invalid Call');
return \Yii::t('yii|Invalid Call');
}
}
<?php
/**
* InvalidConfigException class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -15,14 +13,14 @@ namespace yii\base;
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class InvalidConfigException extends \Exception
class InvalidConfigException extends Exception
{
/**
* @return string the user-friendly name of this exception
*/
public function getName()
{
return \Yii::t('yii', 'Invalid Configuration');
return \Yii::t('yii|Invalid Configuration');
}
}
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
/**
* InvalidParamException represents an exception caused by invalid parameters passed to a method.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class InvalidParamException extends Exception
{
/**
* @return string the user-friendly name of this exception
*/
public function getName()
{
return \Yii::t('yii|Invalid Parameter');
}
}
<?php
/**
* InvalidRequestException class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -15,19 +13,14 @@ namespace yii\base;
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class InvalidRequestException extends \Exception
class InvalidRequestException extends UserException
{
/**
* @var boolean whether this exception is caused by end user's mistake (e.g. wrong URL)
*/
public $causedByUser = true;
/**
* @return string the user-friendly name of this exception
*/
public function getName()
{
return \Yii::t('yii', 'Invalid Request');
return \Yii::t('yii|Invalid Request');
}
}
<?php
/**
* InvalidRouteException class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -15,19 +13,14 @@ namespace yii\base;
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class InvalidRouteException extends \Exception
class InvalidRouteException extends UserException
{
/**
* @var boolean whether this exception is caused by end user's mistake (e.g. wrong URL)
*/
public $causedByUser = true;
/**
* @return string the user-friendly name of this exception
*/
public function getName()
{
return \Yii::t('yii', 'Invalid Route');
return \Yii::t('yii|Invalid Route');
}
}
<?php
/**
* Model class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
use yii\util\StringHelper;
use yii\helpers\StringHelper;
use yii\validators\Validator;
use yii\validators\RequiredValidator;
......@@ -260,7 +258,7 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess
*/
public function beforeValidate()
{
$event = new ModelEvent($this);
$event = new ModelEvent;
$this->trigger(self::EVENT_BEFORE_VALIDATE, $event);
return $event->isValid;
}
......@@ -331,7 +329,7 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess
foreach ($this->rules() as $rule) {
if ($rule instanceof Validator) {
$validators->add($rule);
} elseif (isset($rule[0], $rule[1])) { // attributes, validator type
} elseif (is_array($rule) && isset($rule[0], $rule[1])) { // attributes, validator type
$validator = Validator::createValidator($rule[1], $this, $rule[0], array_slice($rule, 2));
$validators->add($validator);
} else {
......@@ -422,12 +420,31 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess
}
/**
* Returns the first error of every attribute in the model.
* @return array the first errors. An empty array will be returned if there is no error.
*/
public function getFirstErrors()
{
if (empty($this->_errors)) {
return array();
} else {
$errors = array();
foreach ($this->_errors as $attributeErrors) {
if (isset($attributeErrors[0])) {
$errors[] = $attributeErrors[0];
}
}
}
return $errors;
}
/**
* Returns the first error of the specified attribute.
* @param string $attribute attribute name.
* @return string the error message. Null is returned if no error.
* @see getErrors
*/
public function getError($attribute)
public function getFirstError($attribute)
{
return isset($this->_errors[$attribute]) ? reset($this->_errors[$attribute]) : null;
}
......@@ -443,25 +460,6 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess
}
/**
* Adds a list of errors.
* @param array $errors a list of errors. The array keys must be attribute names.
* The array values should be error messages. If an attribute has multiple errors,
* these errors must be given in terms of an array.
*/
public function addErrors($errors)
{
foreach ($errors as $attribute => $error) {
if (is_array($error)) {
foreach ($error as $e) {
$this->_errors[$attribute][] = $e;
}
} else {
$this->_errors[$attribute][] = $error;
}
}
}
/**
* Removes errors for all attributes or a single attribute.
* @param string $attribute attribute name. Use null to remove errors for all attribute.
*/
......@@ -543,7 +541,7 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess
public function onUnsafeAttribute($name, $value)
{
if (YII_DEBUG) {
\Yii::warning("Failed to set unsafe attribute '$name' in '" . get_class($this) . "'.");
\Yii::info("Failed to set unsafe attribute '$name' in '" . get_class($this) . "'.", __CLASS__);
}
}
......@@ -658,13 +656,13 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess
}
/**
* Unsets the element at the specified offset.
* Sets the element value at the specified offset to null.
* This method is required by the SPL interface `ArrayAccess`.
* It is implicitly called when you use something like `unset($model[$offset])`.
* @param mixed $offset the offset to unset element
*/
public function offsetUnset($offset)
{
unset($this->$offset);
$this->$offset = null;
}
}
<?php
/**
* ModelEvent class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* NotSupportedException class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -15,14 +13,14 @@ namespace yii\base;
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class NotSupportedException extends \Exception
class NotSupportedException extends Exception
{
/**
* @return string the user-friendly name of this exception
*/
public function getName()
{
return \Yii::t('yii', 'Not Supported');
return \Yii::t('yii|Not Supported');
}
}
<?php
/**
* Object class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -67,7 +65,7 @@ class Object
if (method_exists($this, $getter)) {
return $this->$getter();
} else {
throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '.' . $name);
throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '::' . $name);
}
}
......@@ -88,9 +86,9 @@ class Object
if (method_exists($this, $setter)) {
$this->$setter($value);
} elseif (method_exists($this, 'get' . $name)) {
throw new InvalidCallException('Setting read-only property: ' . get_class($this) . '.' . $name);
throw new InvalidCallException('Setting read-only property: ' . get_class($this) . '::' . $name);
} else {
throw new UnknownPropertyException('Setting unknown property: ' . get_class($this) . '.' . $name);
throw new UnknownPropertyException('Setting unknown property: ' . get_class($this) . '::' . $name);
}
}
......@@ -131,7 +129,7 @@ class Object
if (method_exists($this, $setter)) {
$this->$setter(null);
} elseif (method_exists($this, 'get' . $name)) {
throw new InvalidCallException('Unsetting read-only property: ' . get_class($this) . '.' . $name);
throw new InvalidCallException('Unsetting read-only property: ' . get_class($this) . '::' . $name);
}
}
......
<?php
/**
* Request class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -13,12 +11,18 @@ namespace yii\base;
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Request extends Component
abstract class Request extends Component
{
private $_scriptFile;
private $_isConsoleRequest;
/**
* Resolves the current request into a route and the associated parameters.
* @return array the first element is the route, and the second is the associated parameters.
*/
abstract public function resolve();
/**
* Returns a value indicating whether the current request is made via command line
* @return boolean the value indicating whether the current request is made via console
*/
......@@ -39,24 +43,35 @@ class Request extends Component
/**
* Returns entry script file path.
* @return string entry script file path (processed w/ realpath())
* @throws InvalidConfigException if the entry script file path cannot be determined automatically.
*/
public function getScriptFile()
{
if ($this->_scriptFile === null) {
$this->_scriptFile = realpath($_SERVER['SCRIPT_FILENAME']);
if (isset($_SERVER['SCRIPT_FILENAME'])) {
$this->setScriptFile($_SERVER['SCRIPT_FILENAME']);
} else {
throw new InvalidConfigException('Unable to determine the entry script file path.');
}
}
return $this->_scriptFile;
}
/**
* Sets the entry script file path.
* This can be an absolute or relative file path, or a path alias.
* Note that you normally do not have to set the script file path
* as [[getScriptFile()]] can determine it based on `$_SERVER['SCRIPT_FILENAME']`.
* @param string $value the entry script file
* The entry script file path can normally be determined based on the `SCRIPT_FILENAME` SERVER variable.
* However, for some server configurations, this may not be correct or feasible.
* This setter is provided so that the entry script file path can be manually specified.
* @param string $value the entry script file path. This can be either a file path or a path alias.
* @throws InvalidConfigException if the provided entry script file path is invalid.
*/
public function setScriptFile($value)
{
$this->_scriptFile = realpath(\Yii::getAlias($value));
$scriptFile = realpath(\Yii::getAlias($value));
if ($scriptFile !== false && is_file($scriptFile)) {
$this->_scriptFile = $scriptFile;
} else {
throw new InvalidConfigException('Unable to determine the entry script file path.');
}
}
}
<?php
/**
* Response class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* SecurityManager class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
/**
* SecurityManager provides private keys, hashing and encryption functions.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class SecurityManager extends Component
{
const STATE_VALIDATION_KEY = 'Yii.SecurityManager.validationkey';
const STATE_ENCRYPTION_KEY = 'Yii.SecurityManager.encryptionkey';
/**
* @var string the name of the hashing algorithm to be used by {@link computeHMAC}.
* See {@link http://php.net/manual/en/function.hash-algos.php hash-algos} for the list of possible
* hash algorithms. Note that if you are using PHP 5.1.1 or below, you can only use 'sha1' or 'md5'.
*
* Defaults to 'sha1', meaning using SHA1 hash algorithm.
*/
public $hashAlgorithm = 'sha1';
/**
* @var mixed the name of the crypt algorithm to be used by {@link encrypt} and {@link decrypt}.
* This will be passed as the first parameter to {@link http://php.net/manual/en/function.mcrypt-module-open.php mcrypt_module_open}.
*
* This property can also be configured as an array. In this case, the array elements will be passed in order
* as parameters to mcrypt_module_open. For example, <code>array('rijndael-256', '', 'ofb', '')</code>.
*
* Defaults to 'des', meaning using DES crypt algorithm.
*/
public $cryptAlgorithm = 'des';
private $_validationKey;
private $_encryptionKey;
/**
* @return string a randomly generated private key
*/
protected function generateRandomKey()
{
return sprintf('%08x%08x%08x%08x', mt_rand(), mt_rand(), mt_rand(), mt_rand());
}
/**
* @return string the private key used to generate HMAC.
* If the key is not explicitly set, a random one is generated and returned.
*/
public function getValidationKey()
{
if ($this->_validationKey !== null) {
return $this->_validationKey;
} else {
if (($key = \Yii::$application->getGlobalState(self::STATE_VALIDATION_KEY)) !== null) {
$this->setValidationKey($key);
} else {
$key = $this->generateRandomKey();
$this->setValidationKey($key);
\Yii::$application->setGlobalState(self::STATE_VALIDATION_KEY, $key);
}
return $this->_validationKey;
}
}
/**
* @param string $value the key used to generate HMAC
* @throws CException if the key is empty
*/
public function setValidationKey($value)
{
if (!empty($value)) {
$this->_validationKey = $value;
} else {
throw new CException(Yii::t('yii', 'SecurityManager.validationKey cannot be empty.'));
}
}
/**
* @return string the private key used to encrypt/decrypt data.
* If the key is not explicitly set, a random one is generated and returned.
*/
public function getEncryptionKey()
{
if ($this->_encryptionKey !== null) {
return $this->_encryptionKey;
} else {
if (($key = \Yii::$application->getGlobalState(self::STATE_ENCRYPTION_KEY)) !== null) {
$this->setEncryptionKey($key);
} else {
$key = $this->generateRandomKey();
$this->setEncryptionKey($key);
\Yii::$application->setGlobalState(self::STATE_ENCRYPTION_KEY, $key);
}
return $this->_encryptionKey;
}
}
/**
* @param string $value the key used to encrypt/decrypt data.
* @throws CException if the key is empty
*/
public function setEncryptionKey($value)
{
if (!empty($value)) {
$this->_encryptionKey = $value;
} else {
throw new CException(Yii::t('yii', 'SecurityManager.encryptionKey cannot be empty.'));
}
}
/**
* This method has been deprecated since version 1.1.3.
* Please use {@link hashAlgorithm} instead.
* @return string
*/
public function getValidation()
{
return $this->hashAlgorithm;
}
/**
* This method has been deprecated since version 1.1.3.
* Please use {@link hashAlgorithm} instead.
* @param string $value -
*/
public function setValidation($value)
{
$this->hashAlgorithm = $value;
}
/**
* Encrypts data.
* @param string $data data to be encrypted.
* @param string $key the decryption key. This defaults to null, meaning using {@link getEncryptionKey EncryptionKey}.
* @return string the encrypted data
* @throws CException if PHP Mcrypt extension is not loaded
*/
public function encrypt($data, $key = null)
{
$module = $this->openCryptModule();
$key = $this->substr($key === null ? md5($this->getEncryptionKey()) : $key, 0, mcrypt_enc_get_key_size($module));
srand();
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($module), MCRYPT_RAND);
mcrypt_generic_init($module, $key, $iv);
$encrypted = $iv . mcrypt_generic($module, $data);
mcrypt_generic_deinit($module);
mcrypt_module_close($module);
return $encrypted;
}
/**
* Decrypts data
* @param string $data data to be decrypted.
* @param string $key the decryption key. This defaults to null, meaning using {@link getEncryptionKey EncryptionKey}.
* @return string the decrypted data
* @throws CException if PHP Mcrypt extension is not loaded
*/
public function decrypt($data, $key = null)
{
$module = $this->openCryptModule();
$key = $this->substr($key === null ? md5($this->getEncryptionKey()) : $key, 0, mcrypt_enc_get_key_size($module));
$ivSize = mcrypt_enc_get_iv_size($module);
$iv = $this->substr($data, 0, $ivSize);
mcrypt_generic_init($module, $key, $iv);
$decrypted = mdecrypt_generic($module, $this->substr($data, $ivSize, $this->strlen($data)));
mcrypt_generic_deinit($module);
mcrypt_module_close($module);
return rtrim($decrypted, "\0");
}
/**
* Opens the mcrypt module with the configuration specified in {@link cryptAlgorithm}.
* @return resource the mycrypt module handle.
* @since 1.1.3
*/
protected function openCryptModule()
{
if (extension_loaded('mcrypt')) {
if (is_array($this->cryptAlgorithm)) {
$module = @call_user_func_array('mcrypt_module_open', $this->cryptAlgorithm);
} else {
$module = @mcrypt_module_open($this->cryptAlgorithm, '', MCRYPT_MODE_CBC, '');
}
if ($module === false) {
throw new CException(Yii::t('yii', 'Failed to initialize the mcrypt module.'));
}
return $module;
} else {
throw new CException(Yii::t('yii', 'SecurityManager requires PHP mcrypt extension to be loaded in order to use data encryption feature.'));
}
}
/**
* Prefixes data with an HMAC.
* @param string $data data to be hashed.
* @param string $key the private key to be used for generating HMAC. Defaults to null, meaning using {@link validationKey}.
* @return string data prefixed with HMAC
*/
public function hashData($data, $key = null)
{
return $this->computeHMAC($data, $key) . $data;
}
/**
* Validates if data is tampered.
* @param string $data data to be validated. The data must be previously
* generated using {@link hashData()}.
* @param string $key the private key to be used for generating HMAC. Defaults to null, meaning using {@link validationKey}.
* @return string the real data with HMAC stripped off. False if the data
* is tampered.
*/
public function validateData($data, $key = null)
{
$len = $this->strlen($this->computeHMAC('test'));
if ($this->strlen($data) >= $len) {
$hmac = $this->substr($data, 0, $len);
$data2 = $this->substr($data, $len, $this->strlen($data));
return $hmac === $this->computeHMAC($data2, $key) ? $data2 : false;
} else {
return false;
}
}
/**
* Computes the HMAC for the data with {@link getValidationKey ValidationKey}.
* @param string $data data to be generated HMAC
* @param string $key the private key to be used for generating HMAC. Defaults to null, meaning using {@link validationKey}.
* @return string the HMAC for the data
*/
protected function computeHMAC($data, $key = null)
{
if ($key === null) {
$key = $this->getValidationKey();
}
if (function_exists('hash_hmac')) {
return hash_hmac($this->hashAlgorithm, $data, $key);
}
if (!strcasecmp($this->hashAlgorithm, 'sha1')) {
$pack = 'H40';
$func = 'sha1';
} else {
$pack = 'H32';
$func = 'md5';
}
if ($this->strlen($key) > 64) {
$key = pack($pack, $func($key));
}
if ($this->strlen($key) < 64) {
$key = str_pad($key, 64, chr(0));
}
$key = $this->substr($key, 0, 64);
return $func((str_repeat(chr(0x5C), 64) ^ $key) . pack($pack, $func((str_repeat(chr(0x36), 64) ^ $key) . $data)));
}
/**
* Returns the length of the given string.
* If available uses the multibyte string function mb_strlen.
* @param string $string the string being measured for length
* @return int the length of the string
*/
private function strlen($string)
{
return function_exists('mb_strlen') ? mb_strlen($string, '8bit') : strlen($string);
}
/**
* Returns the portion of string specified by the start and length parameters.
* If available uses the multibyte string function mb_substr
* @param string $string the input string. Must be one character or longer.
* @param int $start the starting position
* @param int $length the desired portion length
* @return string the extracted part of string, or FALSE on failure or an empty string.
*/
private function substr($string, $start, $length)
{
return function_exists('mb_substr') ? mb_substr($string, $start, $length, '8bit') : substr($string, $start, $length);
}
}
<?php
/**
* Theme class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -11,7 +9,7 @@ namespace yii\base;
use Yii;
use yii\base\InvalidConfigException;
use yii\util\FileHelper;
use yii\helpers\FileHelper;
/**
* Theme represents an application theme.
......@@ -42,7 +40,8 @@ class Theme extends Component
/**
* @var array the mapping between view directories and their corresponding themed versions.
* If not set, it will be initialized as a mapping from [[Application::basePath]] to [[basePath]].
* This property is used by [[apply()]] when a view is trying to apply the theme.
* This property is used by [[applyTo()]] when a view is trying to apply the theme.
* Path aliases can be used when specifying directories.
*/
public $pathMap;
......@@ -58,14 +57,16 @@ class Theme extends Component
if (empty($this->pathMap)) {
if ($this->basePath !== null) {
$this->basePath = FileHelper::ensureDirectory($this->basePath);
$this->pathMap = array(Yii::$application->getBasePath() => $this->basePath);
$this->pathMap = array(Yii::$app->getBasePath() => $this->basePath);
} else {
throw new InvalidConfigException("Theme::basePath must be set.");
}
}
$paths = array();
foreach ($this->pathMap as $from => $to) {
$paths[FileHelper::normalizePath($from) . DIRECTORY_SEPARATOR] = FileHelper::normalizePath($to) . DIRECTORY_SEPARATOR;
$from = FileHelper::normalizePath(Yii::getAlias($from));
$to = FileHelper::normalizePath(Yii::getAlias($to));
$paths[$from . DIRECTORY_SEPARATOR] = $to . DIRECTORY_SEPARATOR;
}
$this->pathMap = $paths;
}
......@@ -95,7 +96,7 @@ class Theme extends Component
* @param string $path the file to be themed
* @return string the themed file, or the original file if the themed version is not available.
*/
public function apply($path)
public function applyTo($path)
{
$path = FileHelper::normalizePath($path);
foreach ($this->pathMap as $from => $to) {
......
<?php
/**
* UnknownMethodException class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -15,14 +13,14 @@ namespace yii\base;
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class UnknownMethodException extends \Exception
class UnknownMethodException extends Exception
{
/**
* @return string the user-friendly name of this exception
*/
public function getName()
{
return \Yii::t('yii', 'Unknown Method');
return \Yii::t('yii|Unknown Method');
}
}
<?php
/**
* UnknownPropertyException class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -15,14 +13,14 @@ namespace yii\base;
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class UnknownPropertyException extends \Exception
class UnknownPropertyException extends Exception
{
/**
* @return string the user-friendly name of this exception
*/
public function getName()
{
return \Yii::t('yii', 'Unknown Property');
return \Yii::t('yii|Unknown Property');
}
}
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
/**
* UserException is the base class for exceptions that are meant to be shown to end users.
* Such exceptions are often caused by mistakes of end users.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class UserException extends Exception
{
}
<?php
/**
* Vector class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -101,7 +99,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
* Returns the item at the specified index.
* @param integer $index the index of the item
* @return mixed the item at the index
* @throws InvalidCallException if the index is out of range
* @throws InvalidParamException if the index is out of range
*/
public function itemAt($index)
{
......@@ -110,7 +108,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
} elseif ($index >= 0 && $index < $this->_c) { // in case the value is null
return $this->_d[$index];
} else {
throw new InvalidCallException('Index out of range: ' . $index);
throw new InvalidParamException('Index out of range: ' . $index);
}
}
......@@ -132,7 +130,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
* one step towards the end.
* @param integer $index the specified position.
* @param mixed $item new item to be inserted into the vector
* @throws InvalidCallException if the index specified is out of range, or the vector is read-only.
* @throws InvalidParamException if the index specified is out of range, or the vector is read-only.
*/
public function insertAt($index, $item)
{
......@@ -142,7 +140,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
array_splice($this->_d, $index, 0, array($item));
$this->_c++;
} else {
throw new InvalidCallException('Index out of range: ' . $index);
throw new InvalidParamException('Index out of range: ' . $index);
}
}
......@@ -169,7 +167,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
* Removes an item at the specified position.
* @param integer $index the index of the item to be removed.
* @return mixed the removed item.
* @throws InvalidCallException if the index is out of range, or the vector is read only.
* @throws InvalidParamException if the index is out of range, or the vector is read only.
*/
public function removeAt($index)
{
......@@ -183,7 +181,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
return $item;
}
} else {
throw new InvalidCallException('Index out of range: ' . $index);
throw new InvalidParamException('Index out of range: ' . $index);
}
}
......@@ -193,7 +191,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
* Defaults to false, meaning all items in the vector will be cleared directly
* without calling [[removeAt]].
*/
public function clear($safeClear = false)
public function removeAll($safeClear = false)
{
if ($safeClear) {
for ($i = $this->_c - 1; $i >= 0; --$i) {
......@@ -211,7 +209,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
* @param mixed $item the item
* @return boolean whether the vector contains the item
*/
public function contains($item)
public function has($item)
{
return $this->indexOf($item) >= 0;
}
......@@ -242,13 +240,13 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
* Copies iterable data into the vector.
* Note, existing data in the vector will be cleared first.
* @param mixed $data the data to be copied from, must be an array or an object implementing `Traversable`
* @throws InvalidCallException if data is neither an array nor an object implementing `Traversable`.
* @throws InvalidParamException if data is neither an array nor an object implementing `Traversable`.
*/
public function copyFrom($data)
{
if (is_array($data) || $data instanceof \Traversable) {
if ($this->_c > 0) {
$this->clear();
$this->removeAll();
}
if ($data instanceof self) {
$data = $data->_d;
......@@ -257,7 +255,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
$this->add($item);
}
} else {
throw new InvalidCallException('Data must be either an array or an object implementing Traversable.');
throw new InvalidParamException('Data must be either an array or an object implementing Traversable.');
}
}
......@@ -265,7 +263,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
* Merges iterable data into the vector.
* New items will be appended to the end of the existing items.
* @param array|\Traversable $data the data to be merged with. It must be an array or object implementing Traversable
* @throws InvalidCallException if data is neither an array nor an object implementing `Traversable`.
* @throws InvalidParamException if data is neither an array nor an object implementing `Traversable`.
*/
public function mergeWith($data)
{
......@@ -277,7 +275,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
$this->add($item);
}
} else {
throw new InvalidCallException('The data to be merged with must be an array or an object implementing Traversable.');
throw new InvalidParamException('The data to be merged with must be an array or an object implementing Traversable.');
}
}
......
<?php
/**
* VectorIterator class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* ViewRenderer class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* Widget class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
use Yii;
use yii\helpers\FileHelper;
/**
* Widget is the base class for widgets.
*
......@@ -72,35 +73,26 @@ class Widget extends Component
/**
* Renders a view.
*
* The method first finds the actual view file corresponding to the specified view.
* It then calls [[renderFile()]] to render the view file. The rendering result is returned
* as a string. If the view file does not exist, an exception will be thrown.
*
* To determine which view file should be rendered, the method calls [[findViewFile()]] which
* will search in the directories as specified by [[basePath]].
*
* View name can be a path alias representing an absolute file path (e.g. `@application/views/layout/index`),
* or a path relative to [[basePath]]. The file suffix is optional and defaults to `.php` if not given
* in the view name.
*
* @param string $view the view to be rendered. This can be either a path alias or a path relative to [[basePath]].
* @param array $params the parameters that should be made available in the view. The PHP function `extract()`
* will be called on this variable to extract the variables from this parameter.
* @return string the rendering result
* @throws Exception if the view file cannot be found
* @param string $view the view name. Please refer to [[findViewFile()]] on how to specify a view name.
* @param array $params the parameters (name-value pairs) that should be made available in the view.
* @return string the rendering result.
* @throws InvalidParamException if the view file does not exist.
*/
public function render($view, $params = array())
{
return $this->createView()->renderPartial($view, $params);
return Yii::$app->getView()->render($view, $params, $this);
}
/**
* @return View
* Renders a view file.
* @param string $file the view file to be rendered. This can be either a file path or a path alias.
* @param array $params the parameters (name-value pairs) that should be made available in the view.
* @return string the rendering result.
* @throws InvalidParamException if the view file does not exist.
*/
public function createView()
public function renderFile($file, $params = array())
{
return new View($this);
return Yii::$app->getView()->renderFile($file, $params, $this);
}
/**
......
<?php
/**
* ApcCache class file
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* Cache class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\caching;
use yii\base\Component;
use yii\helpers\StringHelper;
/**
* Cache is the base class for cache classes supporting different cache storage implementation.
......@@ -72,13 +71,13 @@ abstract class Cache extends Component implements \ArrayAccess
/**
* Builds a normalized cache key from one or multiple parameters.
* Builds a normalized cache key from a given key.
*
* The generated key contains letters and digits only, and its length is no more than 32.
*
* If only one parameter is given and it is already a normalized key, then
* it will be returned back without change. Otherwise, a normalized key
* is generated by serializing all given parameters and applying MD5 hashing.
* If the given key is a string containing alphanumeric characters only and no more than 32 characters,
* then the key will be returned back without change. Otherwise, a normalized key
* is generated by serializing the given key and applying MD5 hashing.
*
* The following example builds a cache key using three parameters:
*
......@@ -86,16 +85,15 @@ abstract class Cache extends Component implements \ArrayAccess
* $key = $cache->buildKey($className, $method, $id);
* ~~~
*
* @param string $key the first parameter
* @param array|string $key the key to be normalized
* @return string the generated cache key
*/
public function buildKey($key)
{
if (func_num_args() === 1 && ctype_alnum($key) && strlen($key) <= 32) {
return (string)$key;
if (is_string($key)) {
return ctype_alnum($key) && StringHelper::strlen($key) <= 32 ? $key : md5($key);
} else {
$params = func_get_args();
return md5(serialize($params));
return md5(json_encode($key));
}
}
......
<?php
/**
* ChainedDependency class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* DbCache class file
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\caching;
use Yii;
use yii\base\InvalidConfigException;
use yii\db\Connection;
use yii\db\Query;
......@@ -16,30 +15,20 @@ use yii\db\Query;
/**
* DbCache implements a cache application component by storing cached data in a database.
*
* DbCache stores cache data in a DB table whose name is specified via [[cacheTableName]].
* For MySQL database, the table should be created beforehand as follows :
*
* ~~~
* CREATE TABLE tbl_cache (
* id char(128) NOT NULL,
* expire int(11) DEFAULT NULL,
* data LONGBLOB,
* PRIMARY KEY (id),
* KEY expire (expire)
* );
* ~~~
*
* You should replace `LONGBLOB` as follows if you are using a different DBMS:
*
* - PostgreSQL: `BYTEA`
* - SQLite, SQL server, Oracle: `BLOB`
*
* DbCache connects to the database via the DB connection specified in [[connectionID]]
* which must refer to a valid DB application component.
* By default, DbCache stores session data in a DB table named 'tbl_cache'. This table
* must be pre-created. The table name can be changed by setting [[cacheTable]].
*
* Please refer to [[Cache]] for common cache operations that are supported by DbCache.
*
* @property Connection $db The DB connection instance.
* The following example shows how you can configure the application to use DbCache:
*
* ~~~
* 'cache' => array(
* 'class' => 'yii\caching\DbCache',
* // 'db' => 'mydb',
* // 'cacheTable' => 'my_cache',
* )
* ~~~
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
......@@ -47,50 +36,56 @@ use yii\db\Query;
class DbCache extends Cache
{
/**
* @var string the ID of the [[Connection|DB connection]] application component. Defaults to 'db'.
* @var Connection|string the DB connection object or the application component ID of the DB connection.
* After the DbCache object is created, if you want to change this property, you should only assign it
* with a DB connection object.
*/
public $connectionID = 'db';
public $db = 'db';
/**
* @var string name of the DB table to store cache content. Defaults to 'tbl_cache'.
* The table must be created before using this cache component.
* @var string name of the DB table to store cache content.
* The table should be pre-created as follows:
*
* ~~~
* CREATE TABLE tbl_cache (
* id char(128) NOT NULL PRIMARY KEY,
* expire int(11),
* data BLOB
* );
* ~~~
*
* where 'BLOB' refers to the BLOB-type of your preferred DBMS. Below are the BLOB type
* that can be used for some popular DBMS:
*
* - MySQL: LONGBLOB
* - PostgreSQL: BYTEA
* - MSSQL: BLOB
*
* When using DbCache in a production server, we recommend you create a DB index for the 'expire'
* column in the cache table to improve the performance.
*/
public $cacheTableName = 'tbl_cache';
public $cacheTable = 'tbl_cache';
/**
* @var integer the probability (parts per million) that garbage collection (GC) should be performed
* when storing a piece of data in the cache. Defaults to 10, meaning 0.001% chance.
* when storing a piece of data in the cache. Defaults to 100, meaning 0.01% chance.
* This number should be between 0 and 1000000. A value 0 meaning no GC will be performed at all.
**/
public $gcProbability = 100;
/**
* @var Connection the DB connection instance
*/
private $_db;
/**
* Returns the DB connection instance used for caching purpose.
* @return Connection the DB connection instance
* @throws InvalidConfigException if [[connectionID]] does not point to a valid application component.
*/
public function getDb()
{
if ($this->_db === null) {
$db = \Yii::$application->getComponent($this->connectionID);
if ($db instanceof Connection) {
$this->_db = $db;
} else {
throw new InvalidConfigException("DbCache::connectionID must refer to the ID of a DB application component.");
}
}
return $this->_db;
}
/**
* Sets the DB connection used by the cache component.
* @param Connection $value the DB connection instance
* Initializes the DbCache component.
* This method will initialize the [[db]] property to make sure it refers to a valid DB connection.
* @throws InvalidConfigException if [[db]] is invalid.
*/
public function setDb($value)
public function init()
{
$this->_db = $value;
parent::init();
if (is_string($this->db)) {
$this->db = Yii::$app->getComponent($this->db);
}
if (!$this->db instanceof Connection) {
throw new InvalidConfigException("DbCache::db must be either a DB connection instance or the application component ID of a DB connection.");
}
}
/**
......@@ -103,17 +98,16 @@ class DbCache extends Cache
{
$query = new Query;
$query->select(array('data'))
->from($this->cacheTableName)
->where('id = :id AND (expire = 0 OR expire > :time)', array(':id' => $key, ':time' => time()));
$db = $this->getDb();
if ($db->enableQueryCache) {
->from($this->cacheTable)
->where('id = :id AND (expire = 0 OR expire >' . time() . ')', array(':id' => $key));
if ($this->db->enableQueryCache) {
// temporarily disable and re-enable query caching
$db->enableQueryCache = false;
$result = $query->createCommand($db)->queryScalar();
$db->enableQueryCache = true;
$this->db->enableQueryCache = false;
$result = $query->createCommand($this->db)->queryScalar();
$this->db->enableQueryCache = true;
return $result;
} else {
return $query->createCommand($db)->queryScalar();
return $query->createCommand($this->db)->queryScalar();
}
}
......@@ -129,17 +123,16 @@ class DbCache extends Cache
}
$query = new Query;
$query->select(array('id', 'data'))
->from($this->cacheTableName)
->from($this->cacheTable)
->where(array('id' => $keys))
->andWhere("expire = 0 OR expire > " . time() . ")");
->andWhere('(expire = 0 OR expire > ' . time() . ')');
$db = $this->getDb();
if ($db->enableQueryCache) {
$db->enableQueryCache = false;
$rows = $query->createCommand($db)->queryAll();
$db->enableQueryCache = true;
if ($this->db->enableQueryCache) {
$this->db->enableQueryCache = false;
$rows = $query->createCommand($this->db)->queryAll();
$this->db->enableQueryCache = true;
} else {
$rows = $query->createCommand($db)->queryAll();
$rows = $query->createCommand($this->db)->queryAll();
}
$results = array();
......@@ -163,13 +156,13 @@ class DbCache extends Cache
*/
protected function setValue($key, $value, $expire)
{
$command = $this->getDb()->createCommand();
$command->update($this->cacheTableName, array(
'expire' => $expire > 0 ? $expire + time() : 0,
'data' => array($value, \PDO::PARAM_LOB),
), array(
'id' => $key,
));;
$command = $this->db->createCommand()
->update($this->cacheTable, array(
'expire' => $expire > 0 ? $expire + time() : 0,
'data' => array($value, \PDO::PARAM_LOB),
), array(
'id' => $key,
));
if ($command->execute()) {
$this->gc();
......@@ -198,14 +191,13 @@ class DbCache extends Cache
$expire = 0;
}
$command = $this->getDb()->createCommand();
$command->insert($this->cacheTableName, array(
'id' => $key,
'expire' => $expire,
'data' => array($value, \PDO::PARAM_LOB),
));
try {
$command->execute();
$this->db->createCommand()
->insert($this->cacheTable, array(
'id' => $key,
'expire' => $expire,
'data' => array($value, \PDO::PARAM_LOB),
))->execute();
return true;
} catch (\Exception $e) {
return false;
......@@ -220,8 +212,9 @@ class DbCache extends Cache
*/
protected function deleteValue($key)
{
$command = $this->getDb()->createCommand();
$command->delete($this->cacheTableName, array('id' => $key))->execute();
$this->db->createCommand()
->delete($this->cacheTable, array('id' => $key))
->execute();
return true;
}
......@@ -233,8 +226,9 @@ class DbCache extends Cache
public function gc($force = false)
{
if ($force || mt_rand(0, 1000000) < $this->gcProbability) {
$command = $this->getDb()->createCommand();
$command->delete($this->cacheTableName, 'expire > 0 AND expire < ' . time())->execute();
$this->db->createCommand()
->delete($this->cacheTable, 'expire > 0 AND expire < ' . time())
->execute();
}
}
......@@ -245,8 +239,9 @@ class DbCache extends Cache
*/
protected function flushValues()
{
$command = $this->getDb()->createCommand();
$command->delete($this->cacheTableName)->execute();
$this->db->createCommand()
->delete($this->cacheTable)
->execute();
return true;
}
}
<?php
/**
* DbDependency class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\caching;
use Yii;
use yii\base\InvalidConfigException;
use yii\db\Connection;
use yii\db\Query;
/**
* DbDependency represents a dependency based on the query result of a SQL statement.
*
* If the query result changes, the dependency is considered as changed.
* The query is specified via the [[query]] property.
* The query is specified via the [[sql]] property.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
......@@ -25,88 +23,52 @@ use yii\db\Query;
class DbDependency extends Dependency
{
/**
* @var string the ID of the [[Connection|DB connection]] application component. Defaults to 'db'.
* @var string the application component ID of the DB connection.
*/
public $connectionID = 'db';
public $db = 'db';
/**
* @var Query the SQL query whose result is used to determine if the dependency has been changed.
* @var string the SQL query whose result is used to determine if the dependency has been changed.
* Only the first row of the query result will be used.
*/
public $query;
public $sql;
/**
* @var Connection the DB connection instance
* @var array the parameters (name=>value) to be bound to the SQL statement specified by [[sql]].
*/
private $_db;
public $params;
/**
* Constructor.
* @param Query $query the SQL query whose result is used to determine if the dependency has been changed.
* @param string $sql the SQL query whose result is used to determine if the dependency has been changed.
* @param array $params the parameters (name=>value) to be bound to the SQL statement specified by [[sql]].
* @param array $config name-value pairs that will be used to initialize the object properties
*/
public function __construct($query = null, $config = array())
public function __construct($sql, $params = array(), $config = array())
{
$this->query = $query;
$this->sql = $sql;
$this->params = $params;
parent::__construct($config);
}
/**
* PHP sleep magic method.
* This method ensures that the database instance is set null because it contains resource handles.
* @return array
*/
public function __sleep()
{
$this->_db = null;
return array_keys((array)$this);
}
/**
* Generates the data needed to determine if dependency has been changed.
* This method returns the value of the global state.
* @return mixed the data needed to determine if dependency has been changed.
*/
protected function generateDependencyData()
{
$db = $this->getDb();
/**
* @var \yii\db\Command $command
*/
$command = $this->query->createCommand($db);
$db = Yii::$app->getComponent($this->db);
if (!$db instanceof Connection) {
throw new InvalidConfigException("DbDependency::db must be the application component ID of a DB connection.");
}
if ($db->enableQueryCache) {
// temporarily disable and re-enable query caching
$db->enableQueryCache = false;
$result = $command->queryRow();
$result = $db->createCommand($this->sql, $this->params)->queryRow();
$db->enableQueryCache = true;
} else {
$result = $command->queryRow();
$result = $db->createCommand($this->sql, $this->params)->queryRow();
}
return $result;
}
/**
* Returns the DB connection instance used for caching purpose.
* @return Connection the DB connection instance
* @throws InvalidConfigException if [[connectionID]] does not point to a valid application component.
*/
public function getDb()
{
if ($this->_db === null) {
$db = \Yii::$application->getComponent($this->connectionID);
if ($db instanceof Connection) {
$this->_db = $db;
} else {
throw new InvalidConfigException("DbCache::connectionID must refer to the ID of a DB application component.");
}
}
return $this->_db;
}
/**
* Sets the DB connection used by the cache component.
* @param Connection $value the DB connection instance
*/
public function setDb($value)
{
$this->_db = $value;
}
}
<?php
/**
* Dependency class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* DummyCache class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -13,7 +11,7 @@ namespace yii\caching;
* DummyCache is a placeholder cache component.
*
* DummyCache does not cache anything. It is provided so that one can always configure
* a 'cache' application component and save the check of existence of `\Yii::$application->cache`.
* a 'cache' application component and save the check of existence of `\Yii::$app->cache`.
* By replacing DummyCache with some other cache component, one can quickly switch from
* non-caching mode to caching mode.
*
......
<?php
/**
* ExpressionDependency class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* FileCache class file
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -28,7 +26,7 @@ class FileCache extends Cache
/**
* @var string the directory to store cache files. You may use path alias here.
*/
public $cachePath = '@application/runtime/cache';
public $cachePath = '@app/runtime/cache';
/**
* @var string cache file suffix. Defaults to '.bin'.
*/
......@@ -54,9 +52,6 @@ class FileCache extends Cache
{
parent::init();
$this->cachePath = \Yii::getAlias($this->cachePath);
if ($this->cachePath === false) {
throw new InvalidConfigException('FileCache.cachePath must be a valid path alias.');
}
if (!is_dir($this->cachePath)) {
mkdir($this->cachePath, 0777, true);
}
......
<?php
/**
* FileDependency class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* MemCache class file
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* MemCacheServer class file
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* WinCache class file
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* XCache class file
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* ZendDataCache class file
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
......@@ -3,13 +3,12 @@
* Console Application class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\console;
use yii\base\Exception;
use yii\base\InvalidRouteException;
/**
......@@ -85,16 +84,17 @@ class Application extends \yii\base\Application
* Processes the request.
* The request is represented in terms of a controller route and action parameters.
* @return integer the exit status of the controller action (0 means normal, non-zero values mean abnormal)
* @throws Exception if the script is not running from the command line
*/
public function processRequest()
{
/** @var $request Request */
$request = $this->getRequest();
if ($request->getIsConsoleRequest()) {
return $this->runAction($request->route, $request->params);
list ($route, $params) = $request->resolve();
return $this->runAction($route, $params);
} else {
echo "Error: this script must be run from the command line.";
return 1;
throw new Exception(\Yii::t('yii|This script must be run from the command line.'));
}
}
......@@ -106,14 +106,14 @@ class Application extends \yii\base\Application
* @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 Exception if the route is invalid
*/
public function runAction($route, $params = array())
{
try {
return parent::runAction($route, $params);
} catch (InvalidRouteException $e) {
echo "Error: unknown command \"$route\".\n";
return 1;
throw new Exception(\Yii::t('yii|Unknown command "{command}".', array('{command}' => $route)));
}
}
......@@ -127,8 +127,8 @@ class Application extends \yii\base\Application
'message' => 'yii\console\controllers\MessageController',
'help' => 'yii\console\controllers\HelpController',
'migrate' => 'yii\console\controllers\MigrateController',
'shell' => 'yii\console\controllers\ShellController',
'create' => 'yii\console\controllers\CreateController',
'app' => 'yii\console\controllers\AppController',
'cache' => 'yii\console\controllers\CacheController',
);
}
......@@ -148,9 +148,4 @@ class Application extends \yii\base\Application
),
));
}
public function usageError($message)
{
}
}
<?php
/**
* Controller class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -11,7 +9,7 @@ namespace yii\console;
use Yii;
use yii\base\Action;
use yii\base\InvalidRequestException;
use yii\base\InlineAction;
use yii\base\InvalidRouteException;
/**
......@@ -49,14 +47,11 @@ class Controller extends \yii\base\Controller
public function runAction($id, $params = array())
{
if ($params !== array()) {
$class = new \ReflectionClass($this);
$options = $this->globalOptions();
foreach ($params as $name => $value) {
if ($class->hasProperty($name)) {
$property = $class->getProperty($name);
if ($property->isPublic() && !$property->isStatic() && $property->getDeclaringClass()->getName() === get_class($this)) {
$this->$name = $value;
unset($params[$name]);
}
if (in_array($name, $options, true)) {
$this->$name = $value;
unset($params[$name]);
}
}
}
......@@ -64,25 +59,60 @@ class Controller extends \yii\base\Controller
}
/**
* Validates the parameter being bound to actions.
* This method is invoked when parameters are being bound to the currently requested action.
* Child classes may override this method to throw exceptions when there are missing and/or unknown parameters.
* @param Action $action the currently requested action
* @param array $missingParams the names of the missing parameters
* @param array $unknownParams the unknown parameters (name=>value)
* @throws InvalidRequestException if there are missing or unknown parameters
* Binds the parameters to the action.
* This method is invoked by [[Action]] when it begins to run with the given parameters.
* This method will first bind the parameters with the [[globalOptions()|global options]]
* available to the action. It then validates the given arguments.
* @param Action $action the action to be bound with parameters
* @param array $params the parameters to be bound to the action
* @return array the valid parameters that the action can run with.
* @throws Exception if there are unknown options or missing arguments
*/
public function validateActionParams($action, $missingParams, $unknownParams)
public function bindActionParams($action, $params)
{
if (!empty($missingParams)) {
throw new InvalidRequestException(Yii::t('yii', 'Missing required options: {params}', array(
'{params}' => implode(', ', $missingParams),
if ($params !== array()) {
$options = $this->globalOptions();
foreach ($params as $name => $value) {
if (in_array($name, $options, true)) {
$this->$name = $value;
unset($params[$name]);
}
}
}
$args = isset($params[Request::ANONYMOUS_PARAMS]) ? $params[Request::ANONYMOUS_PARAMS] : array();
unset($params[Request::ANONYMOUS_PARAMS]);
if ($params !== array()) {
throw new Exception(Yii::t('yii|Unknown options: {params}', array(
'{params}' => implode(', ', array_keys($params)),
)));
} elseif (!empty($unknownParams)) {
throw new InvalidRequestException(Yii::t('yii', 'Unknown options: {params}', array(
'{params}' => implode(', ', $unknownParams),
}
if ($action instanceof InlineAction) {
$method = new \ReflectionMethod($this, $action->actionMethod);
} else {
$method = new \ReflectionMethod($action, 'run');
}
$missing = array();
foreach ($method->getParameters() as $i => $param) {
$name = $param->getName();
if (!isset($args[$i])) {
if ($param->isDefaultValueAvailable()) {
$args[$i] = $param->getDefaultValue();
} else {
$missing[] = $name;
}
}
}
if ($missing !== array()) {
throw new Exception(Yii::t('yii|Missing required arguments: {params}', array(
'{params}' => implode(', ', $missing),
)));
}
return $args;
}
/**
......@@ -103,12 +133,17 @@ class Controller extends \yii\base\Controller
}
}
public function usageError($message)
{
echo "\nError: $message\n";
Yii::$application->end(1);
}
/**
* Returns the names of the global options for this command.
* A global option requires the existence of a public member variable whose
* name is the option name.
* Child classes may override this method to specify possible global options.
*
* Note that the values setting via global options are not available
* until [[beforeAction()]] is being called.
*
* @return array the names of the global options for this command.
*/
public function globalOptions()
{
return array();
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\console;
use yii\base\UserException;
/**
* Exception represents an exception caused by incorrect usage of a console command.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Exception extends UserException
{
/**
* @return string the user-friendly name of this exception
*/
public function getName()
{
return \Yii::t('yii|Error');
}
}
<?php
/**
* Request class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -15,49 +13,39 @@ namespace yii\console;
*/
class Request extends \yii\base\Request
{
/**
* @var string the controller route specified by this request. If this is an empty string,
* it means the [[Application::defaultRoute|default route]] will be used.
* Note that the value of this property may not be a correct route. The console application
* will determine it is valid or not when it attempts to execute with this route.
*/
public $route;
/**
* @var array
*/
public $params;
public function init()
{
parent::init();
$this->resolveRequest();
}
const ANONYMOUS_PARAMS = '-args';
public function getRawParams()
{
return isset($_SERVER['argv']) ? $_SERVER['argv'] : array();
}
protected function resolveRequest()
/**
* Resolves the current request into a route and the associated parameters.
* @return array the first element is the route, and the second is the associated parameters.
*/
public function resolve()
{
$rawParams = $this->getRawParams();
array_shift($rawParams); // the 1st argument is the yiic script name
if (isset($rawParams[0])) {
$this->route = $rawParams[0];
$route = $rawParams[0];
array_shift($rawParams);
} else {
$this->route = '';
$route = '';
}
$this->params = array();
$params = array(self::ANONYMOUS_PARAMS => array());
foreach ($rawParams as $param) {
if (preg_match('/^--(\w+)(=(.*))?$/', $param, $matches)) {
$name = $matches[1];
$this->params[$name] = isset($matches[3]) ? $matches[3] : true;
$params[$name] = isset($matches[3]) ? $matches[3] : true;
} else {
$this->params['args'][] = $param;
$params[self::ANONYMOUS_PARAMS][] = $param;
}
}
return array($route, $params);
}
}
<?php
/**
* CreateController class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\console\controllers;
use yii\console\Controller;
use yii\util\FileHelper;
use yii\helpers\FileHelper;
use yii\base\Exception;
/**
......@@ -20,14 +18,14 @@ use yii\base\Exception;
* @author Alexander Makarov <sam@rmcreative.ru>
* @since 2.0
*/
class CreateController extends Controller
class AppController extends Controller
{
private $_rootPath;
private $_config;
/**
* @var string custom template path. If specified, templates will be
* searched there additionally to `framework/console/create`.
* searched there additionally to `framework/console/webapp`.
*/
public $templatesPath;
......@@ -46,6 +44,16 @@ class CreateController extends Controller
}
}
public function globalOptions()
{
return array('templatesPath', 'type');
}
public function actionIndex()
{
$this->forward('help/index', array('-args' => array('app/create')));
}
/**
* Generates Yii application at the path specified via appPath parameter.
*
......@@ -56,7 +64,7 @@ class CreateController extends Controller
* @throws \yii\base\Exception if path specified is not valid
* @return integer the exit status
*/
public function actionIndex($path)
public function actionCreate($path)
{
$path = strtr($path, '/\\', DIRECTORY_SEPARATOR);
if(strpos($path, DIRECTORY_SEPARATOR) === false) {
......@@ -127,7 +135,7 @@ class CreateController extends Controller
*/
protected function getDefaultTemplatesPath()
{
return realpath(__DIR__.'/../create');
return realpath(__DIR__.'/../webapp');
}
/**
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\console\controllers;
use yii\console\Controller;
use yii\console\Exception;
use yii\caching\Cache;
/**
* This command allows you to flush cache.
*
* @author Alexander Makarov <sam@rmcreative.ru>
* @since 2.0
*/
class CacheController extends Controller
{
public function actionIndex()
{
$this->forward('help/index', array('-args' => array('cache/flush')));
}
/**
* Flushes cache.
* @param string $component Name of the cache application component to use.
*
* @throws \yii\console\Exception
*/
public function actionFlush($component = 'cache')
{
/** @var $cache Cache */
$cache = \Yii::$app->getComponent($component);
if(!$cache || !$cache instanceof Cache) {
throw new Exception('Application component "'.$component.'" is not defined or not a cache.');
}
if(!$cache->flush()) {
throw new Exception('Unable to flush cache.');
}
echo "\nDone.\n";
}
}
<?php
/**
* MessageController class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/** @var $controller \yii\console\controllers\CreateController */
/** @var $controller \yii\console\controllers\AppController */
$controller = $this;
return array(
......
<?php
/**
* ActiveQuery class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* ActiveRecord class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\db;
use yii\base\Model;
use yii\base\Event;
use yii\base\InvalidParamException;
use yii\base\ModelEvent;
use yii\base\UnknownMethodException;
use yii\base\InvalidCallException;
use yii\db\Connection;
use yii\db\TableSchema;
use yii\db\Expression;
use yii\util\StringHelper;
use yii\helpers\StringHelper;
/**
* ActiveRecord is the base class for classes representing relational data in terms of objects.
......@@ -96,7 +94,7 @@ class ActiveRecord extends Model
*/
public static function getDb()
{
return \Yii::$application->getDb();
return \Yii::$app->getDb();
}
/**
......@@ -849,7 +847,7 @@ class ActiveRecord extends Model
*/
public function beforeSave($insert)
{
$event = new ModelEvent($this);
$event = new ModelEvent;
$this->trigger($insert ? self::EVENT_BEFORE_INSERT : self::EVENT_BEFORE_UPDATE, $event);
return $event->isValid;
}
......@@ -889,7 +887,7 @@ class ActiveRecord extends Model
*/
public function beforeDelete()
{
$event = new ModelEvent($this);
$event = new ModelEvent;
$this->trigger(self::EVENT_BEFORE_DELETE, $event);
return $event->isValid;
}
......@@ -1045,7 +1043,7 @@ class ActiveRecord extends Model
* It can be declared in either the Active Record class itself or one of its behaviors.
* @param string $name the relation name
* @return ActiveRelation the relation object
* @throws InvalidCallException if the named relation does not exist.
* @throws InvalidParamException if the named relation does not exist.
*/
public function getRelation($name)
{
......@@ -1057,7 +1055,7 @@ class ActiveRecord extends Model
}
} catch (UnknownMethodException $e) {
}
throw new InvalidCallException(get_class($this) . ' has no relation named "' . $name . '".');
throw new InvalidParamException(get_class($this) . ' has no relation named "' . $name . '".');
}
/**
......
<?php
/**
* ActiveRelation class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -57,16 +55,16 @@ class ActiveRelation extends ActiveQuery
/**
* Specifies the relation associated with the pivot table.
* @param string $relationName the relation name. This refers to a relation declared in [[primaryModel]].
* @param callback $callback a PHP callback for customizing the relation associated with the pivot table.
* @param callable $callable a PHP callback for customizing the relation associated with the pivot table.
* Its signature should be `function($query)`, where `$query` is the query to be customized.
* @return ActiveRelation the relation object itself.
*/
public function via($relationName, $callback = null)
public function via($relationName, $callable = null)
{
$relation = $this->primaryModel->getRelation($relationName);
$this->via = array($relationName, $relation);
if ($callback !== null) {
call_user_func($callback, $relation);
if ($callable !== null) {
call_user_func($callable, $relation);
}
return $this;
}
......@@ -77,11 +75,11 @@ class ActiveRelation extends ActiveQuery
* @param array $link the link between the pivot table and the table associated with [[primaryModel]].
* The keys of the array represent the columns in the pivot table, and the values represent the columns
* in the [[primaryModel]] table.
* @param callback $callback a PHP callback for customizing the relation associated with the pivot table.
* @param callable $callable a PHP callback for customizing the relation associated with the pivot table.
* Its signature should be `function($query)`, where `$query` is the query to be customized.
* @return ActiveRelation
*/
public function viaTable($tableName, $link, $callback = null)
public function viaTable($tableName, $link, $callable = null)
{
$relation = new ActiveRelation(array(
'modelClass' => get_class($this->primaryModel),
......@@ -91,8 +89,8 @@ class ActiveRelation extends ActiveQuery
'asArray' => true,
));
$this->via = $relation;
if ($callback !== null) {
call_user_func($callback, $relation);
if ($callable !== null) {
call_user_func($callable, $relation);
}
return $this;
}
......
<?php
/**
* ColumnSchema class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* Connection class file
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -12,6 +10,7 @@ namespace yii\db;
use yii\base\Component;
use yii\base\InvalidConfigException;
use yii\base\NotSupportedException;
use yii\caching\Cache;
/**
* Connection represents a connection to a database via [PDO](http://www.php.net/manual/en/ref.pdo.php).
......@@ -138,10 +137,10 @@ class Connection extends Component
/**
* @var boolean whether to enable schema caching.
* Note that in order to enable truly schema caching, a valid cache component as specified
* by [[schemaCacheID]] must be enabled and [[enableSchemaCache]] must be set true.
* by [[schemaCache]] must be enabled and [[enableSchemaCache]] must be set true.
* @see schemaCacheDuration
* @see schemaCacheExclude
* @see schemaCacheID
* @see schemaCache
*/
public $enableSchemaCache = false;
/**
......@@ -157,20 +156,20 @@ class Connection extends Component
*/
public $schemaCacheExclude = array();
/**
* @var string the ID of the cache application component that is used to cache the table metadata.
* Defaults to 'cache'.
* @var Cache|string the cache object or the ID of the cache application component that
* is used to cache the table metadata.
* @see enableSchemaCache
*/
public $schemaCacheID = 'cache';
public $schemaCache = 'cache';
/**
* @var boolean whether to enable query caching.
* Note that in order to enable query caching, a valid cache component as specified
* by [[queryCacheID]] must be enabled and [[enableQueryCache]] must be set true.
* by [[queryCache]] must be enabled and [[enableQueryCache]] must be set true.
*
* Methods [[beginCache()]] and [[endCache()]] can be used as shortcuts to turn on
* and off query caching on the fly.
* @see queryCacheDuration
* @see queryCacheID
* @see queryCache
* @see queryCacheDependency
* @see beginCache()
* @see endCache()
......@@ -178,7 +177,7 @@ class Connection extends Component
public $enableQueryCache = false;
/**
* @var integer number of seconds that query results can remain valid in cache.
* Defaults to 3600, meaning one hour.
* Defaults to 3600, meaning 3600 seconds, or one hour.
* Use 0 to indicate that the cached data will never expire.
* @see enableQueryCache
*/
......@@ -190,11 +189,11 @@ class Connection extends Component
*/
public $queryCacheDependency;
/**
* @var string the ID of the cache application component that is used for query caching.
* Defaults to 'cache'.
* @var Cache|string the cache object or the ID of the cache application component
* that is used for query caching.
* @see enableQueryCache
*/
public $queryCacheID = 'cache';
public $queryCache = 'cache';
/**
* @var string the charset used for database connection. The property is only used
* for MySQL and PostgreSQL databases. Defaults to null, meaning using default charset
......@@ -292,7 +291,7 @@ class Connection extends Component
* This method is provided as a shortcut to setting two properties that are related
* with query caching: [[queryCacheDuration]] and [[queryCacheDependency]].
* @param integer $duration the number of seconds that query results may remain valid in cache.
* See [[queryCacheDuration]] for more details.
* If not set, it will use the value of [[queryCacheDuration]]. See [[queryCacheDuration]] for more details.
* @param \yii\caching\Dependency $dependency the dependency for the cached query result.
* See [[queryCacheDependency]] for more details.
*/
......@@ -322,7 +321,7 @@ class Connection extends Component
{
if ($this->pdo === null) {
if (empty($this->dsn)) {
throw new InvalidConfigException('Connection.dsn cannot be empty.');
throw new InvalidConfigException('Connection::dsn cannot be empty.');
}
try {
\Yii::trace('Opening DB connection: ' . $this->dsn, __CLASS__);
......@@ -332,7 +331,7 @@ class Connection extends Component
catch (\PDOException $e) {
\Yii::error("Failed to open DB connection ({$this->dsn}): " . $e->getMessage(), __CLASS__);
$message = YII_DEBUG ? 'Failed to open DB connection: ' . $e->getMessage() : 'Failed to open DB connection.';
throw new Exception($message, (int)$e->getCode(), $e->errorInfo);
throw new Exception($message, $e->errorInfo, (int)$e->getCode());
}
}
}
......
<?php
/**
* DataReader class file
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* Exception class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -26,13 +24,14 @@ class Exception extends \yii\base\Exception
/**
* Constructor.
* @param string $message PDO error message
* @param integer $code PDO error code
* @param mixed $errorInfo PDO error info
* @param integer $code PDO error code
* @param \Exception $previous The previous exception used for the exception chaining.
*/
public function __construct($message, $code = 0, $errorInfo = null)
public function __construct($message, $errorInfo = null, $code = 0, \Exception $previous = null)
{
$this->errorInfo = $errorInfo;
parent::__construct($message, $code);
parent::__construct($message, $code, $previous);
}
/**
......@@ -40,6 +39,6 @@ class Exception extends \yii\base\Exception
*/
public function getName()
{
return \Yii::t('yii', 'Database Exception');
return \Yii::t('yii|Database Exception');
}
}
\ No newline at end of file
<?php
/**
* Expression class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* Migration class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -51,7 +49,7 @@ class Migration extends \yii\base\Component
{
parent::init();
if ($this->db === null) {
$this->db = \Yii::$application->getComponent('db');
$this->db = \Yii::$app->getComponent('db');
}
}
......
<?php
/**
* Query class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -37,9 +35,19 @@ namespace yii\db;
class Query extends \yii\base\Component
{
/**
* @var string|array the columns being selected. This refers to the SELECT clause in a SQL
* statement. It can be either a string (e.g. `'id, name'`) or an array (e.g. `array('id', 'name')`).
* If not set, if means all columns.
* Sort ascending
* @see orderBy
*/
const SORT_ASC = false;
/**
* Sort ascending
* @see orderBy
*/
const SORT_DESC = true;
/**
* @var array the columns being selected. For example, `array('id', 'name')`.
* This is used to construct the SELECT clause in a SQL statement. If not set, if means selecting all columns.
* @see select()
*/
public $select;
......@@ -54,8 +62,8 @@ class Query extends \yii\base\Component
*/
public $distinct;
/**
* @var string|array the table(s) to be selected from. This refers to the FROM clause in a SQL statement.
* It can be either a string (e.g. `'tbl_user, tbl_post'`) or an array (e.g. `array('tbl_user', 'tbl_post')`).
* @var array the table(s) to be selected from. For example, `array('tbl_user', 'tbl_post')`.
* This is used to construct the FROM clause in a SQL statement.
* @see from()
*/
public $from;
......@@ -75,20 +83,33 @@ class Query extends \yii\base\Component
*/
public $offset;
/**
* @var string|array how to sort the query results. This refers to the ORDER BY clause in a SQL statement.
* It can be either a string (e.g. `'id ASC, name DESC'`) or an array (e.g. `array('id ASC', 'name DESC')`).
* @var array how to sort the query results. This is used to construct the ORDER BY clause in a SQL statement.
* The array keys are the columns to be sorted by, and the array values are the corresponding sort directions which
* can be either [[Query::SORT_ASC]] or [[Query::SORT_DESC]]. The array may also contain [[Expression]] objects.
* If that is the case, the expressions will be converted into strings without any change.
*/
public $orderBy;
/**
* @var string|array how to group the query results. This refers to the GROUP BY clause in a SQL statement.
* It can be either a string (e.g. `'company, department'`) or an array (e.g. `array('company', 'department')`).
* @var array how to group the query results. For example, `array('company', 'department')`.
* This is used to construct the GROUP BY clause in a SQL statement.
*/
public $groupBy;
/**
* @var string|array how to join with other tables. This refers to the JOIN clause in a SQL statement.
* It can be either a string (e.g. `'LEFT JOIN tbl_user ON tbl_user.id=author_id'`) or an array (e.g.
* `array('LEFT JOIN tbl_user ON tbl_user.id=author_id', 'LEFT JOIN tbl_team ON tbl_team.id=team_id')`).
* @see join()
* @var array how to join with other tables. Each array element represents the specification
* of one join which has the following structure:
*
* ~~~
* array($joinType, $tableName, $joinCondition)
* ~~~
*
* For example,
*
* ~~~
* array(
* array('INNER JOIN', 'tbl_user', 'tbl_user.id = author_id'),
* array('LEFT JOIN', 'tbl_team', 'tbl_team.id = team_id'),
* )
* ~~~
*/
public $join;
/**
......@@ -97,9 +118,8 @@ class Query extends \yii\base\Component
*/
public $having;
/**
* @var string|Query[] the UNION clause(s) in a SQL statement. This can be either a string
* representing a single UNION clause or an array representing multiple UNION clauses.
* Each union clause can be a string or a `Query` object which refers to the SQL statement.
* @var array this is used to construct the UNION clause(s) in a SQL statement.
* Each array element can be either a string or a [[Query]] object representing a sub-query.
*/
public $union;
/**
......@@ -117,7 +137,7 @@ class Query extends \yii\base\Component
public function createCommand($db = null)
{
if ($db === null) {
$db = \Yii::$application->db;
$db = \Yii::$app->db;
}
$sql = $db->getQueryBuilder()->build($this);
return $db->createCommand($sql, $this->params);
......@@ -136,6 +156,9 @@ class Query extends \yii\base\Component
*/
public function select($columns, $option = null)
{
if (!is_array($columns)) {
$columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY);
}
$this->select = $columns;
$this->selectOption = $option;
return $this;
......@@ -163,6 +186,9 @@ class Query extends \yii\base\Component
*/
public function from($tables)
{
if (!is_array($tables)) {
$tables = preg_split('/\s*,\s*/', trim($tables), -1, PREG_SPLIT_NO_EMPTY);
}
$this->from = $tables;
return $this;
}
......@@ -362,10 +388,13 @@ class Query extends \yii\base\Component
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
* @return Query the query object itself
* @see addGroup()
* @see addGroupBy()
*/
public function groupBy($columns)
{
if (!is_array($columns)) {
$columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY);
}
$this->groupBy = $columns;
return $this;
}
......@@ -377,19 +406,16 @@ class Query extends \yii\base\Component
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
* @return Query the query object itself
* @see group()
* @see groupBy()
*/
public function addGroup($columns)
public function addGroupBy($columns)
{
if (empty($this->groupBy)) {
if (!is_array($columns)) {
$columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY);
}
if ($this->groupBy === null) {
$this->groupBy = $columns;
} else {
if (!is_array($this->groupBy)) {
$this->groupBy = preg_split('/\s*,\s*/', trim($this->groupBy), -1, PREG_SPLIT_NO_EMPTY);
}
if (!is_array($columns)) {
$columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY);
}
$this->groupBy = array_merge($this->groupBy, $columns);
}
return $this;
......@@ -456,43 +482,58 @@ class Query extends \yii\base\Component
/**
* Sets the ORDER BY part of the query.
* @param string|array $columns the columns (and the directions) to be ordered by.
* Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array (e.g. array('id ASC', 'name DESC')).
* Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array
* (e.g. `array('id' => Query::SORT_ASC ASC, 'name' => Query::SORT_DESC)`).
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
* @return Query the query object itself
* @see addOrder()
* @see addOrderBy()
*/
public function orderBy($columns)
{
$this->orderBy = $columns;
$this->orderBy = $this->normalizeOrderBy($columns);
return $this;
}
/**
* Adds additional ORDER BY columns to the query.
* @param string|array $columns the columns (and the directions) to be ordered by.
* Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array (e.g. array('id ASC', 'name DESC')).
* Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array
* (e.g. `array('id' => Query::SORT_ASC ASC, 'name' => Query::SORT_DESC)`).
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
* @return Query the query object itself
* @see order()
* @see orderBy()
*/
public function addOrderBy($columns)
{
if (empty($this->orderBy)) {
$columns = $this->normalizeOrderBy($columns);
if ($this->orderBy === null) {
$this->orderBy = $columns;
} else {
if (!is_array($this->orderBy)) {
$this->orderBy = preg_split('/\s*,\s*/', trim($this->orderBy), -1, PREG_SPLIT_NO_EMPTY);
}
if (!is_array($columns)) {
$columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY);
}
$this->orderBy = array_merge($this->orderBy, $columns);
}
return $this;
}
protected function normalizeOrderBy($columns)
{
if (is_array($columns)) {
return $columns;
} else {
$columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY);
$result = array();
foreach ($columns as $column) {
if (preg_match('/^(.*?)\s+(asc|desc)$/i', $column, $matches)) {
$result[$matches[1]] = strcasecmp($matches[2], 'desc') ? self::SORT_ASC : self::SORT_DESC;
} else {
$result[$column] = self::SORT_ASC;
}
}
return $result;
}
}
/**
* Sets the LIMIT part of the query.
* @param integer $limit the limit
......
<?php
/**
* QueryBuilder class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -62,10 +60,10 @@ class QueryBuilder extends \yii\base\Object
$this->buildFrom($query->from),
$this->buildJoin($query->join),
$this->buildWhere($query->where),
$this->buildGroup($query->groupBy),
$this->buildGroupBy($query->groupBy),
$this->buildHaving($query->having),
$this->buildUnion($query->union),
$this->buildOrder($query->orderBy),
$this->buildOrderBy($query->orderBy),
$this->buildLimit($query->limit, $query->offset),
);
return implode($this->separator, array_filter($clauses));
......@@ -131,11 +129,10 @@ class QueryBuilder extends \yii\base\Object
* @param string $table the table that new rows will be inserted into.
* @param array $columns the column names
* @param array $rows the rows to be batch inserted into the table
* @param array $params the parameters to be bound to the command
* @return string the batch INSERT SQL statement
* @throws NotSupportedException if this is not supported by the underlying DBMS
*/
public function batchInsert($table, $columns, $rows, $params = array())
public function batchInsert($table, $columns, $rows)
{
throw new NotSupportedException($this->db->getDriverName() . ' does not support batch insert.');
......@@ -593,21 +590,19 @@ class QueryBuilder extends \yii\base\Object
return $operator === 'IN' ? '0=1' : '';
}
if (is_array($column)) {
if (count($column) > 1) {
return $this->buildCompositeInCondition($operator, $column, $values);
if (count($column) > 1) {
return $this->buildCompositeInCondition($operator, $column, $values);
} elseif (is_array($column)) {
$column = reset($column);
}
foreach ($values as $i => $value) {
if (is_array($value)) {
$value = isset($value[$column]) ? $value[$column] : null;
}
if ($value === null) {
$values[$i] = 'NULL';
} else {
$column = reset($column);
foreach ($values as $i => $value) {
if (is_array($value)) {
$value = isset($value[$column]) ? $value[$column] : null;
}
if ($value === null) {
$values[$i] = 'NULL';
} else {
$values[$i] = is_string($value) ? $this->db->quoteValue($value) : (string)$value;
}
}
$values[$i] = is_string($value) ? $this->db->quoteValue($value) : (string)$value;
}
}
if (strpos($column, '(') === false) {
......@@ -678,7 +673,7 @@ class QueryBuilder extends \yii\base\Object
}
/**
* @param string|array $columns
* @param array $columns
* @param boolean $distinct
* @param string $selectOption
* @return string the SELECT clause built from [[query]].
......@@ -694,13 +689,6 @@ class QueryBuilder extends \yii\base\Object
return $select . ' *';
}
if (!is_array($columns)) {
if (strpos($columns, '(') !== false) {
return $select . ' ' . $columns;
} else {
$columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY);
}
}
foreach ($columns as $i => $column) {
if (is_object($column)) {
$columns[$i] = (string)$column;
......@@ -721,7 +709,7 @@ class QueryBuilder extends \yii\base\Object
}
/**
* @param string|array $tables
* @param array $tables
* @return string the FROM clause built from [[query]].
*/
public function buildFrom($tables)
......@@ -730,13 +718,6 @@ class QueryBuilder extends \yii\base\Object
return '';
}
if (!is_array($tables)) {
if (strpos($tables, '(') !== false) {
return 'FROM ' . $tables;
} else {
$tables = preg_split('/\s*,\s*/', trim($tables), -1, PREG_SPLIT_NO_EMPTY);
}
}
foreach ($tables as $i => $table) {
if (strpos($table, '(') === false) {
if (preg_match('/^(.*?)(?i:\s+as\s+|\s+)(.*)$/i', $table, $matches)) { // with alias
......@@ -757,37 +738,36 @@ class QueryBuilder extends \yii\base\Object
/**
* @param string|array $joins
* @return string the JOIN clause built from [[query]].
* @throws Exception if the $joins parameter is not in proper format
*/
public function buildJoin($joins)
{
if (empty($joins)) {
return '';
}
if (is_string($joins)) {
return $joins;
}
foreach ($joins as $i => $join) {
if (is_array($join)) { // 0:join type, 1:table name, 2:on-condition
if (isset($join[0], $join[1])) {
$table = $join[1];
if (strpos($table, '(') === false) {
if (preg_match('/^(.*?)(?i:\s+as\s+|\s+)(.*)$/', $table, $matches)) { // with alias
$table = $this->db->quoteTableName($matches[1]) . ' ' . $this->db->quoteTableName($matches[2]);
} else {
$table = $this->db->quoteTableName($table);
}
if (is_object($join)) {
$joins[$i] = (string)$join;
} elseif (is_array($join) && isset($join[0], $join[1])) {
// 0:join type, 1:table name, 2:on-condition
$table = $join[1];
if (strpos($table, '(') === false) {
if (preg_match('/^(.*?)(?i:\s+as\s+|\s+)(.*)$/', $table, $matches)) { // with alias
$table = $this->db->quoteTableName($matches[1]) . ' ' . $this->db->quoteTableName($matches[2]);
} else {
$table = $this->db->quoteTableName($table);
}
$joins[$i] = $join[0] . ' ' . $table;
if (isset($join[2])) {
$condition = $this->buildCondition($join[2]);
if ($condition !== '') {
$joins[$i] .= ' ON ' . $this->buildCondition($join[2]);
}
}
$joins[$i] = $join[0] . ' ' . $table;
if (isset($join[2])) {
$condition = $this->buildCondition($join[2]);
if ($condition !== '') {
$joins[$i] .= ' ON ' . $this->buildCondition($join[2]);
}
} else {
throw new Exception('A join clause must be specified as an array of at least two elements.');
}
} else {
throw new Exception('A join clause must be specified as an array of join type, join table, and optionally join condition.');
}
}
......@@ -805,16 +785,12 @@ class QueryBuilder extends \yii\base\Object
}
/**
* @param string|array $columns
* @param array $columns
* @return string the GROUP BY clause
*/
public function buildGroup($columns)
public function buildGroupBy($columns)
{
if (empty($columns)) {
return '';
} else {
return 'GROUP BY ' . $this->buildColumns($columns);
}
return empty($columns) ? '' : 'GROUP BY ' . $this->buildColumns($columns);
}
/**
......@@ -828,36 +804,24 @@ class QueryBuilder extends \yii\base\Object
}
/**
* @param string|array $columns
* @param array $columns
* @return string the ORDER BY clause built from [[query]].
*/
public function buildOrder($columns)
public function buildOrderBy($columns)
{
if (empty($columns)) {
return '';
}
if (!is_array($columns)) {
if (strpos($columns, '(') !== false) {
return 'ORDER BY ' . $columns;
$orders = array();
foreach ($columns as $name => $direction) {
if (is_object($direction)) {
$orders[] = (string)$direction;
} else {
$columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY);
}
}
foreach ($columns as $i => $column) {
if (is_object($column)) {
$columns[$i] = (string)$column;
} elseif (strpos($column, '(') === false) {
if (preg_match('/^(.*?)\s+(asc|desc)$/i', $column, $matches)) {
$columns[$i] = $this->db->quoteColumnName($matches[1]) . ' ' . $matches[2];
} else {
$columns[$i] = $this->db->quoteColumnName($column);
}
$orders[] = $this->db->quoteColumnName($name) . ($direction === Query::SORT_DESC ? ' DESC' : '');
}
}
if (is_array($columns)) {
$columns = implode(', ', $columns);
}
return 'ORDER BY ' . $columns;
return 'ORDER BY ' . implode(', ', $orders);
}
/**
......@@ -878,7 +842,7 @@ class QueryBuilder extends \yii\base\Object
}
/**
* @param string|array $unions
* @param array $unions
* @return string the UNION clause built from [[query]].
*/
public function buildUnion($unions)
......@@ -886,9 +850,6 @@ class QueryBuilder extends \yii\base\Object
if (empty($unions)) {
return '';
}
if (!is_array($unions)) {
$unions = array($unions);
}
foreach ($unions as $i => $union) {
if ($union instanceof Query) {
$unions[$i] = $this->build($union);
......
<?php
/**
* Driver class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\db;
use Yii;
use yii\base\NotSupportedException;
use yii\base\InvalidCallException;
use yii\caching\Cache;
......@@ -86,21 +85,21 @@ abstract class Schema extends \yii\base\Object
$db = $this->db;
$realName = $this->getRealTableName($name);
/** @var $cache Cache */
if ($db->enableSchemaCache && ($cache = \Yii::$application->getComponent($db->schemaCacheID)) !== null && !in_array($name, $db->schemaCacheExclude, true)) {
$key = $this->getCacheKey($cache, $name);
if ($refresh || ($table = $cache->get($key)) === false) {
$table = $this->loadTableSchema($realName);
if ($table !== null) {
$cache->set($key, $table, $db->schemaCacheDuration);
if ($db->enableSchemaCache && !in_array($name, $db->schemaCacheExclude, true)) {
/** @var $cache Cache */
$cache = is_string($db->schemaCache) ? Yii::$app->getComponent($db->schemaCache) : $db->schemaCache;
if ($cache instanceof Cache) {
$key = $this->getCacheKey($cache, $name);
if ($refresh || ($table = $cache->get($key)) === false) {
$table = $this->loadTableSchema($realName);
if ($table !== null) {
$cache->set($key, $table, $db->schemaCacheDuration);
}
}
return $this->_tables[$name] = $table;
}
$this->_tables[$name] = $table;
} else {
$this->_tables[$name] = $table = $this->loadTableSchema($realName);
}
return $table;
return $this->_tables[$name] = $table = $this->loadTableSchema($realName);
}
/**
......@@ -111,7 +110,12 @@ abstract class Schema extends \yii\base\Object
*/
public function getCacheKey($cache, $name)
{
return $cache->buildKey(__CLASS__, $this->db->dsn, $this->db->username, $name);
return $cache->buildKey(array(
__CLASS__,
$this->db->dsn,
$this->db->username,
$name,
));
}
/**
......@@ -170,8 +174,9 @@ abstract class Schema extends \yii\base\Object
*/
public function refresh()
{
/** @var $cache \yii\caching\Cache */
if ($this->db->enableSchemaCache && ($cache = \Yii::$application->getComponent($this->db->schemaCacheID)) !== null) {
/** @var $cache Cache */
$cache = is_string($this->db->schemaCache) ? Yii::$app->getComponent($this->db->schemaCache) : $this->db->schemaCache;
if ($this->db->enableSchemaCache && $cache instanceof Cache) {
foreach ($this->_tables as $name => $table) {
$cache->delete($this->getCacheKey($cache, $name));
}
......
<?php
/**
* TableSchema class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008-2011 Yii Software LLC
* @license http://www.yiiframework.com/license/
......@@ -9,7 +7,7 @@
namespace yii\db;
use yii\base\InvalidCallException;
use yii\base\InvalidParamException;
/**
* TableSchema represents the metadata of a database table.
......@@ -83,7 +81,7 @@ class TableSchema extends \yii\base\Object
/**
* Manually specifies the primary key for this table.
* @param string|array $keys the primary key (can be composite)
* @throws InvalidCallException if the specified key cannot be found in the table.
* @throws InvalidParamException if the specified key cannot be found in the table.
*/
public function fixPrimaryKey($keys)
{
......@@ -98,7 +96,7 @@ class TableSchema extends \yii\base\Object
if (isset($this->columns[$key])) {
$this->columns[$key]->isPrimaryKey = true;
} else {
throw new InvalidCallException("Primary key '$key' cannot be found in table '{$this->name}'.");
throw new InvalidParamException("Primary key '$key' cannot be found in table '{$this->name}'.");
}
}
}
......
<?php
/**
* Transaction class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* QueryBuilder class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\db\mysql;
use yii\db\Exception;
use yii\base\InvalidCallException;
use yii\base\InvalidParamException;
/**
* QueryBuilder is the query builder for MySQL databases.
......@@ -54,7 +52,7 @@ class QueryBuilder extends \yii\db\QueryBuilder
$quotedTable = $this->db->quoteTableName($table);
$row = $this->db->createCommand('SHOW CREATE TABLE ' . $quotedTable)->queryRow();
if ($row === false) {
throw new Exception("Unable to find '$oldName' in table '$table'.");
throw new Exception("Unable to find column '$oldName' in table '$table'.");
}
if (isset($row['Create Table'])) {
$sql = $row['Create Table'];
......@@ -98,7 +96,7 @@ class QueryBuilder extends \yii\db\QueryBuilder
* @param mixed $value the value for the primary key of the next new row inserted. If this is not set,
* the next new row's primary key will have a value 1.
* @return string the SQL statement for resetting sequence
* @throws InvalidCallException if the table does not exist or there is no sequence associated with the table.
* @throws InvalidParamException if the table does not exist or there is no sequence associated with the table.
*/
public function resetSequence($tableName, $value = null)
{
......@@ -113,9 +111,9 @@ class QueryBuilder extends \yii\db\QueryBuilder
}
return "ALTER TABLE $tableName AUTO_INCREMENT=$value";
} elseif ($table === null) {
throw new InvalidCallException("Table not found: $tableName");
throw new InvalidParamException("Table not found: $tableName");
} else {
throw new InvalidCallException("There is not sequence associated with table '$tableName'.'");
throw new InvalidParamException("There is not sequence associated with table '$tableName'.'");
}
}
......
<?php
/**
* Schema class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* QueryBuilder class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\db\sqlite;
use yii\db\Exception;
use yii\base\InvalidParamException;
use yii\base\NotSupportedException;
use yii\base\InvalidCallException;
/**
* QueryBuilder is the query builder for SQLite databases.
......@@ -50,7 +48,7 @@ class QueryBuilder extends \yii\db\QueryBuilder
* @param mixed $value the value for the primary key of the next new row inserted. If this is not set,
* the next new row's primary key will have a value 1.
* @return string the SQL statement for resetting sequence
* @throws InvalidCallException if the table does not exist or there is no sequence associated with the table.
* @throws InvalidParamException if the table does not exist or there is no sequence associated with the table.
*/
public function resetSequence($tableName, $value = null)
{
......@@ -70,9 +68,9 @@ class QueryBuilder extends \yii\db\QueryBuilder
} catch (Exception $e) {
}
} elseif ($table === null) {
throw new InvalidCallException("Table not found: $tableName");
throw new InvalidParamException("Table not found: $tableName");
} else {
throw new InvalidCallException("There is not sequence associated with table '$tableName'.'");
throw new InvalidParamException("There is not sequence associated with table '$tableName'.'");
}
}
......
<?php
/**
* Schema class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* ArrayHelper class file.
*
* @copyright Copyright (c) 2008 Yii Software LLC
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\util;
namespace yii\helpers;
use yii\base\InvalidCallException;
use Yii;
use yii\base\InvalidParamException;
/**
* ArrayHelper provides additional array functionality you can use in your
......@@ -60,11 +59,11 @@ class ArrayHelper
*
* ~~~
* // working with array
* $username = \yii\util\ArrayHelper::getValue($_POST, 'username');
* $username = \yii\helpers\ArrayHelper::getValue($_POST, 'username');
* // working with object
* $username = \yii\util\ArrayHelper::getValue($user, 'username');
* $username = \yii\helpers\ArrayHelper::getValue($user, 'username');
* // working with anonymous function
* $fullName = \yii\util\ArrayHelper::getValue($user, function($user, $defaultValue) {
* $fullName = \yii\helpers\ArrayHelper::getValue($user, function($user, $defaultValue) {
* return $user->firstName . ' ' . $user->lastName;
* });
* ~~~
......@@ -242,7 +241,7 @@ class ArrayHelper
* value is for sorting strings in case-insensitive manner. Please refer to
* See [PHP manual](http://php.net/manual/en/function.sort.php) for more details.
* When sorting by multiple keys with different sort flags, use an array of sort flags.
* @throws InvalidCallException if the $ascending or $sortFlag parameters do not have
* @throws InvalidParamException if the $ascending or $sortFlag parameters do not have
* correct number of elements as that of $key.
*/
public static function multisort(&$array, $key, $ascending = true, $sortFlag = SORT_REGULAR)
......@@ -255,12 +254,12 @@ class ArrayHelper
if (is_scalar($ascending)) {
$ascending = array_fill(0, $n, $ascending);
} elseif (count($ascending) !== $n) {
throw new InvalidCallException('The length of $ascending parameter must be the same as that of $keys.');
throw new InvalidParamException('The length of $ascending parameter must be the same as that of $keys.');
}
if (is_scalar($sortFlag)) {
$sortFlag = array_fill(0, $n, $sortFlag);
} elseif (count($sortFlag) !== $n) {
throw new InvalidCallException('The length of $ascending parameter must be the same as that of $keys.');
throw new InvalidParamException('The length of $ascending parameter must be the same as that of $keys.');
}
$args = array();
foreach ($keys as $i => $key) {
......@@ -281,4 +280,61 @@ class ArrayHelper
$args[] = &$array;
call_user_func_array('array_multisort', $args);
}
/**
* Encodes special characters in an array of strings into HTML entities.
* Both the array keys and values will be encoded.
* If a value is an array, this method will also encode it recursively.
* @param array $data data to be encoded
* @param boolean $valuesOnly whether to encode array values only. If false,
* both the array keys and array values will be encoded.
* @param string $charset the charset that the data is using. If not set,
* [[\yii\base\Application::charset]] will be used.
* @return array the encoded data
* @see http://www.php.net/manual/en/function.htmlspecialchars.php
*/
public static function htmlEncode($data, $valuesOnly = true, $charset = null)
{
if ($charset === null) {
$charset = Yii::$app->charset;
}
$d = array();
foreach ($data as $key => $value) {
if (!$valuesOnly && is_string($key)) {
$key = htmlspecialchars($key, ENT_QUOTES, $charset);
}
if (is_string($value)) {
$d[$key] = htmlspecialchars($value, ENT_QUOTES, $charset);
} elseif (is_array($value)) {
$d[$key] = static::htmlEncode($value, $charset);
}
}
return $d;
}
/**
* Decodes HTML entities into the corresponding characters in an array of strings.
* Both the array keys and values will be decoded.
* If a value is an array, this method will also decode it recursively.
* @param array $data data to be decoded
* @param boolean $valuesOnly whether to decode array values only. If false,
* both the array keys and array values will be decoded.
* @return array the decoded data
* @see http://www.php.net/manual/en/function.htmlspecialchars-decode.php
*/
public static function htmlDecode($data, $valuesOnly = true)
{
$d = array();
foreach ($data as $key => $value) {
if (!$valuesOnly && is_string($key)) {
$key = htmlspecialchars_decode($key, ENT_QUOTES);
}
if (is_string($value)) {
$d[$key] = htmlspecialchars_decode($value, ENT_QUOTES);
} elseif (is_array($value)) {
$d[$key] = static::htmlDecode($value);
}
}
return $d;
}
}
\ No newline at end of file
<?php
/**
* ConsoleColor class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\console;
namespace yii\helpers;
// todo define how subclassing will work
// todo add a run() or render() method
// todo test this on all kinds of terminals, especially windows (check out lib ncurses)
// todo not sure if all methods should be static
// todo subclass DetailView
// todo subclass GridView
// todo more subclasses
/**
* Console View is the base class for console view components
......@@ -359,7 +349,7 @@ class ConsoleColor
}
$styleString[] = array();
foreach($styleA as $name => $content) {
if ($name = 'text-decoration') {
if ($name === 'text-decoration') {
$content = implode(' ', $content);
}
$styleString[] = $name.':'.$content;
......
......@@ -3,11 +3,11 @@
* Filesystem helper class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\util;
namespace yii\helpers;
use yii\base\Exception;
use yii\base\InvalidConfigException;
......@@ -43,7 +43,7 @@ class FileHelper
public static function ensureDirectory($path)
{
$p = \Yii::getAlias($path);
if ($p !== false && ($p = realpath($p)) !== false && is_dir($p)) {
if (($p = realpath($p)) !== false && is_dir($p)) {
return $p;
} else {
throw new InvalidConfigException('Directory does not exist: ' . $path);
......@@ -91,10 +91,10 @@ class FileHelper
public static function localize($file, $language = null, $sourceLanguage = null)
{
if ($language === null) {
$language = \Yii::$application->getLanguage();
$language = \Yii::$app->language;
}
if ($sourceLanguage === null) {
$sourceLanguage = \Yii::$application->sourceLanguage;
$sourceLanguage = \Yii::$app->sourceLanguage;
}
if ($language === $sourceLanguage) {
return $file;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment