Browse Source

...

tags/2.0.0-beta
Qiang Xue 13 years ago
parent
commit
7f35f9ada1
  1. 2
      docs/internals/base.md
  2. 140
      framework/YiiBase.php
  3. 166
      framework/base/Application.php
  4. 4
      framework/base/Behavior.php
  5. 80
      framework/base/Component.php
  6. 52
      framework/base/Dictionary.php
  7. 2
      framework/base/Event.php
  8. 4
      framework/base/Initable.php
  9. 75
      framework/base/Model.php
  10. 99
      framework/base/Module.php
  11. 124
      framework/base/Object.php
  12. 47
      framework/base/Vector.php
  13. 17
      framework/db/dao/ColumnSchema.php
  14. 226
      framework/db/dao/Command.php
  15. 70
      framework/db/dao/Connection.php
  16. 2
      framework/db/dao/DataReader.php
  17. 79
      framework/db/dao/Query.php
  18. 65
      framework/db/dao/QueryBuilder.php
  19. 5
      framework/db/dao/Schema.php
  20. 6
      framework/db/dao/TableSchema.php
  21. 16
      framework/db/dao/Transaction.php
  22. 21
      framework/logging/Logger.php
  23. 4
      framework/logging/Router.php
  24. 2
      framework/validators/Validator.php
  25. 2
      tests/unit/framework/base/BehaviorTest.php
  26. 2
      tests/unit/framework/base/ComponentTest.php
  27. 34
      tests/unit/framework/base/ObjectTest.php

2
docs/internals/base.md

@ -16,7 +16,7 @@ change API. Results in less repetitive code. Performance drop isn't significant.
### callbacks and expressions
### [[Object::create()]|create] method
### [[Object::newInstance|newInstance]] method
This method is a powerful way to instantiate a class. Differences from `new`:

140
framework/YiiBase.php

