Commit f6d405b9 by Alexander Makarov

Merge branch 'refs/heads/master' into template-engines

parents 1d6b8d85 0ed14a74
......@@ -300,7 +300,7 @@ foreach ($customers as $customer) {
~~~
How many SQL queries will be performed in the above code, assuming there are more than 100 customers in
the database? 101! The first SQL query brings back 100 customers. Then for each customer, another SQL query
the database? 101! The first SQL query brings back 100 customers. Then for each customer, a SQL query
is performed to bring back the customer's orders.
To solve the above performance problem, you can use the so-called *eager loading* by calling [[ActiveQuery::with()]]:
......@@ -318,7 +318,7 @@ foreach ($customers as $customer) {
}
~~~
As you can see, only two SQL queries were needed for the same task.
As you can see, only two SQL queries are needed for the same task.
Sometimes, you may want to customize the relational queries on the fly. It can be
......
Yii2 class loader
=================
Yii 2 class loader is PSR-0 compliant. That means it can handle most of the PHP
libraries and frameworks out there.
In order to autoload a library you need to set a root alias for it.
PEAR-style libraries
--------------------
```php
\Yii::setAlias('@Twig', '@app/vendors/Twig');
```
References
----------
- YiiBase::autoload
\ No newline at end of file
......@@ -251,10 +251,8 @@ switch ($this->phpType) {
~~~
<?php
/**
* Component class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
~~~
......
<?php
/**
* YiiBase class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
use yii\base\Exception;
use yii\base\InvalidConfigException;
use yii\base\InvalidParamException;
use yii\logging\Logger;
/**
......@@ -63,7 +61,7 @@ class YiiBase
*/
public static $classPath = array();
/**
* @var yii\base\Application the application instance
* @var yii\console\Application|yii\web\Application the application instance
*/
public static $app;
/**
......@@ -96,7 +94,7 @@ class YiiBase
*/
public static $objectConfig = array();
private static $_imported = array(); // alias => class name or directory
private static $_imported = array(); // alias => class name or directory
private static $_logger;
/**
......@@ -161,9 +159,7 @@ class YiiBase
return self::$_imported[$alias] = $className;
}
if (($path = static::getAlias(dirname($alias))) === false) {
throw new Exception('Invalid path alias: ' . $alias);
}
$path = static::getAlias(dirname($alias));
if ($isClass) {
if ($forceInclude) {
......@@ -193,24 +189,30 @@ class YiiBase
*
* Note, this method does not ensure the existence of the resulting path.
* @param string $alias alias
* @param boolean $throwException whether to throw an exception if the given alias is invalid.
* If this is false and an invalid alias is given, false will be returned by this method.
* @return string|boolean path corresponding to the alias, false if the root alias is not previously registered.
* @see setAlias
*/
public static function getAlias($alias)
public static function getAlias($alias, $throwException = true)
{
if (!is_string($alias)) {
return false;
} elseif (isset(self::$aliases[$alias])) {
return self::$aliases[$alias];
} elseif ($alias === '' || $alias[0] !== '@') { // not an alias
return $alias;
} elseif (($pos = strpos($alias, '/')) !== false) {
$rootAlias = substr($alias, 0, $pos);
if (isset(self::$aliases[$rootAlias])) {
return self::$aliases[$alias] = self::$aliases[$rootAlias] . substr($alias, $pos);
if (is_string($alias)) {
if (isset(self::$aliases[$alias])) {
return self::$aliases[$alias];
} elseif ($alias === '' || $alias[0] !== '@') { // not an alias
return $alias;
} elseif (($pos = strpos($alias, '/')) !== false || ($pos = strpos($alias, '\\')) !== false) {
$rootAlias = substr($alias, 0, $pos);
if (isset(self::$aliases[$rootAlias])) {
return self::$aliases[$alias] = self::$aliases[$rootAlias] . substr($alias, $pos);
}
}
}
return false;
if ($throwException) {
throw new InvalidParamException("Invalid path alias: $alias");
} else {
return false;
}
}
/**
......@@ -238,10 +240,8 @@ class YiiBase
unset(self::$aliases[$alias]);
} elseif ($path[0] !== '@') {
self::$aliases[$alias] = rtrim($path, '\\/');
} elseif (($p = static::getAlias($path)) !== false) {
self::$aliases[$alias] = $p;
} else {
throw new Exception('Invalid path: ' . $path);
self::$aliases[$alias] = static::getAlias($path);
}
}
......@@ -275,14 +275,14 @@ class YiiBase
// namespaced class, e.g. yii\base\Component
// convert namespace to path alias, e.g. yii\base\Component to @yii/base/Component
$alias = '@' . str_replace('\\', '/', ltrim($className, '\\'));
if (($path = static::getAlias($alias)) !== false) {
if (($path = static::getAlias($alias, false)) !== false) {
$classFile = $path . '.php';
}
} elseif (($pos = strpos($className, '_')) !== false) {
// PEAR-styled class, e.g. PHPUnit_Framework_TestCase
// convert class name to path alias, e.g. PHPUnit_Framework_TestCase to @PHPUnit/Framework/TestCase
$alias = '@' . str_replace('_', '/', $className);
if (($path = static::getAlias($alias)) !== false) {
if (($path = static::getAlias($alias, false)) !== false) {
$classFile = $path . '.php';
}
}
......@@ -298,7 +298,7 @@ class YiiBase
}
}
if (isset($classFile, $alias)) {
if (isset($classFile, $alias) && is_file($classFile)) {
if (!YII_DEBUG || basename(realpath($classFile)) === basename($alias) . '.php') {
include($classFile);
return true;
......
<?php
/**
* Action class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* ActionEvent class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
/**
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class ActionFilter extends Behavior
{
/**
* @var array list of action IDs that this filter should apply to. If this property is not set,
* then the filter applies to all actions, unless they are listed in [[except]].
*/
public $only;
/**
* @var array list of action IDs that this filter should not apply to.
*/
public $except = array();
/**
* Declares event handlers for the [[owner]]'s events.
* @return array events (array keys) and the corresponding event handler methods (array values).
*/
public function events()
{
return array(
'beforeAction' => 'beforeFilter',
'afterAction' => 'afterFilter',
);
}
/**
* @param ActionEvent $event
* @return boolean
*/
public function beforeFilter($event)
{
if ($this->isActive($event->action)) {
$event->isValid = $this->beforeAction($event->action);
}
return $event->isValid;
}
/**
* @param ActionEvent $event
* @return boolean
*/
public function afterFilter($event)
{
if ($this->isActive($event->action)) {
$this->afterAction($event->action);
}
}
/**
* This method is invoked right before an action is to be executed (after all possible filters.)
* You may override this method to do last-minute preparation for the action.
* @param Action $action the action to be executed.
* @return boolean whether the action should continue to be executed.
*/
public function beforeAction($action)
{
return true;
}
/**
* This method is invoked right after an action is executed.
* You may override this method to do some postprocessing for the action.
* @param Action $action the action just executed.
*/
public function afterAction($action)
{
}
/**
* Returns a value indicating whether the filer is active for the given action.
* @param Action $action the action being filtered
* @return boolean whether the filer is active for the given action.
*/
protected function isActive($action)
{
return !in_array($action->id, $this->except, true) && (empty($this->only) || in_array($action->id, $this->only, true));
}
}
\ No newline at end of file
<?php
/**
* Application class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
use Yii;
use yii\util\FileHelper;
use yii\helpers\FileHelper;
/**
* Application is the base class for all application classes.
......@@ -94,7 +92,12 @@ class Application extends Module
private $_runtimePath;
private $_ended = false;
private $_language;
/**
* @var string Used to reserve memory for fatal error handler. This memory
* reserve can be removed if it's OK to write to PHP log only in this particular case.
*/
private $_memoryReserve;
/**
* Constructor.
......@@ -110,6 +113,7 @@ class Application extends Module
$this->setBasePath($basePath);
if (YII_ENABLE_ERROR_HANDLER) {
ini_set('display_errors', 0);
set_exception_handler(array($this, 'handleException'));
set_error_handler(array($this, 'handleError'), error_reporting());
}
......@@ -142,12 +146,64 @@ class Application extends Module
$this->_ended = true;
$this->afterRequest();
}
$this->handleFatalError();
if ($exit) {
exit($status);
}
}
/**
* Handles fatal PHP errors
*/
public function handleFatalError()
{
if (YII_ENABLE_ERROR_HANDLER) {
$error = error_get_last();
if (ErrorException::isFatalErorr($error)) {
unset($this->_memoryReserve);
$exception = new ErrorException($error['message'], $error['type'], $error['type'], $error['file'], $error['line']);
if (function_exists('xdebug_get_function_stack')) {
$trace = array_slice(array_reverse(xdebug_get_function_stack()), 4, -1);
foreach ($trace as &$frame) {
if (!isset($frame['function'])) {
$frame['function'] = 'unknown';
}
// XDebug < 2.1.1: http://bugs.xdebug.org/view.php?id=695
if (!isset($frame['type'])) {
$frame['type'] = '::';
}
// XDebug has a different key name
$frame['args'] = array();
if (isset($frame['params']) && !isset($frame['args'])) {
$frame['args'] = $frame['params'];
}
}
$ref = new \ReflectionProperty('Exception', 'trace');
$ref->setAccessible(true);
$ref->setValue($exception, $trace);
}
$this->logException($exception);
if (($handler = $this->getErrorHandler()) !== null) {
@$handler->handle($exception);
} else {
$this->renderException($exception);
}
exit(1);
}
}
}
/**
* Runs the application.
* This is the main entrance of an application.
* @return integer the exit status (0 means normal, non-zero values mean abnormal)
......@@ -155,6 +211,10 @@ class Application extends Module
public function run()
{
$this->beforeRequest();
// Allocating twice more than required to display memory exhausted error
// in case of trying to allocate last 1 byte while all memory is taken.
$this->_memoryReserve = str_repeat('x', 1024 * 256);
register_shutdown_function(array($this, 'end'), 0, false);
$status = $this->processRequest();
$this->afterRequest();
return $status;
......@@ -235,14 +295,6 @@ class Application extends Module
date_default_timezone_set($value);
}
// /**
// * Returns the security manager component.
// * @return SecurityManager the security manager application component.
// */
// public function getSecurityManager()
// {
// return $this->getComponent('securityManager');
// }
//
// /**
// * Returns the locale instance.
......@@ -293,15 +345,6 @@ class Application extends Module
}
/**
* Returns the application theme.
* @return Theme the theme that this application is currently using.
*/
public function getTheme()
{
return $this->getComponent('theme');
}
/**
* Returns the cache component.
* @return \yii\caching\Cache the cache application component. Null if the component is not enabled.
*/
......@@ -320,12 +363,21 @@ class Application extends Module
}
/**
* Returns the view renderer.
* @return ViewRenderer the view renderer used by this application.
* Returns the view object.
* @return View the view object that is used to render various view files.
*/
public function getView()
{
return $this->getComponent('view');
}
/**
* Returns the URL manager for this application.
* @return \yii\web\UrlManager the URL manager for this application.
*/
public function getViewRenderer()
public function getUrlManager()
{
return $this->getComponent('viewRenderer');
return $this->getComponent('urlManager');
}
/**
......@@ -343,8 +395,6 @@ class Application extends Module
public function registerDefaultAliases()
{
Yii::$aliases['@app'] = $this->getBasePath();
Yii::$aliases['@entry'] = dirname($_SERVER['SCRIPT_FILENAME']);
Yii::$aliases['@www'] = '';
}
/**
......@@ -360,8 +410,11 @@ class Application extends Module
'i18n' => array(
'class' => 'yii\i18n\I18N',
),
'securityManager' => array(
'class' => 'yii\base\SecurityManager',
'urlManager' => array(
'class' => 'yii\web\UrlManager',
),
'view' => array(
'class' => 'yii\base\View',
),
));
}
......@@ -375,12 +428,24 @@ class Application extends Module
* @param string $message the error message
* @param string $file the filename that the error was raised in
* @param integer $line the line number the error was raised at
* @throws \ErrorException the error exception
*
* @throws ErrorException
*/
public function handleError($code, $message, $file, $line)
{
if (error_reporting() !== 0) {
throw new \ErrorException($message, 0, $code, $file, $line);
$exception = new ErrorException($message, $code, $code, $file, $line);
// in case error appeared in __toString method we can't throw any exception
$trace = debug_backtrace(false);
array_shift($trace);
foreach ($trace as $frame) {
if ($frame['function'] == '__toString') {
$this->handleException($exception);
}
}
throw $exception;
}
}
......@@ -409,11 +474,14 @@ class Application extends Module
$this->end(1);
} catch(\Exception $e) {
} catch (\Exception $e) {
// exception could be thrown in end() or ErrorHandler::handle()
$msg = (string)$e;
$msg .= "\nPrevious exception:\n";
$msg .= (string)$exception;
if (YII_DEBUG) {
echo $msg;
}
$msg .= "\n\$_SERVER = " . var_export($_SERVER, true);
error_log($msg);
exit(1);
......
<?php
/**
* Behavior class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* Component class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -60,7 +58,7 @@ class Component extends \yii\base\Object
}
}
}
throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '.' . $name);
throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '::' . $name);
}
/**
......@@ -107,9 +105,9 @@ class Component extends \yii\base\Object
}
}
if (method_exists($this, 'get' . $name)) {
throw new InvalidCallException('Setting read-only property: ' . get_class($this) . '.' . $name);
throw new InvalidCallException('Setting read-only property: ' . get_class($this) . '::' . $name);
} else {
throw new UnknownPropertyException('Setting unknown property: ' . get_class($this) . '.' . $name);
throw new UnknownPropertyException('Setting unknown property: ' . get_class($this) . '::' . $name);
}
}
......
<?php
/**
* Controller class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
use Yii;
use yii\util\StringHelper;
use yii\helpers\FileHelper;
use yii\helpers\StringHelper;
/**
* Controller is the base class for classes containing controller logic.
......@@ -297,34 +296,46 @@ class Controller extends Component
/**
* Renders a view and applies layout if available.
*
* @param $view
* @param array $params
* @return string
* @param string $view the view name. Please refer to [[findViewFile()]] on how to specify a view name.
* @param array $params the parameters (name-value pairs) that should be made available in the view.
* These parameters will not be available in the layout.
* @return string the rendering result.
* @throws InvalidParamException if the view file or the layout file does not exist.
*/
public function render($view, $params = array())
{
return $this->createView()->render($view, $params);
}
public function renderContent($content)
{
return $this->createView()->renderContent($content);
$output = Yii::$app->getView()->render($view, $params, $this);
$layoutFile = $this->findLayoutFile();
if ($layoutFile !== false) {
return Yii::$app->getView()->renderFile($layoutFile, array('content' => $output), $this);
} else {
return $output;
}
}
/**
* Renders a view.
* This method differs from [[render()]] in that it does not apply any layout.
* @param string $view the view name. Please refer to [[findViewFile()]] on how to specify a view name.
* @param array $params the parameters (name-value pairs) that should be made available in the view.
* @return string the rendering result.
* @throws InvalidParamException if the view file does not exist.
*/
public function renderPartial($view, $params = array())
{
return $this->createView()->renderPartial($view, $params);
return Yii::$app->getView()->render($view, $params, $this);
}
/**
* Renders a view file.
* @param string $file the view file to be rendered. This can be either a file path or a path alias.
* @param array $params the parameters (name-value pairs) that should be made available in the view.
* @return string the rendering result.
* @throws InvalidParamException if the view file does not exist.
*/
public function renderFile($file, $params = array())
{
return $this->createView()->renderFile($file, $params);
}
public function createView()
{
return new View($this);
return Yii::$app->getView()->renderFile($file, $params, $this);
}
/**
......@@ -337,4 +348,63 @@ class Controller extends Component
{
return $this->module->getViewPath() . DIRECTORY_SEPARATOR . $this->id;
}
/**
* Finds the applicable layout file.
*
* This method locates an applicable layout file via two steps.
*
* In the first step, it determines the layout name and the context module:
*
* - If [[layout]] is specified as a string, use it as the layout name and [[module]] as the context module;
* - If [[layout]] is null, search through all ancestor modules of this controller and find the first
* module whose [[Module::layout|layout]] is not null. The layout and the corresponding module
* are used as the layout name and the context module, respectively. If such a module is not found
* or the corresponding layout is not a string, it will return false, meaning no applicable layout.
*
* In the second step, it determines the actual layout file according to the previously found layout name
* and context module. The layout name can be
*
* - a path alias (e.g. "@app/views/layouts/main");
* - an absolute path (e.g. "/main"): the layout name starts with a slash. The actual layout file will be
* looked for under the [[Application::layoutPath|layout path]] of the application;
* - a relative path (e.g. "main"): the actual layout layout file will be looked for under the
* [[Module::viewPath|view path]] of the context module.
*
* If the layout name does not contain a file extension, it will use the default one `.php`.
*
* @return string|boolean the layout file path, or false if layout is not needed.
* @throws InvalidParamException if an invalid path alias is used to specify the layout
*/
protected function findLayoutFile()
{
$module = $this->module;
if (is_string($this->layout)) {
$view = $this->layout;
} elseif ($this->layout === null) {
while ($module !== null && $module->layout === null) {
$module = $module->module;
}
if ($module !== null && is_string($module->layout)) {
$view = $module->layout;
}
}
if (!isset($view)) {
return false;
}
if (strncmp($view, '@', 1) === 0) {
$file = Yii::getAlias($view);
} elseif (strncmp($view, '/', 1) === 0) {
$file = Yii::$app->getLayoutPath() . DIRECTORY_SEPARATOR . $view;
} else {
$file = $module->getLayoutPath() . DIRECTORY_SEPARATOR . $view;
}
if (FileHelper::getExtension($file) === '') {
$file .= '.php';
}
return $file;
}
}
<?php
/**
* Dictionary class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
use yii\util\ArrayHelper;
use yii\helpers\ArrayHelper;
/**
* Dictionary implements a collection that stores key-value pairs.
......@@ -184,7 +182,7 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co
* Copies iterable data into the dictionary.
* Note, existing data in the dictionary will be cleared first.
* @param mixed $data the data to be copied from, must be an array or an object implementing `Traversable`
* @throws InvalidCallException if data is neither an array nor an iterator.
* @throws InvalidParamException if data is neither an array nor an iterator.
*/
public function copyFrom($data)
{
......@@ -199,7 +197,7 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co
$this->add($key, $value);
}
} else {
throw new InvalidCallException('Data must be either an array or an object implementing Traversable.');
throw new InvalidParamException('Data must be either an array or an object implementing Traversable.');
}
}
......@@ -216,7 +214,7 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co
*
* @param array|\Traversable $data the data to be merged with. It must be an array or object implementing Traversable
* @param boolean $recursive whether the merging should be recursive.
* @throws InvalidCallException if data is neither an array nor an object implementing `Traversable`.
* @throws InvalidParamException if data is neither an array nor an object implementing `Traversable`.
*/
public function mergeWith($data, $recursive = true)
{
......@@ -240,7 +238,7 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co
}
}
} else {
throw new InvalidCallException('The data to be merged with must be an array or an object implementing Traversable.');
throw new InvalidParamException('The data to be merged with must be an array or an object implementing Traversable.');
}
}
......
<?php
/**
* DictionaryIterator class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
/**
* ErrorException represents a PHP error.
*
* @author Alexander Makarov <sam@rmcreative.ru>
* @since 2.0
*/
class ErrorException extends Exception
{
protected $severity;
/**
* Constructs the exception
* @link http://php.net/manual/en/errorexception.construct.php
* @param $message [optional]
* @param $code [optional]
* @param $severity [optional]
* @param $filename [optional]
* @param $lineno [optional]
* @param $previous [optional]
*/
public function __construct($message = '', $code = 0, $severity = 1, $filename = __FILE__, $lineno = __LINE__, \Exception $previous = null)
{
parent::__construct($message, $code, $previous);
$this->severity = $severity;
$this->file = $filename;
$this->line = $lineno;
}
/**
* Gets the exception severity
* @link http://php.net/manual/en/errorexception.getseverity.php
* @return int the severity level of the exception.
*/
final public function getSeverity()
{
return $this->severity;
}
/**
* Returns if error is one of fatal type
*
* @param array $error error got from error_get_last()
* @return bool if error is one of fatal type
*/
public static function isFatalErorr($error)
{
return isset($error['type']) && in_array($error['type'], array(E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING));
}
/**
* @return string the user-friendly name of this exception
*/
public function getName()
{
$names = array(
E_ERROR => \Yii::t('yii|Fatal Error'),
E_PARSE => \Yii::t('yii|Parse Error'),
E_CORE_ERROR => \Yii::t('yii|Core Error'),
E_COMPILE_ERROR => \Yii::t('yii|Compile Error'),
E_USER_ERROR => \Yii::t('yii|User Error'),
E_WARNING => \Yii::t('yii|Warning'),
E_CORE_WARNING => \Yii::t('yii|Core Warning'),
E_COMPILE_WARNING => \Yii::t('yii|Compile Warning'),
E_USER_WARNING => \Yii::t('yii|User Warning'),
E_STRICT => \Yii::t('yii|Strict'),
E_NOTICE => \Yii::t('yii|Notice'),
E_RECOVERABLE_ERROR => \Yii::t('yii|Recoverable Error'),
E_DEPRECATED => \Yii::t('yii|Deprecated'),
);
return isset($names[$this->getCode()]) ? $names[$this->getCode()] : \Yii::t('yii|Error');
}
}
<?php
/**
* ErrorHandler class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -18,7 +16,7 @@ namespace yii\base;
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
use yii\util\VarDumper;
use yii\helpers\VarDumper;
class ErrorHandler extends Component
{
......@@ -80,7 +78,7 @@ class ErrorHandler extends Component
if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest') {
\Yii::$app->renderException($exception);
} else {
$view = new View($this);
$view = new View;
if (!YII_DEBUG || $exception instanceof UserException) {
$viewName = $this->errorView;
} else {
......@@ -88,7 +86,7 @@ class ErrorHandler extends Component
}
echo $view->render($viewName, array(
'exception' => $exception,
));
), $this);
}
} else {
\Yii::$app->renderException($exception);
......@@ -255,15 +253,10 @@ class ErrorHandler extends Component
*/
public function renderAsHtml($exception)
{
$view = new View($this);
if (!YII_DEBUG || $exception instanceof UserException) {
$viewName = $this->errorView;
} else {
$viewName = $this->exceptionView;
}
$view = new View;
$name = !YII_DEBUG || $exception instanceof HttpException ? $this->errorView : $this->exceptionView;
echo $view->render($name, array(
'exception' => $exception,
));
), $this);
}
}
<?php
/**
* Event class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* Exception class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -24,5 +22,4 @@ class Exception extends \Exception
{
return \Yii::t('yii|Exception');
}
}
}
\ No newline at end of file
<?php
/**
* HttpException class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* InlineAction class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* InvalidCallException class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* InvalidConfigException class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
/**
* InvalidParamException represents an exception caused by invalid parameters passed to a method.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class InvalidParamException extends Exception
{
/**
* @return string the user-friendly name of this exception
*/
public function getName()
{
return \Yii::t('yii|Invalid Parameter');
}
}
<?php
/**
* InvalidRequestException class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* InvalidRouteException class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* Model class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
use yii\util\StringHelper;
use yii\helpers\StringHelper;
use yii\validators\Validator;
use yii\validators\RequiredValidator;
......@@ -422,12 +420,31 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess
}
/**
* Returns the first error of every attribute in the model.
* @return array the first errors. An empty array will be returned if there is no error.
*/
public function getFirstErrors()
{
if (empty($this->_errors)) {
return array();
} else {
$errors = array();
foreach ($this->_errors as $errors) {
if (isset($errors[0])) {
$errors[] = $errors[0];
}
}
}
return $errors;
}
/**
* Returns the first error of the specified attribute.
* @param string $attribute attribute name.
* @return string the error message. Null is returned if no error.
* @see getErrors
*/
public function getError($attribute)
public function getFirstError($attribute)
{
return isset($this->_errors[$attribute]) ? reset($this->_errors[$attribute]) : null;
}
......@@ -443,25 +460,6 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess
}
/**
* Adds a list of errors.
* @param array $errors a list of errors. The array keys must be attribute names.
* The array values should be error messages. If an attribute has multiple errors,
* these errors must be given in terms of an array.
*/
public function addErrors($errors)
{
foreach ($errors as $attribute => $error) {
if (is_array($error)) {
foreach ($error as $e) {
$this->_errors[$attribute][] = $e;
}
} else {
$this->_errors[$attribute][] = $error;
}
}
}
/**
* Removes errors for all attributes or a single attribute.
* @param string $attribute attribute name. Use null to remove errors for all attribute.
*/
......@@ -543,7 +541,7 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess
public function onUnsafeAttribute($name, $value)
{
if (YII_DEBUG) {
\Yii::warning("Failed to set unsafe attribute '$name' in '" . get_class($this) . "'.");
\Yii::info("Failed to set unsafe attribute '$name' in '" . get_class($this) . "'.", __CLASS__);
}
}
......
<?php
/**
* ModelEvent class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* Module class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
use Yii;
use yii\util\StringHelper;
use yii\util\FileHelper;
use yii\helpers\StringHelper;
use yii\helpers\FileHelper;
/**
* Module is the base class for module and application classes.
......
<?php
/**
* NotSupportedException class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* Object class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -67,7 +65,7 @@ class Object
if (method_exists($this, $getter)) {
return $this->$getter();
} else {
throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '.' . $name);
throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '::' . $name);
}
}
......@@ -88,9 +86,9 @@ class Object
if (method_exists($this, $setter)) {
$this->$setter($value);
} elseif (method_exists($this, 'get' . $name)) {
throw new InvalidCallException('Setting read-only property: ' . get_class($this) . '.' . $name);
throw new InvalidCallException('Setting read-only property: ' . get_class($this) . '::' . $name);
} else {
throw new UnknownPropertyException('Setting unknown property: ' . get_class($this) . '.' . $name);
throw new UnknownPropertyException('Setting unknown property: ' . get_class($this) . '::' . $name);
}
}
......@@ -131,7 +129,7 @@ class Object
if (method_exists($this, $setter)) {
$this->$setter(null);
} elseif (method_exists($this, 'get' . $name)) {
throw new InvalidCallException('Unsetting read-only property: ' . get_class($this) . '.' . $name);
throw new InvalidCallException('Unsetting read-only property: ' . get_class($this) . '::' . $name);
}
}
......
<?php
/**
* Request class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -13,12 +11,18 @@ namespace yii\base;
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Request extends Component
abstract class Request extends Component
{
private $_scriptFile;
private $_isConsoleRequest;
/**
* Resolves the current request into a route and the associated parameters.
* @return array the first element is the route, and the second is the associated parameters.
*/
abstract public function resolve();
/**
* Returns a value indicating whether the current request is made via command line
* @return boolean the value indicating whether the current request is made via console
*/
......@@ -39,24 +43,35 @@ class Request extends Component
/**
* Returns entry script file path.
* @return string entry script file path (processed w/ realpath())
* @throws InvalidConfigException if the entry script file path cannot be determined automatically.
*/
public function getScriptFile()
{
if ($this->_scriptFile === null) {
$this->_scriptFile = realpath($_SERVER['SCRIPT_FILENAME']);
if (isset($_SERVER['SCRIPT_FILENAME'])) {
$this->setScriptFile($_SERVER['SCRIPT_FILENAME']);
} else {
throw new InvalidConfigException('Unable to determine the entry script file path.');
}
}
return $this->_scriptFile;
}
/**
* Sets the entry script file path.
* This can be an absolute or relative file path, or a path alias.
* Note that you normally do not have to set the script file path
* as [[getScriptFile()]] can determine it based on `$_SERVER['SCRIPT_FILENAME']`.
* @param string $value the entry script file
* The entry script file path can normally be determined based on the `SCRIPT_FILENAME` SERVER variable.
* However, for some server configurations, this may not be correct or feasible.
* This setter is provided so that the entry script file path can be manually specified.
* @param string $value the entry script file path. This can be either a file path or a path alias.
* @throws InvalidConfigException if the provided entry script file path is invalid.
*/
public function setScriptFile($value)
{
$this->_scriptFile = realpath(\Yii::getAlias($value));
$scriptFile = realpath(\Yii::getAlias($value));
if ($scriptFile !== false && is_file($scriptFile)) {
$this->_scriptFile = $scriptFile;
} else {
throw new InvalidConfigException('Unable to determine the entry script file path.');
}
}
}
<?php
/**
* Response class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* SecurityManager class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
/**
* SecurityManager provides private keys, hashing and encryption functions.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class SecurityManager extends Component
{
const STATE_VALIDATION_KEY = 'Yii.SecurityManager.validationkey';
const STATE_ENCRYPTION_KEY = 'Yii.SecurityManager.encryptionkey';
/**
* @var string the name of the hashing algorithm to be used by {@link computeHMAC}.
* See {@link http://php.net/manual/en/function.hash-algos.php hash-algos} for the list of possible
* hash algorithms. Note that if you are using PHP 5.1.1 or below, you can only use 'sha1' or 'md5'.
*
* Defaults to 'sha1', meaning using SHA1 hash algorithm.
*/
public $hashAlgorithm = 'sha1';
/**
* @var mixed the name of the crypt algorithm to be used by {@link encrypt} and {@link decrypt}.
* This will be passed as the first parameter to {@link http://php.net/manual/en/function.mcrypt-module-open.php mcrypt_module_open}.
*
* This property can also be configured as an array. In this case, the array elements will be passed in order
* as parameters to mcrypt_module_open. For example, <code>array('rijndael-256', '', 'ofb', '')</code>.
*
* Defaults to 'des', meaning using DES crypt algorithm.
*/
public $cryptAlgorithm = 'des';
private $_validationKey;
private $_encryptionKey;
/**
* @return string a randomly generated private key
*/
protected function generateRandomKey()
{
return sprintf('%08x%08x%08x%08x', mt_rand(), mt_rand(), mt_rand(), mt_rand());
}
/**
* @return string the private key used to generate HMAC.
* If the key is not explicitly set, a random one is generated and returned.
*/
public function getValidationKey()
{
if ($this->_validationKey !== null) {
return $this->_validationKey;
} else {
if (($key = \Yii::$app->getGlobalState(self::STATE_VALIDATION_KEY)) !== null) {
$this->setValidationKey($key);
} else {
$key = $this->generateRandomKey();
$this->setValidationKey($key);
\Yii::$app->setGlobalState(self::STATE_VALIDATION_KEY, $key);
}
return $this->_validationKey;
}
}
/**
* @param string $value the key used to generate HMAC
* @throws CException if the key is empty
*/
public function setValidationKey($value)
{
if (!empty($value)) {
$this->_validationKey = $value;
} else {
throw new CException(Yii::t('yii|SecurityManager.validationKey cannot be empty.'));
}
}
/**
* @return string the private key used to encrypt/decrypt data.
* If the key is not explicitly set, a random one is generated and returned.
*/
public function getEncryptionKey()
{
if ($this->_encryptionKey !== null) {
return $this->_encryptionKey;
} else {
if (($key = \Yii::$app->getGlobalState(self::STATE_ENCRYPTION_KEY)) !== null) {
$this->setEncryptionKey($key);
} else {
$key = $this->generateRandomKey();
$this->setEncryptionKey($key);
\Yii::$app->setGlobalState(self::STATE_ENCRYPTION_KEY, $key);
}
return $this->_encryptionKey;
}
}
/**
* @param string $value the key used to encrypt/decrypt data.
* @throws CException if the key is empty
*/
public function setEncryptionKey($value)
{
if (!empty($value)) {
$this->_encryptionKey = $value;
} else {
throw new CException(Yii::t('yii|SecurityManager.encryptionKey cannot be empty.'));
}
}
/**
* This method has been deprecated since version 1.1.3.
* Please use {@link hashAlgorithm} instead.
* @return string
*/
public function getValidation()
{
return $this->hashAlgorithm;
}
/**
* This method has been deprecated since version 1.1.3.
* Please use {@link hashAlgorithm} instead.
* @param string $value -
*/
public function setValidation($value)
{
$this->hashAlgorithm = $value;
}
/**
* Encrypts data.
* @param string $data data to be encrypted.
* @param string $key the decryption key. This defaults to null, meaning using {@link getEncryptionKey EncryptionKey}.
* @return string the encrypted data
* @throws CException if PHP Mcrypt extension is not loaded
*/
public function encrypt($data, $key = null)
{
$module = $this->openCryptModule();
$key = $this->substr($key === null ? md5($this->getEncryptionKey()) : $key, 0, mcrypt_enc_get_key_size($module));
srand();
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($module), MCRYPT_RAND);
mcrypt_generic_init($module, $key, $iv);
$encrypted = $iv . mcrypt_generic($module, $data);
mcrypt_generic_deinit($module);
mcrypt_module_close($module);
return $encrypted;
}
/**
* Decrypts data
* @param string $data data to be decrypted.
* @param string $key the decryption key. This defaults to null, meaning using {@link getEncryptionKey EncryptionKey}.
* @return string the decrypted data
* @throws CException if PHP Mcrypt extension is not loaded
*/
public function decrypt($data, $key = null)
{
$module = $this->openCryptModule();
$key = $this->substr($key === null ? md5($this->getEncryptionKey()) : $key, 0, mcrypt_enc_get_key_size($module));
$ivSize = mcrypt_enc_get_iv_size($module);
$iv = $this->substr($data, 0, $ivSize);
mcrypt_generic_init($module, $key, $iv);
$decrypted = mdecrypt_generic($module, $this->substr($data, $ivSize, $this->strlen($data)));
mcrypt_generic_deinit($module);
mcrypt_module_close($module);
return rtrim($decrypted, "\0");
}
/**
* Opens the mcrypt module with the configuration specified in {@link cryptAlgorithm}.
* @return resource the mycrypt module handle.
* @since 1.1.3
*/
protected function openCryptModule()
{
if (extension_loaded('mcrypt')) {
if (is_array($this->cryptAlgorithm)) {
$module = @call_user_func_array('mcrypt_module_open', $this->cryptAlgorithm);
} else {
$module = @mcrypt_module_open($this->cryptAlgorithm, '', MCRYPT_MODE_CBC, '');
}
if ($module === false) {
throw new CException(Yii::t('yii|Failed to initialize the mcrypt module.'));
}
return $module;
} else {
throw new CException(Yii::t('yii|SecurityManager requires PHP mcrypt extension to be loaded in order to use data encryption feature.'));
}
}
/**
* Prefixes data with an HMAC.
* @param string $data data to be hashed.
* @param string $key the private key to be used for generating HMAC. Defaults to null, meaning using {@link validationKey}.
* @return string data prefixed with HMAC
*/
public function hashData($data, $key = null)
{
return $this->computeHMAC($data, $key) . $data;
}
/**
* Validates if data is tampered.
* @param string $data data to be validated. The data must be previously
* generated using {@link hashData()}.
* @param string $key the private key to be used for generating HMAC. Defaults to null, meaning using {@link validationKey}.
* @return string the real data with HMAC stripped off. False if the data
* is tampered.
*/
public function validateData($data, $key = null)
{
$len = $this->strlen($this->computeHMAC('test'));
if ($this->strlen($data) >= $len) {
$hmac = $this->substr($data, 0, $len);
$data2 = $this->substr($data, $len, $this->strlen($data));
return $hmac === $this->computeHMAC($data2, $key) ? $data2 : false;
} else {
return false;
}
}
/**
* Computes the HMAC for the data with {@link getValidationKey ValidationKey}.
* @param string $data data to be generated HMAC
* @param string $key the private key to be used for generating HMAC. Defaults to null, meaning using {@link validationKey}.
* @return string the HMAC for the data
*/
protected function computeHMAC($data, $key = null)
{
if ($key === null) {
$key = $this->getValidationKey();
}
if (function_exists('hash_hmac')) {
return hash_hmac($this->hashAlgorithm, $data, $key);
}
if (!strcasecmp($this->hashAlgorithm, 'sha1')) {
$pack = 'H40';
$func = 'sha1';
} else {
$pack = 'H32';
$func = 'md5';
}
if ($this->strlen($key) > 64) {
$key = pack($pack, $func($key));
}
if ($this->strlen($key) < 64) {
$key = str_pad($key, 64, chr(0));
}
$key = $this->substr($key, 0, 64);
return $func((str_repeat(chr(0x5C), 64) ^ $key) . pack($pack, $func((str_repeat(chr(0x36), 64) ^ $key) . $data)));
}
/**
* Returns the length of the given string.
* If available uses the multibyte string function mb_strlen.
* @param string $string the string being measured for length
* @return int the length of the string
*/
private function strlen($string)
{
return function_exists('mb_strlen') ? mb_strlen($string, '8bit') : strlen($string);
}
/**
* Returns the portion of string specified by the start and length parameters.
* If available uses the multibyte string function mb_substr
* @param string $string the input string. Must be one character or longer.
* @param int $start the starting position
* @param int $length the desired portion length
* @return string the extracted part of string, or FALSE on failure or an empty string.
*/
private function substr($string, $start, $length)
{
return function_exists('mb_substr') ? mb_substr($string, $start, $length, '8bit') : substr($string, $start, $length);
}
}
<?php
/**
* Theme class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -11,7 +9,7 @@ namespace yii\base;
use Yii;
use yii\base\InvalidConfigException;
use yii\util\FileHelper;
use yii\helpers\FileHelper;
/**
* Theme represents an application theme.
......@@ -42,7 +40,8 @@ class Theme extends Component
/**
* @var array the mapping between view directories and their corresponding themed versions.
* If not set, it will be initialized as a mapping from [[Application::basePath]] to [[basePath]].
* This property is used by [[apply()]] when a view is trying to apply the theme.
* This property is used by [[applyTo()]] when a view is trying to apply the theme.
* Path aliases can be used when specifying directories.
*/
public $pathMap;
......@@ -65,7 +64,9 @@ class Theme extends Component
}
$paths = array();
foreach ($this->pathMap as $from => $to) {
$paths[FileHelper::normalizePath($from) . DIRECTORY_SEPARATOR] = FileHelper::normalizePath($to) . DIRECTORY_SEPARATOR;
$from = FileHelper::normalizePath(Yii::getAlias($from));
$to = FileHelper::normalizePath(Yii::getAlias($to));
$paths[$from . DIRECTORY_SEPARATOR] = $to . DIRECTORY_SEPARATOR;
}
$this->pathMap = $paths;
}
......@@ -95,7 +96,7 @@ class Theme extends Component
* @param string $path the file to be themed
* @return string the themed file, or the original file if the themed version is not available.
*/
public function apply($path)
public function applyTo($path)
{
$path = FileHelper::normalizePath($path);
foreach ($this->pathMap as $from => $to) {
......
<?php
/**
* UnknownMethodException class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* UnknownPropertyException class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* UserException class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* Vector class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -101,7 +99,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
* Returns the item at the specified index.
* @param integer $index the index of the item
* @return mixed the item at the index
* @throws InvalidCallException if the index is out of range
* @throws InvalidParamException if the index is out of range
*/
public function itemAt($index)
{
......@@ -110,7 +108,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
} elseif ($index >= 0 && $index < $this->_c) { // in case the value is null
return $this->_d[$index];
} else {
throw new InvalidCallException('Index out of range: ' . $index);
throw new InvalidParamException('Index out of range: ' . $index);
}
}
......@@ -132,7 +130,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
* one step towards the end.
* @param integer $index the specified position.
* @param mixed $item new item to be inserted into the vector
* @throws InvalidCallException if the index specified is out of range, or the vector is read-only.
* @throws InvalidParamException if the index specified is out of range, or the vector is read-only.
*/
public function insertAt($index, $item)
{
......@@ -142,7 +140,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
array_splice($this->_d, $index, 0, array($item));
$this->_c++;
} else {
throw new InvalidCallException('Index out of range: ' . $index);
throw new InvalidParamException('Index out of range: ' . $index);
}
}
......@@ -169,7 +167,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
* Removes an item at the specified position.
* @param integer $index the index of the item to be removed.
* @return mixed the removed item.
* @throws InvalidCallException if the index is out of range, or the vector is read only.
* @throws InvalidParamException if the index is out of range, or the vector is read only.
*/
public function removeAt($index)
{
......@@ -183,7 +181,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
return $item;
}
} else {
throw new InvalidCallException('Index out of range: ' . $index);
throw new InvalidParamException('Index out of range: ' . $index);
}
}
......@@ -242,7 +240,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
* Copies iterable data into the vector.
* Note, existing data in the vector will be cleared first.
* @param mixed $data the data to be copied from, must be an array or an object implementing `Traversable`
* @throws InvalidCallException if data is neither an array nor an object implementing `Traversable`.
* @throws InvalidParamException if data is neither an array nor an object implementing `Traversable`.
*/
public function copyFrom($data)
{
......@@ -257,7 +255,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
$this->add($item);
}
} else {
throw new InvalidCallException('Data must be either an array or an object implementing Traversable.');
throw new InvalidParamException('Data must be either an array or an object implementing Traversable.');
}
}
......@@ -265,7 +263,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
* Merges iterable data into the vector.
* New items will be appended to the end of the existing items.
* @param array|\Traversable $data the data to be merged with. It must be an array or object implementing Traversable
* @throws InvalidCallException if data is neither an array nor an object implementing `Traversable`.
* @throws InvalidParamException if data is neither an array nor an object implementing `Traversable`.
*/
public function mergeWith($data)
{
......@@ -277,7 +275,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
$this->add($item);
}
} else {
throw new InvalidCallException('The data to be merged with must be an array or an object implementing Traversable.');
throw new InvalidParamException('The data to be merged with must be an array or an object implementing Traversable.');
}
}
......
<?php
/**
* VectorIterator class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* ViewRenderer class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* Widget class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
use Yii;
use yii\helpers\FileHelper;
/**
* Widget is the base class for widgets.
*
......@@ -72,35 +73,26 @@ class Widget extends Component
/**
* Renders a view.
*
* The method first finds the actual view file corresponding to the specified view.
* It then calls [[renderFile()]] to render the view file. The rendering result is returned
* as a string. If the view file does not exist, an exception will be thrown.
*
* To determine which view file should be rendered, the method calls [[findViewFile()]] which
* will search in the directories as specified by [[basePath]].
*
* View name can be a path alias representing an absolute file path (e.g. `@app/views/layout/index`),
* or a path relative to [[basePath]]. The file suffix is optional and defaults to `.php` if not given
* in the view name.
*
* @param string $view the view to be rendered. This can be either a path alias or a path relative to [[basePath]].
* @param array $params the parameters that should be made available in the view. The PHP function `extract()`
* will be called on this variable to extract the variables from this parameter.
* @return string the rendering result
* @throws Exception if the view file cannot be found
* @param string $view the view name. Please refer to [[findViewFile()]] on how to specify a view name.
* @param array $params the parameters (name-value pairs) that should be made available in the view.
* @return string the rendering result.
* @throws InvalidParamException if the view file does not exist.
*/
public function render($view, $params = array())
{
return $this->createView()->renderPartial($view, $params);
return Yii::$app->getView()->render($view, $params, $this);
}
/**
* @return View
* Renders a view file.
* @param string $file the view file to be rendered. This can be either a file path or a path alias.
* @param array $params the parameters (name-value pairs) that should be made available in the view.
* @return string the rendering result.
* @throws InvalidParamException if the view file does not exist.
*/
public function createView()
public function renderFile($file, $params = array())
{
return new View($this);
return Yii::$app->getView()->renderFile($file, $params, $this);
}
/**
......
<?php
/**
* ApcCache class file
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* Cache class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\caching;
use yii\base\Component;
use yii\helpers\StringHelper;
/**
* Cache is the base class for cache classes supporting different cache storage implementation.
......@@ -72,13 +71,13 @@ abstract class Cache extends Component implements \ArrayAccess
/**
* Builds a normalized cache key from one or multiple parameters.
* Builds a normalized cache key from a given key.
*
* The generated key contains letters and digits only, and its length is no more than 32.
*
* If only one parameter is given and it is already a normalized key, then
* it will be returned back without change. Otherwise, a normalized key
* is generated by serializing all given parameters and applying MD5 hashing.
* If the given key is a string containing alphanumeric characters only and no more than 32 characters,
* then the key will be returned back without change. Otherwise, a normalized key
* is generated by serializing the given key and applying MD5 hashing.
*
* The following example builds a cache key using three parameters:
*
......@@ -86,16 +85,15 @@ abstract class Cache extends Component implements \ArrayAccess
* $key = $cache->buildKey($className, $method, $id);
* ~~~
*
* @param string $key the first parameter
* @param array|string $key the key to be normalized
* @return string the generated cache key
*/
public function buildKey($key)
{
if (func_num_args() === 1 && ctype_alnum($key) && strlen($key) <= 32) {
return (string)$key;
if (is_string($key)) {
return ctype_alnum($key) && StringHelper::strlen($key) <= 32 ? $key : md5($key);
} else {
$params = func_get_args();
return md5(serialize($params));
return md5(json_encode($key));
}
}
......
<?php
/**
* ChainedDependency class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* DbCache class file
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* DbDependency class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\caching;
use Yii;
use yii\base\InvalidConfigException;
use yii\db\Connection;
use yii\db\Query;
/**
* DbDependency represents a dependency based on the query result of a SQL statement.
*
* If the query result changes, the dependency is considered as changed.
* The query is specified via the [[query]] property.
* The query is specified via the [[sql]] property.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
......@@ -29,23 +27,25 @@ class DbDependency extends Dependency
*/
public $connectionID = 'db';
/**
* @var Query the SQL query whose result is used to determine if the dependency has been changed.
* @var string the SQL query whose result is used to determine if the dependency has been changed.
* Only the first row of the query result will be used.
*/
public $query;
public $sql;
/**
* @var Connection the DB connection instance
* @var array the parameters (name=>value) to be bound to the SQL statement specified by [[sql]].
*/
private $_db;
public $params;
/**
* Constructor.
* @param Query $query the SQL query whose result is used to determine if the dependency has been changed.
* @param string $sql the SQL query whose result is used to determine if the dependency has been changed.
* @param array $params the parameters (name=>value) to be bound to the SQL statement specified by [[sql]].
* @param array $config name-value pairs that will be used to initialize the object properties
*/
public function __construct($query = null, $config = array())
public function __construct($sql, $params = array(), $config = array())
{
$this->query = $query;
$this->sql = $sql;
$this->params = $params;
parent::__construct($config);
}
......@@ -68,22 +68,23 @@ class DbDependency extends Dependency
protected function generateDependencyData()
{
$db = $this->getDb();
/**
* @var \yii\db\Command $command
*/
$command = $this->query->createCommand($db);
if ($db->enableQueryCache) {
// temporarily disable and re-enable query caching
$db->enableQueryCache = false;
$result = $command->queryRow();
$result = $db->createCommand($this->sql, $this->params)->queryRow();
$db->enableQueryCache = true;
} else {
$result = $command->queryRow();
$result = $db->createCommand($this->sql, $this->params)->queryRow();
}
return $result;
}
/**
* @var Connection the DB connection instance
*/
private $_db;
/**
* Returns the DB connection instance used for caching purpose.
* @return Connection the DB connection instance
* @throws InvalidConfigException if [[connectionID]] does not point to a valid application component.
......@@ -91,11 +92,11 @@ class DbDependency extends Dependency
public function getDb()
{
if ($this->_db === null) {
$db = \Yii::$app->getComponent($this->connectionID);
$db = Yii::$app->getComponent($this->connectionID);
if ($db instanceof Connection) {
$this->_db = $db;
} else {
throw new InvalidConfigException("DbCache::connectionID must refer to the ID of a DB application component.");
throw new InvalidConfigException("DbCacheDependency::connectionID must refer to the ID of a DB application component.");
}
}
return $this->_db;
......
<?php
/**
* Dependency class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* DummyCache class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* ExpressionDependency class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* FileCache class file
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -54,9 +52,6 @@ class FileCache extends Cache
{
parent::init();
$this->cachePath = \Yii::getAlias($this->cachePath);
if ($this->cachePath === false) {
throw new InvalidConfigException('FileCache.cachePath must be a valid path alias.');
}
if (!is_dir($this->cachePath)) {
mkdir($this->cachePath, 0777, true);
}
......
<?php
/**
* FileDependency class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* MemCache class file
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* MemCacheServer class file
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* WinCache class file
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* XCache class file
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* ZendDataCache class file
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
......@@ -3,7 +3,7 @@
* Console Application class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -91,9 +91,10 @@ class Application extends \yii\base\Application
/** @var $request Request */
$request = $this->getRequest();
if ($request->getIsConsoleRequest()) {
return $this->runAction($request->route, $request->params);
list ($route, $params) = $request->resolve();
return $this->runAction($route, $params);
} else {
throw new Exception(\Yii::t('yii|this script must be run from the command line.'));
throw new Exception(\Yii::t('yii|This script must be run from the command line.'));
}
}
......@@ -126,7 +127,7 @@ class Application extends \yii\base\Application
'message' => 'yii\console\controllers\MessageController',
'help' => 'yii\console\controllers\HelpController',
'migrate' => 'yii\console\controllers\MigrateController',
'app' => 'yii\console\controllers\CreateController',
'app' => 'yii\console\controllers\AppController',
'cache' => 'yii\console\controllers\CacheController',
);
}
......
<?php
/**
* Controller class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* Exception class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* Request class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -17,49 +15,37 @@ class Request extends \yii\base\Request
{
const ANONYMOUS_PARAMS = '-args';
/**
* @var string the controller route specified by this request. If this is an empty string,
* it means the [[Application::defaultRoute|default route]] will be used.
* Note that the value of this property may not be a correct route. The console application
* will determine it is valid or not when it attempts to execute with this route.
*/
public $route;
/**
* @var array
*/
public $params;
public function init()
{
parent::init();
$this->resolveRequest();
}
public function getRawParams()
{
return isset($_SERVER['argv']) ? $_SERVER['argv'] : array();
}
protected function resolveRequest()
/**
* Resolves the current request into a route and the associated parameters.
* @return array the first element is the route, and the second is the associated parameters.
*/
public function resolve()
{
$rawParams = $this->getRawParams();
array_shift($rawParams); // the 1st argument is the yiic script name
if (isset($rawParams[0])) {
$this->route = $rawParams[0];
$route = $rawParams[0];
array_shift($rawParams);
} else {
$this->route = '';
$route = '';
}
$this->params = array(self::ANONYMOUS_PARAMS => array());
$params = array(self::ANONYMOUS_PARAMS => array());
foreach ($rawParams as $param) {
if (preg_match('/^--(\w+)(=(.*))?$/', $param, $matches)) {
$name = $matches[1];
$this->params[$name] = isset($matches[3]) ? $matches[3] : true;
$params[$name] = isset($matches[3]) ? $matches[3] : true;
} else {
$this->params[self::ANONYMOUS_PARAMS][] = $param;
$params[self::ANONYMOUS_PARAMS][] = $param;
}
}
return array($route, $params);
}
}
<?php
/**
* CreateController class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\console\controllers;
use yii\console\Controller;
use yii\util\FileHelper;
use yii\helpers\FileHelper;
use yii\base\Exception;
/**
......@@ -20,14 +18,14 @@ use yii\base\Exception;
* @author Alexander Makarov <sam@rmcreative.ru>
* @since 2.0
*/
class CreateController extends Controller
class AppController extends Controller
{
private $_rootPath;
private $_config;
/**
* @var string custom template path. If specified, templates will be
* searched there additionally to `framework/console/create`.
* searched there additionally to `framework/console/webapp`.
*/
public $templatesPath;
......@@ -46,6 +44,16 @@ class CreateController extends Controller
}
}
public function globalOptions()
{
return array('templatesPath', 'type');
}
public function actionIndex()
{
$this->forward('help/index', array('-args' => array('app/create')));
}
/**
* Generates Yii application at the path specified via appPath parameter.
*
......@@ -56,7 +64,7 @@ class CreateController extends Controller
* @throws \yii\base\Exception if path specified is not valid
* @return integer the exit status
*/
public function actionIndex($path)
public function actionCreate($path)
{
$path = strtr($path, '/\\', DIRECTORY_SEPARATOR);
if(strpos($path, DIRECTORY_SEPARATOR) === false) {
......@@ -127,7 +135,7 @@ class CreateController extends Controller
*/
protected function getDefaultTemplatesPath()
{
return realpath(__DIR__.'/../create');
return realpath(__DIR__.'/../webapp');
}
/**
......
<?php
/**
* CacheController class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* HelpController class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -15,7 +13,7 @@ use yii\console\Exception;
use yii\base\InlineAction;
use yii\console\Controller;
use yii\console\Request;
use yii\util\StringHelper;
use yii\helpers\StringHelper;
/**
* This command provides help information about console commands.
......
<?php
/**
* MessageController class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* MigrateController class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -15,7 +13,7 @@ use yii\console\Exception;
use yii\console\Controller;
use yii\db\Connection;
use yii\db\Query;
use yii\util\ArrayHelper;
use yii\helpers\ArrayHelper;
/**
* This command manages application migrations.
......@@ -116,7 +114,7 @@ class MigrateController extends Controller
{
if (parent::beforeAction($action)) {
$path = Yii::getAlias($this->migrationPath);
if ($path === false || !is_dir($path)) {
if (!is_dir($path)) {
throw new Exception("The migration directory \"{$this->migrationPath}\" does not exist.");
}
$this->migrationPath = $path;
......
<?php
/** @var $controller \yii\console\controllers\CreateController */
/** @var $controller \yii\console\controllers\AppController */
$controller = $this;
return array(
......
<?php
/**
* ActiveQuery class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* ActiveRecord class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\db;
use yii\base\Model;
use yii\base\Event;
use yii\base\InvalidParamException;
use yii\base\ModelEvent;
use yii\base\UnknownMethodException;
use yii\base\InvalidCallException;
use yii\db\Connection;
use yii\db\TableSchema;
use yii\db\Expression;
use yii\util\StringHelper;
use yii\helpers\StringHelper;
/**
* ActiveRecord is the base class for classes representing relational data in terms of objects.
......@@ -1045,7 +1043,7 @@ class ActiveRecord extends Model
* It can be declared in either the Active Record class itself or one of its behaviors.
* @param string $name the relation name
* @return ActiveRelation the relation object
* @throws InvalidCallException if the named relation does not exist.
* @throws InvalidParamException if the named relation does not exist.
*/
public function getRelation($name)
{
......@@ -1057,7 +1055,7 @@ class ActiveRecord extends Model
}
} catch (UnknownMethodException $e) {
}
throw new InvalidCallException(get_class($this) . ' has no relation named "' . $name . '".');
throw new InvalidParamException(get_class($this) . ' has no relation named "' . $name . '".');
}
/**
......
<?php
/**
* ActiveRelation class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -57,16 +55,16 @@ class ActiveRelation extends ActiveQuery
/**
* Specifies the relation associated with the pivot table.
* @param string $relationName the relation name. This refers to a relation declared in [[primaryModel]].
* @param callback $callback a PHP callback for customizing the relation associated with the pivot table.
* @param callable $callable a PHP callback for customizing the relation associated with the pivot table.
* Its signature should be `function($query)`, where `$query` is the query to be customized.
* @return ActiveRelation the relation object itself.
*/
public function via($relationName, $callback = null)
public function via($relationName, $callable = null)
{
$relation = $this->primaryModel->getRelation($relationName);
$this->via = array($relationName, $relation);
if ($callback !== null) {
call_user_func($callback, $relation);
if ($callable !== null) {
call_user_func($callable, $relation);
}
return $this;
}
......@@ -77,11 +75,11 @@ class ActiveRelation extends ActiveQuery
* @param array $link the link between the pivot table and the table associated with [[primaryModel]].
* The keys of the array represent the columns in the pivot table, and the values represent the columns
* in the [[primaryModel]] table.
* @param callback $callback a PHP callback for customizing the relation associated with the pivot table.
* @param callable $callable a PHP callback for customizing the relation associated with the pivot table.
* Its signature should be `function($query)`, where `$query` is the query to be customized.
* @return ActiveRelation
*/
public function viaTable($tableName, $link, $callback = null)
public function viaTable($tableName, $link, $callable = null)
{
$relation = new ActiveRelation(array(
'modelClass' => get_class($this->primaryModel),
......@@ -91,8 +89,8 @@ class ActiveRelation extends ActiveQuery
'asArray' => true,
));
$this->via = $relation;
if ($callback !== null) {
call_user_func($callback, $relation);
if ($callable !== null) {
call_user_func($callable, $relation);
}
return $this;
}
......
<?php
/**
* ColumnSchema class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* Command class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -136,7 +134,7 @@ class Command extends \yii\base\Component
} catch (\Exception $e) {
\Yii::error($e->getMessage() . "\nFailed to prepare SQL: $sql", __CLASS__);
$errorInfo = $e instanceof \PDOException ? $e->errorInfo : null;
throw new Exception($e->getMessage(), (int)$e->getCode(), $errorInfo);
throw new Exception($e->getMessage(), $errorInfo, (int)$e->getCode());
}
}
}
......@@ -294,7 +292,7 @@ class Command extends \yii\base\Component
\Yii::error("$message\nFailed to execute SQL: {$sql}{$paramLog}", __CLASS__);
$errorInfo = $e instanceof \PDOException ? $e->errorInfo : null;
throw new Exception($message, (int)$e->getCode(), $errorInfo);
throw new Exception($message, $errorInfo, (int)$e->getCode());
}
}
......@@ -391,7 +389,13 @@ class Command extends \yii\base\Component
}
if (isset($cache)) {
$cacheKey = $cache->buildKey(__CLASS__, $db->dsn, $db->username, $sql, $paramLog);
$cacheKey = $cache->buildKey(array(
__CLASS__,
$db->dsn,
$db->username,
$sql,
$paramLog,
));
if (($result = $cache->get($cacheKey)) !== false) {
\Yii::trace('Query result found in cache', __CLASS__);
return $result;
......@@ -433,7 +437,7 @@ class Command extends \yii\base\Component
$message = $e->getMessage();
\Yii::error("$message\nCommand::$method() failed: {$sql}{$paramLog}", __CLASS__);
$errorInfo = $e instanceof \PDOException ? $e->errorInfo : null;
throw new Exception($message, (int)$e->getCode(), $errorInfo);
throw new Exception($message, $errorInfo, (int)$e->getCode());
}
}
......
<?php
/**
* Connection class file
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -322,7 +320,7 @@ class Connection extends Component
{
if ($this->pdo === null) {
if (empty($this->dsn)) {
throw new InvalidConfigException('Connection.dsn cannot be empty.');
throw new InvalidConfigException('Connection::dsn cannot be empty.');
}
try {
\Yii::trace('Opening DB connection: ' . $this->dsn, __CLASS__);
......@@ -332,7 +330,7 @@ class Connection extends Component
catch (\PDOException $e) {
\Yii::error("Failed to open DB connection ({$this->dsn}): " . $e->getMessage(), __CLASS__);
$message = YII_DEBUG ? 'Failed to open DB connection: ' . $e->getMessage() : 'Failed to open DB connection.';
throw new Exception($message, (int)$e->getCode(), $e->errorInfo);
throw new Exception($message, $e->errorInfo, (int)$e->getCode());
}
}
}
......
<?php
/**
* DataReader class file
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* Exception class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -26,13 +24,14 @@ class Exception extends \yii\base\Exception
/**
* Constructor.
* @param string $message PDO error message
* @param integer $code PDO error code
* @param mixed $errorInfo PDO error info
* @param integer $code PDO error code
* @param \Exception $previous The previous exception used for the exception chaining.
*/
public function __construct($message, $code = 0, $errorInfo = null)
public function __construct($message, $errorInfo = null, $code = 0, \Exception $previous = null)
{
$this->errorInfo = $errorInfo;
parent::__construct($message, $code);
parent::__construct($message, $code, $previous);
}
/**
......
<?php
/**
* Expression class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* Migration class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* Query class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -37,9 +35,19 @@ namespace yii\db;
class Query extends \yii\base\Component
{
/**
* @var string|array the columns being selected. This refers to the SELECT clause in a SQL
* statement. It can be either a string (e.g. `'id, name'`) or an array (e.g. `array('id', 'name')`).
* If not set, if means all columns.
* Sort ascending
* @see orderBy
*/
const SORT_ASC = false;
/**
* Sort ascending
* @see orderBy
*/
const SORT_DESC = true;
/**
* @var array the columns being selected. For example, `array('id', 'name')`.
* This is used to construct the SELECT clause in a SQL statement. If not set, if means selecting all columns.
* @see select()
*/
public $select;
......@@ -54,8 +62,8 @@ class Query extends \yii\base\Component
*/
public $distinct;
/**
* @var string|array the table(s) to be selected from. This refers to the FROM clause in a SQL statement.
* It can be either a string (e.g. `'tbl_user, tbl_post'`) or an array (e.g. `array('tbl_user', 'tbl_post')`).
* @var array the table(s) to be selected from. For example, `array('tbl_user', 'tbl_post')`.
* This is used to construct the FROM clause in a SQL statement.
* @see from()
*/
public $from;
......@@ -75,20 +83,33 @@ class Query extends \yii\base\Component
*/
public $offset;
/**
* @var string|array how to sort the query results. This refers to the ORDER BY clause in a SQL statement.
* It can be either a string (e.g. `'id ASC, name DESC'`) or an array (e.g. `array('id ASC', 'name DESC')`).
* @var array how to sort the query results. This is used to construct the ORDER BY clause in a SQL statement.
* The array keys are the columns to be sorted by, and the array values are the corresponding sort directions which
* can be either [[Query::SORT_ASC]] or [[Query::SORT_DESC]]. The array may also contain [[Expression]] objects.
* If that is the case, the expressions will be converted into strings without any change.
*/
public $orderBy;
/**
* @var string|array how to group the query results. This refers to the GROUP BY clause in a SQL statement.
* It can be either a string (e.g. `'company, department'`) or an array (e.g. `array('company', 'department')`).
* @var array how to group the query results. For example, `array('company', 'department')`.
* This is used to construct the GROUP BY clause in a SQL statement.
*/
public $groupBy;
/**
* @var string|array how to join with other tables. This refers to the JOIN clause in a SQL statement.
* It can be either a string (e.g. `'LEFT JOIN tbl_user ON tbl_user.id=author_id'`) or an array (e.g.
* `array('LEFT JOIN tbl_user ON tbl_user.id=author_id', 'LEFT JOIN tbl_team ON tbl_team.id=team_id')`).
* @see join()
* @var array how to join with other tables. Each array element represents the specification
* of one join which has the following structure:
*
* ~~~
* array($joinType, $tableName, $joinCondition)
* ~~~
*
* For example,
*
* ~~~
* array(
* array('INNER JOIN', 'tbl_user', 'tbl_user.id = author_id'),
* array('LEFT JOIN', 'tbl_team', 'tbl_team.id = team_id'),
* )
* ~~~
*/
public $join;
/**
......@@ -97,9 +118,8 @@ class Query extends \yii\base\Component
*/
public $having;
/**
* @var string|Query[] the UNION clause(s) in a SQL statement. This can be either a string
* representing a single UNION clause or an array representing multiple UNION clauses.
* Each union clause can be a string or a `Query` object which refers to the SQL statement.
* @var array this is used to construct the UNION clause(s) in a SQL statement.
* Each array element can be either a string or a [[Query]] object representing a sub-query.
*/
public $union;
/**
......@@ -136,6 +156,9 @@ class Query extends \yii\base\Component
*/
public function select($columns, $option = null)
{
if (!is_array($columns)) {
$columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY);
}
$this->select = $columns;
$this->selectOption = $option;
return $this;
......@@ -163,6 +186,9 @@ class Query extends \yii\base\Component
*/
public function from($tables)
{
if (!is_array($tables)) {
$tables = preg_split('/\s*,\s*/', trim($tables), -1, PREG_SPLIT_NO_EMPTY);
}
$this->from = $tables;
return $this;
}
......@@ -362,10 +388,13 @@ class Query extends \yii\base\Component
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
* @return Query the query object itself
* @see addGroup()
* @see addGroupBy()
*/
public function groupBy($columns)
{
if (!is_array($columns)) {
$columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY);
}
$this->groupBy = $columns;
return $this;
}
......@@ -377,19 +406,16 @@ class Query extends \yii\base\Component
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
* @return Query the query object itself
* @see group()
* @see groupBy()
*/
public function addGroup($columns)
public function addGroupBy($columns)
{
if (empty($this->groupBy)) {
if (!is_array($columns)) {
$columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY);
}
if ($this->groupBy === null) {
$this->groupBy = $columns;
} else {
if (!is_array($this->groupBy)) {
$this->groupBy = preg_split('/\s*,\s*/', trim($this->groupBy), -1, PREG_SPLIT_NO_EMPTY);
}
if (!is_array($columns)) {
$columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY);
}
$this->groupBy = array_merge($this->groupBy, $columns);
}
return $this;
......@@ -456,43 +482,58 @@ class Query extends \yii\base\Component
/**
* Sets the ORDER BY part of the query.
* @param string|array $columns the columns (and the directions) to be ordered by.
* Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array (e.g. array('id ASC', 'name DESC')).
* Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array
* (e.g. `array('id' => Query::SORT_ASC ASC, 'name' => Query::SORT_DESC)`).
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
* @return Query the query object itself
* @see addOrder()
* @see addOrderBy()
*/
public function orderBy($columns)
{
$this->orderBy = $columns;
$this->orderBy = $this->normalizeOrderBy($columns);
return $this;
}
/**
* Adds additional ORDER BY columns to the query.
* @param string|array $columns the columns (and the directions) to be ordered by.
* Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array (e.g. array('id ASC', 'name DESC')).
* Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array
* (e.g. `array('id' => Query::SORT_ASC ASC, 'name' => Query::SORT_DESC)`).
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
* @return Query the query object itself
* @see order()
* @see orderBy()
*/
public function addOrderBy($columns)
{
if (empty($this->orderBy)) {
$columns = $this->normalizeOrderBy($columns);
if ($this->orderBy === null) {
$this->orderBy = $columns;
} else {
if (!is_array($this->orderBy)) {
$this->orderBy = preg_split('/\s*,\s*/', trim($this->orderBy), -1, PREG_SPLIT_NO_EMPTY);
}
if (!is_array($columns)) {
$columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY);
}
$this->orderBy = array_merge($this->orderBy, $columns);
}
return $this;
}
protected function normalizeOrderBy($columns)
{
if (is_array($columns)) {
return $columns;
} else {
$columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY);
$result = array();
foreach ($columns as $column) {
if (preg_match('/^(.*?)\s+(asc|desc)$/i', $column, $matches)) {
$result[$matches[1]] = strcasecmp($matches[2], 'desc') ? self::SORT_ASC : self::SORT_DESC;
} else {
$result[$column] = self::SORT_ASC;
}
}
return $result;
}
}
/**
* Sets the LIMIT part of the query.
* @param integer $limit the limit
......
<?php
/**
* QueryBuilder class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -62,10 +60,10 @@ class QueryBuilder extends \yii\base\Object
$this->buildFrom($query->from),
$this->buildJoin($query->join),
$this->buildWhere($query->where),
$this->buildGroup($query->groupBy),
$this->buildGroupBy($query->groupBy),
$this->buildHaving($query->having),
$this->buildUnion($query->union),
$this->buildOrder($query->orderBy),
$this->buildOrderBy($query->orderBy),
$this->buildLimit($query->limit, $query->offset),
);
return implode($this->separator, array_filter($clauses));
......@@ -592,21 +590,19 @@ class QueryBuilder extends \yii\base\Object
return $operator === 'IN' ? '0=1' : '';
}
if (is_array($column)) {
if (count($column) > 1) {
return $this->buildCompositeInCondition($operator, $column, $values);
if (count($column) > 1) {
return $this->buildCompositeInCondition($operator, $column, $values);
} elseif (is_array($column)) {
$column = reset($column);
}
foreach ($values as $i => $value) {
if (is_array($value)) {
$value = isset($value[$column]) ? $value[$column] : null;
}
if ($value === null) {
$values[$i] = 'NULL';
} else {
$column = reset($column);
foreach ($values as $i => $value) {
if (is_array($value)) {
$value = isset($value[$column]) ? $value[$column] : null;
}
if ($value === null) {
$values[$i] = 'NULL';
} else {
$values[$i] = is_string($value) ? $this->db->quoteValue($value) : (string)$value;
}
}
$values[$i] = is_string($value) ? $this->db->quoteValue($value) : (string)$value;
}
}
if (strpos($column, '(') === false) {
......@@ -677,7 +673,7 @@ class QueryBuilder extends \yii\base\Object
}
/**
* @param string|array $columns
* @param array $columns
* @param boolean $distinct
* @param string $selectOption
* @return string the SELECT clause built from [[query]].
......@@ -693,13 +689,6 @@ class QueryBuilder extends \yii\base\Object
return $select . ' *';
}
if (!is_array($columns)) {
if (strpos($columns, '(') !== false) {
return $select . ' ' . $columns;
} else {
$columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY);
}
}
foreach ($columns as $i => $column) {
if (is_object($column)) {
$columns[$i] = (string)$column;
......@@ -720,7 +709,7 @@ class QueryBuilder extends \yii\base\Object
}
/**
* @param string|array $tables
* @param array $tables
* @return string the FROM clause built from [[query]].
*/
public function buildFrom($tables)
......@@ -729,13 +718,6 @@ class QueryBuilder extends \yii\base\Object
return '';
}
if (!is_array($tables)) {
if (strpos($tables, '(') !== false) {
return 'FROM ' . $tables;
} else {
$tables = preg_split('/\s*,\s*/', trim($tables), -1, PREG_SPLIT_NO_EMPTY);
}
}
foreach ($tables as $i => $table) {
if (strpos($table, '(') === false) {
if (preg_match('/^(.*?)(?i:\s+as\s+|\s+)(.*)$/i', $table, $matches)) { // with alias
......@@ -756,37 +738,36 @@ class QueryBuilder extends \yii\base\Object
/**
* @param string|array $joins
* @return string the JOIN clause built from [[query]].
* @throws Exception if the $joins parameter is not in proper format
*/
public function buildJoin($joins)
{
if (empty($joins)) {
return '';
}
if (is_string($joins)) {
return $joins;
}
foreach ($joins as $i => $join) {
if (is_array($join)) { // 0:join type, 1:table name, 2:on-condition
if (isset($join[0], $join[1])) {
$table = $join[1];
if (strpos($table, '(') === false) {
if (preg_match('/^(.*?)(?i:\s+as\s+|\s+)(.*)$/', $table, $matches)) { // with alias
$table = $this->db->quoteTableName($matches[1]) . ' ' . $this->db->quoteTableName($matches[2]);
} else {
$table = $this->db->quoteTableName($table);
}
if (is_object($join)) {
$joins[$i] = (string)$join;
} elseif (is_array($join) && isset($join[0], $join[1])) {
// 0:join type, 1:table name, 2:on-condition
$table = $join[1];
if (strpos($table, '(') === false) {
if (preg_match('/^(.*?)(?i:\s+as\s+|\s+)(.*)$/', $table, $matches)) { // with alias
$table = $this->db->quoteTableName($matches[1]) . ' ' . $this->db->quoteTableName($matches[2]);
} else {
$table = $this->db->quoteTableName($table);
}
$joins[$i] = $join[0] . ' ' . $table;
if (isset($join[2])) {
$condition = $this->buildCondition($join[2]);
if ($condition !== '') {
$joins[$i] .= ' ON ' . $this->buildCondition($join[2]);
}
}
$joins[$i] = $join[0] . ' ' . $table;
if (isset($join[2])) {
$condition = $this->buildCondition($join[2]);
if ($condition !== '') {
$joins[$i] .= ' ON ' . $this->buildCondition($join[2]);
}
} else {
throw new Exception('A join clause must be specified as an array of at least two elements.');
}
} else {
throw new Exception('A join clause must be specified as an array of join type, join table, and optionally join condition.');
}
}
......@@ -804,16 +785,12 @@ class QueryBuilder extends \yii\base\Object
}
/**
* @param string|array $columns
* @param array $columns
* @return string the GROUP BY clause
*/
public function buildGroup($columns)
public function buildGroupBy($columns)
{
if (empty($columns)) {
return '';
} else {
return 'GROUP BY ' . $this->buildColumns($columns);
}
return empty($columns) ? '' : 'GROUP BY ' . $this->buildColumns($columns);
}
/**
......@@ -827,36 +804,24 @@ class QueryBuilder extends \yii\base\Object
}
/**
* @param string|array $columns
* @param array $columns
* @return string the ORDER BY clause built from [[query]].
*/
public function buildOrder($columns)
public function buildOrderBy($columns)
{
if (empty($columns)) {
return '';
}
if (!is_array($columns)) {
if (strpos($columns, '(') !== false) {
return 'ORDER BY ' . $columns;
$orders = array();
foreach ($columns as $name => $direction) {
if (is_object($direction)) {
$orders[] = (string)$direction;
} else {
$columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY);
}
}
foreach ($columns as $i => $column) {
if (is_object($column)) {
$columns[$i] = (string)$column;
} elseif (strpos($column, '(') === false) {
if (preg_match('/^(.*?)\s+(asc|desc)$/i', $column, $matches)) {
$columns[$i] = $this->db->quoteColumnName($matches[1]) . ' ' . $matches[2];
} else {
$columns[$i] = $this->db->quoteColumnName($column);
}
$orders[] = $this->db->quoteColumnName($name) . ($direction === Query::SORT_DESC ? ' DESC' : '');
}
}
if (is_array($columns)) {
$columns = implode(', ', $columns);
}
return 'ORDER BY ' . $columns;
return 'ORDER BY ' . implode(', ', $orders);
}
/**
......@@ -877,7 +842,7 @@ class QueryBuilder extends \yii\base\Object
}
/**
* @param string|array $unions
* @param array $unions
* @return string the UNION clause built from [[query]].
*/
public function buildUnion($unions)
......@@ -885,9 +850,6 @@ class QueryBuilder extends \yii\base\Object
if (empty($unions)) {
return '';
}
if (!is_array($unions)) {
$unions = array($unions);
}
foreach ($unions as $i => $union) {
if ($union instanceof Query) {
$unions[$i] = $this->build($union);
......
<?php
/**
* Driver class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......@@ -111,7 +109,12 @@ abstract class Schema extends \yii\base\Object
*/
public function getCacheKey($cache, $name)
{
return $cache->buildKey(__CLASS__, $this->db->dsn, $this->db->username, $name);
return $cache->buildKey(array(
__CLASS__,
$this->db->dsn,
$this->db->username,
$name,
));
}
/**
......
<?php
/**
* TableSchema class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008-2011 Yii Software LLC
* @license http://www.yiiframework.com/license/
......@@ -9,7 +7,7 @@
namespace yii\db;
use yii\base\InvalidCallException;
use yii\base\InvalidParamException;
/**
* TableSchema represents the metadata of a database table.
......@@ -83,7 +81,7 @@ class TableSchema extends \yii\base\Object
/**
* Manually specifies the primary key for this table.
* @param string|array $keys the primary key (can be composite)
* @throws InvalidCallException if the specified key cannot be found in the table.
* @throws InvalidParamException if the specified key cannot be found in the table.
*/
public function fixPrimaryKey($keys)
{
......@@ -98,7 +96,7 @@ class TableSchema extends \yii\base\Object
if (isset($this->columns[$key])) {
$this->columns[$key]->isPrimaryKey = true;
} else {
throw new InvalidCallException("Primary key '$key' cannot be found in table '{$this->name}'.");
throw new InvalidParamException("Primary key '$key' cannot be found in table '{$this->name}'.");
}
}
}
......
<?php
/**
* Transaction class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* QueryBuilder class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\db\mysql;
use yii\db\Exception;
use yii\base\InvalidCallException;
use yii\base\InvalidParamException;
/**
* QueryBuilder is the query builder for MySQL databases.
......@@ -54,7 +52,7 @@ class QueryBuilder extends \yii\db\QueryBuilder
$quotedTable = $this->db->quoteTableName($table);
$row = $this->db->createCommand('SHOW CREATE TABLE ' . $quotedTable)->queryRow();
if ($row === false) {
throw new Exception("Unable to find '$oldName' in table '$table'.");
throw new Exception("Unable to find column '$oldName' in table '$table'.");
}
if (isset($row['Create Table'])) {
$sql = $row['Create Table'];
......@@ -98,7 +96,7 @@ class QueryBuilder extends \yii\db\QueryBuilder
* @param mixed $value the value for the primary key of the next new row inserted. If this is not set,
* the next new row's primary key will have a value 1.
* @return string the SQL statement for resetting sequence
* @throws InvalidCallException if the table does not exist or there is no sequence associated with the table.
* @throws InvalidParamException if the table does not exist or there is no sequence associated with the table.
*/
public function resetSequence($tableName, $value = null)
{
......@@ -113,9 +111,9 @@ class QueryBuilder extends \yii\db\QueryBuilder
}
return "ALTER TABLE $tableName AUTO_INCREMENT=$value";
} elseif ($table === null) {
throw new InvalidCallException("Table not found: $tableName");
throw new InvalidParamException("Table not found: $tableName");
} else {
throw new InvalidCallException("There is not sequence associated with table '$tableName'.'");
throw new InvalidParamException("There is not sequence associated with table '$tableName'.'");
}
}
......
<?php
/**
* Schema class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* QueryBuilder class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\db\sqlite;
use yii\db\Exception;
use yii\base\InvalidParamException;
use yii\base\NotSupportedException;
use yii\base\InvalidCallException;
/**
* QueryBuilder is the query builder for SQLite databases.
......@@ -50,7 +48,7 @@ class QueryBuilder extends \yii\db\QueryBuilder
* @param mixed $value the value for the primary key of the next new row inserted. If this is not set,
* the next new row's primary key will have a value 1.
* @return string the SQL statement for resetting sequence
* @throws InvalidCallException if the table does not exist or there is no sequence associated with the table.
* @throws InvalidParamException if the table does not exist or there is no sequence associated with the table.
*/
public function resetSequence($tableName, $value = null)
{
......@@ -70,9 +68,9 @@ class QueryBuilder extends \yii\db\QueryBuilder
} catch (Exception $e) {
}
} elseif ($table === null) {
throw new InvalidCallException("Table not found: $tableName");
throw new InvalidParamException("Table not found: $tableName");
} else {
throw new InvalidCallException("There is not sequence associated with table '$tableName'.'");
throw new InvalidParamException("There is not sequence associated with table '$tableName'.'");
}
}
......
<?php
/**
* Schema class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
<?php
/**
* ArrayHelper class file.
*
* @copyright Copyright (c) 2008 Yii Software LLC
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\util;
namespace yii\helpers;
use yii\base\InvalidCallException;
use Yii;
use yii\base\InvalidParamException;
/**
* ArrayHelper provides additional array functionality you can use in your
......@@ -60,11 +59,11 @@ class ArrayHelper
*
* ~~~
* // working with array
* $username = \yii\util\ArrayHelper::getValue($_POST, 'username');
* $username = \yii\helpers\ArrayHelper::getValue($_POST, 'username');
* // working with object
* $username = \yii\util\ArrayHelper::getValue($user, 'username');
* $username = \yii\helpers\ArrayHelper::getValue($user, 'username');
* // working with anonymous function
* $fullName = \yii\util\ArrayHelper::getValue($user, function($user, $defaultValue) {
* $fullName = \yii\helpers\ArrayHelper::getValue($user, function($user, $defaultValue) {
* return $user->firstName . ' ' . $user->lastName;
* });
* ~~~
......@@ -242,7 +241,7 @@ class ArrayHelper
* value is for sorting strings in case-insensitive manner. Please refer to
* See [PHP manual](http://php.net/manual/en/function.sort.php) for more details.
* When sorting by multiple keys with different sort flags, use an array of sort flags.
* @throws InvalidCallException if the $ascending or $sortFlag parameters do not have
* @throws InvalidParamException if the $ascending or $sortFlag parameters do not have
* correct number of elements as that of $key.
*/
public static function multisort(&$array, $key, $ascending = true, $sortFlag = SORT_REGULAR)
......@@ -255,12 +254,12 @@ class ArrayHelper
if (is_scalar($ascending)) {
$ascending = array_fill(0, $n, $ascending);
} elseif (count($ascending) !== $n) {
throw new InvalidCallException('The length of $ascending parameter must be the same as that of $keys.');
throw new InvalidParamException('The length of $ascending parameter must be the same as that of $keys.');
}
if (is_scalar($sortFlag)) {
$sortFlag = array_fill(0, $n, $sortFlag);
} elseif (count($sortFlag) !== $n) {
throw new InvalidCallException('The length of $ascending parameter must be the same as that of $keys.');
throw new InvalidParamException('The length of $ascending parameter must be the same as that of $keys.');
}
$args = array();
foreach ($keys as $i => $key) {
......@@ -281,4 +280,61 @@ class ArrayHelper
$args[] = &$array;
call_user_func_array('array_multisort', $args);
}
/**
* Encodes special characters in an array of strings into HTML entities.
* Both the array keys and values will be encoded.
* If a value is an array, this method will also encode it recursively.
* @param array $data data to be encoded
* @param boolean $valuesOnly whether to encode array values only. If false,
* both the array keys and array values will be encoded.
* @param string $charset the charset that the data is using. If not set,
* [[\yii\base\Application::charset]] will be used.
* @return array the encoded data
* @see http://www.php.net/manual/en/function.htmlspecialchars.php
*/
public static function htmlEncode($data, $valuesOnly = true, $charset = null)
{
if ($charset === null) {
$charset = Yii::$app->charset;
}
$d = array();
foreach ($data as $key => $value) {
if (!$valuesOnly && is_string($key)) {
$key = htmlspecialchars($key, ENT_QUOTES, $charset);
}
if (is_string($value)) {
$d[$key] = htmlspecialchars($value, ENT_QUOTES, $charset);
} elseif (is_array($value)) {
$d[$key] = static::htmlEncode($value, $charset);
}
}
return $d;
}
/**
* Decodes HTML entities into the corresponding characters in an array of strings.
* Both the array keys and values will be decoded.
* If a value is an array, this method will also decode it recursively.
* @param array $data data to be decoded
* @param boolean $valuesOnly whether to decode array values only. If false,
* both the array keys and array values will be decoded.
* @return array the decoded data
* @see http://www.php.net/manual/en/function.htmlspecialchars-decode.php
*/
public static function htmlDecode($data, $valuesOnly = true)
{
$d = array();
foreach ($data as $key => $value) {
if (!$valuesOnly && is_string($key)) {
$key = htmlspecialchars_decode($key, ENT_QUOTES);
}
if (is_string($value)) {
$d[$key] = htmlspecialchars_decode($value, ENT_QUOTES);
} elseif (is_array($value)) {
$d[$key] = static::htmlDecode($value);
}
}
return $d;
}
}
\ No newline at end of file
<?php
/**
* ConsoleColor class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\console;
namespace yii\helpers;
// todo define how subclassing will work
// todo add a run() or render() method
// todo test this on all kinds of terminals, especially windows (check out lib ncurses)
// todo not sure if all methods should be static
// todo subclass DetailView
// todo subclass GridView
// todo more subclasses
/**
* Console View is the base class for console view components
......@@ -359,7 +349,7 @@ class ConsoleColor
}
$styleString[] = array();
foreach($styleA as $name => $content) {
if ($name = 'text-decoration') {
if ($name === 'text-decoration') {
$content = implode(' ', $content);
}
$styleString[] = $name.':'.$content;
......
......@@ -3,11 +3,11 @@
* Filesystem helper class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\util;
namespace yii\helpers;
use yii\base\Exception;
use yii\base\InvalidConfigException;
......@@ -43,7 +43,7 @@ class FileHelper
public static function ensureDirectory($path)
{
$p = \Yii::getAlias($path);
if ($p !== false && ($p = realpath($p)) !== false && is_dir($p)) {
if (($p = realpath($p)) !== false && is_dir($p)) {
return $p;
} else {
throw new InvalidConfigException('Directory does not exist: ' . $path);
......
<?php
/**
* StringHelper class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\util;
namespace yii\helpers;
/**
* StringHelper
......@@ -19,6 +17,33 @@ namespace yii\util;
class StringHelper
{
/**
* Returns the number of bytes in the given string.
* This method ensures the string is treated as a byte array.
* It will use `mb_strlen()` if it is available.
* @param string $string the string being measured for length
* @return integer the number of bytes in the given string.
*/
public static function strlen($string)
{
return function_exists('mb_strlen') ? mb_strlen($string, '8bit') : strlen($string);
}
/**
* Returns the portion of string specified by the start and length parameters.
* This method ensures the string is treated as a byte array.
* It will use `mb_substr()` if it is available.
* @param string $string the input string. Must be one character or longer.
* @param integer $start the starting position
* @param integer $length the desired portion length
* @return string the extracted part of string, or FALSE on failure or an empty string.
* @see http://www.php.net/manual/en/function.substr.php
*/
public static function substr($string, $start, $length)
{
return function_exists('mb_substr') ? mb_substr($string, $start, $length, '8bit') : substr($string, $start, $length);
}
/**
* Converts a word to its plural form.
* Note that this is for English only!
* For example, 'apple' will become 'apples', and 'child' will become 'children'.
......@@ -27,7 +52,7 @@ class StringHelper
*/
public static function pluralize($name)
{
$rules = array(
static $rules = array(
'/(m)ove$/i' => '\1oves',
'/(f)oot$/i' => '\1eet',
'/(c)hild$/i' => '\1hildren',
......
<?php
/**
* VarDumper class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008-2011 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\util;
namespace yii\helpers;
/**
* VarDumper is intended to replace the buggy PHP function var_dump and print_r.
......@@ -17,14 +15,15 @@ namespace yii\util;
* recursive display of some peculiar variables.
*
* VarDumper can be used as follows,
* <pre>
*
* ~~~
* VarDumper::dump($var);
* </pre>
* ~~~
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class VarDumper
class CVarDumper
{
private static $_objects;
private static $_output;
......@@ -38,9 +37,9 @@ class VarDumper
* @param integer $depth maximum depth that the dumper should go into the variable. Defaults to 10.
* @param boolean $highlight whether the result should be syntax-highlighted
*/
public static function dump($var,$depth=10,$highlight=false)
public static function dump($var, $depth = 10, $highlight = false)
{
echo self::dumpAsString($var,$depth,$highlight);
echo self::dumpAsString($var, $depth, $highlight);
}
/**
......@@ -52,16 +51,15 @@ class VarDumper
* @param boolean $highlight whether the result should be syntax-highlighted
* @return string the string representation of the variable
*/
public static function dumpAsString($var,$depth=10,$highlight=false)
public static function dumpAsString($var, $depth = 10, $highlight = false)
{
self::$_output='';
self::$_objects=array();
self::$_depth=$depth;
self::dumpInternal($var,0);
if($highlight)
{
$result=highlight_string("<?php\n".self::$_output,true);
self::$_output=preg_replace('/&lt;\\?php<br \\/>/','',$result,1);
self::$_output = '';
self::$_objects = array();
self::$_depth = $depth;
self::dumpInternal($var, 0);
if ($highlight) {
$result = highlight_string("<?php\n" . self::$_output, true);
self::$_output = preg_replace('/&lt;\\?php<br \\/>/', '', $result, 1);
}
return self::$_output;
}
......@@ -70,73 +68,65 @@ class VarDumper
* @param mixed $var variable to be dumped
* @param integer $level depth level
*/
private static function dumpInternal($var,$level)
private static function dumpInternal($var, $level)
{
switch(gettype($var))
{
switch (gettype($var)) {
case 'boolean':
self::$_output.=$var?'true':'false';
self::$_output .= $var ? 'true' : 'false';
break;
case 'integer':
self::$_output.="$var";
self::$_output .= "$var";
break;
case 'double':
self::$_output.="$var";
self::$_output .= "$var";
break;
case 'string':
self::$_output.="'".addslashes($var)."'";
self::$_output .= "'" . addslashes($var) . "'";
break;
case 'resource':
self::$_output.='{resource}';
self::$_output .= '{resource}';
break;
case 'NULL':
self::$_output.="null";
self::$_output .= "null";
break;
case 'unknown type':
self::$_output.='{unknown}';
self::$_output .= '{unknown}';
break;
case 'array':
if(self::$_depth<=$level)
self::$_output.='array(...)';
else if(empty($var))
self::$_output.='array()';
else
{
$keys=array_keys($var);
$spaces=str_repeat(' ',$level*4);
self::$_output.="array\n".$spaces.'(';
foreach($keys as $key)
{
if(gettype($key)=='integer')
$key2=$key;
else
$key2="'".str_replace("'","\\'",$key)."'";
self::$_output.="\n".$spaces." $key2 => ";
self::$_output.=self::dumpInternal($var[$key],$level+1);
if (self::$_depth <= $level) {
self::$_output .= 'array(...)';
} elseif (empty($var)) {
self::$_output .= 'array()';
} else {
$keys = array_keys($var);
$spaces = str_repeat(' ', $level * 4);
self::$_output .= "array\n" . $spaces . '(';
foreach ($keys as $key) {
self::$_output .= "\n" . $spaces . ' ';
self::dumpInternal($key, 0);
self::$_output .= ' => ';
self::dumpInternal($var[$key], $level + 1);
}
self::$_output.="\n".$spaces.')';
self::$_output .= "\n" . $spaces . ')';
}
break;
case 'object':
if(($id=array_search($var,self::$_objects,true))!==false)
self::$_output.=get_class($var).'#'.($id+1).'(...)';
else if(self::$_depth<=$level)
self::$_output.=get_class($var).'(...)';
else
{
$id=array_push(self::$_objects,$var);
$className=get_class($var);
$members=(array)$var;
$spaces=str_repeat(' ',$level*4);
self::$_output.="$className#$id\n".$spaces.'(';
foreach($members as $key=>$value)
{
$keyDisplay=strtr(trim($key),array("\0"=>':'));
self::$_output.="\n".$spaces." [$keyDisplay] => ";
self::$_output.=self::dumpInternal($value,$level+1);
if (($id = array_search($var, self::$_objects, true)) !== false) {
self::$_output .= get_class($var) . '#' . ($id + 1) . '(...)';
} elseif (self::$_depth <= $level) {
self::$_output .= get_class($var) . '(...)';
} else {
$id = self::$_objects[] = $var;
$className = get_class($var);
$members = (array)$var;
$spaces = str_repeat(' ', $level * 4);
self::$_output .= "$className#$id\n" . $spaces . '(';
foreach ($members as $key => $value) {
$keyDisplay = strtr(trim($key), array("\0" => ':'));
self::$_output .= "\n" . $spaces . " [$keyDisplay] => ";
self::dumpInternal($value, $level + 1);
}
self::$_output.="\n".$spaces.')';
self::$_output .= "\n" . $spaces . ')';
}
break;
}
......
......@@ -6,7 +6,7 @@
* according to file extension names.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
* @since 2.0
*/
......
......@@ -4,91 +4,93 @@ namespace yii\i18n;
use Yii;
use yii\base\Component;
use yii\base\InvalidConfigException;
class I18N extends Component
{
/**
* @var array list of [[MessageSource]] configurations or objects. The array keys are message
* categories, and the array values are the corresponding [[MessageSource]] objects or the configurations
* for creating the [[MessageSource]] objects. The message categories can contain the wildcard '*' at the end
* to match multiple categories with the same prefix. For example, 'app\*' matches both 'app\cat1' and 'app\cat2'.
*/
public $translations;
public function init()
{
if (!isset($this->translations['yii'])) {
$this->translations['yii'] = array(
'class' => 'yii\i18n\PhpMessageSource',
'sourceLanguage' => 'en_US',
'basePath' => '@yii/messages',
);
}
if (!isset($this->translations['app'])) {
$this->translations['app'] = array(
'class' => 'yii\i18n\PhpMessageSource',
'sourceLanguage' => 'en_US',
'basePath' => '@app/messages',
);
}
}
public function translate($message, $params = array(), $language = null)
{
if ($language === null) {
$language = Yii::$app->language;
}
if (strpos($message, '|') !== false && preg_match('/^([\w\-\.]+)\|(.*)/', $message, $matches)) {
// allow chars for category: word chars, ".", "-", "/","\"
if (strpos($message, '|') !== false && preg_match('/^([\w\-\\/\.\\\\]+)\|(.*)/', $message, $matches)) {
$category = $matches[1];
$message = $matches[2];
} else {
$category = 'app';
}
// $message = $this->getMessageSource($category)->translate($category, $message, $language);
//
// if (!is_array($params)) {
// $params = array($params);
// }
//
// if (isset($params[0])) {
// $message = $this->getPluralFormat($message, $params[0], $language);
// if (!isset($params['{n}'])) {
// $params['{n}'] = $params[0];
// }
// unset($params[0]);
// }
$message = $this->getMessageSource($category)->translate($category, $message, $language);
return $params === array() ? $message : strtr($message, $params);
}
if (!is_array($params)) {
$params = array($params);
}
public function getLocale($language)
{
if (isset($params[0])) {
$message = $this->getPluralForm($message, $params[0], $language);
if (!isset($params['{n}'])) {
$params['{n}'] = $params[0];
}
unset($params[0]);
}
return $params === array() ? $message : strtr($message, $params);
}
public function getMessageSource($category)
{
return $category === 'yii' ? $this->getMessages() : $this->getCoreMessages();
}
private $_coreMessages;
private $_messages;
public function getCoreMessages()
{
if (is_object($this->_coreMessages)) {
return $this->_coreMessages;
} elseif ($this->_coreMessages === null) {
return $this->_coreMessages = new PhpMessageSource(array(
'sourceLanguage' => 'en_US',
'basePath' => '@yii/messages',
));
if (isset($this->translations[$category])) {
$source = $this->translations[$category];
} else {
return $this->_coreMessages = Yii::createObject($this->_coreMessages);
// try wildcard matching
foreach ($this->translations as $pattern => $config) {
if (substr($pattern, -1) === '*' && strpos($category, rtrim($pattern, '*')) === 0) {
$source = $config;
break;
}
}
}
}
public function setCoreMessages($config)
{
$this->_coreMessages = $config;
}
public function getMessages()
{
if (is_object($this->_messages)) {
return $this->_messages;
} elseif ($this->_messages === null) {
return $this->_messages = new PhpMessageSource(array(
'sourceLanguage' => 'en_US',
'basePath' => '@app/messages',
));
if (isset($source)) {
return $source instanceof MessageSource ? $source : Yii::createObject($source);
} else {
return $this->_messages = Yii::createObject($this->_messages);
throw new InvalidConfigException("Unable to locate message source for category '$category'.");
}
}
public function setMessages($config)
public function getLocale($language)
{
$this->_messages = $config;
}
protected function getPluralFormat($message, $number, $language)
protected function getPluralForm($message, $number, $language)
{
if (strpos($message, '|') === false) {
return $message;
......@@ -96,7 +98,7 @@ class I18N extends Component
$chunks = explode('|', $message);
$rules = $this->getLocale($language)->getPluralRules();
foreach ($rules as $i => $rule) {
if (isset($chunks[$i]) && self::evaluate($rule, $number)) {
if (isset($chunks[$i]) && $this->evaluate($rule, $number)) {
return $chunks[$i];
}
}
......@@ -110,7 +112,7 @@ class I18N extends Component
* @param mixed $n the number value
* @return boolean the expression result
*/
protected static function evaluate($expression, $n)
protected function evaluate($expression, $n)
{
return @eval("return $expression;");
}
......
<?php
/**
* MessageSource class file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008 Yii Software LLC
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment