+
echo DetailView::widget(array(
'model' => $model,
diff --git a/framework/yii/grid/DataColumn.php b/framework/yii/grid/DataColumn.php
index 295dece..4ebbb8f 100644
--- a/framework/yii/grid/DataColumn.php
+++ b/framework/yii/grid/DataColumn.php
@@ -68,6 +68,12 @@ class DataColumn extends Column
* - If you don't want a filter for this data column, set this value to be false.
*/
public $filter;
+ /**
+ * @var array the HTML attributes for the filter input fields. This property is used in combination with
+ * the [[filter]] property. When [[filter]] is not set or is an array, this property will be used to
+ * render the HTML attributes for the generated filter input fields.
+ */
+ public $filterInputOptions = array('class' => 'form-control');
protected function renderHeaderCellContent()
@@ -111,9 +117,10 @@ class DataColumn extends Column
return $this->filter;
} elseif ($this->filter !== false && $this->grid->filterModel instanceof Model && $this->attribute !== null) {
if (is_array($this->filter)) {
- return Html::activeDropDownList($this->grid->filterModel, $this->attribute, $this->filter, array('prompt' => ''));
+ $options = array_merge(array('prompt' => ''), $this->filterInputOptions);
+ return Html::activeDropDownList($this->grid->filterModel, $this->attribute, $this->filter, $options);
} else {
- return Html::activeTextInput($this->grid->filterModel, $this->attribute);
+ return Html::activeTextInput($this->grid->filterModel, $this->attribute, $this->filterInputOptions);
}
} else {
return parent::renderFilterCellContent();
From d9b256d73455ca771ca985efa7b23d7bfa8b7312 Mon Sep 17 00:00:00 2001
From: Jin Hu
Date: Thu, 26 Sep 2013 20:29:59 +0800
Subject: [PATCH 029/613] Fixed pagination not working before data loaded
---
framework/yii/data/DataProvider.php | 1 +
tests/unit/framework/data/ActiveDataProviderTest.php | 17 +++++++++++++++++
2 files changed, 18 insertions(+)
diff --git a/framework/yii/data/DataProvider.php b/framework/yii/data/DataProvider.php
index b29f616..d75be6f 100644
--- a/framework/yii/data/DataProvider.php
+++ b/framework/yii/data/DataProvider.php
@@ -48,6 +48,7 @@ abstract class DataProvider extends Component implements DataProviderInterface
if ($this->id !== null) {
$this->_pagination->pageVar = $this->id . '-page';
}
+ $this->_pagination->totalCount = $this->getTotalCount();
}
return $this->_pagination;
}
diff --git a/tests/unit/framework/data/ActiveDataProviderTest.php b/tests/unit/framework/data/ActiveDataProviderTest.php
index 3f65ebb..79c0a39 100644
--- a/tests/unit/framework/data/ActiveDataProviderTest.php
+++ b/tests/unit/framework/data/ActiveDataProviderTest.php
@@ -85,4 +85,21 @@ class ActiveDataProviderTest extends DatabaseTestCase
$provider->refresh();
$this->assertEquals(2, count($provider->getModels()));
}
+
+ public function testPaginationBeforeModels()
+ {
+ $query = new Query;
+ $provider = new ActiveDataProvider(array(
+ 'db' => $this->getConnection(),
+ 'query' => $query->from('tbl_order')->orderBy('id'),
+ ));
+ $pagination = $provider->getPagination();
+ $this->assertEquals(1, $pagination->getPageCount());
+ $this->assertCount(3, $provider->getModels());
+
+ $provider->getPagination()->pageSize = 2;
+ $this->assertEquals(3, count($provider->getModels()));
+ $provider->refresh();
+ $this->assertEquals(2, count($provider->getModels()));
+ }
}
From b7948e48406f21a059431a619c901b3cd88a8ec5 Mon Sep 17 00:00:00 2001
From: Jin Hu
Date: Thu, 26 Sep 2013 23:35:02 +0800
Subject: [PATCH 030/613] Removed unnecessary lines
---
framework/yii/data/ActiveDataProvider.php | 1 -
framework/yii/data/ArrayDataProvider.php | 1 -
2 files changed, 2 deletions(-)
diff --git a/framework/yii/data/ActiveDataProvider.php b/framework/yii/data/ActiveDataProvider.php
index aaf71b2..2fe0efb 100644
--- a/framework/yii/data/ActiveDataProvider.php
+++ b/framework/yii/data/ActiveDataProvider.php
@@ -156,7 +156,6 @@ class ActiveDataProvider extends DataProvider
throw new InvalidConfigException('The "query" property must be an instance of Query or its subclass.');
}
if (($pagination = $this->getPagination()) !== false) {
- $pagination->totalCount = $this->getTotalCount();
$this->query->limit($pagination->getLimit())->offset($pagination->getOffset());
}
if (($sort = $this->getSort()) !== false) {
diff --git a/framework/yii/data/ArrayDataProvider.php b/framework/yii/data/ArrayDataProvider.php
index d6eaca7..9534803 100644
--- a/framework/yii/data/ArrayDataProvider.php
+++ b/framework/yii/data/ArrayDataProvider.php
@@ -114,7 +114,6 @@ class ArrayDataProvider extends DataProvider
}
if (($pagination = $this->getPagination()) !== false) {
- $pagination->totalCount = $this->getTotalCount();
$models = array_slice($models, $pagination->getOffset(), $pagination->getLimit());
}
From 45778a4bd7037e2797f29bc80d1c09cedbefffeb Mon Sep 17 00:00:00 2001
From: Alexander Makarov
Date: Fri, 27 Sep 2013 20:36:47 +0400
Subject: [PATCH 031/613] Added ->send() to redirect phpdoc example
---
framework/yii/web/Response.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/framework/yii/web/Response.php b/framework/yii/web/Response.php
index e6505fd..b353e7c 100644
--- a/framework/yii/web/Response.php
+++ b/framework/yii/web/Response.php
@@ -581,7 +581,7 @@ class Response extends \yii\base\Response
* In a controller action you may use this method like this:
*
* ~~~
- * return Yii::$app->getResponse()->redirect($url);
+ * return Yii::$app->getResponse()->redirect($url)->send();
* ~~~
*
* @param string|array $url the URL to be redirected to. This can be in one of the following formats:
From 3e94fb479f1bb8cfe8669064e0a1489e3a508d88 Mon Sep 17 00:00:00 2001
From: Alexander Makarov
Date: Fri, 27 Sep 2013 20:51:08 +0400
Subject: [PATCH 032/613] Fixed phpdoc
---
framework/yii/helpers/Console.php | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/framework/yii/helpers/Console.php b/framework/yii/helpers/Console.php
index eeadcbc..c0b7b32 100644
--- a/framework/yii/helpers/Console.php
+++ b/framework/yii/helpers/Console.php
@@ -8,11 +8,8 @@
namespace yii\helpers;
/**
- * TODO adjust phpdoc
- * Console View is the base class for console view components
- *
- * A console view provides functionality to create rich console application by allowing to format output
- * by adding color and font style to it.
+ * Console helper provides useful methods for command line related tasks such as getting input or formatting and coloring
+ * output.
*
* @author Carsten Brandt
* @since 2.0
From 907d24fb9e07b2a4fdf344a76e984cfb7f734d97 Mon Sep 17 00:00:00 2001
From: Alexander Makarov
Date: Sat, 28 Sep 2013 01:01:49 +0400
Subject: [PATCH 033/613] Advanced application: fixed console return codes
---
apps/advanced/environments/dev/yii | 3 ++-
apps/advanced/environments/prod/yii | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/apps/advanced/environments/dev/yii b/apps/advanced/environments/dev/yii
index 9a257d7..e7d5f6c 100644
--- a/apps/advanced/environments/dev/yii
+++ b/apps/advanced/environments/dev/yii
@@ -24,4 +24,5 @@ $config = yii\helpers\ArrayHelper::merge(
);
$application = new yii\console\Application($config);
-return $application->run();
+$exitCode = $application->run();
+exit($exitCode);
diff --git a/apps/advanced/environments/prod/yii b/apps/advanced/environments/prod/yii
index 7f24a70..9e13eb2 100644
--- a/apps/advanced/environments/prod/yii
+++ b/apps/advanced/environments/prod/yii
@@ -24,4 +24,5 @@ $config = yii\helpers\ArrayHelper::merge(
);
$application = new yii\console\Application($config);
-return $application->run();
+$exitCode = $application->run();
+exit($exitCode);
From 4ab2e986c6ccf6f1d89db1971e353b0c32d8df6d Mon Sep 17 00:00:00 2001
From: Alexander Makarov
Date: Sat, 28 Sep 2013 01:10:38 +0400
Subject: [PATCH 034/613] Advanced application: init script can now be executed
in non-interactive input mode
Usage:
init --env=Development
init --env=Production
---
apps/advanced/README.md | 3 ++-
apps/advanced/init | 72 ++++++++++++++++++++++++++++++++++++++-----------
2 files changed, 59 insertions(+), 16 deletions(-)
diff --git a/apps/advanced/README.md b/apps/advanced/README.md
index 6860c11..cdc10eb 100644
--- a/apps/advanced/README.md
+++ b/apps/advanced/README.md
@@ -103,7 +103,8 @@ GETTING STARTED
After you install the application, you have to conduct the following steps to initialize
the installed application. You only need to do these once for all.
-1. Execute the `init` command and select `dev` as environment.
+1. Execute the `init` command and select `dev` as environment. Alternatively you can execute it as `init --env=Development`
+or `init --env=Production`.
2. Create a new database. It is assumed that MySQL InnoDB is used. If not, adjust `console/migrations/m130524_201442_init.php`.
3. In `common/config/params.php` set your database details in `components.db` values.
diff --git a/apps/advanced/init b/apps/advanced/init
index 17ed854..3a8f6a6 100755
--- a/apps/advanced/init
+++ b/apps/advanced/init
@@ -1,27 +1,49 @@
#!/usr/bin/env php
$name) {
- echo " [$i] $name\n";
+echo "Yii Application Initialization Tool v1.0\n\n";
+
+$envName = null;
+if (empty($params['env'])) {
+ echo "Which environment do you want the application to be initialized in?\n\n";
+ foreach ($envNames as $i => $name) {
+ echo " [$i] $name\n";
+ }
+ echo "\n Your choice [0-" . (count($envs) - 1) . ', or "q" to quit] ';
+ $answer = trim(fgets(STDIN));
+
+ if (!ctype_digit($answer) || !in_array($answer, range(0, count($envs) - 1))) {
+ echo "\n Quit initialization.\n";
+ exit(1);
+ }
+
+ if(isset($envNames[$answer])) {
+ $envName = $envNames[$answer];
+ }
+}
+else {
+ $envName = $params['env'];
}
-echo "\n Your choice [0-" . (count($envs) - 1) . ', or "q" to quit] ';
-$answer = trim(fgets(STDIN));
-if (!ctype_digit($answer) || !isset($envNames[$answer])) {
- echo "\n Quit initialization.\n";
- return;
+
+if (!in_array($envName, $envNames)) {
+ $envsList = implode(', ', $envNames);
+ echo "\n $envName is not a valid environment. Try one of the following: $envsList. \n";
+ exit(2);
}
-$env = $envs[$envNames[$answer]];
-echo "\n Initialize the application under '{$envNames[$answer]}' environment? [yes|no] ";
-$answer = trim(fgets(STDIN));
-if (strncasecmp($answer, 'y', 1)) {
- echo "\n Quit initialization.\n";
- return;
+$env = $envs[$envName];
+
+if (empty($params['env'])) {
+ echo "\n Initialize the application under '{$envNames[$answer]}' environment? [yes|no] ";
+ $answer = trim(fgets(STDIN));
+ if (strncasecmp($answer, 'y', 1)) {
+ echo "\n Quit initialization.\n";
+ exit(1);
+ }
}
echo "\n Start initialization ...\n\n";
@@ -110,3 +132,23 @@ function copyFile($root, $source, $target, &$all)
file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source));
return true;
}
+
+function getParams()
+{
+ $rawParams = array();
+ if (isset($_SERVER['argv'])) {
+ $rawParams = $_SERVER['argv'];
+ array_shift($rawParams);
+ }
+
+ $params = array();
+ foreach ($rawParams as $param) {
+ if (preg_match('/^--(\w+)(=(.*))?$/', $param, $matches)) {
+ $name = $matches[1];
+ $params[$name] = isset($matches[3]) ? $matches[3] : true;
+ } else {
+ $params[] = $param;
+ }
+ }
+ return $params;
+}
From c4354d6be688f6323980c1d37c84fcfee86dfbc7 Mon Sep 17 00:00:00 2001
From: Alexander Makarov
Date: Sat, 28 Sep 2013 01:14:19 +0400
Subject: [PATCH 035/613] Advanced application: init is now automatically
called when installing via Composer
---
apps/advanced/composer.json | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/apps/advanced/composer.json b/apps/advanced/composer.json
index 2d5b987..4c0fced 100644
--- a/apps/advanced/composer.json
+++ b/apps/advanced/composer.json
@@ -20,7 +20,8 @@
},
"scripts": {
"post-create-project-cmd": [
- "yii\\composer\\InstallHandler::setPermissions"
+ "yii\\composer\\InstallHandler::setPermissions",
+ "./init"
]
},
"extra": {
From abd775e5a58ee641866d1aae201445faa78222a8 Mon Sep 17 00:00:00 2001
From: Alexander Makarov
Date: Sat, 28 Sep 2013 01:27:00 +0400
Subject: [PATCH 036/613] fixed typos
---
extensions/composer/README.md | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/extensions/composer/README.md b/extensions/composer/README.md
index 986fc6c..853d3c3 100644
--- a/extensions/composer/README.md
+++ b/extensions/composer/README.md
@@ -17,11 +17,11 @@ This is the yii2 composer installer.
Installation
------------
-This extension offers you enhanced composer handling for your yii2-project. It will therefor require you to use composer.
+This extension offers you enhanced Composer handling for your yii2-project. It will therefore require you to use Composer.
-`
+```
php composer.phar require yiisoft/yii2-composer "*"
-`
+```
*Note: You might have to run `php composer.phar selfupdate` before using this extension.*
@@ -29,9 +29,9 @@ php composer.phar require yiisoft/yii2-composer "*"
Usage & Documentation
---------------------
-This extensions allows you to hook to certain composer events and prepare your yii2-app for usage.
+This extension allows you to hook to certain composer events and automate preparing your Yii2 application for further usage.
-After the package is installed, the composer.json file has to be modified to enable this extension.
+After the package is installed, the `composer.json` file has to be modified to enable this extension.
To see it in action take a look at the example apps in the repository:
From f8ddb3d7be0c14ae362a1637baa9fee21042f3d5 Mon Sep 17 00:00:00 2001
From: Alexander Makarov
Date: Sat, 28 Sep 2013 01:27:23 +0400
Subject: [PATCH 037/613] Advanced application: added applying migrations to
readme
---
apps/advanced/README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/apps/advanced/README.md b/apps/advanced/README.md
index cdc10eb..3903532 100644
--- a/apps/advanced/README.md
+++ b/apps/advanced/README.md
@@ -107,6 +107,7 @@ the installed application. You only need to do these once for all.
or `init --env=Production`.
2. Create a new database. It is assumed that MySQL InnoDB is used. If not, adjust `console/migrations/m130524_201442_init.php`.
3. In `common/config/params.php` set your database details in `components.db` values.
+4. Apply migrations with `yii migrate`.
Now you should be able to access:
From 76cab3ea6449ef90bbfade7683b1c83aa2336a35 Mon Sep 17 00:00:00 2001
From: Alexander Makarov
Date: Sat, 28 Sep 2013 02:01:06 +0400
Subject: [PATCH 038/613] Renamed base helper classes
---
framework/yii/classes.php | 22 +-
framework/yii/helpers/AbstractArrayHelper.php | 451 +++++++
framework/yii/helpers/AbstractConsole.php | 835 +++++++++++++
framework/yii/helpers/AbstractFileHelper.php | 329 +++++
framework/yii/helpers/AbstractHtml.php | 1599 ++++++++++++++++++++++++
framework/yii/helpers/AbstractHtmlPurifier.php | 34 +
framework/yii/helpers/AbstractInflector.php | 480 +++++++
framework/yii/helpers/AbstractJson.php | 112 ++
framework/yii/helpers/AbstractMarkdown.php | 44 +
framework/yii/helpers/AbstractSecurity.php | 285 +++++
framework/yii/helpers/AbstractStringHelper.php | 138 ++
framework/yii/helpers/AbstractVarDumper.php | 127 ++
framework/yii/helpers/ArrayHelper.php | 2 +-
framework/yii/helpers/ArrayHelperBase.php | 451 -------
framework/yii/helpers/Console.php | 2 +-
framework/yii/helpers/ConsoleBase.php | 835 -------------
framework/yii/helpers/FileHelper.php | 2 +-
framework/yii/helpers/FileHelperBase.php | 329 -----
framework/yii/helpers/Html.php | 2 +-
framework/yii/helpers/HtmlBase.php | 1599 ------------------------
framework/yii/helpers/HtmlPurifier.php | 2 +-
framework/yii/helpers/HtmlPurifierBase.php | 34 -
framework/yii/helpers/Inflector.php | 2 +-
framework/yii/helpers/InflectorBase.php | 480 -------
framework/yii/helpers/Json.php | 2 +-
framework/yii/helpers/JsonBase.php | 112 --
framework/yii/helpers/Markdown.php | 2 +-
framework/yii/helpers/MarkdownBase.php | 44 -
framework/yii/helpers/Security.php | 2 +-
framework/yii/helpers/SecurityBase.php | 285 -----
framework/yii/helpers/StringHelper.php | 2 +-
framework/yii/helpers/StringHelperBase.php | 138 --
framework/yii/helpers/VarDumper.php | 2 +-
framework/yii/helpers/VarDumperBase.php | 127 --
34 files changed, 4456 insertions(+), 4456 deletions(-)
create mode 100644 framework/yii/helpers/AbstractArrayHelper.php
create mode 100644 framework/yii/helpers/AbstractConsole.php
create mode 100644 framework/yii/helpers/AbstractFileHelper.php
create mode 100644 framework/yii/helpers/AbstractHtml.php
create mode 100644 framework/yii/helpers/AbstractHtmlPurifier.php
create mode 100644 framework/yii/helpers/AbstractInflector.php
create mode 100644 framework/yii/helpers/AbstractJson.php
create mode 100644 framework/yii/helpers/AbstractMarkdown.php
create mode 100644 framework/yii/helpers/AbstractSecurity.php
create mode 100644 framework/yii/helpers/AbstractStringHelper.php
create mode 100644 framework/yii/helpers/AbstractVarDumper.php
delete mode 100644 framework/yii/helpers/ArrayHelperBase.php
delete mode 100644 framework/yii/helpers/ConsoleBase.php
delete mode 100644 framework/yii/helpers/FileHelperBase.php
delete mode 100644 framework/yii/helpers/HtmlBase.php
delete mode 100644 framework/yii/helpers/HtmlPurifierBase.php
delete mode 100644 framework/yii/helpers/InflectorBase.php
delete mode 100644 framework/yii/helpers/JsonBase.php
delete mode 100644 framework/yii/helpers/MarkdownBase.php
delete mode 100644 framework/yii/helpers/SecurityBase.php
delete mode 100644 framework/yii/helpers/StringHelperBase.php
delete mode 100644 framework/yii/helpers/VarDumperBase.php
diff --git a/framework/yii/classes.php b/framework/yii/classes.php
index 40ca225..22472d7 100644
--- a/framework/yii/classes.php
+++ b/framework/yii/classes.php
@@ -125,27 +125,27 @@ return array(
'yii\grid\GridViewAsset' => YII_PATH . '/grid/GridViewAsset.php',
'yii\grid\SerialColumn' => YII_PATH . '/grid/SerialColumn.php',
'yii\helpers\ArrayHelper' => YII_PATH . '/helpers/ArrayHelper.php',
- 'yii\helpers\ArrayHelperBase' => YII_PATH . '/helpers/ArrayHelperBase.php',
+ 'yii\helpers\AbstractArrayHelper' => YII_PATH . '/helpers/AbstractArrayHelper.php',
'yii\helpers\Console' => YII_PATH . '/helpers/Console.php',
- 'yii\helpers\ConsoleBase' => YII_PATH . '/helpers/ConsoleBase.php',
+ 'yii\helpers\AbstractConsole' => YII_PATH . '/helpers/AbstractConsole.php',
'yii\helpers\FileHelper' => YII_PATH . '/helpers/FileHelper.php',
- 'yii\helpers\FileHelperBase' => YII_PATH . '/helpers/FileHelperBase.php',
+ 'yii\helpers\AbstractFileHelper' => YII_PATH . '/helpers/AbstractFileHelper.php',
'yii\helpers\Html' => YII_PATH . '/helpers/Html.php',
- 'yii\helpers\HtmlBase' => YII_PATH . '/helpers/HtmlBase.php',
+ 'yii\helpers\AbstractHtml' => YII_PATH . '/helpers/AbstractHtml.php',
'yii\helpers\HtmlPurifier' => YII_PATH . '/helpers/HtmlPurifier.php',
- 'yii\helpers\HtmlPurifierBase' => YII_PATH . '/helpers/HtmlPurifierBase.php',
+ 'yii\helpers\AbstractHtmlPurifier' => YII_PATH . '/helpers/AbstractHtmlPurifier.php',
'yii\helpers\Inflector' => YII_PATH . '/helpers/Inflector.php',
- 'yii\helpers\InflectorBase' => YII_PATH . '/helpers/InflectorBase.php',
+ 'yii\helpers\AbstractInflector' => YII_PATH . '/helpers/AbstractInflector.php',
'yii\helpers\Json' => YII_PATH . '/helpers/Json.php',
- 'yii\helpers\JsonBase' => YII_PATH . '/helpers/JsonBase.php',
+ 'yii\helpers\AbstractJson' => YII_PATH . '/helpers/AbstractJson.php',
'yii\helpers\Markdown' => YII_PATH . '/helpers/Markdown.php',
- 'yii\helpers\MarkdownBase' => YII_PATH . '/helpers/MarkdownBase.php',
+ 'yii\helpers\AbstractMarkdown' => YII_PATH . '/helpers/AbstractMarkdown.php',
'yii\helpers\Security' => YII_PATH . '/helpers/Security.php',
- 'yii\helpers\SecurityBase' => YII_PATH . '/helpers/SecurityBase.php',
+ 'yii\helpers\AbstractSecurity' => YII_PATH . '/helpers/AbstractSecurity.php',
'yii\helpers\StringHelper' => YII_PATH . '/helpers/StringHelper.php',
- 'yii\helpers\StringHelperBase' => YII_PATH . '/helpers/StringHelperBase.php',
+ 'yii\helpers\AbstractStringHelper' => YII_PATH . '/helpers/AbstractStringHelper.php',
'yii\helpers\VarDumper' => YII_PATH . '/helpers/VarDumper.php',
- 'yii\helpers\VarDumperBase' => YII_PATH . '/helpers/VarDumperBase.php',
+ 'yii\helpers\AbstractVarDumper' => YII_PATH . '/helpers/AbstractVarDumper.php',
'yii\i18n\DbMessageSource' => YII_PATH . '/i18n/DbMessageSource.php',
'yii\i18n\Formatter' => YII_PATH . '/i18n/Formatter.php',
'yii\i18n\GettextFile' => YII_PATH . '/i18n/GettextFile.php',
diff --git a/framework/yii/helpers/AbstractArrayHelper.php b/framework/yii/helpers/AbstractArrayHelper.php
new file mode 100644
index 0000000..c26c1cd
--- /dev/null
+++ b/framework/yii/helpers/AbstractArrayHelper.php
@@ -0,0 +1,451 @@
+
+ * @since 2.0
+ */
+abstract class AbstractArrayHelper
+{
+ /**
+ * Converts an object or an array of objects into an array.
+ * @param object|array $object the object to be converted into an array
+ * @param array $properties a mapping from object class names to the properties that need to put into the resulting arrays.
+ * The properties specified for each class is an array of the following format:
+ *
+ * ~~~
+ * array(
+ * 'app\models\Post' => array(
+ * 'id',
+ * 'title',
+ * // the key name in array result => property name
+ * 'createTime' => 'create_time',
+ * // the key name in array result => anonymous function
+ * 'length' => function ($post) {
+ * return strlen($post->content);
+ * },
+ * ),
+ * )
+ * ~~~
+ *
+ * The result of `ArrayHelper::toArray($post, $properties)` could be like the following:
+ *
+ * ~~~
+ * array(
+ * 'id' => 123,
+ * 'title' => 'test',
+ * 'createTime' => '2013-01-01 12:00AM',
+ * 'length' => 301,
+ * )
+ * ~~~
+ *
+ * @param boolean $recursive whether to recursively converts properties which are objects into arrays.
+ * @return array the array representation of the object
+ */
+ public static function toArray($object, $properties = array(), $recursive = true)
+ {
+ if (!empty($properties) && is_object($object)) {
+ $className = get_class($object);
+ if (!empty($properties[$className])) {
+ $result = array();
+ foreach ($properties[$className] as $key => $name) {
+ if (is_int($key)) {
+ $result[$name] = $object->$name;
+ } else {
+ $result[$key] = static::getValue($object, $name);
+ }
+ }
+ return $result;
+ }
+ }
+ if ($object instanceof Arrayable) {
+ $object = $object->toArray();
+ if (!$recursive) {
+ return $object;
+ }
+ }
+ $result = array();
+ foreach ($object as $key => $value) {
+ if ($recursive && (is_array($value) || is_object($value))) {
+ $result[$key] = static::toArray($value, true);
+ } else {
+ $result[$key] = $value;
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Merges two or more arrays into one recursively.
+ * If each array has an element with the same string key value, the latter
+ * will overwrite the former (different from array_merge_recursive).
+ * Recursive merging will be conducted if both arrays have an element of array
+ * type and are having the same key.
+ * For integer-keyed elements, the elements from the latter array will
+ * be appended to the former array.
+ * @param array $a array to be merged to
+ * @param array $b array to be merged from. You can specify additional
+ * arrays via third argument, fourth argument etc.
+ * @return array the merged array (the original arrays are not changed.)
+ */
+ public static function merge($a, $b)
+ {
+ $args = func_get_args();
+ $res = array_shift($args);
+ while (!empty($args)) {
+ $next = array_shift($args);
+ foreach ($next as $k => $v) {
+ if (is_integer($k)) {
+ isset($res[$k]) ? $res[] = $v : $res[$k] = $v;
+ } elseif (is_array($v) && isset($res[$k]) && is_array($res[$k])) {
+ $res[$k] = self::merge($res[$k], $v);
+ } else {
+ $res[$k] = $v;
+ }
+ }
+ }
+ return $res;
+ }
+
+ /**
+ * Retrieves the value of an array element or object property with the given key or property name.
+ * If the key does not exist in the array, the default value will be returned instead.
+ *
+ * Below are some usage examples,
+ *
+ * ~~~
+ * // working with array
+ * $username = \yii\helpers\ArrayHelper::getValue($_POST, 'username');
+ * // working with object
+ * $username = \yii\helpers\ArrayHelper::getValue($user, 'username');
+ * // working with anonymous function
+ * $fullName = \yii\helpers\ArrayHelper::getValue($user, function($user, $defaultValue) {
+ * return $user->firstName . ' ' . $user->lastName;
+ * });
+ * ~~~
+ *
+ * @param array|object $array array or object to extract value from
+ * @param string|\Closure $key key name of the array element, or property name of the object,
+ * 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 element if found, default value otherwise
+ */
+ public static function getValue($array, $key, $default = null)
+ {
+ if ($key instanceof \Closure) {
+ return $key($array, $default);
+ } elseif (is_array($array)) {
+ return isset($array[$key]) || array_key_exists($key, $array) ? $array[$key] : $default;
+ } else {
+ return $array->$key;
+ }
+ }
+
+ /**
+ * Removes an item from an array and returns the value. If the key does not exist in the array, the default value
+ * will be returned instead.
+ *
+ * Usage examples,
+ *
+ * ~~~
+ * // $array = array('type' => 'A', 'options' => array(1, 2));
+ * // working with array
+ * $type = \yii\helpers\ArrayHelper::remove($array, 'type');
+ * // $array content
+ * // $array = array('options' => array(1, 2));
+ * ~~~
+ *
+ * @param array $array the array to extract value from
+ * @param string $key key name of the array element
+ * @param mixed $default the default value to be returned if the specified key does not exist
+ * @return mixed|null the value of the element if found, default value otherwise
+ */
+ public static function remove(&$array, $key, $default = null)
+ {
+ if (is_array($array) && (isset($array[$key]) || array_key_exists($key, $array))) {
+ $value = $array[$key];
+ unset($array[$key]);
+ return $value;
+ }
+ return $default;
+ }
+
+ /**
+ * Indexes an array according to a specified key.
+ * The input array should be multidimensional or an array of objects.
+ *
+ * The key can be a key name of the sub-array, a property name of object, or an anonymous
+ * function which returns the key value given an array element.
+ *
+ * If a key value is null, the corresponding array element will be discarded and not put in the result.
+ *
+ * For example,
+ *
+ * ~~~
+ * $array = array(
+ * array('id' => '123', 'data' => 'abc'),
+ * array('id' => '345', 'data' => 'def'),
+ * );
+ * $result = ArrayHelper::index($array, 'id');
+ * // the result is:
+ * // array(
+ * // '123' => array('id' => '123', 'data' => 'abc'),
+ * // '345' => array('id' => '345', 'data' => 'def'),
+ * // )
+ *
+ * // using anonymous function
+ * $result = ArrayHelper::index($array, function ($element) {
+ * return $element['id'];
+ * });
+ * ~~~
+ *
+ * @param array $array the array that needs to be indexed
+ * @param string|\Closure $key the column name or anonymous function whose result will be used to index the array
+ * @return array the indexed array
+ */
+ public static function index($array, $key)
+ {
+ $result = array();
+ foreach ($array as $element) {
+ $value = static::getValue($element, $key);
+ $result[$value] = $element;
+ }
+ return $result;
+ }
+
+ /**
+ * Returns the values of a specified column in an array.
+ * The input array should be multidimensional or an array of objects.
+ *
+ * For example,
+ *
+ * ~~~
+ * $array = array(
+ * array('id' => '123', 'data' => 'abc'),
+ * array('id' => '345', 'data' => 'def'),
+ * );
+ * $result = ArrayHelper::getColumn($array, 'id');
+ * // the result is: array( '123', '345')
+ *
+ * // using anonymous function
+ * $result = ArrayHelper::getColumn($array, function ($element) {
+ * return $element['id'];
+ * });
+ * ~~~
+ *
+ * @param array $array
+ * @param string|\Closure $name
+ * @param boolean $keepKeys whether to maintain the array keys. If false, the resulting array
+ * will be re-indexed with integers.
+ * @return array the list of column values
+ */
+ public static function getColumn($array, $name, $keepKeys = true)
+ {
+ $result = array();
+ if ($keepKeys) {
+ foreach ($array as $k => $element) {
+ $result[$k] = static::getValue($element, $name);
+ }
+ } else {
+ foreach ($array as $element) {
+ $result[] = static::getValue($element, $name);
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Builds a map (key-value pairs) from a multidimensional array or an array of objects.
+ * The `$from` and `$to` parameters specify the key names or property names to set up the map.
+ * Optionally, one can further group the map according to a grouping field `$group`.
+ *
+ * For example,
+ *
+ * ~~~
+ * $array = array(
+ * array('id' => '123', 'name' => 'aaa', 'class' => 'x'),
+ * array('id' => '124', 'name' => 'bbb', 'class' => 'x'),
+ * array('id' => '345', 'name' => 'ccc', 'class' => 'y'),
+ * );
+ *
+ * $result = ArrayHelper::map($array, 'id', 'name');
+ * // the result is:
+ * // array(
+ * // '123' => 'aaa',
+ * // '124' => 'bbb',
+ * // '345' => 'ccc',
+ * // )
+ *
+ * $result = ArrayHelper::map($array, 'id', 'name', 'class');
+ * // the result is:
+ * // array(
+ * // 'x' => array(
+ * // '123' => 'aaa',
+ * // '124' => 'bbb',
+ * // ),
+ * // 'y' => array(
+ * // '345' => 'ccc',
+ * // ),
+ * // )
+ * ~~~
+ *
+ * @param array $array
+ * @param string|\Closure $from
+ * @param string|\Closure $to
+ * @param string|\Closure $group
+ * @return array
+ */
+ public static function map($array, $from, $to, $group = null)
+ {
+ $result = array();
+ foreach ($array as $element) {
+ $key = static::getValue($element, $from);
+ $value = static::getValue($element, $to);
+ if ($group !== null) {
+ $result[static::getValue($element, $group)][$key] = $value;
+ } else {
+ $result[$key] = $value;
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Sorts an array of objects or arrays (with the same structure) by one or several keys.
+ * @param array $array the array to be sorted. The array will be modified after calling this method.
+ * @param string|\Closure|array $key the key(s) to be sorted by. This refers to a key name of the sub-array
+ * elements, a property name of the objects, or an anonymous function returning the values for comparison
+ * purpose. The anonymous function signature should be: `function($item)`.
+ * To sort by multiple keys, provide an array of keys here.
+ * @param boolean|array $descending whether to sort in descending or ascending order. When
+ * sorting by multiple keys with different descending orders, use an array of descending flags.
+ * @param integer|array $sortFlag the PHP sort flag. Valid values include
+ * `SORT_REGULAR`, `SORT_NUMERIC`, `SORT_STRING` and `SORT_LOCALE_STRING`.
+ * Please refer to [PHP manual](http://php.net/manual/en/function.sort.php)
+ * for more details. When sorting by multiple keys with different sort flags, use an array of sort flags.
+ * @param boolean|array $caseSensitive whether to sort string in case-sensitive manner. This parameter
+ * is used only when `$sortFlag` is `SORT_STRING`.
+ * When sorting by multiple keys with different case sensitivities, use an array of boolean values.
+ * @throws InvalidParamException if the $descending or $sortFlag parameters do not have
+ * correct number of elements as that of $key.
+ */
+ public static function multisort(&$array, $key, $descending = false, $sortFlag = SORT_REGULAR, $caseSensitive = true)
+ {
+ $keys = is_array($key) ? $key : array($key);
+ if (empty($keys) || empty($array)) {
+ return;
+ }
+ $n = count($keys);
+ if (is_scalar($descending)) {
+ $descending = array_fill(0, $n, $descending);
+ } elseif (count($descending) !== $n) {
+ throw new InvalidParamException('The length of $descending parameter must be the same as that of $keys.');
+ }
+ if (is_scalar($sortFlag)) {
+ $sortFlag = array_fill(0, $n, $sortFlag);
+ } elseif (count($sortFlag) !== $n) {
+ throw new InvalidParamException('The length of $sortFlag parameter must be the same as that of $keys.');
+ }
+ if (is_scalar($caseSensitive)) {
+ $caseSensitive = array_fill(0, $n, $caseSensitive);
+ } elseif (count($caseSensitive) !== $n) {
+ throw new InvalidParamException('The length of $caseSensitive parameter must be the same as that of $keys.');
+ }
+ $args = array();
+ foreach ($keys as $i => $key) {
+ $flag = $sortFlag[$i];
+ $cs = $caseSensitive[$i];
+ if (!$cs && ($flag === SORT_STRING)) {
+ if (defined('SORT_FLAG_CASE')) {
+ $flag = $flag | SORT_FLAG_CASE;
+ $args[] = static::getColumn($array, $key);
+ } else {
+ $column = array();
+ foreach (static::getColumn($array, $key) as $k => $value) {
+ $column[$k] = mb_strtolower($value);
+ }
+ $args[] = $column;
+ }
+ } else {
+ $args[] = static::getColumn($array, $key);
+ }
+ $args[] = $descending[$i] ? SORT_DESC : SORT_ASC;
+ $args[] = $flag;
+ }
+ $args[] = &$array;
+ call_user_func_array('array_multisort', $args);
+ }
+
+ /**
+ * Encodes special characters in an array of strings into HTML entities.
+ * Both the array keys and values will be encoded.
+ * If a value is an array, this method will also encode it recursively.
+ * @param array $data data to be encoded
+ * @param boolean $valuesOnly whether to encode array values only. If false,
+ * both the array keys and array values will be encoded.
+ * @param string $charset the charset that the data is using. If not set,
+ * [[\yii\base\Application::charset]] will be used.
+ * @return array the encoded data
+ * @see http://www.php.net/manual/en/function.htmlspecialchars.php
+ */
+ public static function htmlEncode($data, $valuesOnly = true, $charset = null)
+ {
+ if ($charset === null) {
+ $charset = Yii::$app->charset;
+ }
+ $d = array();
+ foreach ($data as $key => $value) {
+ if (!$valuesOnly && is_string($key)) {
+ $key = htmlspecialchars($key, ENT_QUOTES, $charset);
+ }
+ if (is_string($value)) {
+ $d[$key] = htmlspecialchars($value, ENT_QUOTES, $charset);
+ } elseif (is_array($value)) {
+ $d[$key] = static::htmlEncode($value, $charset);
+ }
+ }
+ return $d;
+ }
+
+ /**
+ * Decodes HTML entities into the corresponding characters in an array of strings.
+ * Both the array keys and values will be decoded.
+ * If a value is an array, this method will also decode it recursively.
+ * @param array $data data to be decoded
+ * @param boolean $valuesOnly whether to decode array values only. If false,
+ * both the array keys and array values will be decoded.
+ * @return array the decoded data
+ * @see http://www.php.net/manual/en/function.htmlspecialchars-decode.php
+ */
+ public static function htmlDecode($data, $valuesOnly = true)
+ {
+ $d = array();
+ foreach ($data as $key => $value) {
+ if (!$valuesOnly && is_string($key)) {
+ $key = htmlspecialchars_decode($key, ENT_QUOTES);
+ }
+ if (is_string($value)) {
+ $d[$key] = htmlspecialchars_decode($value, ENT_QUOTES);
+ } elseif (is_array($value)) {
+ $d[$key] = static::htmlDecode($value);
+ }
+ }
+ return $d;
+ }
+}
diff --git a/framework/yii/helpers/AbstractConsole.php b/framework/yii/helpers/AbstractConsole.php
new file mode 100644
index 0000000..8131aae
--- /dev/null
+++ b/framework/yii/helpers/AbstractConsole.php
@@ -0,0 +1,835 @@
+
+ * @since 2.0
+ */
+abstract class AbstractConsole
+{
+ const FG_BLACK = 30;
+ const FG_RED = 31;
+ const FG_GREEN = 32;
+ const FG_YELLOW = 33;
+ const FG_BLUE = 34;
+ const FG_PURPLE = 35;
+ const FG_CYAN = 36;
+ const FG_GREY = 37;
+
+ const BG_BLACK = 40;
+ const BG_RED = 41;
+ const BG_GREEN = 42;
+ const BG_YELLOW = 43;
+ const BG_BLUE = 44;
+ const BG_PURPLE = 45;
+ const BG_CYAN = 46;
+ const BG_GREY = 47;
+
+ const RESET = 0;
+ const NORMAL = 0;
+ const BOLD = 1;
+ const ITALIC = 3;
+ const UNDERLINE = 4;
+ const BLINK = 5;
+ const NEGATIVE = 7;
+ const CONCEALED = 8;
+ const CROSSED_OUT = 9;
+ const FRAMED = 51;
+ const ENCIRCLED = 52;
+ const OVERLINED = 53;
+
+ /**
+ * Moves the terminal cursor up by sending ANSI control code CUU to the terminal.
+ * If the cursor is already at the edge of the screen, this has no effect.
+ * @param integer $rows number of rows the cursor should be moved up
+ */
+ public static function moveCursorUp($rows = 1)
+ {
+ echo "\033[" . (int)$rows . 'A';
+ }
+
+ /**
+ * Moves the terminal cursor down by sending ANSI control code CUD to the terminal.
+ * If the cursor is already at the edge of the screen, this has no effect.
+ * @param integer $rows number of rows the cursor should be moved down
+ */
+ public static function moveCursorDown($rows = 1)
+ {
+ echo "\033[" . (int)$rows . 'B';
+ }
+
+ /**
+ * Moves the terminal cursor forward by sending ANSI control code CUF to the terminal.
+ * If the cursor is already at the edge of the screen, this has no effect.
+ * @param integer $steps number of steps the cursor should be moved forward
+ */
+ public static function moveCursorForward($steps = 1)
+ {
+ echo "\033[" . (int)$steps . 'C';
+ }
+
+ /**
+ * Moves the terminal cursor backward by sending ANSI control code CUB to the terminal.
+ * If the cursor is already at the edge of the screen, this has no effect.
+ * @param integer $steps number of steps the cursor should be moved backward
+ */
+ public static function moveCursorBackward($steps = 1)
+ {
+ echo "\033[" . (int)$steps . 'D';
+ }
+
+ /**
+ * Moves the terminal cursor to the beginning of the next line by sending ANSI control code CNL to the terminal.
+ * @param integer $lines number of lines the cursor should be moved down
+ */
+ public static function moveCursorNextLine($lines = 1)
+ {
+ echo "\033[" . (int)$lines . 'E';
+ }
+
+ /**
+ * Moves the terminal cursor to the beginning of the previous line by sending ANSI control code CPL to the terminal.
+ * @param integer $lines number of lines the cursor should be moved up
+ */
+ public static function moveCursorPrevLine($lines = 1)
+ {
+ echo "\033[" . (int)$lines . 'F';
+ }
+
+ /**
+ * Moves the cursor to an absolute position given as column and row by sending ANSI control code CUP or CHA to the terminal.
+ * @param integer $column 1-based column number, 1 is the left edge of the screen.
+ * @param integer|null $row 1-based row number, 1 is the top edge of the screen. if not set, will move cursor only in current line.
+ */
+ public static function moveCursorTo($column, $row = null)
+ {
+ if ($row === null) {
+ echo "\033[" . (int)$column . 'G';
+ } else {
+ echo "\033[" . (int)$row . ';' . (int)$column . 'H';
+ }
+ }
+
+ /**
+ * Scrolls whole page up by sending ANSI control code SU to the terminal.
+ * New lines are added at the bottom. This is not supported by ANSI.SYS used in windows.
+ * @param int $lines number of lines to scroll up
+ */
+ public static function scrollUp($lines = 1)
+ {
+ echo "\033[" . (int)$lines . "S";
+ }
+
+ /**
+ * Scrolls whole page down by sending ANSI control code SD to the terminal.
+ * New lines are added at the top. This is not supported by ANSI.SYS used in windows.
+ * @param int $lines number of lines to scroll down
+ */
+ public static function scrollDown($lines = 1)
+ {
+ echo "\033[" . (int)$lines . "T";
+ }
+
+ /**
+ * Saves the current cursor position by sending ANSI control code SCP to the terminal.
+ * Position can then be restored with {@link restoreCursorPosition}.
+ */
+ public static function saveCursorPosition()
+ {
+ echo "\033[s";
+ }
+
+ /**
+ * Restores the cursor position saved with {@link saveCursorPosition} by sending ANSI control code RCP to the terminal.
+ */
+ public static function restoreCursorPosition()
+ {
+ echo "\033[u";
+ }
+
+ /**
+ * Hides the cursor by sending ANSI DECTCEM code ?25l to the terminal.
+ * Use {@link showCursor} to bring it back.
+ * Do not forget to show cursor when your application exits. Cursor might stay hidden in terminal after exit.
+ */
+ public static function hideCursor()
+ {
+ echo "\033[?25l";
+ }
+
+ /**
+ * Will show a cursor again when it has been hidden by {@link hideCursor} by sending ANSI DECTCEM code ?25h to the terminal.
+ */
+ public static function showCursor()
+ {
+ echo "\033[?25h";
+ }
+
+ /**
+ * Clears entire screen content by sending ANSI control code ED with argument 2 to the terminal.
+ * Cursor position will not be changed.
+ * **Note:** ANSI.SYS implementation used in windows will reset cursor position to upper left corner of the screen.
+ */
+ public static function clearScreen()
+ {
+ echo "\033[2J";
+ }
+
+ /**
+ * Clears text from cursor to the beginning of the screen by sending ANSI control code ED with argument 1 to the terminal.
+ * Cursor position will not be changed.
+ */
+ public static function clearScreenBeforeCursor()
+ {
+ echo "\033[1J";
+ }
+
+ /**
+ * Clears text from cursor to the end of the screen by sending ANSI control code ED with argument 0 to the terminal.
+ * Cursor position will not be changed.
+ */
+ public static function clearScreenAfterCursor()
+ {
+ echo "\033[0J";
+ }
+
+ /**
+ * Clears the line, the cursor is currently on by sending ANSI control code EL with argument 2 to the terminal.
+ * Cursor position will not be changed.
+ */
+ public static function clearLine()
+ {
+ echo "\033[2K";
+ }
+
+ /**
+ * Clears text from cursor position to the beginning of the line by sending ANSI control code EL with argument 1 to the terminal.
+ * Cursor position will not be changed.
+ */
+ public static function clearLineBeforeCursor()
+ {
+ echo "\033[1K";
+ }
+
+ /**
+ * Clears text from cursor position to the end of the line by sending ANSI control code EL with argument 0 to the terminal.
+ * Cursor position will not be changed.
+ */
+ public static function clearLineAfterCursor()
+ {
+ echo "\033[0K";
+ }
+
+ /**
+ * Returns the ANSI format code.
+ *
+ * @param array $format An array containing formatting values.
+ * You can pass any of the FG_*, BG_* and TEXT_* constants
+ * and also [[xtermFgColor]] and [[xtermBgColor]] to specify a format.
+ * @return string The ANSI format code according to the given formatting constants.
+ */
+ public static function ansiFormatCode($format)
+ {
+ return "\033[" . implode(';', $format) . 'm';
+ }
+
+ /**
+ * Echoes an ANSI format code that affects the formatting of any text that is printed afterwards.
+ *
+ * @param array $format An array containing formatting values.
+ * You can pass any of the FG_*, BG_* and TEXT_* constants
+ * and also [[xtermFgColor]] and [[xtermBgColor]] to specify a format.
+ * @see ansiFormatCode()
+ * @see ansiFormatEnd()
+ */
+ public static function beginAnsiFormat($format)
+ {
+ echo "\033[" . implode(';', $format) . 'm';
+ }
+
+ /**
+ * Resets any ANSI format set by previous method [[ansiFormatBegin()]]
+ * Any output after this will have default text format.
+ * This is equal to calling
+ *
+ * ```php
+ * echo Console::ansiFormatCode(array(Console::RESET))
+ * ```
+ */
+ public static function endAnsiFormat()
+ {
+ echo "\033[0m";
+ }
+
+ /**
+ * Will return a string formatted with the given ANSI style
+ *
+ * @param string $string the string to be formatted
+ * @param array $format An array containing formatting values.
+ * You can pass any of the FG_*, BG_* and TEXT_* constants
+ * and also [[xtermFgColor]] and [[xtermBgColor]] to specify a format.
+ * @return string
+ */
+ public static function ansiFormat($string, $format = array())
+ {
+ $code = implode(';', $format);
+ return "\033[0m" . ($code !== '' ? "\033[" . $code . "m" : '') . $string . "\033[0m";
+ }
+
+ /**
+ * Returns the ansi format code for xterm foreground color.
+ * You can pass the return value of this to one of the formatting methods:
+ * [[ansiFormat]], [[ansiFormatCode]], [[beginAnsiFormat]]
+ *
+ * @param integer $colorCode xterm color code
+ * @return string
+ * @see http://en.wikipedia.org/wiki/Talk:ANSI_escape_code#xterm-256colors
+ */
+ public static function xtermFgColor($colorCode)
+ {
+ return '38;5;' . $colorCode;
+ }
+
+ /**
+ * Returns the ansi format code for xterm background color.
+ * You can pass the return value of this to one of the formatting methods:
+ * [[ansiFormat]], [[ansiFormatCode]], [[beginAnsiFormat]]
+ *
+ * @param integer $colorCode xterm color code
+ * @return string
+ * @see http://en.wikipedia.org/wiki/Talk:ANSI_escape_code#xterm-256colors
+ */
+ public static function xtermBgColor($colorCode)
+ {
+ return '48;5;' . $colorCode;
+ }
+
+ /**
+ * Strips ANSI control codes from a string
+ *
+ * @param string $string String to strip
+ * @return string
+ */
+ public static function stripAnsiFormat($string)
+ {
+ return preg_replace('/\033\[[\d;?]*\w/', '', $string);
+ }
+
+ /**
+ * Converts an ANSI formatted string to HTML
+ * @param $string
+ * @return mixed
+ */
+ // TODO rework/refactor according to https://github.com/yiisoft/yii2/issues/746
+ public static function ansiToHtml($string)
+ {
+ $tags = 0;
+ return preg_replace_callback(
+ '/\033\[[\d;]+m/',
+ function ($ansi) use (&$tags) {
+ $styleA = array();
+ foreach (explode(';', $ansi) as $controlCode) {
+ switch ($controlCode) {
+ case self::FG_BLACK:
+ $style = array('color' => '#000000');
+ break;
+ case self::FG_BLUE:
+ $style = array('color' => '#000078');
+ break;
+ case self::FG_CYAN:
+ $style = array('color' => '#007878');
+ break;
+ case self::FG_GREEN:
+ $style = array('color' => '#007800');
+ break;
+ case self::FG_GREY:
+ $style = array('color' => '#787878');
+ break;
+ case self::FG_PURPLE:
+ $style = array('color' => '#780078');
+ break;
+ case self::FG_RED:
+ $style = array('color' => '#780000');
+ break;
+ case self::FG_YELLOW:
+ $style = array('color' => '#787800');
+ break;
+ case self::BG_BLACK:
+ $style = array('background-color' => '#000000');
+ break;
+ case self::BG_BLUE:
+ $style = array('background-color' => '#000078');
+ break;
+ case self::BG_CYAN:
+ $style = array('background-color' => '#007878');
+ break;
+ case self::BG_GREEN:
+ $style = array('background-color' => '#007800');
+ break;
+ case self::BG_GREY:
+ $style = array('background-color' => '#787878');
+ break;
+ case self::BG_PURPLE:
+ $style = array('background-color' => '#780078');
+ break;
+ case self::BG_RED:
+ $style = array('background-color' => '#780000');
+ break;
+ case self::BG_YELLOW:
+ $style = array('background-color' => '#787800');
+ break;
+ case self::BOLD:
+ $style = array('font-weight' => 'bold');
+ break;
+ case self::ITALIC:
+ $style = array('font-style' => 'italic');
+ break;
+ case self::UNDERLINE:
+ $style = array('text-decoration' => array('underline'));
+ break;
+ case self::OVERLINED:
+ $style = array('text-decoration' => array('overline'));
+ break;
+ case self::CROSSED_OUT:
+ $style = array('text-decoration' => array('line-through'));
+ break;
+ case self::BLINK:
+ $style = array('text-decoration' => array('blink'));
+ break;
+ case self::NEGATIVE: // ???
+ case self::CONCEALED:
+ case self::ENCIRCLED:
+ case self::FRAMED:
+ // TODO allow resetting codes
+ break;
+ case 0: // ansi reset
+ $return = '';
+ for ($n = $tags; $tags > 0; $tags--) {
+ $return .= '';
+ }
+ return $return;
+ }
+
+ $styleA = ArrayHelper::merge($styleA, $style);
+ }
+ $styleString[] = array();
+ foreach ($styleA as $name => $content) {
+ if ($name === 'text-decoration') {
+ $content = implode(' ', $content);
+ }
+ $styleString[] = $name . ':' . $content;
+ }
+ $tags++;
+ return '';
+ },
+ $string
+ );
+ }
+
+ // TODO rework/refactor according to https://github.com/yiisoft/yii2/issues/746
+ public function markdownToAnsi()
+ {
+ // TODO implement
+ }
+
+ /**
+ * Converts a string to ansi formatted by replacing patterns like %y (for yellow) with ansi control codes
+ *
+ * Uses almost the same syntax as https://github.com/pear/Console_Color2/blob/master/Console/Color2.php
+ * The conversion table is: ('bold' meaning 'light' on some
+ * terminals). It's almost the same conversion table irssi uses.
+ *
+ * text text background
+ * ------------------------------------------------
+ * %k %K %0 black dark grey black
+ * %r %R %1 red bold red red
+ * %g %G %2 green bold green green
+ * %y %Y %3 yellow bold yellow yellow
+ * %b %B %4 blue bold blue blue
+ * %m %M %5 magenta bold magenta magenta
+ * %p %P magenta (think: purple)
+ * %c %C %6 cyan bold cyan cyan
+ * %w %W %7 white bold white white
+ *
+ * %F Blinking, Flashing
+ * %U Underline
+ * %8 Reverse
+ * %_,%9 Bold
+ *
+ * %n Resets the color
+ * %% A single %
+ *
';
+ }
+ }
+ return strtr($summaryContent, array(
+ '{begin}' => $begin,
+ '{end}' => $end,
+ '{count}' => $count,
+ '{totalCount}' => $totalCount,
+ '{page}' => $page,
+ '{pageCount}' => $pageCount,
+ ));
+ }
+
+ /**
+ * Renders the pager.
+ * @return string the rendering result
+ */
+ public function renderPager()
+ {
+ $pagination = $this->dataProvider->getPagination();
+ if ($pagination === false || $this->dataProvider->getCount() <= 0) {
+ return '';
+ }
+ /** @var LinkPager $class */
+ $class = ArrayHelper::remove($this->pager, 'class', LinkPager::className());
+ $this->pager['pagination'] = $pagination;
+ return $class::widget($this->pager);
+ }
+
+ /**
+ * Renders the sorter.
+ * @return string the rendering result
+ */
+ public function renderSorter()
+ {
+ $sort = $this->dataProvider->getSort();
+ if ($sort === false || empty($sort->attributes) || $this->dataProvider->getCount() <= 0) {
+ return '';
+ }
+ /** @var LinkSorter $class */
+ $class = ArrayHelper::remove($this->sorter, 'class', LinkSorter::className());
+ $this->sorter['sort'] = $sort;
+ return $class::widget($this->sorter);
+ }
+}
diff --git a/framework/yii/widgets/ListView.php b/framework/yii/widgets/ListView.php
index c191389..1d8745d 100644
--- a/framework/yii/widgets/ListView.php
+++ b/framework/yii/widgets/ListView.php
@@ -16,7 +16,7 @@ use yii\helpers\Html;
* @author Qiang Xue
* @since 2.0
*/
-class ListView extends ListViewBase
+class ListView extends BaseListView
{
/**
* @var array the HTML attributes for the container of the rendering result of each data model.
diff --git a/framework/yii/widgets/ListViewBase.php b/framework/yii/widgets/ListViewBase.php
deleted file mode 100644
index 33186ae..0000000
--- a/framework/yii/widgets/ListViewBase.php
+++ /dev/null
@@ -1,191 +0,0 @@
-
- * @since 2.0
- */
-abstract class ListViewBase extends Widget
-{
- /**
- * @var array the HTML attributes for the container tag of the list view.
- * The "tag" element specifies the tag name of the container element and defaults to "div".
- */
- public $options = array();
- /**
- * @var \yii\data\DataProviderInterface the data provider for the view. This property is required.
- */
- public $dataProvider;
- /**
- * @var array the configuration for the pager widget. By default, [[LinkPager]] will be
- * used to render the pager. You can use a different widget class by configuring the "class" element.
- */
- public $pager = array();
- /**
- * @var array the configuration for the sorter widget. By default, [[LinkSorter]] will be
- * used to render the sorter. You can use a different widget class by configuring the "class" element.
- */
- public $sorter = array();
- /**
- * @var string the HTML content to be displayed as the summary of the list view.
- * If you do not want to show the summary, you may set it with an empty string.
- *
- * The following tokens will be replaced with the corresponding values:
- *
- * - `{begin}`: the starting row number (1-based) currently being displayed
- * - `{end}`: the ending row number (1-based) currently being displayed
- * - `{count}`: the number of rows currently being displayed
- * - `{totalCount}`: the total number of rows available
- * - `{page}`: the page number (1-based) current being displayed
- * - `{pageCount}`: the number of pages available
- */
- public $summary;
- /**
- * @var string|boolean the HTML content to be displayed when [[dataProvider]] does not have any data.
- * If false, the list view will still be displayed (without body content though).
- */
- public $empty;
- /**
- * @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 = "{summary}\n{items}\n{pager}";
-
-
- /**
- * Renders the data models.
- * @return string the rendering result.
- */
- abstract public function renderItems();
-
- /**
- * Initializes the view.
- */
- public function init()
- {
- if ($this->dataProvider === null) {
- throw new InvalidConfigException('The "dataProvider" property must be set.');
- }
- }
-
- /**
- * Runs the widget.
- */
- public function run()
- {
- if ($this->dataProvider->getCount() > 0 || $this->empty === false) {
- $widget = $this;
- $content = preg_replace_callback("/{\\w+}/", function ($matches) use ($widget) {
- $content = $widget->renderSection($matches[0]);
- return $content === false ? $matches[0] : $content;
- }, $this->layout);
- } else {
- $content = '
';
- }
- }
- return strtr($summaryContent, array(
- '{begin}' => $begin,
- '{end}' => $end,
- '{count}' => $count,
- '{totalCount}' => $totalCount,
- '{page}' => $page,
- '{pageCount}' => $pageCount,
- ));
- }
-
- /**
- * Renders the pager.
- * @return string the rendering result
- */
- public function renderPager()
- {
- $pagination = $this->dataProvider->getPagination();
- if ($pagination === false || $this->dataProvider->getCount() <= 0) {
- return '';
- }
- /** @var LinkPager $class */
- $class = ArrayHelper::remove($this->pager, 'class', LinkPager::className());
- $this->pager['pagination'] = $pagination;
- return $class::widget($this->pager);
- }
-
- /**
- * Renders the sorter.
- * @return string the rendering result
- */
- public function renderSorter()
- {
- $sort = $this->dataProvider->getSort();
- if ($sort === false || empty($sort->attributes) || $this->dataProvider->getCount() <= 0) {
- return '';
- }
- /** @var LinkSorter $class */
- $class = ArrayHelper::remove($this->sorter, 'class', LinkSorter::className());
- $this->sorter['sort'] = $sort;
- return $class::widget($this->sorter);
- }
-}
From 40629ca49bef1a864b2d94593335eac7c927b084 Mon Sep 17 00:00:00 2001
From: Alexander Makarov
Date: Sat, 28 Sep 2013 23:30:54 +0400
Subject: [PATCH 045/613] Added missing beforeCopy option to
FileHelper::copyDirectory
It was mentioned in AssetManager::publish phpdoc.
---
framework/yii/helpers/BaseFileHelper.php | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/framework/yii/helpers/BaseFileHelper.php b/framework/yii/helpers/BaseFileHelper.php
index 2c911b0..c71a1a9 100644
--- a/framework/yii/helpers/BaseFileHelper.php
+++ b/framework/yii/helpers/BaseFileHelper.php
@@ -155,6 +155,11 @@ class BaseFileHelper
* and '.svn/' matches directory paths ending with '.svn'. Note, the '/' characters in a pattern matches
* both '/' and '\' in the paths.
* - recursive: boolean, whether the files under the subdirectories should also be copied. Defaults to true.
+ * - beforeCopy: callback, a PHP callback that is called before copying each sub-directory or file.
+ * This option is used only when publishing a directory. If the callback returns false, the copy
+ * operation for the sub-directory or file will be cancelled.
+ * The signature of the callback should be: `function ($from, $to)`, where `$from` is the sub-directory or
+ * file to be copied from, while `$to` is the copy target.
* - afterCopy: callback, a PHP callback that is called after each sub-directory or file is successfully copied.
* The signature of the callback should be: `function ($from, $to)`, where `$from` is the sub-directory or
* file copied from, while `$to` is the copy target.
@@ -173,6 +178,9 @@ class BaseFileHelper
$from = $src . DIRECTORY_SEPARATOR . $file;
$to = $dst . DIRECTORY_SEPARATOR . $file;
if (static::filterPath($from, $options)) {
+ if (isset($options['beforeCopy'])) {
+ call_user_func($options['beforeCopy'], $from, $to);
+ }
if (is_file($from)) {
copy($from, $to);
if (isset($options['fileMode'])) {
From ba1496cd508ca003bff8ffbae5e1d055a652e5b0 Mon Sep 17 00:00:00 2001
From: Qiang Xue
Date: Sat, 28 Sep 2013 20:11:24 -0400
Subject: [PATCH 046/613] doc fix.
---
framework/yii/web/Response.php | 21 ++++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)
diff --git a/framework/yii/web/Response.php b/framework/yii/web/Response.php
index e6505fd..f0d506b 100644
--- a/framework/yii/web/Response.php
+++ b/framework/yii/web/Response.php
@@ -559,7 +559,20 @@ class Response extends \yii\base\Response
/**
* Redirects the browser to the specified URL.
*
- * This method will send out a "Location" header to achieve the redirection.
+ * This method adds a "Location" header to the current response. Note that it does not send out
+ * the header until [[send()]] is called. In a controller action you may use this method as follows:
+ *
+ * ~~~
+ * return Yii::$app->getResponse()->redirect($url);
+ * ~~~
+ *
+ * In other places, if you want to send out the "Location" header immediately, you should use
+ * the following code:
+ *
+ * ~~~
+ * Yii::$app->getResponse()->redirect($url)->send();
+ * return;
+ * ~~~
*
* In AJAX mode, this normally will not work as expected unless there are some
* client-side JavaScript code handling the redirection. To help achieve this goal,
@@ -578,12 +591,6 @@ class Response extends \yii\base\Response
* });
* ~~~
*
- * In a controller action you may use this method like this:
- *
- * ~~~
- * return Yii::$app->getResponse()->redirect($url);
- * ~~~
- *
* @param string|array $url the URL to be redirected to. This can be in one of the following formats:
*
* - a string representing a URL (e.g. "http://example.com")
From efef0e52ca41ed16f52eefae8c24a1103ee020f6 Mon Sep 17 00:00:00 2001
From: Qiang Xue
Date: Sat, 28 Sep 2013 20:13:48 -0400
Subject: [PATCH 047/613] Fixed beforeCopy option.
---
framework/yii/helpers/BaseFileHelper.php | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/framework/yii/helpers/BaseFileHelper.php b/framework/yii/helpers/BaseFileHelper.php
index c71a1a9..caed59f 100644
--- a/framework/yii/helpers/BaseFileHelper.php
+++ b/framework/yii/helpers/BaseFileHelper.php
@@ -156,8 +156,7 @@ class BaseFileHelper
* both '/' and '\' in the paths.
* - recursive: boolean, whether the files under the subdirectories should also be copied. Defaults to true.
* - beforeCopy: callback, a PHP callback that is called before copying each sub-directory or file.
- * This option is used only when publishing a directory. If the callback returns false, the copy
- * operation for the sub-directory or file will be cancelled.
+ * If the callback returns false, the copy operation for the sub-directory or file will be cancelled.
* The signature of the callback should be: `function ($from, $to)`, where `$from` is the sub-directory or
* file to be copied from, while `$to` is the copy target.
* - afterCopy: callback, a PHP callback that is called after each sub-directory or file is successfully copied.
@@ -178,8 +177,8 @@ class BaseFileHelper
$from = $src . DIRECTORY_SEPARATOR . $file;
$to = $dst . DIRECTORY_SEPARATOR . $file;
if (static::filterPath($from, $options)) {
- if (isset($options['beforeCopy'])) {
- call_user_func($options['beforeCopy'], $from, $to);
+ if (!isset($options['beforeCopy']) || !call_user_func($options['beforeCopy'], $from, $to)) {
+ continue;
}
if (is_file($from)) {
copy($from, $to);
From b45b16d84502b6d557c72839d17b4b8b229806c1 Mon Sep 17 00:00:00 2001
From: Alexander Makarov
Date: Sun, 29 Sep 2013 05:05:57 +0400
Subject: [PATCH 048/613] Renamed test to match class name
---
tests/unit/framework/BaseYiiTest.php | 63 ++++++++++++++++++++++++++++++++++++
tests/unit/framework/YiiBaseTest.php | 63 ------------------------------------
2 files changed, 63 insertions(+), 63 deletions(-)
create mode 100644 tests/unit/framework/BaseYiiTest.php
delete mode 100644 tests/unit/framework/YiiBaseTest.php
diff --git a/tests/unit/framework/BaseYiiTest.php b/tests/unit/framework/BaseYiiTest.php
new file mode 100644
index 0000000..a04de99
--- /dev/null
+++ b/tests/unit/framework/BaseYiiTest.php
@@ -0,0 +1,63 @@
+aliases = Yii::$aliases;
+ }
+
+ protected function tearDown()
+ {
+ parent::tearDown();
+ Yii::$aliases = $this->aliases;
+ }
+
+ public function testAlias()
+ {
+ $this->assertEquals(YII_PATH, Yii::getAlias('@yii'));
+
+ Yii::$aliases = array();
+ $this->assertFalse(Yii::getAlias('@yii', false));
+
+ Yii::setAlias('@yii', '/yii/framework');
+ $this->assertEquals('/yii/framework', Yii::getAlias('@yii'));
+ $this->assertEquals('/yii/framework/test/file', Yii::getAlias('@yii/test/file'));
+ Yii::setAlias('@yii/gii', '/yii/gii');
+ $this->assertEquals('/yii/framework', Yii::getAlias('@yii'));
+ $this->assertEquals('/yii/framework/test/file', Yii::getAlias('@yii/test/file'));
+ $this->assertEquals('/yii/gii', Yii::getAlias('@yii/gii'));
+ $this->assertEquals('/yii/gii/file', Yii::getAlias('@yii/gii/file'));
+
+ Yii::setAlias('@tii', '@yii/test');
+ $this->assertEquals('/yii/framework/test', Yii::getAlias('@tii'));
+
+ Yii::setAlias('@yii', null);
+ $this->assertFalse(Yii::getAlias('@yii', false));
+ $this->assertEquals('/yii/gii/file', Yii::getAlias('@yii/gii/file'));
+
+ Yii::setAlias('@some/alias', '/www');
+ $this->assertEquals('/www', Yii::getAlias('@some/alias'));
+ }
+
+ public function testGetVersion()
+ {
+ $this->assertTrue((boolean)preg_match('~\d+\.\d+(?:\.\d+)?(?:-\w+)?~', \Yii::getVersion()));
+ }
+
+ public function testPowered()
+ {
+ $this->assertTrue(is_string(Yii::powered()));
+ }
+}
diff --git a/tests/unit/framework/YiiBaseTest.php b/tests/unit/framework/YiiBaseTest.php
deleted file mode 100644
index 72b5f24..0000000
--- a/tests/unit/framework/YiiBaseTest.php
+++ /dev/null
@@ -1,63 +0,0 @@
-aliases = Yii::$aliases;
- }
-
- protected function tearDown()
- {
- parent::tearDown();
- Yii::$aliases = $this->aliases;
- }
-
- public function testAlias()
- {
- $this->assertEquals(YII_PATH, Yii::getAlias('@yii'));
-
- Yii::$aliases = array();
- $this->assertFalse(Yii::getAlias('@yii', false));
-
- Yii::setAlias('@yii', '/yii/framework');
- $this->assertEquals('/yii/framework', Yii::getAlias('@yii'));
- $this->assertEquals('/yii/framework/test/file', Yii::getAlias('@yii/test/file'));
- Yii::setAlias('@yii/gii', '/yii/gii');
- $this->assertEquals('/yii/framework', Yii::getAlias('@yii'));
- $this->assertEquals('/yii/framework/test/file', Yii::getAlias('@yii/test/file'));
- $this->assertEquals('/yii/gii', Yii::getAlias('@yii/gii'));
- $this->assertEquals('/yii/gii/file', Yii::getAlias('@yii/gii/file'));
-
- Yii::setAlias('@tii', '@yii/test');
- $this->assertEquals('/yii/framework/test', Yii::getAlias('@tii'));
-
- Yii::setAlias('@yii', null);
- $this->assertFalse(Yii::getAlias('@yii', false));
- $this->assertEquals('/yii/gii/file', Yii::getAlias('@yii/gii/file'));
-
- Yii::setAlias('@some/alias', '/www');
- $this->assertEquals('/www', Yii::getAlias('@some/alias'));
- }
-
- public function testGetVersion()
- {
- $this->assertTrue((boolean)preg_match('~\d+\.\d+(?:\.\d+)?(?:-\w+)?~', \Yii::getVersion()));
- }
-
- public function testPowered()
- {
- $this->assertTrue(is_string(Yii::powered()));
- }
-}
From fb684774db5870abb3ecb0bf91d2924704d6bba6 Mon Sep 17 00:00:00 2001
From: Alexander Makarov
Date: Sun, 29 Sep 2013 05:11:46 +0400
Subject: [PATCH 049/613] better wording
---
docs/guide/i18n.md | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/docs/guide/i18n.md b/docs/guide/i18n.md
index a1c6314..6532717 100644
--- a/docs/guide/i18n.md
+++ b/docs/guide/i18n.md
@@ -41,7 +41,11 @@ Basic message translation
### Strings translation
-Yii basic message translation that works without additional PHP extension and
+Yii basic message translation that works without additional PHP extension.
+
+```php
+echo \Yii::t('app', 'This is a string to translate!');
+```
### Named placeholders
@@ -60,9 +64,8 @@ $sum = 42;
echo \Yii::t('app', 'Balance: {0}', $sum);
```
-> **Tip**: When messages are extracted and passed to translator, he sees strings only. For the code above extracted message will be
-> "Balance: {0}". It's not recommended to use positional placeholders except when there's only one and message context is
-> clear as above.
+> **Tip**: Try keep message strings meaningful and avoid using too many positional parameters. Remember that
+> translator has source string only so it should be obvious about what will replace each placeholder.
Advanced placeholder formatting
-------------------------------
From abc0df6145bda4e4531d5b9482d39aa1a9ba09be Mon Sep 17 00:00:00 2001
From: Alexander Makarov
Date: Sun, 29 Sep 2013 05:12:36 +0400
Subject: [PATCH 050/613] typo
---
framework/yii/i18n/MessageFormatter.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/framework/yii/i18n/MessageFormatter.php b/framework/yii/i18n/MessageFormatter.php
index de717dc..76197d1 100644
--- a/framework/yii/i18n/MessageFormatter.php
+++ b/framework/yii/i18n/MessageFormatter.php
@@ -57,7 +57,7 @@ class MessageFormatter extends \MessageFormatter
/**
* Replace named placeholders with numeric placeholders.
*
- * @param string $pattern The pattern string to relace things into.
+ * @param string $pattern The pattern string to replace things into.
* @param array $args The array of values to insert into the format string.
* @return string The pattern string with placeholders replaced.
*/
From 6dc69e68b55e1eece655c4716f0969693b4aba0e Mon Sep 17 00:00:00 2001
From: ekerazha
Date: Sun, 29 Sep 2013 17:21:41 +0200
Subject: [PATCH 051/613] Add data padding and key derivation.
---
framework/yii/helpers/BaseSecurity.php | 85 ++++++++++++++++++++++++++++++----
1 file changed, 76 insertions(+), 9 deletions(-)
diff --git a/framework/yii/helpers/BaseSecurity.php b/framework/yii/helpers/BaseSecurity.php
index 3be07b4..41caade 100644
--- a/framework/yii/helpers/BaseSecurity.php
+++ b/framework/yii/helpers/BaseSecurity.php
@@ -24,20 +24,40 @@ use yii\base\InvalidParamException;
class BaseSecurity
{
/**
+ * Uses AES, block size is 128-bit (16 bytes).
+ */
+ const CRYPT_BLOCK_SIZE = 16;
+
+ /**
+ * Uses AES-192, key size is 192-bit (24 bytes).
+ */
+ const CRYPT_KEY_SIZE = 24;
+
+ /**
+ * Uses SHA-256.
+ */
+ const DERIVATION_HASH = 'sha256';
+
+ /**
+ * Uses 1000 iterations.
+ */
+ const DERIVATION_ITERATIONS = 1000;
+
+ /**
* Encrypts data.
* @param string $data data to be encrypted.
- * @param string $key the encryption secret key
+ * @param string $password the encryption password
* @return string the encrypted data
* @throws Exception if PHP Mcrypt extension is not loaded or failed to be initialized
* @see decrypt()
*/
- public static function encrypt($data, $key)
+ public static function encrypt($data, $password)
{
$module = static::openCryptModule();
- // 192-bit (24 bytes) key size
- $key = StringHelper::substr($key, 0, 24);
+ $data = static::addPadding($data);
srand();
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($module), MCRYPT_RAND);
+ $key = static::deriveKey($password, $iv);
mcrypt_generic_init($module, $key, $iv);
$encrypted = $iv . mcrypt_generic($module, $data);
mcrypt_generic_deinit($module);
@@ -48,23 +68,70 @@ class BaseSecurity
/**
* Decrypts data
* @param string $data data to be decrypted.
- * @param string $key the decryption secret key
+ * @param string $password the decryption password
* @return string the decrypted data
* @throws Exception if PHP Mcrypt extension is not loaded or failed to be initialized
* @see encrypt()
*/
- public static function decrypt($data, $key)
+ public static function decrypt($data, $password)
{
$module = static::openCryptModule();
- // 192-bit (24 bytes) key size
- $key = StringHelper::substr($key, 0, 24);
$ivSize = mcrypt_enc_get_iv_size($module);
$iv = StringHelper::substr($data, 0, $ivSize);
+ $key = static::deriveKey($password, $iv);
mcrypt_generic_init($module, $key, $iv);
$decrypted = mdecrypt_generic($module, StringHelper::substr($data, $ivSize, StringHelper::strlen($data)));
mcrypt_generic_deinit($module);
mcrypt_module_close($module);
- return rtrim($decrypted, "\0");
+ return static::stripPadding($decrypted);
+ }
+
+ /**
+ * Adds a padding to the given data (PKCS #7).
+ * @param string $data the data to pad
+ * @return string the padded data
+ */
+ protected static function addPadding($data)
+ {
+ $pad = self::CRYPT_BLOCK_SIZE - (StringHelper::strlen($data) % self::CRYPT_BLOCK_SIZE);
+ return $data . str_repeat(chr($pad), $pad);
+ }
+
+ /**
+ * Strips the padding from the given data.
+ * @param string $data the data to trim
+ * @return string the trimmed data
+ */
+ protected static function stripPadding($data)
+ {
+ $end = StringHelper::substr($data, -1);
+ $last = ord($end);
+ $n = StringHelper::strlen($data) - $last;
+ if (StringHelper::substr($data, $n) == str_repeat($end, $last)) {
+ return StringHelper::substr($data, 0, $n);
+ }
+ return false;
+ }
+
+ /**
+ * Derives a key from the given password (PBKDF2).
+ * @param string $password the source password
+ * @param string $salt the random salt
+ * @param int $iterations the number of iterations
+ * @return string the derived key
+ */
+ protected static function deriveKey($password, $salt)
+ {
+ if (function_exists('hash_pbkdf2')) {
+ return hash_pbkdf2(self::DERIVATION_HASH, $password, $salt, self::DERIVATION_ITERATIONS, self::CRYPT_KEY_SIZE, true);
+ }
+ $hmac = hash_hmac(self::DERIVATION_HASH, $salt . pack('N', 1), $password, true);
+ $xorsum = $hmac;
+ for ($i = 1; $i < self::DERIVATION_ITERATIONS; $i++) {
+ $hmac = hash_hmac(self::DERIVATION_HASH, $hmac, $password, true);
+ $xorsum ^= $hmac;
+ }
+ return substr($xorsum, 0, self::CRYPT_KEY_SIZE);
}
/**
From 5d7c37bd7ea2d0e467fabeff312bd184c6216d7d Mon Sep 17 00:00:00 2001
From: Jin Hu
Date: Sun, 29 Sep 2013 23:27:14 +0800
Subject: [PATCH 052/613] Incorrect array representation when has previous
---
framework/yii/base/Exception.php | 8 ++++----
tests/unit/framework/base/ExceptionTest.php | 23 +++++++++++++++++++++++
2 files changed, 27 insertions(+), 4 deletions(-)
create mode 100644 tests/unit/framework/base/ExceptionTest.php
diff --git a/framework/yii/base/Exception.php b/framework/yii/base/Exception.php
index 4f66e53..b771490 100644
--- a/framework/yii/base/Exception.php
+++ b/framework/yii/base/Exception.php
@@ -41,10 +41,10 @@ class Exception extends \Exception implements Arrayable
{
if ($exception instanceof self) {
$array = array(
- 'type' => get_class($this),
- 'name' => $this->getName(),
- 'message' => $this->getMessage(),
- 'code' => $this->getCode(),
+ 'type' => get_class($exception),
+ 'name' => $exception->getName(),
+ 'message' => $exception->getMessage(),
+ 'code' => $exception->getCode(),
);
} else {
$array = array(
diff --git a/tests/unit/framework/base/ExceptionTest.php b/tests/unit/framework/base/ExceptionTest.php
new file mode 100644
index 0000000..af4293a
--- /dev/null
+++ b/tests/unit/framework/base/ExceptionTest.php
@@ -0,0 +1,23 @@
+toArray();
+ $this->assertEquals('bar', $array['message']);
+ $this->assertEquals('foo', $array['previous']['message']);
+
+ $e = new InvalidCallException('bar', 0 ,new UserException('foo'));
+ $array = $e->toArray();
+ $this->assertEquals('bar', $array['message']);
+ $this->assertEquals('foo', $array['previous']['message']);
+ }
+}
From cb7921b8a5ecd391076f869fd344b78f789adf70 Mon Sep 17 00:00:00 2001
From: ekerazha
Date: Sun, 29 Sep 2013 17:59:31 +0200
Subject: [PATCH 053/613] Fix StringHelper::substr() call.
---
framework/yii/helpers/BaseSecurity.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/framework/yii/helpers/BaseSecurity.php b/framework/yii/helpers/BaseSecurity.php
index 41caade..ca42d37 100644
--- a/framework/yii/helpers/BaseSecurity.php
+++ b/framework/yii/helpers/BaseSecurity.php
@@ -104,10 +104,10 @@ class BaseSecurity
*/
protected static function stripPadding($data)
{
- $end = StringHelper::substr($data, -1);
+ $end = StringHelper::substr($data, -1, NULL);
$last = ord($end);
$n = StringHelper::strlen($data) - $last;
- if (StringHelper::substr($data, $n) == str_repeat($end, $last)) {
+ if (StringHelper::substr($data, $n, NULL) == str_repeat($end, $last)) {
return StringHelper::substr($data, 0, $n);
}
return false;
From 9e9b3548db5544c2b3df47985601c95fe3de6011 Mon Sep 17 00:00:00 2001
From: Qiang Xue
Date: Sun, 29 Sep 2013 12:06:00 -0400
Subject: [PATCH 054/613] refactor Exception::toArrayRecursive().
---
framework/yii/base/Exception.php | 21 ++++++---------------
1 file changed, 6 insertions(+), 15 deletions(-)
diff --git a/framework/yii/base/Exception.php b/framework/yii/base/Exception.php
index b771490..64f1d1b 100644
--- a/framework/yii/base/Exception.php
+++ b/framework/yii/base/Exception.php
@@ -39,21 +39,12 @@ class Exception extends \Exception implements Arrayable
*/
protected function toArrayRecursive($exception)
{
- if ($exception instanceof self) {
- $array = array(
- 'type' => get_class($exception),
- 'name' => $exception->getName(),
- 'message' => $exception->getMessage(),
- 'code' => $exception->getCode(),
- );
- } else {
- $array = array(
- 'type' => get_class($exception),
- 'name' => 'Exception',
- 'message' => $exception->getMessage(),
- 'code' => $exception->getCode(),
- );
- }
+ $array = array(
+ 'type' => get_class($exception),
+ 'name' => $exception instanceof self ? $exception->getName() : 'Exception',
+ 'message' => $exception->getMessage(),
+ 'code' => $exception->getCode(),
+ );
if (($prev = $exception->getPrevious()) !== null) {
$array['previous'] = $this->toArrayRecursive($prev);
}
From c4f4e52a5aaadd3369865ac2151dc965c675ecbf Mon Sep 17 00:00:00 2001
From: Qiang Xue
Date: Sun, 29 Sep 2013 12:16:20 -0400
Subject: [PATCH 055/613] fixed test break.
---
framework/yii/helpers/BaseFileHelper.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/framework/yii/helpers/BaseFileHelper.php b/framework/yii/helpers/BaseFileHelper.php
index caed59f..7540168 100644
--- a/framework/yii/helpers/BaseFileHelper.php
+++ b/framework/yii/helpers/BaseFileHelper.php
@@ -177,7 +177,7 @@ class BaseFileHelper
$from = $src . DIRECTORY_SEPARATOR . $file;
$to = $dst . DIRECTORY_SEPARATOR . $file;
if (static::filterPath($from, $options)) {
- if (!isset($options['beforeCopy']) || !call_user_func($options['beforeCopy'], $from, $to)) {
+ if (isset($options['beforeCopy']) && !call_user_func($options['beforeCopy'], $from, $to)) {
continue;
}
if (is_file($from)) {
From 64a33e78498197796cbda9150ec0cf3d846801f8 Mon Sep 17 00:00:00 2001
From: ekerazha
Date: Sun, 29 Sep 2013 18:18:59 +0200
Subject: [PATCH 056/613] Fix phpdoc.
---
framework/yii/helpers/BaseSecurity.php | 1 -
1 file changed, 1 deletion(-)
diff --git a/framework/yii/helpers/BaseSecurity.php b/framework/yii/helpers/BaseSecurity.php
index ca42d37..a1b0ec4 100644
--- a/framework/yii/helpers/BaseSecurity.php
+++ b/framework/yii/helpers/BaseSecurity.php
@@ -117,7 +117,6 @@ class BaseSecurity
* Derives a key from the given password (PBKDF2).
* @param string $password the source password
* @param string $salt the random salt
- * @param int $iterations the number of iterations
* @return string the derived key
*/
protected static function deriveKey($password, $salt)
From 8d4d0ee0bcbd5986e5bc21e48b9c967665ee2e21 Mon Sep 17 00:00:00 2001
From: Carsten Brandt
Date: Mon, 30 Sep 2013 12:53:04 +0200
Subject: [PATCH 057/613] Update RedisCache.php
added version information
---
framework/yii/caching/RedisCache.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/framework/yii/caching/RedisCache.php b/framework/yii/caching/RedisCache.php
index 5c778fc..7cb6451 100644
--- a/framework/yii/caching/RedisCache.php
+++ b/framework/yii/caching/RedisCache.php
@@ -10,7 +10,7 @@ namespace yii\caching;
use yii\redis\Connection;
/**
- * RedisCache implements a cache application component based on [redis](http://redis.io/).
+ * RedisCache implements a cache application component based on [redis](http://redis.io/) version 2.6 or higher.
*
* RedisCache needs to be configured with [[hostname]], [[port]] and [[database]] of the server
* to connect to. By default RedisCache assumes there is a redis server running on localhost at
From b4b9ad483a8d33985a852af23993b9360b482ab0 Mon Sep 17 00:00:00 2001
From: Carsten Brandt
Date: Mon, 30 Sep 2013 14:42:05 +0200
Subject: [PATCH 058/613] Added version information to redis
---
docs/guide/caching.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/docs/guide/caching.md b/docs/guide/caching.md
index 0624d78..64c7e8d 100644
--- a/docs/guide/caching.md
+++ b/docs/guide/caching.md
@@ -60,7 +60,8 @@ is a summary of the available cache components:
the fastest one when dealing with cache in a distributed applications (e.g. with several servers, load
balancers, etc.)
-* [[\yii\caching\RedisCache]]: implements a cache component based on [Redis](http://redis.io/) NoSQL database.
+* [[\yii\caching\RedisCache]]: implements a cache component based on [Redis](http://redis.io/) key-value store
+ (redis version 2.6 or higher is required).
* [[\yii\caching\WinCache]]: uses PHP [WinCache](http://iis.net/downloads/microsoft/wincache-extension)
([see also](http://php.net/manual/en/book.wincache.php)) extension.
From d03d681583b1bdc8ea0246ca610bbb1bb3a6fd73 Mon Sep 17 00:00:00 2001
From: Qiang Xue
Date: Mon, 30 Sep 2013 10:14:08 -0400
Subject: [PATCH 059/613] Fixes #928: client validation should be applied to
active attributes only.
---
framework/yii/widgets/ActiveField.php | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/framework/yii/widgets/ActiveField.php b/framework/yii/widgets/ActiveField.php
index ea8aa1b..7df67fa 100644
--- a/framework/yii/widgets/ActiveField.php
+++ b/framework/yii/widgets/ActiveField.php
@@ -589,9 +589,13 @@ class ActiveField extends Component
*/
protected function getClientOptions()
{
+ $attribute = Html::getAttributeName($this->attribute);
+ if (!in_array($attribute, $this->model->activeAttributes(), true)) {
+ return array();
+ }
+
$enableClientValidation = $this->enableClientValidation || $this->enableClientValidation === null && $this->form->enableClientValidation;
if ($enableClientValidation) {
- $attribute = Html::getAttributeName($this->attribute);
$validators = array();
foreach ($this->model->getActiveValidators($attribute) as $validator) {
/** @var \yii\validators\Validator $validator */
From 2c30ddfcb0621e74552e7f6628cb092f666c5709 Mon Sep 17 00:00:00 2001
From: Carsten Brandt
Date: Tue, 1 Oct 2013 20:01:14 +0200
Subject: [PATCH 060/613] added web\Controller::goBack() as shortcut
goBack() will redirect user to his returnUrl
fixes #925
---
apps/basic/controllers/SiteController.php | 2 +-
framework/yii/web/Controller.php | 13 +++++++++++++
2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/apps/basic/controllers/SiteController.php b/apps/basic/controllers/SiteController.php
index 1196280..e243223 100644
--- a/apps/basic/controllers/SiteController.php
+++ b/apps/basic/controllers/SiteController.php
@@ -61,7 +61,7 @@ class SiteController extends Controller
{
$model = new LoginForm();
if ($model->load($_POST) && $model->login()) {
- return $this->goHome();
+ return $this->goBack();
} else {
return $this->render('login', array(
'model' => $model,
diff --git a/framework/yii/web/Controller.php b/framework/yii/web/Controller.php
index 6b8afa4..7509186 100644
--- a/framework/yii/web/Controller.php
+++ b/framework/yii/web/Controller.php
@@ -146,6 +146,19 @@ class Controller extends \yii\base\Controller
}
/**
+ * Redirects the browser to the last visited page.
+ * @param string|array $defaultUrl the default return URL in case it was not set previously.
+ * If this is null and the return URL was not set previously, [[Application::homeUrl]] will be redirected to.
+ * Please refer to [[User::setReturnUrl()]] on accepted format of the URL.
+ * @return Response the current response object
+ * @see User::getReturnUrl()
+ */
+ public function goBack($defaultUrl = null)
+ {
+ return Yii::$app->getResponse()->redirect(Yii::$app->getUser()->getReturnUrl($defaultUrl));
+ }
+
+ /**
* Refreshes the current page.
* This method is a shortcut to [[Response::refresh()]].
* @param string $anchor the anchor that should be appended to the redirection URL.
From 0035f23781750f2e598077e11fa8deb43b10bd21 Mon Sep 17 00:00:00 2001
From: Qiang Xue
Date: Tue, 1 Oct 2013 21:35:35 -0400
Subject: [PATCH 061/613] refactored data providers.
---
framework/yii/classes.php | 27 +--
framework/yii/data/ActiveDataProvider.php | 158 ++++---------
framework/yii/data/ArrayDataProvider.php | 104 +++------
framework/yii/data/BaseDataProvider.php | 253 +++++++++++++++++++++
framework/yii/data/DataProvider.php | 133 -----------
framework/yii/data/DataProviderInterface.php | 12 +
framework/yii/widgets/BaseListView.php | 1 +
.../unit/framework/data/ActiveDataProviderTest.php | 5 +-
8 files changed, 357 insertions(+), 336 deletions(-)
create mode 100644 framework/yii/data/BaseDataProvider.php
delete mode 100644 framework/yii/data/DataProvider.php
diff --git a/framework/yii/classes.php b/framework/yii/classes.php
index 1469910..78cce95 100644
--- a/framework/yii/classes.php
+++ b/framework/yii/classes.php
@@ -85,7 +85,7 @@ return array(
'yii\captcha\CaptchaValidator' => YII_PATH . '/captcha/CaptchaValidator.php',
'yii\data\ActiveDataProvider' => YII_PATH . '/data/ActiveDataProvider.php',
'yii\data\ArrayDataProvider' => YII_PATH . '/data/ArrayDataProvider.php',
- 'yii\data\DataProvider' => YII_PATH . '/data/DataProvider.php',
+ 'yii\data\BaseDataProvider' => YII_PATH . '/data/BaseDataProvider.php',
'yii\data\DataProviderInterface' => YII_PATH . '/data/DataProviderInterface.php',
'yii\data\Pagination' => YII_PATH . '/data/Pagination.php',
'yii\data\Sort' => YII_PATH . '/data/Sort.php',
@@ -118,6 +118,7 @@ return array(
'yii\db\pgsql\Schema' => YII_PATH . '/db/pgsql/Schema.php',
'yii\db\sqlite\QueryBuilder' => YII_PATH . '/db/sqlite/QueryBuilder.php',
'yii\db\sqlite\Schema' => YII_PATH . '/db/sqlite/Schema.php',
+ 'yii\grid\ActionColumn' => YII_PATH . '/grid/ActionColumn.php',
'yii\grid\CheckboxColumn' => YII_PATH . '/grid/CheckboxColumn.php',
'yii\grid\Column' => YII_PATH . '/grid/Column.php',
'yii\grid\DataColumn' => YII_PATH . '/grid/DataColumn.php',
@@ -126,26 +127,26 @@ return array(
'yii\grid\SerialColumn' => YII_PATH . '/grid/SerialColumn.php',
'yii\helpers\ArrayHelper' => YII_PATH . '/helpers/ArrayHelper.php',
'yii\helpers\BaseArrayHelper' => YII_PATH . '/helpers/BaseArrayHelper.php',
- 'yii\helpers\Console' => YII_PATH . '/helpers/Console.php',
'yii\helpers\BaseConsole' => YII_PATH . '/helpers/BaseConsole.php',
- 'yii\helpers\FileHelper' => YII_PATH . '/helpers/FileHelper.php',
'yii\helpers\BaseFileHelper' => YII_PATH . '/helpers/BaseFileHelper.php',
- 'yii\helpers\Html' => YII_PATH . '/helpers/Html.php',
'yii\helpers\BaseHtml' => YII_PATH . '/helpers/BaseHtml.php',
- 'yii\helpers\HtmlPurifier' => YII_PATH . '/helpers/HtmlPurifier.php',
'yii\helpers\BaseHtmlPurifier' => YII_PATH . '/helpers/BaseHtmlPurifier.php',
- 'yii\helpers\Inflector' => YII_PATH . '/helpers/Inflector.php',
'yii\helpers\BaseInflector' => YII_PATH . '/helpers/BaseInflector.php',
- 'yii\helpers\Json' => YII_PATH . '/helpers/Json.php',
'yii\helpers\BaseJson' => YII_PATH . '/helpers/BaseJson.php',
- 'yii\helpers\Markdown' => YII_PATH . '/helpers/Markdown.php',
'yii\helpers\BaseMarkdown' => YII_PATH . '/helpers/BaseMarkdown.php',
- 'yii\helpers\Security' => YII_PATH . '/helpers/Security.php',
'yii\helpers\BaseSecurity' => YII_PATH . '/helpers/BaseSecurity.php',
- 'yii\helpers\StringHelper' => YII_PATH . '/helpers/StringHelper.php',
'yii\helpers\BaseStringHelper' => YII_PATH . '/helpers/BaseStringHelper.php',
- 'yii\helpers\VarDumper' => YII_PATH . '/helpers/VarDumper.php',
'yii\helpers\BaseVarDumper' => YII_PATH . '/helpers/BaseVarDumper.php',
+ 'yii\helpers\Console' => YII_PATH . '/helpers/Console.php',
+ 'yii\helpers\FileHelper' => YII_PATH . '/helpers/FileHelper.php',
+ 'yii\helpers\Html' => YII_PATH . '/helpers/Html.php',
+ 'yii\helpers\HtmlPurifier' => YII_PATH . '/helpers/HtmlPurifier.php',
+ 'yii\helpers\Inflector' => YII_PATH . '/helpers/Inflector.php',
+ 'yii\helpers\Json' => YII_PATH . '/helpers/Json.php',
+ 'yii\helpers\Markdown' => YII_PATH . '/helpers/Markdown.php',
+ 'yii\helpers\Security' => YII_PATH . '/helpers/Security.php',
+ 'yii\helpers\StringHelper' => YII_PATH . '/helpers/StringHelper.php',
+ 'yii\helpers\VarDumper' => YII_PATH . '/helpers/VarDumper.php',
'yii\i18n\DbMessageSource' => YII_PATH . '/i18n/DbMessageSource.php',
'yii\i18n\Formatter' => YII_PATH . '/i18n/Formatter.php',
'yii\i18n\GettextFile' => YII_PATH . '/i18n/GettextFile.php',
@@ -194,6 +195,7 @@ return array(
'yii\web\Application' => YII_PATH . '/web/Application.php',
'yii\web\AssetBundle' => YII_PATH . '/web/AssetBundle.php',
'yii\web\AssetConverter' => YII_PATH . '/web/AssetConverter.php',
+ 'yii\web\AssetConverterInterface' => YII_PATH . '/web/AssetConverterInterface.php',
'yii\web\AssetManager' => YII_PATH . '/web/AssetManager.php',
'yii\web\CacheSession' => YII_PATH . '/web/CacheSession.php',
'yii\web\Controller' => YII_PATH . '/web/Controller.php',
@@ -204,7 +206,6 @@ return array(
'yii\web\HeaderCollection' => YII_PATH . '/web/HeaderCollection.php',
'yii\web\HttpCache' => YII_PATH . '/web/HttpCache.php',
'yii\web\HttpException' => YII_PATH . '/web/HttpException.php',
- 'yii\web\AssetConverterInterface' => YII_PATH . '/web/AssetConverterInterface.php',
'yii\web\IdentityInterface' => YII_PATH . '/web/IdentityInterface.php',
'yii\web\JqueryAsset' => YII_PATH . '/web/JqueryAsset.php',
'yii\web\JsExpression' => YII_PATH . '/web/JsExpression.php',
@@ -226,6 +227,7 @@ return array(
'yii\widgets\ActiveField' => YII_PATH . '/widgets/ActiveField.php',
'yii\widgets\ActiveForm' => YII_PATH . '/widgets/ActiveForm.php',
'yii\widgets\ActiveFormAsset' => YII_PATH . '/widgets/ActiveFormAsset.php',
+ 'yii\widgets\BaseListView' => YII_PATH . '/widgets/BaseListView.php',
'yii\widgets\Block' => YII_PATH . '/widgets/Block.php',
'yii\widgets\Breadcrumbs' => YII_PATH . '/widgets/Breadcrumbs.php',
'yii\widgets\ContentDecorator' => YII_PATH . '/widgets/ContentDecorator.php',
@@ -235,7 +237,6 @@ return array(
'yii\widgets\LinkPager' => YII_PATH . '/widgets/LinkPager.php',
'yii\widgets\LinkSorter' => YII_PATH . '/widgets/LinkSorter.php',
'yii\widgets\ListView' => YII_PATH . '/widgets/ListView.php',
- 'yii\widgets\BaseListView' => YII_PATH . '/widgets/BaseListView.php',
'yii\widgets\MaskedInput' => YII_PATH . '/widgets/MaskedInput.php',
'yii\widgets\MaskedInputAsset' => YII_PATH . '/widgets/MaskedInputAsset.php',
'yii\widgets\Menu' => YII_PATH . '/widgets/Menu.php',
diff --git a/framework/yii/data/ActiveDataProvider.php b/framework/yii/data/ActiveDataProvider.php
index 2fe0efb..c5f1bcd 100644
--- a/framework/yii/data/ActiveDataProvider.php
+++ b/framework/yii/data/ActiveDataProvider.php
@@ -48,16 +48,10 @@ use yii\db\Connection;
* $posts = $provider->getModels();
* ~~~
*
- * @property integer $count The number of data models in the current page. This property is read-only.
- * @property array $keys The list of key values corresponding to [[models]]. Each data model in [[models]] is
- * uniquely identified by the corresponding key value in this array. This property is read-only.
- * @property array $models The list of data models in the current page. This property is read-only.
- * @property integer $totalCount Total number of possible data models.
- *
* @author Qiang Xue
* @since 2.0
*/
-class ActiveDataProvider extends DataProvider
+class ActiveDataProvider extends BaseDataProvider
{
/**
* @var Query the query that is used to fetch data models and [[totalCount]]
@@ -82,10 +76,6 @@ class ActiveDataProvider extends DataProvider
*/
public $db;
- private $_models;
- private $_keys;
- private $_totalCount;
-
/**
* Initializes the DbCache component.
* This method will initialize the [[db]] property to make sure it refers to a valid DB connection.
@@ -103,122 +93,72 @@ class ActiveDataProvider extends DataProvider
}
/**
- * Returns the number of data models in the current page.
- * This is equivalent to `count($provider->models)`.
- * When [[pagination]] is false, this is the same as [[totalCount]].
- * @return integer the number of data models in the current page.
- */
- public function getCount()
- {
- return count($this->getModels());
- }
-
- /**
- * Returns the total number of data models.
- * When [[pagination]] is false, this returns the same value as [[count]].
- * If [[totalCount]] is not explicitly set, it will be calculated
- * using [[query]] with a COUNT query.
- * @return integer total number of possible data models.
- * @throws InvalidConfigException
+ * @inheritdoc
*/
- public function getTotalCount()
+ protected function prepareModels()
{
- if ($this->getPagination() === false) {
- return $this->getCount();
- } elseif ($this->_totalCount === null) {
- if (!$this->query instanceof Query) {
- throw new InvalidConfigException('The "query" property must be an instance of Query or its subclass.');
- }
- $query = clone $this->query;
- $this->_totalCount = $query->limit(-1)->offset(-1)->count('*', $this->db);
+ if (!$this->query instanceof Query) {
+ throw new InvalidConfigException('The "query" property must be an instance of Query or its subclass.');
}
- return $this->_totalCount;
- }
-
- /**
- * Sets the total number of data models.
- * @param integer $value the total number of data models.
- */
- public function setTotalCount($value)
- {
- $this->_totalCount = $value;
- }
-
- /**
- * Returns the data models in the current page.
- * @return array the list of data models in the current page.
- * @throws InvalidConfigException if [[query]] is not set or invalid.
- */
- public function getModels()
- {
- if ($this->_models === null) {
- if (!$this->query instanceof Query) {
- throw new InvalidConfigException('The "query" property must be an instance of Query or its subclass.');
- }
- if (($pagination = $this->getPagination()) !== false) {
- $this->query->limit($pagination->getLimit())->offset($pagination->getOffset());
- }
- if (($sort = $this->getSort()) !== false) {
- $this->query->addOrderBy($sort->getOrders());
- }
- $this->_models = $this->query->all($this->db);
+ if (($pagination = $this->getPagination()) !== false) {
+ $pagination->totalCount = $this->getTotalCount();
+ $this->query->limit($pagination->getLimit())->offset($pagination->getOffset());
+ }
+ if (($sort = $this->getSort()) !== false) {
+ $this->query->addOrderBy($sort->getOrders());
}
- return $this->_models;
+ return $this->query->all($this->db);
}
/**
- * Returns the key values associated with the data models.
- * @return array the list of key values corresponding to [[models]]. Each data model in [[models]]
- * is uniquely identified by the corresponding key value in this array.
+ * @inheritdoc
*/
- public function getKeys()
+ protected function prepareKeys($models)
{
- if ($this->_keys === null) {
- $this->_keys = array();
- $models = $this->getModels();
- if ($this->key !== null) {
+ $keys = array();
+ if ($this->key !== null) {
+ foreach ($models as $model) {
+ if (is_string($this->key)) {
+ $keys[] = $model[$this->key];
+ } else {
+ $keys[] = call_user_func($this->key, $model);
+ }
+ }
+ return $keys;
+ } elseif ($this->query instanceof ActiveQuery) {
+ /** @var \yii\db\ActiveRecord $class */
+ $class = $this->query->modelClass;
+ $pks = $class::primaryKey();
+ if (count($pks) === 1) {
+ $pk = $pks[0];
foreach ($models as $model) {
- if (is_string($this->key)) {
- $this->_keys[] = $model[$this->key];
- } else {
- $this->_keys[] = call_user_func($this->key, $model);
- }
+ $keys[] = $model[$pk];
}
- } elseif ($this->query instanceof ActiveQuery) {
- /** @var \yii\db\ActiveRecord $class */
- $class = $this->query->modelClass;
- $pks = $class::primaryKey();
- if (count($pks) === 1) {
- $pk = $pks[0];
- foreach ($models as $model) {
- $this->_keys[] = $model[$pk];
- }
- } else {
- foreach ($models as $model) {
- $keys = array();
- foreach ($pks as $pk) {
- $keys[] = $model[$pk];
- }
- $this->_keys[] = json_encode($keys);
+ } else {
+ foreach ($models as $model) {
+ $kk = array();
+ foreach ($pks as $pk) {
+ $kk[] = $model[$pk];
}
+ $keys[] = json_encode($kk);
}
- } else {
- $this->_keys = array_keys($models);
}
+ return $keys;
+ } else {
+ return array_keys($models);
}
- return $this->_keys;
}
/**
- * Refreshes the data provider.
- * After calling this method, if [[getModels()]], [[getKeys()]] or [[getTotalCount()]] is called again,
- * they will re-execute the query and return the latest data available.
+ * @inheritdoc
*/
- public function refresh()
+ protected function prepareTotalCount()
{
- $this->_models = null;
- $this->_totalCount = null;
- $this->_keys = null;
+ if (!$this->query instanceof Query) {
+ throw new InvalidConfigException('The "query" property must be an instance of Query or its subclass.');
+ }
+ $query = clone $this->query;
+ return $query->limit(-1)->offset(-1)->count('*', $this->db);
}
/**
@@ -227,9 +167,7 @@ class ActiveDataProvider extends DataProvider
public function setSort($value)
{
parent::setSort($value);
- if (($sort = $this->getSort()) !== false && empty($sort->attributes) &&
- $this->query instanceof ActiveQuery) {
-
+ if (($sort = $this->getSort()) !== false && empty($sort->attributes) && $this->query instanceof ActiveQuery) {
/** @var Model $model */
$model = new $this->query->modelClass;
foreach($model->attributes() as $attribute) {
diff --git a/framework/yii/data/ArrayDataProvider.php b/framework/yii/data/ArrayDataProvider.php
index 9534803..925c18e 100644
--- a/framework/yii/data/ArrayDataProvider.php
+++ b/framework/yii/data/ArrayDataProvider.php
@@ -47,15 +47,10 @@ use yii\helpers\ArrayHelper;
* Note: if you want to use the sorting feature, you must configure the [[sort]] property
* so that the provider knows which columns can be sorted.
*
- * @property array $keys The list of key values corresponding to [[models]]. Each data model in [[models]] is
- * uniquely identified by the corresponding key value in this array.
- * @property array $models The list of data models in the current page.
- * @property integer $totalCount Total number of possible data models.
- *
* @author Qiang Xue
* @since 2.0
*/
-class ArrayDataProvider extends DataProvider
+class ArrayDataProvider extends BaseDataProvider
{
/**
* @var string|callable the column that is used as the key of the data models.
@@ -71,100 +66,53 @@ class ArrayDataProvider extends DataProvider
*/
public $allModels;
- private $_totalCount;
/**
- * Returns the total number of data models.
- * @return integer total number of possible data models.
+ * @inheritdoc
*/
- public function getTotalCount()
+ protected function prepareModels()
{
- if ($this->getPagination() === false) {
- return $this->getCount();
- } elseif ($this->_totalCount === null) {
- $this->_totalCount = count($this->allModels);
+ if (($models = $this->allModels) === null) {
+ return array();
}
- return $this->_totalCount;
- }
-
- /**
- * Sets the total number of data models.
- * @param integer $value the total number of data models.
- */
- public function setTotalCount($value)
- {
- $this->_totalCount = $value;
- }
-
- private $_models;
- /**
- * Returns the data models in the current page.
- * @return array the list of data models in the current page.
- */
- public function getModels()
- {
- if ($this->_models === null) {
- if (($models = $this->allModels) === null) {
- return array();
- }
-
- if (($sort = $this->getSort()) !== false) {
- $models = $this->sortModels($models, $sort);
- }
-
- if (($pagination = $this->getPagination()) !== false) {
- $models = array_slice($models, $pagination->getOffset(), $pagination->getLimit());
- }
+ if (($sort = $this->getSort()) !== false) {
+ $models = $this->sortModels($models, $sort);
+ }
- $this->_models = $models;
+ if (($pagination = $this->getPagination()) !== false) {
+ $models = array_slice($models, $pagination->getOffset(), $pagination->getLimit());
}
- return $this->_models;
- }
- /**
- * Sets the data models in the current page.
- * @param array $models the models in the current page
- */
- public function setModels($models)
- {
- $this->_models = $models;
+ return $models;
}
- private $_keys;
-
/**
- * Returns the key values associated with the data models.
- * @return array the list of key values corresponding to [[models]]. Each data model in [[models]]
- * is uniquely identified by the corresponding key value in this array.
+ * @inheritdoc
*/
- public function getKeys()
+ protected function prepareKeys($models)
{
- if ($this->_keys === null) {
- $this->_keys = array();
- $models = $this->getModels();
- if ($this->key !== null) {
- foreach ($models as $model) {
- if (is_string($this->key)) {
- $this->_keys[] = $model[$this->key];
- } else {
- $this->_keys[] = call_user_func($this->key, $model);
- }
+ if ($this->key !== null) {
+ $keys = array();
+ foreach ($models as $model) {
+ if (is_string($this->key)) {
+ $keys[] = $model[$this->key];
+ } else {
+ $keys[] = call_user_func($this->key, $model);
}
- } else {
- $this->_keys = array_keys($models);
}
+ return $keys;
+ } else {
+ return array_keys($models);
}
- return $this->_keys;
}
/**
- * Sets the key values associated with the data models.
- * @param array $keys the list of key values corresponding to [[models]].
+ * @inheritdoc
*/
- public function setKeys($keys)
+ protected function prepareTotalCount()
{
- $this->_keys = $keys;
+ return count($this->allModels);
}
/**
diff --git a/framework/yii/data/BaseDataProvider.php b/framework/yii/data/BaseDataProvider.php
new file mode 100644
index 0000000..15705b7
--- /dev/null
+++ b/framework/yii/data/BaseDataProvider.php
@@ -0,0 +1,253 @@
+
+ * @since 2.0
+ */
+abstract class BaseDataProvider extends Component implements DataProviderInterface
+{
+ /**
+ * @var string an ID that uniquely identifies the data provider among all data providers.
+ * You should set this property if the same page contains two or more different data providers.
+ * Otherwise, the [[pagination]] and [[sort]] mainly not work properly.
+ */
+ public $id;
+
+ private $_sort;
+ private $_pagination;
+ private $_keys;
+ private $_models;
+ private $_totalCount;
+
+
+ /**
+ * Prepares the data models that will be made available in the current page.
+ * @return array the available data models
+ */
+ abstract protected function prepareModels();
+
+ /**
+ * Prepares the keys associated with the currently available data models.
+ * @param array $models the available data models
+ * @return array the keys
+ */
+ abstract protected function prepareKeys($models);
+
+ /**
+ * Returns a value indicating the total number of data models in this data provider.
+ * @return integer total number of data models in this data provider.
+ */
+ abstract protected function prepareTotalCount();
+
+ /**
+ * Prepares the data models and keys.
+ *
+ * This method will prepare the data models and keys that can be retrieved via
+ * [[getModels()]] and [[getKeys()]].
+ *
+ * This method will be implicitly called by [[getModels()]] and [[getKeys()]] if it has not been called before.
+ *
+ * @param boolean $forcePrepare whether to force data preparation even if it has been done before.
+ */
+ public function prepare($forcePrepare = false)
+ {
+ if ($forcePrepare || $this->_models === null) {
+ $this->_models = $this->prepareModels();
+ }
+ if ($forcePrepare || $this->_keys === null) {
+ $this->_keys = $this->prepareKeys($this->_models);
+ }
+ }
+
+ /**
+ * Returns the data models in the current page.
+ * @return array the list of data models in the current page.
+ */
+ public function getModels()
+ {
+ $this->prepare();
+ return $this->_models;
+ }
+
+ /**
+ * Sets the data models in the current page.
+ * @param array $models the models in the current page
+ */
+ public function setModels($models)
+ {
+ $this->_models = $models;
+ }
+
+ /**
+ * Returns the key values associated with the data models.
+ * @return array the list of key values corresponding to [[models]]. Each data model in [[models]]
+ * is uniquely identified by the corresponding key value in this array.
+ */
+ public function getKeys()
+ {
+ $this->prepare();
+ return $this->_keys;
+ }
+
+ /**
+ * Sets the key values associated with the data models.
+ * @param array $keys the list of key values corresponding to [[models]].
+ */
+ public function setKeys($keys)
+ {
+ $this->_keys = $keys;
+ }
+
+ /**
+ * Returns the number of data models in the current page.
+ * @return integer the number of data models in the current page.
+ */
+ public function getCount()
+ {
+ return count($this->getModels());
+ }
+
+ /**
+ * Returns the total number of data models.
+ * When [[pagination]] is false, this returns the same value as [[count]].
+ * Otherwise, it will call [[prepareTotalCount()]] to get the count.
+ * @return integer total number of possible data models.
+ */
+ public function getTotalCount()
+ {
+ if ($this->getPagination() === false) {
+ return $this->getCount();
+ } elseif ($this->_totalCount === null) {
+ $this->_totalCount = $this->prepareTotalCount();
+ }
+ return $this->_totalCount;
+ }
+
+ /**
+ * Sets the total number of data models.
+ * @param integer $value the total number of data models.
+ */
+ public function setTotalCount($value)
+ {
+ $this->_totalCount = $value;
+ }
+
+ /**
+ * @return Pagination|boolean the pagination object. If this is false, it means the pagination is disabled.
+ */
+ public function getPagination()
+ {
+ if ($this->_pagination === null) {
+ $this->_pagination = new Pagination;
+ if ($this->id !== null) {
+ $this->_pagination->pageVar = $this->id . '-page';
+ }
+ }
+ return $this->_pagination;
+ }
+
+ /**
+ * Sets the pagination for this data provider.
+ * @param array|Pagination|boolean $value the pagination to be used by this data provider.
+ * This can be one of the following:
+ *
+ * - a configuration array for creating the pagination object. The "class" element defaults
+ * to 'yii\data\Pagination'
+ * - an instance of [[Pagination]] or its subclass
+ * - false, if pagination needs to be disabled.
+ *
+ * @throws InvalidParamException
+ */
+ public function setPagination($value)
+ {
+ if (is_array($value)) {
+ $config = array(
+ 'class' => Pagination::className(),
+ );
+ if ($this->id !== null) {
+ $config['pageVar'] = $this->id . '-page';
+ }
+ $this->_pagination = Yii::createObject(array_merge($config, $value));
+ } elseif ($value instanceof Pagination || $value === false) {
+ $this->_pagination = $value;
+ } else {
+ throw new InvalidParamException('Only Pagination instance, configuration array or false is allowed.');
+ }
+ }
+
+ /**
+ * @return Sort|boolean the sorting object. If this is false, it means the sorting is disabled.
+ */
+ public function getSort()
+ {
+ if ($this->_sort === null) {
+ $this->setSort(array());
+ }
+ return $this->_sort;
+ }
+
+ /**
+ * Sets the sort definition for this data provider.
+ * @param array|Sort|boolean $value the sort definition to be used by this data provider.
+ * This can be one of the following:
+ *
+ * - a configuration array for creating the sort definition object. The "class" element defaults
+ * to 'yii\data\Sort'
+ * - an instance of [[Sort]] or its subclass
+ * - false, if sorting needs to be disabled.
+ *
+ * @throws InvalidParamException
+ */
+ public function setSort($value)
+ {
+ if (is_array($value)) {
+ $config = array(
+ 'class' => Sort::className(),
+ );
+ if ($this->id !== null) {
+ $config['sortVar'] = $this->id . '-sort';
+ }
+ $this->_sort = Yii::createObject(array_merge($config, $value));
+ } elseif ($value instanceof Sort || $value === false) {
+ $this->_sort = $value;
+ } else {
+ throw new InvalidParamException('Only Sort instance, configuration array or false is allowed.');
+ }
+ }
+
+ /**
+ * Refreshes the data provider.
+ * After calling this method, if [[getModels()]], [[getKeys()]] or [[getTotalCount()]] is called again,
+ * they will re-execute the query and return the latest data available.
+ */
+ public function refresh()
+ {
+ $this->_totalCount = null;
+ $this->_models = null;
+ $this->_keys = null;
+ }
+}
diff --git a/framework/yii/data/DataProvider.php b/framework/yii/data/DataProvider.php
deleted file mode 100644
index d75be6f..0000000
--- a/framework/yii/data/DataProvider.php
+++ /dev/null
@@ -1,133 +0,0 @@
-
- * @since 2.0
- */
-abstract class DataProvider extends Component implements DataProviderInterface
-{
- /**
- * @var string an ID that uniquely identifies the data provider among all data providers.
- * You should set this property if the same page contains two or more different data providers.
- * Otherwise, the [[pagination]] and [[sort]] mainly not work properly.
- */
- public $id;
-
- private $_sort;
- private $_pagination;
-
- /**
- * @return Pagination|boolean the pagination object. If this is false, it means the pagination is disabled.
- */
- public function getPagination()
- {
- if ($this->_pagination === null) {
- $this->_pagination = new Pagination;
- if ($this->id !== null) {
- $this->_pagination->pageVar = $this->id . '-page';
- }
- $this->_pagination->totalCount = $this->getTotalCount();
- }
- return $this->_pagination;
- }
-
- /**
- * Sets the pagination for this data provider.
- * @param array|Pagination|boolean $value the pagination to be used by this data provider.
- * This can be one of the following:
- *
- * - a configuration array for creating the pagination object. The "class" element defaults
- * to 'yii\data\Pagination'
- * - an instance of [[Pagination]] or its subclass
- * - false, if pagination needs to be disabled.
- *
- * @throws InvalidParamException
- */
- public function setPagination($value)
- {
- if (is_array($value)) {
- $config = array(
- 'class' => Pagination::className(),
- );
- if ($this->id !== null) {
- $config['pageVar'] = $this->id . '-page';
- }
- $this->_pagination = Yii::createObject(array_merge($config, $value));
- } elseif ($value instanceof Pagination || $value === false) {
- $this->_pagination = $value;
- } else {
- throw new InvalidParamException('Only Pagination instance, configuration array or false is allowed.');
- }
- }
-
- /**
- * @return Sort|boolean the sorting object. If this is false, it means the sorting is disabled.
- */
- public function getSort()
- {
- if ($this->_sort === null) {
- $this->setSort(array());
- }
- return $this->_sort;
- }
-
- /**
- * Sets the sort definition for this data provider.
- * @param array|Sort|boolean $value the sort definition to be used by this data provider.
- * This can be one of the following:
- *
- * - a configuration array for creating the sort definition object. The "class" element defaults
- * to 'yii\data\Sort'
- * - an instance of [[Sort]] or its subclass
- * - false, if sorting needs to be disabled.
- *
- * @throws InvalidParamException
- */
- public function setSort($value)
- {
- if (is_array($value)) {
- $config = array(
- 'class' => Sort::className(),
- );
- if ($this->id !== null) {
- $config['sortVar'] = $this->id . '-sort';
- }
- $this->_sort = Yii::createObject(array_merge($config, $value));
- } elseif ($value instanceof Sort || $value === false) {
- $this->_sort = $value;
- } else {
- throw new InvalidParamException('Only Sort instance, configuration array or false is allowed.');
- }
- }
-
- /**
- * Returns the number of data models in the current page.
- * @return integer the number of data models in the current page.
- */
- public function getCount()
- {
- return count($this->getModels());
- }
-}
diff --git a/framework/yii/data/DataProviderInterface.php b/framework/yii/data/DataProviderInterface.php
index f0bc39d..1dea1e6 100644
--- a/framework/yii/data/DataProviderInterface.php
+++ b/framework/yii/data/DataProviderInterface.php
@@ -19,6 +19,18 @@ namespace yii\data;
interface DataProviderInterface
{
/**
+ * Prepares the data models and keys.
+ *
+ * This method will prepare the data models and keys that can be retrieved via
+ * [[getModels()]] and [[getKeys()]].
+ *
+ * This method will be implicitly called by [[getModels()]] and [[getKeys()]] if it has not been called before.
+ *
+ * @param boolean $forcePrepare whether to force data preparation even if it has been done before.
+ */
+ public function prepare($forcePrepare = false);
+
+ /**
* Returns the number of data models in the current page.
* This is equivalent to `count($provider->getModels())`.
* When [[pagination]] is false, this is the same as [[totalCount]].
diff --git a/framework/yii/widgets/BaseListView.php b/framework/yii/widgets/BaseListView.php
index 7268fbc..d4647ff 100644
--- a/framework/yii/widgets/BaseListView.php
+++ b/framework/yii/widgets/BaseListView.php
@@ -83,6 +83,7 @@ abstract class BaseListView extends Widget
if ($this->dataProvider === null) {
throw new InvalidConfigException('The "dataProvider" property must be set.');
}
+ $this->dataProvider->prepare();
}
/**
diff --git a/tests/unit/framework/data/ActiveDataProviderTest.php b/tests/unit/framework/data/ActiveDataProviderTest.php
index 79c0a39..276c525 100644
--- a/tests/unit/framework/data/ActiveDataProviderTest.php
+++ b/tests/unit/framework/data/ActiveDataProviderTest.php
@@ -94,9 +94,10 @@ class ActiveDataProviderTest extends DatabaseTestCase
'query' => $query->from('tbl_order')->orderBy('id'),
));
$pagination = $provider->getPagination();
- $this->assertEquals(1, $pagination->getPageCount());
+ $this->assertEquals(0, $pagination->getPageCount());
$this->assertCount(3, $provider->getModels());
-
+ $this->assertEquals(1, $pagination->getPageCount());
+
$provider->getPagination()->pageSize = 2;
$this->assertEquals(3, count($provider->getModels()));
$provider->refresh();
From fe58cbd56a02af1dcd349356de5585ec78287bd3 Mon Sep 17 00:00:00 2001
From: Qiang Xue
Date: Tue, 1 Oct 2013 21:35:56 -0400
Subject: [PATCH 062/613] doc update.
---
framework/yii/web/AssetManager.php | 4 ++--
framework/yii/web/Request.php | 2 ++
framework/yii/web/User.php | 4 ++--
3 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/framework/yii/web/AssetManager.php b/framework/yii/web/AssetManager.php
index 500848b..35e555f 100644
--- a/framework/yii/web/AssetManager.php
+++ b/framework/yii/web/AssetManager.php
@@ -16,8 +16,8 @@ use yii\helpers\FileHelper;
/**
* AssetManager manages asset bundles and asset publishing.
*
- * @property AssetConverterInterface $converter The asset converter. Note that the type of this property differs in
- * getter and setter. See [[getConverter()]] and [[setConverter()]] for details.
+ * @property AssetConverterInterface $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
diff --git a/framework/yii/web/Request.php b/framework/yii/web/Request.php
index 4fb6257..e5d9477 100644
--- a/framework/yii/web/Request.php
+++ b/framework/yii/web/Request.php
@@ -29,6 +29,8 @@ use yii\helpers\Security;
* 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 $csrfTokenFromHeader The CSRF token sent via [[CSRF_HEADER]] by browser. Null is returned
+ * if no such header is sent. 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.
diff --git a/framework/yii/web/User.php b/framework/yii/web/User.php
index f6a9bc8..0dd16d0 100644
--- a/framework/yii/web/User.php
+++ b/framework/yii/web/User.php
@@ -23,8 +23,8 @@ use yii\base\InvalidParamException;
*
* @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 IdentityInterface $identity The identity object associated with the currently logged user. Null is
- * returned if the user is not logged in (not authenticated).
+ * @property IdentityInterface $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.
From d798cc791b4c1195a042848485279e19fdebe589 Mon Sep 17 00:00:00 2001
From: Qiang Xue
Date: Tue, 1 Oct 2013 21:40:35 -0400
Subject: [PATCH 063/613] Set totalCount.
---
framework/yii/data/ArrayDataProvider.php | 1 +
1 file changed, 1 insertion(+)
diff --git a/framework/yii/data/ArrayDataProvider.php b/framework/yii/data/ArrayDataProvider.php
index 925c18e..77f31cd 100644
--- a/framework/yii/data/ArrayDataProvider.php
+++ b/framework/yii/data/ArrayDataProvider.php
@@ -81,6 +81,7 @@ class ArrayDataProvider extends BaseDataProvider
}
if (($pagination = $this->getPagination()) !== false) {
+ $pagination->totalCount = $this->getTotalCount();
$models = array_slice($models, $pagination->getOffset(), $pagination->getLimit());
}
From 09a91910866ef97bf78733ce70e995d666e69fee Mon Sep 17 00:00:00 2001
From: Qiang Xue
Date: Tue, 1 Oct 2013 21:56:08 -0400
Subject: [PATCH 064/613] Fixes #927: doc typo.
---
framework/yii/log/FileTarget.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/framework/yii/log/FileTarget.php b/framework/yii/log/FileTarget.php
index 970c71b..5aa4c12 100644
--- a/framework/yii/log/FileTarget.php
+++ b/framework/yii/log/FileTarget.php
@@ -78,7 +78,7 @@ class FileTarget extends Target
}
/**
- * Sends log messages to specified email addresses.
+ * Writes log messages to a file.
* @throws InvalidConfigException if unable to open the log file for writing
*/
public function export()
From c1f977cd459eb9997484d577de307c741305f0d4 Mon Sep 17 00:00:00 2001
From: Qiang Xue
Date: Tue, 1 Oct 2013 22:57:08 -0400
Subject: [PATCH 065/613] Simplified the default file map for PhpMessageSource.
---
framework/yii/i18n/PhpMessageSource.php | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/framework/yii/i18n/PhpMessageSource.php b/framework/yii/i18n/PhpMessageSource.php
index f62939f..1cd2103 100644
--- a/framework/yii/i18n/PhpMessageSource.php
+++ b/framework/yii/i18n/PhpMessageSource.php
@@ -26,6 +26,8 @@ use Yii;
* );
* ~~~
*
+ * You may use [[fileMap]] to customize the association between category names and the file names.
+ *
* @author Qiang Xue
* @since 2.0
*/
@@ -60,10 +62,8 @@ class PhpMessageSource extends MessageSource
$messageFile = Yii::getAlias($this->basePath) . "/$language/";
if (isset($this->fileMap[$category])) {
$messageFile .= $this->fileMap[$category];
- } elseif (($pos = strrpos($category, '\\')) !== false) {
- $messageFile .= (substr($category, $pos) . '.php');
} else {
- $messageFile .= "$category.php";
+ $messageFile .= str_replace('\\', '/', $category) . '.php';
}
if (is_file($messageFile)) {
$messages = include($messageFile);
From 3f88320595023696fdbd30af625f325dac444a57 Mon Sep 17 00:00:00 2001
From: Carsten Brandt
Date: Wed, 2 Oct 2013 12:27:04 +0200
Subject: [PATCH 066/613] second try to fix random memcache failure on travis
issue #877
---
tests/unit/framework/caching/CacheTestCase.php | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/tests/unit/framework/caching/CacheTestCase.php b/tests/unit/framework/caching/CacheTestCase.php
index 480941f..542999a 100644
--- a/tests/unit/framework/caching/CacheTestCase.php
+++ b/tests/unit/framework/caching/CacheTestCase.php
@@ -145,14 +145,9 @@ abstract class CacheTestCase extends TestCase
$cache = $this->getCacheInstance();
$this->assertTrue($cache->set('expire_test', 'expire_test', 2));
- sleep(1);
+ usleep(500000);
$this->assertEquals('expire_test', $cache->get('expire_test'));
- // wait a bit more than 2 sec to avoid random test failure
- if (isset($_ENV['TRAVIS']) && substr(StringHelper::basename(get_class($this)), 0, 8) == 'MemCache') {
- sleep(3); // usleep with 2,5 seconds does not work well on travis and memcache
- } else {
- usleep(2500000);
- }
+ usleep(2500000);
$this->assertFalse($cache->get('expire_test'));
}
From bcc0cbeba8648eb8eb41c4c5becc654bb476bc3d Mon Sep 17 00:00:00 2001
From: Qiang Xue
Date: Wed, 2 Oct 2013 08:29:52 -0400
Subject: [PATCH 067/613] Added doc about BaseDataProvider::getPagination().
---
framework/yii/data/BaseDataProvider.php | 3 +++
1 file changed, 3 insertions(+)
diff --git a/framework/yii/data/BaseDataProvider.php b/framework/yii/data/BaseDataProvider.php
index 15705b7..3b0669d 100644
--- a/framework/yii/data/BaseDataProvider.php
+++ b/framework/yii/data/BaseDataProvider.php
@@ -157,6 +157,9 @@ abstract class BaseDataProvider extends Component implements DataProviderInterfa
}
/**
+ * Returns the pagination object used by this data provider.
+ * Note that you should call [[prepare()]] or [[getModels()]] first to get correct values
+ * of [[Pagination::totalCount]] and [[Pagination::pageCount]].
* @return Pagination|boolean the pagination object. If this is false, it means the pagination is disabled.
*/
public function getPagination()
From 618f9811123e680cba38616a18305bdd27136778 Mon Sep 17 00:00:00 2001
From: Alexander Makarov
Date: Thu, 3 Oct 2013 01:41:38 +0400
Subject: [PATCH 068/613] Renamed i18n to be all lowecase when accessed as a
property
---
framework/yii/BaseYii.php | 2 +-
framework/yii/base/Application.php | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/framework/yii/BaseYii.php b/framework/yii/BaseYii.php
index b586160..cf94166 100644
--- a/framework/yii/BaseYii.php
+++ b/framework/yii/BaseYii.php
@@ -541,7 +541,7 @@ class BaseYii
public static function t($category, $message, $params = array(), $language = null)
{
if (self::$app !== null) {
- return self::$app->getI18N()->translate($category, $message, $params, $language ?: self::$app->language);
+ return self::$app->getI18n()->translate($category, $message, $params, $language ?: self::$app->language);
} else {
return is_array($params) ? strtr($message, $params) : $message;
}
diff --git a/framework/yii/base/Application.php b/framework/yii/base/Application.php
index e8c496c..3cc90d9 100644
--- a/framework/yii/base/Application.php
+++ b/framework/yii/base/Application.php
@@ -383,7 +383,7 @@ abstract class Application extends Module
* Returns the internationalization (i18n) component
* @return \yii\i18n\I18N the internationalization component
*/
- public function getI18N()
+ public function getI18n()
{
return $this->getComponent('i18n');
}
From 6fc5f0a4caceaddbc10daa775d24fb0d399817ae Mon Sep 17 00:00:00 2001
From: Alexander Makarov
Date: Thu, 3 Oct 2013 01:54:58 +0400
Subject: [PATCH 069/613] Minor additions to i18n docs
---
docs/guide/i18n.md | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/docs/guide/i18n.md b/docs/guide/i18n.md
index 6532717..2e17ce0 100644
--- a/docs/guide/i18n.md
+++ b/docs/guide/i18n.md
@@ -39,14 +39,17 @@ Later you can easily change it in runtime:
Basic message translation
-------------------------
-### Strings translation
-
-Yii basic message translation that works without additional PHP extension.
+Yii basic message translation in its basic variant works without additional PHP extension. What it does is finding a
+translation of the message from source language into targer language. Message itself is specified as the first
+`\Yii::t` method parameter:
```php
echo \Yii::t('app', 'This is a string to translate!');
```
+Yii tries to load approprite translation from one of the message sources defined via `i18n` component configuration.
+
+TBD: https://github.com/yiisoft/yii2/issues/930
### Named placeholders
From 8c9dadf36212bff6fef815a930dbcda4a4263bf5 Mon Sep 17 00:00:00 2001
From: Qiang Xue
Date: Wed, 2 Oct 2013 21:22:25 -0400
Subject: [PATCH 070/613] Fixed DB validation handling for model generator.
---
framework/yii/gii/generators/model/Generator.php | 3 +++
1 file changed, 3 insertions(+)
diff --git a/framework/yii/gii/generators/model/Generator.php b/framework/yii/gii/generators/model/Generator.php
index b9c8f23..7fba83f 100644
--- a/framework/yii/gii/generators/model/Generator.php
+++ b/framework/yii/gii/generators/model/Generator.php
@@ -464,6 +464,9 @@ class Generator extends \yii\gii\Generator
return $this->_tableNames;
}
$db = $this->getDbConnection();
+ if ($db === null) {
+ return array();
+ }
$tableNames = array();
if (strpos($this->tableName, '*') !== false) {
if (($pos = strrpos($this->tableName, '.')) !== false) {
From 38c0b197f9a10c9caec82dd4de194002f8219fa2 Mon Sep 17 00:00:00 2001
From: Qiang Xue
Date: Thu, 3 Oct 2013 11:01:52 -0400
Subject: [PATCH 071/613] Fixes #916: generation of class name from table name
has problem.
---
framework/yii/gii/generators/model/Generator.php | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/framework/yii/gii/generators/model/Generator.php b/framework/yii/gii/generators/model/Generator.php
index 7fba83f..69edb5f 100644
--- a/framework/yii/gii/generators/model/Generator.php
+++ b/framework/yii/gii/generators/model/Generator.php
@@ -514,7 +514,8 @@ class Generator extends \yii\gii\Generator
$patterns[] = '/^' . str_replace('*', '(\w+)', $pattern) . '$/';
}
if (!empty($db->tablePrefix)) {
- $patterns[] = "/^{$db->tablePrefix}(.*?)|(.*?){$db->tablePrefix}$/";
+ $patterns[] = "/^{$db->tablePrefix}(.*?)$/";
+ $patterns[] = "/^(.*?){$db->tablePrefix}$/";
} else {
$patterns[] = "/^tbl_(.*?)$/";
}
@@ -523,6 +524,7 @@ class Generator extends \yii\gii\Generator
foreach ($patterns as $pattern) {
if (preg_match($pattern, $tableName, $matches)) {
$className = $matches[1];
+ break;
}
}
return $this->_classNames[$tableName] = Inflector::id2camel($className, '_');
From c5a34c534b987a5767db7757699453cb14991c14 Mon Sep 17 00:00:00 2001
From: Aaron Francis
Date: Thu, 3 Oct 2013 16:33:28 -0500
Subject: [PATCH 072/613] Fix Issue #934
Fixes issue #934. Command is created for the selected database, not the default database.
---
framework/yii/console/controllers/MigrateController.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/framework/yii/console/controllers/MigrateController.php b/framework/yii/console/controllers/MigrateController.php
index e2c771c..e9e3973 100644
--- a/framework/yii/console/controllers/MigrateController.php
+++ b/framework/yii/console/controllers/MigrateController.php
@@ -584,7 +584,7 @@ class MigrateController extends Controller
->from($this->migrationTable)
->orderBy('version DESC')
->limit($limit)
- ->createCommand()
+ ->createCommand($this->db)
->queryAll();
$history = ArrayHelper::map($rows, 'version', 'apply_time');
unset($history[self::BASE_MIGRATION]);
From 536075c0408e745fb285f86867062338d744128d Mon Sep 17 00:00:00 2001
From: egorpromo
Date: Fri, 4 Oct 2013 21:17:13 +0700
Subject: [PATCH 073/613] Just simple correction of unintelligible description
---
framework/yii/web/Application.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/framework/yii/web/Application.php b/framework/yii/web/Application.php
index 5fd2310..b0638a7 100644
--- a/framework/yii/web/Application.php
+++ b/framework/yii/web/Application.php
@@ -45,7 +45,7 @@ class Application extends \yii\base\Application
* )
* ~~~
*
- * Defaults to null, meaning catch-all is not effective.
+ * Defaults to null, meaning catch-all is not used.
*/
public $catchAll;
/**
From 293cb9d86f0f62f71a6943075d9a2985e09af655 Mon Sep 17 00:00:00 2001
From: Qiang Xue
Date: Fri, 4 Oct 2013 20:35:58 -0400
Subject: [PATCH 074/613] Fixed search form.
---
framework/yii/gii/generators/crud/templates/views/_search.php | 5 ++++-
framework/yii/grid/DataColumn.php | 2 +-
framework/yii/helpers/BaseHtml.php | 2 +-
framework/yii/web/Request.php | 1 +
4 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/framework/yii/gii/generators/crud/templates/views/_search.php b/framework/yii/gii/generators/crud/templates/views/_search.php
index a649589..13e2b82 100644
--- a/framework/yii/gii/generators/crud/templates/views/_search.php
+++ b/framework/yii/gii/generators/crud/templates/views/_search.php
@@ -23,7 +23,10 @@ use yii\widgets\ActiveForm;
- $form = ActiveForm::begin(array('method' => 'get')); ?>
+ $form = ActiveForm::begin(array(
+ 'action' => array('index'),
+ 'method' => 'get',
+ )); ?>
'form-control');
+ public $filterInputOptions = array('class' => 'form-control', 'id' => null);
protected function renderHeaderCellContent()
diff --git a/framework/yii/helpers/BaseHtml.php b/framework/yii/helpers/BaseHtml.php
index 2baa679..ff12cd5 100644
--- a/framework/yii/helpers/BaseHtml.php
+++ b/framework/yii/helpers/BaseHtml.php
@@ -237,7 +237,7 @@ class BaseHtml
$hiddenInputs[] = static::hiddenInput($request->restVar, $method);
$method = 'post';
}
- if ($request->enableCsrfValidation) {
+ if ($request->enableCsrfValidation && !strcasecmp($method, 'post')) {
$hiddenInputs[] = static::hiddenInput($request->csrfVar, $request->getCsrfToken());
}
}
diff --git a/framework/yii/web/Request.php b/framework/yii/web/Request.php
index e5d9477..312adc1 100644
--- a/framework/yii/web/Request.php
+++ b/framework/yii/web/Request.php
@@ -77,6 +77,7 @@ class Request extends \yii\base\Request
*/
const CSRF_HEADER = 'X-CSRF-Token';
+
/**
* @var boolean whether to enable CSRF (Cross-Site Request Forgery) validation. Defaults to true.
* When CSRF validation is enabled, forms submitted to an Yii Web application must be originated
From 863a5cc01510742768f136c7544221f103a448b2 Mon Sep 17 00:00:00 2001
From: Larry Ullman
Date: Sat, 5 Oct 2013 08:36:54 -0400
Subject: [PATCH 075/613] Initial edits
---
docs/guide/configuration.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/guide/configuration.md b/docs/guide/configuration.md
index f9b6285..aa85dd5 100644
--- a/docs/guide/configuration.md
+++ b/docs/guide/configuration.md
@@ -1,8 +1,8 @@
Configuration
=============
-In Yii application and majority of components have sensible defaults so it's unlikely you spend lots of time configuring
-it. Still there are some mandatory options such as database connection you should set up.
+Yii applications rely upon components to perform most of the common tasks, such as connecting to a database, routing browser requests, and handling sessions. How these stock components behave can be adjusted by *configuring* your Yii application. The majority of components have sensible defaults, so it's unlikely that you'll spend a lot of time configuring
+it. Still there are some mandatory settings, such as the database connection, that you will have to establish.
How application is configured depends on application template but there are some general principles applying in any case.
From cbbb2cab76aa41fc76a1d589084371efc430501e Mon Sep 17 00:00:00 2001
From: Aris Karageorgos
Date: Sat, 5 Oct 2013 19:42:50 +0700
Subject: [PATCH 076/613] Fixed typo
---
docs/guide/configuration.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/guide/configuration.md b/docs/guide/configuration.md
index aa85dd5..8325855 100644
--- a/docs/guide/configuration.md
+++ b/docs/guide/configuration.md
@@ -2,7 +2,7 @@ Configuration
=============
Yii applications rely upon components to perform most of the common tasks, such as connecting to a database, routing browser requests, and handling sessions. How these stock components behave can be adjusted by *configuring* your Yii application. The majority of components have sensible defaults, so it's unlikely that you'll spend a lot of time configuring
-it. Still there are some mandatory settings, such as the database connection, that you will have to establish.
+them. Still there are some mandatory settings, such as the database connection, that you will have to establish.
How application is configured depends on application template but there are some general principles applying in any case.
From 951b944b2a0f10db7587458a1c270c4ffafaea7c Mon Sep 17 00:00:00 2001
From: Larry Ullman
Date: Sat, 5 Oct 2013 08:44:36 -0400
Subject: [PATCH 077/613] Edited password section
---
docs/guide/security.md | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/docs/guide/security.md b/docs/guide/security.md
index af30e5b..a7f4054 100644
--- a/docs/guide/security.md
+++ b/docs/guide/security.md
@@ -6,24 +6,23 @@ Hashing and verifying passwords
Most developers know that you cannot store passwords in plain text, but many believe it's safe to hash passwords using `md5` or `sha1`. There was a time when those hashing algorithms were sufficient, but modern hardware makes it possible to break those hashes very quickly using a brute force attack.
-In order to truly secure user passwords, even in the worst case scenario (your database is broken into), you need to use a hashing algorithm that is resistant to brute force attacks. The best current choice is bcrypt. In PHP, you can create a bcrypt hash by using [crypt function](http://php.net/manual/en/function.crypt.php). However, this function is not easy to use properly, so Yii provides two helper functions for generating hash from
-password and verifying existing hash.
+In order to truly secure user passwords, even in the worst case scenario (your database is broken into), you need to use a hashing algorithm that is resistant to brute force attacks. The best current choice is `bcrypt`. In PHP, you can create a `bcrypt` hash by using the [crypt function](http://php.net/manual/en/function.crypt.php). However, this function is not easy to use properly, so Yii provides two helper functions to make securely generating and verifying hashes easier.
-When user sets his password we're taking password string from POST and then getting a hash:
+When a user provides a password for the first time (e.g., upon registration), the password needs to be hashed:
```php
$hash = \yii\helpers\Security::generatePasswordHash($password);
```
-The hash we've got is persisted to database to be used later.
+The hash would then be associated with the model, so that it will be stored in the database for later use.
-Then when user is trying to log in we're verifying the password he entered against a hash that we've previously persisted:
+When user attempts to log in, the submitted log in password must be verified against the previously hashed and stored password:
```php
-if(Security::validatePassword($password, $hash)) {
+use \yii\helpers;
+if (Security::validatePassword($password, $hash)) {
// all good, logging user in
-}
-else {
+} else {
// wrong password
}
```
From cf9104f7fdd75894ff7c5796df331213fea2ae91 Mon Sep 17 00:00:00 2001
From: Qiang Xue
Date: Sat, 5 Oct 2013 21:56:06 -0400
Subject: [PATCH 078/613] make grid view filtering work.
---
framework/yii/assets/yii.gridView.js | 61 ++++++++++++++++++++++++++++++++++++
framework/yii/grid/GridView.php | 35 ++++++++++++++++++++-
2 files changed, 95 insertions(+), 1 deletion(-)
diff --git a/framework/yii/assets/yii.gridView.js b/framework/yii/assets/yii.gridView.js
index b07ece2..a452c17 100644
--- a/framework/yii/assets/yii.gridView.js
+++ b/framework/yii/assets/yii.gridView.js
@@ -22,6 +22,8 @@
};
var defaults = {
+ filterUrl: undefined,
+ filterSelector: undefined
};
var methods = {
@@ -32,6 +34,32 @@
$e.data('yiiGridView', {
settings: settings
});
+
+ var enterPressed = false;
+ $(document).on('change.yiiGridView keydown.yiiGridView', settings.filterSelector, function (event) {
+ if (event.type === 'keydown') {
+ if (event.keyCode !== 13) {
+ return; // only react to enter key
+ } else {
+ enterPressed = true;
+ }
+ } else {
+ // prevent processing for both keydown and change events
+ if (enterPressed) {
+ enterPressed = false;
+ return;
+ }
+ }
+ var data = $(settings.filterSelector).serialize();
+ var url = settings.filterUrl;
+ if (url.indexOf('?') >= 0) {
+ url += '&' + data;
+ } else {
+ url += '?' + data;
+ }
+ window.location.href = url;
+ return false;
+ });
});
},
@@ -74,5 +102,38 @@
return this.data('yiiGridView');
}
};
+
+ var enterPressed = false;
+
+ var filterChanged = function (event) {
+ if (event.type === 'keydown') {
+ if (event.keyCode !== 13) {
+ return; // only react to enter key
+ } else {
+ enterPressed = true;
+ }
+ } else {
+ // prevent processing for both keydown and change events
+ if (enterPressed) {
+ enterPressed = false;
+ return;
+ }
+ }
+ var data = $(settings.filterSelector).serialize();
+ if (settings.pageVar !== undefined) {
+ data += '&' + settings.pageVar + '=1';
+ }
+ if (settings.enableHistory && settings.ajaxUpdate !== false && window.History.enabled) {
+ // Ajaxify this link
+ var url = $('#' + id).yiiGridView('getUrl'),
+ params = $.deparam.querystring($.param.querystring(url, data));
+
+ delete params[settings.ajaxVar];
+ window.History.pushState(null, document.title, decodeURIComponent($.param.querystring(url.substr(0, url.indexOf('?')), params)));
+ } else {
+ $('#' + id).yiiGridView('update', {data: data});
+ }
+ return false;
+ };
})(window.jQuery);
diff --git a/framework/yii/grid/GridView.php b/framework/yii/grid/GridView.php
index f4433bc..4bf7a39 100644
--- a/framework/yii/grid/GridView.php
+++ b/framework/yii/grid/GridView.php
@@ -14,6 +14,7 @@ use yii\base\InvalidConfigException;
use yii\base\Widget;
use yii\db\ActiveRecord;
use yii\helpers\Html;
+use yii\helpers\Json;
use yii\widgets\BaseListView;
/**
@@ -137,6 +138,14 @@ class GridView extends BaseListView
*/
public $filterModel;
/**
+ * @var string|array the URL for returning the filtering result. [[Html::url()]] will be called to
+ * normalize the URL. If not set, the current controller action will be used.
+ * When the user makes change to any filter input, the current filtering inputs will be appended
+ * as GET parameters to this URL.
+ */
+ public $filterUrl;
+ public $filterSelector;
+ /**
* @var string whether the filters should be displayed in the grid view. Valid values include:
*
* - [[FILTER_POS_HEADER]]: the filters will be displayed on top of each column's header cell.
@@ -167,6 +176,9 @@ class GridView extends BaseListView
if (!isset($this->options['id'])) {
$this->options['id'] = $this->getId();
}
+ if (!isset($this->filterRowOptions['id'])) {
+ $this->filterRowOptions['id'] = $this->options['id'] . '-filters';
+ }
$this->initColumns();
}
@@ -177,12 +189,33 @@ class GridView extends BaseListView
public function run()
{
$id = $this->options['id'];
+ $options = Json::encode($this->getClientOptions());
$view = $this->getView();
GridViewAsset::register($view);
- $view->registerJs("jQuery('#$id').yiiGridView();");
+ $view->registerJs("jQuery('#$id').yiiGridView($options);");
parent::run();
}
+
+ /**
+ * Returns the options for the grid view JS widget.
+ * @return array the options
+ */
+ protected function getClientOptions()
+ {
+ $filterUrl = isset($this->filterUrl) ? $this->filterUrl : array(Yii::$app->controller->action->id);
+ $id = $this->filterRowOptions['id'];
+ $filterSelector = "#$id input, #$id select";
+ if (isset($this->filterSelector)) {
+ $filterSelector .= ', ' . $this->filterSelector;
+ }
+
+ return array(
+ 'filterUrl' => Html::url($filterUrl),
+ 'filterSelector' => $filterSelector,
+ );
+ }
+
/**
* Renders the data models for the grid view.
*/
From 0904c3454ec339a291abc313500d4e6b41069a6b Mon Sep 17 00:00:00 2001
From: Qiang Xue
Date: Sun, 6 Oct 2013 12:14:30 -0400
Subject: [PATCH 079/613] Fixed composer autoload declaration.
---
extensions/composer/composer.json | 2 +-
extensions/jui/composer.json | 2 +-
extensions/mutex/composer.json | 2 +-
extensions/smarty/composer.json | 2 +-
extensions/twig/composer.json | 2 +-
5 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/extensions/composer/composer.json b/extensions/composer/composer.json
index d8cf49d..db430a2 100644
--- a/extensions/composer/composer.json
+++ b/extensions/composer/composer.json
@@ -22,6 +22,6 @@
"yiisoft/yii2": "*"
},
"autoload": {
- "psr-0": { "yii\\composer": "" }
+ "psr-0": { "yii\\composer\\": "" }
}
}
diff --git a/extensions/jui/composer.json b/extensions/jui/composer.json
index f5e259f..e228973 100644
--- a/extensions/jui/composer.json
+++ b/extensions/jui/composer.json
@@ -16,6 +16,6 @@
"yiisoft/yii2": "*"
},
"autoload": {
- "psr-0": { "yii\\jui": "" }
+ "psr-0": { "yii\\jui\\": "" }
}
}
diff --git a/extensions/mutex/composer.json b/extensions/mutex/composer.json
index db8cde3..2fb95c4 100644
--- a/extensions/mutex/composer.json
+++ b/extensions/mutex/composer.json
@@ -22,6 +22,6 @@
"yiisoft/yii2": "*"
},
"autoload": {
- "psr-0": { "yii\\mutex": "" }
+ "psr-0": { "yii\\mutex\\": "" }
}
}
diff --git a/extensions/smarty/composer.json b/extensions/smarty/composer.json
index b1e1681..5682574 100644
--- a/extensions/smarty/composer.json
+++ b/extensions/smarty/composer.json
@@ -23,6 +23,6 @@
"smarty/smarty": "v3.1.13"
},
"autoload": {
- "psr-0": { "yii\\smarty": "" }
+ "psr-0": { "yii\\smarty\\": "" }
}
}
diff --git a/extensions/twig/composer.json b/extensions/twig/composer.json
index 0c1644a..ba21065 100644
--- a/extensions/twig/composer.json
+++ b/extensions/twig/composer.json
@@ -23,6 +23,6 @@
"twig/twig": "1.13.*"
},
"autoload": {
- "psr-0": { "yii\\twig": "" }
+ "psr-0": { "yii\\twig\\": "" }
}
}
From 1005b1ad452cc7b020cb45c79c9266b329ff1419 Mon Sep 17 00:00:00 2001
From: Alexander Makarov
Date: Tue, 8 Oct 2013 01:51:19 +0300
Subject: [PATCH 080/613] Added link to the guide to readme
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 1cd0121..dc03ac7 100644
--- a/README.md
+++ b/README.md
@@ -42,7 +42,7 @@ DOCUMENTATION
For 1.1 users, you may refer to [Upgrading from Yii 1.1](docs/guide/upgrade-from-v1.md)
to have a general idea of what has changed in 2.0.
-We are writing more documentation to get you started and learn more in depth.
+[Definitive Guide draft](docs/guide/index.md) is available. It's not complete yet but main parts are already OK.
HOW TO PARTICIPATE
From 9ef953a85ca6803d87940c48e7af1c2ffa5717a4 Mon Sep 17 00:00:00 2001
From: Qiang Xue
Date: Mon, 7 Oct 2013 23:39:41 -0400
Subject: [PATCH 081/613] Yii extension composer installer WIP.
---
extensions/composer/yii/composer/Installer.php | 134 +++++++++++++++++++++
.../composer/yii/composer/InstallerPlugin.php | 30 +++++
2 files changed, 164 insertions(+)
create mode 100644 extensions/composer/yii/composer/Installer.php
create mode 100644 extensions/composer/yii/composer/InstallerPlugin.php
diff --git a/extensions/composer/yii/composer/Installer.php b/extensions/composer/yii/composer/Installer.php
new file mode 100644
index 0000000..6ac9e4a
--- /dev/null
+++ b/extensions/composer/yii/composer/Installer.php
@@ -0,0 +1,134 @@
+
+ * @since 2.0
+ */
+class Installer extends LibraryInstaller
+{
+ /**
+ * @inheritdoc
+ */
+ public function supports($packageType)
+ {
+ return $packageType === 'yii2-extension';
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
+ {
+ parent::install($repo, $package);
+ $this->addPackage($package);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
+ {
+ parent::update($repo, $initial, $target);
+ $this->removePackage($initial);
+ $this->addPackage($target);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package)
+ {
+ parent::uninstall($repo, $package);
+ $this->removePackage($package);
+ }
+
+ protected function addPackage(PackageInterface $package)
+ {
+ $extension = array('name' => $package->getPrettyName());
+
+ $root = $package->getPrettyName();
+ if ($targetDir = $package->getTargetDir()) {
+ $root .= '/' . trim($targetDir, '/');
+ }
+ $root = trim($root, '/');
+
+ $extra = $package->getExtra();
+
+ if (isset($extra['preinit']) && is_string($extra['preinit'])) {
+ $extension['preinit'] = "/$root/" . ltrim(str_replace('\\', '/', $extra['preinit']), '/');
+ }
+ if (isset($extra['init']) && is_string($extra['init'])) {
+ $extension['init'] = "/$root/" . ltrim(str_replace('\\', '/', $extra['init']), '/');
+ }
+
+ if (isset($extra['aliases']) && is_array($extra['aliases'])) {
+ foreach ($extra['aliases'] as $alias => $path) {
+ $extension['aliases']['@' . ltrim($alias, '@')] = "/$root/" . ltrim(str_replace('\\', '/', $path), '/');
+ }
+ }
+
+ if (!empty($aliases)) {
+ foreach ($aliases as $alias => $path) {
+ if (strncmp($alias, '@', 1) !== 0) {
+ $alias = '@' . $alias;
+ }
+ $path = trim(str_replace('\\', '/', $path), '/');
+ $extension['aliases'][$alias] = $root . '/' . $path;
+ }
+ }
+
+ $extensions = $this->loadExtensions();
+ $extensions[$package->getId()] = $extension;
+ $this->saveExtensions($extensions);
+ }
+
+ protected function removePackage(PackageInterface $package)
+ {
+ $packages = $this->loadExtensions();
+ unset($packages[$package->getId()]);
+ $this->saveExtensions($packages);
+ }
+
+ protected function loadExtensions()
+ {
+ $file = $this->vendorDir . '/yii-extensions.php';
+ if (!is_file($file)) {
+ return array();
+ }
+ $extensions = require($file);
+ /** @var string $vendorDir defined in yii-extensions.php */
+ $n = strlen($vendorDir);
+ foreach ($extensions as &$extension) {
+ if (isset($extension['aliases'])) {
+ foreach ($extension['aliases'] as $alias => $path) {
+ $extension['aliases'][$alias] = '' . substr($path, $n);
+ }
+ }
+ if (isset($extension['preinit'])) {
+ $extension['preinit'] = '' . substr($extension['preinit'], $n);
+ }
+ if (isset($extension['init'])) {
+ $extension['init'] = '' . substr($extension['init'], $n);
+ }
+ }
+ return $extensions;
+ }
+
+ protected function saveExtensions(array $extensions)
+ {
+ $file = $this->vendorDir . '/yii-extensions.php';
+ $array = str_replace("'", '$vendorDir . \'', var_export($extensions, true));
+ file_put_contents($file, "
+ * @since 2.0
+ */
+class InstallerPlugin implements PluginInterface
+{
+ /**
+ * @inheritdoc
+ */
+ public function activate(Composer $composer, IOInterface $io)
+ {
+ $installer = new Installer($io, $composer);
+ $composer->getInstallationManager()->addInstaller($installer);
+ }
+}
From b301f181135272220913a6d5a0e3d211e46b2345 Mon Sep 17 00:00:00 2001
From: Qiang Xue
Date: Tue, 8 Oct 2013 20:34:47 -0400
Subject: [PATCH 082/613] Added installation commands to Installer.
---
extensions/composer/yii/composer/Installer.php | 90 +++++++++++++++++++++++---
1 file changed, 82 insertions(+), 8 deletions(-)
diff --git a/extensions/composer/yii/composer/Installer.php b/extensions/composer/yii/composer/Installer.php
index 6ac9e4a..8b5b9ea 100644
--- a/extensions/composer/yii/composer/Installer.php
+++ b/extensions/composer/yii/composer/Installer.php
@@ -17,6 +17,14 @@ use Composer\Repository\InstalledRepositoryInterface;
*/
class Installer extends LibraryInstaller
{
+ const EXTRA_WRITABLES = 'yii-writables';
+ const EXTRA_EXECUTABLES = 'yii-executables';
+ const EXTRA_CONFIG = 'yii-config';
+ const EXTRA_COMMANDS = 'yii-commands';
+ const EXTRA_ALIASES = 'yii-aliases';
+ const EXTRA_PREINIT = 'yii-preinit';
+ const EXTRA_INIT = 'yii-init';
+
/**
* @inheritdoc
*/
@@ -65,11 +73,11 @@ class Installer extends LibraryInstaller
$extra = $package->getExtra();
- if (isset($extra['preinit']) && is_string($extra['preinit'])) {
- $extension['preinit'] = "/$root/" . ltrim(str_replace('\\', '/', $extra['preinit']), '/');
+ if (isset($extra[self::EXTRA_PREINIT]) && is_string($extra[self::EXTRA_PREINIT])) {
+ $extension[self::EXTRA_PREINIT] = "/$root/" . ltrim(str_replace('\\', '/', $extra[self::EXTRA_PREINIT]), '/');
}
- if (isset($extra['init']) && is_string($extra['init'])) {
- $extension['init'] = "/$root/" . ltrim(str_replace('\\', '/', $extra['init']), '/');
+ if (isset($extra[self::EXTRA_INIT]) && is_string($extra[self::EXTRA_INIT])) {
+ $extension[self::EXTRA_INIT] = "/$root/" . ltrim(str_replace('\\', '/', $extra[self::EXTRA_INIT]), '/');
}
if (isset($extra['aliases']) && is_array($extra['aliases'])) {
@@ -115,11 +123,11 @@ class Installer extends LibraryInstaller
$extension['aliases'][$alias] = '' . substr($path, $n);
}
}
- if (isset($extension['preinit'])) {
- $extension['preinit'] = '' . substr($extension['preinit'], $n);
+ if (isset($extension[self::EXTRA_PREINIT])) {
+ $extension[self::EXTRA_PREINIT] = '' . substr($extension[self::EXTRA_PREINIT], $n);
}
- if (isset($extension['init'])) {
- $extension['init'] = '' . substr($extension['init'], $n);
+ if (isset($extension[self::EXTRA_INIT])) {
+ $extension[self::EXTRA_INIT] = '' . substr($extension[self::EXTRA_INIT], $n);
}
}
return $extensions;
@@ -131,4 +139,70 @@ class Installer extends LibraryInstaller
$array = str_replace("'", '$vendorDir . \'', var_export($extensions, true));
file_put_contents($file, " array(),
+ self::EXTRA_EXECUTABLES => array(),
+ ), $event->getComposer()->getPackage()->getExtra());
+
+ foreach ((array)$options[self::EXTRA_WRITABLES] as $path) {
+ echo "Setting writable: $path ...";
+ if (is_dir($path)) {
+ chmod($path, 0777);
+ echo "done\n";
+ } else {
+ echo "The directory was not found: " . getcwd() . DIRECTORY_SEPARATOR . $path;
+ return;
+ }
+ }
+
+ foreach ((array)$options[self::EXTRA_EXECUTABLES] as $path) {
+ echo "Setting executable: $path ...";
+ if (is_file($path)) {
+ chmod($path, 0755);
+ echo "done\n";
+ } else {
+ echo "\n\tThe file was not found: " . getcwd() . DIRECTORY_SEPARATOR . $path . "\n";
+ return;
+ }
+ }
+ }
+
+ /**
+ * Executes a yii command.
+ * @param CommandEvent $event
+ */
+ public static function run($event)
+ {
+ $options = array_merge(array(
+ self::EXTRA_COMMANDS => array(),
+ ), $event->getComposer()->getPackage()->getExtra());
+
+ if (!isset($options[self::EXTRA_CONFIG])) {
+ throw new Exception('Please specify the "' . self::EXTRA_CONFIG . '" parameter in composer.json.');
+ }
+ $configFile = getcwd() . '/' . $options[self::EXTRA_CONFIG];
+ if (!is_file($configFile)) {
+ throw new Exception("Config file does not exist: $configFile");
+ }
+
+ require_once(__DIR__ . '/../../../yii2/yii/Yii.php');
+ $application = new Application(require($configFile));
+ $request = $application->getRequest();
+
+ foreach ((array)$options[self::EXTRA_COMMANDS] as $command) {
+ $params = str_getcsv($command, ' '); // see http://stackoverflow.com/a/6609509/291573
+ $request->setParams($params);
+ list($route, $params) = $request->resolve();
+ echo "Running command: yii {$command}\n";
+ $application->runAction($route, $params);
+ }
+ }
}
From 35cf49732e52f8875a29ee9c9a11de1764d8f24e Mon Sep 17 00:00:00 2001
From: Qiang Xue
Date: Tue, 8 Oct 2013 20:43:08 -0400
Subject: [PATCH 083/613] Fixed the namespace.
---
extensions/twig/yii/twig/ViewRenderer.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/extensions/twig/yii/twig/ViewRenderer.php b/extensions/twig/yii/twig/ViewRenderer.php
index 06ad2d2..860a2f2 100644
--- a/extensions/twig/yii/twig/ViewRenderer.php
+++ b/extensions/twig/yii/twig/ViewRenderer.php
@@ -7,7 +7,7 @@
* @license http://www.yiiframework.com/license/
*/
-namespace yii\renderers;
+namespace yii\twig;
use Yii;
use yii\base\View;
From aede3c9f47bc4207777469acb39dd7885d02de9a Mon Sep 17 00:00:00 2001
From: Qiang Xue
Date: Wed, 9 Oct 2013 08:14:57 -0400
Subject: [PATCH 084/613] Removed duplicated indexBy declaration.
---
framework/yii/db/ActiveQuery.php | 6 ------
1 file changed, 6 deletions(-)
diff --git a/framework/yii/db/ActiveQuery.php b/framework/yii/db/ActiveQuery.php
index 12997ee..21f2f67 100644
--- a/framework/yii/db/ActiveQuery.php
+++ b/framework/yii/db/ActiveQuery.php
@@ -55,12 +55,6 @@ class ActiveQuery extends Query
*/
public $with;
/**
- * @var string|callable $column the name of the column by which the query results should be indexed by.
- * This can also be a callable (e.g. anonymous function) that returns the index value based on the given
- * row or model data. For more details, see [[indexBy()]].
- */
- public $indexBy;
- /**
* @var boolean whether to return each record as an array. If false (default), an object
* of [[modelClass]] will be created to represent each record.
*/
From fceb2d6e2160a6dea24ce3eea09f6c5563104e22 Mon Sep 17 00:00:00 2001
From: Qiang Xue
Date: Wed, 9 Oct 2013 20:33:06 -0400
Subject: [PATCH 085/613] Fixes #957: Json::encode() doesn't handle empty
object correctly.
---
framework/yii/helpers/BaseJson.php | 34 +++++++++++++------------------
tests/unit/framework/helpers/JsonTest.php | 4 ++++
2 files changed, 18 insertions(+), 20 deletions(-)
diff --git a/framework/yii/helpers/BaseJson.php b/framework/yii/helpers/BaseJson.php
index bd6ede5..80224d5 100644
--- a/framework/yii/helpers/BaseJson.php
+++ b/framework/yii/helpers/BaseJson.php
@@ -81,32 +81,26 @@ class BaseJson
*/
protected static function processData($data, &$expressions, $expPrefix)
{
- if (is_array($data)) {
- foreach ($data as $key => $value) {
- if (is_array($value) || is_object($value)) {
- $data[$key] = static::processData($value, $expressions, $expPrefix);
- }
- }
- return $data;
- } elseif (is_object($data)) {
+ if (is_object($data)) {
if ($data instanceof JsExpression) {
$token = "!{[$expPrefix=" . count($expressions) . ']}!';
$expressions['"' . $token . '"'] = $data->expression;
return $token;
- } else {
- $data = $data instanceof Arrayable ? $data->toArray() : get_object_vars($data);
- $result = array();
- foreach ($data as $key => $value) {
- if (is_array($value) || is_object($value)) {
- $result[$key] = static::processData($value, $expressions, $expPrefix);
- } else {
- $result[$key] = $value;
- }
+ }
+ $data = $data instanceof Arrayable ? $data->toArray() : get_object_vars($data);
+ if ($data === array() && !$data instanceof Arrayable) {
+ return new \stdClass();
+ }
+ }
+
+ if (is_array($data)) {
+ foreach ($data as $key => $value) {
+ if (is_array($value) || is_object($value)) {
+ $data[$key] = static::processData($value, $expressions, $expPrefix);
}
- return $result;
}
- } else {
- return $data;
}
+
+ return $data;
}
}
diff --git a/tests/unit/framework/helpers/JsonTest.php b/tests/unit/framework/helpers/JsonTest.php
index df2ca5f..069fdc3 100644
--- a/tests/unit/framework/helpers/JsonTest.php
+++ b/tests/unit/framework/helpers/JsonTest.php
@@ -45,6 +45,10 @@ class JsonTest extends TestCase
'b' => new JsExpression($expression2),
);
$this->assertSame("{\"a\":[1,$expression1],\"b\":$expression2}", Json::encode($data));
+
+ // https://github.com/yiisoft/yii2/issues/957
+ $data = (object)null;
+ $this->assertSame('{}', Json::encode($data));
}
public function testDecode()
From 6488fe47ec186d951ab0f16bbae994f073643ca8 Mon Sep 17 00:00:00 2001
From: Alexander Makarov
Date: Thu, 10 Oct 2013 13:34:06 +0400
Subject: [PATCH 086/613] Better phpdoc for chained method calls
---
framework/yii/db/ActiveQuery.php | 9 +++--
framework/yii/db/ActiveRelation.php | 4 +--
framework/yii/db/Command.php | 8 ++---
framework/yii/db/Query.php | 38 +++++++++++-----------
framework/yii/gii/components/ActiveField.php | 4 +++
.../yii/requirements/YiiRequirementChecker.php | 2 +-
framework/yii/web/HeaderCollection.php | 6 ++--
framework/yii/web/Response.php | 2 +-
framework/yii/widgets/ActiveField.php | 30 ++++++++---------
9 files changed, 53 insertions(+), 50 deletions(-)
diff --git a/framework/yii/db/ActiveQuery.php b/framework/yii/db/ActiveQuery.php
index 21f2f67..48af835 100644
--- a/framework/yii/db/ActiveQuery.php
+++ b/framework/yii/db/ActiveQuery.php
@@ -168,7 +168,7 @@ class ActiveQuery extends Query
/**
* Sets the [[asArray]] property.
* @param boolean $value whether to return the query results in terms of arrays instead of Active Records.
- * @return ActiveQuery the query object itself
+ * @return static the query object itself
*/
public function asArray($value = true)
{
@@ -196,7 +196,7 @@ class ActiveQuery extends Query
* ))->all();
* ~~~
*
- * @return ActiveQuery the query object itself
+ * @return static the query object itself
*/
public function with()
{
@@ -223,12 +223,11 @@ class ActiveQuery extends Query
* }
* ~~~
*
- * @return ActiveQuery the query object itself
+ * @return static the query object itself
*/
public function indexBy($column)
{
- $this->indexBy = $column;
- return $this;
+ parent::indexBy($column);
}
private function createModels($rows)
diff --git a/framework/yii/db/ActiveRelation.php b/framework/yii/db/ActiveRelation.php
index f05c56a..c1c8b2d 100644
--- a/framework/yii/db/ActiveRelation.php
+++ b/framework/yii/db/ActiveRelation.php
@@ -66,7 +66,7 @@ class ActiveRelation extends ActiveQuery
* @param string $relationName the relation name. This refers to a relation declared in [[primaryModel]].
* @param callable $callable a PHP callback for customizing the relation associated with the pivot table.
* Its signature should be `function($query)`, where `$query` is the query to be customized.
- * @return ActiveRelation the relation object itself.
+ * @return static the relation object itself.
*/
public function via($relationName, $callable = null)
{
@@ -86,7 +86,7 @@ class ActiveRelation extends ActiveQuery
* in the [[primaryModel]] table.
* @param callable $callable a PHP callback for customizing the relation associated with the pivot table.
* Its signature should be `function($query)`, where `$query` is the query to be customized.
- * @return ActiveRelation
+ * @return static
*/
public function viaTable($tableName, $link, $callable = null)
{
diff --git a/framework/yii/db/Command.php b/framework/yii/db/Command.php
index bfb8a26..73ac04b 100644
--- a/framework/yii/db/Command.php
+++ b/framework/yii/db/Command.php
@@ -88,7 +88,7 @@ class Command extends \yii\base\Component
* Specifies the SQL statement to be executed.
* The previous SQL execution (if any) will be cancelled, and [[params]] will be cleared as well.
* @param string $sql the SQL statement to be set.
- * @return Command this command instance
+ * @return static this command instance
*/
public function setSql($sql)
{
@@ -174,7 +174,7 @@ class Command extends \yii\base\Component
* @param integer $dataType SQL data type of the parameter. If null, the type is determined by the PHP type of the value.
* @param integer $length length of the data type
* @param mixed $driverOptions the driver-specific options
- * @return Command the current command being executed
+ * @return static the current command being executed
* @see http://www.php.net/manual/en/function.PDOStatement-bindParam.php
*/
public function bindParam($name, &$value, $dataType = null, $length = null, $driverOptions = null)
@@ -201,7 +201,7 @@ class Command extends \yii\base\Component
* placeholders, this will be the 1-indexed position of the parameter.
* @param mixed $value The value to bind to the parameter
* @param integer $dataType SQL data type of the parameter. If null, the type is determined by the PHP type of the value.
- * @return Command the current command being executed
+ * @return static the current command being executed
* @see http://www.php.net/manual/en/function.PDOStatement-bindValue.php
*/
public function bindValue($name, $value, $dataType = null)
@@ -225,7 +225,7 @@ class Command extends \yii\base\Component
* e.g. `array(':name' => 'John', ':age' => 25)`. By default, the PDO type of each value is determined
* by its PHP type. You may explicitly specify the PDO type by using an array: `array(value, type)`,
* e.g. `array(':name' => 'John', ':profile' => array($profile, \PDO::PARAM_LOB))`.
- * @return Command the current command being executed
+ * @return static the current command being executed
*/
public function bindValues($values)
{
diff --git a/framework/yii/db/Query.php b/framework/yii/db/Query.php
index d1e7864..dbe0424 100644
--- a/framework/yii/db/Query.php
+++ b/framework/yii/db/Query.php
@@ -166,7 +166,7 @@ class Query extends Component
* }
* ~~~
*
- * @return Query the query object itself
+ * @return static the query object itself
*/
public function indexBy($column)
{
@@ -325,7 +325,7 @@ class Query extends Component
* (which means the column contains a DB expression).
* @param string $option additional option that should be appended to the 'SELECT' keyword. For example,
* in MySQL, the option 'SQL_CALC_FOUND_ROWS' can be used.
- * @return Query the query object itself
+ * @return static the query object itself
*/
public function select($columns, $option = null)
{
@@ -340,7 +340,7 @@ class Query extends Component
/**
* Sets the value indicating whether to SELECT DISTINCT or not.
* @param bool $value whether to SELECT DISTINCT or not.
- * @return Query the query object itself
+ * @return static the query object itself
*/
public function distinct($value = true)
{
@@ -355,7 +355,7 @@ class Query extends Component
* Table names can contain schema prefixes (e.g. `'public.tbl_user'`) and/or table aliases (e.g. `'tbl_user u'`).
* The method will automatically quote the table names unless it contains some parenthesis
* (which means the table is given as a sub-query or DB expression).
- * @return Query the query object itself
+ * @return static the query object itself
*/
public function from($tables)
{
@@ -431,7 +431,7 @@ class Query extends Component
*
* @param string|array $condition the conditions that should be put in the WHERE part.
* @param array $params the parameters (name => value) to be bound to the query.
- * @return Query the query object itself
+ * @return static the query object itself
* @see andWhere()
* @see orWhere()
*/
@@ -448,7 +448,7 @@ class Query extends Component
* @param string|array $condition the new WHERE condition. Please refer to [[where()]]
* on how to specify this parameter.
* @param array $params the parameters (name => value) to be bound to the query.
- * @return Query the query object itself
+ * @return static the query object itself
* @see where()
* @see orWhere()
*/
@@ -469,7 +469,7 @@ class Query extends Component
* @param string|array $condition the new WHERE condition. Please refer to [[where()]]
* on how to specify this parameter.
* @param array $params the parameters (name => value) to be bound to the query.
- * @return Query the query object itself
+ * @return static the query object itself
* @see where()
* @see andWhere()
*/
@@ -560,7 +560,7 @@ class Query extends Component
* Columns can be specified in either a string (e.g. "id, name") or an array (e.g. array('id', 'name')).
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
- * @return Query the query object itself
+ * @return static the query object itself
* @see addGroupBy()
*/
public function groupBy($columns)
@@ -578,7 +578,7 @@ class Query extends Component
* Columns can be specified in either a string (e.g. "id, name") or an array (e.g. array('id', 'name')).
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
- * @return Query the query object itself
+ * @return static the query object itself
* @see groupBy()
*/
public function addGroupBy($columns)
@@ -599,7 +599,7 @@ class Query extends Component
* @param string|array $condition the conditions to be put after HAVING.
* Please refer to [[where()]] on how to specify this parameter.
* @param array $params the parameters (name => value) to be bound to the query.
- * @return Query the query object itself
+ * @return static the query object itself
* @see andHaving()
* @see orHaving()
*/
@@ -616,7 +616,7 @@ class Query extends Component
* @param string|array $condition the new HAVING condition. Please refer to [[where()]]
* on how to specify this parameter.
* @param array $params the parameters (name => value) to be bound to the query.
- * @return Query the query object itself
+ * @return static the query object itself
* @see having()
* @see orHaving()
*/
@@ -637,7 +637,7 @@ class Query extends Component
* @param string|array $condition the new HAVING condition. Please refer to [[where()]]
* on how to specify this parameter.
* @param array $params the parameters (name => value) to be bound to the query.
- * @return Query the query object itself
+ * @return static the query object itself
* @see having()
* @see andHaving()
*/
@@ -659,7 +659,7 @@ class Query extends Component
* (e.g. `array('id' => Query::SORT_ASC, 'name' => Query::SORT_DESC)`).
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
- * @return Query the query object itself
+ * @return static the query object itself
* @see addOrderBy()
*/
public function orderBy($columns)
@@ -675,7 +675,7 @@ class Query extends Component
* (e.g. `array('id' => Query::SORT_ASC, 'name' => Query::SORT_DESC)`).
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
- * @return Query the query object itself
+ * @return static the query object itself
* @see orderBy()
*/
public function addOrderBy($columns)
@@ -710,7 +710,7 @@ class Query extends Component
/**
* Sets the LIMIT part of the query.
* @param integer $limit the limit. Use null or negative value to disable limit.
- * @return Query the query object itself
+ * @return static the query object itself
*/
public function limit($limit)
{
@@ -721,7 +721,7 @@ class Query extends Component
/**
* Sets the OFFSET part of the query.
* @param integer $offset the offset. Use null or negative value to disable offset.
- * @return Query the query object itself
+ * @return static the query object itself
*/
public function offset($offset)
{
@@ -732,7 +732,7 @@ class Query extends Component
/**
* Appends a SQL statement using UNION operator.
* @param string|Query $sql the SQL statement to be appended using UNION
- * @return Query the query object itself
+ * @return static the query object itself
*/
public function union($sql)
{
@@ -744,7 +744,7 @@ class Query extends Component
* Sets the parameters to be bound to the query.
* @param array $params list of query parameter values indexed by parameter placeholders.
* For example, `array(':name' => 'Dan', ':age' => 31)`.
- * @return Query the query object itself
+ * @return static the query object itself
* @see addParams()
*/
public function params($params)
@@ -757,7 +757,7 @@ class Query extends Component
* Adds additional parameters to be bound to the query.
* @param array $params list of query parameter values indexed by parameter placeholders.
* For example, `array(':name' => 'Dan', ':age' => 31)`.
- * @return Query the query object itself
+ * @return static the query object itself
* @see params()
*/
public function addParams($params)
diff --git a/framework/yii/gii/components/ActiveField.php b/framework/yii/gii/components/ActiveField.php
index 6a67217..8bb67a9 100644
--- a/framework/yii/gii/components/ActiveField.php
+++ b/framework/yii/gii/components/ActiveField.php
@@ -32,6 +32,10 @@ class ActiveField extends \yii\widgets\ActiveField
}
}
+ /**
+ * Makes filed remember its value between page reloads
+ * @return static the field object itself
+ */
public function sticky()
{
$this->options['class'] .= ' sticky';
diff --git a/framework/yii/requirements/YiiRequirementChecker.php b/framework/yii/requirements/YiiRequirementChecker.php
index 7d5ae42..c8ad45d 100644
--- a/framework/yii/requirements/YiiRequirementChecker.php
+++ b/framework/yii/requirements/YiiRequirementChecker.php
@@ -63,7 +63,7 @@ class YiiRequirementChecker
* @param array|string $requirements requirements to be checked.
* If an array, it is treated as the set of requirements;
* If a string, it is treated as the path of the file, which contains the requirements;
- * @return YiiRequirementChecker self instance.
+ * @return static self instance.
*/
function check($requirements)
{
diff --git a/framework/yii/web/HeaderCollection.php b/framework/yii/web/HeaderCollection.php
index 609058b..a729f6b 100644
--- a/framework/yii/web/HeaderCollection.php
+++ b/framework/yii/web/HeaderCollection.php
@@ -83,7 +83,7 @@ class HeaderCollection extends Object implements \IteratorAggregate, \ArrayAcces
* If there is already a header with the same name, it will be replaced.
* @param string $name the name of the header
* @param string $value the value of the header
- * @return HeaderCollection the collection object itself
+ * @return static the collection object itself
*/
public function set($name, $value = '')
{
@@ -98,7 +98,7 @@ class HeaderCollection extends Object implements \IteratorAggregate, \ArrayAcces
* be appended to it instead of replacing it.
* @param string $name the name of the header
* @param string $value the value of the header
- * @return HeaderCollection the collection object itself
+ * @return static the collection object itself
*/
public function add($name, $value)
{
@@ -112,7 +112,7 @@ class HeaderCollection extends Object implements \IteratorAggregate, \ArrayAcces
* If there is already a header with the same name, the new one will be ignored.
* @param string $name the name of the header
* @param string $value the value of the header
- * @return HeaderCollection the collection object itself
+ * @return static the collection object itself
*/
public function setDefault($name, $value)
{
diff --git a/framework/yii/web/Response.php b/framework/yii/web/Response.php
index f0d506b..703ea6f 100644
--- a/framework/yii/web/Response.php
+++ b/framework/yii/web/Response.php
@@ -605,7 +605,7 @@ class Response extends \yii\base\Response
* @param integer $statusCode the HTTP status code. If null, it will use 302.
* See [[http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html]]
* for details about HTTP status code
- * @return Response the response object itself
+ * @return static the response object itself
*/
public function redirect($url, $statusCode = null)
{
diff --git a/framework/yii/widgets/ActiveField.php b/framework/yii/widgets/ActiveField.php
index 7df67fa..d31c50b 100644
--- a/framework/yii/widgets/ActiveField.php
+++ b/framework/yii/widgets/ActiveField.php
@@ -221,7 +221,7 @@ class ActiveField extends Component
* @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.
- * @return ActiveField the field object itself
+ * @return static the field object itself
*/
public function label($label = null, $options = array())
{
@@ -244,7 +244,7 @@ class ActiveField extends Component
*
* - tag: this specifies the tag name. If not set, "div" will be used.
*
- * @return ActiveField the field object itself
+ * @return static the field object itself
*/
public function error($options = array())
{
@@ -263,7 +263,7 @@ class ActiveField extends Component
*
* - tag: this specifies the tag name. If not set, "div" will be used.
*
- * @return ActiveField the field object itself
+ * @return static the field object itself
*/
public function hint($content, $options = array())
{
@@ -278,7 +278,7 @@ class ActiveField extends Component
* @param string $type the input type (e.g. 'text', 'password')
* @param array $options the tag options in terms of name-value pairs. These will be rendered as
* the attributes of the resulting tag. The values will be HTML-encoded using [[Html::encode()]].
- * @return ActiveField the field object itself
+ * @return static the field object itself
*/
public function input($type, $options = array())
{
@@ -293,7 +293,7 @@ class ActiveField extends Component
* unless they are explicitly specified in `$options`.
* @param array $options the tag options in terms of name-value pairs. These will be rendered as
* the attributes of the resulting tag. The values will be HTML-encoded using [[Html::encode()]].
- * @return ActiveField the field object itself
+ * @return static the field object itself
*/
public function textInput($options = array())
{
@@ -308,7 +308,7 @@ class ActiveField extends Component
* unless they are explicitly specified in `$options`.
* @param array $options the tag options in terms of name-value pairs. These will be rendered as
* the attributes of the resulting tag. The values will be HTML-encoded using [[Html::encode()]].
- * @return ActiveField the field object itself
+ * @return static the field object itself
*/
public function passwordInput($options = array())
{
@@ -323,7 +323,7 @@ class ActiveField extends Component
* unless they are explicitly specified in `$options`.
* @param array $options the tag options in terms of name-value pairs. These will be rendered as
* the attributes of the resulting tag. The values will be HTML-encoded using [[Html::encode()]].
- * @return ActiveField the field object itself
+ * @return static the field object itself
*/
public function fileInput($options = array())
{
@@ -339,7 +339,7 @@ class ActiveField extends Component
* The model attribute value will be used as the content in the textarea.
* @param array $options the tag options in terms of name-value pairs. These will be rendered as
* the attributes of the resulting tag. The values will be HTML-encoded using [[Html::encode()]].
- * @return ActiveField the field object itself
+ * @return static the field object itself
*/
public function textarea($options = array())
{
@@ -367,7 +367,7 @@ class ActiveField extends Component
* @param boolean $enclosedByLabel whether to enclose the radio within the label.
* If true, the method will still use [[template]] to layout the checkbox and the error message
* except that the radio is enclosed by the label tag.
- * @return ActiveField the field object itself
+ * @return static the field object itself
*/
public function radio($options = array(), $enclosedByLabel = true)
{
@@ -402,7 +402,7 @@ class ActiveField extends Component
* @param boolean $enclosedByLabel whether to enclose the checkbox within the label.
* If true, the method will still use [[template]] to layout the checkbox and the error message
* except that the checkbox is enclosed by the label tag.
- * @return ActiveField the field object itself
+ * @return static the field object itself
*/
public function checkbox($options = array(), $enclosedByLabel = true)
{
@@ -448,7 +448,7 @@ class ActiveField extends Component
* The rest of 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.
*
- * @return ActiveField the field object itself
+ * @return static the field object itself
*/
public function dropDownList($items, $options = array())
{
@@ -490,7 +490,7 @@ class ActiveField extends Component
* The rest of 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.
*
- * @return ActiveField the field object itself
+ * @return static the field object itself
*/
public function listBox($items, $options = array())
{
@@ -522,7 +522,7 @@ class ActiveField extends Component
* where $index is the zero-based index of the checkbox in the whole list; $label
* is the label for the checkbox; and $name, $value and $checked represent the name,
* value and the checked status of the checkbox input.
- * @return ActiveField the field object itself
+ * @return static the field object itself
*/
public function checkboxList($items, $options = array())
{
@@ -552,7 +552,7 @@ class ActiveField extends Component
* where $index is the zero-based index of the radio button in the whole list; $label
* is the label for the radio button; and $name, $value and $checked represent the name,
* value and the checked status of the radio button input.
- * @return ActiveField the field object itself
+ * @return static the field object itself
*/
public function radioList($items, $options = array())
{
@@ -571,7 +571,7 @@ class ActiveField extends Component
*
* @param string $class the widget class name
* @param array $config name-value pairs that will be used to initialize the widget
- * @return ActiveField the field object itself
+ * @return static the field object itself
*/
public function widget($class, $config = array())
{
From c7d7a3ce3659d31aa82ca9bf82ffb55d80a004c6 Mon Sep 17 00:00:00 2001
From: Alexander Makarov
Date: Thu, 10 Oct 2013 13:53:12 +0400
Subject: [PATCH 087/613] Fixed missing error page when AccessControl is used
with default deny rule
---
framework/yii/web/AccessControl.php | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/framework/yii/web/AccessControl.php b/framework/yii/web/AccessControl.php
index 7f791b8..75e2dc9 100644
--- a/framework/yii/web/AccessControl.php
+++ b/framework/yii/web/AccessControl.php
@@ -119,6 +119,12 @@ class AccessControl extends ActionFilter
return false;
}
}
+ if (isset($this->denyCallback)) {
+ call_user_func($this->denyCallback, $rule);
+ }
+ else {
+ $this->denyAccess($user);
+ }
return false;
}
From 817516adc5eed7b90c81ef04d34c7003b679ab2e Mon Sep 17 00:00:00 2001
From: Alexander Makarov
Date: Thu, 10 Oct 2013 14:14:30 +0400
Subject: [PATCH 088/613] Added missing return
---
framework/yii/db/ActiveQuery.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/framework/yii/db/ActiveQuery.php b/framework/yii/db/ActiveQuery.php
index 48af835..375e91f 100644
--- a/framework/yii/db/ActiveQuery.php
+++ b/framework/yii/db/ActiveQuery.php
@@ -227,7 +227,7 @@ class ActiveQuery extends Query
*/
public function indexBy($column)
{
- parent::indexBy($column);
+ return parent::indexBy($column);
}
private function createModels($rows)
From 8bff031fc235caa4fd085ab8a90a131a803cd040 Mon Sep 17 00:00:00 2001
From: Qiang Xue
Date: Thu, 10 Oct 2013 11:23:20 -0400
Subject: [PATCH 089/613] Fixed the issue that dots in URL rules would match
any character.
---
framework/yii/web/UrlRule.php | 1 +
tests/unit/framework/web/UrlRuleTest.php | 11 +++++++++++
2 files changed, 12 insertions(+)
diff --git a/framework/yii/web/UrlRule.php b/framework/yii/web/UrlRule.php
index ec73c92..10f0627 100644
--- a/framework/yii/web/UrlRule.php
+++ b/framework/yii/web/UrlRule.php
@@ -156,6 +156,7 @@ class UrlRule extends Object
}
}
}
+ $tr['.'] = '\\.';
$this->_template = preg_replace('/<(\w+):?([^>]+)?>/', '<$1>', $this->pattern);
$this->pattern = '#^' . trim(strtr($this->_template, $tr), '/') . '$#u';
diff --git a/tests/unit/framework/web/UrlRuleTest.php b/tests/unit/framework/web/UrlRuleTest.php
index 0a0def4..5e57cb6 100644
--- a/tests/unit/framework/web/UrlRuleTest.php
+++ b/tests/unit/framework/web/UrlRuleTest.php
@@ -380,6 +380,17 @@ class UrlRuleTest extends TestCase
),
),
array(
+ 'with dot', // https://github.com/yiisoft/yii/issues/2945
+ array(
+ 'pattern' => 'posts.html',
+ 'route' => 'post/index',
+ ),
+ array(
+ array('posts.html', 'post/index'),
+ array('postsahtml', false),
+ ),
+ ),
+ array(
'creation only',
array(
'pattern' => 'posts',
From 0c113faf62b384e255704af46878d5ba4f40dac5 Mon Sep 17 00:00:00 2001
From: Carsten Brandt
Date: Fri, 11 Oct 2013 01:13:32 +0200
Subject: [PATCH 090/613] added unit test for asset bundles
---
tests/unit/data/web/assets/.gitignore | 2 +
tests/unit/framework/web/AssetBundleTest.php | 84 ++++++++++++++++++++++++++++
2 files changed, 86 insertions(+)
create mode 100644 tests/unit/data/web/assets/.gitignore
create mode 100644 tests/unit/framework/web/AssetBundleTest.php
diff --git a/tests/unit/data/web/assets/.gitignore b/tests/unit/data/web/assets/.gitignore
new file mode 100644
index 0000000..c96a04f
--- /dev/null
+++ b/tests/unit/data/web/assets/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
\ No newline at end of file
diff --git a/tests/unit/framework/web/AssetBundleTest.php b/tests/unit/framework/web/AssetBundleTest.php
new file mode 100644
index 0000000..60bb7eb
--- /dev/null
+++ b/tests/unit/framework/web/AssetBundleTest.php
@@ -0,0 +1,84 @@
+
+ */
+
+namespace yiiunit\framework\web;
+
+use Yii;
+use yii\base\View;
+use yii\web\AssetBundle;
+use yii\web\AssetManager;
+
+/**
+ * @group web
+ */
+class AssetBundleTest extends \yiiunit\TestCase
+{
+ protected function setUp()
+ {
+ parent::setUp();
+ $this->mockApplication();
+
+ Yii::setAlias('@testWeb', '/');
+ Yii::setAlias('@testWebRoot', '@yiiunit/data/web');
+ }
+
+ protected function getView()
+ {
+ $view = new View();
+ $view->setAssetManager(new AssetManager(array(
+ 'basePath' => '@testWebRoot/assets',
+ 'baseUrl' => '@testWeb/assets',
+ )));
+
+ return $view;
+ }
+
+ public function testRegister()
+ {
+ $view = $this->getView();
+
+ $this->assertEmpty($view->assetBundles);
+ TestJqueryAsset::register($view);
+ $this->assertEquals(1, count($view->assetBundles));
+ $this->assertArrayHasKey('yiiunit\\framework\\web\\TestJqueryAsset', $view->assetBundles);
+ }
+
+ public function testSimpleDependency()
+ {
+ $view = $this->getView();
+
+ $this->assertEmpty($view->assetBundles);
+ TestAssetBundle::register($view);
+ $this->assertEquals(2, count($view->assetBundles));
+ $this->assertArrayHasKey('yiiunit\\framework\\web\\TestAssetBundle', $view->assetBundles);
+ $this->assertArrayHasKey('yiiunit\\framework\\web\\TestJqueryAsset', $view->assetBundles);
+ }
+}
+
+class TestAssetBundle extends AssetBundle
+{
+ public $basePath = '@testWebRoot/files';
+ public $baseUrl = '@testWeb/files';
+ public $css = array(
+ 'cssFile.css',
+ );
+ public $js = array(
+ 'jsFile.js',
+ );
+ public $depends = array(
+ 'yiiunit\\framework\\web\\TestJqueryAsset'
+ );
+}
+
+class TestJqueryAsset extends AssetBundle
+{
+ public $basePath = '@testWebRoot/js';
+ public $baseUrl = '@testWeb/js';
+ public $js = array(
+ 'jquery.js',
+ );
+}
\ No newline at end of file
From a6784f4ae99a97bd78d73bce7745fdfc534c45b3 Mon Sep 17 00:00:00 2001
From: Carsten Brandt
Date: Fri, 11 Oct 2013 01:14:40 +0200
Subject: [PATCH 091/613] doc fix
---
framework/yii/base/View.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/framework/yii/base/View.php b/framework/yii/base/View.php
index df0b2b2..9c6a339 100644
--- a/framework/yii/base/View.php
+++ b/framework/yii/base/View.php
@@ -142,8 +142,8 @@ class View extends Component
*/
public $dynamicPlaceholders = array();
/**
- * @var array list of the registered asset bundles. The keys are the bundle names, and the values
- * are booleans indicating whether the bundles have been registered.
+ * @var AssetBundle[] list of the registered asset bundles. The keys are the bundle names, and the values
+ * are the registered [[AssetBundle]] objects.
* @see registerAssetBundle
*/
public $assetBundles;
From abc1e0c2bb434e628c45accaf44fff378ad36d75 Mon Sep 17 00:00:00 2001
From: Carsten Brandt
Date: Fri, 11 Oct 2013 01:54:05 +0200
Subject: [PATCH 092/613] fix issue #700
adjust depended asset position or throw exception on conflict
---
framework/yii/base/View.php | 45 ++++++++--
framework/yii/web/AssetBundle.php | 5 --
tests/unit/data/views/layout.php | 22 +++++
tests/unit/data/views/rawlayout.php | 5 ++
tests/unit/data/views/simple.php | 1 +
tests/unit/framework/web/AssetBundleTest.php | 126 +++++++++++++++++++++++++++
6 files changed, 194 insertions(+), 10 deletions(-)
create mode 100644 tests/unit/data/views/layout.php
create mode 100644 tests/unit/data/views/rawlayout.php
create mode 100644 tests/unit/data/views/simple.php
diff --git a/framework/yii/base/View.php b/framework/yii/base/View.php
index 9c6a339..1b656d2 100644
--- a/framework/yii/base/View.php
+++ b/framework/yii/base/View.php
@@ -146,7 +146,7 @@ class View extends Component
* are the registered [[AssetBundle]] objects.
* @see registerAssetBundle
*/
- public $assetBundles;
+ public $assetBundles = array();
/**
* @var string the page title
*/
@@ -523,6 +523,9 @@ class View extends Component
$this->trigger(self::EVENT_END_PAGE);
$content = ob_get_clean();
+ foreach(array_keys($this->assetBundles) as $bundle) {
+ $this->registerAssetFiles($bundle);
+ }
echo strtr($content, array(
self::PH_HEAD => $this->renderHeadHtml(),
self::PH_BODY_BEGIN => $this->renderBodyBeginHtml(),
@@ -530,7 +533,6 @@ class View extends Component
));
unset(
- $this->assetBundles,
$this->metaTags,
$this->linkTags,
$this->css,
@@ -566,25 +568,58 @@ class View extends Component
echo self::PH_HEAD;
}
+ protected function registerAssetFiles($name)
+ {
+ if (!isset($this->assetBundles[$name])) {
+ return;
+ }
+ $bundle = $this->assetBundles[$name];
+ foreach($bundle->depends as $depName) {
+ $this->registerAssetFiles($depName);
+ }
+ $bundle->registerAssets($this);
+ unset($this->assetBundles[$name]);
+ }
+
/**
* Registers the named asset bundle.
* All dependent asset bundles will be registered.
* @param string $name the name of the asset bundle.
+ * @param integer|null $position optional parameter to force a minimum Javascript position TODO link to relevant method
+ * Null means to register on default position.
* @return AssetBundle the registered asset bundle instance
* @throws InvalidConfigException if the asset bundle does not exist or a circular dependency is detected
*/
- public function registerAssetBundle($name)
+ public function registerAssetBundle($name, $position = null)
{
if (!isset($this->assetBundles[$name])) {
$am = $this->getAssetManager();
$bundle = $am->getBundle($name);
$this->assetBundles[$name] = false;
- $bundle->registerAssets($this);
+ // register dependencies
+ $pos = isset($bundle->jsOptions['position']) ? $bundle->jsOptions['position'] : null;
+ foreach ($bundle->depends as $dep) {
+ $this->registerAssetBundle($dep, $pos);
+ }
$this->assetBundles[$name] = $bundle;
} elseif ($this->assetBundles[$name] === false) {
throw new InvalidConfigException("A circular dependency is detected for bundle '$name'.");
+ } else {
+ $bundle = $this->assetBundles[$name];
+ }
+
+ if ($position !== null) {
+ $pos = isset($bundle->jsOptions['position']) ? $bundle->jsOptions['position'] : null;
+ if ($pos === null) {
+ $bundle->jsOptions['position'] = $pos = $position;
+ } elseif ($pos > $position) {
+ throw new InvalidConfigException("A dependend AssetBundle of '$name' requires a higher position but it conflicts with the position set for '$name'!");
+ }
+ foreach ($bundle->depends as $dep) {
+ $this->registerAssetBundle($dep, $pos);
+ }
}
- return $this->assetBundles[$name];
+ return $bundle;
}
/**
diff --git a/framework/yii/web/AssetBundle.php b/framework/yii/web/AssetBundle.php
index d324ef3..aa2d02b 100644
--- a/framework/yii/web/AssetBundle.php
+++ b/framework/yii/web/AssetBundle.php
@@ -130,7 +130,6 @@ class AssetBundle extends Object
/**
* Registers the CSS and JS files with the given view.
- * This method will first register all dependent asset bundles.
* It will then try to convert non-CSS or JS files (e.g. LESS, Sass) into the corresponding
* CSS or JS files using [[AssetManager::converter|asset converter]].
* @param \yii\base\View $view the view that the asset files to be registered with.
@@ -139,10 +138,6 @@ class AssetBundle extends Object
*/
public function registerAssets($view)
{
- foreach ($this->depends as $name) {
- $view->registerAssetBundle($name);
- }
-
$this->publish($view->getAssetManager());
foreach ($this->js as $js) {
diff --git a/tests/unit/data/views/layout.php b/tests/unit/data/views/layout.php
new file mode 100644
index 0000000..cd9d9d6
--- /dev/null
+++ b/tests/unit/data/views/layout.php
@@ -0,0 +1,22 @@
+
+beginPage(); ?>
+
+
+
+ Test
+ head(); ?>
+
+
+beginBody(); ?>
+
+
+
+endBody(); ?>
+
+
+endPage(); ?>
\ No newline at end of file
diff --git a/tests/unit/data/views/rawlayout.php b/tests/unit/data/views/rawlayout.php
new file mode 100644
index 0000000..6864642
--- /dev/null
+++ b/tests/unit/data/views/rawlayout.php
@@ -0,0 +1,5 @@
+beginPage(); ?>1head(); ?>2beginBody(); ?>3endBody(); ?>4endPage(); ?>
\ No newline at end of file
diff --git a/tests/unit/data/views/simple.php b/tests/unit/data/views/simple.php
new file mode 100644
index 0000000..437ba90
--- /dev/null
+++ b/tests/unit/data/views/simple.php
@@ -0,0 +1 @@
+This is a damn simple view file.
\ No newline at end of file
diff --git a/tests/unit/framework/web/AssetBundleTest.php b/tests/unit/framework/web/AssetBundleTest.php
index 60bb7eb..02cb5ed 100644
--- a/tests/unit/framework/web/AssetBundleTest.php
+++ b/tests/unit/framework/web/AssetBundleTest.php
@@ -45,6 +45,13 @@ class AssetBundleTest extends \yiiunit\TestCase
TestJqueryAsset::register($view);
$this->assertEquals(1, count($view->assetBundles));
$this->assertArrayHasKey('yiiunit\\framework\\web\\TestJqueryAsset', $view->assetBundles);
+ $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestJqueryAsset'] instanceof AssetBundle);
+
+ $expected = <<
+4
+EOF;
+ $this->assertEquals($expected, $view->renderFile('@yiiunit/data/views/rawlayout.php'));
}
public function testSimpleDependency()
@@ -56,6 +63,125 @@ class AssetBundleTest extends \yiiunit\TestCase
$this->assertEquals(2, count($view->assetBundles));
$this->assertArrayHasKey('yiiunit\\framework\\web\\TestAssetBundle', $view->assetBundles);
$this->assertArrayHasKey('yiiunit\\framework\\web\\TestJqueryAsset', $view->assetBundles);
+ $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestAssetBundle'] instanceof AssetBundle);
+ $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestJqueryAsset'] instanceof AssetBundle);
+
+ $expected = <<
+23
+
+4
+EOF;
+ $this->assertEquals($expected, $view->renderFile('@yiiunit/data/views/rawlayout.php'));
+ }
+
+ public function positionProvider()
+ {
+ return array(
+ array(View::POS_HEAD, true),
+ array(View::POS_HEAD, false),
+ array(View::POS_BEGIN, true),
+ array(View::POS_BEGIN, false),
+ array(View::POS_END, true),
+ array(View::POS_END, false),
+ );
+ }
+
+ /**
+ * @dataProvider positionProvider
+ */
+ public function testPositionDependency($pos, $jqAlreadyRegistered)
+ {
+ $view = $this->getView();
+
+ $view->getAssetManager()->bundles['yiiunit\\framework\\web\\TestAssetBundle'] = array(
+ 'jsOptions' => array(
+ 'position' => $pos,
+ ),
+ );
+
+ $this->assertEmpty($view->assetBundles);
+ if ($jqAlreadyRegistered) {
+ TestJqueryAsset::register($view);
+ }
+ TestAssetBundle::register($view);
+ $this->assertEquals(2, count($view->assetBundles));
+ $this->assertArrayHasKey('yiiunit\\framework\\web\\TestAssetBundle', $view->assetBundles);
+ $this->assertArrayHasKey('yiiunit\\framework\\web\\TestJqueryAsset', $view->assetBundles);
+
+ $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestAssetBundle'] instanceof AssetBundle);
+ $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestJqueryAsset'] instanceof AssetBundle);
+
+ $this->assertArrayHasKey('position', $view->assetBundles['yiiunit\\framework\\web\\TestAssetBundle']->jsOptions);
+ $this->assertEquals($pos, $view->assetBundles['yiiunit\\framework\\web\\TestAssetBundle']->jsOptions['position']);
+ $this->assertArrayHasKey('position', $view->assetBundles['yiiunit\\framework\\web\\TestJqueryAsset']->jsOptions);
+ $this->assertEquals($pos, $view->assetBundles['yiiunit\\framework\\web\\TestJqueryAsset']->jsOptions['position']);
+
+ switch($pos)
+ {
+ case View::POS_HEAD:
+ $expected = <<
+
+
+234
+EOF;
+ break;
+ case View::POS_BEGIN:
+ $expected = <<
+2
+
+34
+EOF;
+ break;
+ default:
+ case View::POS_END:
+ $expected = <<
+23
+
+4
+EOF;
+ break;
+ }
+ $this->assertEquals($expected, $view->renderFile('@yiiunit/data/views/rawlayout.php'));
+ }
+
+ public function positionProvider2()
+ {
+ return array(
+ array(View::POS_BEGIN, true),
+ array(View::POS_BEGIN, false),
+ array(View::POS_END, true),
+ array(View::POS_END, false),
+ );
+ }
+
+ /**
+ * @dataProvider positionProvider
+ */
+ public function testPositionDependencyConflict($pos, $jqAlreadyRegistered)
+ {
+ $view = $this->getView();
+
+ $view->getAssetManager()->bundles['yiiunit\\framework\\web\\TestAssetBundle'] = array(
+ 'jsOptions' => array(
+ 'position' => $pos - 1,
+ ),
+ );
+ $view->getAssetManager()->bundles['yiiunit\\framework\\web\\TestJqueryAsset'] = array(
+ 'jsOptions' => array(
+ 'position' => $pos,
+ ),
+ );
+
+ $this->assertEmpty($view->assetBundles);
+ if ($jqAlreadyRegistered) {
+ TestJqueryAsset::register($view);
+ }
+ $this->setExpectedException('yii\\base\\InvalidConfigException');
+ TestAssetBundle::register($view);
}
}
From a922c41ee63ac4e182042a201c442257f6e35788 Mon Sep 17 00:00:00 2001
From: Carsten Brandt
Date: Fri, 11 Oct 2013 02:14:59 +0200
Subject: [PATCH 093/613] more asset bundle tests and docs
---
framework/yii/base/View.php | 37 +++++++++-------
tests/unit/framework/web/AssetBundleTest.php | 64 +++++++++++++++++++++++++---
2 files changed, 81 insertions(+), 20 deletions(-)
diff --git a/framework/yii/base/View.php b/framework/yii/base/View.php
index 1b656d2..27ede61 100644
--- a/framework/yii/base/View.php
+++ b/framework/yii/base/View.php
@@ -543,6 +543,24 @@ class View extends Component
}
/**
+ * Registers all files provided by an asset bundle including depending bundles files.
+ * Removes a bundle from [[assetBundles]] once registered.
+ * @param string $name name of the bundle to register
+ */
+ private function registerAssetFiles($name)
+ {
+ if (!isset($this->assetBundles[$name])) {
+ return;
+ }
+ $bundle = $this->assetBundles[$name];
+ foreach($bundle->depends as $dep) {
+ $this->registerAssetFiles($dep);
+ }
+ $bundle->registerAssets($this);
+ unset($this->assetBundles[$name]);
+ }
+
+ /**
* Marks the beginning of an HTML body section.
*/
public function beginBody()
@@ -568,25 +586,14 @@ class View extends Component
echo self::PH_HEAD;
}
- protected function registerAssetFiles($name)
- {
- if (!isset($this->assetBundles[$name])) {
- return;
- }
- $bundle = $this->assetBundles[$name];
- foreach($bundle->depends as $depName) {
- $this->registerAssetFiles($depName);
- }
- $bundle->registerAssets($this);
- unset($this->assetBundles[$name]);
- }
-
/**
* Registers the named asset bundle.
* All dependent asset bundles will be registered.
* @param string $name the name of the asset bundle.
- * @param integer|null $position optional parameter to force a minimum Javascript position TODO link to relevant method
- * Null means to register on default position.
+ * @param integer|null $position if set, this forces a minimum position for javascript files.
+ * This will adjust depending assets javascript file position or fail if requirement can not be met.
+ * If this is null, asset bundles position settings will not be changed.
+ * See [[registerJsFile]] for more details on javascript position.
* @return AssetBundle the registered asset bundle instance
* @throws InvalidConfigException if the asset bundle does not exist or a circular dependency is detected
*/
diff --git a/tests/unit/framework/web/AssetBundleTest.php b/tests/unit/framework/web/AssetBundleTest.php
index 02cb5ed..ce33ce7 100644
--- a/tests/unit/framework/web/AssetBundleTest.php
+++ b/tests/unit/framework/web/AssetBundleTest.php
@@ -42,10 +42,10 @@ class AssetBundleTest extends \yiiunit\TestCase
$view = $this->getView();
$this->assertEmpty($view->assetBundles);
- TestJqueryAsset::register($view);
+ TestSimpleAsset::register($view);
$this->assertEquals(1, count($view->assetBundles));
- $this->assertArrayHasKey('yiiunit\\framework\\web\\TestJqueryAsset', $view->assetBundles);
- $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestJqueryAsset'] instanceof AssetBundle);
+ $this->assertArrayHasKey('yiiunit\\framework\\web\\TestSimpleAsset', $view->assetBundles);
+ $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestSimpleAsset'] instanceof AssetBundle);
$expected = <<
@@ -60,11 +60,13 @@ EOF;
$this->assertEmpty($view->assetBundles);
TestAssetBundle::register($view);
- $this->assertEquals(2, count($view->assetBundles));
+ $this->assertEquals(3, count($view->assetBundles));
$this->assertArrayHasKey('yiiunit\\framework\\web\\TestAssetBundle', $view->assetBundles);
$this->assertArrayHasKey('yiiunit\\framework\\web\\TestJqueryAsset', $view->assetBundles);
+ $this->assertArrayHasKey('yiiunit\\framework\\web\\TestAssetLevel3', $view->assetBundles);
$this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestAssetBundle'] instanceof AssetBundle);
$this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestJqueryAsset'] instanceof AssetBundle);
+ $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestAssetLevel3'] instanceof AssetBundle);
$expected = <<
@@ -105,17 +107,21 @@ EOF;
TestJqueryAsset::register($view);
}
TestAssetBundle::register($view);
- $this->assertEquals(2, count($view->assetBundles));
+ $this->assertEquals(3, count($view->assetBundles));
$this->assertArrayHasKey('yiiunit\\framework\\web\\TestAssetBundle', $view->assetBundles);
$this->assertArrayHasKey('yiiunit\\framework\\web\\TestJqueryAsset', $view->assetBundles);
+ $this->assertArrayHasKey('yiiunit\\framework\\web\\TestAssetLevel3', $view->assetBundles);
$this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestAssetBundle'] instanceof AssetBundle);
$this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestJqueryAsset'] instanceof AssetBundle);
+ $this->assertTrue($view->assetBundles['yiiunit\\framework\\web\\TestAssetLevel3'] instanceof AssetBundle);
$this->assertArrayHasKey('position', $view->assetBundles['yiiunit\\framework\\web\\TestAssetBundle']->jsOptions);
$this->assertEquals($pos, $view->assetBundles['yiiunit\\framework\\web\\TestAssetBundle']->jsOptions['position']);
$this->assertArrayHasKey('position', $view->assetBundles['yiiunit\\framework\\web\\TestJqueryAsset']->jsOptions);
$this->assertEquals($pos, $view->assetBundles['yiiunit\\framework\\web\\TestJqueryAsset']->jsOptions['position']);
+ $this->assertArrayHasKey('position', $view->assetBundles['yiiunit\\framework\\web\\TestAssetLevel3']->jsOptions);
+ $this->assertEquals($pos, $view->assetBundles['yiiunit\\framework\\web\\TestAssetLevel3']->jsOptions['position']);
switch($pos)
{
@@ -183,6 +189,21 @@ EOF;
$this->setExpectedException('yii\\base\\InvalidConfigException');
TestAssetBundle::register($view);
}
+
+ public function testCircularDependency()
+ {
+ $this->setExpectedException('yii\\base\\InvalidConfigException');
+ TestAssetCircleA::register($this->getView());
+ }
+}
+
+class TestSimpleAsset extends AssetBundle
+{
+ public $basePath = '@testWebRoot/js';
+ public $baseUrl = '@testWeb/js';
+ public $js = array(
+ 'jquery.js',
+ );
}
class TestAssetBundle extends AssetBundle
@@ -207,4 +228,37 @@ class TestJqueryAsset extends AssetBundle
public $js = array(
'jquery.js',
);
+ public $depends = array(
+ 'yiiunit\\framework\\web\\TestAssetLevel3'
+ );
+}
+
+class TestAssetLevel3 extends AssetBundle
+{
+ public $basePath = '@testWebRoot/js';
+ public $baseUrl = '@testWeb/js';
+}
+
+class TestAssetCircleA extends AssetBundle
+{
+ public $basePath = '@testWebRoot/js';
+ public $baseUrl = '@testWeb/js';
+ public $js = array(
+ 'jquery.js',
+ );
+ public $depends = array(
+ 'yiiunit\\framework\\web\\TestAssetCircleB'
+ );
+}
+
+class TestAssetCircleB extends AssetBundle
+{
+ public $basePath = '@testWebRoot/js';
+ public $baseUrl = '@testWeb/js';
+ public $js = array(
+ 'jquery.js',
+ );
+ public $depends = array(
+ 'yiiunit\\framework\\web\\TestAssetCircleA'
+ );
}
\ No newline at end of file
From 80cf9c8be9d5d29386f725d7900e4b94dba5ccf9 Mon Sep 17 00:00:00 2001
From: Carsten Brandt
Date: Fri, 11 Oct 2013 02:19:32 +0200
Subject: [PATCH 094/613] better error message
---
framework/yii/base/View.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/framework/yii/base/View.php b/framework/yii/base/View.php
index 27ede61..9071cee 100644
--- a/framework/yii/base/View.php
+++ b/framework/yii/base/View.php
@@ -620,7 +620,7 @@ class View extends Component
if ($pos === null) {
$bundle->jsOptions['position'] = $pos = $position;
} elseif ($pos > $position) {
- throw new InvalidConfigException("A dependend AssetBundle of '$name' requires a higher position but it conflicts with the position set for '$name'!");
+ throw new InvalidConfigException("An asset bundle that depends on '$name' has a higher javascript file position configured than '$name'.");
}
foreach ($bundle->depends as $dep) {
$this->registerAssetBundle($dep, $pos);
From 72b4f4f71779e1111c2657749ec87b1ee8b4a245 Mon Sep 17 00:00:00 2001
From: Carsten Brandt
Date: Fri, 11 Oct 2013 02:20:51 +0200
Subject: [PATCH 095/613] added comment
---
framework/yii/base/View.php | 1 +
1 file changed, 1 insertion(+)
diff --git a/framework/yii/base/View.php b/framework/yii/base/View.php
index 9071cee..e3dcda8 100644
--- a/framework/yii/base/View.php
+++ b/framework/yii/base/View.php
@@ -622,6 +622,7 @@ class View extends Component
} elseif ($pos > $position) {
throw new InvalidConfigException("An asset bundle that depends on '$name' has a higher javascript file position configured than '$name'.");
}
+ // update position for all dependencies
foreach ($bundle->depends as $dep) {
$this->registerAssetBundle($dep, $pos);
}
From 7817514e86cb96841bc47213b8fcdd905f3c2731 Mon Sep 17 00:00:00 2001
From: Carsten Brandt
Date: Fri, 11 Oct 2013 02:42:32 +0200
Subject: [PATCH 096/613] fixed default status code for Response::redirect()
fixes #961
---
framework/yii/web/Response.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/framework/yii/web/Response.php b/framework/yii/web/Response.php
index 703ea6f..2dc8721 100644
--- a/framework/yii/web/Response.php
+++ b/framework/yii/web/Response.php
@@ -602,12 +602,12 @@ class Response extends \yii\base\Response
* Any relative URL will be converted into an absolute one by prepending it with the host info
* of the current request.
*
- * @param integer $statusCode the HTTP status code. If null, it will use 302.
+ * @param integer $statusCode the HTTP status code. Defaults to 302.
* See [[http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html]]
* for details about HTTP status code
* @return static the response object itself
*/
- public function redirect($url, $statusCode = null)
+ public function redirect($url, $statusCode = 302)
{
if (is_array($url) && isset($url[0])) {
// ensure the route is absolute
From 982b7fe4ae41539515173fb1f8709f33bebb7571 Mon Sep 17 00:00:00 2001
From: Carsten Brandt
Date: Fri, 11 Oct 2013 11:59:23 +0200
Subject: [PATCH 097/613] better validation of module in gii module generator
fixes #963
---
framework/yii/gii/generators/module/Generator.php | 3 +++
1 file changed, 3 insertions(+)
diff --git a/framework/yii/gii/generators/module/Generator.php b/framework/yii/gii/generators/module/Generator.php
index 52fbfe4..1b35db8 100644
--- a/framework/yii/gii/generators/module/Generator.php
+++ b/framework/yii/gii/generators/module/Generator.php
@@ -147,6 +147,9 @@ EOD;
if (strpos($this->moduleClass, '\\') === false || Yii::getAlias('@' . str_replace('\\', '/', $this->moduleClass)) === false) {
$this->addError('moduleClass', 'Module class must be properly namespaced.');
}
+ if (substr($this->moduleClass, -1, 1) == '\\') {
+ $this->addError('moduleClass', 'Module class name must not be empty. Please enter a fully qualified class name. e.g. "app\\modules\\admin\\Module".');
+ }
}
/**
From 6ba6fbe9471b6d733bcbc63dfe3ba02b093385b6 Mon Sep 17 00:00:00 2001
From: Carsten Brandt
Date: Fri, 11 Oct 2013 12:51:27 +0200
Subject: [PATCH 098/613] mention response component in controller.md
---
docs/guide/controller.md | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/docs/guide/controller.md b/docs/guide/controller.md
index 2874c66..c665037 100644
--- a/docs/guide/controller.md
+++ b/docs/guide/controller.md
@@ -35,6 +35,9 @@ class SiteController extends Controller
```
As you can see, typical controller contains actions that are public class methods named as `actionSomething`.
+The output of an action is what the method returns. The return value will be handled by the `response` application
+component which can convert the output to differnet formats such as JSON for example. The default behavior
+is to output the value unchanged though.
Routes
------
@@ -183,7 +186,6 @@ Filters
Catching all incoming requests
------------------------------
-
See also
--------
From 300c866be2ed3e8c83cfc88c92eb295d0e2deedd Mon Sep 17 00:00:00 2001
From: Carsten Brandt
Date: Fri, 11 Oct 2013 14:01:17 +0200
Subject: [PATCH 099/613] adjusted composer.json for smarty and twig
not need to suggest packages in core. They are required by extension
composer.json anyway.
---
extensions/smarty/composer.json | 2 +-
framework/composer.json | 4 +---
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/extensions/smarty/composer.json b/extensions/smarty/composer.json
index 5682574..333e76e 100644
--- a/extensions/smarty/composer.json
+++ b/extensions/smarty/composer.json
@@ -20,7 +20,7 @@
"minimum-stability": "dev",
"require": {
"yiisoft/yii2": "*",
- "smarty/smarty": "v3.1.13"
+ "smarty/smarty": ">=v3.1.13"
},
"autoload": {
"psr-0": { "yii\\smarty\\": "" }
diff --git a/framework/composer.json b/framework/composer.json
index 89d6064..c5ff072 100644
--- a/framework/composer.json
+++ b/framework/composer.json
@@ -74,8 +74,6 @@
"psr-0": { "yii\\": "/" }
},
"suggest": {
- "michelf/php-markdown": "Required by Markdown.",
- "twig/twig": "Required by TwigViewRenderer.",
- "smarty/smarty": "Required by SmartyViewRenderer."
+ "michelf/php-markdown": "Required by Markdown."
}
}
From ee89134ffe29179a95ff856e1d7490545e2c13dc Mon Sep 17 00:00:00 2001
From: Carsten Brandt
Date: Fri, 11 Oct 2013 14:51:07 +0200
Subject: [PATCH 100/613] make db\Command::getPdoType() protected
fixes #964
---
framework/yii/db/Command.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/framework/yii/db/Command.php b/framework/yii/db/Command.php
index 73ac04b..d0f3877 100644
--- a/framework/yii/db/Command.php
+++ b/framework/yii/db/Command.php
@@ -251,7 +251,7 @@ class Command extends \yii\base\Component
* @return integer the PDO type
* @see http://www.php.net/manual/en/pdo.constants.php
*/
- private function getPdoType($data)
+ protected function getPdoType($data)
{
static $typeMap = array( // php type => PDO type
'boolean' => \PDO::PARAM_BOOL,
From 2ae5c23d484a7b616a1dfdc5bd9dfe746980e466 Mon Sep 17 00:00:00 2001
From: Qiang Xue
Date: Fri, 11 Oct 2013 20:41:59 -0400
Subject: [PATCH 101/613] minor doc fix.
---
docs/guide/active-record.md | 4 +++-
docs/guide/validation.md | 4 ++--
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/docs/guide/active-record.md b/docs/guide/active-record.md
index fc98f98..7d0c744 100644
--- a/docs/guide/active-record.md
+++ b/docs/guide/active-record.md
@@ -175,7 +175,9 @@ $customer->delete();
Customer::updateAllCounters(array('age' => 1));
```
-Notice that you can always use the `save` method, and ActiveRecord will automatically perform an INSERT for new records and an UPDATE for existing ones.
+> Info: The `save()` method will either perform an `INSERT` or `UPDATE` SQL statement, depending
+ on whether the ActiveRecord being saved is new or not by checking `ActiveRecord::isNewRecord`.
+
Data Input and Validation
-------------------------
diff --git a/docs/guide/validation.md b/docs/guide/validation.md
index 0322573..c555913 100644
--- a/docs/guide/validation.md
+++ b/docs/guide/validation.md
@@ -38,7 +38,7 @@ Compares the specified attribute value with another value and validates if they
Verifies if the attribute represents a date, time or datetime in a proper format.
-- `format` the date format that the value being validated should follow accodring to [[http://www.php.net/manual/en/datetime.createfromformat.php]]. _('Y-m-d')_
+- `format` the date format that the value being validated should follow according to [[http://www.php.net/manual/en/datetime.createfromformat.php]]. _('Y-m-d')_
- `timestampAttribute` the name of the attribute to receive the parsing result.
### `default`: [[DefaultValueValidator]]
@@ -179,4 +179,4 @@ if ($validator->validateValue($email)) {
}
```
-TBD: refer to http://www.yiiframework.com/wiki/56/ for the format
\ No newline at end of file
+TBD: refer to http://www.yiiframework.com/wiki/56/ for the format
From bc743a32b78d48f824dcbf4eff0601b7b23fff63 Mon Sep 17 00:00:00 2001
From: Qiang Xue
Date: Sat, 12 Oct 2013 20:52:41 -0400
Subject: [PATCH 102/613] Fixes #968: clientOptions should not be ignored when
enabling internationalization.
---
extensions/jui/yii/jui/DatePicker.php | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/extensions/jui/yii/jui/DatePicker.php b/extensions/jui/yii/jui/DatePicker.php
index c275190..ea05579 100644
--- a/extensions/jui/yii/jui/DatePicker.php
+++ b/extensions/jui/yii/jui/DatePicker.php
@@ -9,6 +9,7 @@ namespace yii\jui;
use Yii;
use yii\helpers\Html;
+use yii\helpers\Json;
/**
* DatePicker renders an datepicker jQuery UI widget.
@@ -61,11 +62,19 @@ class DatePicker extends InputWidget
public function run()
{
echo $this->renderWidget() . "\n";
- $this->registerWidget('datepicker', DatePickerAsset::className());
if ($this->language !== false) {
$view = $this->getView();
DatePickerRegionalAsset::register($view);
- $view->registerJs("$('#{$this->options['id']}').datepicker('option', $.datepicker.regional['{$this->language}']);");
+ // do not pass in any options when creating the widget
+ // set the options later so that the options can be combined with regional options
+ $options = $this->clientOptions;
+ $this->clientOptions = array();
+ $this->registerWidget('datepicker', DatePickerAsset::className());
+ $this->clientOptions = $options;
+ $options = Json::encode($options);
+ $view->registerJs("$('#{$this->options['id']}').datepicker('option', $.extend({}, $.datepicker.regional['{$this->language}'], $options));");
+ } else {
+ $this->registerWidget('datepicker', DatePickerAsset::className());
}
}
From 3a981e26dabb389ddb9e2cb23168a5e091fc3c0c Mon Sep 17 00:00:00 2001
From: Carsten Brandt
Date: Sun, 13 Oct 2013 15:19:20 +0200
Subject: [PATCH 103/613] improved errorhandler output
when error occurs while handling errors output was not readable in web
context
---
framework/yii/base/Application.php | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/framework/yii/base/Application.php b/framework/yii/base/Application.php
index 3cc90d9..683b9ce 100644
--- a/framework/yii/base/Application.php
+++ b/framework/yii/base/Application.php
@@ -450,7 +450,11 @@ abstract class Application extends Module
$msg .= "\nPrevious exception:\n";
$msg .= (string)$exception;
if (YII_DEBUG) {
- echo $msg;
+ if (PHP_SAPI === 'cli') {
+ echo $msg . "\n";
+ } else {
+ echo '
';
+ }
}
$msg .= "\n\$_SERVER = " . var_export($_SERVER, true);
error_log($msg);
From cba8ec73104902128248257250f2e84688838f2b Mon Sep 17 00:00:00 2001
From: Carsten Brandt
Date: Sun, 13 Oct 2013 15:41:14 +0200
Subject: [PATCH 104/613] fixes issue with debugmodule initializing view
component too early
fixes #929
---
framework/yii/debug/Module.php | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/framework/yii/debug/Module.php b/framework/yii/debug/Module.php
index dd027a7..9550b57 100644
--- a/framework/yii/debug/Module.php
+++ b/framework/yii/debug/Module.php
@@ -8,6 +8,7 @@
namespace yii\debug;
use Yii;
+use yii\base\Application;
use yii\base\View;
use yii\web\HttpException;
@@ -55,7 +56,11 @@ class Module extends \yii\base\Module
parent::init();
$this->dataPath = Yii::getAlias($this->dataPath);
$this->logTarget = Yii::$app->getLog()->targets['debug'] = new LogTarget($this);
- Yii::$app->getView()->on(View::EVENT_END_BODY, array($this, 'renderToolbar'));
+ // do not initialize view component before application is ready (needed when debug in preload)
+ $module = $this;
+ Yii::$app->on(Application::EVENT_BEFORE_ACTION, function() use ($module) {
+ Yii::$app->getView()->on(View::EVENT_END_BODY, array($module, 'renderToolbar'));
+ });
foreach (array_merge($this->corePanels(), $this->panels) as $id => $config) {
$config['module'] = $this;
From 1600889f4ed85d25b06cb1e1ae283e19e429cddd Mon Sep 17 00:00:00 2001
From: Carsten Brandt
Date: Sun, 13 Oct 2013 19:50:14 +0200
Subject: [PATCH 105/613] added isAttributeActive to Model
consistent api for safe and required
---
framework/yii/base/Model.php | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/framework/yii/base/Model.php b/framework/yii/base/Model.php
index 93b5a6b..c8c253a 100644
--- a/framework/yii/base/Model.php
+++ b/framework/yii/base/Model.php
@@ -422,6 +422,7 @@ class Model extends Component implements IteratorAggregate, ArrayAccess
* Returns a value indicating whether the attribute is safe for massive assignments.
* @param string $attribute attribute name
* @return boolean whether the attribute is safe for massive assignments
+ * @see safeAttributes()
*/
public function isAttributeSafe($attribute)
{
@@ -429,6 +430,17 @@ class Model extends Component implements IteratorAggregate, ArrayAccess
}
/**
+ * Returns a value indicating whether the attribute is active in the current scenario.
+ * @param string $attribute attribute name
+ * @return boolean whether the attribute is active in the current scenario
+ * @see activeAttributes()
+ */
+ public function isAttributeActive($attribute)
+ {
+ return in_array($attribute, $this->activeAttributes(), true);
+ }
+
+ /**
* Returns the text label for the specified attribute.
* @param string $attribute the attribute name
* @return string the attribute label
From 5ad8fe5f45afab3dbc08e331e69f8e73a13d5f05 Mon Sep 17 00:00:00 2001
From: Carsten Brandt
Date: Sun, 13 Oct 2013 19:56:12 +0200
Subject: [PATCH 106/613] Filter only active attributes in gridview
When we do not want an attribute to be searched we do not define it in
the filter model, or mark it inctive in the scenario when we use the
original model.
GridView should not try to access the attribute then and automatically
not display the filter field.
---
framework/yii/grid/DataColumn.php | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/framework/yii/grid/DataColumn.php b/framework/yii/grid/DataColumn.php
index 9e0ec79..478394b 100644
--- a/framework/yii/grid/DataColumn.php
+++ b/framework/yii/grid/DataColumn.php
@@ -115,7 +115,9 @@ class DataColumn extends Column
{
if (is_string($this->filter)) {
return $this->filter;
- } elseif ($this->filter !== false && $this->grid->filterModel instanceof Model && $this->attribute !== null) {
+ } elseif ($this->filter !== false && $this->grid->filterModel instanceof Model &&
+ $this->attribute !== null && $this->grid->filterModel->isAttributeActive($this->attribute))
+ {
if (is_array($this->filter)) {
$options = array_merge(array('prompt' => ''), $this->filterInputOptions);
return Html::activeDropDownList($this->grid->filterModel, $this->attribute, $this->filter, $options);
From 6544db48dc905726309114a3416adaeb862999b1 Mon Sep 17 00:00:00 2001
From: Carsten Brandt
Date: Sun, 13 Oct 2013 21:43:51 +0200
Subject: [PATCH 107/613] consistent summary display for ListView and GridView
Total 0 items. when list is empty.
and showing x out of x for n>0 and paging on.
---
framework/yii/widgets/BaseListView.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/framework/yii/widgets/BaseListView.php b/framework/yii/widgets/BaseListView.php
index d4647ff..8e827d6 100644
--- a/framework/yii/widgets/BaseListView.php
+++ b/framework/yii/widgets/BaseListView.php
@@ -132,14 +132,14 @@ abstract class BaseListView extends Widget
public function renderSummary()
{
$count = $this->dataProvider->getCount();
- if (($pagination = $this->dataProvider->getPagination()) !== false) {
+ if (($pagination = $this->dataProvider->getPagination()) !== false && $count > 0) {
$totalCount = $this->dataProvider->getTotalCount();
$begin = $pagination->getPage() * $pagination->pageSize + 1;
$end = $begin + $count - 1;
$page = $pagination->getPage() + 1;
$pageCount = $pagination->pageCount;
if (($summaryContent = $this->summary) === null) {
- $summaryContent = '
ActiveForm::end(); ?>
diff --git a/framework/yii/gii/views/default/view.php b/framework/yii/gii/views/default/view.php
index 9754918..91c6bcb 100644
--- a/framework/yii/gii/views/default/view.php
+++ b/framework/yii/gii/views/default/view.php
@@ -45,10 +45,10 @@ foreach ($generator->templates as $name => $path) {
Please select which set of the templates should be used to generated the code.
'); ?>
From 6f9785a2937144744ae5f3466b0d1167b6bb995e Mon Sep 17 00:00:00 2001
From: Alexander Makarov
Date: Thu, 17 Oct 2013 12:30:41 +0400
Subject: [PATCH 148/613] fixes #995
---
framework/yii/base/Model.php | 6 +++---
framework/yii/data/ActiveDataProvider.php | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/framework/yii/base/Model.php b/framework/yii/base/Model.php
index c8c253a..7fb8c35 100644
--- a/framework/yii/base/Model.php
+++ b/framework/yii/base/Model.php
@@ -117,7 +117,7 @@ class Model extends Component implements IteratorAggregate, ArrayAccess
* ~~~
*
* In the above `$attribute` refers to currently validated attribute name while `$params` contains an array of
- * validator configuration options such as `max` in case of `length` validator. Currently validate attribute value
+ * validator configuration options such as `max` in case of `string` validator. Currently validate attribute value
* can be accessed as `$this->[$attribute]`.
*
* Yii also provides a set of [[Validator::builtInValidators|built-in validators]].
@@ -129,8 +129,8 @@ class Model extends Component implements IteratorAggregate, ArrayAccess
* array(
* // built-in "required" validator
* array('username', 'required'),
- * // built-in "length" validator customized with "min" and "max" properties
- * array('username', 'length', 'min' => 3, 'max' => 12),
+ * // built-in "string" validator customized with "min" and "max" properties
+ * array('username', 'string', 'min' => 3, 'max' => 12),
* // built-in "compare" validator that is used in "register" scenario only
* array('password', 'compare', 'compareAttribute' => 'password2', 'on' => 'register'),
* // an inline validator defined via the "authenticate()" method in the model class
diff --git a/framework/yii/data/ActiveDataProvider.php b/framework/yii/data/ActiveDataProvider.php
index c5f1bcd..bd822f9 100644
--- a/framework/yii/data/ActiveDataProvider.php
+++ b/framework/yii/data/ActiveDataProvider.php
@@ -77,7 +77,7 @@ class ActiveDataProvider extends BaseDataProvider
public $db;
/**
- * Initializes the DbCache component.
+ * Initializes the DB connection component.
* This method will initialize the [[db]] property to make sure it refers to a valid DB connection.
* @throws InvalidConfigException if [[db]] is invalid.
*/
From 22055868581d8df27e61023a1f72875b15496322 Mon Sep 17 00:00:00 2001
From: Alexander Makarov
Date: Thu, 17 Oct 2013 12:51:58 +0400
Subject: [PATCH 149/613] Fixed typos
---
docs/guide/i18n.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/guide/i18n.md b/docs/guide/i18n.md
index 9d12f65..2ec822d 100644
--- a/docs/guide/i18n.md
+++ b/docs/guide/i18n.md
@@ -40,7 +40,7 @@ Basic message translation
-------------------------
Yii basic message translation in its basic variant works without additional PHP extension. What it does is finding a
-translation of the message from source language into targer language. Message itself is specified as the first
+translation of the message from source language into target language. Message itself is specified as the second
`\Yii::t` method parameter:
```php
From 0ddd52c09a3e5ab38277376913764f5f6c94476c Mon Sep 17 00:00:00 2001
From: Carsten Brandt
Date: Thu, 17 Oct 2013 12:56:14 +0200
Subject: [PATCH 150/613] commented private property
fixes #997
---
framework/yii/data/Sort.php | 3 +++
1 file changed, 3 insertions(+)
diff --git a/framework/yii/data/Sort.php b/framework/yii/data/Sort.php
index 78fe2e0..5eb031e 100644
--- a/framework/yii/data/Sort.php
+++ b/framework/yii/data/Sort.php
@@ -234,6 +234,9 @@ class Sort extends Object
return $orders;
}
+ /**
+ * @var array the currently requested sort order as computed by [[getAttributeOrders]].
+ */
private $_attributeOrders;
/**
From 38ccc9e793d728ca777d8ef73a9600dff3bd1046 Mon Sep 17 00:00:00 2001
From: Alexander Makarov
Date: Thu, 17 Oct 2013 15:10:00 +0400
Subject: [PATCH 151/613] Fixes #930: Added i18n docs about configuring message
source
---
docs/guide/i18n.md | 41 +++++++++++++++++++++++++++++++++++++++--
1 file changed, 39 insertions(+), 2 deletions(-)
diff --git a/docs/guide/i18n.md b/docs/guide/i18n.md
index 2ec822d..0196434 100644
--- a/docs/guide/i18n.md
+++ b/docs/guide/i18n.md
@@ -47,9 +47,46 @@ translation of the message from source language into target language. Message it
echo \Yii::t('app', 'This is a string to translate!');
```
-Yii tries to load approprite translation from one of the message sources defined via `i18n` component configuration.
+Yii tries to load approprite translation from one of the message sources defined via `i18n` component configuration:
-TBD: https://github.com/yiisoft/yii2/issues/930
+```php
+'components' => array(
+ // ...
+ 'i18n' => array(
+ 'translations' => array(
+ 'app*' => array(
+ 'class' => 'yii\i18n\PhpMessageSource',
+ //'basePath' => '@app/messages',
+ //'sourceLanguage' => 'en_US',
+ 'fileMap' => array(
+ 'app' => 'app.php',
+ 'app/error' => 'error.php',
+ ),
+ ),
+ ),
+ ),
+),
+```
+
+In the above `app*` is a pattern that specifies which categories are handled by the message source. In this case we're
+handling everything that begins with `app`.
+
+`class` defines which message source is used. There following message sources are available:
+
+- PhpMessageSource that uses PHP files.
+- GettextMessageSource that uses GNU Gettext MO or PO files.
+- DbMessageSource that uses database.
+
+`basePath` defines where to store messages for the currently used message source. In this case it's `messages` directory
+ in your application directory. In case of using database this option should be skipped.
+
+`sourceLanguage` defines which language is used in `\Yii::t` second argument. If not specified, application's source
+language is used.
+
+`fileMap` specifies how message categories specified in the first argument of `\Yii::t()` are mapped to files when
+`PhpMessageSource` is used. In the example we're defining two categories `app` and `app/error`.
+
+Instead of configuring `fileMap` you can rely on convention which is `messages/BasePath/LanguageID/CategoryName.php`.
### Named placeholders
From f03c689b0209e35b98fe8fb5c71af2c95912d64e Mon Sep 17 00:00:00 2001
From: Alexander Makarov
Date: Thu, 17 Oct 2013 15:37:56 +0400
Subject: [PATCH 152/613] typo fix
---
docs/guide/i18n.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/guide/i18n.md b/docs/guide/i18n.md
index 0196434..57f08f7 100644
--- a/docs/guide/i18n.md
+++ b/docs/guide/i18n.md
@@ -71,7 +71,7 @@ Yii tries to load approprite translation from one of the message sources defined
In the above `app*` is a pattern that specifies which categories are handled by the message source. In this case we're
handling everything that begins with `app`.
-`class` defines which message source is used. There following message sources are available:
+`class` defines which message source is used. The following message sources are available:
- PhpMessageSource that uses PHP files.
- GettextMessageSource that uses GNU Gettext MO or PO files.
From b9de474ccec42d3d04f7bb5ad80040f083596ae5 Mon Sep 17 00:00:00 2001
From: Eugene Kuzminov
Date: Thu, 17 Oct 2013 15:24:52 +0300
Subject: [PATCH 153/613] debug panel : change json_encode/decode to
serialise/unserialise to prevent non-UTF characters error
---
framework/yii/debug/LogTarget.php | 6 +++---
framework/yii/debug/controllers/DefaultController.php | 4 ++--
framework/yii/debug/panels/RequestPanel.php | 2 +-
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/framework/yii/debug/LogTarget.php b/framework/yii/debug/LogTarget.php
index b415b50..33c81eb 100644
--- a/framework/yii/debug/LogTarget.php
+++ b/framework/yii/debug/LogTarget.php
@@ -49,7 +49,7 @@ class LogTarget extends Target
if (!is_file($indexFile)) {
$manifest = array();
} else {
- $manifest = json_decode(file_get_contents($indexFile), true);
+ $manifest = unserialize(file_get_contents($indexFile));
}
$request = Yii::$app->getRequest();
$manifest[$this->tag] = $summary = array(
@@ -68,8 +68,8 @@ class LogTarget extends Target
$data[$id] = $panel->save();
}
$data['summary'] = $summary;
- file_put_contents($dataFile, json_encode($data));
- file_put_contents($indexFile, json_encode($manifest));
+ file_put_contents($dataFile, serialize($data));
+ file_put_contents($indexFile, serialize($manifest));
}
/**
diff --git a/framework/yii/debug/controllers/DefaultController.php b/framework/yii/debug/controllers/DefaultController.php
index dd01412..b00881b 100644
--- a/framework/yii/debug/controllers/DefaultController.php
+++ b/framework/yii/debug/controllers/DefaultController.php
@@ -76,7 +76,7 @@ class DefaultController extends Controller
if ($this->_manifest === null) {
$indexFile = $this->module->dataPath . '/index.json';
if (is_file($indexFile)) {
- $this->_manifest = array_reverse(json_decode(file_get_contents($indexFile), true), true);
+ $this->_manifest = array_reverse(unserialize(file_get_contents($indexFile)), true);
} else {
$this->_manifest = array();
}
@@ -89,7 +89,7 @@ class DefaultController extends Controller
$manifest = $this->getManifest();
if (isset($manifest[$tag])) {
$dataFile = $this->module->dataPath . "/$tag.json";
- $data = json_decode(file_get_contents($dataFile), true);
+ $data = unserialize(file_get_contents($dataFile));
foreach ($this->module->panels as $id => $panel) {
if (isset($data[$id])) {
$panel->tag = $tag;
diff --git a/framework/yii/debug/panels/RequestPanel.php b/framework/yii/debug/panels/RequestPanel.php
index 6aa4bf8..58256e4 100644
--- a/framework/yii/debug/panels/RequestPanel.php
+++ b/framework/yii/debug/panels/RequestPanel.php
@@ -151,7 +151,7 @@ EOD;
}
$rows = array();
foreach ($values as $name => $value) {
- $rows[] = '
If you have business inquiries or other questions, please fill out the following form to contact us. Thank you.
@@ -21,16 +21,16 @@ $this->params['breadcrumbs'][] = $this->title;
diff --git a/docs/guide/upgrade-from-v1.md b/docs/guide/upgrade-from-v1.md
index f174864..bf6e562 100644
--- a/docs/guide/upgrade-from-v1.md
+++ b/docs/guide/upgrade-from-v1.md
@@ -340,10 +340,10 @@ It is represented as an `ActiveField` object. Using fields, you can build a form
```php
- field($model, 'username'); ?>
- field($model, 'password')->passwordInput(); ?>
+ =$form->field($model, 'username'); ?>
+ =$form->field($model, 'password')->passwordInput(); ?>
-
+ =Html::submitButton('Login'); ?>
```
diff --git a/docs/guide/view.md b/docs/guide/view.md
index 6ca2368..be64d22 100644
--- a/docs/guide/view.md
+++ b/docs/guide/view.md
@@ -30,7 +30,7 @@ as the corresponding key.
So the view for the action above should be in `views/site/index.php` and can be something like:
```php
-
Hello, !
+
Hello, =$username?>!
```
Instead of just scalar values you can pass anything else such as arrays or objects.
@@ -78,7 +78,7 @@ use yii\helpers\Html;
?>
- name); ?>
+ =Html::encode($user->name); ?>
```
@@ -99,7 +99,7 @@ use yii\helpers\HtmlPurifier;
?>
diff --git a/framework/yii/gii/generators/model/templates/model.php b/framework/yii/gii/generators/model/templates/model.php
index b194294..d5f0a18 100644
--- a/framework/yii/gii/generators/model/templates/model.php
+++ b/framework/yii/gii/generators/model/templates/model.php
@@ -15,29 +15,29 @@
echo "
-namespace ns; ?>;
+namespace =$generator->ns; ?>;
/**
- * This is the model class for table "".
+ * This is the model class for table "=$tableName; ?>".
*
columns as $column): ?>
- * @property phpType} \${$column->name}\n"; ?>
+ * @property ="{$column->phpType} \${$column->name}\n"; ?>
*
$relation): ?>
- * @property
+ * @property =$relation[1] . ($relation[2] ? '[]' : '') . ' $' . lcfirst($name) . "\n"; ?>
*/
-class extends baseClass, '\\') . "\n"; ?>
+class =$className; ?> extends ='\\' . ltrim($generator->baseClass, '\\') . "\n"; ?>
{
/**
* @inheritdoc
*/
public static function tableName()
{
- return '';
+ return '=$tableName; ?>';
}
/**
@@ -45,7 +45,7 @@ class extends base
*/
public function rules()
{
- return array();
+ return array(="\n\t\t\t" . implode(",\n\t\t\t", $rules) . "\n\t\t"; ?>);
}
/**
@@ -55,7 +55,7 @@ class extends base
{
return array(
$label): ?>
- '" . addslashes($label) . "',\n"; ?>
+ ="'$name' => '" . addslashes($label) . "',\n"; ?>
);
}
@@ -64,9 +64,9 @@ class extends base
/**
* @return \yii\db\ActiveRelation
*/
- public function get()
+ public function get=$name; ?>()
{
-
+ =$relation[0] . "\n"; ?>
}
}
diff --git a/framework/yii/gii/generators/module/templates/controller.php b/framework/yii/gii/generators/module/templates/controller.php
index 4d3da93..d5e92d6 100644
--- a/framework/yii/gii/generators/module/templates/controller.php
+++ b/framework/yii/gii/generators/module/templates/controller.php
@@ -8,7 +8,7 @@
echo "
-namespace getControllerNamespace(); ?>;
+namespace =$generator->getControllerNamespace(); ?>;
use yii\web\Controller;
diff --git a/framework/yii/gii/generators/module/templates/module.php b/framework/yii/gii/generators/module/templates/module.php
index 40af635..b22469c 100644
--- a/framework/yii/gii/generators/module/templates/module.php
+++ b/framework/yii/gii/generators/module/templates/module.php
@@ -13,12 +13,12 @@ $className = substr($className, $pos + 1);
echo "
-namespace ;
+namespace =$ns; ?>;
-class extends \yii\base\Module
+class =$className; ?> extends \yii\base\Module
{
- public $controllerNamespace = 'getControllerNamespace(); ?>';
+ public $controllerNamespace = '=$generator->getControllerNamespace(); ?>';
public function init()
{
diff --git a/framework/yii/gii/generators/module/templates/view.php b/framework/yii/gii/generators/module/templates/view.php
index d0e1ce6..9ca15c1 100644
--- a/framework/yii/gii/generators/module/templates/view.php
+++ b/framework/yii/gii/generators/module/templates/view.php
@@ -4,15 +4,15 @@
* @var yii\gii\generators\module\Generator $generator
*/
?>
-
-
echo $this->context->action->uniqueId; ?>
+
+
=" echo $this->context->action->uniqueId; ?>
- This is the view content for action " echo $this->context->action->id; ?>".
- The action belongs to the controller " echo get_class($this->context); ?>"
- in the " echo $this->context->module->id; ?>" module.
+ This is the view content for action "=" echo $this->context->action->id; ?>".
+ The action belongs to the controller "=" echo get_class($this->context); ?>"
+ in the "=" echo $this->context->module->id; ?>" module.
You may customize this page by editing the following file:
- echo __FILE__; ?>
+ =" echo __FILE__; ?>
- renderFile($generator->formView(), array(
+ =$this->renderFile($generator->formView(), array(
'generator' => $generator,
'form' => $form,
)); ?>
- field($generator, 'template')->sticky()
+ =$form->field($generator, 'template')->sticky()
->label('Code Template')
->dropDownList($templates)->hint('
Please select which set of the templates should be used to generated the code.
'); ?>
If you have business inquiries or other questions, please fill out the following form to contact us. Thank you.
@@ -21,16 +21,16 @@ $this->params['breadcrumbs'][] = $this->title;
diff --git a/docs/guide/upgrade-from-v1.md b/docs/guide/upgrade-from-v1.md
index 713f967..f04e849 100644
--- a/docs/guide/upgrade-from-v1.md
+++ b/docs/guide/upgrade-from-v1.md
@@ -340,10 +340,10 @@ It is represented as an `ActiveField` object. Using fields, you can build a form
```php
- =$form->field($model, 'username'); ?>
- =$form->field($model, 'password')->passwordInput(); ?>
+ = $form->field($model, 'username') ?>
+ = $form->field($model, 'password')->passwordInput() ?>