+
renderFile($generator->formView(), array(
'generator' => $generator,
'form' => $form,
)); ?>
field($generator, 'template')->sticky()
- ->label(array('label' => 'Code Template'))
+ ->label('Code Template')
->dropDownList($templates)->hint('
Please select which set of the templates should be used to generated the code.
'); ?>
diff --git a/framework/yii/grid/DataColumn.php b/framework/yii/grid/DataColumn.php
index d31507d..295dece 100644
--- a/framework/yii/grid/DataColumn.php
+++ b/framework/yii/grid/DataColumn.php
@@ -28,6 +28,14 @@ class DataColumn extends Column
*/
public $attribute;
/**
+ * @var string label to be displayed in the [[header|header cell]] and also to be used as the sorting
+ * link label when sorting is enabled for this column.
+ * If it is not set and the models provided by the GridViews data provider are instances
+ * of [[yii\db\ActiveRecord]], the label will be determined using [[yii\db\ActiveRecord::getAttributeLabel()]].
+ * Otherwise [[yii\helpers\Inflector::camel2words()]] will be used to get a label.
+ */
+ public $label;
+ /**
* @var \Closure an anonymous function that returns the value to be displayed for every data model.
* If this is not set, `$model[$attribute]` will be used to obtain the value.
*/
@@ -46,6 +54,11 @@ class DataColumn extends Column
*/
public $enableSorting = true;
/**
+ * @var array the HTML attributes for the link tag in the header cell
+ * generated by [[Sort::link]] when sorting is enabled for this column.
+ */
+ public $sortLinkOptions = array();
+ /**
* @var string|array|boolean the HTML code representing a filter input (e.g. a text field, a dropdown list)
* that is used for this data column. This property is effective only when [[GridView::filterModel]] is set.
*
@@ -59,25 +72,36 @@ class DataColumn extends Column
protected function renderHeaderCellContent()
{
- if ($this->attribute !== null && $this->header === null) {
- $provider = $this->grid->dataProvider;
- if ($this->enableSorting && ($sort = $provider->getSort()) !== false && $sort->hasAttribute($this->attribute)) {
- return $sort->link($this->attribute);
- }
- $models = $provider->getModels();
- if (($model = reset($models)) instanceof Model) {
+ if ($this->header !== null || $this->label === null && $this->attribute === null) {
+ return parent::renderHeaderCellContent();
+ }
+
+ $provider = $this->grid->dataProvider;
+
+ if ($this->label === null) {
+ if ($provider instanceof ActiveDataProvider && $provider->query instanceof ActiveQuery) {
/** @var Model $model */
- return $model->getAttributeLabel($this->attribute);
- } elseif ($provider instanceof ActiveDataProvider) {
- if ($provider->query instanceof ActiveQuery) {
+ $model = new $provider->query->modelClass;
+ $label = $model->getAttributeLabel($this->attribute);
+ } else {
+ $models = $provider->getModels();
+ if (($model = reset($models)) instanceof Model) {
/** @var Model $model */
- $model = new $provider->query->modelClass;
- return $model->getAttributeLabel($this->attribute);
+ $label = $model->getAttributeLabel($this->attribute);
+ } else {
+ $label = Inflector::camel2words($this->attribute);
}
}
- return Inflector::camel2words($this->attribute);
} else {
- return parent::renderHeaderCellContent();
+ $label = $this->label;
+ }
+
+ if ($this->attribute !== null && $this->enableSorting &&
+ ($sort = $provider->getSort()) !== false && $sort->hasAttribute($this->attribute)) {
+
+ return $sort->link($this->attribute, array_merge($this->sortLinkOptions, array('label' => Html::encode($label))));
+ } else {
+ return Html::encode($label);
}
}
diff --git a/framework/yii/grid/GridView.php b/framework/yii/grid/GridView.php
index 9490f27..a783a75 100644
--- a/framework/yii/grid/GridView.php
+++ b/framework/yii/grid/GridView.php
@@ -108,7 +108,7 @@ class GridView extends ListViewBase
* 'class' => DataColumn::className(),
* 'attribute' => 'name',
* 'format' => 'text',
- * 'header' => 'Name',
+ * 'label' => 'Name',
* ),
* array(
* 'class' => CheckboxColumn::className(),
@@ -119,21 +119,11 @@ class GridView extends ListViewBase
* If a column is of class [[DataColumn]], the "class" element can be omitted.
*
* As a shortcut format, a string may be used to specify the configuration of a data column
- * which only contains "attribute", "format", and/or "header" options: `"attribute:format:header"`.
+ * which only contains "attribute", "format", and/or "label" options: `"attribute:format:label"`.
* For example, the above "name" column can also be specified as: `"name:text:Name"`.
- * Both "format" and "header" are optional. They will take default values if absent.
+ * Both "format" and "label" are optional. They will take default values if absent.
*/
public $columns = array();
- /**
- * @var string the layout that determines how different sections of the list view should be organized.
- * The following tokens will be replaced with the corresponding section contents:
- *
- * - `{summary}`: the summary section. See [[renderSummary()]].
- * - `{items}`: the list items. See [[renderItems()]].
- * - `{sorter}`: the sorter. See [[renderSorter()]].
- * - `{pager}`: the pager. See [[renderPager()]].
- */
- public $layout = "{items}\n{summary}\n{pager}";
public $emptyCell = ' ';
/**
* @var \yii\base\Model the model that keeps the user-entered filter data. When this property is set,
@@ -372,7 +362,7 @@ class GridView extends ListViewBase
}
/**
- * Creates a [[DataColumn]] object based on a string in the format of "attribute:format:header".
+ * Creates a [[DataColumn]] object based on a string in the format of "attribute:format:label".
* @param string $text the column specification string
* @return DataColumn the column instance
* @throws InvalidConfigException if the column specification is invalid
@@ -380,14 +370,14 @@ class GridView extends ListViewBase
protected function createDataColumn($text)
{
if (!preg_match('/^([\w\.]+)(:(\w*))?(:(.*))?$/', $text, $matches)) {
- throw new InvalidConfigException('The column must be specified in the format of "attribute", "attribute:format" or "attribute:format:header');
+ throw new InvalidConfigException('The column must be specified in the format of "attribute", "attribute:format" or "attribute:format:label');
}
return Yii::createObject(array(
'class' => $this->dataColumnClass ?: DataColumn::className(),
'grid' => $this,
'attribute' => $matches[1],
'format' => isset($matches[3]) ? $matches[3] : 'text',
- 'header' => isset($matches[5]) ? $matches[5] : null,
+ 'label' => isset($matches[5]) ? $matches[5] : null,
));
}
diff --git a/framework/yii/grid/SerialColumn.php b/framework/yii/grid/SerialColumn.php
index 3a5e21b..2fdb770 100644
--- a/framework/yii/grid/SerialColumn.php
+++ b/framework/yii/grid/SerialColumn.php
@@ -9,7 +9,7 @@ namespace yii\grid;
/**
* SerialColumn displays a column of row numbers (1-based).
- *
+ *
* @author Qiang Xue
* @since 2.0
*/
diff --git a/framework/yii/helpers/ArrayHelperBase.php b/framework/yii/helpers/ArrayHelperBase.php
index 2492246..59129de 100644
--- a/framework/yii/helpers/ArrayHelperBase.php
+++ b/framework/yii/helpers/ArrayHelperBase.php
@@ -143,7 +143,7 @@ class ArrayHelperBase
* or an anonymous function returning the value. The anonymous function signature should be:
* `function($array, $defaultValue)`.
* @param mixed $default the default value to be returned if the specified key does not exist
- * @return mixed the value of the
+ * @return mixed the value of the element if found, default value otherwise
*/
public static function getValue($array, $key, $default = null)
{
diff --git a/framework/yii/helpers/ConsoleBase.php b/framework/yii/helpers/ConsoleBase.php
index 3593e74..a985291 100644
--- a/framework/yii/helpers/ConsoleBase.php
+++ b/framework/yii/helpers/ConsoleBase.php
@@ -665,8 +665,8 @@ class ConsoleBase
/**
* Prints text to STDOUT appended with a carriage return (PHP_EOL).
*
- * @param string $string
- * @return mixed Number of bytes printed or bool false on error
+ * @param string $string the text to print
+ * @return integer|boolean number of bytes printed or false on error.
*/
public static function output($string = null)
{
@@ -676,8 +676,8 @@ class ConsoleBase
/**
* Prints text to STDERR appended with a carriage return (PHP_EOL).
*
- * @param string $string
- * @return mixed Number of bytes printed or false on error
+ * @param string $string the text to print
+ * @return integer|boolean number of bytes printed or false on error.
*/
public static function error($string = null)
{
diff --git a/framework/yii/helpers/FileHelperBase.php b/framework/yii/helpers/FileHelperBase.php
index 6358ea1..0e480da 100644
--- a/framework/yii/helpers/FileHelperBase.php
+++ b/framework/yii/helpers/FileHelperBase.php
@@ -133,7 +133,7 @@ class FileHelperBase
* @param string $dst the destination directory
* @param array $options options for directory copy. Valid options are:
*
- * - dirMode: integer, the permission to be set for newly copied directories. Defaults to 0777.
+ * - dirMode: integer, the permission to be set for newly copied directories. Defaults to 0775.
* - fileMode: integer, the permission to be set for newly copied files. Defaults to the current environment setting.
* - filter: callback, a PHP callback that is called for each directory or file.
* The signature of the callback should be: `function ($path)`, where `$path` refers the full path to be filtered.
@@ -162,7 +162,7 @@ class FileHelperBase
public static function copyDirectory($src, $dst, $options = array())
{
if (!is_dir($dst)) {
- static::mkdir($dst, isset($options['dirMode']) ? $options['dirMode'] : 0777, true);
+ static::createDirectory($dst, isset($options['dirMode']) ? $options['dirMode'] : 0775, true);
}
$handle = opendir($src);
@@ -302,25 +302,25 @@ class FileHelperBase
}
/**
- * Makes directory.
+ * Creates a new directory.
*
* This method is similar to the PHP `mkdir()` function except that
* it uses `chmod()` to set the permission of the created directory
* in order to avoid the impact of the `umask` setting.
*
- * @param string $path path to be created.
- * @param integer $mode the permission to be set for created directory.
+ * @param string $path path of the directory to be created.
+ * @param integer $mode the permission to be set for the created directory.
* @param boolean $recursive whether to create parent directories if they do not exist.
* @return boolean whether the directory is created successfully
*/
- public static function mkdir($path, $mode = 0777, $recursive = true)
+ public static function createDirectory($path, $mode = 0775, $recursive = true)
{
if (is_dir($path)) {
return true;
}
$parentDir = dirname($path);
if ($recursive && !is_dir($parentDir)) {
- static::mkdir($parentDir, $mode, true);
+ static::createDirectory($parentDir, $mode, true);
}
$result = mkdir($path, $mode);
chmod($path, $mode);
diff --git a/framework/yii/helpers/HtmlBase.php b/framework/yii/helpers/HtmlBase.php
index cfff8f5..a5786cb 100644
--- a/framework/yii/helpers/HtmlBase.php
+++ b/framework/yii/helpers/HtmlBase.php
@@ -238,7 +238,7 @@ class HtmlBase
$method = 'post';
}
if ($request->enableCsrfValidation) {
- $hiddenInputs[] = static::hiddenInput($request->csrfTokenName, $request->getCsrfToken());
+ $hiddenInputs[] = static::hiddenInput($request->csrfVar, $request->getCsrfToken());
}
}
@@ -1049,7 +1049,10 @@ class HtmlBase
*/
public static function activeFileInput($model, $attribute, $options = array())
{
- return static::activeInput('file', $model, $attribute, $options);
+ // add a hidden field so that if a model only has a file field, we can
+ // still use isset($_POST[$modelClass]) to detect if the input is submitted
+ return static::activeHiddenInput($model, $attribute, array('id' => null, 'value' => ''))
+ . static::activeInput('file', $model, $attribute, $options);
}
/**
diff --git a/framework/yii/helpers/SecurityBase.php b/framework/yii/helpers/SecurityBase.php
index 05b2682..5b192de 100644
--- a/framework/yii/helpers/SecurityBase.php
+++ b/framework/yii/helpers/SecurityBase.php
@@ -133,19 +133,19 @@ class SecurityBase
}
/**
- * Generates a random key.
+ * Generates a random key. The key may contain uppercase and lowercase latin letters, digits, underscore, dash and dot.
* @param integer $length the length of the key that should be generated
* @return string the generated random key
*/
public static function generateRandomKey($length = 32)
{
if (function_exists('openssl_random_pseudo_bytes')) {
- $key = base64_encode(openssl_random_pseudo_bytes($length, $strong));
+ $key = strtr(base64_encode(openssl_random_pseudo_bytes($length, $strong)), '+/=', '_-.');
if ($strong) {
return substr($key, 0, $length);
}
}
- $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+ $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-.';
return substr(str_shuffle(str_repeat($chars, 5)), 0, $length);
}
@@ -262,7 +262,7 @@ class SecurityBase
protected static function generateSalt($cost = 13)
{
$cost = (int)$cost;
- if ($cost < 4 || $cost > 30) {
+ if ($cost < 4 || $cost > 31) {
throw new InvalidParamException('Cost must be between 4 and 31.');
}
diff --git a/framework/yii/helpers/StringHelperBase.php b/framework/yii/helpers/StringHelperBase.php
index 54dabda..cbb696e 100644
--- a/framework/yii/helpers/StringHelperBase.php
+++ b/framework/yii/helpers/StringHelperBase.php
@@ -47,8 +47,8 @@ class StringHelperBase
/**
* Returns the trailing name component of a path.
- * This method does the same as the php function `basename()` except that it will
- * always use \ and / as directory separators, independent of the operating system.
+ * This method is similar to the php function `basename()` except that it will
+ * treat both \ and / as directory separators, independent of the operating system.
* This method was mainly created to work on php namespaces. When working with real
* file paths, php's `basename()` should work fine for you.
* Note: this method is not aware of the actual filesystem, or path components such as "..".
@@ -70,6 +70,24 @@ class StringHelperBase
}
/**
+ * Returns parent directory's path.
+ * This method is similar to `dirname()` except that it will treat
+ * both \ and / as directory separators, independent of the operating system.
+ * @param string $path A path string.
+ * @return string the parent directory's path.
+ * @see http://www.php.net/manual/en/function.basename.php
+ */
+ public static function dirname($path)
+ {
+ $pos = mb_strrpos(str_replace('\\', '/', $path), '/');
+ if ($pos !== false) {
+ return mb_substr($path, 0, $pos);
+ } else {
+ return $path;
+ }
+ }
+
+ /**
* Compares two strings or string arrays, and return their differences.
* This is a wrapper of the [phpspec/php-diff](https://packagist.org/packages/phpspec/php-diff) package.
* @param string|array $lines1 the first string or string array to be compared. If it is a string,
diff --git a/framework/yii/log/FileTarget.php b/framework/yii/log/FileTarget.php
index 74a33be..970c71b 100644
--- a/framework/yii/log/FileTarget.php
+++ b/framework/yii/log/FileTarget.php
@@ -9,6 +9,7 @@ namespace yii\log;
use Yii;
use yii\base\InvalidConfigException;
+use yii\helpers\FileHelper;
/**
* FileTarget records log messages in a file.
@@ -37,6 +38,19 @@ class FileTarget extends Target
* @var integer number of log files used for rotation. Defaults to 5.
*/
public $maxLogFiles = 5;
+ /**
+ * @var integer the permission to be set for newly created log files.
+ * This value will be used by PHP chmod() function. No umask will be applied.
+ * If not set, the permission will be determined by the current environment.
+ */
+ public $fileMode;
+ /**
+ * @var integer the permission to be set for newly created directories.
+ * This value will be used by PHP chmod() function. No umask will be applied.
+ * Defaults to 0775, meaning the directory is read-writable by owner and group,
+ * but read-only for other users.
+ */
+ public $dirMode = 0775;
/**
@@ -53,7 +67,7 @@ class FileTarget extends Target
}
$logPath = dirname($this->logFile);
if (!is_dir($logPath)) {
- @mkdir($logPath, 0777, true);
+ FileHelper::createDirectory($logPath, $this->dirMode, true);
}
if ($this->maxLogFiles < 1) {
$this->maxLogFiles = 1;
@@ -87,6 +101,9 @@ class FileTarget extends Target
@flock($fp, LOCK_UN);
@fclose($fp);
}
+ if ($this->fileMode !== null) {
+ @chmod($this->logFile, $this->fileMode);
+ }
}
/**
diff --git a/framework/yii/log/Logger.php b/framework/yii/log/Logger.php
index bb7cea5..54f3a49 100644
--- a/framework/yii/log/Logger.php
+++ b/framework/yii/log/Logger.php
@@ -61,6 +61,13 @@ use yii\base\InvalidConfigException;
* When the application ends or [[flushInterval]] is reached, Logger will call [[flush()]]
* to send logged messages to different log targets, such as file, email, Web.
*
+ * @property array $dbProfiling The first element indicates the number of SQL statements executed, and the
+ * second element the total time spent in SQL execution. This property is read-only.
+ * @property float $elapsedTime The total elapsed time in seconds for current request. This property is
+ * read-only.
+ * @property array $profiling The profiling results. Each array element has the following structure:
+ * `array($token, $category, $time)`. This property is read-only.
+ *
* @author Qiang Xue
* @since 2.0
*/
diff --git a/framework/yii/log/Target.php b/framework/yii/log/Target.php
index 48c340f..0cb72ef 100644
--- a/framework/yii/log/Target.php
+++ b/framework/yii/log/Target.php
@@ -22,7 +22,9 @@ use yii\base\InvalidConfigException;
* satisfying both filter conditions will be handled. Additionally, you
* may specify [[except]] to exclude messages of certain categories.
*
- * @property integer $levels the message levels that this target is interested in.
+ * @property integer $levels The message levels that this target is interested in. This is a bitmap of level
+ * values. Defaults to 0, meaning all available levels. Note that the type of this property differs in getter
+ * and setter. See [[getLevels()]] and [[setLevels()]] for details.
*
* @author Qiang Xue
* @since 2.0
diff --git a/framework/yii/rbac/DbManager.php b/framework/yii/rbac/DbManager.php
index 90d301e..46c375f 100644
--- a/framework/yii/rbac/DbManager.php
+++ b/framework/yii/rbac/DbManager.php
@@ -24,6 +24,8 @@ use yii\base\InvalidParamException;
* the three tables used to store the authorization data by setting [[itemTable]],
* [[itemChildTable]] and [[assignmentTable]].
*
+ * @property Item[] $items The authorization items of the specific type. This property is read-only.
+ *
* @author Qiang Xue
* @author Alexander Kochetov
* @since 2.0
diff --git a/framework/yii/rbac/Item.php b/framework/yii/rbac/Item.php
index 2504ad5..f7930c1 100644
--- a/framework/yii/rbac/Item.php
+++ b/framework/yii/rbac/Item.php
@@ -18,6 +18,9 @@ use yii\base\Object;
* A user may be assigned one or several authorization items (called [[Assignment]] assignments).
* He can perform an operation only when it is among his assigned items.
*
+ * @property Item[] $children All child items of this item. This property is read-only.
+ * @property string $name The item name.
+ *
* @author Qiang Xue
* @author Alexander Kochetov
* @since 2.0
diff --git a/framework/yii/rbac/Manager.php b/framework/yii/rbac/Manager.php
index 23ac1a8..3d3aafc 100644
--- a/framework/yii/rbac/Manager.php
+++ b/framework/yii/rbac/Manager.php
@@ -33,9 +33,9 @@ use yii\base\InvalidParamException;
* at appropriate places in the application code to check if the current user
* has the needed permission for an operation.
*
- * @property array $roles Roles (name => Item).
- * @property array $tasks Tasks (name => Item).
- * @property array $operations Operations (name => Item).
+ * @property Item[] $operations Operations (name => AuthItem). This property is read-only.
+ * @property Item[] $roles Roles (name => AuthItem). This property is read-only.
+ * @property Item[] $tasks Tasks (name => AuthItem). This property is read-only.
*
* @author Qiang Xue
* @author Alexander Kochetov
diff --git a/framework/yii/rbac/PhpManager.php b/framework/yii/rbac/PhpManager.php
index 3808541..203b17e 100644
--- a/framework/yii/rbac/PhpManager.php
+++ b/framework/yii/rbac/PhpManager.php
@@ -23,7 +23,7 @@ use yii\base\InvalidParamException;
* (for example, the authorization data for a personal blog system).
* Use [[DbManager]] for more complex authorization data.
*
- * @property array $authItems The authorization items of the specific type.
+ * @property Item[] $items The authorization items of the specific type. This property is read-only.
*
* @author Qiang Xue
* @author Alexander Kochetov
diff --git a/framework/yii/redis/Connection.php b/framework/yii/redis/Connection.php
new file mode 100644
index 0000000..848b408
--- /dev/null
+++ b/framework/yii/redis/Connection.php
@@ -0,0 +1,428 @@
+
+ * @since 2.0
+ */
+class Connection extends Component
+{
+ /**
+ * @event Event an event that is triggered after a DB connection is established
+ */
+ const EVENT_AFTER_OPEN = 'afterOpen';
+
+ /**
+ * @var string the Data Source Name, or DSN, contains the information required to connect to the database.
+ * DSN format: redis://server:port[/db]
+ * Where db is a zero based integer which refers to the DB to use.
+ * If no DB is given, ID 0 is used.
+ *
+ * Example: redis://localhost:6379/2
+ */
+ public $dsn;
+ /**
+ * @var string the password for establishing DB connection. Defaults to null meaning no AUTH command is send.
+ * See http://redis.io/commands/auth
+ */
+ public $password;
+ /**
+ * @var float timeout to use for connection to redis. If not set the timeout set in php.ini will be used: ini_get("default_socket_timeout")
+ */
+ public $connectionTimeout = null;
+ /**
+ * @var float timeout to use for redis socket when reading and writing data. If not set the php default value will be used.
+ */
+ public $dataTimeout = null;
+
+ /**
+ * @var array List of available redis commands http://redis.io/commands
+ */
+ public $redisCommands = array(
+ 'BRPOP', // key [key ...] timeout Remove and get the last element in a list, or block until one is available
+ 'BRPOPLPUSH', // source destination timeout Pop a value from a list, push it to another list and return it; or block until one is available
+ 'CLIENT KILL', // ip:port Kill the connection of a client
+ 'CLIENT LIST', // Get the list of client connections
+ 'CLIENT GETNAME', // Get the current connection name
+ 'CLIENT SETNAME', // connection-name Set the current connection name
+ 'CONFIG GET', // parameter Get the value of a configuration parameter
+ 'CONFIG SET', // parameter value Set a configuration parameter to the given value
+ 'CONFIG RESETSTAT', // Reset the stats returned by INFO
+ 'DBSIZE', // Return the number of keys in the selected database
+ 'DEBUG OBJECT', // key Get debugging information about a key
+ 'DEBUG SEGFAULT', // Make the server crash
+ 'DECR', // key Decrement the integer value of a key by one
+ 'DECRBY', // key decrement Decrement the integer value of a key by the given number
+ 'DEL', // key [key ...] Delete a key
+ 'DISCARD', // Discard all commands issued after MULTI
+ 'DUMP', // key Return a serialized version of the value stored at the specified key.
+ 'ECHO', // message Echo the given string
+ 'EVAL', // script numkeys key [key ...] arg [arg ...] Execute a Lua script server side
+ 'EVALSHA', // sha1 numkeys key [key ...] arg [arg ...] Execute a Lua script server side
+ 'EXEC', // Execute all commands issued after MULTI
+ 'EXISTS', // key Determine if a key exists
+ 'EXPIRE', // key seconds Set a key's time to live in seconds
+ 'EXPIREAT', // key timestamp Set the expiration for a key as a UNIX timestamp
+ 'FLUSHALL', // Remove all keys from all databases
+ 'FLUSHDB', // Remove all keys from the current database
+ 'GET', // key Get the value of a key
+ 'GETBIT', // key offset Returns the bit value at offset in the string value stored at key
+ 'GETRANGE', // key start end Get a substring of the string stored at a key
+ 'GETSET', // key value Set the string value of a key and return its old value
+ 'HDEL', // key field [field ...] Delete one or more hash fields
+ 'HEXISTS', // key field Determine if a hash field exists
+ 'HGET', // key field Get the value of a hash field
+ 'HGETALL', // key Get all the fields and values in a hash
+ 'HINCRBY', // key field increment Increment the integer value of a hash field by the given number
+ 'HINCRBYFLOAT', // key field increment Increment the float value of a hash field by the given amount
+ 'HKEYS', // key Get all the fields in a hash
+ 'HLEN', // key Get the number of fields in a hash
+ 'HMGET', // key field [field ...] Get the values of all the given hash fields
+ 'HMSET', // key field value [field value ...] Set multiple hash fields to multiple values
+ 'HSET', // key field value Set the string value of a hash field
+ 'HSETNX', // key field value Set the value of a hash field, only if the field does not exist
+ 'HVALS', // key Get all the values in a hash
+ 'INCR', // key Increment the integer value of a key by one
+ 'INCRBY', // key increment Increment the integer value of a key by the given amount
+ 'INCRBYFLOAT', // key increment Increment the float value of a key by the given amount
+ 'INFO', // [section] Get information and statistics about the server
+ 'KEYS', // pattern Find all keys matching the given pattern
+ 'LASTSAVE', // Get the UNIX time stamp of the last successful save to disk
+ 'LINDEX', // key index Get an element from a list by its index
+ 'LINSERT', // key BEFORE|AFTER pivot value Insert an element before or after another element in a list
+ 'LLEN', // key Get the length of a list
+ 'LPOP', // key Remove and get the first element in a list
+ 'LPUSH', // key value [value ...] Prepend one or multiple values to a list
+ 'LPUSHX', // key value Prepend a value to a list, only if the list exists
+ 'LRANGE', // key start stop Get a range of elements from a list
+ 'LREM', // key count value Remove elements from a list
+ 'LSET', // key index value Set the value of an element in a list by its index
+ 'LTRIM', // key start stop Trim a list to the specified range
+ 'MGET', // key [key ...] Get the values of all the given keys
+ 'MIGRATE', // host port key destination-db timeout Atomically transfer a key from a Redis instance to another one.
+ 'MONITOR', // Listen for all requests received by the server in real time
+ 'MOVE', // key db Move a key to another database
+ 'MSET', // key value [key value ...] Set multiple keys to multiple values
+ 'MSETNX', // key value [key value ...] Set multiple keys to multiple values, only if none of the keys exist
+ 'MULTI', // Mark the start of a transaction block
+ 'OBJECT', // subcommand [arguments [arguments ...]] Inspect the internals of Redis objects
+ 'PERSIST', // key Remove the expiration from a key
+ 'PEXPIRE', // key milliseconds Set a key's time to live in milliseconds
+ 'PEXPIREAT', // key milliseconds-timestamp Set the expiration for a key as a UNIX timestamp specified in milliseconds
+ 'PING', // Ping the server
+ 'PSETEX', // key milliseconds value Set the value and expiration in milliseconds of a key
+ 'PSUBSCRIBE', // pattern [pattern ...] Listen for messages published to channels matching the given patterns
+ 'PTTL', // key Get the time to live for a key in milliseconds
+ 'PUBLISH', // channel message Post a message to a channel
+ 'PUNSUBSCRIBE', // [pattern [pattern ...]] Stop listening for messages posted to channels matching the given patterns
+ 'QUIT', // Close the connection
+ 'RANDOMKEY', // Return a random key from the keyspace
+ 'RENAME', // key newkey Rename a key
+ 'RENAMENX', // key newkey Rename a key, only if the new key does not exist
+ 'RESTORE', // key ttl serialized-value Create a key using the provided serialized value, previously obtained using DUMP.
+ 'RPOP', // key Remove and get the last element in a list
+ 'RPOPLPUSH', // source destination Remove the last element in a list, append it to another list and return it
+ 'RPUSH', // key value [value ...] Append one or multiple values to a list
+ 'RPUSHX', // key value Append a value to a list, only if the list exists
+ 'SADD', // key member [member ...] Add one or more members to a set
+ 'SAVE', // Synchronously save the dataset to disk
+ 'SCARD', // key Get the number of members in a set
+ 'SCRIPT EXISTS', // script [script ...] Check existence of scripts in the script cache.
+ 'SCRIPT FLUSH', // Remove all the scripts from the script cache.
+ 'SCRIPT KILL', // Kill the script currently in execution.
+ 'SCRIPT LOAD', // script Load the specified Lua script into the script cache.
+ 'SDIFF', // key [key ...] Subtract multiple sets
+ 'SDIFFSTORE', // destination key [key ...] Subtract multiple sets and store the resulting set in a key
+ 'SELECT', // index Change the selected database for the current connection
+ 'SET', // key value Set the string value of a key
+ 'SETBIT', // key offset value Sets or clears the bit at offset in the string value stored at key
+ 'SETEX', // key seconds value Set the value and expiration of a key
+ 'SETNX', // key value Set the value of a key, only if the key does not exist
+ 'SETRANGE', // key offset value Overwrite part of a string at key starting at the specified offset
+ 'SHUTDOWN', // [NOSAVE] [SAVE] Synchronously save the dataset to disk and then shut down the server
+ 'SINTER', // key [key ...] Intersect multiple sets
+ 'SINTERSTORE', // destination key [key ...] Intersect multiple sets and store the resulting set in a key
+ 'SISMEMBER', // key member Determine if a given value is a member of a set
+ 'SLAVEOF', // host port Make the server a slave of another instance, or promote it as master
+ 'SLOWLOG', // subcommand [argument] Manages the Redis slow queries log
+ 'SMEMBERS', // key Get all the members in a set
+ 'SMOVE', // source destination member Move a member from one set to another
+ 'SORT', // key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination] Sort the elements in a list, set or sorted set
+ 'SPOP', // key Remove and return a random member from a set
+ 'SRANDMEMBER', // key [count] Get one or multiple random members from a set
+ 'SREM', // key member [member ...] Remove one or more members from a set
+ 'STRLEN', // key Get the length of the value stored in a key
+ 'SUBSCRIBE', // channel [channel ...] Listen for messages published to the given channels
+ 'SUNION', // key [key ...] Add multiple sets
+ 'SUNIONSTORE', // destination key [key ...] Add multiple sets and store the resulting set in a key
+ 'SYNC', // Internal command used for replication
+ 'TIME', // Return the current server time
+ 'TTL', // key Get the time to live for a key
+ 'TYPE', // key Determine the type stored at key
+ 'UNSUBSCRIBE', // [channel [channel ...]] Stop listening for messages posted to the given channels
+ 'UNWATCH', // Forget about all watched keys
+ 'WATCH', // key [key ...] Watch the given keys to determine execution of the MULTI/EXEC block
+ 'ZADD', // key score member [score member ...] Add one or more members to a sorted set, or update its score if it already exists
+ 'ZCARD', // key Get the number of members in a sorted set
+ 'ZCOUNT', // key min max Count the members in a sorted set with scores within the given values
+ 'ZINCRBY', // key increment member Increment the score of a member in a sorted set
+ 'ZINTERSTORE', // destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX] Intersect multiple sorted sets and store the resulting sorted set in a new key
+ 'ZRANGE', // key start stop [WITHSCORES] Return a range of members in a sorted set, by index
+ 'ZRANGEBYSCORE', // key min max [WITHSCORES] [LIMIT offset count] Return a range of members in a sorted set, by score
+ 'ZRANK', // key member Determine the index of a member in a sorted set
+ 'ZREM', // key member [member ...] Remove one or more members from a sorted set
+ 'ZREMRANGEBYRANK', // key start stop Remove all members in a sorted set within the given indexes
+ 'ZREMRANGEBYSCORE', // key min max Remove all members in a sorted set within the given scores
+ 'ZREVRANGE', // key start stop [WITHSCORES] Return a range of members in a sorted set, by index, with scores ordered from high to low
+ 'ZREVRANGEBYSCORE', // key max min [WITHSCORES] [LIMIT offset count] Return a range of members in a sorted set, by score, with scores ordered from high to low
+ 'ZREVRANK', // key member Determine the index of a member in a sorted set, with scores ordered from high to low
+ 'ZSCORE', // key member Get the score associated with the given member in a sorted set
+ 'ZUNIONSTORE', // destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX] Add multiple sorted sets and store the resulting sorted set in a new key
+ );
+ /**
+ * @var Transaction the currently active transaction
+ */
+ private $_transaction;
+ /**
+ * @var resource redis socket connection
+ */
+ private $_socket;
+
+ /**
+ * Closes the connection when this component is being serialized.
+ * @return array
+ */
+ public function __sleep()
+ {
+ $this->close();
+ return array_keys(get_object_vars($this));
+ }
+
+ /**
+ * Returns a value indicating whether the DB connection is established.
+ * @return boolean whether the DB connection is established
+ */
+ public function getIsActive()
+ {
+ return $this->_socket !== null;
+ }
+
+ /**
+ * Establishes a DB connection.
+ * It does nothing if a DB connection has already been established.
+ * @throws Exception if connection fails
+ */
+ public function open()
+ {
+ if ($this->_socket === null) {
+ if (empty($this->dsn)) {
+ throw new InvalidConfigException('Connection.dsn cannot be empty.');
+ }
+ $dsn = explode('/', $this->dsn);
+ $host = $dsn[2];
+ if (strpos($host, ':')===false) {
+ $host .= ':6379';
+ }
+ $db = isset($dsn[3]) ? $dsn[3] : 0;
+
+ \Yii::trace('Opening DB connection: ' . $this->dsn, __CLASS__);
+ $this->_socket = @stream_socket_client(
+ $host,
+ $errorNumber,
+ $errorDescription,
+ $this->connectionTimeout ? $this->connectionTimeout : ini_get("default_socket_timeout")
+ );
+ if ($this->_socket) {
+ if ($this->dataTimeout !== null) {
+ stream_set_timeout($this->_socket, $timeout=(int)$this->dataTimeout, (int) (($this->dataTimeout - $timeout) * 1000000));
+ }
+ if ($this->password !== null) {
+ $this->executeCommand('AUTH', array($this->password));
+ }
+ $this->executeCommand('SELECT', array($db));
+ $this->initConnection();
+ } else {
+ \Yii::error("Failed to open DB connection ({$this->dsn}): " . $errorNumber . ' - ' . $errorDescription, __CLASS__);
+ $message = YII_DEBUG ? 'Failed to open DB connection: ' . $errorNumber . ' - ' . $errorDescription : 'Failed to open DB connection.';
+ throw new Exception($message, $errorDescription, (int)$errorNumber);
+ }
+ }
+ }
+
+ /**
+ * Closes the currently active DB connection.
+ * It does nothing if the connection is already closed.
+ */
+ public function close()
+ {
+ if ($this->_socket !== null) {
+ \Yii::trace('Closing DB connection: ' . $this->dsn, __CLASS__);
+ $this->executeCommand('QUIT');
+ stream_socket_shutdown($this->_socket, STREAM_SHUT_RDWR);
+ $this->_socket = null;
+ $this->_transaction = null;
+ }
+ }
+
+ /**
+ * Initializes the DB connection.
+ * This method is invoked right after the DB connection is established.
+ * The default implementation triggers an [[EVENT_AFTER_OPEN]] event.
+ */
+ protected function initConnection()
+ {
+ $this->trigger(self::EVENT_AFTER_OPEN);
+ }
+
+ /**
+ * Returns the currently active transaction.
+ * @return Transaction the currently active transaction. Null if no active transaction.
+ */
+ public function getTransaction()
+ {
+ return $this->_transaction && $this->_transaction->isActive ? $this->_transaction : null;
+ }
+
+ /**
+ * Starts a transaction.
+ * @return Transaction the transaction initiated
+ */
+ public function beginTransaction()
+ {
+ $this->open();
+ $this->_transaction = new Transaction(array(
+ 'db' => $this,
+ ));
+ $this->_transaction->begin();
+ return $this->_transaction;
+ }
+
+ /**
+ * Returns the name of the DB driver for the current [[dsn]].
+ * @return string name of the DB driver
+ */
+ public function getDriverName()
+ {
+ if (($pos = strpos($this->dsn, ':')) !== false) {
+ return strtolower(substr($this->dsn, 0, $pos));
+ } else {
+ return 'redis';
+ }
+ }
+
+ /**
+ *
+ * @param string $name
+ * @param array $params
+ * @return mixed
+ */
+ public function __call($name, $params)
+ {
+ $redisCommand = strtoupper(Inflector::camel2words($name, false));
+ if (in_array($redisCommand, $this->redisCommands)) {
+ return $this->executeCommand($name, $params);
+ } else {
+ return parent::__call($name, $params);
+ }
+ }
+
+ /**
+ * Executes a redis command.
+ * For a list of available commands and their parameters see http://redis.io/commands.
+ *
+ * @param string $name the name of the command
+ * @param array $params list of parameters for the command
+ * @return array|bool|null|string Dependend on the executed command this method
+ * will return different data types:
+ *
+ * - `true` for commands that return "status reply".
+ * - `string` for commands that return "integer reply"
+ * as the value is in the range of a signed 64 bit integer.
+ * - `string` or `null` for commands that return "bulk reply".
+ * - `array` for commands that return "Multi-bulk replies".
+ *
+ * See [redis protocol description](http://redis.io/topics/protocol)
+ * for details on the mentioned reply types.
+ * @trows Exception for commands that return [error reply](http://redis.io/topics/protocol#error-reply).
+ */
+ public function executeCommand($name, $params=array())
+ {
+ $this->open();
+
+ array_unshift($params, $name);
+ $command = '*' . count($params) . "\r\n";
+ foreach($params as $arg) {
+ $command .= '$' . mb_strlen($arg, '8bit') . "\r\n" . $arg . "\r\n";
+ }
+
+ \Yii::trace("Executing Redis Command: {$name}", __CLASS__);
+ fwrite($this->_socket, $command);
+
+ return $this->parseResponse(implode(' ', $params));
+ }
+
+ private function parseResponse($command)
+ {
+ if(($line = fgets($this->_socket)) === false) {
+ throw new Exception("Failed to read from socket.\nRedis command was: " . $command);
+ }
+ $type = $line[0];
+ $line = mb_substr($line, 1, -2, '8bit');
+ switch($type)
+ {
+ case '+': // Status reply
+ return true;
+ case '-': // Error reply
+ throw new Exception("Redis error: " . $line . "\nRedis command was: " . $command);
+ case ':': // Integer reply
+ // no cast to int as it is in the range of a signed 64 bit integer
+ return $line;
+ case '$': // Bulk replies
+ if ($line == '-1') {
+ return null;
+ }
+ $length = $line + 2;
+ $data = '';
+ while ($length > 0) {
+ if(($block = fread($this->_socket, $line + 2)) === false) {
+ throw new Exception("Failed to read from socket.\nRedis command was: " . $command);
+ }
+ $data .= $block;
+ $length -= mb_strlen($block, '8bit');
+ }
+ return mb_substr($data, 0, -2, '8bit');
+ case '*': // Multi-bulk replies
+ $count = (int) $line;
+ $data = array();
+ for($i = 0; $i < $count; $i++) {
+ $data[] = $this->parseResponse($command);
+ }
+ return $data;
+ default:
+ throw new Exception('Received illegal data from redis: ' . $line . "\nRedis command was: " . $command);
+ }
+ }
+}
diff --git a/framework/yii/redis/Transaction.php b/framework/yii/redis/Transaction.php
new file mode 100644
index 0000000..94cff7a
--- /dev/null
+++ b/framework/yii/redis/Transaction.php
@@ -0,0 +1,93 @@
+
+ * @since 2.0
+ */
+class Transaction extends \yii\base\Object
+{
+ /**
+ * @var Connection the database connection that this transaction is associated with.
+ */
+ public $db;
+ /**
+ * @var boolean whether this transaction is active. Only an active transaction
+ * can [[commit()]] or [[rollBack()]]. This property is set true when the transaction is started.
+ */
+ private $_active = false;
+
+ /**
+ * Returns a value indicating whether this transaction is active.
+ * @return boolean whether this transaction is active. Only an active transaction
+ * can [[commit()]] or [[rollBack()]].
+ */
+ public function getIsActive()
+ {
+ return $this->_active;
+ }
+
+ /**
+ * Begins a transaction.
+ * @throws InvalidConfigException if [[connection]] is null
+ */
+ public function begin()
+ {
+ if (!$this->_active) {
+ if ($this->db === null) {
+ throw new InvalidConfigException('Transaction::db must be set.');
+ }
+ \Yii::trace('Starting transaction', __CLASS__);
+ $this->db->open();
+ $this->db->createCommand('MULTI')->execute();
+ $this->_active = true;
+ }
+ }
+
+ /**
+ * Commits a transaction.
+ * @throws Exception if the transaction or the DB connection is not active.
+ */
+ public function commit()
+ {
+ if ($this->_active && $this->db && $this->db->isActive) {
+ \Yii::trace('Committing transaction', __CLASS__);
+ $this->db->createCommand('EXEC')->execute();
+ // TODO handle result of EXEC
+ $this->_active = false;
+ } else {
+ throw new Exception('Failed to commit transaction: transaction was inactive.');
+ }
+ }
+
+ /**
+ * Rolls back a transaction.
+ * @throws Exception if the transaction or the DB connection is not active.
+ */
+ public function rollback()
+ {
+ if ($this->_active && $this->db && $this->db->isActive) {
+ \Yii::trace('Rolling back transaction', __CLASS__);
+ $this->db->pdo->commit();
+ $this->_active = false;
+ } else {
+ throw new Exception('Failed to roll back transaction: transaction was inactive.');
+ }
+ }
+}
diff --git a/framework/yii/validators/ExistValidator.php b/framework/yii/validators/ExistValidator.php
index 9c74890..8cbce5f 100644
--- a/framework/yii/validators/ExistValidator.php
+++ b/framework/yii/validators/ExistValidator.php
@@ -66,7 +66,7 @@ class ExistValidator extends Validator
}
/** @var $className \yii\db\ActiveRecord */
- $className = $this->className === null ? get_class($object) : Yii::import($this->className);
+ $className = $this->className === null ? get_class($object) : $this->className;
$attributeName = $this->attributeName === null ? $attribute : $this->attributeName;
$query = $className::find();
$query->where(array($attributeName => $value));
diff --git a/framework/yii/validators/FileValidator.php b/framework/yii/validators/FileValidator.php
index 8a3ab9e..e2880af 100644
--- a/framework/yii/validators/FileValidator.php
+++ b/framework/yii/validators/FileValidator.php
@@ -13,13 +13,15 @@ use yii\web\UploadedFile;
/**
* FileValidator verifies if an attribute is receiving a valid uploaded file.
*
+ * @property integer $sizeLimit The size limit for uploaded files. This property is read-only.
+ *
* @author Qiang Xue
* @since 2.0
*/
class FileValidator extends Validator
{
/**
- * @var mixed a list of file name extensions that are allowed to be uploaded.
+ * @var array|string a list of file name extensions that are allowed to be uploaded.
* This can be either an array or a string consisting of file extension names
* separated by space or comma (e.g. "gif, jpg").
* Extension names are case-insensitive. Defaults to null, meaning all file name
@@ -133,7 +135,7 @@ class FileValidator extends Validator
return;
}
foreach ($files as $i => $file) {
- if (!$file instanceof UploadedFile || $file->getError() == UPLOAD_ERR_NO_FILE) {
+ if (!$file instanceof UploadedFile || $file->error == UPLOAD_ERR_NO_FILE) {
unset($files[$i]);
}
}
@@ -150,7 +152,7 @@ class FileValidator extends Validator
}
} else {
$file = $object->$attribute;
- if ($file instanceof UploadedFile && $file->getError() != UPLOAD_ERR_NO_FILE) {
+ if ($file instanceof UploadedFile && $file->error != UPLOAD_ERR_NO_FILE) {
$this->validateFile($object, $attribute, $file);
} else {
$this->addError($object, $attribute, $this->uploadRequired);
@@ -166,37 +168,37 @@ class FileValidator extends Validator
*/
protected function validateFile($object, $attribute, $file)
{
- switch ($file->getError()) {
+ switch ($file->error) {
case UPLOAD_ERR_OK:
- if ($this->maxSize !== null && $file->getSize() > $this->maxSize) {
- $this->addError($object, $attribute, $this->tooBig, array('{file}' => $file->getName(), '{limit}' => $this->getSizeLimit()));
+ if ($this->maxSize !== null && $file->size > $this->maxSize) {
+ $this->addError($object, $attribute, $this->tooBig, array('{file}' => $file->name, '{limit}' => $this->getSizeLimit()));
}
- if ($this->minSize !== null && $file->getSize() < $this->minSize) {
- $this->addError($object, $attribute, $this->tooSmall, array('{file}' => $file->getName(), '{limit}' => $this->minSize));
+ if ($this->minSize !== null && $file->size < $this->minSize) {
+ $this->addError($object, $attribute, $this->tooSmall, array('{file}' => $file->name, '{limit}' => $this->minSize));
}
- if (!empty($this->types) && !in_array(strtolower(pathinfo($file->getName(), PATHINFO_EXTENSION)), $this->types, true)) {
- $this->addError($object, $attribute, $this->wrongType, array('{file}' => $file->getName(), '{extensions}' => implode(', ', $this->types)));
+ if (!empty($this->types) && !in_array(strtolower(pathinfo($file->name, PATHINFO_EXTENSION)), $this->types, true)) {
+ $this->addError($object, $attribute, $this->wrongType, array('{file}' => $file->name, '{extensions}' => implode(', ', $this->types)));
}
break;
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
- $this->addError($object, $attribute, $this->tooBig, array('{file}' => $file->getName(), '{limit}' => $this->getSizeLimit()));
+ $this->addError($object, $attribute, $this->tooBig, array('{file}' => $file->name, '{limit}' => $this->getSizeLimit()));
break;
case UPLOAD_ERR_PARTIAL:
$this->addError($object, $attribute, $this->message);
- Yii::warning('File was only partially uploaded: ' . $file->getName(), __METHOD__);
+ Yii::warning('File was only partially uploaded: ' . $file->name, __METHOD__);
break;
case UPLOAD_ERR_NO_TMP_DIR:
$this->addError($object, $attribute, $this->message);
- Yii::warning('Missing the temporary folder to store the uploaded file: ' . $file->getName(), __METHOD__);
+ Yii::warning('Missing the temporary folder to store the uploaded file: ' . $file->name, __METHOD__);
break;
case UPLOAD_ERR_CANT_WRITE:
$this->addError($object, $attribute, $this->message);
- Yii::warning('Failed to write the uploaded file to disk: ' . $file->getName(), __METHOD__);
+ Yii::warning('Failed to write the uploaded file to disk: ' . $file->name, __METHOD__);
break;
case UPLOAD_ERR_EXTENSION:
$this->addError($object, $attribute, $this->message);
- Yii::warning('File upload was stopped by some PHP extension: ' . $file->getName(), __METHOD__);
+ Yii::warning('File upload was stopped by some PHP extension: ' . $file->name, __METHOD__);
break;
default:
break;
diff --git a/framework/yii/validators/RegularExpressionValidator.php b/framework/yii/validators/RegularExpressionValidator.php
index 4ae2099..df57e7d 100644
--- a/framework/yii/validators/RegularExpressionValidator.php
+++ b/framework/yii/validators/RegularExpressionValidator.php
@@ -30,7 +30,6 @@ class RegularExpressionValidator extends Validator
/**
* @var boolean whether to invert the validation logic. Defaults to false. If set to true,
* the regular expression defined via [[pattern]] should NOT match the attribute value.
- * @throws InvalidConfigException if the "pattern" is not a valid regular expression
**/
public $not = false;
@@ -82,7 +81,6 @@ class RegularExpressionValidator extends Validator
* @param \yii\base\View $view the view object that is going to be used to render views or view files
* containing a model form with this validator applied.
* @return string the client-side validation script.
- * @throws InvalidConfigException if the "pattern" is not a valid regular expression
*/
public function clientValidateAttribute($object, $attribute, $view)
{
diff --git a/framework/yii/validators/StringValidator.php b/framework/yii/validators/StringValidator.php
index 2cbab6c..946ca6e 100644
--- a/framework/yii/validators/StringValidator.php
+++ b/framework/yii/validators/StringValidator.php
@@ -52,7 +52,7 @@ class StringValidator extends Validator
*/
public $tooLong;
/**
- * @var string user-defined error message used when the length of the value is not equal to [[is]].
+ * @var string user-defined error message used when the length of the value is not equal to [[length]].
*/
public $notEqual;
/**
diff --git a/framework/yii/validators/UniqueValidator.php b/framework/yii/validators/UniqueValidator.php
index b650693..c3876e8 100644
--- a/framework/yii/validators/UniqueValidator.php
+++ b/framework/yii/validators/UniqueValidator.php
@@ -61,7 +61,7 @@ class UniqueValidator extends Validator
}
/** @var $className \yii\db\ActiveRecord */
- $className = $this->className === null ? get_class($object) : Yii::import($this->className);
+ $className = $this->className === null ? get_class($object) : $this->className;
$attributeName = $this->attributeName === null ? $attribute : $this->attributeName;
$table = $className::getTableSchema();
diff --git a/framework/yii/web/AccessControl.php b/framework/yii/web/AccessControl.php
index 35d6cae..7f791b8 100644
--- a/framework/yii/web/AccessControl.php
+++ b/framework/yii/web/AccessControl.php
@@ -31,15 +31,17 @@ use yii\base\ActionFilter;
* 'class' => \yii\web\AccessControl::className(),
* 'only' => array('create', 'update'),
* 'rules' => array(
+ * // deny all POST requests
+ * array(
+ * 'allow' => false,
+ * 'verbs' => array('POST')
+ * ),
* // allow authenticated users
* array(
* 'allow' => true,
* 'roles' => array('@'),
* ),
- * // deny all
- * array(
- * 'allow' => false,
- * ),
+ * // everything else is denied
* ),
* ),
* );
diff --git a/framework/yii/web/AccessRule.php b/framework/yii/web/AccessRule.php
index 0de791c..7aeaac1 100644
--- a/framework/yii/web/AccessRule.php
+++ b/framework/yii/web/AccessRule.php
@@ -11,6 +11,7 @@ use yii\base\Component;
use yii\base\Action;
/**
+ * This class represents an access rule defined by the [[AccessControl]] action filter
*
* @author Qiang Xue
* @since 2.0
diff --git a/framework/yii/web/Application.php b/framework/yii/web/Application.php
index 249b0b4..5fd2310 100644
--- a/framework/yii/web/Application.php
+++ b/framework/yii/web/Application.php
@@ -11,7 +11,14 @@ use Yii;
use yii\base\InvalidRouteException;
/**
- * Application is the base class for all application classes.
+ * Application is the base class for all web application classes.
+ *
+ * @property AssetManager $assetManager The asset manager component. This property is read-only.
+ * @property string $homeUrl The homepage URL.
+ * @property Request $request The request component. This property is read-only.
+ * @property Response $response The response component. This property is read-only.
+ * @property Session $session The session component. This property is read-only.
+ * @property User $user The user component. This property is read-only.
*
* @author Qiang Xue
* @since 2.0
diff --git a/framework/yii/web/AssetManager.php b/framework/yii/web/AssetManager.php
index 702fd30..c6f7fea 100644
--- a/framework/yii/web/AssetManager.php
+++ b/framework/yii/web/AssetManager.php
@@ -16,6 +16,9 @@ use yii\helpers\FileHelper;
/**
* AssetManager manages asset bundles and asset publishing.
*
+ * @property IAssetConverter $converter The asset converter. Note that the type of this property differs in
+ * getter and setter. See [[getConverter()]] and [[setConverter()]] for details.
+ *
* @author Qiang Xue
* @since 2.0
*/
@@ -55,16 +58,17 @@ class AssetManager extends Component
public $linkAssets = false;
/**
* @var integer the permission to be set for newly published asset files.
- * This value will be used by PHP chmod() function.
+ * This value will be used by PHP chmod() function. No umask will be applied.
* If not set, the permission will be determined by the current environment.
*/
public $fileMode;
/**
* @var integer the permission to be set for newly generated asset directories.
- * This value will be used by PHP chmod() function.
- * Defaults to 0777, meaning the directory can be read, written and executed by all users.
+ * This value will be used by PHP chmod() function. No umask will be applied.
+ * Defaults to 0775, meaning the directory is read-writable by owner and group,
+ * but read-only for other users.
*/
- public $dirMode = 0777;
+ public $dirMode = 0775;
/**
* Initializes the component.
@@ -202,7 +206,7 @@ class AssetManager extends Component
$dstFile = $dstDir . DIRECTORY_SEPARATOR . $fileName;
if (!is_dir($dstDir)) {
- mkdir($dstDir, $this->dirMode, true);
+ FileHelper::createDirectory($dstDir, $this->dirMode, true);
}
if ($this->linkAssets) {
diff --git a/framework/yii/web/CacheSession.php b/framework/yii/web/CacheSession.php
index 79acd74..bb387e1 100644
--- a/framework/yii/web/CacheSession.php
+++ b/framework/yii/web/CacheSession.php
@@ -21,6 +21,8 @@ use yii\base\InvalidConfigException;
* may be swapped out and get lost. Therefore, you must make sure the cache used by this component
* is NOT volatile. If you want to use database as storage medium, use [[DbSession]] is a better choice.
*
+ * @property boolean $useCustomStorage Whether to use custom storage. This property is read-only.
+ *
* @author Qiang Xue
* @since 2.0
*/
diff --git a/framework/yii/web/Controller.php b/framework/yii/web/Controller.php
index b094981..adb1b4d 100644
--- a/framework/yii/web/Controller.php
+++ b/framework/yii/web/Controller.php
@@ -12,8 +12,7 @@ use yii\base\InlineAction;
use yii\helpers\Html;
/**
- * Controller is the base class of Web controllers.
- *
+ * Controller is the base class of web controllers.
*
* @author Qiang Xue
* @since 2.0
diff --git a/framework/yii/web/CookieCollection.php b/framework/yii/web/CookieCollection.php
index 3e22092..6940493 100644
--- a/framework/yii/web/CookieCollection.php
+++ b/framework/yii/web/CookieCollection.php
@@ -15,7 +15,9 @@ use yii\base\Object;
/**
* CookieCollection maintains the cookies available in the current request.
*
- * @property integer $count the number of cookies in the collection
+ * @property integer $count The number of cookies in the collection. This property is read-only.
+ * @property ArrayIterator $iterator An iterator for traversing the cookies in the collection. This property
+ * is read-only.
*
* @author Qiang Xue
* @since 2.0
diff --git a/framework/yii/web/DbSession.php b/framework/yii/web/DbSession.php
index 30f5ed0..c508bb8 100644
--- a/framework/yii/web/DbSession.php
+++ b/framework/yii/web/DbSession.php
@@ -17,9 +17,9 @@ use yii\base\InvalidConfigException;
*
* By default, DbSession stores session data in a DB table named 'tbl_session'. This table
* must be pre-created. The table name can be changed by setting [[sessionTable]].
- *
+ *
* The following example shows how you can configure the application to use DbSession:
- *
+ *
* ~~~
* 'session' => array(
* 'class' => 'yii\web\DbSession',
@@ -28,6 +28,8 @@ use yii\base\InvalidConfigException;
* )
* ~~~
*
+ * @property boolean $useCustomStorage Whether to use custom storage. This property is read-only.
+ *
* @author Qiang Xue
* @since 2.0
*/
diff --git a/framework/yii/web/HeaderCollection.php b/framework/yii/web/HeaderCollection.php
index 872a997..609058b 100644
--- a/framework/yii/web/HeaderCollection.php
+++ b/framework/yii/web/HeaderCollection.php
@@ -14,6 +14,10 @@ use ArrayIterator;
/**
* HeaderCollection is used by [[Response]] to maintain the currently registered HTTP headers.
*
+ * @property integer $count The number of headers in the collection. This property is read-only.
+ * @property ArrayIterator $iterator An iterator for traversing the headers in the collection. This property
+ * is read-only.
+ *
* @author Qiang Xue
* @since 2.0
*/
diff --git a/framework/yii/web/HttpCache.php b/framework/yii/web/HttpCache.php
index cc9e6ed..d2f3923 100644
--- a/framework/yii/web/HttpCache.php
+++ b/framework/yii/web/HttpCache.php
@@ -12,6 +12,8 @@ use yii\base\ActionFilter;
use yii\base\Action;
/**
+ * The HttpCache provides functionality for caching via HTTP Last-Modified and Etag headers
+ *
* @author Da:Sourcerer
* @author Qiang Xue
* @since 2.0
diff --git a/framework/yii/web/JqueryAsset.php b/framework/yii/web/JqueryAsset.php
index 4585acd..9991eb4 100644
--- a/framework/yii/web/JqueryAsset.php
+++ b/framework/yii/web/JqueryAsset.php
@@ -8,6 +8,8 @@
namespace yii\web;
/**
+ * This asset bundle provides the [jquery javascript library](http://jquery.com/)
+ *
* @author Qiang Xue
* @since 2.0
*/
diff --git a/framework/yii/web/JsExpression.php b/framework/yii/web/JsExpression.php
index 027c065..7daac08 100644
--- a/framework/yii/web/JsExpression.php
+++ b/framework/yii/web/JsExpression.php
@@ -11,8 +11,10 @@ use yii\base\Object;
/**
* JsExpression marks a string as a JavaScript expression.
- * When using [[Json::encode()]] to encode a value, JsonExpression objects
+ *
+ * When using [[yii\helpers\Json::encode()]] to encode a value, JsonExpression objects
* will be specially handled and encoded as a JavaScript expression instead of a string.
+ *
* @author Qiang Xue
* @since 2.0
*/
diff --git a/framework/yii/web/PageCache.php b/framework/yii/web/PageCache.php
index d28203e..9bc8981 100644
--- a/framework/yii/web/PageCache.php
+++ b/framework/yii/web/PageCache.php
@@ -14,6 +14,8 @@ use yii\base\View;
use yii\caching\Dependency;
/**
+ * The PageCache provides functionality for whole page caching
+ *
* @author Qiang Xue
* @since 2.0
*/
diff --git a/framework/yii/web/Request.php b/framework/yii/web/Request.php
index c2f5c4b..9e625f7 100644
--- a/framework/yii/web/Request.php
+++ b/framework/yii/web/Request.php
@@ -12,27 +12,89 @@ use yii\base\InvalidConfigException;
use yii\helpers\Security;
/**
+ * The web Request class represents an HTTP request
+ *
+ * It encapsulates the $_SERVER variable and resolves its inconsistency among different Web servers.
+ * Also it provides an interface to retrieve request parameters from $_POST, $_GET, $_COOKIES and REST
+ * parameters sent via other HTTP methods like PUT or DELETE.
+ *
+ * @property string $absoluteUrl The currently requested absolute URL. This property is read-only.
+ * @property string $acceptTypes User browser accept types, null if not present. This property is read-only.
+ * @property array $acceptedContentTypes The content types ordered by the preference level. The first element
+ * represents the most preferred content type.
+ * @property array $acceptedLanguages The languages ordered by the preference level. The first element
+ * represents the most preferred language.
+ * @property string $baseUrl The relative URL for the application.
+ * @property string $cookieValidationKey The secret key used for cookie validation. If it was not set
+ * previously, a random key will be generated and used.
+ * @property CookieCollection $cookies The cookie collection. This property is read-only.
+ * @property string $csrfToken The random token for CSRF validation. This property is read-only.
+ * @property string $hostInfo Schema and hostname part (with port number if needed) of the request URL (e.g.
+ * `http://www.yiiframework.com`).
+ * @property boolean $isAjax Whether this is an AJAX (XMLHttpRequest) request. This property is read-only.
+ * @property boolean $isDelete Whether this is a DELETE request. This property is read-only.
+ * @property boolean $isFlash Whether this is an Adobe Flash or Adobe Flex request. This property is
+ * read-only.
+ * @property boolean $isGet Whether this is a GET request. This property is read-only.
+ * @property boolean $isHead Whether this is a HEAD request. This property is read-only.
+ * @property boolean $isOptions Whether this is a OPTIONS request. This property is read-only.
+ * @property boolean $isPatch Whether this is a PATCH request. This property is read-only.
+ * @property boolean $isPost Whether this is a POST request. This property is read-only.
+ * @property boolean $isPut Whether this is a PUT request. This property is read-only.
+ * @property boolean $isSecureConnection If the request is sent via secure channel (https). This property is
+ * read-only.
+ * @property string $method Request method, such as GET, POST, HEAD, PUT, PATCH, DELETE. The value returned is
+ * turned into upper case. This property is read-only.
+ * @property string $pathInfo Part of the request URL that is after the entry script and before the question
+ * mark. Note, the returned path info is already URL-decoded.
+ * @property integer $port Port number for insecure requests.
+ * @property string $preferredLanguage The language that the application should use. Null is returned if both
+ * [[getAcceptedLanguages()]] and `$languages` are empty. This property is read-only.
+ * @property string $queryString Part of the request URL that is after the question mark. This property is
+ * read-only.
+ * @property string $rawBody The request body. This property is read-only.
+ * @property string $referrer URL referrer, null if not present. This property is read-only.
+ * @property array $restParams The RESTful request parameters.
+ * @property string $scriptFile The entry script file path.
+ * @property string $scriptUrl The relative URL of the entry script.
+ * @property integer $securePort Port number for secure requests.
+ * @property string $serverName Server name. This property is read-only.
+ * @property integer $serverPort Server port number. This property is read-only.
+ * @property string $url The currently requested relative URL. Note that the URI returned is URL-encoded.
+ * @property string $userAgent User agent, null if not present. This property is read-only.
+ * @property string $userHost User host name, null if cannot be determined. This property is read-only.
+ * @property string $userIP User IP address. This property is read-only.
+ *
* @author Qiang Xue
* @since 2.0
*/
class Request extends \yii\base\Request
{
/**
+ * The name of the HTTP header for sending CSRF token.
+ */
+ const CSRF_HEADER = 'X-CSRF-TOKEN';
+
+ /**
* @var boolean whether to enable CSRF (Cross-Site Request Forgery) validation. Defaults to false.
- * By setting this property to true, forms submitted to an Yii Web application must be originated
+ * When CSRF validation is enabled, forms submitted to an Yii Web application must be originated
* from the same application. If not, a 400 HTTP exception will be raised.
*
* Note, this feature requires that the user client accepts cookie. Also, to use this feature,
- * forms submitted via POST method must contain a hidden input whose name is specified by [[csrfTokenName]].
+ * forms submitted via POST method must contain a hidden input whose name is specified by [[csrfVar]].
* You may use [[\yii\web\Html::beginForm()]] to generate his hidden input.
+ *
+ * In JavaScript, you may get the values of [[csrfVar]] and [[csrfToken]] via `yii.getCsrfVar()` and
+ * `yii.getCsrfToken()`, respectively. The [[\yii\web\YiiAsset]] asset must be registered.
+ *
* @see http://en.wikipedia.org/wiki/Cross-site_request_forgery
*/
public $enableCsrfValidation = false;
/**
- * @var string the name of the token used to prevent CSRF. Defaults to 'YII_CSRF_TOKEN'.
- * This property is effectively only when {@link enableCsrfValidation} is true.
+ * @var string the name of the token used to prevent CSRF. Defaults to '_csrf'.
+ * This property is used only when [[enableCsrfValidation]] is true.
*/
- public $csrfTokenName = '_csrf';
+ public $csrfVar = '_csrf';
/**
* @var array the configuration of the CSRF cookie. This property is used only when [[enableCsrfValidation]] is true.
* @see Cookie
@@ -87,6 +149,33 @@ class Request extends \yii\base\Request
}
/**
+ * Returns whether this is a GET request.
+ * @return boolean whether this is a GET request.
+ */
+ public function getIsGet()
+ {
+ return $this->getMethod() === 'GET';
+ }
+
+ /**
+ * Returns whether this is an OPTIONS request.
+ * @return boolean whether this is a OPTIONS request.
+ */
+ public function getIsOptions()
+ {
+ return $this->getMethod() === 'OPTIONS';
+ }
+
+ /**
+ * Returns whether this is a HEAD request.
+ * @return boolean whether this is a HEAD request.
+ */
+ public function getIsHead()
+ {
+ return $this->getMethod() === 'HEAD';
+ }
+
+ /**
* Returns whether this is a POST request.
* @return boolean whether this is a POST request.
*/
@@ -898,7 +987,7 @@ class Request extends \yii\base\Request
public function getCsrfToken()
{
if ($this->_csrfCookie === null) {
- $this->_csrfCookie = $this->getCookies()->get($this->csrfTokenName);
+ $this->_csrfCookie = $this->getCookies()->get($this->csrfVar);
if ($this->_csrfCookie === null) {
$this->_csrfCookie = $this->createCsrfCookie();
Yii::$app->getResponse()->getCookies()->add($this->_csrfCookie);
@@ -909,6 +998,14 @@ class Request extends \yii\base\Request
}
/**
+ * @return string the CSRF token sent via [[CSRF_HEADER]] by browser. Null is returned if no such header is sent.
+ */
+ public function getCsrfTokenFromHeader()
+ {
+ return isset($_SERVER[self::CSRF_HEADER]) ? $_SERVER[self::CSRF_HEADER] : null;
+ }
+
+ /**
* Creates a cookie with a randomly generated CSRF token.
* Initial values specified in [[csrfCookie]] will be applied to the generated cookie.
* @return Cookie the generated cookie
@@ -917,7 +1014,7 @@ class Request extends \yii\base\Request
protected function createCsrfCookie()
{
$options = $this->csrfCookie;
- $options['name'] = $this->csrfTokenName;
+ $options['name'] = $this->csrfVar;
$options['value'] = sha1(uniqid(mt_rand(), true));
return new Cookie($options);
}
@@ -935,22 +1032,23 @@ class Request extends \yii\base\Request
}
$method = $this->getMethod();
if ($method === 'POST' || $method === 'PUT' || $method === 'PATCH' || $method === 'DELETE') {
- $cookies = $this->getCookies();
+ $trueToken = $this->getCookies()->getValue($this->csrfVar);
switch ($method) {
case 'POST':
- $token = $this->getPost($this->csrfTokenName);
+ $token = $this->getPost($this->csrfVar);
break;
case 'PUT':
- $token = $this->getPut($this->csrfTokenName);
+ $token = $this->getPut($this->csrfVar);
break;
case 'PATCH':
- $token = $this->getPatch($this->csrfTokenName);
+ $token = $this->getPatch($this->csrfVar);
break;
case 'DELETE':
- $token = $this->getDelete($this->csrfTokenName);
+ $token = $this->getDelete($this->csrfVar);
}
- if (empty($token) || $cookies->getValue($this->csrfTokenName) !== $token) {
+ $valid = !empty($token) && $token === $trueToken || $this->getCsrfTokenFromHeader() === $trueToken;
+ if (!$valid) {
throw new HttpException(400, Yii::t('yii', 'Unable to verify your data submission.'));
}
}
diff --git a/framework/yii/web/Response.php b/framework/yii/web/Response.php
index 19a9ea2..cfbc537 100644
--- a/framework/yii/web/Response.php
+++ b/framework/yii/web/Response.php
@@ -17,6 +17,29 @@ use yii\helpers\Security;
use yii\helpers\StringHelper;
/**
+ * The web Response class represents an HTTP response
+ *
+ * It holds the [[headers]], [[cookies]] and [[content]] that is to be sent to the client.
+ * It also controls the HTTP [[statusCode|status code]].
+ *
+ * @property CookieCollection $cookies The cookie collection. This property is read-only.
+ * @property HeaderCollection $headers The header collection. This property is read-only.
+ * @property boolean $isClientError Whether this response indicates a client error. This property is
+ * read-only.
+ * @property boolean $isEmpty Whether this response is empty. This property is read-only.
+ * @property boolean $isForbidden Whether this response indicates the current request is forbidden. This
+ * property is read-only.
+ * @property boolean $isInformational Whether this response is informational. This property is read-only.
+ * @property boolean $isInvalid Whether this response has a valid [[statusCode]]. This property is read-only.
+ * @property boolean $isNotFound Whether this response indicates the currently requested resource is not
+ * found. This property is read-only.
+ * @property boolean $isOk Whether this response is OK. This property is read-only.
+ * @property boolean $isRedirection Whether this response is a redirection. This property is read-only.
+ * @property boolean $isServerError Whether this response indicates a server error. This property is
+ * read-only.
+ * @property boolean $isSuccessful Whether this response is successful. This property is read-only.
+ * @property integer $statusCode The HTTP status code to send with the response.
+ *
* @author Qiang Xue
* @author Carsten Brandt
* @since 2.0
diff --git a/framework/yii/web/Session.php b/framework/yii/web/Session.php
index cbed8fc..fc9fe16 100644
--- a/framework/yii/web/Session.php
+++ b/framework/yii/web/Session.php
@@ -45,18 +45,27 @@ use yii\base\InvalidParamException;
* useful for displaying confirmation messages. To use flash messages, simply
* call methods such as [[setFlash()]], [[getFlash()]].
*
+ * @property array $allFlashes Flash messages (key => message). This property is read-only.
+ * @property array $cookieParams The session cookie parameters.
+ * @property integer $count The number of session variables. This property is read-only.
+ * @property string $flash The key identifying the flash message. Note that flash messages and normal session
+ * variables share the same name space. If you have a normal session variable using the same name, its value will
+ * be overwritten by this method. This property is write-only.
+ * @property float $gCProbability The probability (percentage) that the GC (garbage collection) process is
+ * started on every session initialization, defaults to 1 meaning 1% chance.
* @property string $id The current session ID.
+ * @property boolean $isActive Whether the session has started. This property is read-only.
+ * @property SessionIterator $iterator An iterator for traversing the session variables. This property is
+ * read-only.
* @property string $name The current session name.
- * @property boolean $isActive Whether the session has started
- * @property string $savePath The current session save path, defaults to {@link http://php.net/manual/en/session.configuration.php#ini.session.save-path}.
- * @property array $cookieParams The session cookie parameters.
- * @property boolean $useCookies Whether cookies should be used to store session IDs.
- * @property float $gCProbability The probability (percentage) that the gc (garbage collection) process is started on every session initialization, defaults to 1 meaning 1% chance.
- * @property boolean $useTransparentSessionID Whether transparent sid support is enabled or not, defaults to false.
- * @property integer $timeout The number of seconds after which data will be seen as 'garbage' and cleaned up, defaults to 1440 seconds.
- * @property SessionIterator $iterator An iterator for traversing the session variables.
- * @property integer $count The number of session variables.
- * @property array $allFlashes The list of all flash messages.
+ * @property string $savePath The current session save path, defaults to '/tmp'.
+ * @property integer $timeout The number of seconds after which data will be seen as 'garbage' and cleaned up.
+ * The default value is 1440 seconds (or the value of "session.gc_maxlifetime" set in php.ini).
+ * @property boolean|null $useCookies The value indicating whether cookies should be used to store session
+ * IDs.
+ * @property boolean $useCustomStorage Whether to use custom storage. This property is read-only.
+ * @property boolean $useTransparentSessionID Whether transparent sid support is enabled or not, defaults to
+ * false.
*
* @author Qiang Xue
* @since 2.0
diff --git a/framework/yii/web/UploadedFile.php b/framework/yii/web/UploadedFile.php
index ee3b1f0..c4e2f0f 100644
--- a/framework/yii/web/UploadedFile.php
+++ b/framework/yii/web/UploadedFile.php
@@ -7,41 +7,53 @@
namespace yii\web;
+use yii\base\Object;
use yii\helpers\Html;
/**
+ * UploadedFile represents the information for an uploaded file.
+ *
+ * You can call [[getInstance()]] to retrieve the instance of an uploaded file,
+ * and then use [[saveAs()]] to save it on the server.
+ * You may also query other information about the file, including [[name]],
+ * [[tempName]], [[type]], [[size]] and [[error]].
+ *
+ * @property boolean $hasError Whether there is an error with the uploaded file. Check [[error]] for detailed
+ * error code information. This property is read-only.
+ *
* @author Qiang Xue
* @since 2.0
*/
-class UploadedFile extends \yii\base\Object
+class UploadedFile extends Object
{
private static $_files;
- private $_name;
- private $_tempName;
- private $_type;
- private $_size;
- private $_error;
-
/**
- * Constructor.
- * Instead of using the constructor to create a new instance,
- * you should normally call [[getInstance()]] or [[getInstances()]]
- * to obtain new instances.
- * @param string $name the original name of the file being uploaded
- * @param string $tempName the path of the uploaded file on the server.
- * @param string $type the MIME-type of the uploaded file (such as "image/gif").
- * @param integer $size the actual size of the uploaded file in bytes
- * @param integer $error the error code
+ * @var string the original name of the file being uploaded
*/
- public function __construct($name, $tempName, $type, $size, $error)
- {
- $this->_name = $name;
- $this->_tempName = $tempName;
- $this->_type = $type;
- $this->_size = $size;
- $this->_error = $error;
- }
+ public $name;
+ /**
+ * @var string the path of the uploaded file on the server.
+ * Note, this is a temporary file which will be automatically deleted by PHP
+ * after the current request is processed.
+ */
+ public $tempName;
+ /**
+ * @var string the MIME-type of the uploaded file (such as "image/gif").
+ * Since this MIME type is not checked on the server side, do not take this value for granted.
+ * Instead, use [[FileHelper::getMimeType()]] to determine the exact MIME type.
+ */
+ public $type;
+ /**
+ * @var integer the actual size of the uploaded file in bytes
+ */
+ public $size;
+ /**
+ * @var integer an error code describing the status of this file uploading.
+ * @see http://www.php.net/manual/en/features.file-upload.errors.php
+ */
+ public $error;
+
/**
* String output.
@@ -51,7 +63,7 @@ class UploadedFile extends \yii\base\Object
*/
public function __toString()
{
- return $this->_name;
+ return $this->name;
}
/**
@@ -142,69 +154,23 @@ class UploadedFile extends \yii\base\Object
*/
public function saveAs($file, $deleteTempFile = true)
{
- if ($this->_error == UPLOAD_ERR_OK) {
+ if ($this->error == UPLOAD_ERR_OK) {
if ($deleteTempFile) {
- return move_uploaded_file($this->_tempName, $file);
- } elseif (is_uploaded_file($this->_tempName)) {
- return copy($this->_tempName, $file);
+ return move_uploaded_file($this->tempName, $file);
+ } elseif (is_uploaded_file($this->tempName)) {
+ return copy($this->tempName, $file);
}
}
return false;
}
/**
- * @return string the original name of the file being uploaded
- */
- public function getName()
- {
- return $this->_name;
- }
-
- /**
- * @return string the path of the uploaded file on the server.
- * Note, this is a temporary file which will be automatically deleted by PHP
- * after the current request is processed.
- */
- public function getTempName()
- {
- return $this->_tempName;
- }
-
- /**
- * @return string the MIME-type of the uploaded file (such as "image/gif").
- * Since this MIME type is not checked on the server side, do not take this value for granted.
- * Instead, use [[FileHelper::getMimeType()]] to determine the exact MIME type.
- */
- public function getType()
- {
- return $this->_type;
- }
-
- /**
- * @return integer the actual size of the uploaded file in bytes
- */
- public function getSize()
- {
- return $this->_size;
- }
-
- /**
- * Returns an error code describing the status of this file uploading.
- * @return integer the error code
- * @see http://www.php.net/manual/en/features.file-upload.errors.php
- */
- public function getError()
- {
- return $this->_error;
- }
-
- /**
* @return boolean whether there is an error with the uploaded file.
* Check [[error]] for detailed error code information.
*/
public function getHasError()
{
- return $this->_error != UPLOAD_ERR_OK;
+ return $this->error != UPLOAD_ERR_OK;
}
/**
@@ -240,7 +206,13 @@ class UploadedFile extends \yii\base\Object
self::loadFilesRecursive($key . '[' . $i . ']', $name, $tempNames[$i], $types[$i], $sizes[$i], $errors[$i]);
}
} else {
- self::$_files[$key] = new static($names, $tempNames, $types, $sizes, $errors);
+ self::$_files[$key] = new static(array(
+ 'name' => $names,
+ 'tempName' => $tempNames,
+ 'type' => $types,
+ 'size' => $sizes,
+ 'error' => $errors,
+ ));
}
}
}
diff --git a/framework/yii/web/UrlManager.php b/framework/yii/web/UrlManager.php
index 6617947..0d9547f 100644
--- a/framework/yii/web/UrlManager.php
+++ b/framework/yii/web/UrlManager.php
@@ -14,6 +14,10 @@ use yii\caching\Cache;
/**
* UrlManager handles HTTP request parsing and creation of URLs based on a set of rules.
*
+ * @property string $baseUrl The base URL that is used by [[createUrl()]] to prepend URLs it creates.
+ * @property string $hostInfo The host info (e.g. "http://www.example.com") that is used by
+ * [[createAbsoluteUrl()]] to prepend URLs it creates.
+ *
* @author Qiang Xue
* @since 2.0
*/
diff --git a/framework/yii/web/User.php b/framework/yii/web/User.php
index 0ad8f68..22b85e5 100644
--- a/framework/yii/web/User.php
+++ b/framework/yii/web/User.php
@@ -10,6 +10,7 @@ namespace yii\web;
use Yii;
use yii\base\Component;
use yii\base\InvalidConfigException;
+use yii\base\InvalidParamException;
/**
* User is the class for the "user" application component that manages the user authentication status.
@@ -20,6 +21,14 @@ use yii\base\InvalidConfigException;
* User works with a class implementing the [[Identity]] interface. This class implements
* the actual user authentication logic and is often backed by a user database table.
*
+ * @property string|integer $id The unique identifier for the user. If null, it means the user is a guest.
+ * This property is read-only.
+ * @property Identity $identity The identity object associated with the currently logged user. Null is
+ * returned if the user is not logged in (not authenticated).
+ * @property boolean $isGuest Whether the current user is a guest. This property is read-only.
+ * @property string $returnUrl The URL that the user should be redirected to after login. Note that the type
+ * of this property differs in getter and setter. See [[getReturnUrl()]] and [[setReturnUrl()]] for details.
+ *
* @author Qiang Xue
* @since 2.0
*/
@@ -132,7 +141,7 @@ class User extends Component
$this->_identity = null;
} else {
/** @var $class Identity */
- $class = Yii::import($this->identityClass);
+ $class = $this->identityClass;
$this->_identity = $class::findIdentity($id);
}
}
@@ -247,20 +256,34 @@ class User extends Component
* This property is usually used by the login action. If the login is successful,
* the action should read this property and use it to redirect the user browser.
* @param string|array $defaultUrl the default return URL in case it was not set previously.
- * If this is null, it means [[Application::homeUrl]] will be redirected to.
- * Please refer to [[\yii\helpers\Html::url()]] on acceptable URL formats.
+ * If this is null and the return URL was not set previously, [[Application::homeUrl]] will be redirected to.
+ * Please refer to [[setReturnUrl()]] on accepted format of the URL.
* @return string the URL that the user should be redirected to after login.
* @see loginRequired
*/
public function getReturnUrl($defaultUrl = null)
{
$url = Yii::$app->getSession()->get($this->returnUrlVar, $defaultUrl);
+ if (is_array($url)) {
+ if (isset($url[0])) {
+ $route = array_shift($url);
+ return Yii::$app->getUrlManager()->createUrl($route, $url);
+ } else {
+ $url = null;
+ }
+ }
return $url === null ? Yii::$app->getHomeUrl() : $url;
}
/**
* @param string|array $url the URL that the user should be redirected to after login.
- * Please refer to [[\yii\helpers\Html::url()]] on acceptable URL formats.
+ * If an array is given, [[UrlManager::createUrl()]] will be called to create the corresponding URL.
+ * The first element of the array should be the route, and the rest of
+ * the name-value pairs are GET parameters used to construct the URL. For example,
+ *
+ * ~~~
+ * array('admin/index', 'ref' => 1)
+ * ~~~
*/
public function setReturnUrl($url)
{
diff --git a/framework/yii/web/UserEvent.php b/framework/yii/web/UserEvent.php
index 4e39380..3e403da 100644
--- a/framework/yii/web/UserEvent.php
+++ b/framework/yii/web/UserEvent.php
@@ -10,6 +10,7 @@ namespace yii\web;
use yii\base\Event;
/**
+ * This event class is used for Events triggered by the [[User]] class.
*
* @author Qiang Xue
* @since 2.0
diff --git a/framework/yii/web/YiiAsset.php b/framework/yii/web/YiiAsset.php
index 8a4d77a..2ad5384 100644
--- a/framework/yii/web/YiiAsset.php
+++ b/framework/yii/web/YiiAsset.php
@@ -7,6 +7,9 @@
namespace yii\web;
+use Yii;
+use yii\base\View;
+
/**
* @author Qiang Xue
* @since 2.0
diff --git a/framework/yii/widgets/ActiveField.php b/framework/yii/widgets/ActiveField.php
index bba1ead..ea8aa1b 100644
--- a/framework/yii/widgets/ActiveField.php
+++ b/framework/yii/widgets/ActiveField.php
@@ -216,22 +216,19 @@ class ActiveField extends Component
/**
* Generates a label tag for [[attribute]].
- * The label text is the label associated with the attribute, obtained via [[Model::getAttributeLabel()]].
+ * @param string $label the label to use. If null, it will be generated via [[Model::getAttributeLabel()]].
+ * Note that this will NOT be [[Html::encode()|encoded]].
* @param array $options the tag options in terms of name-value pairs. It will be merged with [[labelOptions]].
* The options will be rendered as the attributes of the resulting tag. The values will be HTML-encoded
* using [[Html::encode()]]. If a value is null, the corresponding attribute will not be rendered.
- *
- * The following options are specially handled:
- *
- * - label: this specifies the label to be displayed. Note that this will NOT be [[encoded()]].
- * If this is not set, [[Model::getAttributeLabel()]] will be called to get the label for display
- * (after encoding).
- *
* @return ActiveField the field object itself
*/
- public function label($options = array())
+ public function label($label = null, $options = array())
{
$options = array_merge($this->labelOptions, $options);
+ if ($label !== null) {
+ $options['label'] = $label;
+ }
$this->parts['{label}'] = Html::activeLabel($this->model, $this->attribute, $options);
return $this;
}
@@ -374,7 +371,6 @@ class ActiveField extends Component
*/
public function radio($options = array(), $enclosedByLabel = true)
{
- $options = array_merge($this->inputOptions, $options);
if ($enclosedByLabel) {
if (!isset($options['label'])) {
$options['label'] = Html::encode($this->model->getAttributeLabel($this->attribute));
diff --git a/framework/yii/widgets/FragmentCache.php b/framework/yii/widgets/FragmentCache.php
index 8632566..3f4027b 100644
--- a/framework/yii/widgets/FragmentCache.php
+++ b/framework/yii/widgets/FragmentCache.php
@@ -13,6 +13,10 @@ use yii\caching\Cache;
use yii\caching\Dependency;
/**
+ *
+ * @property string|boolean $cachedContent The cached content. False is returned if valid content is not found
+ * in the cache. This property is read-only.
+ *
* @author Qiang Xue
* @since 2.0
*/
diff --git a/framework/yii/widgets/LinkSorter.php b/framework/yii/widgets/LinkSorter.php
index b555475..c8b30e5 100644
--- a/framework/yii/widgets/LinkSorter.php
+++ b/framework/yii/widgets/LinkSorter.php
@@ -28,6 +28,11 @@ class LinkSorter extends Widget
*/
public $sort;
/**
+ * @var array list of the attributes that support sorting. If not set, it will be determined
+ * using [[Sort::attributes]].
+ */
+ public $attributes;
+ /**
* @var array HTML attributes for the sorter container tag.
*/
public $options = array('class' => 'sorter');
@@ -58,8 +63,9 @@ class LinkSorter extends Widget
*/
protected function renderSortLinks()
{
+ $attributes = empty($this->atttributes) ? array_keys($this->sort->attributes) : $this->attributes;
$links = array();
- foreach (array_keys($this->sort->attributes) as $name) {
+ foreach ($attributes as $name) {
$links[] = $this->sort->link($name);
}
return Html::ul($links, array('encode' => false));
diff --git a/framework/yii/widgets/ListViewBase.php b/framework/yii/widgets/ListViewBase.php
index 6be704d..8c2f8f4 100644
--- a/framework/yii/widgets/ListViewBase.php
+++ b/framework/yii/widgets/ListViewBase.php
@@ -66,7 +66,7 @@ abstract class ListViewBase extends Widget
* - `{sorter}`: the sorter. See [[renderSorter()]].
* - `{pager}`: the pager. See [[renderPager()]].
*/
- public $layout = "{summary}\n{sorter}\n{items}\n{pager}";
+ public $layout = "{summary}\n{items}\n{pager}";
/**
diff --git a/framework/yii/widgets/MaskedInput.php b/framework/yii/widgets/MaskedInput.php
index 35794b8..8b8cbc6 100644
--- a/framework/yii/widgets/MaskedInput.php
+++ b/framework/yii/widgets/MaskedInput.php
@@ -18,17 +18,17 @@ use yii\web\JsExpression;
* MaskedInput is similar to [[Html::textInput()]] except that
* an input mask will be used to force users to enter properly formatted data,
* such as phone numbers, social security numbers.
- *
+ *
* To use MaskedInput, you must set the [[mask]] property. The following example
* shows how to use MaskedInput to collect phone numbers:
- *
+ *
* ~~~
* echo MaskedInput::widget(array(
* 'name' => 'phone',
* 'mask' => '999-999-9999',
* ));
* ~~~
- *
+ *
* The masked text field is implemented based on the [jQuery masked input plugin](http://digitalbush.com/projects/masked-input-plugin).
*
* @author Qiang Xue
diff --git a/tests/unit/data/ar/Customer.php b/tests/unit/data/ar/Customer.php
index 561d1ae..bbc0182 100644
--- a/tests/unit/data/ar/Customer.php
+++ b/tests/unit/data/ar/Customer.php
@@ -3,6 +3,15 @@ namespace yiiunit\data\ar;
use yii\db\ActiveQuery;
+/**
+ * Class Customer
+ *
+ * @property integer $id
+ * @property string $name
+ * @property string $email
+ * @property string $address
+ * @property integer $status
+ */
class Customer extends ActiveRecord
{
const STATUS_ACTIVE = 1;
diff --git a/tests/unit/data/ar/Item.php b/tests/unit/data/ar/Item.php
index 5d23378..e725be9 100644
--- a/tests/unit/data/ar/Item.php
+++ b/tests/unit/data/ar/Item.php
@@ -2,6 +2,13 @@
namespace yiiunit\data\ar;
+/**
+ * Class Item
+ *
+ * @property integer $id
+ * @property string $name
+ * @property integer $category_id
+ */
class Item extends ActiveRecord
{
public static function tableName()
diff --git a/tests/unit/data/ar/Order.php b/tests/unit/data/ar/Order.php
index 119f332..063bb67 100644
--- a/tests/unit/data/ar/Order.php
+++ b/tests/unit/data/ar/Order.php
@@ -2,6 +2,14 @@
namespace yiiunit\data\ar;
+/**
+ * Class Order
+ *
+ * @property integer $id
+ * @property integer $customer_id
+ * @property integer $create_time
+ * @property string $total
+ */
class Order extends ActiveRecord
{
public static function tableName()
diff --git a/tests/unit/data/ar/OrderItem.php b/tests/unit/data/ar/OrderItem.php
index 607133e..297432b 100644
--- a/tests/unit/data/ar/OrderItem.php
+++ b/tests/unit/data/ar/OrderItem.php
@@ -2,6 +2,14 @@
namespace yiiunit\data\ar;
+/**
+ * Class OrderItem
+ *
+ * @property integer $order_id
+ * @property integer $item_id
+ * @property integer $quantity
+ * @property string $subtotal
+ */
class OrderItem extends ActiveRecord
{
public static function tableName()
diff --git a/tests/unit/data/config.php b/tests/unit/data/config.php
index 1996e54..beba900 100644
--- a/tests/unit/data/config.php
+++ b/tests/unit/data/config.php
@@ -1,6 +1,12 @@
array(
+ 'cubrid' => array(
+ 'dsn' => 'cubrid:dbname=demodb;host=localhost;port=33000',
+ 'username' => 'dba',
+ 'password' => '',
+ 'fixture' => __DIR__ . '/cubrid.sql',
+ ),
'mysql' => array(
'dsn' => 'mysql:host=127.0.0.1;dbname=yiitest',
'username' => 'travis',
diff --git a/tests/unit/data/cubrid.sql b/tests/unit/data/cubrid.sql
new file mode 100644
index 0000000..3dcfa37
--- /dev/null
+++ b/tests/unit/data/cubrid.sql
@@ -0,0 +1,108 @@
+/**
+ * This is the database schema for testing CUBRID support of Yii DAO and Active Record.
+ * The database setup in config.php is required to perform then relevant tests:
+ */
+
+DROP TABLE IF EXISTS tbl_composite_fk;
+DROP TABLE IF EXISTS tbl_order_item;
+DROP TABLE IF EXISTS tbl_item;
+DROP TABLE IF EXISTS tbl_order;
+DROP TABLE IF EXISTS tbl_category;
+DROP TABLE IF EXISTS tbl_customer;
+DROP TABLE IF EXISTS tbl_type;
+DROP TABLE IF EXISTS tbl_constraints;
+
+CREATE TABLE `tbl_constraints`
+(
+ `id` integer not null,
+ `field1` varchar(255)
+);
+
+
+CREATE TABLE `tbl_customer` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `email` varchar(128) NOT NULL,
+ `name` varchar(128) NOT NULL,
+ `address` string,
+ `status` int (11) DEFAULT 0,
+ PRIMARY KEY (`id`)
+);
+
+CREATE TABLE `tbl_category` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `name` varchar(128) NOT NULL,
+ PRIMARY KEY (`id`)
+);
+
+CREATE TABLE `tbl_item` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `name` varchar(128) NOT NULL,
+ `category_id` int(11) NOT NULL,
+ PRIMARY KEY (`id`),
+ CONSTRAINT `FK_item_category_id` FOREIGN KEY (`category_id`) REFERENCES `tbl_category` (`id`) ON DELETE CASCADE
+);
+
+CREATE TABLE `tbl_order` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `customer_id` int(11) NOT NULL,
+ `create_time` int(11) NOT NULL,
+ `total` decimal(10,0) NOT NULL,
+ PRIMARY KEY (`id`),
+ CONSTRAINT `FK_order_customer_id` FOREIGN KEY (`customer_id`) REFERENCES `tbl_customer` (`id`) ON DELETE CASCADE
+);
+
+CREATE TABLE `tbl_order_item` (
+ `order_id` int(11) NOT NULL,
+ `item_id` int(11) NOT NULL,
+ `quantity` int(11) NOT NULL,
+ `subtotal` decimal(10,0) NOT NULL,
+ PRIMARY KEY (`order_id`,`item_id`),
+ CONSTRAINT `FK_order_item_order_id` FOREIGN KEY (`order_id`) REFERENCES `tbl_order` (`id`) ON DELETE CASCADE,
+ CONSTRAINT `FK_order_item_item_id` FOREIGN KEY (`item_id`) REFERENCES `tbl_item` (`id`) ON DELETE CASCADE
+);
+
+CREATE TABLE `tbl_type` (
+ `int_col` int(11) NOT NULL,
+ `int_col2` int(11) DEFAULT '1',
+ `char_col` char(100) NOT NULL,
+ `char_col2` varchar(100) DEFAULT 'something',
+ `char_col3` string,
+ `enum_col` enum('a', 'b'),
+ `float_col` double NOT NULL,
+ `float_col2` double DEFAULT '1.23',
+ `blob_col` blob,
+ `numeric_col` decimal(5,2) DEFAULT '33.22',
+ `time` timestamp NOT NULL DEFAULT '2002-01-01 00:00:00'
+);
+
+CREATE TABLE `tbl_composite_fk` (
+ `id` int(11) NOT NULL,
+ `order_id` int(11) NOT NULL,
+ `item_id` int(11) NOT NULL,
+ PRIMARY KEY (`id`),
+ CONSTRAINT `FK_composite_fk_order_item` FOREIGN KEY (`order_id`,`item_id`) REFERENCES `tbl_order_item` (`order_id`,`item_id`) ON DELETE CASCADE
+);
+
+INSERT INTO tbl_customer (email, name, address, status) VALUES ('user1@example.com', 'user1', 'address1', 1);
+INSERT INTO tbl_customer (email, name, address, status) VALUES ('user2@example.com', 'user2', 'address2', 1);
+INSERT INTO tbl_customer (email, name, address, status) VALUES ('user3@example.com', 'user3', 'address3', 2);
+
+INSERT INTO tbl_category (name) VALUES ('Books');
+INSERT INTO tbl_category (name) VALUES ('Movies');
+
+INSERT INTO tbl_item (name, category_id) VALUES ('Agile Web Application Development with Yii1.1 and PHP5', 1);
+INSERT INTO tbl_item (name, category_id) VALUES ('Yii 1.1 Application Development Cookbook', 1);
+INSERT INTO tbl_item (name, category_id) VALUES ('Ice Age', 2);
+INSERT INTO tbl_item (name, category_id) VALUES ('Toy Story', 2);
+INSERT INTO tbl_item (name, category_id) VALUES ('Cars', 2);
+
+INSERT INTO tbl_order (customer_id, create_time, total) VALUES (1, 1325282384, 110.0);
+INSERT INTO tbl_order (customer_id, create_time, total) VALUES (2, 1325334482, 33.0);
+INSERT INTO tbl_order (customer_id, create_time, total) VALUES (2, 1325502201, 40.0);
+
+INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (1, 1, 1, 30.0);
+INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (1, 2, 2, 40.0);
+INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 4, 1, 10.0);
+INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 15.0);
+INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (2, 3, 1, 8.0);
+INSERT INTO tbl_order_item (order_id, item_id, quantity, subtotal) VALUES (3, 2, 1, 40.0);
diff --git a/tests/unit/data/mysql.sql b/tests/unit/data/mysql.sql
index 2e9458e..133348d 100644
--- a/tests/unit/data/mysql.sql
+++ b/tests/unit/data/mysql.sql
@@ -3,6 +3,7 @@
* The database setup in config.php is required to perform then relevant tests:
*/
+DROP TABLE IF EXISTS tbl_composite_fk CASCADE;
DROP TABLE IF EXISTS tbl_order_item CASCADE;
DROP TABLE IF EXISTS tbl_item CASCADE;
DROP TABLE IF EXISTS tbl_order CASCADE;
@@ -62,6 +63,14 @@ CREATE TABLE `tbl_order_item` (
CONSTRAINT `FK_order_item_item_id` FOREIGN KEY (`item_id`) REFERENCES `tbl_item` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+CREATE TABLE `tbl_composite_fk` (
+ `id` int(11) NOT NULL,
+ `order_id` int(11) NOT NULL,
+ `item_id` int(11) NOT NULL,
+ PRIMARY KEY (`id`),
+ CONSTRAINT `FK_composite_fk_order_item` FOREIGN KEY (`order_id`,`item_id`) REFERENCES `tbl_order_item` (`order_id`,`item_id`) ON DELETE CASCADE
+);
+
CREATE TABLE `tbl_type` (
`int_col` int(11) NOT NULL,
`int_col2` int(11) DEFAULT '1',
diff --git a/tests/unit/data/sqlite.sql b/tests/unit/data/sqlite.sql
index f75bfa6..f031ac3 100644
--- a/tests/unit/data/sqlite.sql
+++ b/tests/unit/data/sqlite.sql
@@ -3,6 +3,7 @@
* The database setup in config.php is required to perform then relevant tests:
*/
+DROP TABLE IF EXISTS tbl_composite_fk;
DROP TABLE IF EXISTS tbl_order_item;
DROP TABLE IF EXISTS tbl_item;
DROP TABLE IF EXISTS tbl_order;
@@ -48,6 +49,14 @@ CREATE TABLE tbl_order_item (
PRIMARY KEY (order_id, item_id)
);
+CREATE TABLE `tbl_composite_fk` (
+ `id` int(11) NOT NULL,
+ `order_id` int(11) NOT NULL,
+ `item_id` int(11) NOT NULL,
+ PRIMARY KEY (`id`),
+ CONSTRAINT `FK_composite_fk_order_item` FOREIGN KEY (`order_id`,`item_id`) REFERENCES `tbl_order_item` (`order_id`,`item_id`) ON DELETE CASCADE
+);
+
CREATE TABLE tbl_type (
int_col INTEGER NOT NULL,
int_col2 INTEGER DEFAULT '1',
diff --git a/tests/unit/data/travis/README.md b/tests/unit/data/travis/README.md
new file mode 100644
index 0000000..c86497e
--- /dev/null
+++ b/tests/unit/data/travis/README.md
@@ -0,0 +1,12 @@
+This directory contains scripts for automated test runs via the [Travis CI](http://travis-ci.org) build service. They are used for the preparation of worker instances by setting up needed extensions and configuring database access.
+
+These scripts might be used to configure your own system for test runs. But since their primary purpose remains to support Travis in running the test cases, you would be best advised to stick to the setup notes in the tests themselves.
+
+The scripts are:
+
+ - [`apc-setup.sh`](apc-setup.sh)
+ Installs and configures the [apc pecl extension](http://pecl.php.net/package/apc)
+ - [`memcache-setup.sh`](memcache-setup.sh)
+ Compiles and installs the [memcache pecl extension](http://pecl.php.net/package/memcache)
+ - [`cubrid-setup.sh`](cubrid-setup.sh)
+ Prepares the [CUBRID](http://www.cubrid.org/) server instance by installing the server and PHP PDO driver
diff --git a/tests/unit/data/travis/apc-setup.sh b/tests/unit/data/travis/apc-setup.sh
new file mode 100755
index 0000000..e5e8734
--- /dev/null
+++ b/tests/unit/data/travis/apc-setup.sh
@@ -0,0 +1,2 @@
+echo "extension = apc.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
+echo "apc.enable_cli = 1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
\ No newline at end of file
diff --git a/tests/unit/data/travis/cubrid-setup.sh b/tests/unit/data/travis/cubrid-setup.sh
new file mode 100755
index 0000000..af007ff
--- /dev/null
+++ b/tests/unit/data/travis/cubrid-setup.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# install CUBRID DBMS https://github.com/CUBRID/node-cubrid/blob/056e734ce36bb3fd25f100c983beb3947e899c1c/.travis.yml
+
+sudo hostname localhost
+# Update OS before installing prerequisites.
+sudo apt-get update
+# Install Chef Solo prerequisites.
+sudo apt-get install ruby ruby-dev libopenssl-ruby rdoc ri irb build-essential ssl-cert
+# Install Chef Solo.
+# Chef Solo 11.4.4 is broken, so install a previous version.
+# The bug is planned to be fixed in 11.4.5 which haven't been released yet.
+sudo gem install --version '<11.4.4' chef --no-rdoc --no-ri
+# Make sure the target directory for cookbooks exists.
+mkdir -p /tmp/chef-solo
+# Prepare a file with runlist for Chef Solo.
+echo '{"cubrid":{"version":"'$CUBRID_VERSION'"},"run_list":["cubrid::demodb"]}' > cubrid_chef.json
+# Install CUBRID via Chef Solo. Download all cookbooks from a remote URL.
+sudo chef-solo -c tests/unit/data/travis/cubrid-solo.rb -j cubrid_chef.json -r http://sourceforge.net/projects/cubrid/files/CUBRID-Demo-Virtual-Machines/Vagrant/chef-cookbooks.tar.gz/download
+
+
+install_pdo_cubrid() {
+ wget "http://pecl.php.net/get/PDO_CUBRID-9.1.0.0003.tgz" &&
+ tar -zxf "PDO_CUBRID-9.1.0.0003.tgz" &&
+ sh -c "cd PDO_CUBRID-9.1.0.0003 && phpize && ./configure && make && sudo make install"
+
+ echo "extension=pdo_cubrid.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
+
+ return $?
+}
+
+install_pdo_cubrid > ~/pdo_cubrid.log || ( echo "=== PDO CUBRID BUILD FAILED ==="; cat ~/pdo_cubrid.log )
\ No newline at end of file
diff --git a/tests/unit/data/travis/cubrid-solo.rb b/tests/unit/data/travis/cubrid-solo.rb
new file mode 100644
index 0000000..f5f0004
--- /dev/null
+++ b/tests/unit/data/travis/cubrid-solo.rb
@@ -0,0 +1,5 @@
+file_cache_path "/tmp/chef-solo"
+data_bag_path "/tmp/chef-solo/data_bags"
+encrypted_data_bag_secret "/tmp/chef-solo/data_bag_key"
+cookbook_path [ "/tmp/chef-solo/cookbooks" ]
+role_path "/tmp/chef-solo/roles"
\ No newline at end of file
diff --git a/tests/unit/data/travis/memcache-setup.sh b/tests/unit/data/travis/memcache-setup.sh
new file mode 100755
index 0000000..6b623d6
--- /dev/null
+++ b/tests/unit/data/travis/memcache-setup.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+echo "extension=memcache.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
+echo "extension=memcached.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
diff --git a/tests/unit/framework/YiiBaseTest.php b/tests/unit/framework/YiiBaseTest.php
index e256b2b..72b5f24 100644
--- a/tests/unit/framework/YiiBaseTest.php
+++ b/tests/unit/framework/YiiBaseTest.php
@@ -6,6 +6,7 @@ use yiiunit\TestCase;
/**
* YiiBaseTest
+ * @group base
*/
class YiiBaseTest extends TestCase
{
diff --git a/tests/unit/framework/base/BehaviorTest.php b/tests/unit/framework/base/BehaviorTest.php
index edb9a1e..b6eda09 100644
--- a/tests/unit/framework/base/BehaviorTest.php
+++ b/tests/unit/framework/base/BehaviorTest.php
@@ -28,8 +28,27 @@ class BarBehavior extends Behavior
{
return 'behavior method';
}
+
+ public function __call($name, $params)
+ {
+ if ($name == 'magicBehaviorMethod') {
+ return 'Magic Behavior Method Result!';
+ }
+ return parent::__call($name, $params);
+ }
+
+ public function hasMethod($name)
+ {
+ if ($name == 'magicBehaviorMethod') {
+ return true;
+ }
+ return parent::hasMethod($name);
+ }
}
+/**
+ * @group base
+ */
class BehaviorTest extends TestCase
{
protected function setUp()
@@ -59,4 +78,29 @@ class BehaviorTest extends TestCase
$this->assertEquals('behavior property', $foo->behaviorProperty);
$this->assertEquals('behavior method', $foo->behaviorMethod());
}
+
+ public function testMagicMethods()
+ {
+ $bar = new BarClass();
+ $behavior = new BarBehavior();
+
+ $this->assertFalse($bar->hasMethod('magicBehaviorMethod'));
+ $bar->attachBehavior('bar', $behavior);
+ $this->assertFalse($bar->hasMethod('magicBehaviorMethod', false));
+ $this->assertTrue($bar->hasMethod('magicBehaviorMethod'));
+
+ $this->assertEquals('Magic Behavior Method Result!', $bar->magicBehaviorMethod());
+ }
+
+ public function testCallUnknownMethod()
+ {
+ $bar = new BarClass();
+ $behavior = new BarBehavior();
+ $this->setExpectedException('yii\base\UnknownMethodException');
+
+ $this->assertFalse($bar->hasMethod('nomagicBehaviorMethod'));
+ $bar->attachBehavior('bar', $behavior);
+ $bar->nomagicBehaviorMethod();
+ }
+
}
diff --git a/tests/unit/framework/base/ComponentTest.php b/tests/unit/framework/base/ComponentTest.php
index 79fb7db..98786e2 100644
--- a/tests/unit/framework/base/ComponentTest.php
+++ b/tests/unit/framework/base/ComponentTest.php
@@ -17,6 +17,9 @@ function globalEventHandler2($event)
$event->handled = true;
}
+/**
+ * @group base
+ */
class ComponentTest extends TestCase
{
/**
diff --git a/tests/unit/framework/base/FormatterTest.php b/tests/unit/framework/base/FormatterTest.php
index 01dd682..ae71a5c 100644
--- a/tests/unit/framework/base/FormatterTest.php
+++ b/tests/unit/framework/base/FormatterTest.php
@@ -10,9 +10,7 @@ use yii\base\Formatter;
use yiiunit\TestCase;
/**
- *
- * @author Qiang Xue
- * @since 2.0
+ * @group base
*/
class FormatterTest extends TestCase
{
diff --git a/tests/unit/framework/base/ModelTest.php b/tests/unit/framework/base/ModelTest.php
index e4d8976..b338c17 100644
--- a/tests/unit/framework/base/ModelTest.php
+++ b/tests/unit/framework/base/ModelTest.php
@@ -9,7 +9,7 @@ use yiiunit\data\base\Singer;
use yiiunit\data\base\InvalidRulesModel;
/**
- * ModelTest
+ * @group base
*/
class ModelTest extends TestCase
{
diff --git a/tests/unit/framework/base/ObjectTest.php b/tests/unit/framework/base/ObjectTest.php
index 933b721..0bd9b1d 100644
--- a/tests/unit/framework/base/ObjectTest.php
+++ b/tests/unit/framework/base/ObjectTest.php
@@ -5,7 +5,7 @@ use yii\base\Object;
use yiiunit\TestCase;
/**
- * ObjectTest
+ * @group base
*/
class ObjectTest extends TestCase
{
@@ -134,11 +134,6 @@ class ObjectTest extends TestCase
$this->assertEquals('new text', $this->object->object->text);
}
- public function testAnonymousFunctionProperty()
- {
- $this->assertEquals(2, $this->object->execute(1));
- }
-
public function testConstruct()
{
$object = new NewObject(array('text' => 'test text'));
diff --git a/tests/unit/framework/behaviors/AutoTimestampTest.php b/tests/unit/framework/behaviors/AutoTimestampTest.php
index 0e17a39..c26d912 100644
--- a/tests/unit/framework/behaviors/AutoTimestampTest.php
+++ b/tests/unit/framework/behaviors/AutoTimestampTest.php
@@ -11,6 +11,8 @@ use yii\behaviors\AutoTimestamp;
/**
* Unit test for [[\yii\behaviors\AutoTimestamp]].
* @see AutoTimestamp
+ *
+ * @group behaviors
*/
class AutoTimestampTest extends TestCase
{
diff --git a/tests/unit/framework/caching/ApcCacheTest.php b/tests/unit/framework/caching/ApcCacheTest.php
index 1d07498..adda151 100644
--- a/tests/unit/framework/caching/ApcCacheTest.php
+++ b/tests/unit/framework/caching/ApcCacheTest.php
@@ -5,6 +5,8 @@ use yii\caching\ApcCache;
/**
* Class for testing APC cache backend
+ * @group apc
+ * @group caching
*/
class ApcCacheTest extends CacheTestCase
{
diff --git a/tests/unit/framework/caching/CacheTestCase.php b/tests/unit/framework/caching/CacheTestCase.php
index 491459b..94894a3 100644
--- a/tests/unit/framework/caching/CacheTestCase.php
+++ b/tests/unit/framework/caching/CacheTestCase.php
@@ -91,6 +91,18 @@ abstract class CacheTestCase extends TestCase
$this->assertEquals('array_test', $array['array_test']);
}
+ public function testExists()
+ {
+ $cache = $this->prepare();
+
+ $this->assertTrue($cache->exists('string_test'));
+ // check whether exists affects the value
+ $this->assertEquals('string_test', $cache->get('string_test'));
+
+ $this->assertTrue($cache->exists('number_test'));
+ $this->assertFalse($cache->exists('not_exists'));
+ }
+
public function testArrayAccess()
{
$cache = $this->getCacheInstance();
diff --git a/tests/unit/framework/caching/DbCacheTest.php b/tests/unit/framework/caching/DbCacheTest.php
index 969b034..1e94d58 100644
--- a/tests/unit/framework/caching/DbCacheTest.php
+++ b/tests/unit/framework/caching/DbCacheTest.php
@@ -6,6 +6,8 @@ use yii\caching\DbCache;
/**
* Class for testing file cache backend
+ * @group db
+ * @group caching
*/
class DbCacheTest extends CacheTestCase
{
diff --git a/tests/unit/framework/caching/FileCacheTest.php b/tests/unit/framework/caching/FileCacheTest.php
index 0bdbc86..263ecb4 100644
--- a/tests/unit/framework/caching/FileCacheTest.php
+++ b/tests/unit/framework/caching/FileCacheTest.php
@@ -5,6 +5,7 @@ use yii\caching\FileCache;
/**
* Class for testing file cache backend
+ * @group caching
*/
class FileCacheTest extends CacheTestCase
{
diff --git a/tests/unit/framework/caching/MemCacheTest.php b/tests/unit/framework/caching/MemCacheTest.php
index d54d807..32374b5 100644
--- a/tests/unit/framework/caching/MemCacheTest.php
+++ b/tests/unit/framework/caching/MemCacheTest.php
@@ -5,6 +5,8 @@ use yii\caching\MemCache;
/**
* Class for testing memcache cache backend
+ * @group memcache
+ * @group caching
*/
class MemCacheTest extends CacheTestCase
{
diff --git a/tests/unit/framework/caching/MemCachedTest.php b/tests/unit/framework/caching/MemCachedTest.php
index faf0d56..f39ed17 100644
--- a/tests/unit/framework/caching/MemCachedTest.php
+++ b/tests/unit/framework/caching/MemCachedTest.php
@@ -5,6 +5,8 @@ use yii\caching\MemCache;
/**
* Class for testing memcached cache backend
+ * @group memcached
+ * @group caching
*/
class MemCachedTest extends CacheTestCase
{
diff --git a/tests/unit/framework/caching/RedisCacheTest.php b/tests/unit/framework/caching/RedisCacheTest.php
index 0924d0f..d02773d 100644
--- a/tests/unit/framework/caching/RedisCacheTest.php
+++ b/tests/unit/framework/caching/RedisCacheTest.php
@@ -6,6 +6,8 @@ use yiiunit\TestCase;
/**
* Class for testing redis cache backend
+ * @group redis
+ * @group caching
*/
class RedisCacheTest extends CacheTestCase
{
diff --git a/tests/unit/framework/caching/WinCacheTest.php b/tests/unit/framework/caching/WinCacheTest.php
index b6f2425..1bce102 100644
--- a/tests/unit/framework/caching/WinCacheTest.php
+++ b/tests/unit/framework/caching/WinCacheTest.php
@@ -5,6 +5,8 @@ use yii\caching\WinCache;
/**
* Class for testing wincache backend
+ * @group wincache
+ * @group caching
*/
class WinCacheTest extends CacheTestCase
{
diff --git a/tests/unit/framework/caching/XCacheTest.php b/tests/unit/framework/caching/XCacheTest.php
index 7ee0a0e..989765d 100644
--- a/tests/unit/framework/caching/XCacheTest.php
+++ b/tests/unit/framework/caching/XCacheTest.php
@@ -5,6 +5,8 @@ use yii\caching\XCache;
/**
* Class for testing xcache backend
+ * @group xcache
+ * @group caching
*/
class XCacheTest extends CacheTestCase
{
diff --git a/tests/unit/framework/caching/ZendDataCacheTest.php b/tests/unit/framework/caching/ZendDataCacheTest.php
index 2d68bfd..96354cd 100644
--- a/tests/unit/framework/caching/ZendDataCacheTest.php
+++ b/tests/unit/framework/caching/ZendDataCacheTest.php
@@ -6,6 +6,8 @@ use yii\caching\ZendDataCache;
/**
* Class for testing Zend cache backend
+ * @group zenddata
+ * @group caching
*/
class ZendDataCacheTest extends CacheTestCase
{
diff --git a/tests/unit/framework/console/controllers/AssetControllerTest.php b/tests/unit/framework/console/controllers/AssetControllerTest.php
index aaf5ca9..67dbdaa 100644
--- a/tests/unit/framework/console/controllers/AssetControllerTest.php
+++ b/tests/unit/framework/console/controllers/AssetControllerTest.php
@@ -6,6 +6,8 @@ use yii\console\controllers\AssetController;
/**
* Unit test for [[\yii\console\controllers\AssetController]].
* @see AssetController
+ *
+ * @group console
*/
class AssetControllerTest extends TestCase
{
diff --git a/tests/unit/framework/console/controllers/MessageControllerTest.php b/tests/unit/framework/console/controllers/MessageControllerTest.php
index cdd38b8..b0c697c 100644
--- a/tests/unit/framework/console/controllers/MessageControllerTest.php
+++ b/tests/unit/framework/console/controllers/MessageControllerTest.php
@@ -6,6 +6,8 @@ use yii\console\controllers\MessageController;
/**
* Unit test for [[\yii\console\controllers\MessageController]].
* @see MessageController
+ *
+ * @group console
*/
class MessageControllerTest extends TestCase
{
diff --git a/tests/unit/framework/data/ActiveDataProviderTest.php b/tests/unit/framework/data/ActiveDataProviderTest.php
index 2699a52..3f65ebb 100644
--- a/tests/unit/framework/data/ActiveDataProviderTest.php
+++ b/tests/unit/framework/data/ActiveDataProviderTest.php
@@ -16,6 +16,8 @@ use yiiunit\data\ar\Order;
/**
* @author Qiang Xue
* @since 2.0
+ *
+ * @group data
*/
class ActiveDataProviderTest extends DatabaseTestCase
{
diff --git a/tests/unit/framework/data/SortTest.php b/tests/unit/framework/data/SortTest.php
index 9891ad1..c4cc6aa 100644
--- a/tests/unit/framework/data/SortTest.php
+++ b/tests/unit/framework/data/SortTest.php
@@ -14,6 +14,8 @@ use yii\data\Sort;
/**
* @author Qiang Xue
* @since 2.0
+ *
+ * @group data
*/
class SortTest extends TestCase
{
diff --git a/tests/unit/framework/db/ActiveRecordTest.php b/tests/unit/framework/db/ActiveRecordTest.php
index 7df4159..2f9b345 100644
--- a/tests/unit/framework/db/ActiveRecordTest.php
+++ b/tests/unit/framework/db/ActiveRecordTest.php
@@ -9,6 +9,10 @@ use yiiunit\data\ar\OrderItem;
use yiiunit\data\ar\Order;
use yiiunit\data\ar\Item;
+/**
+ * @group db
+ * @group mysql
+ */
class ActiveRecordTest extends DatabaseTestCase
{
protected function setUp()
diff --git a/tests/unit/framework/db/CommandTest.php b/tests/unit/framework/db/CommandTest.php
index 52fd046..d9eb0e7 100644
--- a/tests/unit/framework/db/CommandTest.php
+++ b/tests/unit/framework/db/CommandTest.php
@@ -7,14 +7,12 @@ use yii\db\Command;
use yii\db\Query;
use yii\db\DataReader;
+/**
+ * @group db
+ * @group mysql
+ */
class CommandTest extends DatabaseTestCase
{
- protected function setUp()
- {
- parent::setUp();
- $this->mockApplication();
- }
-
public function testConstruct()
{
$db = $this->getConnection(false);
@@ -221,6 +219,29 @@ class CommandTest extends DatabaseTestCase
$this->assertTrue(is_array($result) && isset($result[0]));
}
+ // getPDOType is currently private
+// public function testGetPDOType()
+// {
+// $values = array(
+// array(null, \PDO::PARAM_NULL),
+// array('', \PDO::PARAM_STR),
+// array('hello', \PDO::PARAM_STR),
+// array(0, \PDO::PARAM_INT),
+// array(1, \PDO::PARAM_INT),
+// array(1337, \PDO::PARAM_INT),
+// array(true, \PDO::PARAM_BOOL),
+// array(false, \PDO::PARAM_BOOL),
+// array($fp=fopen(__FILE__, 'rb'), \PDO::PARAM_LOB),
+// );
+//
+// $command = $this->getConnection()->createCommand();
+//
+// foreach($values as $value) {
+// $this->assertEquals($value[1], $command->getPdoType($value[0]));
+// }
+// fclose($fp);
+// }
+
public function testInsert()
{
}
diff --git a/tests/unit/framework/db/ConnectionTest.php b/tests/unit/framework/db/ConnectionTest.php
index 42b470b..04c5d53 100644
--- a/tests/unit/framework/db/ConnectionTest.php
+++ b/tests/unit/framework/db/ConnectionTest.php
@@ -4,14 +4,12 @@ namespace yiiunit\framework\db;
use yii\db\Connection;
+/**
+ * @group db
+ * @group mysql
+ */
class ConnectionTest extends DatabaseTestCase
{
- protected function setUp()
- {
- parent::setUp();
- $this->mockApplication();
- }
-
public function testConstruct()
{
$connection = $this->getConnection(false);
diff --git a/tests/unit/framework/db/DatabaseTestCase.php b/tests/unit/framework/db/DatabaseTestCase.php
index 1fd2d56..d8d2916 100644
--- a/tests/unit/framework/db/DatabaseTestCase.php
+++ b/tests/unit/framework/db/DatabaseTestCase.php
@@ -1,18 +1,21 @@
mockApplication();
$databases = $this->getParam('databases');
$this->database = $databases[$this->driverName];
$pdo_database = 'pdo_'.$this->driverName;
@@ -20,6 +23,15 @@ abstract class DatabaseTestCase extends TestCase
if (!extension_loaded('pdo') || !extension_loaded($pdo_database)) {
$this->markTestSkipped('pdo and pdo_'.$pdo_database.' extension are required.');
}
+ $this->mockApplication();
+ }
+
+ protected function tearDown()
+ {
+ if ($this->db) {
+ $this->db->close();
+ }
+ $this->destroyApplication();
}
/**
diff --git a/tests/unit/framework/db/QueryBuilderTest.php b/tests/unit/framework/db/QueryBuilderTest.php
index 146cfdb..d43c901 100644
--- a/tests/unit/framework/db/QueryBuilderTest.php
+++ b/tests/unit/framework/db/QueryBuilderTest.php
@@ -8,15 +8,14 @@ use yii\db\mysql\QueryBuilder as MysqlQueryBuilder;
use yii\db\sqlite\QueryBuilder as SqliteQueryBuilder;
use yii\db\mssql\QueryBuilder as MssqlQueryBuilder;
use yii\db\pgsql\QueryBuilder as PgsqlQueryBuilder;
+use yii\db\cubrid\QueryBuilder as CubridQueryBuilder;
+/**
+ * @group db
+ * @group mysql
+ */
class QueryBuilderTest extends DatabaseTestCase
{
- protected function setUp()
- {
- parent::setUp();
- $this->mockApplication();
- }
-
/**
* @throws \Exception
* @return QueryBuilder
@@ -32,6 +31,8 @@ class QueryBuilderTest extends DatabaseTestCase
return new MssqlQueryBuilder($this->getConnection());
case 'pgsql':
return new PgsqlQueryBuilder($this->getConnection());
+ case 'cubrid':
+ return new CubridQueryBuilder($this->getConnection());
}
throw new \Exception('Test is not implemented for ' . $this->driverName);
}
@@ -112,7 +113,7 @@ class QueryBuilderTest extends DatabaseTestCase
}
}
- public function testAddDropPrimayKey()
+ public function testAddDropPrimaryKey()
{
$tableName = 'tbl_constraints';
$pkeyName = $tableName . "_pkey";
diff --git a/tests/unit/framework/db/QueryTest.php b/tests/unit/framework/db/QueryTest.php
index 5d1f1a9..a275afd 100644
--- a/tests/unit/framework/db/QueryTest.php
+++ b/tests/unit/framework/db/QueryTest.php
@@ -7,14 +7,12 @@ use yii\db\Command;
use yii\db\Query;
use yii\db\DataReader;
+/**
+ * @group db
+ * @group mysql
+ */
class QueryTest extends DatabaseTestCase
{
- protected function setUp()
- {
- parent::setUp();
- $this->mockApplication();
- }
-
public function testSelect()
{
// default
diff --git a/tests/unit/framework/db/SchemaTest.php b/tests/unit/framework/db/SchemaTest.php
new file mode 100644
index 0000000..2a3015d
--- /dev/null
+++ b/tests/unit/framework/db/SchemaTest.php
@@ -0,0 +1,70 @@
+getConnection()->schema;
+
+ $tables = $schema->getTableNames();
+ $this->assertTrue(in_array('tbl_customer', $tables));
+ $this->assertTrue(in_array('tbl_category', $tables));
+ $this->assertTrue(in_array('tbl_item', $tables));
+ $this->assertTrue(in_array('tbl_order', $tables));
+ $this->assertTrue(in_array('tbl_order_item', $tables));
+ $this->assertTrue(in_array('tbl_type', $tables));
+ }
+
+ public function testGetTableSchemas()
+ {
+ /** @var Schema $schema */
+ $schema = $this->getConnection()->schema;
+
+ $tables = $schema->getTableSchemas();
+ $this->assertEquals(count($schema->getTableNames()), count($tables));
+ foreach($tables as $table) {
+ $this->assertInstanceOf('yii\db\TableSchema', $table);
+ }
+ }
+
+ public function testGetNonExistingTableSchema()
+ {
+ $this->assertNull($this->getConnection()->schema->getTableSchema('nonexisting_table'));
+ }
+
+ public function testSchemaCache()
+ {
+ /** @var Schema $schema */
+ $schema = $this->getConnection()->schema;
+
+ $schema->db->enableSchemaCache = true;
+ $schema->db->schemaCache = new FileCache();
+ $noCacheTable = $schema->getTableSchema('tbl_type', true);
+ $cachedTable = $schema->getTableSchema('tbl_type', true);
+ $this->assertEquals($noCacheTable, $cachedTable);
+ }
+
+ public function testCompositeFk()
+ {
+ /** @var Schema $schema */
+ $schema = $this->getConnection()->schema;
+
+ $table = $schema->getTableSchema('tbl_composite_fk');
+
+ $this->assertCount(1, $table->foreignKeys);
+ $this->assertTrue(isset($table->foreignKeys[0]));
+ $this->assertEquals('tbl_order_item', $table->foreignKeys[0][0]);
+ $this->assertEquals('order_id', $table->foreignKeys[0]['order_id']);
+ $this->assertEquals('item_id', $table->foreignKeys[0]['item_id']);
+ }
+}
diff --git a/tests/unit/framework/db/cubrid/CubridActiveRecordTest.php b/tests/unit/framework/db/cubrid/CubridActiveRecordTest.php
new file mode 100644
index 0000000..2d2db15
--- /dev/null
+++ b/tests/unit/framework/db/cubrid/CubridActiveRecordTest.php
@@ -0,0 +1,36 @@
+name = 'boolean customer';
+ $customer->email = 'mail@example.com';
+ $customer->status = true;
+ $customer->save(false);
+
+ $customer->refresh();
+ $this->assertEquals(1, $customer->status);
+
+ $customer->status = false;
+ $customer->save(false);
+
+ $customer->refresh();
+ $this->assertEquals(0, $customer->status);
+ }
+}
diff --git a/tests/unit/framework/db/cubrid/CubridCommandTest.php b/tests/unit/framework/db/cubrid/CubridCommandTest.php
new file mode 100644
index 0000000..45d3c1c
--- /dev/null
+++ b/tests/unit/framework/db/cubrid/CubridCommandTest.php
@@ -0,0 +1,79 @@
+getConnection();
+
+ // bindParam
+ $sql = 'INSERT INTO tbl_customer(email, name, address) VALUES (:email, :name, :address)';
+ $command = $db->createCommand($sql);
+ $email = 'user4@example.com';
+ $name = 'user4';
+ $address = 'address4';
+ $command->bindParam(':email', $email);
+ $command->bindParam(':name', $name);
+ $command->bindParam(':address', $address);
+ $command->execute();
+
+ $sql = 'SELECT name FROM tbl_customer WHERE email=:email';
+ $command = $db->createCommand($sql);
+ $command->bindParam(':email', $email);
+ $this->assertEquals($name, $command->queryScalar());
+
+ $sql = "INSERT INTO tbl_type (int_col, char_col, char_col2, enum_col, float_col, blob_col, numeric_col) VALUES (:int_col, '', :char_col, :enum_col, :float_col, CHAR_TO_BLOB(:blob_col), :numeric_col)";
+ $command = $db->createCommand($sql);
+ $intCol = 123;
+ $charCol = 'abc';
+ $enumCol = 'a';
+ $floatCol = 1.23;
+ $blobCol = "\x10\x11\x12";
+ $numericCol = '1.23';
+ $command->bindParam(':int_col', $intCol);
+ $command->bindParam(':char_col', $charCol);
+ $command->bindParam(':enum_col', $enumCol);
+ $command->bindParam(':float_col', $floatCol);
+ $command->bindParam(':blob_col', $blobCol);
+ $command->bindParam(':numeric_col', $numericCol);
+ $this->assertEquals(1, $command->execute());
+
+ $sql = 'SELECT * FROM tbl_type';
+ $row = $db->createCommand($sql)->queryOne();
+ $this->assertEquals($intCol, $row['int_col']);
+ $this->assertEquals($enumCol, $row['enum_col']);
+ $this->assertEquals($charCol, $row['char_col2']);
+ $this->assertEquals($floatCol, $row['float_col']);
+ $this->assertEquals($blobCol, fread($row['blob_col'], 3));
+ $this->assertEquals($numericCol, $row['numeric_col']);
+
+ // bindValue
+ $sql = 'INSERT INTO tbl_customer(email, name, address) VALUES (:email, \'user5\', \'address5\')';
+ $command = $db->createCommand($sql);
+ $command->bindValue(':email', 'user5@example.com');
+ $command->execute();
+
+ $sql = 'SELECT email FROM tbl_customer WHERE name=:name';
+ $command = $db->createCommand($sql);
+ $command->bindValue(':name', 'user5');
+ $this->assertEquals('user5@example.com', $command->queryScalar());
+ }
+
+ public function testAutoQuoting()
+ {
+ $db = $this->getConnection(false);
+
+ $sql = 'SELECT [[id]], [[t.name]] FROM {{tbl_customer}} t';
+ $command = $db->createCommand($sql);
+ $this->assertEquals('SELECT "id", "t"."name" FROM "tbl_customer" t', $command->sql);
+ }
+}
diff --git a/tests/unit/framework/db/cubrid/CubridConnectionTest.php b/tests/unit/framework/db/cubrid/CubridConnectionTest.php
new file mode 100644
index 0000000..4cd6e20
--- /dev/null
+++ b/tests/unit/framework/db/cubrid/CubridConnectionTest.php
@@ -0,0 +1,44 @@
+getConnection(false);
+ $this->assertEquals(123, $connection->quoteValue(123));
+ $this->assertEquals("'string'", $connection->quoteValue('string'));
+ $this->assertEquals("'It''s interesting'", $connection->quoteValue("It's interesting"));
+ }
+
+ public function testQuoteTableName()
+ {
+ $connection = $this->getConnection(false);
+ $this->assertEquals('"table"', $connection->quoteTableName('table'));
+ $this->assertEquals('"table"', $connection->quoteTableName('"table"'));
+ $this->assertEquals('"schema"."table"', $connection->quoteTableName('schema.table'));
+ $this->assertEquals('"schema"."table"', $connection->quoteTableName('schema."table"'));
+ $this->assertEquals('{{table}}', $connection->quoteTableName('{{table}}'));
+ $this->assertEquals('(table)', $connection->quoteTableName('(table)'));
+ }
+
+ public function testQuoteColumnName()
+ {
+ $connection = $this->getConnection(false);
+ $this->assertEquals('"column"', $connection->quoteColumnName('column'));
+ $this->assertEquals('"column"', $connection->quoteColumnName('"column"'));
+ $this->assertEquals('"table"."column"', $connection->quoteColumnName('table.column'));
+ $this->assertEquals('"table"."column"', $connection->quoteColumnName('table."column"'));
+ $this->assertEquals('[[column]]', $connection->quoteColumnName('[[column]]'));
+ $this->assertEquals('{{column}}', $connection->quoteColumnName('{{column}}'));
+ $this->assertEquals('(column)', $connection->quoteColumnName('(column)'));
+ }
+}
diff --git a/tests/unit/framework/db/cubrid/CubridQueryBuilderTest.php b/tests/unit/framework/db/cubrid/CubridQueryBuilderTest.php
new file mode 100644
index 0000000..107b73b
--- /dev/null
+++ b/tests/unit/framework/db/cubrid/CubridQueryBuilderTest.php
@@ -0,0 +1,84 @@
+ 5)', 'int NOT NULL AUTO_INCREMENT PRIMARY KEY CHECK (value > 5)'),
+ array(Schema::TYPE_PK . '(8) CHECK (value > 5)', 'int NOT NULL AUTO_INCREMENT PRIMARY KEY CHECK (value > 5)'),
+ array(Schema::TYPE_STRING, 'varchar(255)'),
+ array(Schema::TYPE_STRING . '(32)', 'varchar(32)'),
+ array(Schema::TYPE_STRING . ' CHECK (value LIKE "test%")', 'varchar(255) CHECK (value LIKE "test%")'),
+ array(Schema::TYPE_STRING . '(32) CHECK (value LIKE "test%")', 'varchar(32) CHECK (value LIKE "test%")'),
+ array(Schema::TYPE_STRING . ' NOT NULL', 'varchar(255) NOT NULL'),
+ array(Schema::TYPE_TEXT, 'varchar'),
+ array(Schema::TYPE_TEXT . '(255)', 'varchar'),
+ array(Schema::TYPE_TEXT . ' CHECK (value LIKE "test%")', 'varchar CHECK (value LIKE "test%")'),
+ array(Schema::TYPE_TEXT . '(255) CHECK (value LIKE "test%")', 'varchar CHECK (value LIKE "test%")'),
+ array(Schema::TYPE_TEXT . ' NOT NULL', 'varchar NOT NULL'),
+ array(Schema::TYPE_TEXT . '(255) NOT NULL', 'varchar NOT NULL'),
+ array(Schema::TYPE_SMALLINT, 'smallint'),
+ array(Schema::TYPE_SMALLINT . '(8)', 'smallint'),
+ array(Schema::TYPE_INTEGER, 'int'),
+ array(Schema::TYPE_INTEGER . '(8)', 'int'),
+ array(Schema::TYPE_INTEGER . ' CHECK (value > 5)', 'int CHECK (value > 5)'),
+ array(Schema::TYPE_INTEGER . '(8) CHECK (value > 5)', 'int CHECK (value > 5)'),
+ array(Schema::TYPE_INTEGER . ' NOT NULL', 'int NOT NULL'),
+ array(Schema::TYPE_BIGINT, 'bigint'),
+ array(Schema::TYPE_BIGINT . '(8)', 'bigint'),
+ array(Schema::TYPE_BIGINT . ' CHECK (value > 5)', 'bigint CHECK (value > 5)'),
+ array(Schema::TYPE_BIGINT . '(8) CHECK (value > 5)', 'bigint CHECK (value > 5)'),
+ array(Schema::TYPE_BIGINT . ' NOT NULL', 'bigint NOT NULL'),
+ array(Schema::TYPE_FLOAT, 'float(7)'),
+ array(Schema::TYPE_FLOAT . '(16)', 'float(16)'),
+ array(Schema::TYPE_FLOAT . ' CHECK (value > 5.6)', 'float(7) CHECK (value > 5.6)'),
+ array(Schema::TYPE_FLOAT . '(16) CHECK (value > 5.6)', 'float(16) CHECK (value > 5.6)'),
+ array(Schema::TYPE_FLOAT . ' NOT NULL', 'float(7) NOT NULL'),
+ array(Schema::TYPE_DECIMAL, 'decimal(10,0)'),
+ array(Schema::TYPE_DECIMAL . '(12,4)', 'decimal(12,4)'),
+ array(Schema::TYPE_DECIMAL . ' CHECK (value > 5.6)', 'decimal(10,0) CHECK (value > 5.6)'),
+ array(Schema::TYPE_DECIMAL . '(12,4) CHECK (value > 5.6)', 'decimal(12,4) CHECK (value > 5.6)'),
+ array(Schema::TYPE_DECIMAL . ' NOT NULL', 'decimal(10,0) NOT NULL'),
+ array(Schema::TYPE_DATETIME, 'datetime'),
+ array(Schema::TYPE_DATETIME . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "datetime CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"),
+ array(Schema::TYPE_DATETIME . ' NOT NULL', 'datetime NOT NULL'),
+ array(Schema::TYPE_TIMESTAMP, 'timestamp'),
+ array(Schema::TYPE_TIMESTAMP . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "timestamp CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"),
+ array(Schema::TYPE_TIMESTAMP . ' NOT NULL', 'timestamp NOT NULL'),
+ array(Schema::TYPE_TIME, 'time'),
+ array(Schema::TYPE_TIME . " CHECK(value BETWEEN '12:00:00' AND '13:01:01')", "time CHECK(value BETWEEN '12:00:00' AND '13:01:01')"),
+ array(Schema::TYPE_TIME . ' NOT NULL', 'time NOT NULL'),
+ array(Schema::TYPE_DATE, 'date'),
+ array(Schema::TYPE_DATE . " CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')", "date CHECK(value BETWEEN '2011-01-01' AND '2013-01-01')"),
+ array(Schema::TYPE_DATE . ' NOT NULL', 'date NOT NULL'),
+ array(Schema::TYPE_BINARY, 'blob'),
+ array(Schema::TYPE_BOOLEAN, 'smallint'),
+ array(Schema::TYPE_BOOLEAN . ' NOT NULL DEFAULT 1', 'smallint NOT NULL DEFAULT 1'),
+ array(Schema::TYPE_MONEY, 'decimal(19,4)'),
+ array(Schema::TYPE_MONEY . '(16,2)', 'decimal(16,2)'),
+ array(Schema::TYPE_MONEY . ' CHECK (value > 0.0)', 'decimal(19,4) CHECK (value > 0.0)'),
+ array(Schema::TYPE_MONEY . '(16,2) CHECK (value > 0.0)', 'decimal(16,2) CHECK (value > 0.0)'),
+ array(Schema::TYPE_MONEY . ' NOT NULL', 'decimal(19,4) NOT NULL'),
+ );
+ }
+
+}
diff --git a/tests/unit/framework/db/cubrid/CubridQueryTest.php b/tests/unit/framework/db/cubrid/CubridQueryTest.php
new file mode 100644
index 0000000..b7c9009
--- /dev/null
+++ b/tests/unit/framework/db/cubrid/CubridQueryTest.php
@@ -0,0 +1,13 @@
+driverName = 'sqlsrv';
- parent::setUp();
- }
+ protected $driverName = 'sqlsrv';
}
diff --git a/tests/unit/framework/db/mssql/MssqlCommandTest.php b/tests/unit/framework/db/mssql/MssqlCommandTest.php
index e27fcee..86f7f45 100644
--- a/tests/unit/framework/db/mssql/MssqlCommandTest.php
+++ b/tests/unit/framework/db/mssql/MssqlCommandTest.php
@@ -4,13 +4,13 @@ namespace yiiunit\framework\db\mssql;
use yiiunit\framework\db\CommandTest;
+/**
+ * @group db
+ * @group mssql
+ */
class MssqlCommandTest extends CommandTest
{
- public function setUp()
- {
- $this->driverName = 'sqlsrv';
- parent::setUp();
- }
+ protected $driverName = 'sqlsrv';
public function testAutoQuoting()
{
diff --git a/tests/unit/framework/db/mssql/MssqlConnectionTest.php b/tests/unit/framework/db/mssql/MssqlConnectionTest.php
index 7bbaae7..6531f83 100644
--- a/tests/unit/framework/db/mssql/MssqlConnectionTest.php
+++ b/tests/unit/framework/db/mssql/MssqlConnectionTest.php
@@ -4,13 +4,13 @@ namespace yiiunit\framework\db\mssql;
use yiiunit\framework\db\ConnectionTest;
+/**
+ * @group db
+ * @group mssql
+ */
class MssqlConnectionTest extends ConnectionTest
{
- public function setUp()
- {
- $this->driverName = 'sqlsrv';
- parent::setUp();
- }
+ protected $driverName = 'sqlsrv';
public function testQuoteValue()
{
diff --git a/tests/unit/framework/db/mssql/MssqlQueryTest.php b/tests/unit/framework/db/mssql/MssqlQueryTest.php
index 4f37c14..a2cb019 100644
--- a/tests/unit/framework/db/mssql/MssqlQueryTest.php
+++ b/tests/unit/framework/db/mssql/MssqlQueryTest.php
@@ -4,11 +4,11 @@ namespace yiiunit\framework\db\mssql;
use yiiunit\framework\db\QueryTest;
+/**
+ * @group db
+ * @group mssql
+ */
class MssqlQueryTest extends QueryTest
{
- public function setUp()
- {
- $this->driverName = 'sqlsrv';
- parent::setUp();
- }
+ protected $driverName = 'sqlsrv';
}
diff --git a/tests/unit/framework/db/pgsql/PostgreSQLActiveRecordTest.php b/tests/unit/framework/db/pgsql/PostgreSQLActiveRecordTest.php
index 2836223..1fffad7 100644
--- a/tests/unit/framework/db/pgsql/PostgreSQLActiveRecordTest.php
+++ b/tests/unit/framework/db/pgsql/PostgreSQLActiveRecordTest.php
@@ -4,11 +4,11 @@ namespace yiiunit\framework\db\pgsql;
use yiiunit\framework\db\ActiveRecordTest;
+/**
+ * @group db
+ * @group pgsql
+ */
class PostgreSQLActiveRecordTest extends ActiveRecordTest
{
- protected function setUp()
- {
- $this->driverName = 'pgsql';
- parent::setUp();
- }
+ protected $driverName = 'pgsql';
}
diff --git a/tests/unit/framework/db/pgsql/PostgreSQLConnectionTest.php b/tests/unit/framework/db/pgsql/PostgreSQLConnectionTest.php
index 7ac65c5..26ac0e0 100644
--- a/tests/unit/framework/db/pgsql/PostgreSQLConnectionTest.php
+++ b/tests/unit/framework/db/pgsql/PostgreSQLConnectionTest.php
@@ -3,13 +3,13 @@ namespace yiiunit\framework\db\pgsql;
use yiiunit\framework\db\ConnectionTest;
+/**
+ * @group db
+ * @group pgsql
+ */
class PostgreSQLConnectionTest extends ConnectionTest
{
- public function setUp()
- {
- $this->driverName = 'pgsql';
- parent::setUp();
- }
+ protected $driverName = 'pgsql';
public function testConnection()
{
diff --git a/tests/unit/framework/db/pgsql/PostgreSQLQueryBuilderTest.php b/tests/unit/framework/db/pgsql/PostgreSQLQueryBuilderTest.php
index 7c31190..3ef329e 100644
--- a/tests/unit/framework/db/pgsql/PostgreSQLQueryBuilderTest.php
+++ b/tests/unit/framework/db/pgsql/PostgreSQLQueryBuilderTest.php
@@ -2,22 +2,24 @@
namespace yiiunit\framework\db\pgsql;
-use yii\base\NotSupportedException;
use yii\db\pgsql\Schema;
use yiiunit\framework\db\QueryBuilderTest;
+/**
+ * @group db
+ * @group pgsql
+ */
class PostgreSQLQueryBuilderTest extends QueryBuilderTest
{
-
public $driverName = 'pgsql';
public function columnTypes()
{
return array(
- array(Schema::TYPE_PK, 'serial not null primary key'),
- array(Schema::TYPE_PK . '(8)', 'serial not null primary key'),
- array(Schema::TYPE_PK . ' CHECK (value > 5)', 'serial not null primary key CHECK (value > 5)'),
- array(Schema::TYPE_PK . '(8) CHECK (value > 5)', 'serial not null primary key CHECK (value > 5)'),
+ array(Schema::TYPE_PK, 'serial NOT NULL PRIMARY KEY'),
+ array(Schema::TYPE_PK . '(8)', 'serial NOT NULL PRIMARY KEY'),
+ array(Schema::TYPE_PK . ' CHECK (value > 5)', 'serial NOT NULL PRIMARY KEY CHECK (value > 5)'),
+ array(Schema::TYPE_PK . '(8) CHECK (value > 5)', 'serial NOT NULL PRIMARY KEY CHECK (value > 5)'),
array(Schema::TYPE_STRING, 'varchar(255)'),
array(Schema::TYPE_STRING . '(32)', 'varchar(32)'),
array(Schema::TYPE_STRING . ' CHECK (value LIKE "test%")', 'varchar(255) CHECK (value LIKE "test%")'),
diff --git a/tests/unit/framework/db/sqlite/SqliteActiveRecordTest.php b/tests/unit/framework/db/sqlite/SqliteActiveRecordTest.php
index 2e76162..a689e5d 100644
--- a/tests/unit/framework/db/sqlite/SqliteActiveRecordTest.php
+++ b/tests/unit/framework/db/sqlite/SqliteActiveRecordTest.php
@@ -3,11 +3,11 @@ namespace yiiunit\framework\db\sqlite;
use yiiunit\framework\db\ActiveRecordTest;
+/**
+ * @group db
+ * @group sqlite
+ */
class SqliteActiveRecordTest extends ActiveRecordTest
{
- protected function setUp()
- {
- $this->driverName = 'sqlite';
- parent::setUp();
- }
+ protected $driverName = 'sqlite';
}
diff --git a/tests/unit/framework/db/sqlite/SqliteCommandTest.php b/tests/unit/framework/db/sqlite/SqliteCommandTest.php
index e330c7e..1f9ddc2 100644
--- a/tests/unit/framework/db/sqlite/SqliteCommandTest.php
+++ b/tests/unit/framework/db/sqlite/SqliteCommandTest.php
@@ -3,13 +3,13 @@ namespace yiiunit\framework\db\sqlite;
use yiiunit\framework\db\CommandTest;
+/**
+ * @group db
+ * @group sqlite
+ */
class SqliteCommandTest extends CommandTest
{
- protected function setUp()
- {
- $this->driverName = 'sqlite';
- parent::setUp();
- }
+ protected $driverName = 'sqlite';
public function testAutoQuoting()
{
diff --git a/tests/unit/framework/db/sqlite/SqliteConnectionTest.php b/tests/unit/framework/db/sqlite/SqliteConnectionTest.php
index 2065200..e1a2961 100644
--- a/tests/unit/framework/db/sqlite/SqliteConnectionTest.php
+++ b/tests/unit/framework/db/sqlite/SqliteConnectionTest.php
@@ -3,13 +3,13 @@ namespace yiiunit\framework\db\sqlite;
use yiiunit\framework\db\ConnectionTest;
+/**
+ * @group db
+ * @group sqlite
+ */
class SqliteConnectionTest extends ConnectionTest
{
- protected function setUp()
- {
- $this->driverName = 'sqlite';
- parent::setUp();
- }
+ protected $driverName = 'sqlite';
public function testConstruct()
{
diff --git a/tests/unit/framework/db/sqlite/SqliteQueryBuilderTest.php b/tests/unit/framework/db/sqlite/SqliteQueryBuilderTest.php
index 2f6b164..b20acad 100644
--- a/tests/unit/framework/db/sqlite/SqliteQueryBuilderTest.php
+++ b/tests/unit/framework/db/sqlite/SqliteQueryBuilderTest.php
@@ -2,13 +2,16 @@
namespace yiiunit\framework\db\sqlite;
-use yii\base\NotSupportedException;
use yii\db\sqlite\Schema;
use yiiunit\framework\db\QueryBuilderTest;
+/**
+ * @group db
+ * @group sqlite
+ */
class SqliteQueryBuilderTest extends QueryBuilderTest
{
- public $driverName = 'sqlite';
+ protected $driverName = 'sqlite';
public function columnTypes()
{
@@ -73,9 +76,9 @@ class SqliteQueryBuilderTest extends QueryBuilderTest
);
}
- public function testAddDropPrimayKey()
+ public function testAddDropPrimaryKey()
{
$this->setExpectedException('yii\base\NotSupportedException');
- parent::testAddDropPrimayKey();
+ parent::testAddDropPrimaryKey();
}
}
diff --git a/tests/unit/framework/db/sqlite/SqliteQueryTest.php b/tests/unit/framework/db/sqlite/SqliteQueryTest.php
index ebbb1bb..f1db36b 100644
--- a/tests/unit/framework/db/sqlite/SqliteQueryTest.php
+++ b/tests/unit/framework/db/sqlite/SqliteQueryTest.php
@@ -3,11 +3,11 @@ namespace yiiunit\framework\db\sqlite;
use yiiunit\framework\db\QueryTest;
+/**
+ * @group db
+ * @group sqlite
+ */
class SqliteQueryTest extends QueryTest
{
- protected function setUp()
- {
- $this->driverName = 'sqlite';
- parent::setUp();
- }
+ protected $driverName = 'sqlite';
}
diff --git a/tests/unit/framework/db/sqlite/SqliteSchemaTest.php b/tests/unit/framework/db/sqlite/SqliteSchemaTest.php
new file mode 100644
index 0000000..260bb4c
--- /dev/null
+++ b/tests/unit/framework/db/sqlite/SqliteSchemaTest.php
@@ -0,0 +1,13 @@
+assertEquals(array($dirName . DIRECTORY_SEPARATOR . $fileName), $foundFiles);
}
- public function testMkdir()
+ public function testCreateDirectory()
{
$basePath = $this->testFilePath;
$dirName = $basePath . DIRECTORY_SEPARATOR . 'test_dir_level_1' . DIRECTORY_SEPARATOR . 'test_dir_level_2';
- $this->assertTrue(FileHelper::mkdir($dirName), 'FileHelper::mkdir should return true if directory was created!');
+ $this->assertTrue(FileHelper::createDirectory($dirName), 'FileHelper::createDirectory should return true if directory was created!');
$this->assertTrue(file_exists($dirName), 'Unable to create directory recursively!');
- $this->assertTrue(FileHelper::mkdir($dirName), 'FileHelper::mkdir should return true for already existing directories!');
+ $this->assertTrue(FileHelper::createDirectory($dirName), 'FileHelper::createDirectory should return true for already existing directories!');
}
public function testGetMimeTypeByExtension()
diff --git a/tests/unit/framework/helpers/HtmlTest.php b/tests/unit/framework/helpers/HtmlTest.php
index 6d725de..857f9c2 100644
--- a/tests/unit/framework/helpers/HtmlTest.php
+++ b/tests/unit/framework/helpers/HtmlTest.php
@@ -6,6 +6,9 @@ use Yii;
use yii\helpers\Html;
use yiiunit\TestCase;
+/**
+ * @group helpers
+ */
class HtmlTest extends TestCase
{
protected function setUp()
diff --git a/tests/unit/framework/helpers/InflectorTest.php b/tests/unit/framework/helpers/InflectorTest.php
index 732c10d..de7fe01 100644
--- a/tests/unit/framework/helpers/InflectorTest.php
+++ b/tests/unit/framework/helpers/InflectorTest.php
@@ -6,6 +6,9 @@ use Yii;
use yii\helpers\Inflector;
use yiiunit\TestCase;
+/**
+ * @group helpers
+ */
class InflectorTest extends TestCase
{
public function testPluralize()
diff --git a/tests/unit/framework/helpers/JsonTest.php b/tests/unit/framework/helpers/JsonTest.php
index 3734744..df2ca5f 100644
--- a/tests/unit/framework/helpers/JsonTest.php
+++ b/tests/unit/framework/helpers/JsonTest.php
@@ -7,6 +7,9 @@ use yii\helpers\Json;
use yii\test\TestCase;
use yii\web\JsExpression;
+/**
+ * @group helpers
+ */
class JsonTest extends TestCase
{
public function testEncode()
diff --git a/tests/unit/framework/helpers/StringHelperTest.php b/tests/unit/framework/helpers/StringHelperTest.php
index fe6a96c..8af731d 100644
--- a/tests/unit/framework/helpers/StringHelperTest.php
+++ b/tests/unit/framework/helpers/StringHelperTest.php
@@ -6,6 +6,7 @@ use yii\test\TestCase;
/**
* StringHelperTest
+ * @group helpers
*/
class StringHelperTest extends TestCase
{
diff --git a/tests/unit/framework/helpers/VarDumperTest.php b/tests/unit/framework/helpers/VarDumperTest.php
index 2b40b63..d41a69d 100644
--- a/tests/unit/framework/helpers/VarDumperTest.php
+++ b/tests/unit/framework/helpers/VarDumperTest.php
@@ -4,6 +4,9 @@ namespace yiiunit\framework\helpers;
use \yii\helpers\VarDumper;
use yii\test\TestCase;
+/**
+ * @group helpers
+ */
class VarDumperTest extends TestCase
{
public function testDumpObject()
diff --git a/tests/unit/framework/i18n/FormatterTest.php b/tests/unit/framework/i18n/FormatterTest.php
index c13fff3..6966853 100644
--- a/tests/unit/framework/i18n/FormatterTest.php
+++ b/tests/unit/framework/i18n/FormatterTest.php
@@ -13,6 +13,7 @@ use yiiunit\TestCase;
/**
* @author Qiang Xue
* @since 2.0
+ * @group i18n
*/
class FormatterTest extends TestCase
{
diff --git a/tests/unit/framework/i18n/GettextMessageSourceTest.php b/tests/unit/framework/i18n/GettextMessageSourceTest.php
index 7b499f4..d039629 100644
--- a/tests/unit/framework/i18n/GettextMessageSourceTest.php
+++ b/tests/unit/framework/i18n/GettextMessageSourceTest.php
@@ -5,6 +5,9 @@ namespace yiiunit\framework\i18n;
use yii\i18n\GettextMessageSource;
use yiiunit\TestCase;
+/**
+ * @group i18n
+ */
class GettextMessageSourceTest extends TestCase
{
public function testLoadMessages()
diff --git a/tests/unit/framework/i18n/GettextMoFileTest.php b/tests/unit/framework/i18n/GettextMoFileTest.php
index 0aa22da..9b61145 100644
--- a/tests/unit/framework/i18n/GettextMoFileTest.php
+++ b/tests/unit/framework/i18n/GettextMoFileTest.php
@@ -5,6 +5,9 @@ namespace yiiunit\framework\i18n;
use yii\i18n\GettextMoFile;
use yiiunit\TestCase;
+/**
+ * @group i18n
+ */
class GettextMoFileTest extends TestCase
{
public function testLoad()
diff --git a/tests/unit/framework/i18n/GettextPoFileTest.php b/tests/unit/framework/i18n/GettextPoFileTest.php
index 8dddb40..4165b81 100644
--- a/tests/unit/framework/i18n/GettextPoFileTest.php
+++ b/tests/unit/framework/i18n/GettextPoFileTest.php
@@ -5,6 +5,9 @@ namespace yiiunit\framework\i18n;
use yii\i18n\GettextPoFile;
use yiiunit\TestCase;
+/**
+ * @group i18n
+ */
class GettextPoFileTest extends TestCase
{
public function testLoad()
diff --git a/tests/unit/framework/rbac/PhpManagerTest.php b/tests/unit/framework/rbac/PhpManagerTest.php
index b3b7c4f..8c5d366 100644
--- a/tests/unit/framework/rbac/PhpManagerTest.php
+++ b/tests/unit/framework/rbac/PhpManagerTest.php
@@ -5,6 +5,9 @@ namespace yiiunit\framework\rbac;
use Yii;
use yii\rbac\PhpManager;
+/**
+ * @group rbac
+ */
class PhpManagerTest extends ManagerTestCase
{
protected function setUp()
diff --git a/tests/unit/framework/requirements/YiiRequirementCheckerTest.php b/tests/unit/framework/requirements/YiiRequirementCheckerTest.php
index 7554729..652d003 100644
--- a/tests/unit/framework/requirements/YiiRequirementCheckerTest.php
+++ b/tests/unit/framework/requirements/YiiRequirementCheckerTest.php
@@ -7,6 +7,7 @@ use yiiunit\TestCase;
/**
* Test case for [[YiiRequirementChecker]].
* @see YiiRequirementChecker
+ * @group requirements
*/
class YiiRequirementCheckerTest extends TestCase
{
diff --git a/tests/unit/framework/validators/EmailValidatorTest.php b/tests/unit/framework/validators/EmailValidatorTest.php
index 5807aed..b33a809 100644
--- a/tests/unit/framework/validators/EmailValidatorTest.php
+++ b/tests/unit/framework/validators/EmailValidatorTest.php
@@ -6,6 +6,7 @@ use yiiunit\TestCase;
/**
* EmailValidatorTest
+ * @group validators
*/
class EmailValidatorTest extends TestCase
{
diff --git a/tests/unit/framework/web/ResponseTest.php b/tests/unit/framework/web/ResponseTest.php
index 41ed939..2a9b4bf 100644
--- a/tests/unit/framework/web/ResponseTest.php
+++ b/tests/unit/framework/web/ResponseTest.php
@@ -13,6 +13,9 @@ class MockResponse extends \yii\web\Response
}
}
+/**
+ * @group web
+ */
class ResponseTest extends \yiiunit\TestCase
{
/**
diff --git a/tests/unit/framework/web/UrlManagerTest.php b/tests/unit/framework/web/UrlManagerTest.php
index efa6695..a77a66d 100644
--- a/tests/unit/framework/web/UrlManagerTest.php
+++ b/tests/unit/framework/web/UrlManagerTest.php
@@ -5,6 +5,9 @@ use yii\web\Request;
use yii\web\UrlManager;
use yiiunit\TestCase;
+/**
+ * @group web
+ */
class UrlManagerTest extends TestCase
{
protected function setUp()
diff --git a/tests/unit/framework/web/UrlRuleTest.php b/tests/unit/framework/web/UrlRuleTest.php
index d67dc58..0a0def4 100644
--- a/tests/unit/framework/web/UrlRuleTest.php
+++ b/tests/unit/framework/web/UrlRuleTest.php
@@ -7,6 +7,9 @@ use yii\web\UrlRule;
use yii\web\Request;
use yiiunit\TestCase;
+/**
+ * @group web
+ */
class UrlRuleTest extends TestCase
{
public function testCreateUrl()
diff --git a/tests/unit/framework/web/XmlResponseFormatterTest.php b/tests/unit/framework/web/XmlResponseFormatterTest.php
index 590caef..e97962a 100644
--- a/tests/unit/framework/web/XmlResponseFormatterTest.php
+++ b/tests/unit/framework/web/XmlResponseFormatterTest.php
@@ -26,6 +26,8 @@ class Post extends Object
/**
* @author Qiang Xue
* @since 2.0
+ *
+ * @group web
*/
class XmlResponseFormatterTest extends \yiiunit\TestCase
{
diff --git a/tests/unit/framework/widgets/SpacelessTest.php b/tests/unit/framework/widgets/SpacelessTest.php
index 6b2cf45..00f5a96 100644
--- a/tests/unit/framework/widgets/SpacelessTest.php
+++ b/tests/unit/framework/widgets/SpacelessTest.php
@@ -4,6 +4,9 @@ namespace yiiunit\framework\widgets;
use yii\widgets\Spaceless;
+/**
+ * @group widgets
+ */
class SpacelessTest extends \yiiunit\TestCase
{
public function testWidget()