@ -49,12 +49,16 @@ class YiiBase
* @var array class map used by the Yii autoloading mechanism.
* The array keys are the class names, and the array values are the corresponding class file paths.
* This property mainly affects how [[autoload]] works.
* @see import
* @see autoload
*/
public static $classMap = array();
/**
* @var array list of directories where Yii will search for new classes to be included.
* The first directory in the array will be searched first, and so on.
* This property mainly affects how [[autoload]] works.
* @see import
* @see autoload
*/
public static $classPath = array();
/**
@ -63,10 +67,34 @@ class YiiBase
public static $app;
/**
* @var array registered path aliases
* @see getAlias
* @see setAlias
*/
public static $aliases = array(
'@yii' => __DIR__,
);
/**
* @var array initial property values that will be applied to objects newly created via [[createObject]].
* The array keys are fully qualified namespaced class names, and the array values are the corresponding
* name-value pairs for initializing the created class instances. Make sure the class names do not have
* the leading backslashes. For example,
*
* ~~~
* array(
* 'mycompany\foo\Bar' => array(
* 'prop1' => 'value1',
* 'prop2' => 'value2',
* ),
* 'mycompany\foo\Car' => array(
* 'prop1' => 'value1',
* 'prop2' => 'value2',
* ),
* )
* ~~~
*
* @see createObject
*/
public static $objectConfig = array();
private static $_imported = array(); // alias => class name or directory
private static $_logger;
@ -140,13 +168,11 @@ class YiiBase
if ($forceInclude) {
require($path . "/$className.php");
self::$_imported[$alias] = $className;
}
else {
} else {
self::$classMap[$className] = $path . "/$className.php";
}
return $className;
}
else { // a directory
} else { // a directory
array_unshift(self::$classPath, $path);
return self::$_imported[$alias] = $path;
}
@ -172,11 +198,9 @@ class YiiBase
{
if (isset(self::$aliases[$alias])) {
return self::$aliases[$alias];
}
elseif ($alias[0] !== '@') { // not an alias
} elseif ($alias[0] !== '@') { // not an alias
return $alias;
}
elseif (($pos = strpos($alias, '/')) !== false) {
} 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);
@ -207,14 +231,11 @@ class YiiBase
{
if ($path === null) {
unset(self::$aliases[$alias]);
}
elseif ($path[0] !== '@') {
} elseif ($path[0] !== '@') {
self::$aliases[$alias] = rtrim($path, '\\/');
}
elseif (($p = static::getAlias($path)) !== false) {
} elseif (($p = static::getAlias($path)) !== false) {
self::$aliases[$alias] = $p;
}
else {
} else {
throw new \yii\base\Exception('Invalid path: ' . $path);
}
}
@ -278,22 +299,34 @@ class YiiBase
}
/**
* Creates a new component instance using the given configuration.
* Creates a new object using the given configuration.
*
* The specified configuration can be either a string or an array.
* If the former, the string is treated as the object type; if the latter,
* the array must contain a `class` element specifying the object type, and
* The configuration can be either a string or an array.
* If a string, it is treated as the *object type*; if an array,
* it must contain a `class` element specifying the *object type*, and
* the rest of the name-value pairs in the array will be used to initialize
* the corresponding object properties.
*
* The object type can be either a class name or [[getAlias|path alias]] of
* The object type can be either a class name or the [[getAlias|alias]] of
* the class. For example,
*
* - `\app\components\GoogleMap`: namespaced class
* - `@app/components/GoogleMap`: an alias
*
* This method does the following steps to create an object:
*
* - create the object using the PHP `new` operator;
* - if [[objectConfig]] contains the configuration for the object class,
* initialize the object properties with that configuration;
* - initialize the object properties using the configuration passed to this method;
* - call the `init` method of the object if it implements the [[yii\base\Initable]] interface.
*
* Below are some usage examples:
*
* ~~~
* $component = Yii::create('@app/components/GoogleMap');
* $component = Yii::create('\application\components\GoogleMap');
* $component = Yii::create(array(
* 'class' => '@app/components/GoogleMap',
* $object = \Yii::createObject('@app/components/GoogleMap');
* $object = \Yii::createObject(array(
* 'class' => '\app\components\GoogleMap',
* 'apiKey' => 'xyz',
* ));
* ~~~
@ -301,25 +334,19 @@ class YiiBase
* Any additional parameters passed to this method will be
* passed to the constructor of the object being created.
*
* If a component class implements the [[\yii\base\Initable]] interface,
* its [[\yii\base\Initable::init|init]] method will be invoked AFTER
* the component properties are initialized.
*
* @param mixed $config the configuration. It can be either a string or an array.
* @return mixed the created object
* @throws \yii\base\Exception if the configuration is invalid.
*/
public static function create($config)
public static function createObject($config)
{
if (is_string($config)) {
$class = $config;
$config = array();
}
elseif (isset($config['class'])) {
} elseif (isset($config['class'])) {
$class = $config['class'];
unset($config['class']);
}
else {
} else {
throw new \yii\base\Exception('Object configuration must be an array containing a "class" element.');
}
@ -327,36 +354,38 @@ class YiiBase
$class = static::import($class, true);
}
if (($n = func_num_args()) > 1) {
if (($n = func_num_args()-1) > 0) {
$args = func_get_args();
if ($n === 2) {
$object = new $class($args[1]);
}
elseif ($n === 3) {
$object = new $class($args[1], $args[2]);
}
elseif ($n === 4) {
$object = new $class($args[1], $args[2], $args[3]);
}
else {
unset($args[0]);
$r = new ReflectionClass($class);
$object = $r->newInstanceArgs($args);
}
array_shift($args); // remove $config
}
else {
if ($n === 0) {
$object = new $class;
} elseif ($n === 1) {
$object = new $class($args[0]);
} elseif ($n === 2) {
$object = new $class($args[0], $args[1]);
} elseif ($n === 3) {
$object = new $class($args[0], $args[1], $args[2]);
} else {
$r = new \ReflectionClass($class);
$object = $r->newInstanceArgs($args);
}
$c = get_class($object);
if (isset(\Yii::$objectConfig[$c])) {
$config = isset($config) ? array_merge(\Yii::$objectConfig[$c], $config) : \Yii::$objectConfig[$c];
}
foreach ($config as $name => $value) {
$object->$name = $value;
if (!empty($config)) {
foreach ($config as $name => $value) {
$object->$name = $value;
}
}
if ($object instanceof \yii\base\Initable) {
$object->init();
}
return $object;
}
/**
@ -426,7 +455,7 @@ class YiiBase
* @param string $category the category of this log message
* @see endProfile
*/
public static function beginProfile($token, $category)
public static function beginProfile($token, $category = 'application')
{
self::getLogger()->beginProfile($token, $category);
}
@ -438,7 +467,7 @@ class YiiBase
* @param string $category the category of this log message
* @see beginProfile
*/
public static function endProfile($token, $category)
public static function endProfile($token, $category = 'application')
{
self::getLogger()->endProfile($token, $category);
}
@ -451,8 +480,7 @@ class YiiBase
{
if (self::$_logger !== null) {
return self::$_logger;
}
else {
} else {
return self::$_logger = new \yii\logging\Logger;
}
}

166
framework/base/Application.php

@ -119,15 +119,17 @@ abstract class Application extends Module
\Yii::$app = $this;
// set basePath at early as possible to avoid trouble
if (is_string($config))
if (is_string($config)) {
$config = require($config);
if (isset($config['basePath']))
{
}
if (isset($config['basePath'])) {
$this->setBasePath($config['basePath']);
unset($config['basePath']);
}
else
{
$this->setBasePath('protected');
}
\Yii::setAlias('application', $this->getBasePath());
\Yii::setAlias('webroot', dirname($_SERVER['SCRIPT_FILENAME']));
\Yii::setAlias('ext', $this->getBasePath() . DIRECTORY_SEPARATOR . 'extensions');
@ -153,11 +155,13 @@ abstract class Application extends Module
*/
public function run()
{
if ($this->hasEventHandlers('onBeginRequest'))
if ($this->hasEventHandlers('onBeginRequest')) {
$this->onBeginRequest(new CEvent($this));
}
$this->processRequest();
if ($this->hasEventHandlers('onEndRequest'))
if ($this->hasEventHandlers('onEndRequest')) {
$this->onEndRequest(new CEvent($this));
}
}
/**
@ -170,10 +174,12 @@ abstract class Application extends Module
*/
public function end($status = 0, $exit = true)
{
if ($this->hasEventHandlers('onEndRequest'))
if ($this->hasEventHandlers('onEndRequest')) {
$this->onEndRequest(new CEvent($this));
if ($exit)
}
if ($exit) {
exit($status);
}
}
/**
@ -191,8 +197,7 @@ abstract class Application extends Module
*/
public function onEndRequest($event)
{
if (!$this->_ended)
{
if (!$this->_ended) {
$this->_ended = true;
$this->raiseEvent('onEndRequest', $event);
}
@ -204,10 +209,13 @@ abstract class Application extends Module
*/
public function getId()
{
if ($this->_id !== null)
if ($this->_id !== null) {
return $this->_id;
}
else
{
return $this->_id = sprintf('%x', crc32($this->getBasePath() . $this->name));
}
}
/**
@ -236,9 +244,10 @@ abstract class Application extends Module
*/
public function setBasePath($path)
{
if (($this->_basePath = realpath($path)) === false || !is_dir($this->_basePath))
if (($this->_basePath = realpath($path)) === false || !is_dir($this->_basePath)) {
throw new \yii\base\Exception(\Yii::t('yii', 'Application base path "{path}" is not a valid directory.',
array('{path}' => $path)));
}
}
/**
@ -247,8 +256,9 @@ abstract class Application extends Module
*/
public function getRuntimePath()
{
if ($this->_runtimePath !== null)
if ($this->_runtimePath !== null) {
return $this->_runtimePath;
}
else
{
$this->setRuntimePath($this->getBasePath() . DIRECTORY_SEPARATOR . 'runtime');
@ -263,9 +273,10 @@ abstract class Application extends Module
*/
public function setRuntimePath($path)
{
if (($runtimePath = realpath($path)) === false || !is_dir($runtimePath) || !is_writable($runtimePath))
if (($runtimePath = realpath($path)) === false || !is_dir($runtimePath) || !is_writable($runtimePath)) {
throw new \yii\base\Exception(\Yii::t('yii', 'Application runtime path "{path}" is not valid. Please make sure it is a directory writable by the Web server process.',
array('{path}' => $path)));
}
$this->_runtimePath = $runtimePath;
}
@ -284,9 +295,10 @@ abstract class Application extends Module
*/
public function setExtensionPath($path)
{
if (($extensionPath = realpath($path)) === false || !is_dir($extensionPath))
if (($extensionPath = realpath($path)) === false || !is_dir($extensionPath)) {
throw new \yii\base\Exception(\Yii::t('yii', 'Extension path "{path}" does not exist.',
array('{path}' => $path)));
}
\Yii::setAlias('ext', $extensionPath);
}
@ -359,12 +371,15 @@ abstract class Application extends Module
*/
public function findLocalizedFile($srcFile, $srcLanguage = null, $language = null)
{
if ($srcLanguage === null)
if ($srcLanguage === null) {
$srcLanguage = $this->sourceLanguage;
if ($language === null)
}
if ($language === null) {
$language = $this->getLanguage();
if ($language === $srcLanguage)
}
if ($language === $srcLanguage) {
return $srcFile;
}
$desiredFile = dirname($srcFile) . DIRECTORY_SEPARATOR . $language . DIRECTORY_SEPARATOR . basename($srcFile);
return is_file($desiredFile) ? $desiredFile : $srcFile;
}
@ -528,10 +543,13 @@ abstract class Application extends Module
public function createAbsoluteUrl($route, $params = array(), $schema = '', $ampersand = '&')
{
$url = $this->createUrl($route, $params, $ampersand);
if (strpos($url, 'http') === 0)
if (strpos($url, 'http') === 0) {
return $url;
}
else
{
return $this->getRequest()->getHostInfo($schema) . $url;
}
}
/**
@ -552,15 +570,19 @@ abstract class Application extends Module
*/
public function getHomeUrl()
{
if ($this->_homeUrl === null)
{
if ($this->getUrlManager()->showScriptName)
if ($this->_homeUrl === null) {
if ($this->getUrlManager()->showScriptName) {
return $this->getRequest()->getScriptUrl();
}
else
{
return $this->getRequest()->getBaseUrl() . '/';
}
}
else
{
return $this->_homeUrl;
}
}
/**
@ -582,12 +604,16 @@ abstract class Application extends Module
*/
public function getGlobalState($key, $defaultValue = null)
{
if ($this->_globalState === null)
if ($this->_globalState === null) {
$this->loadGlobalState();
if (isset($this->_globalState[$key]))
}
if (isset($this->_globalState[$key])) {
return $this->_globalState[$key];
}
else
{
return $defaultValue;
}
}
/**
@ -602,14 +628,13 @@ abstract class Application extends Module
*/
public function setGlobalState($key, $value, $defaultValue = null)
{
if ($this->_globalState === null)
if ($this->_globalState === null) {
$this->loadGlobalState();
}
$changed = $this->_stateChanged;
if ($value === $defaultValue)
{
if (isset($this->_globalState[$key]))
{
if ($value === $defaultValue) {
if (isset($this->_globalState[$key])) {
unset($this->_globalState[$key]);
$this->_stateChanged = true;
}
@ -620,8 +645,9 @@ abstract class Application extends Module
$this->_stateChanged = true;
}
if ($this->_stateChanged !== $changed)
if ($this->_stateChanged !== $changed) {
$this->attachEventHandler('onEndRequest', array($this, 'saveGlobalState'));
}
}
/**
@ -643,8 +669,9 @@ abstract class Application extends Module
public function loadGlobalState()
{
$persister = $this->getStatePersister();
if (($this->_globalState = $persister->load()) === null)
if (($this->_globalState = $persister->load()) === null) {
$this->_globalState = array();
}
$this->_stateChanged = false;
$this->detachEventHandler('onEndRequest', array($this, 'saveGlobalState'));
}
@ -656,8 +683,7 @@ abstract class Application extends Module
*/
public function saveGlobalState()
{
if ($this->_stateChanged)
{
if ($this->_stateChanged) {
$this->_stateChanged = false;
$this->detachEventHandler('onEndRequest', array($this, 'saveGlobalState'));
$this->getStatePersister()->save($this->_globalState);
@ -685,12 +711,14 @@ abstract class Application extends Module
restore_exception_handler();
$category = 'exception.' . get_class($exception);
if ($exception instanceof \yii\web\HttpException)
if ($exception instanceof \yii\web\HttpException) {
$category .= '.' . $exception->statusCode;
}
// php <5.2 doesn't support string conversion auto-magically
$message = $exception->__toString();
if (isset($_SERVER['REQUEST_URI']))
if (isset($_SERVER['REQUEST_URI'])) {
$message .= ' REQUEST_URI=' . $_SERVER['REQUEST_URI'];
}
\Yii::error($message, $category);
try
@ -699,11 +727,9 @@ abstract class Application extends Module
//$event = new CExceptionEvent($this, $exception);
$event = new Event($this, array('exception' => $exception));
$this->onException($event);
if (!$event->handled)
{
if (!$event->handled) {
// try an error handler
if (($handler = $this->getErrorHandler()) !== null)
{
if (($handler = $this->getErrorHandler()) !== null) {
$handler->handle($event);
}
else
@ -712,7 +738,7 @@ abstract class Application extends Module
}
}
}
catch(Exception $e)
catch (Exception $e)
{
$this->displayException($e);
}
@ -721,7 +747,7 @@ abstract class Application extends Module
{
$this->end(1);
}
catch(Exception $e)
catch (Exception $e)
{
// use the most primitive way to log error
$msg = get_class($e) . ': ' . $e->getMessage() . ' (' . $e->getFile() . ':' . $e->getLine() . ")\n";
@ -754,8 +780,7 @@ abstract class Application extends Module
*/
public function handleError($code, $message, $file, $line)
{
if ($code & error_reporting())
{
if ($code & error_reporting()) {
// disable error capturing to avoid recursive errors
restore_error_handler();
restore_exception_handler();
@ -763,23 +788,29 @@ abstract class Application extends Module
$log = "$message ($file:$line)\nStack trace:\n";
$trace = debug_backtrace();
// skip the first 3 stacks as they do not tell the error position
if (count($trace) > 3)
if (count($trace) > 3) {
$trace = array_slice($trace, 3);
}
foreach ($trace as $i => $t)
{
if (!isset($t['file']))
if (!isset($t['file'])) {
$t['file'] = 'unknown';
if (!isset($t['line']))
}
if (!isset($t['line'])) {
$t['line'] = 0;
if (!isset($t['function']))
}
if (!isset($t['function'])) {
$t['function'] = 'unknown';
}
$log .= "#$i {$t['file']}( {$t['line']}): ";
if (isset($t['object']) && is_object($t['object']))
if (isset($t['object']) && is_object($t['object'])) {
$log .= get_class($t['object']) . '->';
}
$log .= " {$t['function']}()\n";
}
if (isset($_SERVER['REQUEST_URI']))
if (isset($_SERVER['REQUEST_URI'])) {
$log .= 'REQUEST_URI=' . $_SERVER['REQUEST_URI'];
}
\Yii::error($log, 'php');
try
@ -787,16 +818,18 @@ abstract class Application extends Module
\Yii::import('CErrorEvent', true);
$event = new CErrorEvent($this, $code, $message, $file, $line);
$this->onError($event);
if (!$event->handled)
{
if (!$event->handled) {
// try an error handler
if (($handler = $this->getErrorHandler()) !== null)
if (($handler = $this->getErrorHandler()) !== null) {
$handler->handle($event);
}
else
{
$this->displayError($code, $message, $file, $line);
}
}
}
catch(Exception $e)
catch (Exception $e)
{
$this->displayException($e);
}
@ -805,7 +838,7 @@ abstract class Application extends Module
{
$this->end(1);
}
catch(Exception $e)
catch (Exception $e)
{
// use the most primitive way to log error
$msg = get_class($e) . ': ' . $e->getMessage() . ' (' . $e->getFile() . ':' . $e->getLine() . ")\n";
@ -860,27 +893,31 @@ abstract class Application extends Module
*/
public function displayError($code, $message, $file, $line)
{
if (YII_DEBUG)
{
if (YII_DEBUG) {
echo "<h1>PHP Error [$code]</h1>\n";
echo "<p>$message ($file:$line)</p>\n";
echo '<pre>';
$trace = debug_backtrace();
// skip the first 3 stacks as they do not tell the error position
if (count($trace) > 3)
if (count($trace) > 3) {
$trace = array_slice($trace, 3);
}
foreach ($trace as $i => $t)
{
if (!isset($t['file']))
if (!isset($t['file'])) {
$t['file'] = 'unknown';
if (!isset($t['line']))
}
if (!isset($t['line'])) {
$t['line'] = 0;
if (!isset($t['function']))
}
if (!isset($t['function'])) {
$t['function'] = 'unknown';
}
echo "#$i {$t['file']}( {$t['line']}): ";
if (isset($t['object']) && is_object($t['object']))
if (isset($t['object']) && is_object($t['object'])) {
echo get_class($t['object']) . '->';
}
echo " {$t['function']}()\n";
}
@ -901,8 +938,7 @@ abstract class Application extends Module
*/
public function displayException($exception)
{
if (YII_DEBUG)
{
if (YII_DEBUG) {
echo '<h1>' . get_class($exception) . "</h1>\n";
echo '<p>' . $exception->getMessage() . ' (' . $exception->getFile() . ':' . $exception->getLine() . ')</p>';
echo '<pre>' . $exception->getTraceAsString() . '</pre>';
@ -919,10 +955,12 @@ abstract class Application extends Module
*/
protected function initSystemHandlers()
{
if (YII_ENABLE_EXCEPTION_HANDLER)
if (YII_ENABLE_EXCEPTION_HANDLER) {
set_exception_handler(array($this, 'handleException'));
if (YII_ENABLE_ERROR_HANDLER)
}
if (YII_ENABLE_ERROR_HANDLER) {
set_error_handler(array($this, 'handleError'), error_reporting());
}
}
/**

4
framework/base/Behavior.php

@ -47,8 +47,8 @@ class Behavior extends Object
*
* ~~~
* array(
* 'onBeforeValidate' => 'myBeforeValidate',
* 'onAfterValidate' => 'myAfterValidate',
* 'onBeforeValidate' => 'myBeforeValidate',
* 'onAfterValidate' => 'myAfterValidate',
* )
* ~~~
*

80
framework/base/Component.php

@ -22,7 +22,7 @@ namespace yii\base;
* ~~~
* public function onClick($event)
* {
* $this->raiseEvent('onClick', $event);
* $this->raiseEvent('onClick', $event);
* }
* ~~~
*
@ -54,8 +54,8 @@ namespace yii\base;
*
* ~~~
* $component->onClick->insertAt(0, $callback); // attach a handler as the first one
* $component->onClick[] = $callback; // attach a handler as the last one
* unset($component->onClick[0]); // detach the first handler
* $component->onClick[] = $callback; // attach a handler as the last one
* unset($component->onClick[0]); // detach the first handler
* ~~~
*
*
@ -98,15 +98,18 @@ class Component extends Object
$getter = 'get' . $name;
if (method_exists($this, $getter)) { // read property, e.g. getName()
return $this->$getter();
} elseif (method_exists($this, $name) && strncasecmp($name, 'on', 2) === 0) { // event, e.g. onClick()
}
elseif (method_exists($this, $name) && strncasecmp($name, 'on', 2) === 0) { // event, e.g. onClick()
$name = strtolower($name);
if (!isset($this->_e[$name])) {
$this->_e[$name] = new Vector;
}
return $this->_e[$name];
} elseif (isset($this->_b[$name])) { // behavior
}
elseif (isset($this->_b[$name])) { // behavior
return $this->_b[$name];
} elseif (is_array($this->_b)) { // a behavior property
}
elseif (is_array($this->_b)) { // a behavior property
foreach ($this->_b as $object) {
if ($object->canGetProperty($name)) {
return $object->$name;
@ -135,15 +138,17 @@ class Component extends Object
public function __set($name, $value)
{
$setter = 'set' . $name;
if (method_exists($this, $setter)) { // write property
if (method_exists($this, $setter)) { // write property
return $this->$setter($value);
} elseif (method_exists($this, $name) && strncasecmp($name, 'on', 2) === 0) { // event
}
elseif (method_exists($this, $name) && strncasecmp($name, 'on', 2) === 0) { // event
$name = strtolower($name);
if (!isset($this->_e[$name])) {
$this->_e[$name] = new Vector;
}
return $this->_e[$name]->add($value);
} elseif (is_array($this->_b)) { // behavior
}
elseif (is_array($this->_b)) { // behavior
foreach ($this->_b as $object) {
if ($object->canSetProperty($name)) {
return $object->$name = $value;
@ -152,7 +157,8 @@ class Component extends Object
}
if (method_exists($this, 'get' . $name)) {
throw new Exception('Setting read-only property: ' . get_class($this) . '.' . $name);
} else {
}
else {
throw new Exception('Setting unknown property: ' . get_class($this) . '.' . $name);
}
}
@ -175,12 +181,15 @@ class Component extends Object
$getter = 'get' . $name;
if (method_exists($this, $getter)) { // property is not null
return $this->$getter() !== null;
} elseif (method_exists($this, $name) && strncasecmp($name, 'on', 2) === 0) { // has event handler
}
elseif (method_exists($this, $name) && strncasecmp($name, 'on', 2) === 0) { // has event handler
$name = strtolower($name);
return isset($this->_e[$name]) && $this->_e[$name]->getCount();
} elseif (isset($this->_b[$name])) { // has behavior
return true;
} elseif (is_array($this->_b)) {
}
elseif (isset($this->_b[$name])) { // has behavior
return true;
}
elseif (is_array($this->_b)) {
foreach ($this->_b as $object) {
if ($object->canGetProperty($name)) {
return $object->$name !== null;
@ -206,14 +215,17 @@ class Component extends Object
public function __unset($name)
{
$setter = 'set' . $name;
if (method_exists($this, $setter)) { // write property
if (method_exists($this, $setter)) { // write property
return $this->$setter(null);
} elseif (method_exists($this, $name) && strncasecmp($name, 'on', 2) === 0) { // event
}
elseif (method_exists($this, $name) && strncasecmp($name, 'on', 2) === 0) { // event
unset($this->_e[strtolower($name)]);
return;
} elseif (isset($this->_b[$name])) { // behavior
}
elseif (isset($this->_b[$name])) { // behavior
return $this->detachBehavior($name);
} elseif (is_array($this->_b)) { // behavior property
}
elseif (is_array($this->_b)) { // behavior property
foreach ($this->_b as $object) {
if ($object->canSetProperty($name)) {
return $object->$name = null;
@ -266,7 +278,7 @@ class Component extends Object
*/
public function hasEvent($name)
{
return method_exists($this, $name) && strncasecmp($name, 'on', 2)===0;
return method_exists($this, $name) && strncasecmp($name, 'on', 2) === 0;
}
/**
@ -318,10 +330,10 @@ class Component extends Object
* some examples:
*
* ~~~
* 'handleOnClick' // handleOnClick() is a global function
* array($object, 'handleOnClick') // $object->handleOnClick()
* array('Page', 'handleOnClick') // Page::handleOnClick()
* function($event) { ... } // anonymous function
* 'handleOnClick' // handleOnClick() is a global function
* array($object, 'handleOnClick') // $object->handleOnClick()
* array('Page', 'handleOnClick') // Page::handleOnClick()
* function($event) { ... } // anonymous function
* ~~~
*
* An event handler must be defined with the following signature,
@ -374,17 +386,21 @@ class Component extends Object
foreach ($this->_e[$name] as $handler) {
if (is_string($handler) || $handler instanceof \Closure) {
call_user_func($handler, $event);
} elseif (is_callable($handler, true)) {
}
elseif (is_callable($handler, true)) {
// an array: 0 - object, 1 - method name
list($object, $method) = $handler;
if (is_string($object)) { // static method call
if (is_string($object)) { // static method call
call_user_func($handler, $event);
} elseif (method_exists($object, $method)) {
}
elseif (method_exists($object, $method)) {
$object->$method($event);
} else {
}
else {
throw new Exception('Event "' . get_class($this) . '.' . $name . '" is attached with an invalid handler.');
}
} else {
}
else {
throw new Exception('Event "' . get_class($this) . '.' . $name . '" is attached with an invalid handler.');
}
@ -393,7 +409,8 @@ class Component extends Object
return;
}
}
} elseif (!$this->hasEvent($name)) {
}
elseif (!$this->hasEvent($name)) {
throw new Exception('Raising unknown event: ' . get_class($this) . '.' . $name);
}
}
@ -419,16 +436,15 @@ class Component extends Object
*
* - a [[Behavior]] object
* - a string specifying the behavior class
* - an object configuration array
* - an object configuration array that will be passed to [[\Yii::createObject]] to create the behavior object.
*
* parameter to [[\Yii::create]] to create the behavior object.
* @return Behavior the behavior object
* @see detachBehavior
*/
public function attachBehavior($name, $behavior)
{
if (!($behavior instanceof Behavior)) {
$behavior = \Yii::create($behavior);
$behavior = \Yii::createObject($behavior);
}
$behavior->attach($this);
return $this->_b[$name] = $behavior;

52
framework/base/Dictionary.php

@ -21,11 +21,11 @@ namespace yii\base;
* like a regular PHP array as follows,
*
* ~~~
* $dictionary[$key] = $value; // add a key-value pair
* unset($dictionary[$key]); // remove the value with the specified key
* if (isset($dictionary[$key])) // if the dictionary contains the key
* $dictionary[$key] = $value; // add a key-value pair
* unset($dictionary[$key]); // remove the value with the specified key
* if (isset($dictionary[$key])) // if the dictionary contains the key
* foreach ($dictionary as $key=>$value) // traverse the items in the dictionary
* $n = count($dictionary); // returns the number of items in the dictionary
* $n = count($dictionary); // returns the number of items in the dictionary
* ~~~
*
* @author Qiang Xue <qiang.xue@gmail.com>
@ -114,7 +114,8 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co
{
if ($key === null) {
$this->_d[] = $value;
} else {
}
else {
$this->_d[$key] = $value;
}
}
@ -131,7 +132,8 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co
$value = $this->_d[$key];
unset($this->_d[$key]);
return $value;
} else { // the value is null
}
else { // the value is null
unset($this->_d[$key]);
return null;
}
@ -149,7 +151,8 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co
foreach (array_keys($this->_d) as $key) {
$this->remove($key);
}
} else {
}
else {
$this->_d = array();
}
}
@ -181,8 +184,7 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co
*/
public function copyFrom($data)
{
if (is_array($data) || $data instanceof \Traversable)
{
if (is_array($data) || $data instanceof \Traversable) {
if ($this->_d !== array()) {
$this->clear();
}
@ -192,7 +194,8 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co
foreach ($data as $key => $value) {
$this->add($key, $value);
}
} else {
}
else {
throw new Exception('Data must be either an array or an object implementing Traversable.');
}
}
@ -214,7 +217,7 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co
*
* @throws CException If data is neither an array nor an iterator.
*/
public function mergeWith($data, $recursive=true)
public function mergeWith($data, $recursive = true)
{
if (is_array($data) || $data instanceof \Traversable) {
if ($data instanceof self) {
@ -222,20 +225,23 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co
}
if ($recursive) {
if ($data instanceof \Traversable) {
$d=array();
foreach($data as $key => $value) {
$d = array();
foreach ($data as $key => $value) {
$d[$key] = $value;
}
$this->_d = self::mergeArray($this->_d, $d);
} else {
}
else {
$this->_d = self::mergeArray($this->_d, $data);
}
} else {
foreach($data as $key => $value) {
}
else {
foreach ($data as $key => $value) {
$this->add($key, $value);
}
}
} else {
}
else {
throw new Exception('Dictionary data must be an array or an object implementing Traversable.');
}
}
@ -278,7 +284,7 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co
*/
public function offsetSet($offset, $item)
{
$this->add($offset,$item);
$this->add($offset, $item);
}
/**
@ -308,12 +314,14 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co
*/
public static function mergeArray($a, $b)
{
foreach($b as $k=>$v) {
if(is_integer($k)) {
foreach ($b as $k => $v) {
if (is_integer($k)) {
isset($a[$k]) ? $a[] = $v : $a[$k] = $v;
} elseif(is_array($v) && isset($a[$k]) && is_array($a[$k])) {
}
elseif (is_array($v) && isset($a[$k]) && is_array($a[$k])) {
$a[$k] = self::mergeArray($a[$k], $v);
} else {
}
else {
$a[$k] = $v;
}
}

2
framework/base/Event.php

@ -51,7 +51,7 @@ class Event extends Object
* @param mixed $sender sender of the event
* @param mixed $params parameters of the event
*/
public function __construct($sender=null, $params=null)
public function __construct($sender = null, $params = null)
{
$this->sender = $sender;
$this->params = $params;

4
framework/base/Initable.php

@ -13,7 +13,7 @@ namespace yii\base;
* Initable is an interface indicating a class needs initialization to work properly.
*
* Initable requires a class to implement the [[init]] method.
* When [[\Yii::create]] is being used to create a new component which implements
* When [[\Yii::createObject]] is being used to create a new component which implements
* Initable, it will call the [[init]] method after setting the initial values of the
* component properties.
*
@ -24,7 +24,7 @@ interface Initable
{
/**
* Initializes this component.
* This method is invoked by [[\Yii::create]] after its creates the new
* This method is invoked by [[\Yii::createObject]] after its creates the new
* component instance and initializes the component properties. In other words,
* at this stage, the component has been fully configured.
*/

75
framework/base/Model.php

@ -35,15 +35,15 @@ namespace yii\base;
class Model extends Component implements Initable, \IteratorAggregate, \ArrayAccess
{
private static $_attributes = array(); // class name => array of attribute names
private $_errors; // attribute name => array of errors
private $_validators; // validators
private $_scenario; // scenario
private $_errors; // attribute name => array of errors
private $_validators; // validators
private $_scenario; // scenario
/**
* Constructor.
* @param string $scenario name of the [[scenario]] that this model is used in.
*/
public function __construct($scenario='')
public function __construct($scenario = '')
{
$this->_scenario = $scenario;
$this->afterConstruct();
@ -52,7 +52,7 @@ class Model extends Component implements Initable, \IteratorAggregate, \ArrayAcc
/**
* Initializes this model.
*
* This method is required by the [[Initable]] interface. It is invoked by [[\Yii::create]]
* This method is required by the [[Initable]] interface. It is invoked by [[\Yii::createObject]]
* after it creates the new model instance and initializes the model properties.
*
* The default implementation calls [[behaviors]] and registers any available behaviors.
@ -72,9 +72,9 @@ class Model extends Component implements Initable, \IteratorAggregate, \ArrayAcc
*
* ~~~
* 'behaviorName' => array(
* 'class' => 'BehaviorClass',
* 'property1' => 'value1',
* 'property2' => 'value2',
* 'class' => 'BehaviorClass',
* 'property1' => 'value1',
* 'property2' => 'value2',
* )
* ~~~
*
@ -123,10 +123,10 @@ class Model extends Component implements Initable, \IteratorAggregate, \ArrayAcc
*
* ~~~
* array(
* 'attribute list',
* 'validator type',
* 'on'=>'scenario name',
* ...other parameters...
* 'attribute list',
* 'validator type',
* 'on'=>'scenario name',
* ...other parameters...
* )
* ~~~
*
@ -134,11 +134,11 @@ class Model extends Component implements Initable, \IteratorAggregate, \ArrayAcc
*
* - attribute list: required, specifies the attributes (separated by commas) to be validated;
* - validator type: required, specifies the validator to be used. It can be the name of a model
* class method, the name of a built-in validator, or a validator class (or its path alias).
* class method, the name of a built-in validator, or a validator class (or its path alias).
* - on: optional, specifies the [[scenario|scenarios]] (separated by commas) when the validation
* rule can be applied. If this option is not set, the rule will apply to any scenario.
* rule can be applied. If this option is not set, the rule will apply to any scenario.
* - additional name-value pairs can be specified to initialize the corresponding validator properties.
* Please refer to individual validator class API for possible properties.
* Please refer to individual validator class API for possible properties.
*
* A validator can be either a model class method or an object.
* If the former, the method must have the following signature:
@ -156,10 +156,10 @@ class Model extends Component implements Initable, \IteratorAggregate, \ArrayAcc
*
* ~~~
* array(
* array('username', 'required'),
* array('username', 'length', 'min'=>3, 'max'=>12),
* array('password', 'compare', 'compareAttribute'=>'password2', 'on'=>'register'),
* array('password', 'authenticate', 'on'=>'login'),
* array('username', 'required'),
* array('username', 'length', 'min'=>3, 'max'=>12),
* array('password', 'compare', 'compareAttribute'=>'password2', 'on'=>'register'),
* array('password', 'authenticate', 'on'=>'login'),
* );
* ~~~
*
@ -364,10 +364,11 @@ class Model extends Component implements Initable, \IteratorAggregate, \ArrayAcc
{
$validators = new Vector;
foreach ($this->rules() as $rule) {
if (isset($rule[0], $rule[1])) { // attributes, validator type
if (isset($rule[0], $rule[1])) { // attributes, validator type
$validator = \yii\validators\Validator::createValidator($rule[1], $this, $rule[0], array_slice($rule, 2));
$validators->add($validator);
} else {
}
else {
throw new Exception('Invalid validation rule: a rule must specify both attribute names and validator type.');
}
}
@ -439,13 +440,13 @@ class Model extends Component implements Initable, \IteratorAggregate, \ArrayAcc
*
* ~~~
* array(
* 'username' => array(
* 'Username is required.',
* 'Username must contain only word characters.',
* ),
* 'email' => array(
* 'Email address is invalid.',
* )
* 'username' => array(
* 'Username is required.',
* 'Username must contain only word characters.',
* ),
* 'email' => array(
* 'Email address is invalid.',
* )
* )
* ~~~
*
@ -455,7 +456,8 @@ class Model extends Component implements Initable, \IteratorAggregate, \ArrayAcc
{
if ($attribute === null) {
return $this->_errors === null ? array() : $this->_errors;
} else {
}
else {
return isset($this->_errors[$attribute]) ? $this->_errors[$attribute] : array();
}
}
@ -494,7 +496,8 @@ class Model extends Component implements Initable, \IteratorAggregate, \ArrayAcc
foreach ($error as $e) {
$this->_errors[$attribute][] = $e;
}
} else {
}
else {
$this->_errors[$attribute][] = $error;
}
}
@ -508,7 +511,8 @@ class Model extends Component implements Initable, \IteratorAggregate, \ArrayAcc
{
if ($attribute === null) {
$this->_errors = array();
} else {
}
else {
unset($this->_errors[$attribute]);
}
}
@ -543,7 +547,8 @@ class Model extends Component implements Initable, \IteratorAggregate, \ArrayAcc
$values[$name] = $this->$name;
}
}
} else {
}
else {
foreach ($this->attributeNames() as $name) {
$values[$name] = $this->$name;
}
@ -567,7 +572,8 @@ class Model extends Component implements Initable, \IteratorAggregate, \ArrayAcc
foreach ($values as $name => $value) {
if (isset($attributes[$name])) {
$this->$name = $value;
} elseif ($safeOnly) {
}
elseif ($safeOnly) {
$this->onUnsafeAttribute($name, $value);
}
}
@ -633,7 +639,8 @@ class Model extends Component implements Initable, \IteratorAggregate, \ArrayAcc
foreach ($validator->attributes as $name) {
$unsafe[] = $name;
}
} else {
}
else {
foreach ($validator->attributes as $name) {
$attributes[$name] = true;
}

99
framework/base/Module.php

@ -59,10 +59,10 @@ abstract class Module extends Component
$this->_parentModule = $parent;
// set basePath at early as possible to avoid trouble
if (is_string($config))
if (is_string($config)) {
$config = require($config);
if (isset($config['basePath']))
{
}
if (isset($config['basePath'])) {
$this->setBasePath($config['basePath']);
unset($config['basePath']);
}
@ -139,7 +139,7 @@ abstract class Module extends Component
*/
public function setId($id)
{
$this->_id=$id;
$this->_id = $id;
}
/**
@ -216,8 +216,8 @@ abstract class Module extends Component
*
* ~~~
* array(
* '@models' => '@app/models', // an existing alias
* '@backend' => __DIR__ . '/../backend', // a directory
* '@models' => '@app/models', // an existing alias
* '@backend' => __DIR__ . '/../backend', // a directory
* )
* ~~~
*/
@ -246,23 +246,22 @@ abstract class Module extends Component
*/
public function getModule($id)
{
if (isset($this->_modules[$id]) || array_key_exists($id, $this->_modules))
if (isset($this->_modules[$id]) || array_key_exists($id, $this->_modules)) {
return $this->_modules[$id];
}
elseif (isset($this->_moduleConfig[$id]))
{
$config = $this->_moduleConfig[$id];
if (!isset($config['enabled']) || $config['enabled'])
{
if (!isset($config['enabled']) || $config['enabled']) {
\Yii::trace("Loading \"$id\" module", 'system.base.CModule');
$class = $config['class'];
unset($config['class'], $config['enabled']);
if ($this === \Yii::$app)
{
$module = Yii::create($class, $id, null, $config);
if ($this === \Yii::$app) {
$module = \Yii::createObject($class, $id, null, $config);
}
else
{
$module = Yii::create($class, $this->getId() . '/' . $id, $this, $config);
$module = \Yii::createObject($class, $this->getId() . '/' . $id, $this, $config);
}
return $this->_modules[$id] = $module;
}
@ -299,10 +298,10 @@ abstract class Module extends Component
* For example, the following array declares two modules:
* <pre>
* array(
* 'admin', // a single module ID
* 'payment'=>array( // ID-configuration pair
* 'server'=>'paymentserver.com',
* ),
* 'admin', // a single module ID
* 'payment'=>array( // ID-configuration pair
* 'server'=>'paymentserver.com',
* ),
* )
* </pre>
*
@ -318,21 +317,22 @@ abstract class Module extends Component
{
foreach ($modules as $id => $module)
{
if (is_int($id))
{
if (is_int($id)) {
$id = $module;
$module = array();
}
if (!isset($module['class']))
{
if (!isset($module['class'])) {
Yii::setPathOfAlias($id, $this->getModulePath() . DIRECTORY_SEPARATOR . $id);
$module['class'] = $id . '.' . ucfirst($id) . 'Module';
}
if (isset($this->_moduleConfig[$id]))
if (isset($this->_moduleConfig[$id])) {
$this->_moduleConfig[$id] = CMap::mergeArray($this->_moduleConfig[$id], $module);
}
else
{
$this->_moduleConfig[$id] = $module;
}
}
}
@ -356,16 +356,16 @@ abstract class Module extends Component
*/
public function getComponent($id, $createIfNull = true)
{
if (isset($this->_components[$id]))
if (isset($this->_components[$id])) {
return $this->_components[$id];
}
elseif (isset($this->_componentConfig[$id]) && $createIfNull)
{
$config = $this->_componentConfig[$id];
if (!isset($config['enabled']) || $config['enabled'])
{
if (!isset($config['enabled']) || $config['enabled']) {
\Yii::trace("Loading \"$id\" application component", 'system.CModule');
unset($config['enabled']);
$component = \Yii::create($config);
$component = \Yii::createObject($config);
return $this->_components[$id] = $component;
}
}
@ -381,13 +381,14 @@ abstract class Module extends Component
*/
public function setComponent($id, $component)
{
if ($component === null)
if ($component === null) {
unset($this->_components[$id]);
else
{
}
else {
$this->_components[$id] = $component;
if (!$component->getIsInitialized())
if (!$component->getIsInitialized()) {
$component->init();
}
}
}
@ -401,10 +402,12 @@ abstract class Module extends Component
*/
public function getComponents($loadedOnly = true)
{
if ($loadedOnly)
if ($loadedOnly) {
return $this->_components;
else
}
else {
return array_merge($this->_componentConfig, $this->_components);
}
}
/**
@ -421,15 +424,15 @@ abstract class Module extends Component
* The following is the configuration for two components:
* <pre>
* array(
* 'db'=>array(
* 'class'=>'CDbConnection',
* 'connectionString'=>'sqlite:path/to/file.db',
* ),
* 'cache'=>array(
* 'class'=>'CDbCache',
* 'connectionID'=>'db',
* 'enabled'=>!YII_DEBUG, // enable caching in non-debug mode
* ),
* 'db'=>array(
* 'class'=>'CDbConnection',
* 'connectionString'=>'sqlite:path/to/file.db',
* ),
* 'cache'=>array(
* 'class'=>'CDbCache',
* 'connectionID'=>'db',
* 'enabled'=>!YII_DEBUG, // enable caching in non-debug mode
* ),
* )
* </pre>
*
@ -442,12 +445,17 @@ abstract class Module extends Component
{
foreach ($components as $id => $component)
{
if ($component instanceof IApplicationComponent)
if ($component instanceof IApplicationComponent) {
$this->setComponent($id, $component);
}
elseif (isset($this->_componentConfig[$id]) && $merge)
{
$this->_componentConfig[$id] = CMap::mergeArray($this->_componentConfig[$id], $component);
}
else
{
$this->_componentConfig[$id] = $component;
}
}
}
@ -457,10 +465,11 @@ abstract class Module extends Component
*/
public function configure($config)
{
if (is_array($config))
{
if (is_array($config)) {
foreach ($config as $key => $value)
{
$this->$key = $value;
}
}
}
@ -470,7 +479,9 @@ abstract class Module extends Component
public function preloadComponents()
{
foreach ($this->preload as $id)
{
$this->getComponent($id);
}
}
/**

124
framework/base/Object.php

@ -21,12 +21,12 @@ namespace yii\base;
*
* public function getLabel()
* {
* return $this->_label;
* return $this->_label;
* }
*
* public function setLabel($value)
* {
* $this->_label = $value;
* $this->_label = $value;
* }
* ~~~
*
@ -85,7 +85,8 @@ class Object
$getter = 'get' . $name;
if (method_exists($this, $getter)) {
return $this->$getter();
} else {
}
else {
throw new Exception('Getting unknown property: ' . get_class($this) . '.' . $name);
}
}
@ -105,9 +106,11 @@ class Object
$setter = 'set' . $name;
if (method_exists($this, $setter)) {
$this->$setter($value);
} elseif (method_exists($this, 'get' . $name)) {
}
elseif (method_exists($this, 'get' . $name)) {
throw new Exception('Setting read-only property: ' . get_class($this) . '.' . $name);
} else {
}
else {
throw new Exception('Setting unknown property: ' . get_class($this) . '.' . $name);
}
}
@ -127,7 +130,8 @@ class Object
$getter = 'get' . $name;
if (method_exists($this, $getter)) { // property is not null
return $this->$getter() !== null;
} else {
}
else {
return false;
}
}
@ -146,9 +150,10 @@ class Object
public function __unset($name)
{
$setter = 'set' . $name;
if (method_exists($this, $setter)) { // write property
if (method_exists($this, $setter)) { // write property
$this->$setter(null);
} elseif (method_exists($this, 'get' . $name)) {
}
elseif (method_exists($this, 'get' . $name)) {
throw new Exception('Unsetting read-only property: ' . get_class($this) . '.' . $name);
}
}
@ -244,74 +249,107 @@ class Object
* @param array $_data_ additional parameters to be passed to the above expression/callback.
* @return mixed the expression result
*/
public function evaluateExpression($_expression_, $_data_=array())
public function evaluateExpression($_expression_, $_data_ = array())
{
if (is_string($_expression_)) {
extract($_data_);
return eval('return ' . $_expression_ . ';');
} else {
}
else {
$_data_[] = $this;
return call_user_func_array($_expression_, $_data_);
}
}
/**
* Creates a new object instance.
*
* This method calls [[\Yii::create]] to create the new object instance.
*
* This method differs from the PHP `new` operator in that it does the following
* steps to create a new object instance:
*
* - Call class constructor (same as the `new` operator);
* - Initialize the object properties using the name-value pairs given as the
* last parameter to this method;
* - Call [[Initable::init|init]] if the class implements [[Initable]].
* Creates a new instance of the calling class.
*
* Parameters passed to this method will be used as the parameters to the object
* constructor.
*
* Additionally, one can pass in an associative array as the last parameter to
* this method. This method will treat the array as name-value pairs that initialize
* the corresponding object properties. For example,
* This method does the following steps to create a object:
*
* - create the object using the PHP `new` operator;
* - if [[Yii::objectConfig]] contains the configuration for the object class,
* initialize the object properties with that configuration;
* - if the number of the given parameters is more than the number of the parameters
* listed in the object constructor and the last given parameter is an array,
* initialize the object properties using that array;
* - call the `init` method of the object if it implements the [[yii\base\Initable]] interface.
*
* For example,
*
* ~~~
* class Foo extends \yii\base\Object
* class Foo extends \yii\base\Object implements \yii\base\Initable
* {
* public $c;
* public function __construct($a, $b)
* {
* ...
* }
* public $c;
* public function __construct($a, $b)
* {
* ...
* }
* public function init()
* {
* ...
* }
* }
*
* $model = Foo::create(1, 2, array('c' => 3));
* $model = Foo::newInstance(1, 2, array('c' => 3));
* // which is equivalent to the following lines:
* $model = new Foo(1, 2);
* $model->c = 3;
* $model->init();
* ~~~
*
* @return object the created object
* @throws Exception if the configuration is invalid.
*/
public static function create()
public static function newInstance()
{
$class = '\\' . get_called_class();
$c = get_called_class();
$class = '\\' . $c;
if (($n = func_num_args()) > 0) {
$args = func_get_args();
if (is_array($args[$n-1])) {
// the last parameter could be configuration array
if (is_array($args[$n - 1])) {
$method = new \ReflectionMethod($class, '__construct');
if ($method->getNumberOfParameters()+1 == $n) {
$config = $args[$n-1];
array_pop($args);
if ($method->getNumberOfParameters() < $n) {
// the last EXTRA parameter is a configuration array
$config = $args[--$n];
unset($args[$n]);
}
}
$config['class'] = $class;
array_unshift($args, $config);
return call_user_func_array('\Yii::create', $args);
} else {
return \Yii::create($class);
}
if ($n === 0) {
$object = new $class;
}
elseif ($n === 1) {
$object = new $class($args[0]);
}
elseif ($n === 2) {
$object = new $class($args[0], $args[1]);
}
elseif ($n === 3) {
$object = new $class($args[0], $args[1], $args[2]);
}
else {
$r = new \ReflectionClass($class);
$object = $r->newInstanceArgs($args);
}
if (isset(\Yii::$objectConfig[$c])) {
$config = isset($config) ? array_merge(\Yii::$objectConfig[$c], $config) : \Yii::$objectConfig[$c];
}
if (!empty($config)) {
foreach ($config as $name => $value) {
$object->$name = $value;
}
}
if ($object instanceof \yii\base\Initable) {
$object->init();
}
return $object;
}
}

47
framework/base/Vector.php

@ -22,12 +22,12 @@ namespace yii\base;
* like a regular PHP array as follows,
*
* ~~~
* $vector[] = $item; // append new item at the end
* $vector[$index] = $item; // set new item at $index
* unset($vector[$index]); // remove the item at $index
* if (isset($vector[$index])) // if the vector has an item at $index
* $vector[] = $item; // append new item at the end
* $vector[$index] = $item; // set new item at $index
* unset($vector[$index]); // remove the item at $index
* if (isset($vector[$index])) // if the vector has an item at $index
* foreach ($vector as $index=>$item) // traverse each item in the vector
* $n = count($vector); // count the number of items
* $n = count($vector); // count the number of items
* ~~~
*
* Note that if you plan to extend Vector by performing additional operations
@ -103,9 +103,11 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
{
if (isset($this->_d[$index])) {
return $this->_d[$index];
} elseif ($index >= 0 && $index < $this->_c) { // in case the value is null
}
elseif ($index >= 0 && $index < $this->_c) { // in case the value is null
return $this->_d[$index];
} else {
}
else {
throw new Exception('Index out of range: ' . $index);
}
}
@ -119,7 +121,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
public function add($item)
{
$this->insertAt($this->_c, $item);
return $this->_c-1;
return $this->_c - 1;
}
/**
@ -134,10 +136,12 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
{
if ($index === $this->_c) {
$this->_d[$this->_c++] = $item;
} elseif ($index >= 0 && $index < $this->_c) {
}
elseif ($index >= 0 && $index < $this->_c) {
array_splice($this->_d, $index, 0, array($item));
$this->_c++;
} else {
}
else {
throw new Exception('Index out of range: ' . $index);
}
}
@ -156,7 +160,8 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
if (($index = $this->indexOf($item)) >= 0) {
$this->removeAt($index);
return $index;
} else {
}
else {
return false;
}
}
@ -173,12 +178,14 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
$this->_c--;
if ($index === $this->_c) {
return array_pop($this->_d);
} else {
}
else {
$item = $this->_d[$index];
array_splice($this->_d, $index, 1);
return $item;
}
} else {
}
else {
throw new Exception('Index out of range: ' . $index);
}
}
@ -192,10 +199,11 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
public function clear($safeClear = false)
{
if ($safeClear) {
for ($i = $this->_c-1;$i >= 0;--$i) {
for ($i = $this->_c - 1; $i >= 0; --$i) {
$this->removeAt($i);
}
} else {
}
else {
$this->_d = array();
$this->_c = 0;
}
@ -252,7 +260,8 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
foreach ($data as $item) {
$this->add($item);
}
} else {
}
else {
throw new Exception('Data must be either an array or an object implementing Traversable.');
}
}
@ -272,7 +281,8 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
foreach ($data as $item) {
$this->add($item);
}
} else {
}
else {
throw new Exception('Data must be either an array or an object implementing Traversable.');
}
}
@ -318,7 +328,8 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
{
if ($offset === null || $offset === $this->_c) {
$this->insertAt($this->_c, $item);
} else {
}
else {
$this->removeAt($offset);
$this->insertAt($offset, $item);
}

17
framework/db/dao/ColumnSchema.php

@ -86,10 +86,10 @@ class ColumnSchema extends \yii\base\Component
{
static $typeMap = array( // logical type => php type
'smallint' => 'integer',
'integer' => 'integer',
'bigint' => 'integer',
'boolean' => 'boolean',
'float' => 'double',
'integer' => 'integer',
'bigint' => 'integer',
'boolean' => 'boolean',
'float' => 'double',
);
if (isset($typeMap[$this->type])) {
if ($this->type === 'bigint') {
@ -114,9 +114,12 @@ class ColumnSchema extends \yii\base\Component
return $value;
}
switch ($this->phpType) {
case 'string': return (string)$value;
case 'integer': return (integer)$value;
case 'boolean': return (boolean)$value;
case 'string':
return (string)$value;
case 'integer':
return (integer)$value;
case 'boolean':
return (boolean)$value;
}
return $value;
}

226
framework/db/dao/Command.php

@ -38,10 +38,10 @@ use yii\db\Exception;
*
* ~~~
* $user = \Yii::app()->db->createCommand()
* ->select('username, password')
* ->from('tbl_user')
* ->where('id=:id', array(':id'=>1))
* ->queryRow();
* ->select('username, password')
* ->from('tbl_user')
* ->where('id=:id', array(':id'=>1))
* ->queryRow();
* ~~~
*
* @author Qiang Xue <qiang.xue@gmail.com>
@ -93,11 +93,13 @@ class Command extends \yii\base\Component
$this->connection = $connection;
if (is_object($query)) {
$this->query = $query;
} else {
}
else {
$this->query = new Query;
if (is_array($query)) {
$this->query->fromArray($query);
} else {
}
else {
$this->_sql = $query;
}
}
@ -161,9 +163,10 @@ class Command extends \yii\base\Component
$sql = $this->getSql();
try {
$this->pdoStatement = $this->connection->pdo->prepare($sql);
} catch(\Exception $e) {
}
catch (\Exception $e) {
\Yii::error($e->getMessage() . "\nFailed to prepare SQL: $sql", __CLASS__);
$errorInfo = $e instanceof \PDOException ? $e->errorInfo : null;
$errorInfo = $e instanceof \PDOException ? $e->errorInfo : null;
throw new Exception($e->getMessage(), (int)$e->getCode(), $errorInfo);
}
}
@ -197,11 +200,14 @@ class Command extends \yii\base\Component
$this->prepare();
if ($dataType === null) {
$this->pdoStatement->bindParam($name, $value, $this->connection->getPdoType(gettype($value)));
} elseif ($length === null) {
}
elseif ($length === null) {
$this->pdoStatement->bindParam($name, $value, $dataType);
} elseif ($driverOptions === null) {
}
elseif ($driverOptions === null) {
$this->pdoStatement->bindParam($name, $value, $dataType, $length);
} else {
}
else {
$this->pdoStatement->bindParam($name, $value, $dataType, $length, $driverOptions);
}
$this->_params[$name] =& $value;
@ -224,7 +230,8 @@ class Command extends \yii\base\Component
$this->prepare();
if ($dataType === null) {
$this->pdoStatement->bindValue($name, $value, $this->connection->getPdoType(gettype($value)));
} else {
}
else {
$this->pdoStatement->bindValue($name, $value, $dataType);
}
$this->_params[$name] = $value;
@ -248,7 +255,7 @@ class Command extends \yii\base\Component
/**
* Executes the SQL statement.
* This method is meant only for executing non-query SQL statement, such as `INSERT`, `DELETE`, `UPDATE` SQLs.
* This method should only be used for executing non-query SQL statement, such as `INSERT`, `DELETE`, `UPDATE` SQLs.
* No result set will be returned.
* @param array $params input parameters (name=>value) for the SQL execution. This is an alternative
* to [[bindValues]]. Note that if you pass parameters in this way, any previous call to [[bindParam]]
@ -263,8 +270,9 @@ class Command extends \yii\base\Component
$this->_params = array_merge($this->_params, $params);
if ($this->_params === array()) {
$paramLog = '';
} else {
$paramLog = "Parameters: " . var_export($this->_params, true);
}
else {
$paramLog = "\nParameters: " . var_export($this->_params, true);
}
\Yii::trace("Executing SQL: {$sql}{$paramLog}", __CLASS__);
@ -277,7 +285,8 @@ class Command extends \yii\base\Component
$this->prepare();
if ($params === array()) {
$this->pdoStatement->execute();
} else {
}
else {
$this->pdoStatement->execute($params);
}
$n = $this->pdoStatement->rowCount();
@ -286,7 +295,8 @@ class Command extends \yii\base\Component
\Yii::endProfile(__METHOD__ . "($sql)", __CLASS__);
}
return $n;
} catch (Exception $e) {
}
catch (Exception $e) {
if ($this->connection->enableProfiling) {
\Yii::endProfile(__METHOD__ . "($sql)", __CLASS__);
}
@ -312,13 +322,13 @@ class Command extends \yii\base\Component
}
/**
* Executes the SQL statement and returns all rows.
* Executes the SQL statement and returns ALL rows at once.
* @param array $params input parameters (name=>value) for the SQL execution. This is an alternative
* to [[bindValues]]. Note that if you pass parameters in this way, any previous call to [[bindParam]]
* or [[bindValue]] will be ignored.
* @param boolean $fetchAssociative whether each row should be returned as an associated array with
* column names as the keys or the array keys are column indexes (0-based).
* @return array all rows of the query result. Each array element is an array representing a row.
* @param mixed $fetchMode the result fetch mode. Please refer to [PHP manual](http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php)
* for valid fetch modes. If this parameter is null, the value set in [[fetchMode]] will be used.
* @return array all rows of the query result. Each array element is an array representing a row of data.
* An empty array is returned if the query results in nothing.
* @throws Exception execution failed
*/
@ -329,13 +339,14 @@ class Command extends \yii\base\Component
/**
* Executes the SQL statement and returns the first row of the result.
* This is a convenient method of {@link query} when only the first row of data is needed.
* This method is best used when only the first row of result is needed for a query.
* @param array $params input parameters (name=>value) for the SQL execution. This is an alternative
* to [[bindValues]]. Note that if you pass parameters in this way, any previous call to [[bindParam]]
* or [[bindValue]] will be ignored.
* @param boolean $fetchAssociative whether the row should be returned as an associated array with
* column names as the keys or the array keys are column indexes (0-based).
* @return mixed the first row (in terms of an array) of the query result, false if no result.
* @param mixed $fetchMode the result fetch mode. Please refer to [PHP manual](http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php)
* for valid fetch modes. If this parameter is null, the value set in [[fetchMode]] will be used.
* @return array|boolean the first row (in terms of an array) of the query result. False is returned if the query
* results in nothing.
* @throws Exception execution failed
*/
public function queryRow($params = array(), $fetchMode = null)
@ -345,12 +356,12 @@ class Command extends \yii\base\Component
/**
* Executes the SQL statement and returns the value of the first column in the first row of data.
* This is a convenient method of {@link query} when only a single scalar
* value is needed (e.g. obtaining the count of the records).
* This method is best used when only a single value is needed for a query.
* @param array $params input parameters (name=>value) for the SQL execution. This is an alternative
* to [[bindValues]]. Note that if you pass parameters in this way, any previous call to [[bindParam]]
* or [[bindValue]] will be ignored.
* @return mixed the value of the first column in the first row of the query result. False is returned if there is no value.
* @return mixed the value of the first column in the first row of the query result.
* False is returned if there is no value.
* @throws Exception execution failed
*/
public function queryScalar($params = array())
@ -366,12 +377,12 @@ class Command extends \yii\base\Component
/**
* Executes the SQL statement and returns the first column of the result.
* This is a convenient method of {@link query} when only the first column of data is needed.
* Note, the column returned will contain the first element in each row of result.
* This method is best used when only the first column of result (i.e. the first element in each row)
* is needed for a query.
* @param array $params input parameters (name=>value) for the SQL execution. This is an alternative
* to [[bindValues]]. Note that if you pass parameters in this way, any previous call to [[bindParam]]
* or [[bindValue]] will be ignored.
* @return array the first column of the query result. Empty array if no result.
* @return array the first column of the query result. Empty array is returned if the query results in nothing.
* @throws Exception execution failed
*/
public function queryColumn($params = array())
@ -380,11 +391,13 @@ class Command extends \yii\base\Component
}
/**
* Performs the actual DB query of a SQL statement.
* @param string $method method of PDOStatement to be called
* @param mixed $mode parameters to be passed to the method
* @param array $params input parameters (name=>value) for the SQL execution. This is an alternative
* to [[bindValues]]. Note that if you pass parameters in this way, any previous call to [[bindParam]]
* or [[bindValue]] will be ignored.
* @param mixed $fetchMode the result fetch mode. Please refer to [PHP manual](http://www.php.net/manual/en/function.PDOStatement-setFetchMode.php)
* for valid fetch modes. If this parameter is null, the value set in [[fetchMode]] will be used.
* @return mixed the method execution result
*/
private function queryInternal($method, $params, $fetchMode = null)
@ -395,21 +408,22 @@ class Command extends \yii\base\Component
$this->_params = array_merge($this->_params, $params);
if ($this->_params === array()) {
$paramLog = '';
} else {
$paramLog = "Parameters: " . var_export($this->_params, true);
}
else {
$paramLog = "\nParameters: " . var_export($this->_params, true);
}
\Yii::trace("Querying SQL: {$sql}{$paramLog}", __CLASS__);
$cachingEnabled = $db->queryCachingCount > 0 && $method !== ''
&& $db->queryCachingDuration >= 0
&& ($cache = \Yii::app()->getComponent($db->queryCacheID)) !== null;
if ($cachingEnabled) {
if ($db->queryCachingCount > 0 && $db->queryCachingDuration >= 0 && $method !== '') {
$cache = \Yii::app()->getComponent($db->queryCacheID);
}
if (isset($cache)) {
$db->queryCachingCount--;
$cacheKey = 'yii:dbquery' . $db->connectionString . ':' . $db->username;
$cacheKey .= ':' . $sql . ':' . $paramLog;
$cacheKey = __CLASS__ . "/{$db->dsn}/{$db->username}/$sql/$paramLog";
if (($result = $cache->get($cacheKey)) !== false) {
\Yii::trace('Query result found in cache', 'system.db.Command');
\Yii::trace('Query result found in cache', __CLASS__);
return $result;
}
}
@ -422,13 +436,15 @@ class Command extends \yii\base\Component
$this->prepare();
if ($params === array()) {
$this->pdoStatement->execute();
} else {
}
else {
$this->pdoStatement->execute($params);
}
if ($method === '') {
$result = new DataReader($this);
} else {
}
else {
if ($fetchMode === null) {
$fetchMode = $this->fetchMode;
}
@ -440,58 +456,46 @@ class Command extends \yii\base\Component
\Yii::endProfile(__METHOD__ . "($sql)", __CLASS__);
}
if ($cachingEnabled) {
if (isset($cache)) {
$cache->set($cacheKey, $result, $db->queryCachingDuration, $db->queryCachingDependency);
\Yii::trace('Saved query result in cache', __CLASS__);
}
return $result;
} catch (Exception $e) {
}
catch (Exception $e) {
if ($db->enableProfiling) {
\Yii::endProfile(__METHOD__ . "($sql)", __CLASS__);
}
$errorInfo = $e instanceof \PDOException ? $e->errorInfo : null;
$message = $e->getMessage();
\Yii::log(\Yii::t('yii', 'Command::{method}() failed: {error}. The SQL statement executed was: {sql}.',
array('{method}' => $method, '{error}' => $message, '{sql}' => $this->getSql() . $par)), CLogger::LEVEL_ERROR, 'system.db.Command');
if (YII_DEBUG) {
$message .= '. The SQL statement executed was: ' . $this->getSql() . $par;
}
throw new Exception(\Yii::t('yii', 'Command failed to execute the SQL statement: {error}',
array('{error}' => $message)), (int)$e->getCode(), $errorInfo);
\Yii::error("$message\nCommand::$method() failed: {$sql}{$paramLog}", __CLASS__);
$errorInfo = $e instanceof \PDOException ? $e->errorInfo : null;
throw new Exception($message, (int)$e->getCode(), $errorInfo);
}
}
/**
/**
* Sets the SELECT part of the query.
* @param mixed $columns the columns to be selected. Defaults to '*', meaning all columns.
* Columns can be specified in either a string (e.g. "id, name") or an array (e.g. array('id', 'name')).
* Columns can contain table prefixes (e.g. "tbl_user.id") and/or column aliases (e.g. "tbl_user.id AS user_id").
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
* @param boolean $distinct whether to use 'SELECT DISTINCT'.
* @param string $option additional option that should be appended to the 'SELECT' keyword. For example,
* in MySQL, the option 'SQL_CALC_FOUND_ROWS' can be used. This parameter is supported since version 1.1.8.
* in MySQL, the option 'SQL_CALC_FOUND_ROWS' can be used.
* @return Command the command object itself
*/
public function select($columns = '*', $option = '')
public function select($columns = '*', $distinct = false, $option = '')
{
$this->query->select = $columns;
$this->query->distinct = $distinct;
$this->query->selectOption = $option;
return $this;
}
/**
* Sets the SELECT part of the query with the DISTINCT flag turned on.
* This is the same as {@link select} except that the DISTINCT flag is turned on.
* @param mixed $columns the columns to be selected. See {@link select} for more details.
* @return Command the command object itself
*/
public function selectDistinct($columns = '*', $option = '')
{
$this->query->distinct = true;
return $this->select($columns, $option);
}
/**
* Sets the FROM part of the query.
* @param mixed $tables the table(s) to be selected from. This can be either a string (e.g. 'tbl_user')
* or an array (e.g. array('tbl_user', 'tbl_profile')) specifying one or several table names.
@ -513,32 +517,42 @@ class Command extends \yii\base\Component
* specifying the values to be bound to the query.
*
* The $conditions parameter should be either a string (e.g. 'id=1') or an array.
* If the latter, it must be of the format <code>array(operator, operand1, operand2, ...)</code>,
* If the latter, it must be in the format `array(operator, operand1, operand2, ...)`,
* where the operator can be one of the followings, and the possible operands depend on the corresponding
* operator:
* <ul>
* <li><code>and</code>: the operands should be concatenated together using AND. For example,
* array('and', 'id=1', 'id=2') will generate 'id=1 AND id=2'. If an operand is an array,
* it will be converted into a string using the same rules described here. For example,
* array('and', 'type=1', array('or', 'id=1', 'id=2')) will generate 'type=1 AND (id=1 OR id=2)'.
* The method will NOT do any quoting or escaping.</li>
* <li><code>or</code>: similar as the <code>and</code> operator except that the operands are concatenated using OR.</li>
* <li><code>in</code>: operand 1 should be a column or DB expression, and operand 2 be an array representing
*
* - `and`: the operands should be concatenated together using `AND`. For example,
* `array('and', 'id=1', 'id=2')` will generate `id=1 AND id=2`. If an operand is an array,
* it will be converted into a string using the rules described here. For example,
* `array('and', 'type=1', array('or', 'id=1', 'id=2'))` will generate `type=1 AND (id=1 OR id=2)`.
* The method will NOT do any quoting or escaping.
*
* - `or`: similar to the `and` operator except that the operands are concatenated using `OR`.
*
* - `in`: operand 1 should be a column or DB expression, and operand 2 be an array representing
* the range of the values that the column or DB expression should be in. For example,
* array('in', 'id', array(1,2,3)) will generate 'id IN (1,2,3)'.
* The method will properly quote the column name and escape values in the range.</li>
* <li><code>not in</code>: similar as the <code>in</code> operator except that IN is replaced with NOT IN in the generated condition.</li>
* <li><code>like</code>: operand 1 should be a column or DB expression, and operand 2 be a string or an array representing
* `array('in', 'id', array(1,2,3))` will generate `id IN (1,2,3)`.
* The method will properly quote the column name and escape values in the range.
*
* - `not in`: similar to the `in` operator except that `IN` is replaced with `NOT IN` in the generated condition.
*
* - `like`: operand 1 should be a column or DB expression, and operand 2 be a string or an array representing
* the values that the column or DB expression should be like.
* For example, array('like', 'name', '%tester%') will generate "name LIKE '%tester%'".
* When the value range is given as an array, multiple LIKE predicates will be generated and concatenated using AND.
* For example, array('like', 'name', array('%test%', '%sample%')) will generate
* "name LIKE '%test%' AND name LIKE '%sample%'".
* The method will properly quote the column name and escape values in the range.</li>
* <li><code>not like</code>: similar as the <code>like</code> operator except that LIKE is replaced with NOT LIKE in the generated condition.</li>
* <li><code>or like</code>: similar as the <code>like</code> operator except that OR is used to concatenated the LIKE predicates.</li>
* <li><code>or not like</code>: similar as the <code>not like</code> operator except that OR is used to concatenated the NOT LIKE predicates.</li>
* </ul>
* For example, `array('like', 'name', '%tester%')` will generate `name LIKE '%tester%'`.
* When the value range is given as an array, multiple `LIKE` predicates will be generated and concatenated
* using `AND`. For example, `array('like', 'name', array('%test%', '%sample%'))` will generate
* `name LIKE '%test%' AND name LIKE '%sample%'`.
* The method will properly quote the column name and escape values in the range.
*
* - `or like`: similar to the `like` operator except that `OR` is used to concatenate the `LIKE`
* predicates when operand 2 is an array.
*
* - `not like`: similar to the `like` operator except that `LIKE` is replaced with `NOT LIKE`
* in the generated condition.
*
* - `or not like`: similar to the `not like` operator except that `OR` is used to concatenate
* the `NOT LIKE` predicates.
*
* @param mixed $conditions the conditions that should be put in the WHERE part.
* @param array $params the parameters (name=>value) to be bound to the query
* @return Command the command object itself
@ -557,7 +571,7 @@ class Command extends \yii\base\Component
* The method will automatically quote the table name unless it contains some parenthesis
* (which means the table is given as a sub-query or DB expression).
* @param mixed $conditions the join condition that should appear in the ON part.
* Please refer to {@link where} on how to specify conditions.
* Please refer to [[where]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query
* @return Command the command object itself
*/
@ -573,7 +587,7 @@ class Command extends \yii\base\Component
* The method will automatically quote the table name unless it contains some parenthesis
* (which means the table is given as a sub-query or DB expression).
* @param mixed $conditions the join condition that should appear in the ON part.
* Please refer to {@link where} on how to specify conditions.
* Please refer to [[where]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query
* @return Command the command object itself
*/
@ -589,7 +603,7 @@ class Command extends \yii\base\Component
* The method will automatically quote the table name unless it contains some parenthesis
* (which means the table is given as a sub-query or DB expression).
* @param mixed $conditions the join condition that should appear in the ON part.
* Please refer to {@link where} on how to specify conditions.
* Please refer to [[where]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query
* @return Command the command object itself
*/
@ -643,7 +657,7 @@ class Command extends \yii\base\Component
/**
* Sets the HAVING part of the query.
* @param mixed $conditions the conditions to be put after HAVING.
* Please refer to {@link where} on how to specify conditions.
* Please refer to [[where]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query
* @return Command the command object itself
*/
@ -719,8 +733,8 @@ class Command extends \yii\base\Component
* The method will properly escape the column names and bind the values to be updated.
* @param string $table the table to be updated.
* @param array $columns the column data (name=>value) to be updated.
* @param mixed $conditions the conditions that will be put in the WHERE part. Please
* refer to {@link where} on how to specify conditions.
* @param mixed $conditions the conditions that will be put in the WHERE part.
* Please refer to [[where]] on how to specify this parameter.
* @param array $params the parameters to be bound to the query.
* @return integer number of rows affected by the execution.
*/
@ -733,8 +747,8 @@ class Command extends \yii\base\Component
/**
* Creates and executes a DELETE SQL statement.
* @param string $table the table where the data will be deleted from.
* @param mixed $conditions the conditions that will be put in the WHERE part. Please
* refer to {@link where} on how to specify conditions.
* @param mixed $conditions the conditions that will be put in the WHERE part.
* Please refer to [[where]] on how to specify this parameter.
* @param array $params the parameters to be bound to the query.
* @return integer number of rows affected by the execution.
*/
@ -750,7 +764,9 @@ class Command extends \yii\base\Component
* The columns in the new table should be specified as name-definition pairs (e.g. 'name'=>'string'),
* where name stands for a column name which will be properly quoted by the method, and definition
* stands for the column type which can contain an abstract DB type.
* The {@link getColumnType} method will be invoked to convert any abstract type into a physical one.
* The method [[\yii\db\dao\QueryBuilder::getColumnType()]] will be called
* to convert the abstract column types to physical ones. For example, `string` will be converted
* as `varchar(255)`, and `string not null` becomes `varchar(255) not null`.
*
* If a column is specified with definition only (e.g. 'PRIMARY KEY (name, type)'), it will be directly
* inserted into the generated SQL.
@ -804,9 +820,9 @@ class Command extends \yii\base\Component
* Builds and executes a SQL statement for adding a new DB column.
* @param string $table the table that the new column will be added to. The table name will be properly quoted by the method.
* @param string $column the name of the new column. The name will be properly quoted by the method.
* @param string $type the column type. The {@link getColumnType} method will be invoked to convert abstract column type (if any)
* into the physical one. Anything that is not recognized as abstract type will be kept in the generated SQL.
* For example, 'string' will be turned into 'varchar(255)', while 'string not null' will become 'varchar(255) not null'.
* @param string $type the column type. [[\yii\db\dao\QueryBuilder::getColumnType()]] will be called
* to convert the give column type to the physical one. For example, `string` will be converted
* as `varchar(255)`, and `string not null` becomes `varchar(255) not null`.
* @return integer number of rows affected by the execution.
*/
public function addColumn($table, $column, $type)
@ -844,9 +860,9 @@ class Command extends \yii\base\Component
* Builds and executes a SQL statement for changing the definition of a column.
* @param string $table the table whose column is to be changed. The table name will be properly quoted by the method.
* @param string $column the name of the column to be changed. The name will be properly quoted by the method.
* @param string $type the new column type. The {@link getColumnType} method will be invoked to convert abstract column type (if any)
* into the physical one. Anything that is not recognized as abstract type will be kept in the generated SQL.
* For example, 'string' will be turned into 'varchar(255)', while 'string not null' will become 'varchar(255) not null'.
* @param string $type the column type. [[\yii\db\dao\QueryBuilder::getColumnType()]] will be called
* to convert the give column type to the physical one. For example, `string` will be converted
* as `varchar(255)`, and `string not null` becomes `varchar(255) not null`.
* @return integer number of rows affected by the execution.
*/
public function alterColumn($table, $column, $type)
@ -920,7 +936,7 @@ class Command extends \yii\base\Component
* The method will automatically quote the table name unless it contains some parenthesis
* (which means the table is given as a sub-query or DB expression).
* @param mixed $conditions the join condition that should appear in the ON part.
* Please refer to {@link where} on how to specify conditions.
* Please refer to [[where]] on how to specify this parameter.
* @param array $params the parameters (name=>value) to be bound to the query
* @return Command the command object itself
*/

70
framework/db/dao/Connection.php

@ -26,7 +26,7 @@ use yii\db\Exception;
* the DB connection:
*
* ~~~
* $connection = \yii\db\dao\Connection::create($dsn, $username, $password);
* $connection = \yii\db\dao\Connection::newInstance($dsn, $username, $password);
* $connection->active = true; // same as: $connection->open();
* ~~~
*
@ -57,13 +57,13 @@ use yii\db\Exception;
* ~~~
* $transaction = $connection->beginTransaction();
* try {
* $connection->createCommand($sql1)->execute();
* $connection->createCommand($sql2)->execute();
* // ... executing other SQL statements ...
* $transaction->commit();
* $connection->createCommand($sql1)->execute();
* $connection->createCommand($sql2)->execute();
* // ... executing other SQL statements ...
* $transaction->commit();
* }
* catch(Exception $e) {
* $transaction->rollBack();
* $transaction->rollBack();
* }
* ~~~
*
@ -72,15 +72,15 @@ use yii\db\Exception;
*
* ~~~
* array(
* 'components' => array(
* 'db' => array(
* 'class' => '\yii\db\dao\Connection',
* 'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
* 'username' => 'root',
* 'password' => '',
* 'charset' => 'utf8',
* ),
* ),
* 'components' => array(
* 'db' => array(
* 'class' => '\yii\db\dao\Connection',
* 'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
* 'username' => 'root',
* 'password' => '',
* 'charset' => 'utf8',
* ),
* ),
* )
* ~~~
*
@ -219,7 +219,7 @@ class Connection extends \yii\base\ApplicationComponent
/**
* @var array mapping between PDO driver names and [[Schema]] classes.
* The keys of the array are PDO driver names while the values the corresponding
* schema class name or configuration. Please refer to [[\Yii::create]] for
* schema class name or configuration. Please refer to [[\Yii::createObject]] for
* details on how to specify a configuration.
*
* This property is mainly used by [[getSchema]] when fetching the database schema information.
@ -227,15 +227,15 @@ class Connection extends \yii\base\ApplicationComponent
* [[Schema]] class to support DBMS that is not supported by Yii.
*/
public $schemaMap = array(
'pgsql' => '\yii\db\dao\pgsql\Schema', // PostgreSQL
'mysqli' => '\yii\db\dao\mysql\Schema', // MySQL
'mysql' => '\yii\db\dao\mysql\Schema', // MySQL
'sqlite' => '\yii\db\dao\sqlite\Schema', // sqlite 3
'sqlite2' => '\yii\db\dao\sqlite\Schema', // sqlite 2
'mssql' => '\yii\db\dao\mssql\Schema', // Mssql driver on windows hosts
'dblib' => '\yii\db\dao\mssql\Schema', // dblib drivers on linux (and maybe others os) hosts
'sqlsrv' => '\yii\db\dao\mssql\Schema', // Mssql
'oci' => '\yii\db\dao\oci\Schema', // Oracle driver
'pgsql' => '\yii\db\dao\pgsql\Schema', // PostgreSQL
'mysqli' => '\yii\db\dao\mysql\Schema', // MySQL
'mysql' => '\yii\db\dao\mysql\Schema', // MySQL
'sqlite' => '\yii\db\dao\sqlite\Schema', // sqlite 3
'sqlite2' => '\yii\db\dao\sqlite\Schema', // sqlite 2
'mssql' => '\yii\db\dao\mssql\Schema', // Mssql driver on windows hosts
'dblib' => '\yii\db\dao\mssql\Schema', // dblib drivers on linux (and maybe others os) hosts
'sqlsrv' => '\yii\db\dao\mssql\Schema', // Mssql
'oci' => '\yii\db\dao\oci\Schema', // Oracle driver
);
/**
@ -428,7 +428,8 @@ class Connection extends \yii\base\ApplicationComponent
{
if ($this->_transaction !== null && $this->_transaction->active) {
return $this->_transaction;
} else {
}
else {
return null;
}
}
@ -453,11 +454,13 @@ class Connection extends \yii\base\ApplicationComponent
{
if ($this->_schema !== null) {
return $this->_schema;
} else {
}
else {
$driver = $this->getDriverName();
if (isset($this->schemaMap[$driver])) {
return $this->_schema = \Yii::create($this->schemaMap[$driver], $this);
} else {
return $this->_schema = \Yii::createObject($this->schemaMap[$driver], $this);
}
else {
throw new Exception("Connection does not support reading schema for '$driver' database.");
}
}
@ -500,7 +503,8 @@ class Connection extends \yii\base\ApplicationComponent
$this->open();
if (($value = $this->pdo->quote($str)) !== false) {
return $value;
} else { // the driver doesn't support quote (e.g. oci)
}
else { // the driver doesn't support quote (e.g. oci)
return "'" . addcslashes(str_replace("'", "''", $str), "\000\n\r\\\032") . "'";
}
}
@ -542,7 +546,8 @@ class Connection extends \yii\base\ApplicationComponent
{
if ($this->tablePrefix !== null && strpos($sql, '{{') !== false) {
return preg_replace('/{{(.*?)}}/', $this->tablePrefix . '\1', $sql);
} else {
}
else {
return $sql;
}
}
@ -572,7 +577,8 @@ class Connection extends \yii\base\ApplicationComponent
{
if (($pos = strpos($this->dsn, ':')) !== false) {
return strtolower(substr($this->dsn, 0, $pos));
} else {
}
else {
return strtolower($this->getAttribute(\PDO::ATTR_DRIVER_NAME));
}
}

2
framework/db/dao/DataReader.php

@ -22,7 +22,7 @@ use yii\db\Exception;
*
* ~~~
* foreach($reader as $row) {
* // $row represents a row of data
* // $row represents a row of data
* }
* ~~~
*

79
framework/db/dao/Query.php

@ -102,10 +102,10 @@ class Query extends \yii\base\Object
}
if ($this->select !== $query->select) {
if($this->select === '*') {
if ($this->select === '*') {
$this->select = $query->select;
}
elseif($query->select!=='*') {
elseif ($query->select !== '*') {
$select1 = is_string($this->select) ? preg_split('/\s*,\s*/', trim($this->select), -1, PREG_SPLIT_NO_EMPTY) : $this->select;
$select2 = is_string($query->select) ? preg_split('/\s*,\s*/', trim($query->select), -1, PREG_SPLIT_NO_EMPTY) : $query->select;
$this->select = array_merge($select1, array_diff($select2, $select1));
@ -238,16 +238,19 @@ class Query extends \yii\base\Object
*/
public function addCondition($condition, $operator = 'AND')
{
if (is_array($condition))
{
if ($condition === array())
if (is_array($condition)) {
if ($condition === array()) {
return $this;
}
$condition = '(' . implode(') ' . $operator . ' (', $condition) . ')';
}
if ($this->condition === '')
if ($this->condition === '') {
$this->condition = $condition;
}
else
{
$this->condition = '(' . $this->condition . ') ' . $operator . ' (' . $condition . ')';
}
return $this;
}
@ -271,10 +274,12 @@ class Query extends \yii\base\Object
*/
public function addSearchCondition($column, $keyword, $escape = true, $operator = 'AND', $like = 'LIKE')
{
if ($keyword == '')
if ($keyword == '') {
return $this;
if ($escape)
}
if ($escape) {
$keyword = '%' . strtr($keyword, array('%' => '\%', '_' => '\_', '\\' => '\\\\')) . '%';
}
$condition = $column . " $like " . self::PARAM_PREFIX . self::$paramCount;
$this->params[self::PARAM_PREFIX . self::$paramCount++] = $keyword;
return $this->addCondition($condition, $operator);
@ -294,13 +299,14 @@ class Query extends \yii\base\Object
*/
public function addInCondition($column, $values, $operator = 'AND')
{
if (($n = count($values)) < 1)
return $this->addCondition('0=1', $operator); // 0=1 is used because in MSSQL value alone can't be used in WHERE
if ($n === 1)
{
if (($n = count($values)) < 1) {
return $this->addCondition('0=1', $operator);
} // 0=1 is used because in MSSQL value alone can't be used in WHERE
if ($n === 1) {
$value = reset($values);
if ($value === null)
if ($value === null) {
return $this->addCondition($column . ' IS NULL');
}
$condition = $column . '=' . self::PARAM_PREFIX . self::$paramCount;
$this->params[self::PARAM_PREFIX . self::$paramCount++] = $value;
}
@ -331,13 +337,14 @@ class Query extends \yii\base\Object
*/
public function addNotInCondition($column, $values, $operator = 'AND')
{
if (($n = count($values)) < 1)
if (($n = count($values)) < 1) {
return $this;
if ($n === 1)
{
}
if ($n === 1) {
$value = reset($values);
if ($value === null)
if ($value === null) {
return $this->addCondition($column . ' IS NOT NULL');
}
$condition = $column . '!=' . self::PARAM_PREFIX . self::$paramCount;
$this->params[self::PARAM_PREFIX . self::$paramCount++] = $value;
}
@ -370,8 +377,9 @@ class Query extends \yii\base\Object
$params = array();
foreach ($columns as $name => $value)
{
if ($value === null)
if ($value === null) {
$params[] = $name . ' IS NULL';
}
else
{
$params[] = $name . '=' . self::PARAM_PREFIX . self::$paramCount;
@ -426,35 +434,42 @@ class Query extends \yii\base\Object
*/
public function compare($column, $value, $partialMatch = false, $operator = 'AND', $escape = true)
{
if (is_array($value))
{
if ($value === array())
if (is_array($value)) {
if ($value === array()) {
return $this;
}
return $this->addInCondition($column, $value, $operator);
}
else
{
$value = "$value";
}
if (preg_match('/^(?:\s*(<>|<=|>=|<|>|=))?(.*)$/', $value, $matches))
{
if (preg_match('/^(?:\s*(<>|<=|>=|<|>|=))?(.*)$/', $value, $matches)) {
$value = $matches[2];
$op = $matches[1];
}
else
{
$op = '';
}
if ($value === '')
if ($value === '') {
return $this;
}
if ($partialMatch)
{
if ($op === '')
if ($partialMatch) {
if ($op === '') {
return $this->addSearchCondition($column, $value, $escape, $operator);
if ($op === '<>')
}
if ($op === '<>') {
return $this->addSearchCondition($column, $value, $escape, $operator, 'NOT LIKE');
}
}
elseif ($op === '')
{
$op = '=';
}
$this->addCondition($column . $op . self::PARAM_PREFIX . self::$paramCount, $operator);
$this->params[self::PARAM_PREFIX . self::$paramCount++] = $value;
@ -479,8 +494,9 @@ class Query extends \yii\base\Object
*/
public function addBetweenCondition($column, $valueStart, $valueEnd, $operator = 'AND')
{
if ($valueStart === '' || $valueEnd === '')
if ($valueStart === '' || $valueEnd === '') {
return $this;
}
$paramStart = self::PARAM_PREFIX . self::$paramCount++;
$paramEnd = self::PARAM_PREFIX . self::$paramCount++;
@ -488,10 +504,13 @@ class Query extends \yii\base\Object
$this->params[$paramEnd] = $valueEnd;
$condition = "$column BETWEEN $paramStart AND $paramEnd";
if ($this->condition === '')
if ($this->condition === '') {
$this->condition = $condition;
}
else
{
$this->condition = '(' . $this->condition . ') ' . $operator . ' (' . $condition . ')';
}
return $this;
}

65
framework/db/dao/QueryBuilder.php

@ -23,21 +23,21 @@ class QueryBuilder extends \yii\base\Object
/**
* @var array the abstract column types mapped to physical column types.
*/
public $typeMap = array(
'pk' => 'int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY',
'string' => 'varchar(255)',
'text' => 'text',
'integer' => 'int(11)',
'float' => 'float',
'decimal' => 'decimal',
'datetime' => 'datetime',
'timestamp' => 'timestamp',
'time' => 'time',
'date' => 'date',
'binary' => 'blob',
'boolean' => 'tinyint(1)',
public $typeMap = array(
'pk' => 'int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY',
'string' => 'varchar(255)',
'text' => 'text',
'integer' => 'int(11)',
'float' => 'float',
'decimal' => 'decimal',
'datetime' => 'datetime',
'timestamp' => 'timestamp',
'time' => 'time',
'date' => 'date',
'binary' => 'blob',
'boolean' => 'tinyint(1)',
'money' => 'decimal(19,4)',
);
);
/**
* @var Connection the database connection.
*/
@ -177,7 +177,9 @@ class QueryBuilder extends \yii\base\Object
$cols[] = "\t" . $this->schema->quoteColumnName($name) . ' ' . $this->schema->getColumnType($type);
}
else
{
$cols[] = "\t" . $type;
}
}
$sql = "CREATE TABLE " . $this->schema->quoteTableName($table) . " (\n" . implode(",\n", $cols) . "\n)";
return $options === null ? $sql : $sql . ' ' . $options;
@ -288,20 +290,24 @@ class QueryBuilder extends \yii\base\Object
public function addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete = null, $update = null)
{
$columns = preg_split('/\s*,\s*/', $columns, -1, PREG_SPLIT_NO_EMPTY);
foreach ($columns as $i => $col)
foreach ($columns as $i => $col) {
$columns[$i] = $this->schema->quoteColumnName($col);
}
$refColumns = preg_split('/\s*,\s*/', $refColumns, -1, PREG_SPLIT_NO_EMPTY);
foreach ($refColumns as $i => $col)
foreach ($refColumns as $i => $col) {
$refColumns[$i] = $this->schema->quoteColumnName($col);
}
$sql = 'ALTER TABLE ' . $this->schema->quoteTableName($table)
. ' ADD CONSTRAINT ' . $this->schema->quoteColumnName($name)
. ' FOREIGN KEY (' . implode(', ', $columns) . ')'
. ' REFERENCES ' . $this->schema->quoteTableName($refTable)
. ' (' . implode(', ', $refColumns) . ')';
if ($delete !== null)
if ($delete !== null) {
$sql .= ' ON DELETE ' . $delete;
if ($update !== null)
}
if ($update !== null) {
$sql .= ' ON UPDATE ' . $update;
}
return $sql;
}
@ -332,10 +338,13 @@ class QueryBuilder extends \yii\base\Object
$columns = preg_split('/\s*,\s*/', $column, -1, PREG_SPLIT_NO_EMPTY);
foreach ($columns as $col)
{
if (strpos($col, '(') !== false)
if (strpos($col, '(') !== false) {
$cols[] = $col;
}
else
{
$cols[] = $this->schema->quoteColumnName($col);
}
}
return ($unique ? 'CREATE UNIQUE INDEX ' : 'CREATE INDEX ')
. $this->schema->quoteTableName($name) . ' ON '
@ -400,8 +409,8 @@ class QueryBuilder extends \yii\base\Object
* @param string $type abstract column type
* @return string physical column type.
*/
public function getColumnType($type)
{
public function getColumnType($type)
{
if (isset($this->typeMap[$type])) {
return $this->typeMap[$type];
}
@ -485,19 +494,19 @@ class QueryBuilder extends \yii\base\Object
}
foreach ($joins as $i => $join) {
if (is_array($join)) { // join type, table name, on-condition
if (is_array($join)) { // join type, table name, 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->connection->quoteTableName($matches[1]).' '.$this->connection->quoteTableName($matches[2]);
if (strpos($table, '(') === false) {
if (preg_match('/^(.*?)(?i:\s+as\s+|\s+)(.*)$/', $table, $matches)) { // with alias
$table = $this->connection->quoteTableName($matches[1]) . ' ' . $this->connection->quoteTableName($matches[2]);
}
else {
$table = $this->connection->quoteTableName($table);
}
}
$joins[$i] = strtoupper($join[0]) . ' ' . $table;
if (isset($join[2])) { // join condition
if (isset($join[2])) { // join condition
$condition = $this->buildCondition($join[2]);
$joins[$i] .= ' ON ' . $condition;
}
@ -582,8 +591,8 @@ class QueryBuilder extends \yii\base\Object
if ($query->limit !== null && $query->limit >= 0) {
$sql = 'LIMIT ' . (int)$query->limit;
}
if ($query->offset>0) {
$sql .= ' OFFSET '.(int)$query->offset;
if ($query->offset > 0) {
$sql .= ' OFFSET ' . (int)$query->offset;
}
return ltrim($sql);
}

5
framework/db/dao/Schema.php

@ -20,6 +20,9 @@ use yii\db\Exception;
*/
abstract class Schema extends \yii\base\Object
{
/**
* @var \yii\db\dao\Connection the database connection
*/
public $connection;
private $_tableNames = array();
@ -194,7 +197,9 @@ abstract class Schema extends \yii\base\Object
$name = substr($name, $pos + 1);
}
else
{
$prefix = '';
}
return $prefix . $this->quoteSimpleColumnName($name);
}

6
framework/db/dao/TableSchema.php

@ -55,9 +55,9 @@ class TableSchema extends \yii\base\Object
*
* ~~~
* array(
* 'ForeignTableName',
* 'fk1' => 'pk1', // pk1 is in foreign table
* 'fk2' => 'pk2', // if composite foreign key
* 'ForeignTableName',
* 'fk1' => 'pk1', // pk1 is in foreign table
* 'fk2' => 'pk2', // if composite foreign key
* )
* ~~~
*/

16
framework/db/dao/Transaction.php

@ -23,13 +23,13 @@ use yii\db\Exception;
* ~~~
* $transaction = $connection->beginTransaction();
* try {
* $connection->createCommand($sql1)->execute();
* $connection->createCommand($sql2)->execute();
* //.... other SQL executions
* $transaction->commit();
* $connection->createCommand($sql1)->execute();
* $connection->createCommand($sql2)->execute();
* //.... other SQL executions
* $transaction->commit();
* }
* catch(Exception $e) {
* $transaction->rollBack();
* $transaction->rollBack();
* }
* ~~~
*
@ -69,7 +69,8 @@ class Transaction extends \yii\base\Object
\Yii::trace('Committing transaction', __CLASS__);
$this->connection->pdo->commit();
$this->active = false;
} else {
}
else {
throw new Exception('Failed to commit transaction: transaction was inactive.');
}
}
@ -84,7 +85,8 @@ class Transaction extends \yii\base\Object
\Yii::trace('Rolling back transaction', __CLASS__);
$this->connection->pdo->rollBack();
$this->active = false;
} else {
}
else {
throw new Exception('Failed to roll back transaction: transaction was inactive.');
}
}

21
framework/logging/Logger.php

@ -22,12 +22,12 @@ namespace yii\logging;
*/
class Logger extends \yii\base\Component
{
const LEVEL_ERROR = 1;
const LEVEL_WARNING = 2;
const LEVEL_INFO = 3;
const LEVEL_TRACE = 4;
const LEVEL_PROFILE_BEGIN = 5;
const LEVEL_PROFILE_END = 6;
const LEVEL_ERROR = 'error';
const LEVEL_WARNING = 'warning';
const LEVEL_INFO = 'info';
const LEVEL_TRACE = 'trace';
const LEVEL_PROFILE_BEGIN = 'profile-begin';
const LEVEL_PROFILE_END = 'profile-end';
/**
* @var integer how many messages should be logged before they are flushed from memory and sent to targets.
@ -253,13 +253,10 @@ class Logger extends \yii\base\Component
$stack = array();
foreach ($this->messages as $log) {
if ($log[1] < self::LEVEL_PROFILE_BEGIN) {
continue;
}
list($token, $level, $category, $timestamp) = $log;
if ($level === self::LEVEL_PROFILE_BEGIN) {
if ($log[1] === self::LEVEL_PROFILE_BEGIN) {
$stack[] = $log;
} else {
} elseif ($log[1] === self::LEVEL_PROFILE_END) {
list($token, $level, $category, $timestamp) = $log;
if (($last = array_pop($stack)) !== null && $last[0] === $token) {
$timings[] = array($token, $category, $timestamp - $last[3]);
} else {

4
framework/logging/Router.php

@ -101,7 +101,7 @@ class Router extends \yii\base\ApplicationComponent
* Sets the log targets.
* @param array $config list of log target configurations. Each array element
* represents the configuration for creating a single log target. It will be
* passed to [[\Yii::create]] to create the target instance.
* passed to [[\Yii::createObject]] to create the target instance.
*/
public function setTargets($config)
{
@ -110,7 +110,7 @@ class Router extends \yii\base\ApplicationComponent
$this->_targets[$name] = $target;
}
else {
$this->_targets[$name] = \Yii::create($target);
$this->_targets[$name] = \Yii::createObject($target);
}
}
}

2
framework/validators/Validator.php

@ -166,7 +166,7 @@ abstract class Validator extends \yii\base\Component
foreach ($params as $name => $value) {
$config[$name] = $value;
}
$validator = \Yii::create($config);
$validator = \Yii::createObject($config);
return $validator;
}

2
tests/unit/framework/base/BehaviorTest.php

@ -21,7 +21,7 @@ class BehaviorTest extends \yiiunit\TestCase
{
public function testAttachAndAccessing()
{
$bar = BarClass::create();
$bar = BarClass::newInstance();
$behavior = new BarBehavior();
$bar->attachBehavior('bar', $behavior);
$this->assertEquals('behavior property', $bar->behaviorProperty);

2
tests/unit/framework/base/ComponentTest.php

@ -206,7 +206,7 @@ class ComponentTest extends \yiiunit\TestCase
public function testCreate()
{
$component = NewComponent2::create(1, 2, array('a'=>3));
$component = NewComponent2::newInstance(1, 2, array('a'=>3));
$this->assertEquals(1, $component->b);
$this->assertEquals(2, $component->c);
$this->assertEquals(3, $component->a);

34
tests/unit/framework/base/ObjectTest.php

@ -7,6 +7,23 @@ class Foo extends \yii\base\Object
public $prop;
}
class Bar extends \yii\base\Component implements \yii\base\Initable
{
public $prop1;
public $prop2;
public $prop3;
public function __construct($a, $b)
{
$this->prop1 = $a + $b;
}
public function init()
{
$this->prop3 = 3;
}
}
/**
* ObjectTest
*/
@ -24,15 +41,28 @@ class ObjectTest extends \yiiunit\TestCase
$this->object = null;
}
public function testCreate()
public function testNewInstance()
{
$foo = Foo::create(array(
$foo = Foo::newInstance(array(
'prop' => array(
'test' => 'test',
),
));
$this->assertEquals('test', $foo->prop['test']);
$bar = Bar::newInstance(10, 20);
$this->assertEquals(30, $bar->prop1);
$this->assertEquals(null, $bar->prop2);
$this->assertEquals(3, $bar->prop3);
$bar = Bar::newInstance(100, 200, array(
'prop2' => 'x',
'prop3' => 400,
));
$this->assertEquals(300, $bar->prop1);
$this->assertEquals('x', $bar->prop2);
$this->assertEquals(3, $bar->prop3);
}
public function testHasProperty()

Loading…
Cancel
Save