Browse Source

Merge branch 'master' into '2.1'

tags/3.0.0-alpha1
Klimov Paul 7 years ago
parent
commit
4488a6d9af
  1. 3
      .travis.yml
  2. 21
      build/controllers/DevController.php
  3. 2
      build/controllers/MimeTypeController.php
  4. 21
      build/controllers/PhpDocController.php
  5. 29
      build/controllers/ReleaseController.php
  6. 6
      build/controllers/TranslationController.php
  7. 2
      build/controllers/Utf8Controller.php
  8. 2
      composer.json
  9. 10
      cs/src/YiiConfig.php
  10. 2
      docs/guide-fr/output-data-widgets.md
  11. 2
      docs/guide-ja/output-data-widgets.md
  12. 5
      docs/guide-ru/concept-service-locator.md
  13. 2
      docs/guide-ru/output-data-widgets.md
  14. 12
      docs/guide-ru/structure-applications.md
  15. 30
      docs/guide-ru/test-overview.md
  16. 1
      docs/guide-zh-CN/concept-service-locator.md
  17. 97
      docs/guide-zh-CN/db-dao.md
  18. BIN
      docs/guide-zh-CN/images/start-country-list.png
  19. BIN
      docs/guide-zh-CN/images/start-entry-confirmation.png
  20. BIN
      docs/guide-zh-CN/images/start-form-validation.png
  21. BIN
      docs/guide-zh-CN/images/start-gii-country-grid.png
  22. BIN
      docs/guide-zh-CN/images/start-gii-country-update.png
  23. BIN
      docs/guide-zh-CN/images/start-gii-crud-preview.png
  24. BIN
      docs/guide-zh-CN/images/start-gii-crud.png
  25. BIN
      docs/guide-zh-CN/images/start-gii-model-preview.png
  26. BIN
      docs/guide-zh-CN/images/start-gii-model.png
  27. BIN
      docs/guide-zh-CN/images/start-hello-world.png
  28. 213
      docs/guide-zh-CN/input-forms.md
  29. 86
      docs/guide-zh-CN/input-multiple-models.md
  30. 21
      docs/guide-zh-CN/input-validation.md
  31. 25
      docs/guide-zh-CN/rest-rate-limiting.md
  32. 118
      docs/guide-zh-CN/runtime-requests.md
  33. 6
      docs/guide-zh-CN/runtime-responses.md
  34. 8
      docs/guide-zh-CN/runtime-sessions-cookies.md
  35. 2
      docs/guide-zh-CN/start-workflow.md
  36. 2
      docs/guide-zh-CN/structure-application-components.md
  37. 13
      docs/guide-zh-CN/structure-applications.md
  38. 4
      docs/guide-zh-CN/structure-assets.md
  39. 2
      docs/guide-zh-CN/structure-controllers.md
  40. 48
      docs/guide-zh-CN/structure-views.md
  41. 2
      docs/guide/README.md
  42. 4
      docs/guide/concept-di-container.md
  43. 17
      docs/guide/concept-service-locator.md
  44. 21
      docs/guide/db-migrations.md
  45. 202
      docs/guide/input-form-javascript.md
  46. 2
      docs/guide/input-forms.md
  47. 4
      docs/guide/input-validation.md
  48. 2
      docs/guide/output-data-widgets.md
  49. 3
      docs/guide/runtime-logging.md
  50. 65
      docs/guide/runtime-requests.md
  51. 1
      docs/guide/security-overview.md
  52. 2
      docs/guide/start-installation.md
  53. 28
      docs/guide/structure-modules.md
  54. 210
      docs/guide/tutorial-yii-as-micro-framework.md
  55. 5
      framework/BaseYii.php
  56. 88
      framework/CHANGELOG.md
  57. 117
      framework/UPGRADE.md
  58. 21
      framework/assets/yii.activeForm.js
  59. 1
      framework/assets/yii.gridView.js
  60. 1
      framework/assets/yii.js
  61. 2
      framework/assets/yii.validation.js
  62. 2
      framework/base/ActionFilter.php
  63. 4
      framework/base/Application.php
  64. 4
      framework/base/BaseObject.php
  65. 12
      framework/base/Component.php
  66. 6
      framework/base/Controller.php
  67. 8
      framework/base/ErrorHandler.php
  68. 1
      framework/base/Event.php
  69. 11
      framework/base/Model.php
  70. 36
      framework/base/Module.php
  71. 4
      framework/base/Request.php
  72. 7
      framework/base/Security.php
  73. 30
      framework/base/StaticInstanceInterface.php
  74. 41
      framework/base/StaticInstanceTrait.php
  75. 1
      framework/base/Theme.php
  76. 9
      framework/base/View.php
  77. 2
      framework/base/Widget.php
  78. 1
      framework/behaviors/AttributeTypecastBehavior.php
  79. 185
      framework/behaviors/AttributesBehavior.php
  80. 2
      framework/behaviors/SluggableBehavior.php
  81. 1
      framework/behaviors/TimestampBehavior.php
  82. 1
      framework/caching/ArrayCache.php
  83. 2
      framework/caching/Cache.php
  84. 1
      framework/caching/ChainedDependency.php
  85. 1
      framework/caching/DbCache.php
  86. 4
      framework/caching/DbQueryDependency.php
  87. 5
      framework/caching/Dependency.php
  88. 3
      framework/caching/migrations/m150909_153426_cache_init.php
  89. 6
      framework/captcha/Captcha.php
  90. 2
      framework/composer.json
  91. 24
      framework/console/Controller.php
  92. 1
      framework/console/ErrorHandler.php
  93. 4
      framework/console/Markdown.php
  94. 1
      framework/console/UnknownCommandException.php
  95. 1
      framework/console/controllers/AssetController.php
  96. 57
      framework/console/controllers/BaseMigrateController.php
  97. 52
      framework/console/controllers/CacheController.php
  98. 13
      framework/console/controllers/FixtureController.php
  99. 3
      framework/console/controllers/HelpController.php
  100. 21
      framework/console/controllers/MessageController.php
  101. Some files were not shown because too many files have changed in this diff Show More

3
.travis.yml

@ -56,6 +56,8 @@ matrix:
fast_finish: true
include:
# run tests coverage on PHP 7.1
- php: 7.2
- php: 7.1
env: TASK_TESTS_COVERAGE=1
- php: nightly
@ -69,6 +71,7 @@ matrix:
allow_failures:
- php: nightly
- php: 7.2
install:
- |

21
build/controllers/DevController.php

@ -14,7 +14,7 @@ use yii\helpers\Console;
use yii\helpers\FileHelper;
/**
* This command helps to set up a dev environment with all extensions and applications
* This command helps to set up a dev environment with all extensions and applications.
*
* It will clone an extension or app repo and link the yii2 dev installation to the containted applications/extensions vendor dirs
* to help working on yii using the application to test it.
@ -62,7 +62,7 @@ class DevController extends Controller
/**
* Install all extensions and advanced + basic app
* Install all extensions and advanced + basic app.
*/
public function actionAll()
{
@ -88,7 +88,7 @@ class DevController extends Controller
}
/**
* Runs a command in all extension and application directories
* Runs a command in all extension and application directories.
*
* Can be used to run e.g. `git pull`.
*
@ -118,7 +118,7 @@ class DevController extends Controller
}
/**
* This command installs a project template in the `apps` directory and links the framework and extensions
* This command installs a project template in the `apps` directory and links the framework and extensions.
*
* It basically runs the following commands in the dev repo root:
*
@ -178,7 +178,7 @@ class DevController extends Controller
}
/**
* This command installs an extension in the `extensions` directory and links the framework and other extensions
* This command installs an extension in the `extensions` directory and links the framework and other extensions.
*
* @param string $extension the application name e.g. `basic` or `advanced`.
* @param string $repo url of the git repo to clone if it does not already exist.
@ -237,12 +237,13 @@ class DevController extends Controller
if (in_array($actionID, ['ext', 'app', 'all'], true)) {
$options[] = 'useHttp';
}
return $options;
}
/**
* Remove all symlinks in the vendor subdirectory of the directory specified
* Remove all symlinks in the vendor subdirectory of the directory specified.
* @param string $dir base directory
*/
protected function cleanupVendorDir($dir)
@ -261,7 +262,7 @@ class DevController extends Controller
}
/**
* Creates symlinks to framework and extension sources for the application
* Creates symlinks to framework and extension sources for the application.
* @param string $dir application directory
* @param string $base Yii sources base directory
*
@ -293,7 +294,7 @@ class DevController extends Controller
}
/**
* Properly removes symlinked directory under Windows, MacOS and Linux
* Properly removes symlinked directory under Windows, MacOS and Linux.
*
* @param string $file path to symlink
*/
@ -307,7 +308,7 @@ class DevController extends Controller
}
/**
* Get a list of subdirectories for directory specified
* Get a list of subdirectories for directory specified.
* @param string $dir directory to read
*
* @return array list of subdirectories
@ -336,7 +337,7 @@ class DevController extends Controller
}
/**
* Finds linkable applications
* Finds linkable applications.
*
* @param string $dir directory to search in
* @return array list of applications command can link

2
build/controllers/MimeTypeController.php

@ -13,7 +13,7 @@ use yii\helpers\Console;
use yii\helpers\VarDumper;
/**
* MimeTypeController generates a map of file extensions to MIME types
* MimeTypeController generates a map of file extensions to MIME types.
*
* It uses `mime.types` file from apache http located under
* http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/conf/mime.types?view=markup

21
build/controllers/PhpDocController.php

@ -13,7 +13,7 @@ use yii\helpers\Console;
use yii\helpers\FileHelper;
/**
* PhpDocController is there to help maintaining PHPDoc annotation in class files
* PhpDocController is there to help maintaining PHPDoc annotation in class files.
*
* @author Carsten Brandt <mail@cebe.cc>
* @author Alexander Makarov <sam@rmcreative.ru>
@ -34,7 +34,7 @@ class PhpDocController extends Controller
/**
* Generates `@property` annotations in class files from getters and setters
* Generates `@property` annotations in class files from getters and setters.
*
* Property description will be taken from getter or setter or from an `@property` annotation
* in the getters docblock if there is one defined.
@ -70,7 +70,7 @@ class PhpDocController extends Controller
}
/**
* Fix some issues with PHPdoc in files
* Fix some issues with PHPDoc in files.
*
* @param string $root the directory to parse files from. Defaults to YII2_PATH.
*/
@ -243,7 +243,7 @@ class PhpDocController extends Controller
}
/**
* Fix file PHPdoc
* Fix file PHPDoc.
*/
protected function fixFileDoc(&$lines)
{
@ -284,7 +284,7 @@ class PhpDocController extends Controller
}
/**
* Markdown aware fix of whitespace issues in doc comments
* Markdown aware fix of whitespace issues in doc comments.
*/
protected function fixDocBlockIndentation(&$lines)
{
@ -350,12 +350,15 @@ class PhpDocController extends Controller
case 'boolean': $types[$i] = 'bool'; break;
}
}
return '@' . $matches[1] . ' ' . implode('|', $types);
}, $line);
}
/**
* Fixes line spacing code style for properties and constants
* Fixes line spacing code style for properties and constants.
* @param string[] $lines
* @return string[]
*/
protected function fixLineSpacing($lines)
{
@ -551,7 +554,7 @@ class PhpDocController extends Controller
}
/**
* remove multi empty lines and trim trailing whitespace
* remove multi empty lines and trim trailing whitespace.
*
* @param $doc
* @return string
@ -571,7 +574,7 @@ class PhpDocController extends Controller
}
/**
* Replace property annotations in doc comment
* Replace property annotations in doc comment.
* @param $doc
* @param $properties
* @return string
@ -759,6 +762,7 @@ class PhpDocController extends Controller
$sets[] = $set;
}
}
return $sets;
}
@ -768,6 +772,7 @@ class PhpDocController extends Controller
if ($str == '') {
return '';
}
return strtoupper(substr($str, 0, 1)) . substr($str, 1) . ($str[strlen($str) - 1] != '.' ? '.' : '');
}

29
build/controllers/ReleaseController.php

@ -71,6 +71,7 @@ class ReleaseController extends Controller
} elseif ($actionID === 'info') {
$options[] = 'update';
}
return array_merge(parent::options($actionID), $options);
}
@ -140,6 +141,7 @@ class ReleaseController extends Controller
$w = $l;
}
}
return $w;
}
@ -367,6 +369,7 @@ class ReleaseController extends Controller
/**
* @param array $what list of items
* @param array $limit list of things to allow, or empty to allow any, can be `app`, `framework`, `extension`
* @param bool $ensureGitClean
* @throws \yii\base\Exception
*/
protected function validateWhat(array $what, $limit = [], $ensureGitClean = true)
@ -434,11 +437,11 @@ class ReleaseController extends Controller
$this->dryRun || Yii::$app->runAction('mime-type', ["$frameworkPath/helpers/mimeTypes.php"]);
$this->stdout("done.\n", Console::FG_GREEN, Console::BOLD);
$this->stdout("fixing various PHPdoc style issues...\n", Console::BOLD);
$this->stdout("fixing various PHPDoc style issues...\n", Console::BOLD);
$this->dryRun || Yii::$app->runAction('php-doc/fix', [$frameworkPath]);
$this->stdout("done.\n", Console::FG_GREEN, Console::BOLD);
$this->stdout("updating PHPdoc @property annotations...\n", Console::BOLD);
$this->stdout("updating PHPDoc @property annotations...\n", Console::BOLD);
$this->dryRun || Yii::$app->runAction('php-doc/property', [$frameworkPath]);
$this->stdout("done.\n", Console::FG_GREEN, Console::BOLD);
@ -558,13 +561,13 @@ class ReleaseController extends Controller
// adjustments
$this->stdout("fixing various PHPdoc style issues...\n", Console::BOLD);
$this->stdout("fixing various PHPDoc style issues...\n", Console::BOLD);
$this->setAppAliases($name, $path);
$this->dryRun || Yii::$app->runAction('php-doc/fix', [$path, 'skipFrameworkRequirements' => true]);
$this->resetAppAliases();
$this->stdout("done.\n", Console::FG_GREEN, Console::BOLD);
$this->stdout("updating PHPdoc @property annotations...\n", Console::BOLD);
$this->stdout("updating PHPDoc @property annotations...\n", Console::BOLD);
$this->setAppAliases($name, $path);
$this->dryRun || Yii::$app->runAction('php-doc/property', [$path, 'skipFrameworkRequirements' => true]);
$this->resetAppAliases();
@ -676,11 +679,11 @@ class ReleaseController extends Controller
// adjustments
$this->stdout("fixing various PHPdoc style issues...\n", Console::BOLD);
$this->stdout("fixing various PHPDoc style issues...\n", Console::BOLD);
$this->dryRun || Yii::$app->runAction('php-doc/fix', [$path]);
$this->stdout("done.\n", Console::FG_GREEN, Console::BOLD);
$this->stdout("updating PHPdoc @property annotations...\n", Console::BOLD);
$this->stdout("updating PHPDoc @property annotations...\n", Console::BOLD);
$this->dryRun || Yii::$app->runAction('php-doc/property', [$path]);
$this->stdout("done.\n", Console::FG_GREEN, Console::BOLD);
@ -846,7 +849,10 @@ class ReleaseController extends Controller
}
/**
* Extract changelog content for a specific version
* Extract changelog content for a specific version.
* @param string $file
* @param string $version
* @return array
*/
protected function splitChangelog($file, $version)
{
@ -875,11 +881,14 @@ class ReleaseController extends Controller
${$state}[] = $line;
}
}
return [$start, $changelog, $end];
}
/**
* Ensure sorting of the changelog lines
* Ensure sorting of the changelog lines.
* @param string[] $changelog
* @return string[]
*/
protected function resortChangelog($changelog)
{
@ -895,6 +904,7 @@ class ReleaseController extends Controller
$o = ['Bug' => 'C', 'Enh' => 'D', 'Chg' => 'E', 'New' => 'F'];
return $o[$m[1]] . ' ' . (!empty($m[2]) ? $m[2] : 'AAAA' . $i++);
}
return 'B' . $i++;
}, SORT_ASC, SORT_NATURAL);
@ -929,6 +939,7 @@ class ReleaseController extends Controller
return true;
}
}
return false;
});
}
@ -1001,6 +1012,7 @@ class ReleaseController extends Controller
rsort($tags, SORT_NATURAL); // TODO this can not deal with alpha/beta/rc...
$versions[$ext] = reset($tags);
}
return $versions;
}
@ -1034,6 +1046,7 @@ class ReleaseController extends Controller
}
$versions[$k] = implode('.', $parts);
}
return $versions;
}
}

6
build/controllers/TranslationController.php

@ -83,7 +83,7 @@ class TranslationController extends Controller
}
/**
* Checks for files existence
* Checks for files existence.
*
* @param string $translatedFilePath
* @param string $sourceFilePath
@ -104,7 +104,7 @@ class TranslationController extends Controller
}
/**
* Getting DIFF from git
* Getting DIFF from git.
*
* @param string $translatedFilePath path pointing to translated file
* @param string $sourceFilePath path pointing to original file
@ -117,7 +117,7 @@ class TranslationController extends Controller
}
/**
* Adds all necessary HTML tags and classes to diff output
* Adds all necessary HTML tags and classes to diff output.
*
* @param string $diff DIFF
* @return string highlighted DIFF

2
build/controllers/Utf8Controller.php

@ -96,7 +96,7 @@ class Utf8Controller extends Controller
}
/**
* Equvalent for ord() just for unicode
* Equivalent for ord() just for unicode.
*
* http://stackoverflow.com/a/10333324/1106908
*

2
composer.json

@ -78,7 +78,7 @@
"psr/http-message": "~1.0.0",
"ezyang/htmlpurifier": "~4.6",
"cebe/markdown": "~1.0.0 | ~1.1.0",
"bower-asset/jquery": "2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable",
"bower-asset/jquery": "3.2.*@stable | 3.1.*@stable | 2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable",
"bower-asset/inputmask": "~3.2.2 | ~3.3.5",
"bower-asset/punycode": "1.3.*",
"bower-asset/yii2-pjax": "~2.0.1"

10
cs/src/YiiConfig.php

@ -95,7 +95,7 @@ class YiiConfig extends Config
'no_useless_return' => true,
'no_whitespace_before_comma_in_array' => true,
'no_whitespace_in_blank_line' => true,
// 'non_printable_character' => true, // breaks Formatter::asCurrency() tests
'non_printable_character' => true,
'normalize_index_brace' => true,
'object_operator_without_whitespace' => true,
// 'ordered_class_elements' => [ // needs more discussion
@ -124,9 +124,7 @@ class YiiConfig extends Config
'php_unit_dedicate_assert' => true,
'php_unit_fqcn_annotation' => true,
// 'php_unit_strict' => true, // needs more attention
// 'phpdoc_add_missing_param_annotation' => [ // needs more attention
// 'only_untyped' => false,
// ],
'phpdoc_add_missing_param_annotation' => true,
'phpdoc_indent' => true,
// 'phpdoc_inline_tag' => true, // see https://github.com/yiisoft/yii2/issues/11635
'phpdoc_no_access' => true,
@ -137,10 +135,10 @@ class YiiConfig extends Config
'phpdoc_return_self_reference' => true,
'phpdoc_scalar' => true,
'phpdoc_single_line_var_spacing' => true,
// 'phpdoc_summary' => true, // needs more attention (summary should be separated by blank line from description)
'phpdoc_summary' => true,
// 'phpdoc_to_comment' => true, // breaks phpdoc for define('CONSTANT', $value);
'phpdoc_trim' => true,
// 'phpdoc_types' => true, // conflicts with yii\base\Object typehits https://github.com/yiisoft/yii2/pull/12699
'phpdoc_types' => true,
'phpdoc_var_without_name' => true,
'protected_to_private' => true,
'psr4' => true,

2
docs/guide-fr/output-data-widgets.md

@ -586,7 +586,7 @@ class UserView extends ActiveRecord
/**
* @inheritdoc
*/
public static function attributeLabels()
public function attributeLabels()
{
return [
// définissez vos étiquettes d'attribut ici

2
docs/guide-ja/output-data-widgets.md

@ -662,7 +662,7 @@ class UserView extends ActiveRecord
/**
* @inheritdoc
*/
public static function attributeLabels()
public function attributeLabels()
{
return [
// ここで属性のラベルを定義

5
docs/guide-ru/concept-service-locator.md

@ -62,7 +62,7 @@ $cache = $locator->cache;
Поскольку Service Locator часто используется с [конфигурациями](concept-configurations.md), в нём имеется доступное
для записи свойство [[yii\di\ServiceLocator::setComponents()|components]]. Это позволяет настроить и зарегистрировать
сразу несколько компонентов. Следующий код демонстрирует конфигурационный массив, который может использоваться
для регистрации компонентов `db`, `cache` и `search` в Service Locator (то есть в [приложении](structure-applications.md)):
для регистрации компонентов `db`, `cache`, `tz` и `search` в Service Locator (то есть в [приложении](structure-applications.md)):
```php
return [
@ -75,6 +75,9 @@ return [
'password' => '',
],
'cache' => 'yii\caching\ApcCache',
'tz' => function() {
return new \DateTimeZone(Yii::$app->formatter->defaultTimeZone);
},
'search' => function () {
$solr = new app\components\SolrService('127.0.0.1');
// ... дополнительная инициализация ...

2
docs/guide-ru/output-data-widgets.md

@ -644,7 +644,7 @@ class UserView extends ActiveRecord
/**
* @inheritdoc
*/
public static function attributeLabels()
public function attributeLabels()
{
return [
// здесь определяйте ваши метки атрибутов

12
docs/guide-ru/structure-applications.md

@ -136,12 +136,12 @@ ID в качестве элемента данного свойства.
> будет использован компонент приложения. Если Вы вместо этого хотите использовать модуль, то можете указать его при
> помощи анонимной функции похожей на эту:
> ```php
[
function () {
return Yii::$app->getModule('user');
},
]
```
> [
> function () {
> return Yii::$app->getModule('user');
> },
> ]
> ```
В процессе [начальной загрузки](runtime-bootstrapping.md), каждый компонент будет создан. Если класс компонента имеет
интерфейс [[yii\base\BootstrapInterface]], то также будет вызван метод [[yii\base\BootstrapInterface::bootstrap()|bootstrap()]].

30
docs/guide-ru/test-overview.md

@ -1,21 +1,15 @@
Тестирование
============
Тестирование является важной составляющей разработки программного обеспечения. Мы проводим тестирование непрерывно, осознаем мы это или нет.
Например, когда мы пишем класс на языке PHP, мы можем отлаживать его шаг за шагом или просто использовать `echo` или `die` для проверки, что
реализация работает в соответствии с намеченным планом. В случае веб приложения, мы вводим некоторые тестовые данные в форму для того, чтобы
убедиться, что страница взаимодействует с нами, как ожидается.
Процесс тестирования может быть автоматизирован так, что каждый раз когда нам нужно что-то проверить, мы просто должны
вызвать код, который сделает это за нас. Код, который проверяет, что результат совпадает с тем, что мы планировали, называется тестом, а процесс
создания тестов и их последующего использования - автоматизированным тестированием, что и является главной темой данного раздела.
Тестирование является важной составляющей разработки программного обеспечения. Мы проводим тестирование непрерывно, осознаем мы это или нет. Например, когда мы пишем класс на языке PHP, мы можем отлаживать его шаг за шагом или просто использовать `echo` или `die` для проверки, что реализация работает в соответствии с намеченным планом. В случае веб приложения, мы вводим некоторые тестовые данные в форму для того, чтобы убедиться, что страница взаимодействует с нами, как ожидается.
Процесс тестирования может быть автоматизирован так, что каждый раз, когда нам нужно что-то проверить, мы просто должны
вызвать код, который сделает это за нас. Код, который проверяет, что результат совпадает с тем, что мы планировали, называется тестом, а процесс создания тестов и их последующего использования - автоматизированным тестированием, что и является главной темой данного раздела.
Разработка с тестами
--------------------
Разработка через тестирование (TDD) и разработка через поведение (BDD) - это подходы разработки программного обеспечения, в рамках которых
поведение части кода или целая фича описывается в виде набора сценариев или тестов ДО написания фактического кода и только
Разработка через тестирование (TDD) и разработка через поведение (BDD) - это подходы разработки программного обеспечения, в рамках которых поведение части кода или целая фича описывается в виде набора сценариев или тестов ДО написания фактического кода и только
затем создается реализация. Тем самым мы можем использовать данные тесты для проверки, что достигается заданное поведение.
Процесс разработки фичи следующий:
@ -26,8 +20,7 @@
- Запустить все тесты и убедиться, что они отрабатывают без ошибок
- Улучшить код и убедиться, что все тесты все еще отрабатывают без ошибок
После того как это завершено процесс повторяется снова для другой фичи или улучшения. Если существующая фича должна быть изменена, то и тесты
также должны быть изменены.
После того как это завершено, процесс повторяется снова для другой фичи или улучшения. Если существующая фича должна быть изменена, то и тесты также должны быть изменены.
> Tip: Если вы чувствуете, что вы теряете время выполняя много мелких и простых итераций, попробуйте покрыть это
> вашим тестовым сценарием перед следующим выполнением тестов. Если вы слишком много отлаживаете, попробуйте сделать обратное.
@ -35,12 +28,12 @@
Написание тестов до реализации конкретного функционала позволяет нам сосредоточиться на том, что мы хотим достичь и полностью
погрузиться в "как это сделать" впоследствии.
Обычно это приводит к лучшим абстракциям и более легкой поддержке тестов, когда речь идет о корректировки фичи или уменьшении связанности компонентов.
Обычно это приводит к лучшим абстракциям и более легкой поддержке тестов, когда речь идет о корректировке фичи или уменьшении связанности компонентов.
Таким образом плюсы этого подхода следующие:
Таким образом, плюсы этого подхода следующие:
- Позволяет вам сосредоточиться на одной вещи, что в свою очередь приводит к улучшению планирования и реализации.
- Более подробное покрытие тестами функционала, таким образом, если все тесты отрабатывают без ошибок, скорее всего, ничего не сломано.
- Более подробное покрытие тестами функционала. Таким образом, если все тесты отрабатывают без ошибок, скорее всего, ничего не сломано.
В долгосрочной перспективе это, как правило, дает вам хороший эффект экономии времени.
@ -50,8 +43,7 @@
Когда и как тестировать
-----------------------
Принцип разработки описанный выше имеет смысл применять для долгосрочных и относительно сложных проектов, в то время как для простых это может быть
излишним. Есть несколько показателей того, когда данный подход уместен:
Принцип разработки, описанный выше, имеет смысл применять для долгосрочных и относительно сложных проектов, в то время как для простых это может быть излишним. Есть несколько показателей того, когда данный подход уместен:
- Проект уже большой и сложный.
- Требования к проекту начинают усложняться. Проект постоянно растет.
@ -63,7 +55,7 @@
- Legacy-проект который постоянно обновляется.
- Вам поручили работу над проектом, в котором нет ни одного теста.
В некоторых случаях автоматизированно тестирование может быть излишним:
В некоторых случаях автоматизированное тестирование может быть излишним:
- Проект простой и не станет более сложным.
- Это одноразовый проект, который больше не будет дорабатываться.
@ -73,4 +65,4 @@
Что почитать
------------
- Экстремальное программирование. Разработка через тестирование / Кент Бек. ISBN: 0321146530.
- Экстремальное программирование. Разработка через тестирование / Кент Бек. ISBN: 0321146530.

1
docs/guide-zh-CN/concept-service-locator.md

@ -50,6 +50,7 @@ $cache = $locator->cache;
你可以通过 [[yii\di\ServiceLocator::has()]] 检查某组件 ID 是否被注册。若你用一个无效的 ID 调用 [[yii\di\ServiceLocator::get()]],则会抛出一个异常。
因为服务定位器,经常会在创建时附带[配置信息](concept-configurations.md),因此我们提供了一个可写的属性,名为 [[yii\di\ServiceLocator::setComponents()|components]],这样就可以配置该属性,或一次性注册多个组件。下面的代码展示了如何用一个配置数组,配置一个应用并注册"db","cache" 和 "search" 三个组件:
```php
return [
// ...

97
docs/guide-zh-CN/db-dao.md

@ -1,9 +1,10 @@
数据库访问 (DAO)
========
Yii 包含了一个建立在 PHP PDO 之上的数据访问层 (DAO). DAO为不同的数据库提供了一套统一的API. 其中```ActiveRecord``` 提供了数据库与模型(MVC 中的 M,Model) 的交互,```QueryBuilder``` 用于创建动态的查询语句. DAO提供了简单高效的SQL查询,可以用在与数据库交互的各个地方.
Yii 包含了一个建立在 PHP PDO 之上的数据访问层 (DAO). DAO为不同的数据库提供了一套统一的API. 其中 `ActiveRecord` 提供了数据库与模型(MVC 中的 M,Model) 的交互, `QueryBuilder` 用于创建动态的查询语句. DAO提供了简单高效的SQL查询,可以用在与数据库交互的各个地方.
Yii 默认支持以下数据库 (DBMS):
- [MySQL](http://www.mysql.com/)
- [MariaDB](https://mariadb.com/)
- [SQLite](http://sqlite.org/)
@ -12,7 +13,7 @@ Yii 默认支持以下数据库 (DBMS):
- [Oracle](http://www.oracle.com/us/products/database/overview/index.html)
- [MSSQL](https://www.microsoft.com/en-us/sqlserver/default.aspx): 版本>=2005.
##配置
## 配置
开始使用数据库首先需要配置数据库连接组件,通过添加 db 组件到应用配置实现("基础的" Web 应用是 config/web.php),DSN( Data Source Name )是数据源名称,用于指定数据库信息.如下所示:
@ -45,10 +46,10 @@ return [
```$connection = \Yii::$app->db;```
请参考```[[yii\db\Connection]]```获取可配置的属性列表。
请参考 `[[yii\db\Connection]]` 获取可配置的属性列表。
如果你想通过ODBC连接数据库,则需要配置[[yii\db\Connection::driverName]] 属性,例如:
```
```php
'db' => [
'class' => 'yii\db\Connection',
'driverName' => 'mysql',
@ -67,29 +68,30 @@ return [
// ...
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=mydatabase',
'dsn' => 'mysql:host=localhost;dbname=mydatabase',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
],
'secondDb' => [
'class' => 'yii\db\Connection',
'dsn' => 'sqlite:/path/to/database/file',
'dsn' => 'sqlite:/path/to/database/file',
],
],
// ...
];
```
在代码中通过以下方式使用:
```
```php
$primaryConnection = \Yii::$app->db;
$secondaryConnection = \Yii::$app->secondDb;
```
如果不想定义数据库连接为全局[应用](structure-application-components.md)组件,可以在代码中直接初始化使用:
```
```php
$connection = new \yii\db\Connection([
'dsn' => $dsn,
'username' => $username,
@ -98,9 +100,9 @@ $connection = new \yii\db\Connection([
$connection->open();
```
>小提示:如果在创建了连接后需要执行额外的 SQL 查询,可以添加以下代码到应用配置文件:
> 小提示:如果在创建了连接后需要执行额外的 SQL 查询,可以添加以下代码到应用配置文件:
```
```php
return [
// ...
'components' => [
@ -117,43 +119,48 @@ return [
];
```
##SQL 基础查询
## SQL 基础查询
一旦有了连接实例就可以通过[[yii\db\Command]]执行 SQL 查询。
###SELECT 查询
### SELECT 查询
查询返回多行:
```
```php
$command = $connection->createCommand('SELECT * FROM post');
$posts = $command->queryAll();
```
返回单行:
```
```php
$command = $connection->createCommand('SELECT * FROM post WHERE id=1');
$post = $command->queryOne();
```
查询多行单值:
```
```php
$command = $connection->createCommand('SELECT title FROM post');
$titles = $command->queryColumn();
```
查询标量值/计算值:
```
```php
$command = $connection->createCommand('SELECT COUNT(*) FROM post');
$postCount = $command->queryScalar();
```
###UPDATE, INSERT, DELETE 更新、插入和删除等
### UPDATE, INSERT, DELETE 更新、插入和删除等
如果执行 SQL 不返回任何数据可使用命令中的 execute 方法:
```
```php
$command = $connection->createCommand('UPDATE post SET status=1 WHERE id=1');
$command->execute();
```
你可以使用`insert`,`update`,`delete` 方法,这些方法会根据参数生成合适的SQL并执行.
```php
@ -177,7 +184,7 @@ $connection->createCommand()->update('user', ['status' => 1], 'age > 30')->execu
$connection->createCommand()->delete('user', 'status = 0')->execute();
```
###引用的表名和列名 <a name="quoting-table-and-column-names"></a>
### 引用的表名和列名 <a name="quoting-table-and-column-names"></a>
大多数时间都使用以下语法来安全地引用表名和列名:
@ -185,7 +192,8 @@ $connection->createCommand()->delete('user', 'status = 0')->execute();
$sql = "SELECT COUNT([[$column]]) FROM {{table}}";
$rowCount = $connection->createCommand($sql)->queryScalar();
```
以上代码`[[$column]]` 会转变为引用恰当的列名,而`{{table}}` 就转变为引用恰当的表名。
以上代码 `[[$column]]` 会转变为引用恰当的列名,而 `{{table}}` 就转变为引用恰当的表名。
表名有个特殊的变量 {{%Y}} ,如果设置了表前缀使用该变体可以自动在表名前添加前缀:
```php
@ -217,9 +225,9 @@ $sql = "SELECT COUNT($column) FROM $table";
$rowCount = $connection->createCommand($sql)->queryScalar();
```
###预处理语句
### 预处理语句
为安全传递查询参数可以使用预处理语句,首先应当使用`:placeholder`占位,再将变量绑定到对应占位符:
为安全传递查询参数可以使用预处理语句,首先应当使用 `:placeholder` 占位,再将变量绑定到对应占位符:
```php
$command = $connection->createCommand('SELECT * FROM post WHERE id=:id');
@ -239,11 +247,12 @@ $command->execute();
$id = 2;
$command->execute();
```
>提示,在执行前绑定变量,然后在每个执行中改变变量的值(一般用在循环中)比较高效.
##事务
> 提示: 在执行前绑定变量,然后在每个执行中改变变量的值(一般用在循环中)比较高效.
## 事务
当你需要顺序执行多个相关的的`query`时,你可以把他们封装到一个事务中去保护数据一致性.Yii提供了一个简单的接口来实现事务操作.
当你需要顺序执行多个相关的的 `query` 时,你可以把他们封装到一个事务中去保护数据一致性.Yii提供了一个简单的接口来实现事务操作.
如下执行 SQL 事务查询语句:
```php
@ -257,7 +266,8 @@ try {
$transaction->rollBack();
}
```
我们通过[[yii\db\Connection::beginTransaction()|beginTransaction()]]开始一个事务,通过`try catch` 捕获异常.当执行成功,通过[[yii\db\Transaction::commit()|commit()]]提交事务并结束,当发生异常失败通过[[yii\db\Transaction::rollBack()|rollBack()]]进行事务回滚.
我们通过[[yii\db\Connection::beginTransaction()|beginTransaction()]]开始一个事务,通过 `try catch` 捕获异常.当执行成功,通过[[yii\db\Transaction::commit()|commit()]]提交事务并结束,当发生异常失败通过[[yii\db\Transaction::rollBack()|rollBack()]]进行事务回滚.
如需要也可以嵌套多个事务:
@ -281,9 +291,10 @@ try {
$transaction1->rollBack();
}
```
>注意你使用的数据库必须支持`Savepoints`才能正确地执行,以上代码在所有关系数据中都可以执行,但是只有支持`Savepoints`才能保证安全性。
Yii 也支持为事务设置隔离级别`isolation levels`,当执行事务时会使用数据库默认的隔离级别,你也可以为事物指定隔离级别.
> 注意: 你使用的数据库必须支持 `Savepoints` 才能正确地执行,以上代码在所有关系数据中都可以执行,但是只有支持 `Savepoints` 才能保证安全性。
Yii 也支持为事务设置隔离级别 `isolation levels`,当执行事务时会使用数据库默认的隔离级别,你也可以为事务指定隔离级别.
Yii 提供了以下常量作为常用的隔离级别
- [[\yii\db\Transaction::READ_UNCOMMITTED]] - 允许读取改变了的还未提交的数据,可能导致脏读、不可重复读和幻读
@ -291,19 +302,19 @@ Yii 提供了以下常量作为常用的隔离级别
- [[\yii\db\Transaction::REPEATABLE_READ]] - 对相同字段的多次读取结果一致,可导致幻读。
- [[\yii\db\Transaction::SERIALIZABLE]] - 完全服从ACID的原则,确保不发生脏读、不可重复读和幻读。
你可以使用以上常量或者使用一个string字符串命令,在对应数据库中执行该命令用以设置隔离级别,比如对于`postgres`有效的命令为`SERIALIZABLE READ ONLY DEFERRABLE`.
你可以使用以上常量或者使用一个string字符串命令,在对应数据库中执行该命令用以设置隔离级别,比如对于 `postgres` 有效的命令为 `SERIALIZABLE READ ONLY DEFERRABLE`.
> Note: 某些数据库只能针对连接来设置事务隔离级别,所以你必须要为连接明确制定隔离级别.目前受影响的数据库:`MSSQL SQLite`
> Note: 某些数据库只能针对连接来设置事务隔离级别,所以你必须要为连接明确制定隔离级别.目前受影响的数据库: `MSSQL SQLite`
> Note: SQLite 只支持两种事务隔离级别,所以你只能设置`READ UNCOMMITTED` 和 `SERIALIZABLE`.使用其他隔离级别会抛出异常.
> Note: SQLite 只支持两种事务隔离级别,所以你只能设置 `READ UNCOMMITTED``SERIALIZABLE`.使用其他隔离级别会抛出异常.
> Note: PostgreSQL 不允许在事务开始前设置隔离级别,所以你不能在事务开始时指定隔离级别.你可以在事务开始之后调用[[yii\db\Transaction::setIsolationLevel()]] 来设置.
关于隔离级别[isolation levels]: http://en.wikipedia.org/wiki/Isolation_%28database_systems%29#Isolation_levels
##数据库复制和读写分离
## 数据库复制和读写分离
很多数据库支持数据库复制 [database replication](http://en.wikipedia.org/wiki/Replication_(computing)#Database_replication)来提高可用性和响应速度. 在数据库复制中,数据总是从*主服务器* 到 *从服务器*. 所有的插入和更新等写操作在主服务器执行,而读操作在从服务器执行.
很多数据库支持数据库复制 [database replication](http://en.wikipedia.org/wiki/Replication_(computing)#Database_replication) 来提高可用性和响应速度. 在数据库复制中,数据总是从*主服务器* 到 *从服务器*. 所有的插入和更新等写操作在主服务器执行,而读操作在从服务器执行.
通过配置[[yii\db\Connection]]可以实现数据库复制和读写分离.
@ -335,6 +346,7 @@ Yii 提供了以下常量作为常用的隔离级别
],
]
```
以上的配置实现了一主多从的结构,从服务器用以执行读查询,主服务器执行写入查询,读写分离的功能由后台代码自动完成.调用者无须关心.例如:
```php
@ -347,9 +359,10 @@ $rows = $db->createCommand('SELECT * FROM user LIMIT 10')->queryAll();
// 通过主服务器执行更新操作
$db->createCommand("UPDATE user SET username='demo' WHERE id=1")->execute();
```
> Note: 通过[[yii\db\Command::execute()]] 执行的查询被认为是写操作,所有使用[[yii\db\Command]]来执行的其他查询方法被认为是读操作.你可以通过`$db->slave`得到当前正在使用能够的从服务器.
`Connection`组件支持从服务器的负载均衡和故障转移,当第一次执行读查询时,会随即选择一个从服务器进行连接,如果连接失败则又选择另一个,如果所有从服务器都不可用,则会连接主服务器。你可以配置[[yii\db\Connection::serverStatusCache|server status cache]]来记住那些不能连接的从服务器,使Yii 在一段时间[[yii\db\Connection::serverRetryInterval]].内不会重复尝试连接那些根本不可用的从服务器.
`Connection` 组件支持从服务器的负载均衡和故障转移,当第一次执行读查询时,会随即选择一个从服务器进行连接,如果连接失败则又选择另一个,如果所有从服务器都不可用,则会连接主服务器。你可以配置[[yii\db\Connection::serverStatusCache|server status cache]]来记住那些不能连接的从服务器,使Yii 在一段时间[[yii\db\Connection::serverRetryInterval]].内不会重复尝试连接那些根本不可用的从服务器.
> Note: 在上述配置中,每个从服务器连接超时时间被指定为10s. 如果在10s内不能连接,则被认为该服务器已经挂掉.你也可以自定义超时参数.
@ -394,7 +407,8 @@ $db->createCommand("UPDATE user SET username='demo' WHERE id=1")->execute();
],
]
```
上述配置制定了2个主服务器和4个从服务器.`Connection`组件也支持主服务器的负载均衡和故障转移,与从服务器不同的是,如果所有主服务器都不可用,则会抛出异常.
上述配置制定了2个主服务器和4个从服务器.`Connection` 组件也支持主服务器的负载均衡和故障转移,与从服务器不同的是,如果所有主服务器都不可用,则会抛出异常.
> Note: 当你使用[[yii\db\Connection::masters|masters]]来配置一个或多个主服务器时,`Connection`中关于数据库连接的其他属性(例如:`dsn`, `username`, `password`)都会被忽略.
@ -422,18 +436,19 @@ try {
$transaction = $db->slave->beginTransaction();
```
有时你想强制使用主服务器来执行读查询,你可以调用`seMaster()`方法.
有时你想强制使用主服务器来执行读查询,你可以调用 `seMaster()` 方法.
```php
$rows = $db->useMaster(function ($db) {
return $db->createCommand('SELECT * FROM user LIMIT 10')->queryAll();
});
```
你也可以设置`$db->enableSlaves` 为`false`来使所有查询都在主服务器上执行.
##操作数据库模式
你也可以设置 `$db->enableSlaves``false` 来使所有查询都在主服务器上执行.
## 操作数据库模式
###获得模式信息
### 获得模式信息
你可以通过 [[yii\db\Schema]]实例来获取Schema信息:
@ -446,9 +461,10 @@ $schema = $connection->getSchema();
```php
$tables = $schema->getTableNames();
```
更多信息请参考[[yii\db\Schema]]
###修改模式
### 修改模式
除了基础的 SQL 查询,[[yii\db\Command]]还包括一系列方法来修改数据库模式:
@ -468,4 +484,5 @@ $connection->createCommand()->createTable('post', [
'text' => 'text',
]);
```
完整参考请查看[[yii\db\Command]].

BIN
docs/guide-zh-CN/images/start-country-list.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

BIN
docs/guide-zh-CN/images/start-entry-confirmation.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

BIN
docs/guide-zh-CN/images/start-form-validation.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

BIN
docs/guide-zh-CN/images/start-gii-country-grid.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

BIN
docs/guide-zh-CN/images/start-gii-country-update.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

BIN
docs/guide-zh-CN/images/start-gii-crud-preview.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

BIN
docs/guide-zh-CN/images/start-gii-crud.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

BIN
docs/guide-zh-CN/images/start-gii-model-preview.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

BIN
docs/guide-zh-CN/images/start-gii-model.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
docs/guide-zh-CN/images/start-hello-world.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

213
docs/guide-zh-CN/input-forms.md

@ -0,0 +1,213 @@
创建表单
====
基于活动记录(ActiveRecord)的表单:ActiveForm
-----------------------
在yii中使用表单的主要方式是通过[[yii\widgets\ActiveForm]]。当某个表单是基于一个模型时,应该首选这种方式。此外,在[[yii\helpers\Html]]中有很多实用的方法为表单添加按钮和帮助文档。
在客户端显示的表单,大多数情况下都有一个相应的[模型](structure-models.md),用来在服务器上验证其输入的数据(可在[输入验证](input-validation.md)一节获取关于验证的细节)。当创建一个基于模型的表单时,第一步是定义模型本身。该模型可以是一个基于[活动记录](db-active-record.md)的类,表示数据库中的数据,也可以是一个基于通用模型的类(继承自[[yii\base\Model]]),来获取任意的输入数据,如登录表单。
> Tip: 如果一个表单的输入域与数据库的字段不匹配,或者它存在只适用于它的特殊的格式或者方法,则最好为它创建一个单独的继承自[[yii\base\Model]]的模型。
在接下来的例子中,我们展示了通用模型如何用于登录表单:
```php
<?php
class LoginForm extends \yii\base\Model
{
public $username;
public $password;
public function rules()
{
return [
// 在这里定义验证规则
];
}
}
```
在控制器中,我们将传递一个模型是实例到视图,其中[[yii\widgets\ActiveForm|ActiveForm]]小部件将用来显示表单。
```php
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
$form = ActiveForm::begin([
'id' => 'login-form',
'options' => ['class' => 'form-horizontal'],
]) ?>
<?= $form->field($model, 'username') ?>
<?= $form->field($model, 'password')->passwordInput() ?>
<div class="form-group">
<div class="col-lg-offset-1 col-lg-11">
<?= Html::submitButton('Login', ['class' => 'btn btn-primary']) ?>
</div>
</div>
<?php ActiveForm::end() ?>
```
### 用 `begin()``end()` 包裹 <span id="wrapping-with-begin-and-end"></span>
在上面的代码中,[[yii\widgets\ActiveForm::begin()|ActiveForm::begin()]] 不仅创建了一个表单实例,同时也标志的表单的开始。所有在[[yii\widgets\ActiveForm::begin()|ActiveForm::begin()]]与[[yii\widgets\ActiveForm::end()|ActiveForm::end()]]之中的内容都会被HTML中的 `<form>`标签包裹。与其他小部件一样,你可以制定一些选项,通过传递数组到到 `begin` 中来配置小部件。在这种情况下,一个额外的CSS类和ID会在 `<form>` 标签中使用。要查看更多可用的选项,请查看API文档的 [[yii\widgets\ActiveForm]]。
### ActiveField <span id="activefield"></span>
为了在表单中创建表单元素与元素的标签,以及任意适用的Javascript验证,需要使用[[yii\widgets\ActiveForm::field()]|ActiveForm::field()]方法,其返回一个[[yii\widgets\ActiveField]]实例。当直接输出该方法时,结果是一个普通的(文本)输入。要自定义输出,可以附加上[[yii\widgets\ActiveField|ActiveField]]的其他方法来一起调用:
```php
// 密码输入框
<?= $form->field($model, 'password')->passwordInput() ?>
// 增加提示与自定义标签
<?= $form->field($model, 'username')->textInput()->hint('Please enter your name')->label('Name') ?>
// 创建一个HTML5邮件输入元素
<?= $form->field($model, 'email')->input('email') ?>
```
它会通过[[yii\widgets\ActiveField|ActiveField]]中定义的表单字段来创建`<label>`,`<input>`以及其他标签。input输入框的name属性会自动的根据[[yii\base\Model::formName()| form name]] 以及属性来来创建。例如,对于上面例子中的`username`输入字段的name属性将是`LoginForm[username]`。这种命名方式会使登录表单的所有属性在服务器端的`$_POST['LoginForm']`数组中是可用。
> Tip:如果你在一个表单中只有一个模型,并且想要简化input输入名称,你可以覆盖模型的[[yii\base\Model::formName()|formName()]]方法,使其返回一个空的字符串,以此来跳过数组部分。这在[GridView](output-data-widgets.md#grid-view)的过滤模型创建更好的URLs时是非常有用的。
指定模型是属性时可以以更复杂的方式来完成。比如,当上传多个文件时,或者选择多个多个项目时,可能会需要一个数组值,你可以通过附加`[]`来指定它的属性名称:
```php
// allow multiple files to be uploaded:
echo $form->field($model, 'uploadFile[]')->fileInput(['multiple'=>'multiple']);
// allow multiple items to be checked:
echo $form->field($model, 'items[]')->checkboxList(['a' => 'Item A', 'b' => 'Item B', 'c' => 'Item C']);
```
命名表单元素,如提交按钮时需要小心。在[JQuery](https://api.jquery.com/submit/)中有一些保留名词,可能会导致冲突:
> 表单和它们的子元素不应该使用与表单的属性冲突的input name或id,例如submit,length,或者 method。 要检查你的标签是否存在这些问题,一个完整的规则列表详见 DOMLint。
将额外的HTML标签添加到表单中可以通过使用纯HTML或者使用[[yii\helpers\Html|Html]]的方法,比如上述例子中的帮助类的做法[[yii\helpers\Html::submitButton()|Html::submitButton()]]。
> Tip:如果你的应用程序正在使用Twitter的Bootstrap CSS样式,你可以选择使用[[yii\bootstrap\ActiveForm]]代替[[yii\widgets\ActiveForm]],这个表单继承自后者,并且使用Bootstrap特有的样式初始化表单的输入框。
> Tip: 为了使用星号对必填字段进行样式,你可以使用下面的CSS样式:
>
> ```css
> div.required label.control-label:after {
> content: " *";
> color: red;
> }
> ```
创建列表 <span id="creating-activeform-lists"></span>
-----------------------
这里有3中类型的列表:
- 下拉列表
- 单选列表
- 多选列表
为了创建列表,你必须先为它准备选项。这些选项可以手动准备如下:
```php
$items = [
1 => 'item 1',
2 => 'item 2'
]
```
或者直接从数据库中检索:
```php
$items = Category::find()
->select(['label'])
->indexBy('id')
->column();
```
这些 `$items` 必须能被不同的列表组件处理。列表输入框的值(以及当前选中的选项)将会根据当前`$model`的属性的值而自动的生成。
#### 创建一个下拉选择列表 :<span id="creating-activeform-dropdownlist"></span>
我们可以使用活动领域的[[yii\widgets\ActiveField::dropDownList()]] 方法来创建一个下拉列表:
```php
/* @var $form yii\widgets\ActiveForm */
echo $form->field($model, 'category')->dropdownList([
1 => 'item 1',
2 => 'item 2'
],
['prompt'=>'Select Category']
);
```
#### 创建一个单选列表 :<span id="creating-activeform-radioList"></span>
我们可以使用活动领域的[[yii\widgets\ActiveField::radioList()]] 方法来创建一个下拉列表:
```php
/* @var $form yii\widgets\ActiveForm */
echo $form->field($model, 'category')->radioList([
1 => 'radio 1',
2 => 'radio 2'
]);
```
#### 创建一个多选列表: <span id="creating-activeform-checkboxList"></span>
我们可以使用活动领域的[[yii\widgets\ActiveField::checkboxList()]] 方法来创建一个下拉列表:
```php
/* @var $form yii\widgets\ActiveForm */
echo $form->field($model, 'category')->checkboxList([
1 => 'checkbox 1',
2 => 'checkbox 2'
]);
```
使用Pjax <span id="working-with-pjax"></span>
-----------------------
[[yii\widgets\Pjax|Pjax]]组件允许你更新一个页面的某些部分而不用从新加载整个页面。你可以在提交表单后使用Pjax来更新表单,或者替换表单的某些内容。
你可以配置[[yii\widgets\Pjax::$formSelector|$formSelector]]来指定那些表单的提交会触发pjax。如果你没有设置,所有包含`data-pjax`属性,并且含有封闭的Pjax内容的表单,将会触发pjax请求。
```php
use yii\widgets\Pjax;
use yii\widgets\ActiveForm;
Pjax::begin([
// Pjax options
]);
$form = ActiveForm::begin([
'options' => ['data' => ['pjax' => true]],
// more ActiveForm options
]);
// ActiveForm content
ActiveForm::end();
Pjax::end();
```
> Tip: 注意小心[[yii\widgets\Pjax|Pjax]]内部的链接,因为响应仍可能在组件内部呈现。为了避免这种现象,可以使用`data-pjax="0"`这个HTML属性。
#### 提交按钮和文件上传
由于`JQuery.serializeArray()`在处理[文件内容](https://github.com/jquery/jquery/issues/2321)和[提交按钮的值](https://github.com/jquery/jquery/issues/2321)时存在已知的问题,同时也为了推广`FormData`在HTML5中的使用,它将直接被弃用而不是等待修复。
这意味着官方对`FormData`在文件上传,ajax提交按钮的值以及组件[[yii\widgets\Pjax]]的使用上取决于[浏览器](https://developer.mozilla.org/en-US/docs/Web/API/FormData#Browser_compatibility)的支持。
扩展阅读 <span id="further-reading"></span>
---------------
下一节 [输入验证](input-validation.md) 处理提交的表单数据的服务器端验证, 以及 ajax- 和客户端验证。
要学会有关表格的更复杂的用法,你可以查看以下几节:
- [收集列表输入](input-tabular-input.md) 同一种类型的多个模型的采集数据。
- [多模型同时输入](input-multiple-models.md) 在同一窗口中处理多个不同的模型。
- [文件上传](input-file-upload.md) 如何使用表格来上传文件。

86
docs/guide-zh-CN/input-multiple-models.md

@ -1,35 +1,77 @@
多模型的复合表单
==================================
在复杂的用户界面可能会发生,用户在表单中填写数据
后将其保存在数据库的不同表中。yii形式的表单与单模型表单相比
可以让你用更加简单的方法来创建。
当处理负载的数据时,可能会发生需要使用多个模型来收集用户的输入。例如,假设用户登录信息保存在`user`表中,但是用户详细信息却保存在`profile`表中,你也许会使用`User`模型和`Profile`模型来接受用户的输入。在Yii模型与表单的支持下,你可以非常方便用不同于单个模型的方式来解决该问题。
与一个模型一样,你遵循以下模式用于服务端验证:
接下来,我们会使用一个例子阐述如何创建一个表单,它允许你同时为`User`和`Profile`模型收集数据。
1. 实例化模型类
2. 用输入数据填充模型属性
3. 验证所有模型
4. 如果所有模型验证通过,则保存它们
5. 如果验证失败或没有提交数据,传递所有模型对象到视图显示表单
首先,控制user和profile接收数据的控制器如下:
在下文中我们展示了一个在表单中使用多模型的例子... TBD
```php
namespace app\controllers;
多模型实例
---------------
use Yii;
use yii\base\Model;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use app\models\User;
use app\models\Profile;
> Note: This section is under development.
>
> It has no content yet.
class UserController extends Controller
{
public function actionUpdate($id)
{
$user = User::findOne($id);
if (!$user) {
throw new NotFoundHttpException("The user was not found.");
}
$profile = Profile::findOne($user->profile_id);
if (!$profile) {
throw new NotFoundHttpException("The user has no profile.");
}
$user->scenario = 'update';
$profile->scenario = 'update';
if ($user->load(Yii::$app->request->post()) && $profile->load(Yii::$app->request->post())) {
$isValid = $user->validate();
$isValid = $profile->validate() && $isValid;
if ($isValid) {
$user->save(false);
$profile->save(false);
return $this->redirect(['user/view', 'id' => $id]);
}
}
return $this->render('update', [
'user' => $user,
'profile' => $profile,
]);
}
}
```
TBD
在`update`动作中,我们首先加载`$user`和`$profile`模型并设置他们为更新模式。然后我们使用[[yii\base\Model::load()]]方法将用户输入的数据填充到模型中。如果数据顺利填充了,我们会验证这两个模型之后在保存它们。但是,请注意我们使用了`save(false)`来避免验证通过的数据在模型中被重复验证。如果填充不成功,我们将会显示下面的`update`视图:
Dependend models
----------------
```php
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
$form = ActiveForm::begin([
'id' => 'user-update-form',
'options' => ['class' => 'form-horizontal'],
]) ?>
<?= $form->field($user, 'username') ?>
> Note: This section is under development.
>
> It has no content yet.
...other input fields...
<?= $form->field($profile, 'website') ?>
TBD
<?= Html::submitButton('Update', ['class' => 'btn btn-primary']) ?>
<?php ActiveForm::end() ?>
```
如上,在`update`视图中你需要给予输入框两个模型`$user`和`$profile`。

21
docs/guide-zh-CN/input-validation.md

@ -161,13 +161,16 @@ return [
如你所见,这些验证规则并不真的对输入数据进行任何验证。而是,对输入数据进行一些处理,然后把它们存回当前被验证的模型特性。
下面的代码示例展示了对用户输入的完整处理,这将确保只将整数值存储在一个属性中:
```php
['age', 'trim'],
['age', 'default', 'value' => null],
['age', 'integer', 'integerOnly' => true, 'min' => 0],
['age', 'filter', 'filter' => 'intval', 'skipOnEmpty' => true],
```
以上代码将对输入执行以下操作:
1. 从输入值中去除前后空白。
2. 确保空输入在数据库中存储为`null`;我们区分 `未设置` 值和实际值为 `0` 之间的区别。如果值不允许为`null`,则可以在此处设置另一个默认值。
3. 如果该值不为空,则验证该值是否为大于0的整数。大多数验证器的 [[yii\validators\Validator::$skipOnEmpty|$skipOnEmpty]] 属性都被设置为`true`。
@ -322,12 +325,13 @@ class MyForm extends Model
```
> Note: 缺省状态下,行内验证器不会在关联特性的输入值为空或该特性已经在其他验证中失败的情况下起效。若你想要确保该验证器始终启用的话,你可以在定义规则时,酌情将 [[yii\validators\Validator::skipOnEmpty|skipOnEmpty]] 以及 [[yii\validators\Validator::skipOnError|skipOnError]]
属性设为 false,比如,
> 属性设为 false,比如,
>
> ```php
[
['country', 'validateCountry', 'skipOnEmpty' => false, 'skipOnError' => false],
]
```
> [
> ['country', 'validateCountry', 'skipOnEmpty' => false, 'skipOnError' => false],
> ]
> ```
### 独立验证器(Standalone Validators) <span id="standalone-validators"></span>
@ -465,8 +469,9 @@ JS;
```
> Tip: 上述代码主要是演示了如何支持客户端验证。在具体实践中,你可以使用 [in](tutorial-core-validators.md#in) 核心验证器来达到同样的目的。比如这样的验证规则:
>
> ```php
[
['status', 'in', 'range' => Status::find()->select('id')->asArray()->column()],
]
> [
> ['status', 'in', 'range' => Status::find()->select('id')->asArray()->column()],
> ]
```

25
docs/guide-zh-CN/rest-rate-limiting.md

@ -1,16 +1,17 @@
速率限制
=============
限流 (Rate Limiting)
==================
为防止滥用,你应该考虑增加速率限制到您的 API。
例如,您可以限制每个用户的 API 的使用是在 10 分钟内最多 100 次的 API 调用。
如果一个用户在规定的时间内太多的请求被接收,将返回响应状态代码 429 (这意味着过多的请求)。
为防止滥用,你应该考虑对您的 API 限流。
例如,您可以限制每个用户 10 分钟内最多调用 API 100 次。
如果在规定的时间内接收了一个用户大量的请求,将返回响应状态代码 429 (这意味着过多的请求)。
要启用限流, [[yii\web\User::identityClass|user identity class]] 应该实现 [[yii\filters\RateLimitInterface]].
要启用速率限制, [[yii\web\User::identityClass|user identity class]] 应该实现 [[yii\filters\RateLimitInterface]].
这个接口需要实现以下三个方法:
* `getRateLimit()`: 返回允许的请求的最大数及时间,例如,`[100, 600]` 表示在 600 秒内最多 100 次的 API 调用。
* `loadAllowance()`: 返回剩余的允许的请求和最后一次速率限制检查时相应的 UNIX 时间戳数。
* `saveAllowance()`: 保存剩余的允许请求数和当前的 UNIX 时间戳。
- `getRateLimit()`: 返回允许的最大请求数及时间,例如,`[100, 600]` 表示在 600 秒内最多 100 次的 API 调用。
- `loadAllowance()`: 返回剩余的允许的请求和最后一次限流检查时相应的 UNIX 时间戳数。
- `saveAllowance()`: 保存剩余的允许请求数和当前的 UNIX 时间戳。
你可以在 user 表中使用两列来记录容差和时间戳信息。
`loadAllowance()``saveAllowance()` 可以通过实现对符合当前身份验证的用户的这两列值的读和保存。为了提高性能,你也可以
@ -30,9 +31,9 @@ public function behaviors()
当速率限制被激活,默认情况下每个响应将包含以下 HTTP 头发送目前的速率限制信息:
* `X-Rate-Limit-Limit`: 同一个时间段所允许的请求的最大数目;
* `X-Rate-Limit-Remaining`: 在当前时间段内剩余的请求的数量;
* `X-Rate-Limit-Reset`: 为了得到最大请求数所等待的秒数。
- `X-Rate-Limit-Limit`: 同一个时间段所允许的请求的最大数目;
- `X-Rate-Limit-Remaining`: 在当前时间段内剩余的请求的数量;
- `X-Rate-Limit-Reset`: 为了得到最大请求数所等待的秒数。
你可以禁用这些头信息通过配置 [[yii\filters\RateLimiter::enableRateLimitHeaders]] 为 false,
就像在上面的代码示例所示。

118
docs/guide-zh-CN/runtime-requests.md

@ -0,0 +1,118 @@
请求
===
应用的请求使用 [[yii\web\Request]] 对象来表示,它提供了请求参数、HTTP 头、cookie 等信息。
对于一个给定的请求,你可以通过 `request` [应用组件](structure-application-components.md) 来访问,默认情况下它是 [[yii\web\Request]] 的实例。在本节中,我们将介绍如何在应用中使用此组件。
## 请求参数 <span id="request-parameters"></span>
你可以通过 `request` 组件的 [[yii\web\Request::get()|get()]] 和 [[yii\web\Request::post()|post()]] 方法来获取请求参数。
它分别返回 `$_GET``$_POST` 的值。例如:
```php
$request = Yii::$app->request;
$get = $request->get();
// equivalent to: $get = $_GET;
$id = $request->get('id');
// equivalent to: $id = isset($_GET['id']) ? $_GET['id'] : null;
$id = $request->get('id', 1);
// equivalent to: $id = isset($_GET['id']) ? $_GET['id'] : 1;
$post = $request->post();
// equivalent to: $post = $_POST;
$name = $request->post('name');
// equivalent to: $name = isset($_POST['name']) ? $_POST['name'] : null;
$name = $request->post('name', '');
// equivalent to: $name = isset($_POST['name']) ? $_POST['name'] : '';
```
> Info: 推荐上面的方式使用 `request` 组件来获取请求参数而不是直接使用 `$_GET``$_POST`。这将使编写测试变得更容易,因为您可以创建一个带有伪造请求数据的模拟请求组件。
在实现 [RESTful APIs](rest-quick-start.md) 是,你通常会需要获取 PUT、PATCH 或其他 [请求方法](#request-methods) 提交的参数.
你可以通过调用 [[yii\web\Request::getBodyParam()]] 方法来获取。例如:
```php
$request = Yii::$app->request;
// returns all parameters
$params = $request->bodyParams;
// returns the parameter "id"
$param = $request->getBodyParam('id');
```
> Info: 和 `GET` 参数不同,通过 `POST`、`PUT`、`PATCH` 等提交的参数实在请求体中发送。
当使用上述方式访问它们时, `request` 组件将解析这些参数。
你可以通过配置 [[yii\web\Request::parsers]] 属性来自定义解析这些参数的方式。
## 请求方法 <span id="request-methods"></span>
你可以通过 `Yii::$app->request->method` 来获取当前请求使用的 HTTP 请求方法。
`request` 还提供了一组布尔属性,用来检查当前请求是否具有某种类型。例如:
```php
$request = Yii::$app->request;
if ($request->isAjax) { /* the request is an AJAX request */ }
if ($request->isGet) { /* the request method is GET */ }
if ($request->isPost) { /* the request method is POST */ }
if ($request->isPut) { /* the request method is PUT */ }
```
## 请求 URLs <span id="request-urls"></span>
`request` 组件提供了许多检查当前请求地址的方法。
如果被请求的 URL 是 `http://example.com/admin/index.php/product?id=100`,您可以得到以下内容的不同部分:
* [[yii\web\Request::url|url]]: 返回 `/admin/index.php/product?id=100`, 没有 host info 部分的 URL。
* [[yii\web\Request::absoluteUrl|absoluteUrl]]: 返回 `http://example.com/admin/index.php/product?id=100`,包含 host info 的完整 URL 地址。
* [[yii\web\Request::hostInfo|hostInfo]]: 返回 `http://example.com`,URL 的 host info 部分。
* [[yii\web\Request::pathInfo|pathInfo]]: 返回 `/product`,在脚本和问号(查询字符串)之间的部分。
* [[yii\web\Request::queryString|queryString]]: 返回 `id=100`,问号后面的部分。
* [[yii\web\Request::baseUrl|baseUrl]]: 返回 `/admin`,在 host info 和脚本名称之间的部分。
* [[yii\web\Request::scriptUrl|scriptUrl]]: 返回 `/admin/index.php`,不包含 host info 和 查询字符串的部分。
* [[yii\web\Request::serverName|serverName]]: 返回 `example.com`,URL 中的主机名。
* [[yii\web\Request::serverPort|serverPort]]: 返回 80,WEB 服务器使用的端口。
## HTTP 头信息 <span id="http-headers"></span>
你可以通过 [[yii\web\Request::headers]] 返回的 [[yii\web\HeaderCollection|header collection]] 属性来获取 HTTP 头信息。例如:
```php
// $headers is an object of yii\web\HeaderCollection
$headers = Yii::$app->request->headers;
// returns the Accept header value
$accept = $headers->get('Accept');
if ($headers->has('User-Agent')) { /* there is User-Agent header */ }
```
`请求` 组件还支持快速访问一些常用的头信息,包括:
* [[yii\web\Request::userAgent|userAgent]]: 返回 `User-Agent` 的头信息的值。
* [[yii\web\Request::contentType|contentType]]: 返回 `Content-Type` 的头信息的值,它表示请求请求主体中数据的 MIME 类型。
* [[yii\web\Request::acceptableContentTypes|acceptableContentTypes]]: 返回用户可以接受的内容 MIME 类型。返回类型根据它们的评分。高评分的类型首先返回。
* [[yii\web\Request::acceptableLanguages|acceptableLanguages]]: 返回用户可接受的语言。返回的语言是由它们的优先级排序的。第一个元素表示最优先的语言。
如果您的应用支持多语言,并且你想根据是最终用户语言显示页面的语言。你可以通过语言协商方法 [[yii\web\Request::getPreferredLanguage()]] 来设置。
此方法将你的应用支持的语言列表和 [[yii\web\Request::acceptableLanguages|acceptableLanguages]] 进行对比来返回合适的语言。
> Tip: 同样,你可以使用 [[yii\filters\ContentNegotiator|ContentNegotiator]] 过滤器来动态决定响应中应该使用的内容类型和语言。这个过滤器实现了上述属性和方法中的内容协商。
## 客户端信息 <span id="client-information"></span>
你可以分别通过 [[yii\web\Request::userHost|userHost]] 和 [[yii\web\Request::userIP|userIP]] 来获取客户端机器的机器名和 IP 地址。例如:
```php
$userHost = Yii::$app->request->userHost;
$userIP = Yii::$app->request->userIP;
```

6
docs/guide-zh-CN/runtime-responses.md

@ -181,9 +181,9 @@ public function actionOld()
和浏览器跳转类似,文件发送是另一个依赖指定HTTP头的功能,Yii提供方法集合来支持各种文件发送需求,它们对HTTP头都有内置的支持。
* [[yii\web\Response::sendFile()]]: 发送一个已存在的文件到客户端
* [[yii\web\Response::sendContentAsFile()]]: 发送一个文本字符串作为文件到客户端
* [[yii\web\Response::sendStreamAsFile()]]: 发送一个已存在的文件流作为文件到客户端
- [[yii\web\Response::sendFile()]]: 发送一个已存在的文件到客户端
- [[yii\web\Response::sendContentAsFile()]]: 发送一个文本字符串作为文件到客户端
- [[yii\web\Response::sendStreamAsFile()]]: 发送一个已存在的文件流作为文件到客户端
这些方法都将响应对象作为返回值,如果要发送的文件非常大,应考虑使用
[[yii\web\Response::sendStreamAsFile()]] 因为它更节约内存,以下示例显示在控制器操作中如何发送文件:

8
docs/guide-zh-CN/runtime-sessions-cookies.md

@ -125,10 +125,10 @@ $session['captcha.lifetime'] = 3600;
[[yii\web\Session]] 类默认存储session数据为文件到服务器上,Yii提供以下session类实现不同的session存储方式:
* [[yii\web\DbSession]]: 存储session数据在数据表中
* [[yii\web\CacheSession]]: 存储session数据到缓存中,缓存和配置中的[缓存组件](caching-data.md#cache-components)相关
* [[yii\redis\Session]]: 存储session数据到以[redis](http://redis.io/) 作为存储媒介中
* [[yii\mongodb\Session]]: 存储session数据到[MongoDB](http://www.mongodb.org/).
- [[yii\web\DbSession]]: 存储session数据在数据表中
- [[yii\web\CacheSession]]: 存储session数据到缓存中,缓存和配置中的[缓存组件](caching-data.md#cache-components)相关
- [[yii\redis\Session]]: 存储session数据到以[redis](http://redis.io/) 作为存储媒介中
- [[yii\mongodb\Session]]: 存储session数据到[MongoDB](http://www.mongodb.org/).
所有这些session类支持相同的API方法集,因此,切换到不同的session存储介质不需要修改项目使用session的代码。

2
docs/guide-zh-CN/start-workflow.md

@ -51,7 +51,7 @@ Yii 实现了[模型-视图-控制器 (MVC)](http://wikipedia.org/wiki/Model-vie
![应用静态结构](images/application-structure.png)
每个应用都有一个入口脚本 `web/index.php`,这是整个应用中唯一可以访问的 PHP 脚本。入口脚本接受一个 Web 请求并创建[应用](structure-application.md)实例去处理它。 [应用](structure-applications.md)在它的[组](concept-components.md)辅助下解析请求,并分派请求至 MVC 元素。[视图](structure-views.md)使用[小部件](structure-widgets.md)去创建复杂和动态的用户界面。
每个应用都有一个入口脚本 `web/index.php`,这是整个应用中唯一可以访问的 PHP 脚本。入口脚本接受一个 Web 请求并创建[应用](structure-application.md)实例去处理它。 [应用](structure-applications.md)在它的[组](concept-components.md)辅助下解析请求,并分派请求至 MVC 元素。[视图](structure-views.md)使用[小部件](structure-widgets.md)去创建复杂和动态的用户界面。
请求生命周期 <span id="request-lifecycle"></span>

2
docs/guide-zh-CN/structure-application-components.md

@ -15,7 +15,7 @@
第一次使用以上表达式时候会创建应用组件实例,后续再访问会返回此实例,无需再次创建。
应用组件可以是任意对象,可以在 [应用主体配置](structure-applications.md#application-configurations)配置 [[yii\base\Application::components]] 属性 .
应用组件可以是任意对象,可以在 [应用主体配置](structure-applications.md#application-configurations) 配置 [[yii\base\Application::components]] 属性 .
例如:
```php

13
docs/guide-zh-CN/structure-applications.md

@ -118,13 +118,14 @@ $config = require __DIR__ . '/../config/web.php';
```
> Info: 如果模块ID和应用组件ID同名,优先使用应用组件ID,如果你想用模块ID,可以使用如下无名称函数返回模块ID。
>
> ```php
[
function () {
return Yii::$app->getModule('user');
},
]
```
> [
> function () {
> return Yii::$app->getModule('user');
> },
> ]
> ```
在启动阶段,每个组件都会实例化。如果组件类实现接口 [[yii\base\BootstrapInterface]],也会调用 [[yii\base\BootstrapInterface::bootstrap()|bootstrap()]] 方法。

4
docs/guide-zh-CN/structure-assets.md

@ -524,13 +524,14 @@ yii asset assets.php config/assets-prod.php
生成的配置文件可以在应用配置中包含,如最后一小节所描述的。
> Info: 使用`asset` 命令并不是唯一一种自动合并和压缩过程的方法,可使用优秀的工具[grunt](http://gruntjs.com/)来完成这个过程。
### 资源包分组 <span id="grouping-asset-bundles"></span>
上一小节,介绍了如何压缩所有的资源包到一个文件,减少对应用中引用资源文件的 http 请求数,但是在实践中很少这样做。比如,应用有一个“前端”和一个“后端”,每一个都用了一个不同js和css文件集合。在这种情况下,把所有的资源包压缩到一个文件毫无意义,“前端”不会用到“后端”的资源文件,当请求“前端”页面时,“后端”的资源文件也会被发送过来,浪费网络带宽。
为了解决这个问题,可以吧资源包分成若干组,每个组里面有若干个资源包。下面的配置展示了如何对资源包分组:
```php
return [
...
@ -562,6 +563,7 @@ return [
...
];
```
如上所示,资源包分成了三个组:`allShared`,`allBackEnd` 和 `allFrontEnd`
他们分别依赖其他资源包,例如,`allBackEnd` 依赖(depends) `app\assets\AdminAsset`。当使用这个配置运行 `asset` 命令时,将会根据上面的指定组合资源包。

2
docs/guide-zh-CN/structure-controllers.md

@ -330,7 +330,7 @@ class PostController extends Controller
操作参数会被不同的参数填入,如下所示:
* `http://hostname/index.php?r=post/view&id=123`: `$id` 会填入`'123'`,`$version` 仍为 null 空因为没有`version`请求参数;
* `http://hostname/index.php?r=post/view&id=123&version=2`: $id` 和 `$version` 分别填入 `'123'``'2'`
* `http://hostname/index.php?r=post/view&id=123&version=2`: `$id``$version` 分别填入 `'123'``'2'`
* `http://hostname/index.php?r=post/view`: 会抛出[[yii\web\BadRequestHttpException]] 异常
因为请求没有提供参数给必须赋值参数`$id`;
* `http://hostname/index.php?r=post/view&id[]=123`: 会抛出[[yii\web\BadRequestHttpException]] 异常

48
docs/guide-zh-CN/structure-views.md

@ -148,10 +148,9 @@ class PostController extends Controller
### 小部件中渲染 <span id="rendering-in-widgets"></span>
在 [小部件](structure-widgets.md) 中,可调用以下小部件方法来渲染视图:
Within [widgets](structure-widgets.md), you may call the following widget methods to render views.
* [[yii\base\Widget::render()|render()]]: 渲染一个 [视图名](#named-views).
* [[yii\base\Widget::renderFile()|renderFile()]]: 渲染一个视图文件目录或[别名](concept-aliases.md)下的视图文件。
- [[yii\base\Widget::render()|render()]]: 渲染一个 [视图名](#named-views)
- [[yii\base\Widget::renderFile()|renderFile()]]: 渲染一个视图文件目录或[别名](concept-aliases.md)下的视图文件。
例如:
@ -180,10 +179,10 @@ class ListWidget extends Widget
可以在视图中渲染另一个视图,可以调用[[yii\base\View|view component]]视图组件提供的以下方法:
* [[yii\base\View::render()|render()]]: 渲染一个 [视图名](#named-views).
* [[yii\web\View::renderAjax()|renderAjax()]]: 渲染一个 [视图名](#named-views)
- [[yii\base\View::render()|render()]]: 渲染一个 [视图名](#named-views).
- [[yii\web\View::renderAjax()|renderAjax()]]: 渲染一个 [视图名](#named-views)
并注入所有注册的JS/CSS脚本和文件,通常使用在响应AJAX网页请求的情况下。
* [[yii\base\View::renderFile()|renderFile()]]: 渲染一个视图文件目录或[别名](concept-aliases.md)下的视图文件。
- [[yii\base\View::renderFile()|renderFile()]]: 渲染一个视图文件目录或[别名](concept-aliases.md)下的视图文件。
例如,视图中的如下代码会渲染该视图所在目录下的 `_overview.php` 视图文件,
记住视图中 `$this` 对应 [[yii\base\View|view]] 组件:
@ -211,19 +210,19 @@ echo \Yii::$app->view->renderFile('@app/views/site/license.php');
视图名可以依据以下规则到对应的视图文件路径:
* 视图名可省略文件扩展名,这种情况下使用 `.php` 作为扩展,
- 视图名可省略文件扩展名,这种情况下使用 `.php` 作为扩展,
视图名 `about` 对应到 `about.php` 文件名;
* 视图名以双斜杠 `//` 开头,对应的视图文件路径为 `@app/views/ViewName`
- 视图名以双斜杠 `//` 开头,对应的视图文件路径为 `@app/views/ViewName`
也就是说视图文件在 [[yii\base\Application::viewPath|application's view path]] 路径下找,
例如 `//site/about` 对应到 `@app/views/site/about.php`
* 视图名以单斜杠`/`开始,视图文件路径以当前使用[模块](structure-modules.md) 的[[yii\base\Module::viewPath|view path]]开始,
- 视图名以单斜杠`/`开始,视图文件路径以当前使用[模块](structure-modules.md) 的[[yii\base\Module::viewPath|view path]]开始,
如果不存在模块,使用`@app/views/ViewName`开始,例如,如果当前模块为`user`, `/user/create` 对应成
`@app/modules/user/views/user/create.php`, 如果不在模块中,`/user/create`对应`@app/views/user/create.php`。
* 如果 [[yii\base\View::context|context]] 渲染视图 并且上下文实现了 [[yii\base\ViewContextInterface]],
- 如果 [[yii\base\View::context|context]] 渲染视图 并且上下文实现了 [[yii\base\ViewContextInterface]],
视图文件路径由上下文的 [[yii\base\ViewContextInterface::getViewPath()|view path]] 开始,
这种主要用在控制器和小部件中渲染视图,例如
如果上下文为控制器`SiteController`,`site/about` 对应到 `@app/views/site/about.php`
* 如果视图渲染另一个视图,包含另一个视图文件的目录以当前视图的文件路径开始,
- 如果视图渲染另一个视图,包含另一个视图文件的目录以当前视图的文件路径开始,
例如被视图`@app/views/post/index.php` 渲染的 `item` 对应到 `@app/views/post/item`
根据以上规则,在控制器中 `app\controllers\PostController` 调用 `$this->render('view')`
@ -258,7 +257,6 @@ The controller ID is: <?= $this->context->id ?>
推送方式让视图更少依赖上下文对象,是视图获取数据优先使用方式,
缺点是需要手动构建数组,有些繁琐,在不同地方渲染时容易出错。
### 视图间共享数据 <span id="sharing-data-among-views"></span>
[[yii\base\View|view component]]视图组件提供[[yii\base\View::params|params]]参数属性来让不同视图共享数据。
@ -500,11 +498,11 @@ class PostController extends Controller
视图组件提供如下实用的视图相关特性,每项详情会在独立章节中介绍:
* [主题](output-theming.md): 允许为你的Web站点开发和修改主题;
* [片段缓存](caching-fragment.md): 允许你在Web页面中缓存片段;
* [客户脚本处理](output-client-scripts.md): 支持CSS 和 JavaScript 注册和渲染;
* [资源包处理](structure-assets.md): 支持 [资源包](structure-assets.md)的注册和渲染;
* [模板引擎](tutorial-template-engines.md): 允许你使用其他模板引擎,如
- [主题](output-theming.md): 允许为你的Web站点开发和修改主题;
- [片段缓存](caching-fragment.md): 允许你在Web页面中缓存片段;
- [客户脚本处理](output-client-scripts.md): 支持CSS 和 JavaScript 注册和渲染;
- [资源包处理](structure-assets.md): 支持 [资源包](structure-assets.md)的注册和渲染;
- [模板引擎](tutorial-template-engines.md): 允许你使用其他模板引擎,如
[Twig](http://twig.sensiolabs.org/), [Smarty](http://www.smarty.net/)。
开发Web页面时,也可能频繁使用以下实用的小特性。
@ -659,15 +657,15 @@ http://localhost/index.php?r=site/page&view=about
视图负责将模型的数据展示用户想要的格式,总之,视图
* 应主要包含展示代码,如HTML, 和简单的PHP代码来控制、格式化和渲染数据;
* 不应包含执行数据查询代码,这种代码放在模型中;
* 应避免直接访问请求数据,如 `$_GET`, `$_POST`,这种应在控制器中执行,
- 应主要包含展示代码,如HTML, 和简单的PHP代码来控制、格式化和渲染数据;
- 不应包含执行数据查询代码,这种代码放在模型中;
- 应避免直接访问请求数据,如 `$_GET`, `$_POST`,这种应在控制器中执行,
如果需要请求数据,应由控制器推送到视图。
* 可读取模型属性,但不应修改它们。
- 可读取模型属性,但不应修改它们。
为使模型更易于维护,避免创建太复杂或包含太多冗余代码的视图,可遵循以下方法达到这个目标:
* 使用 [布局](#layouts) 来展示公共代码(如,页面头部、尾部);
* 将复杂的视图分成几个小视图,可使用上面描述的渲染方法将这些小视图渲染并组装成大视图;
* 创建并使用 [小部件](structure-widgets.md) 作为视图的数据块;
* 创建并使用助手类在视图中转换和格式化数据。
- 使用 [布局](#layouts) 来展示公共代码(如,页面头部、尾部);
- 将复杂的视图分成几个小视图,可使用上面描述的渲染方法将这些小视图渲染并组装成大视图;
- 创建并使用 [小部件](structure-widgets.md) 作为视图的数据块;
- 创建并使用助手类在视图中转换和格式化数据。

2
docs/guide/README.md

@ -92,6 +92,7 @@ Getting Data from Users
* [Uploading Files](input-file-upload.md)
* [Collecting Tabular Input](input-tabular-input.md)
* [Getting Data for Multiple Models](input-multiple-models.md)
* [Extending ActiveForm on the Client Side](input-form-javascript.md)
Displaying Data
@ -174,6 +175,7 @@ Special Topics
* [Shared Hosting Environment](tutorial-shared-hosting.md)
* [Template Engines](tutorial-template-engines.md)
* [Working with Third-Party Code](tutorial-yii-integration.md)
* [Using Yii as a micro framework](tutorial-yii-as-micro-framework.md)
Widgets

4
docs/guide/concept-di-container.md

@ -386,14 +386,14 @@ Say we work on API application and have:
```php
class FileStorage
{
public function __contruct($root) {
public function __construct($root) {
// whatever
}
}
class DocumentsReader
{
public function __contruct(FileStorage $fs) {
public function __construct(FileStorage $fs) {
// whatever
}
}

17
docs/guide/concept-service-locator.md

@ -12,7 +12,7 @@ The most commonly used service locator in Yii is the *application* object, which
`urlManager` components. You may configure these components, or even replace them with your own implementations, easily
through functionality provided by the service locator.
Besides the application object, each module object is also a service locator.
Besides the application object, each module object is also a service locator. Modules implement [tree traversal](#tree-traversal).
To use a service locator, the first step is to register components with it. A component can be registered
via [[yii\di\ServiceLocator::set()]]. The following code shows different ways of registering components:
@ -64,7 +64,7 @@ Because service locators are often being created with [configurations](concept-c
a writable property named [[yii\di\ServiceLocator::setComponents()|components]] is provided. This allows you
to configure and register multiple components at once. The following code shows a configuration array
that can be used to configure a service locator (e.g. an [application](structure-applications.md)) with
the `db`, `cache` and `search` components:
the `db`, `cache`, `tz` and `search` components:
```php
return [
@ -77,6 +77,9 @@ return [
'password' => '',
],
'cache' => 'yii\caching\ApcCache',
'tz' => function() {
return new \DateTimeZone(Yii::$app->formatter->defaultTimeZone);
},
'search' => function () {
$solr = new app\components\SolrService('127.0.0.1');
// ... other initializations ...
@ -115,3 +118,13 @@ return [
This alternative approach is most preferable when you are releasing a Yii component which encapsulates some non-Yii
3rd-party library. You use the static method like shown above to represent the complex logic of building the
3rd-party object, and the user of your component only needs to call the static method to configure the component.
## Tree traversal <span id="tree-traversal"></span>
Modules allow arbitrary nesting; a Yii application is essentially a tree of modules.
Since each of these modules is a service locator it makes sense for children to have access to their parent.
This allows modules to use `$this->get('db')` instead of referencing the root service locator `Yii::$app->get('db')`.
Added benefit is the option for a developer to override configuration in a module.
Any request for a service to be retrieved from a Module will be passed on to its parent in case the module is not able to satisfy it.

21
docs/guide/db-migrations.md

@ -704,8 +704,17 @@ Below is the list of all these database accessing methods:
* [[yii\db\Migration::dropCommentFromTable()|dropCommentFromTable()]]: dropping comment from table
> Info: [[yii\db\Migration]] does not provide a database query method. This is because you normally do not need
to display extra message about retrieving data from a database. It is also because you can use the powerful
[Query Builder](db-query-builder.md) to build and run complex queries.
> to display extra message about retrieving data from a database. It is also because you can use the powerful
> [Query Builder](db-query-builder.md) to build and run complex queries.
> Using Query Builder in a migration may look like this:
>
> ```php
> // update status field for all users
> foreach((new Query)->from('users')->each() as $user) {
> $this->update('users', ['status' => 1], ['id' => $user['id']]);
> }
> ```
> Note: When manipulating data using a migration you may find that using your [Active Record](db-active-record.md) classes
> for this might be useful because some of the logic is already implemented there. Keep in mind however, that in contrast
@ -788,6 +797,13 @@ yii migrate/redo 3 # redo the last 3 applied migrations
> Note: If a migration is not reversible, you will not be able to redo it.
## Refreshing Migrations <span id="refreshing-migrations"></span>
Since Yii 2.0.13 you can reset the whole database and apply all migrations from the beginning.
```
yii migrate/fresh # Truncate the database and apply all migrations from the beginning.
```
## Listing Migrations <span id="listing-migrations"></span>
@ -909,6 +925,7 @@ return [
'controllerMap' => [
'migrate' => [
'class' => 'yii\console\controllers\MigrateController',
'migrationPath' => null, // disable non-namespaced migrations if app\migrations is listed below
'migrationNamespaces' => [
'app\migrations', // Common migrations for the whole application
'module\migrations', // Migrations for the specific project's module

202
docs/guide/input-form-javascript.md

@ -0,0 +1,202 @@
Extending ActiveForm on the Client Side
=======================================
The [[yii\widgets\ActiveForm]] widget comes with a set of JavaScript methods that are used for client validation.
Its implementation is very flexible and allows you to extend it in different ways.
In the following these are described.
## ActiveForm events
ActiveForm triggers a series of dedicated events. Using the code like the following you can subscribe to these
events and handle them:
```javascript
$('#contact-form').on('beforeSubmit', function (e) {
if (!confirm("Everything is correct. Submit?")) {
return false;
}
return true;
});
```
In the following we'll review events available.
### `beforeValidate`
`beforeValidate` is triggered before validating the whole form.
The signature of the event handler should be:
```javascript
function (event, messages, deferreds)
```
where
- `event`: an Event object.
- `messages`: an associative array with keys being attribute IDs and values being error message arrays
for the corresponding attributes.
- `deferreds`: an array of Deferred objects. You can use `deferreds.add(callback)` to add a new
deferred validation.
If the handler returns a boolean `false`, it will stop further form validation after this event. And as
a result, `afterValidate` event will not be triggered.
### `afterValidate`
`afterValidate` event is triggered after validating the whole form.
The signature of the event handler should be:
```javascript
function (event, messages, errorAttributes)
```
where
- `event`: an Event object.
- `messages`: an associative array with keys being attribute IDs and values being error message arrays
for the corresponding attributes.
- `errorAttributes`: an array of attributes that have validation errors. Please refer to
`attributeDefaults` for the structure of this parameter.
### `beforeValidateAttribute`
`beforeValidateAttribute` event is triggered before validating an attribute.
The signature of the event handler should be:
```javascript
function (event, attribute, messages, deferreds)
```
where
- `event`: an Event object.
- `attribute`: the attribute to be validated. Please refer to `attributeDefaults` for the structure
of this parameter.
- `messages`: an array to which you can add validation error messages for the specified attribute.
- `deferreds`: an array of Deferred objects. You can use `deferreds.add(callback)` to add
a new deferred validation.
If the handler returns a boolean `false`, it will stop further validation of the specified attribute.
And as a result, `afterValidateAttribute` event will not be triggered.
### `afterValidateAttribute`
`afterValidateAttribute` event is triggered after validating the whole form and each attribute.
The signature of the event handler should be:
```javascript
function (event, attribute, messages)
```
where
- `event`: an Event object.
- `attribute`: the attribute being validated. Please refer to `attributeDefaults` for the structure
of this parameter.
- `messages`: an array to which you can add additional validation error messages for the specified
attribute.
### `beforeSubmit`
`beforeSubmit` event is triggered before submitting the form after all validations have passed.
The signature of the event handler should be:
```javascript
function (event)
```
where event is an Event object.
If the handler returns a boolean `false`, it will stop form submission.
### `ajaxBeforeSend`
`ajaxBeforeSend` event is triggered before sending an AJAX request for AJAX-based validation.
The signature of the event handler should be:
```javascript
function (event, jqXHR, settings)
```
where
- `event`: an Event object.
- `jqXHR`: a jqXHR object
- `settings`: the settings for the AJAX request
### `ajaxComplete`
`ajaxComplete` event is triggered after completing an AJAX request for AJAX-based validation.
The signature of the event handler should be:
```javascript
function (event, jqXHR, textStatus)
```
where
- `event`: an Event object.
- `jqXHR`: a jqXHR object
- `textStatus`: the status of the request ("success", "notmodified", "error", "timeout",
"abort", or "parsererror").
## Submitting the form via AJAX
While validation can be made on client side or via AJAX request, the form submission itself is done
as a normal request by default. If you want the form to be submitted via AJAX, you can achieve this
by handling the `beforeSubmit` event of the form in the following way:
```javascript
var $form = $('#formId');
$form.on('beforeSubmit', function() {
var data = $form.serialize();
$.ajax({
url: $form.attr('action'),
type: 'POST',
data: data,
success: function (data) {
// Implement successful
},
error: function(jqXHR, errMsg) {
alert(errMsg);
}
});
return false; // prevent default submit
});
```
To learn more about the jQuery `ajax()` function, please refer to the [jQuery documentation](https://api.jquery.com/jQuery.ajax/).
## Adding fields dynamically
In modern web applications you often have the need of changing a form after it has been displayed to the user.
This can for example be the addition of new fields after click on a "plus"-icon.
To enable client validation for these fields, they have to be registered with the ActiveForm JavaScript plugin.
You have to add a field itself and then add it to validation list:
```javascript
$('#contact-form').yiiActiveForm('add', {
id: 'address',
name: 'address',
container: '.field-address',
input: '#address',
error: '.help-block',
validate: function (attribute, value, messages, deferred, $form) {
yii.validation.required(value, messages, {message: "Validation Message Here"});
}
});
```
To remove a field from validation list so it's not validated you can do the following:
```javascript
$('#contact-form').yiiActiveForm('remove', 'address');
```

2
docs/guide/input-forms.md

@ -66,7 +66,7 @@ As with any widget, you can specify some options as to how the widget should be
the `begin` method. In this case, an extra CSS class and identifying ID are passed to be used in the opening `<form>` tag.
For all available options, please refer to the API documentation of [[yii\widgets\ActiveForm]].
### ActiveField <span id="activefield"></span>.
### ActiveField <span id="activefield"></span>
In order to create a form element in the form, along with the element's label, and any applicable JavaScript validation,
the [[yii\widgets\ActiveForm::field()|ActiveForm::field()]] method is called, which returns an instance of [[yii\widgets\ActiveField]].
When the result of this method is echoed directly, the result is a regular (text) input.

4
docs/guide/input-validation.md

@ -564,7 +564,7 @@ $this->addError('childrenCount', $message);
Or use a loop:
```php
$attributes = ['personalSalary, 'wifeSalary', 'childrenCount'];
$attributes = ['personalSalary', 'wifeSalary', 'childrenCount'];
foreach ($attributes as $attribute) {
$this->addError($attribute, 'Your salary is not enough for children.');
}
@ -817,7 +817,7 @@ JS;
```
### AJAX Validation <span id="ajax-validation"></span>
## AJAX Validation <span id="ajax-validation"></span>
Some validations can only be done on the server-side, because only the server has the necessary information.
For example, to validate if a username is unique or not, it is necessary to check the user table on the server-side.

2
docs/guide/output-data-widgets.md

@ -668,7 +668,7 @@ class UserView extends ActiveRecord
/**
* @inheritdoc
*/
public static function attributeLabels()
public function attributeLabels()
{
return [
// define here your attribute labels

3
docs/guide/runtime-logging.md

@ -308,6 +308,9 @@ return [
];
```
Since version 2.0.13, you may configure [[yii\log\Target::enabled|enabled]] with a callable to
define a dynamic condition for whether the log target should be enabled or not.
See the documentation of [[yii\log\Target::setEnabled()]] for an example.
### Creating New Targets <span id="new-targets"></span>

65
docs/guide/runtime-requests.md

@ -130,10 +130,73 @@ and returns the most appropriate language.
## Client Information <span id="client-information"></span>
You can get the host name and IP address of the client machine through [[yii\web\Request::userHost|userHost]]
You can get the host name and IP address
of the client machine through [[yii\web\Request::userHost|userHost]]
and [[yii\web\Request::userIP|userIP]], respectively. For example,
```php
$userHost = Yii::$app->request->userHost;
$userIP = Yii::$app->request->userIP;
```
## Trusted proxies and headers <span id="trusted-proxies"></span>
In the previous section you have seen how to get user information like host and IP address.
This will work out of the box in a normal setup where a single webserver is used to serve the website.
If your Yii application however runs behind a reverse proxy, you need to add additional configuration
to retrieve this information as the direct client is now the proxy and the user IP address is passed to
the Yii application by a header set by the proxy.
You should not blindly trust headers provided by proxies unless you explicitly trust the proxy.
Since 2.0.13 Yii supports configuring trusted proxies via the
[[yii\web\Request::trustedHosts|trustedHosts]],
[[yii\web\Request::secureHeaders|secureHeaders]],
[[yii\web\Request::ipHeaders|ipHeaders]] and
[[yii\web\Request::secureProtocolHeaders|secureProtocolHeaders]]
properties of the `request` component.
The following is a request config for an application that runs behind an array of reverse proxies,
which are located in the `10.0.2.0/24` IP network:
```php
'request' => [
// ...
'trustedHosts' => [
'/^10\.0\.2\.\d+$/',
],
],
```
The IP is sent by the proxy in the `X-Forwarded-For` header by default, and the protocol (`http` or `https`) is sent in `X-Forwarded-Proto`.
In case your proxies are using different headers you can use the request configuration to adjust these, e.g.:
```php
'request' => [
// ...
'trustedHosts' => [
'/^10\.0\.2\.\d+$/' => [
'X-ProxyUser-Ip',
'Front-End-Https',
],
],
'secureHeaders' => [
'X-Forwarded-For',
'X-Forwarded-Host',
'X-Forwarded-Proto',
'X-Proxy-User-Ip',
'Front-End-Https',
];'
'ipHeaders' => [
'X-Proxy-User-Ip',
],
'secureProtocolHeaders' => [
'Front-End-Https' => ['on']
],
],
```
With the above configuration, all headers listed in `secureHeaders` are filtered from the request,
except the `X-ProxyUser-Ip` and `Front-End-Https` headers in case the request is made by the proxy.
In that case the former is used to retrieve the user IP as configured in `ipHeaders` and the latter
will be used to determine the result of [[yii\web\Request::getIsSecureConnection()]].

1
docs/guide/security-overview.md

@ -12,3 +12,4 @@ Yii powered application as secure as possible, Yii has included several excellen
* [Views security](structure-views.md#security)
* [Auth Clients](https://github.com/yiisoft/yii2-authclient/blob/master/docs/guide/README.md)
* [Best Practices](security-best-practices.md)
* [Trusted proxies and headers](runtime-requests.md#trusted-proxies)

2
docs/guide/start-installation.md

@ -178,6 +178,8 @@ of `basic/web`. Denying access to those other folders is a security improvement.
to modify its Web server configuration, you may still adjust the structure of your application for better security. Please refer to
the [Shared Hosting Environment](tutorial-shared-hosting.md) section for more details.
> Info: If you are running your Yii application behind a reverse proxy, you might need to configure
> [Trusted proxies and headers](runtime-requests.md#trusted-proxies) in the request component.
### Recommended Apache Configuration <span id="recommended-apache-configuration"></span>

28
docs/guide/structure-modules.md

@ -269,6 +269,34 @@ in the `admin` module which is a child module of the `forum` module.
to its parent. The [[yii\base\Application::loadedModules]] property keeps a list of loaded modules, including both
direct children and nested ones, indexed by their class names.
## Accessing components from within modules
Since version 2.0.13 modules support [tree traversal](concept-service-locator.md#tree-traversal). This allows module
developers to reference (application) components via the service locator that is their module.
This means that it is preferable to use `$module->get('db')` over `Yii::$app->get('db')`.
The user of a module is able to specify a specific component to be used for the module in case a different component
(configuration) is required.
For example consider this application configuration:
```php
'components' => [
'db' => [
'tablePrefix' => 'main_',
],
],
'modules' => [
'mymodule' => [
'components' => [
'db' => [
'tablePrefix' => 'module_',
],
],
],
],
```
The application database tables will be prefixed with `main_`, while all module tables will be prefixed with `module_`.
## Best Practices <span id="best-practices"></span>

210
docs/guide/tutorial-yii-as-micro-framework.md

@ -0,0 +1,210 @@
# Using Yii as a Micro-framework
Yii can be easily used without the features included in basic and advanced templates. In other words, Yii is already a micro-framework. It is not required to have the directory structure provided by templates to work with Yii.
This is especially handy when you do not need all the pre-defined template code like assets or views. One of such cases is building a JSON API. In the following sections will show how to do that.
## Installing Yii
Create a directory for your project files and change working directory to that path. Commands used in examples are Unix-based but similar commands exist in Windows.
```bash
mkdir micro-app
cd micro-app
```
> Note: A little bit of Composer knowledge is required to continue. If you don't know how to use composer yet, please take time to read [Composer Guide](https://getcomposer.org/doc/00-intro.md).
Create file `composer.json` under the `micro-app` directory using your favorite editor and add the following:
```json
{
"require": {
"yiisoft/yii2": "~2.0.0"
},
"repositories": [
{
"type": "composer",
"url": "https://asset-packagist.org"
}
]
}
```
Save the file and run the `composer install` command. This will install the framework with all its dependencies.
## Creating the Project Structure
After you have installed the framework, it's time to create an [entry point](structure-entry-scripts.md) for the application. Entry point is the very first file that will be executed when you try to open your application. For the security reasons, it is recommended to put the entrypoint file in a separate directory and make it a web root.
Create a `web` directory and put `index.php` inside with the following content:
```php
<?php
// comment out the following two lines when deployed to production
defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');
require(__DIR__ . '/../vendor/autoload.php');
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
$config = require __DIR__ . '/../config.php';
(new yii\web\Application($config))->run();
```
Also create a file named `config.php` which will contain all application configuration:
```php
<?php
return [
'id' => 'micro-app',
// the basePath of the application will be the `micro-app` directory
'basePath' => __DIR__,
// this is where the application will find all controllers
'controllerNamespace' => 'micro\controllers',
// set an alias to enable autoloading of classes from the 'micro' namespace
'aliases' => [
'@micro' => __DIR__,
],
];
```
> Info: Even though the configuration could be kept in the `index.php` file it is recommended
> to have it separately. This way it can be used for console application also as it is shown below.
Your project is now ready for coding. Although it's up to you to decide the project directory structure, as long as you observe namespaces.
## Creating the first Controller
Create a `controllers` directory and add a file `SiteController.php`, which is the default
controller that will handle a request with no path info.
```php
<?php
namespace micro\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
public function actionIndex()
{
return 'Hello World!';
}
}
```
If you want to use a different name for this controller you can change it and configure [[yii\base\Application::$defaultRoute]] accordingly.
For example, for a `DefaultController` that would be `'defaultRoute' => 'default/index'`.
At this point the project structure should look like this:
```
micro-app/
├── composer.json
├── web/
└── index.php
└── controllers/
└── SiteController.php
```
If you have not set up the web server yet, you may want to take a look at [web server configuration file examples](start-installation.md#configuring-web-servers).
Another options is to use the `yii serve` command which will use the PHP build-in web server. You can run
it from the `micro-app/` directory via:
vendor/bin/yii serve --docroot=./web
Opening the application URL in a browser should now print "Hello World!" which has been returned in the `SiteController::actionIndex()`.
> Info: In our example, we have changed default application namespace `app` to `micro` to demonstrate
> that you are not tied to that name (in case you thought you were), then adjusted
> [[yii\base\Application::$controllerNamespace|controllers namespace]] and set the correct alias.
## Creating a REST API
In order to demonstrate the usage of our "micro framework", we will create a simple REST API for posts.
For this API to serve some data, we need a database first. Add the database connection configuration
to the application configuration:
```php
'components' => [
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'sqlite:@micro/database.sqlite',
],
],
```
> Info: We use an sqlite database here for simplicity. Please refer to the [Database guide](db-dao.md) for more options.
Next we create a [database migration](db-migrations.md) to create a posts table.
Make sure you have a separate configuration file as explained above, we need it to run the console commands below.
Running the following commands will
create a database migration file and apply the migration to the database:
vendor/bin/yii migrate/create --appconfig=config.php create_post_table --fields="title:string,body:text"
vendor/bin/yii migrate/up --appconfig=config.php
Create directory `models` and a `Post.php` file in that directory. This is the code for the model:
```php
<?php
namespace micro\models;
use yii\db\ActiveRecord;
class Post extends ActiveRecord
{
public static function tableName()
{
return '{{posts}}';
}
}
```
> Info: The model created here is an ActiveRecord class, which represents the data from the `posts` table.
> Please refer to the [active record guide](db-active-record.md) for more information.
To serve posts on our API, add the `PostController` in `controllers`:
```php
<?php
namespace micro\controllers;
use yii\rest\ActiveController;
class PostController extends ActiveController
{
public $modelClass = 'micro\models\Post';
public function behaviors()
{
// remove rateLimiter which requires an authenticated user to work
$behaviors = parent::behaviors();
unset($behaviors['rateLimiter']);
return $behaviors;
}
}
```
At this point our API will provide the following URLs:
- `/index.php?r=post` - list all posts
- `/index.php?r=post/view&id=1` - show post with ID 1
- `/index.php?r=post/create` - create a post
- `/index.php?r=post/update&id=1` - update post with ID 1
- `/index.php?r=post/delete&id=1` - delete post with ID 1
Starting from Here you may want to look at the following guides to further develop your application:
- The API currently only understands urlencoded form data as input, to make it a real JSON API, you
need to configure [[yii\web\JsonParser]].
- To make the URLs more friendly you need to configure routing.
See [guide on REST routing](rest-routing.md) on how to do this.
- Please also refer to the [Looking Ahead](start-looking-ahead.md) section for further references.

5
framework/BaseYii.php

@ -471,6 +471,7 @@ class BaseYii
/**
* Marks the beginning of a code block for profiling.
*
* This has to be matched with a call to [[endProfile]] with the same category name.
* The begin- and end- calls must also be properly nested. For example,
*
@ -488,7 +489,7 @@ class BaseYii
*/
public static function beginProfile($token, $category = 'application')
{
static::getProfiler()->begin($token, ['category' => $category]);
static::getLogger()->log($token, Logger::LEVEL_PROFILE_BEGIN, $category);
}
/**
@ -500,7 +501,7 @@ class BaseYii
*/
public static function endProfile($token, $category = 'application')
{
static::getProfiler()->end($token, ['category' => $category]);
static::getLogger()->log($token, Logger::LEVEL_PROFILE_END, $category);
}
/**

88
framework/CHANGELOG.md

@ -37,48 +37,79 @@ Yii Framework 2 Change Log
2.0.13 under development
------------------------
- Bug #14523: Added `yii\web\MultipartFormDataParser::$force` option allowing to enforce parsing even on 'POST' request (klimov-paul)
- Bug #14449: Fix PHP 7.2 compatibility bugs and add explicit closure support in `yii\base\Application` (dynasource)
- Bug #6526: Fixed `yii\db\Command::batchInsert()` casting of double values correctly independent of the locale (cebe, leammas)
- Bug #7890: Allow `migrate/mark` to mark history at the point of the base migration (cebe)
- Bug #14206: `MySqlMutex`, `PgsqlMutex` and `OracleMutex` now use `useMaster()` to ensure lock is aquired on the same DB server (cebe, ryusoft)
- Chg #14321: `yii\widgets\MaskedInput` is now registering its JavaScript `clientOptions` initialization code in head section (DaveFerger)
- Bug #11825: User can login by cookie only once when `autoRenewCookie` is set to false (shirase, silverfire)
- Bug #12860: Fixed possible race conditions in `yii\mutex\FileMutex` (kidol)
- Bug #13757: Fixed ambiguous column error in `BaseActiveRecord::refresh()` when the query adds a JOIN by default (cebe, ivankff)
- Bug #13779: Fixed `yii\db\ActiveRecord::joinWith()` unable to use relation defined via attached behavior (ElisDN, klimov-paul)
- Bug #13859: Fixed ambiguous column error in `Query::column()` when `$indexBy` is used with a JOIN (cebe)
- Enh #14431: Moved `ActiveQuery::getTablesUsedInFrom()` to `Query` to make the functionality available on the lower layer (cebe)
- Bug #13969: Fixed a bug in a `yii\console\controllers\CacheController` when caches defined via a closure were not detected (Kolyunya)
- Bug #14165: Set `_slave` of `Connection` to `false` instead of `null` in `close` method (rossoneri)
- Bug #14192: Fixed wrong default null value for TIMESTAMP when using PostgreSQL (Tigrov)
- Bug #14202: Fixed current time in (UTC) `\Yii::$app->formatter` if time not set (bscheshirwork)
- Bug #14206: `MySqlMutex`, `PgsqlMutex` and `OracleMutex` now use `useMaster()` to ensure lock is aquired on the same DB server (cebe, ryusoft)
- Bug #14248: `yii\console\controllers\MessageController` no longer outputs colorized filenames when console does not support text colorization (PowerGamer1)
- Bug #14264: Fixed a bug where `yii\log\Logger::calculateTimings()` was not accepting messages with array tokens (bizley)
- Bug #14269: Fixed broken error page when calling an undefined method (cebe)
- Bug #14304: Fixed `yii\validators\UniqueValidator` and `yii\validators\ExistValidator` to skip prefixes in case expressions are used (samdark)
- Bug #14307: Fixed PHP warning when `yii\console\UnknownCommandException` is thrown for empty command (rob006)
- Chg #14201: `yii\console\controllers\MessageController::extractMessagesFromTokens()` is now protected (faenir)
- Bug #14318: Trigger `yiiActiveForm.events.afterValidateAttribute` after updating attribute (dmirogin)
- Bug #14334: Fixed `\yii\db\QueryBuilder::buildNotCondition` loses params when operand is `\yii\db\Expression` (Ni-san)
- Bug #14341: Fixed regression in error handling introduced by fixing #14264 (samdark)
- Bug #14370: Fixed creating built-in validator in model with same function name (dmirogin)
- Bug #14406: Fixed caching rules in `yii\web\UrlManager` with different ruleConfig configuration (dmirogin)
- Bug #14423: Fixed `ArrayHelper::merge` behavior with null values for integer-keyed elements (dmirogin)
- Bug #14449: Fix PHP 7.2 compatibility bugs and add explicit closure support in `yii\base\Application` (dynasource)
- Bug #14471: `ContentNegotiator` will always set one of the configured server response formats even if the client does not accept any of them (PowerGamer1)
- Bug #14492: Fixed error handler not escaping error info debug mode, see CVE-2017-11516 (samdark)
- Bug #14493: Fixed getting permissions in `yii\rbac\Dbmanger::getPermissionsByUser` by user with id equals 0 (dmirogin)
- Bug #14523: Added `yii\web\MultipartFormDataParser::$force` option allowing to enforce parsing even on 'POST' request (klimov-paul)
- Bug #14525: Fixed 2.0.12 regression of loading of global fixtures trough `yii fixture/load` (michaelarnauts)
- Bug #14533: Fixed `yii\validators\ExistValidator` and `yii\validators\UniqueValidator` throw exception in case they are set for `yii\db\ActiveRecord` with `$targetClass` pointing to NOSQL ActiveRecord (klimov-paul)
- Bug #14542: Ensured only ASCII characters are in CSRF cookie value since binary data causes issues with ModSecurity and some browsers (samdark)
- Bug #14596: Fix event call on init in `yii\widgets\BaseListView` (panchenkodv)
- Bug #14697: Fixed `console\widgets\Table` rendering when there's no data supplied (bscheshirwork)
- Bug #14723: Fixed serialization of `yii\db\Connection` instance closes database connection (klimov-paul)
- Bug #14773: Fixed `yii\widgets\ActiveField::$options` does not support 'class' option in array format (klimov-paul)
- Bug: Fixed `yii\mutex\FileMutex::$autoRelease` having no effect due to missing base class initialization (kidol)
- Enh #4495: Added closure support in `yii\i18n\Formatter` (developeruz)
- Enh #5786: Allowed to use custom constructors in ActiveRecord-based classes (ElisDN, klimov-paul)
- Enh #6644: Added `yii\helpers\ArrayHelper::setValue()` (LAV45)
- Enh #7823: Added `yii\filters\AjaxFilter` filter (dmirogin)
- Enh #11415: Added `yii\console\widgets\Table` to draw tables in console apps (pana1990, rob006, samdark, tonykor)
- Enh #13254: Made `yii\helpers\StringHelper` and `yii\validators\StringValidator` independent of `Yii::$app` instance (cebe)
- Enh #13378: Added skipOnEmpty option to SluggableBehaviour (andrewnester)
- Enh #13586: Added `$preserveNonEmptyValues` property to the `yii\behaviors\AttributeBehavior` (Kolyunya)
- Enh #13780: Added support for trusted proxies in `yii\web\Request` (sammousa, cebe, silverfire)
- Enh #13787: Added `yii\db\Migration::$maxSqlOutputLength` that allows limiting number of characters for outputting SQL (thiagotalma)
- Enh #13824: Support extracting concatenated strings in `yii message` (developeruz)
- Enh #14089: Added tests for `yii\base\Theme` (vladis84)
- Enh #13586: Added `$preserveNonEmptyValues` property to the `yii\behaviors\AttributeBehavior` (Kolyunya)
- Bug #14192: Fixed wrong default null value for TIMESTAMP when using PostgreSQL (Tigrov)
- Enh #13835: Added `yii\web\Request::getOrigin()` method that returns `HTTP_ORIGIN` of current CORS request (yyxx9988)
- Enh #13853: Added `yii\db\Migration::$compact` as well as `yii\console\controllers\BaseMigrateController::$compact` to allow making the migration console output more compact (francislavoie)
- Enh #14022: `yii\web\UrlManager::setBaseUrl()` now supports aliases (dmirogin)
- Enh #14061: Added request scope assignments cache to `yii\rbac\DbManager::checkAccess()` to avoid duplicate queries for user assignments (leandrogehlen, cebe, nineinchnick, ryusoft)
- Enh #14081: Added `yii\caching\CacheInterface` to make custom cache extensions adoption easier (silverfire)
- Enh #11415: Added `yii\console\widgets\Table` to draw tables in console apps (pana1990, rob006, samdark, tonykor)
- Chg #14286: Used primary inputmask package name instead of an alias (samdark)
- Enh #14089: Added tests for `yii\base\Theme` (vladis84)
- Enh #14105: Implemented a solution for retrieving DBMS constraints in `yii\db\Schema` (sergeymakinen)
- Enh #14151: Added `yii\behaviors\AttributesBehavior` that assigns values specified to one or multiple attributes of an AR object when certain events happen (bscheshirwork)
- Enh #14184: Module service locator now falls back to its parent module service locator in case component isn't found (SamMousa)
- Enh #14188: Add constants and function for sysexits(3) to `ConsoleHelper` (tom--, samdark, cebe)
- Enh #14273: `yii\log\Target::$enabled` now supports callable value (dmirogin)
- Enh #14294: Added `InputWidget::renderInput()` to move behavior described in `InputWidget` class docs to the class itself (cebe)
- Enh #14298: The default response formatter configs defined by `yii\web\Response::defaultFormatters()` now use the array syntax (brandonkelly)
- Bug #14304: Fixed `yii\validators\UniqueValidator` and `yii\validators\ExistValidator` to skip prefixes in case expressions are used (samdark)
- Bug #14334: Fixed `\yii\db\QueryBuilder::buildNotCondition` loses params when operand is `\yii\db\Expression` (Ni-san)
- Bug #14341: Fixed regression in error handling introduced by fixing #14264 (samdark)
- Enh #13378: Added skipOnEmpty option to SluggableBehaviour (andrewnester)
- Enh #14363: Added `yii\widgets\LinkPager::$linkContainerOptions` and possibility to override tag in `yii\widgets\LinkPager::$options` (dmirogin)
- Enh #14389: Optimize `Validator::validateAttributes()` by calling `attributeNames()` only once (nicdnep)
- Enh #6644: Added `yii\helpers\ArrayHelper::setValue()` (LAV45)
- Enh #14105: Implemented a solution for retrieving DBMS constraints in `yii\db\Schema` (sergeymakinen)
- Enh #14417: Added configuration for headers in PHP files generated by `message/extract` command (rob006)
- Enh #13835: Added `yii\web\Request::getOrigin()` method that returns HTTP_ORIGIN of current CORS request (yyxx9988)
- Enh #14188: Add constants and function for sysexits(3) to `ConsoleHelper` (tom--, samdark, cebe)
- Bug #14165: Set `_slave` of `Connection` to `false` instead of `null` in `close` method (rossoneri)
- Bug #14423: Fixed `ArrayHelper::merge` behavior with null values for integer-keyed elements (dmirogin)
- Bug #14406: Fixed caching rules in `yii\web\UrlManager` with different ruleConfig configuration (dmirogin)
- Enh #14431: Moved `ActiveQuery::getTablesUsedInFrom()` to `Query` to make the functionality available on the lower layer (cebe)
- Enh #14620: Updated `yii.activeForm.js` and `yii\web\View` to jQuery 3.0 compatible API (silverfire)
- Enh #14664: Add migrate/fresh command to truncate database and apply migrations again (thyseus)
- Chg #7936: Deprecate `yii\base\Object` in favor of `yii\base\BaseObject` for compatibility with PHP 7.2 (rob006, cebe, klimov-paul)
- Bug #14493: Fixed getting permissions in `yii\rbac\Dbmanger::getPermissionsByUser` by user with id equals 0 (dmirogin)
- Bug #14370: Fixed creating built-in validator in model with same function name (dmirogin)
- Bug #14492: Fixed error handler not escaping error info debug mode (samdark)
- Chg #14201: `yii\console\controllers\MessageController::extractMessagesFromTokens()` is now protected (faenir)
- Chg #14286: Used primary inputmask package name instead of an alias (samdark)
- Chg #14321: `yii\widgets\MaskedInput` is now registering its JavaScript `clientOptions` initialization code in head section (DaveFerger)
- Chg #14487: Changed i18n message error to warning (dmirogin)
- Enh #7823: Added `yii\filters\AjaxFilter` filter (dmirogin)
2.0.12 June 05, 2017
--------------------
@ -142,6 +173,8 @@ Yii Framework 2 Change Log
- Bug #14074: Fixed default value of `yii\console\controllers\FixtureController::$globalFixtures` to contain valid class name (lynicidn)
- Bug #14094: Fixed bug when single `yii\web\UrlManager::createUrl()` call my result multiple calls of `yii\web\UrlRule::createUrl()` for the same rule (rossoneri)
- Bug #14133: Fixed bug when calculating timings with mixed nested profile begin and end in `yii\log\Logger::calculateTimings()` (bizley)
- Bug #14186: Forced validation in `yiiActiveForm` do not trigger `afterValidate` event (arogachev)
- Bug #14510: The state of a form is always "not validated" when using forced validation in `yiiActiveForm` (arogachev)
- Enh #4793: `yii\filters\AccessControl` now can be used without `user` component (bizley)
- Enh #4999: Added support for wildcards at `yii\filters\AccessRule::$controllers` (klimov-paul)
- Enh #5108: `yii\validators\DateValidator` now resets `$timestampAttribute` value on empty validated attribute value (klimov-paul)
@ -568,7 +601,7 @@ Yii Framework 2 Change Log
- Enh #11137: Added weak ETag support to `yii\filters\HttpCache`. It could be turned on via setting `$weakEtag` to `true` (particleflux)
- Enh #11139: `yii\validators\EachValidator` injects specific attribute value in error message parameters (silverfire)
- Enh #11166: migrate command new option `useTablePrefix` (Faryshta)
- Enh #11187: migrate command now generates phpdoc for table migrations (Faryshta)
- Enh #11187: migrate command now generates PHPDoc for table migrations (Faryshta)
- Enh #11207: migrate command can create foreign keys. (Faryshta)
- Enh #11254: Added ability to attach RBAC rule using class name (mdmunir)
- Enh #11285: `yii\base\Security` enhancements (tom--, samdark)
@ -705,6 +738,7 @@ Yii Framework 2 Change Log
- Enh #10783: Added migration and unit-tests for `yii\i18n\DbMessageSource` (silverfire)
- Enh #10797: Cleaned up requirements checker CSS (muhammadcahya)
- Enh: Added last resort measure for `yii\helpers\FileHelper::removeDirectory()` fail to unlink symlinks under Windows (samdark)
- Enh #9707: Added `yii\i18n\Formatter::asWeight()` and `::asLength()` formatters (nineinchnick, silverfire)
- Enh: `yii\behaviors\AttributeBehavior::getValue()` now respects the callable in array format (silverfire)
- Chg #6419: Added `yii\web\ErrorHandler::displayVars` make list of displayed vars customizable. `$_ENV` and `$_SERVER` are not displayed by default anymore (silverfire)
- Chg #9369: `Yii::$app->user->can()` now returns `false` instead of erroring in case `authManager` component is not configured (creocoder)

117
framework/UPGRADE.md

@ -107,7 +107,7 @@ Upgrade from Yii 2.0.x
* Console command used to clear cache now calls related actions "clear" instead of "flush".
* Yii autoloader was removed in favor of Composer-generated one. You should remove explicit inclusion of `Yii.php` from
your entry `index.php` scripts. In case you have relied on class map, use `composer.json` instead of configuring it
with PHP. For details please refer to [guide on autoloading](https://github.com/yiisoft/yii2/blob/2.1/docs/guide/concept-autoloading.md),
with PHP. For details please refer to [guide on autoloading](https://github.com/yiisoft/yii2/blob/2.1/docs/guide/concept-autoloading.md),
[guide on customizing helpers](https://github.com/yiisoft/yii2/blob/2.1/docs/guide/helper-overview.md#customizing-helper-classes-)
and [guide on Working with Third-Party Code](https://github.com/yiisoft/yii2/blob/2.1/docs/guide/tutorial-yii-integration.md).
* The signature of `yii\web\RequestParserInterface::parse()` was changed. The method now accepts the `yii\web\Request` instance
@ -115,11 +115,63 @@ Upgrade from Yii 2.0.x
* Uploaded file retrieve methods have been moved from `yii\http\UploadedFile` to `yii\web\Request`. You should use `Request::getUploadedFileByName()`
instead of `UploadedFile::getInstanceByName()` and `Request::getUploadedFilesByName()` instead of `UploadedFile::getInstancesByName()`.
Instead of `UploadedFile::getInstance()` and `UploadedFile::getInstances()` use construction `$model->load(Yii::$app->request->getUploadedFiles())`.
* The minimum required PHP version is 5.5.0 now.
* `yii\base\Object::className()` has been removed in favor of the [native PHP syntax](http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.class.class)
`::class`. When upgrading to Yii 2.1, You should do a global search and replace for `::className()` to `::class`.
All calls on objects via `->className()` should be replaced by a call to `get_class()`.
You can make this change even before upgrading to Yii 2.1, Yii 2.0.x does work with it.
`::class` does not trigger auto loading so you can even use it in config.
* The following method signature have changed. If you override any of them in your code, you have to adjust these places:
`yii\db\QueryBuilderbuild::buildGroupBy($columns)` -> `buildGroupBy($columns, &$params)`
`yii\db\QueryBuilderbuild::buildOrderByAndLimit($sql, $orderBy, $limit, $offset)` -> `buildOrderByAndLimit($sql, $orderBy, $limit, $offset, &$params)`
`yii\widgets\ActiveField::hint($content = null, $options = [])`
`yii\base\View::renderDynamic($statements)` -> `yii\base\View::renderDynamic($statements, array $params = [])`
* `yii\filters\AccessControl` has been optimized by only instantiating rules at the moment of use.
This could lead to a potential BC-break if you are depending on $rules to be instantiated in init().
* `yii\widgets\BaseListView::run()` and `yii\widgets\GridView::run()` now return content, instead of echoing it.
Normally we call `BaseListView::widget()` and for this case behavior is NOT changed.
In case you call `::run()` method, ensure that its return is processed correctly.
* Method `yii\web\Request::getBodyParams()` has been changed to pass full value of 'content-type' header to the second
argument of `yii\web\RequestParserInterface::parse()`. If you create your own custom parser, which relies on `$contentType`
argument, ensure to process it correctly as it may content additional data.
* `yii\web\UrlNormalizer` is now enabled by default in `yii\web\UrlManager`.
If you are using `yii\web\Request::resolve()` or `yii\web\UrlManager::parseRequest()` directly, make sure that
all potential exceptions are handled correctly or set `yii\web\UrlNormalizer::$normalizer` to `false` to disable normalizer.
* `yii\base\InvalidParamException` was renamed to `yii\base\InvalidArgumentException`.
Upgrade from Yii 2.0.12
-----------------------
* The `yii\web\Request` class allowed to determine the value of `getIsSecureConnection()` form the
`X-Forwarded-Proto` header if the connection was made via a normal HTTP request. This behavior
was insecure as the header could have been set by a malicious client on a non-HTTPS connection.
With 2.0.13 Yii adds support for configuring trusted proxies. If your application runs behind a reverse proxy and relies on
`getIsSecureConnection()` to return the value form the `X-Forwarded-Proto` header you need to explicitly allow
this in the Request configuration. See the [guide](http://www.yiiframework.com/doc-2.0/guide-runtime-requests.html#trusted-proxies) for more information.
This setting also affects you when Yii is running on IIS webserver, which sets the `X-Rewrite-Url` header.
This header is now filtered by default and must be listed in trusted hosts to be detected by Yii:
```php
[ // accept X-Rewrite-Url from all hosts, as it will be set by IIS
'/.*/' => ['X-Rewrite-Url'],
]
```
* For compatibiliy with [PHP 7.2 which does not allow classes to be named `Object` anymore](https://wiki.php.net/rfc/object-typehint),
we needed to rename `yii\base\Object` to `yii\base\BaseObject`.
@ -159,6 +211,29 @@ Upgrade from Yii 2.0.12
require `"yiisoft/yii2": "~2.0.13"` in composer.json and change affected classes to extend from `yii\base\BaseObject`
instead. It is not possible to allow Yii versions `<2.0.13` and be compatible with PHP 7.2 or higher.
* A new method `public static function instance($refresh = false);` has been added to the `yii\db\ActiveRecordInterface` via a new
`yii\base\StaticInstanceInterface`. This change may affect your application in the following ways:
- If you have an `instance()` method defined in an `ActiveRecord` or `Model` class, you need to check whether the behavior is
compatible with the method added by Yii.
- Otherwise this method is implemented in the `yii\base\Model`, so the change only affects your code if you implement `ActiveRecordInterface`
in a class that does not extend `Model`. You may use `yii\base\StaticInstanceTrait` to implement it.
* Fixed built-in validator creating when model has a method with the same name.
It is documented, that for the validation rules declared in model by `yii\base\Model::rules()`, validator can be either
a built-in validator name, a method name of the model class, an anonymous function, or a validator class name.
Before this change behavior was inconsistent with the documentation: method in the model had higher priority, than
a built-in validator. In case you have relied on this behavior, make sure to fix it.
* Behavior was changed for methods `yii\base\Module::get()` and `yii\base\Module::has()` so in case when the requested
component was not found in the current module, the parent ones will be checked for this component hierarchically.
Considering that the root parent module is usually an application, this change can reduce calls to global `Yii::$app->get()`,
and replace them with module-scope calls to `get()`, making code more reliable and easier to test.
However, this change may affect your application if you have code that uses method `yii\base\Module::has()` in order
to check existence of the component exactly in this specific module. In this case make sure the logic is not corrupted.
Upgrade from Yii 2.0.11
-----------------------
@ -205,46 +280,6 @@ Upgrade from Yii 2.0.10
you better fix these cases by specifying an explicit ID.
Upgrade to Yii 2.1.0
--------------------
* The minimum required PHP version is 5.5.0 now.
* `yii\base\Object::className()` has been removed in favor of the [native PHP syntax](http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.class.class)
`::class`. When upgrading to Yii 2.1, You should do a global search and replace for `::className()` to `::class`.
All calls on objects via `->className()` should be replaced by a call to `get_class()`.
You can make this change even before upgrading to Yii 2.1, Yii 2.0.x does work with it.
`::class` does not trigger auto loading so you can even use it in config.
* The following method signature have changed. If you override any of them in your code, you have to adjust these places:
`yii\db\QueryBuilderbuild::buildGroupBy($columns)` -> `buildGroupBy($columns, &$params)`
`yii\db\QueryBuilderbuild::buildOrderByAndLimit($sql, $orderBy, $limit, $offset)` -> `buildOrderByAndLimit($sql, $orderBy, $limit, $offset, &$params)`
`yii\widgets\ActiveField::hint($content = null, $options = [])`
`yii\base\View::renderDynamic($statements)` -> `yii\base\View::renderDynamic($statements, array $params = [])`
* `yii\filters\AccessControl` has been optimized by only instantiating rules at the moment of use.
This could lead to a potential BC-break if you are depending on $rules to be instantiated in init().
* `yii\widgets\BaseListView::run()` and `yii\widgets\GridView::run()` now return content, instead of echoing it.
Normally we call `BaseListView::widget()` and for this case behavior is NOT changed.
In case you call `::run()` method, ensure that its return is processed correctly.
* Method `yii\web\Request::getBodyParams()` has been changed to pass full value of 'content-type' header to the second
argument of `yii\web\RequestParserInterface::parse()`. If you create your own custom parser, which relies on `$contentType`
argument, ensure to process it correctly as it may content additional data.
* `yii\web\UrlNormalizer` is now enabled by default in `yii\web\UrlManager`.
If you are using `yii\web\Request::resolve()` or `yii\web\UrlManager::parseRequest()` directly, make sure that
all potential exceptions are handled correctly or set `yii\web\UrlNormalizer::$normalizer` to `false` to disable normalizer.
* `yii\base\InvalidParamException` was renamed to `yii\base\InvalidArgumentException`.
Upgrade from Yii 2.0.9
----------------------

21
framework/assets/yii.activeForm.js

@ -221,7 +221,7 @@
* Clean up error status when the form is reset.
* Note that $form.on('reset', ...) does work because the "reset" event does not bubble on IE.
*/
$form.bind('reset.yiiActiveForm', methods.resetForm);
$form.on('reset.yiiActiveForm', methods.resetForm);
if (settings.validateOnSubmit) {
$form.on('mouseup.yiiActiveForm keyup.yiiActiveForm', ':submit', function () {
@ -260,6 +260,7 @@
attributes.splice(index, 1);
unwatchAttribute($form, attribute);
}
return attribute;
},
@ -286,7 +287,7 @@
destroy: function () {
return this.each(function () {
$(this).unbind('.yiiActiveForm');
$(this).off('.yiiActiveForm');
$(this).removeData('yiiActiveForm');
});
},
@ -306,9 +307,9 @@
needAjaxValidation = false,
messages = {},
deferreds = deferredArray(),
submitting = data.submitting && !forceValidate;
submitting = data.submitting;
if (data.submitting) {
if (submitting) {
var event = $.Event(events.beforeValidate);
$form.trigger(event, [messages, deferreds]);
@ -391,7 +392,7 @@
});
} else if (data.submitting) {
// delay callback so that the form can be submitted without problem
setTimeout(function () {
window.setTimeout(function () {
updateInputs($form, messages, submitting);
}, 200);
} else {
@ -435,7 +436,7 @@
// Because we bind directly to a form reset event instead of a reset button (that may not exist),
// when this function is executed form input values have not been reset yet.
// Therefore we do the actual reset work through setTimeout.
setTimeout(function () {
window.setTimeout(function () {
$.each(data.attributes, function () {
// Without setTimeout() we would get the input values that are not reset yet.
this.value = getValue($form, this);
@ -535,7 +536,7 @@
if (data.settings.timer !== undefined) {
clearTimeout(data.settings.timer);
}
data.settings.timer = setTimeout(function () {
data.settings.timer = window.setTimeout(function () {
if (data.submitting || $form.is(':hidden')) {
return;
}
@ -574,6 +575,7 @@
for (var i = 0; i < buttonOptions.length; i++) {
attributes[buttonOptions[i]] = $form.attr(buttonOptions[i]);
}
return attributes;
};
@ -702,7 +704,6 @@
if (!$.isArray(messages[attribute.id])) {
messages[attribute.id] = [];
}
$form.trigger(events.afterValidateAttribute, [attribute, messages[attribute.id]]);
attribute.status = 1;
if ($input.length) {
@ -725,6 +726,9 @@
}
attribute.value = getValue($form, attribute);
}
$form.trigger(events.afterValidateAttribute, [attribute, messages[attribute.id]]);
return hasError;
};
@ -762,6 +766,7 @@
if (!$realInput.length) {
$realInput = $form.find('input[type=hidden][name="' + $input.attr('name') + '"]');
}
return $realInput.val();
} else {
return $input.val();

1
framework/assets/yii.gridView.js

@ -205,6 +205,7 @@
keys.push($(this).parent().closest('tr').data('key'));
});
}
return keys;
},

1
framework/assets/yii.js

@ -294,6 +294,7 @@ window.yii = (function ($) {
params[name].push(value || '');
}
}
return params;
},

2
framework/assets/yii.validation.js

@ -243,6 +243,7 @@ yii.validation = (function ($) {
value = $.trim(value);
$input.val(value);
}
return value;
},
@ -377,6 +378,7 @@ yii.validation = (function ($) {
if (!options.skipOnEmpty) {
messages.push(options.uploadRequired);
}
return [];
}

2
framework/base/ActionFilter.php

@ -115,7 +115,7 @@ class ActionFilter extends Behavior
}
/**
* Returns an action ID by converting [[Action::$uniqueId]] into an ID relative to the module
* Returns an action ID by converting [[Action::$uniqueId]] into an ID relative to the module.
* @param Action $action
* @return string
* @since 2.0.7

4
framework/base/Application.php

@ -613,7 +613,7 @@ abstract class Application extends Module
}
/**
* Returns the internationalization (i18n) component
* Returns the internationalization (i18n) component.
* @return \yii\i18n\I18N the internationalization application component.
*/
public function getI18n()
@ -704,7 +704,7 @@ abstract class Application extends Module
}
/**
* Configures [[Yii::$container]] with the $config
* Configures [[Yii::$container]] with the $config.
*
* @param array $config values given in terms of name-value pairs
* @since 2.0.11

4
framework/base/BaseObject.php

@ -78,6 +78,7 @@ class BaseObject implements Configurable
{
/**
* Constructor.
*
* The default implementation does two things:
*
* - Initializes the object with the given configuration `$config`.
@ -214,6 +215,7 @@ class BaseObject implements Configurable
/**
* Returns a value indicating whether a property is defined.
*
* A property is defined if:
*
* - the class has a getter or setter method associated with the specified name
@ -233,6 +235,7 @@ class BaseObject implements Configurable
/**
* Returns a value indicating whether a property can be read.
*
* A property is readable if:
*
* - the class has a getter method associated with the specified name
@ -251,6 +254,7 @@ class BaseObject implements Configurable
/**
* Returns a value indicating whether a property can be set.
*
* A property is writable if:
*
* - the class has a setter method associated with the specified name

12
framework/base/Component.php

@ -111,6 +111,7 @@ class Component extends BaseObject
/**
* Returns the value of a component property.
*
* This method will check in the following order and act accordingly:
*
* - a property defined by a getter: return the getter result
@ -149,6 +150,7 @@ class Component extends BaseObject
/**
* Sets the value of a component property.
*
* This method will check in the following order and act accordingly:
*
* - a property defined by a setter: set the property value
@ -203,6 +205,7 @@ class Component extends BaseObject
/**
* Checks if a property is set, i.e. defined and not null.
*
* This method will check in the following order and act accordingly:
*
* - a property defined by a setter: return whether the property is set
@ -235,6 +238,7 @@ class Component extends BaseObject
/**
* Sets a component property to be null.
*
* This method will check in the following order and act accordingly:
*
* - a property defined by a setter: set the property value to be null
@ -302,6 +306,7 @@ class Component extends BaseObject
/**
* Returns a value indicating whether a property is defined for this component.
*
* A property is defined if:
*
* - the class has a getter or setter method associated with the specified name
@ -323,6 +328,7 @@ class Component extends BaseObject
/**
* Returns a value indicating whether a property can be read.
*
* A property can be read if:
*
* - the class has a getter method associated with the specified name
@ -348,11 +354,13 @@ class Component extends BaseObject
}
}
}
return false;
}
/**
* Returns a value indicating whether a property can be set.
*
* A property can be written if:
*
* - the class has a setter method associated with the specified name
@ -378,11 +386,13 @@ class Component extends BaseObject
}
}
}
return false;
}
/**
* Returns a value indicating whether a method is defined.
*
* A method is defined if:
*
* - the class has a method with the specified name
@ -404,6 +414,7 @@ class Component extends BaseObject
}
}
}
return false;
}
@ -518,6 +529,7 @@ class Component extends BaseObject
if ($removed) {
$this->_events[$name] = array_values($this->_events[$name]);
}
return $removed;
}

6
framework/base/Controller.php

@ -88,6 +88,7 @@ class Controller extends Component implements ViewContextInterface
/**
* Declares external actions for the controller.
*
* This method is meant to be overwritten to declare external actions for the controller.
* It should return an array, with array keys being action IDs, and array values the corresponding
* action class names or action configuration arrays. For example,
@ -189,6 +190,7 @@ class Controller extends Component implements ViewContextInterface
} elseif ($pos > 0) {
return $this->module->runAction($route, $params);
}
return Yii::$app->runAction(ltrim($route, '/'), $params);
}
@ -316,6 +318,7 @@ class Controller extends Component implements ViewContextInterface
array_unshift($modules, $module->module);
$module = $module->module;
}
return $modules;
}
@ -395,6 +398,7 @@ class Controller extends Component implements ViewContextInterface
if ($layoutFile !== false) {
return $this->getView()->renderFile($layoutFile, ['content' => $content], $this);
}
return $content;
}
@ -435,6 +439,7 @@ class Controller extends Component implements ViewContextInterface
if ($this->_view === null) {
$this->_view = Yii::$app->getView();
}
return $this->_view;
}
@ -458,6 +463,7 @@ class Controller extends Component implements ViewContextInterface
if ($this->_viewPath === null) {
$this->_viewPath = $this->module->getViewPath() . DIRECTORY_SEPARATOR . $this->id;
}
return $this->_viewPath;
}

8
framework/base/ErrorHandler.php

@ -49,7 +49,7 @@ abstract class ErrorHandler extends Component
/**
* Register this error handler
* Register this error handler.
*/
public function register()
{
@ -176,11 +176,12 @@ abstract class ErrorHandler extends Component
throw $exception;
}
return false;
}
/**
* Handles fatal PHP errors
* Handles fatal PHP errors.
*/
public function handleFatalError()
{
@ -219,7 +220,7 @@ abstract class ErrorHandler extends Component
abstract protected function renderException($exception);
/**
* Logs the given exception
* Logs the given exception.
* @param \Exception $exception the exception to be logged
* @since 2.0.3 this method is now public.
*/
@ -282,6 +283,7 @@ abstract class ErrorHandler extends Component
} else {
$message = 'Error: ' . $exception->getMessage();
}
return $message;
}

1
framework/base/Event.php

@ -128,6 +128,7 @@ class Event extends BaseObject
if ($removed) {
self::$_events[$name][$class] = array_values(self::$_events[$name][$class]);
}
return $removed;
}

11
framework/base/Model.php

@ -54,9 +54,10 @@ use yii\validators\Validator;
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Model extends Component implements IteratorAggregate, ArrayAccess, Arrayable
class Model extends Component implements StaticInstanceInterface, IteratorAggregate, ArrayAccess, Arrayable
{
use ArrayableTrait;
use StaticInstanceTrait;
/**
* The name of the default scenario.
@ -159,6 +160,7 @@ class Model extends Component implements IteratorAggregate, ArrayAccess, Arrayab
/**
* Returns a list of scenarios and the corresponding active attributes.
*
* An active attribute is one that is subject to validation in the current scenario.
* The returned array should be in the following format:
*
@ -410,6 +412,7 @@ class Model extends Component implements IteratorAggregate, ArrayAccess, Arrayab
if ($this->_validators === null) {
$this->_validators = $this->createValidators();
}
return $this->_validators;
}
@ -428,6 +431,7 @@ class Model extends Component implements IteratorAggregate, ArrayAccess, Arrayab
$validators[] = $validator;
}
}
return $validators;
}
@ -450,6 +454,7 @@ class Model extends Component implements IteratorAggregate, ArrayAccess, Arrayab
throw new InvalidConfigException('Invalid validation rule: a rule must specify both attribute names and validator type.');
}
}
return $validators;
}
@ -474,6 +479,7 @@ class Model extends Component implements IteratorAggregate, ArrayAccess, Arrayab
return true;
}
}
return false;
}
@ -563,6 +569,7 @@ class Model extends Component implements IteratorAggregate, ArrayAccess, Arrayab
if ($attribute === null) {
return $this->_errors === null ? [] : $this->_errors;
}
return isset($this->_errors[$attribute]) ? $this->_errors[$attribute] : [];
}
@ -585,6 +592,7 @@ class Model extends Component implements IteratorAggregate, ArrayAccess, Arrayab
$errors[$name] = reset($es);
}
}
return $errors;
}
@ -828,6 +836,7 @@ class Model extends Component implements IteratorAggregate, ArrayAccess, Arrayab
return true;
}
return false;
}

36
framework/base/Module.php

@ -266,6 +266,7 @@ class Module extends ServiceLocator
if ($this->_viewPath === null) {
$this->_viewPath = $this->getBasePath() . DIRECTORY_SEPARATOR . 'views';
}
return $this->_viewPath;
}
@ -317,6 +318,7 @@ class Module extends ServiceLocator
$this->_version = call_user_func($this->_version, $this);
}
}
return $this->_version;
}
@ -350,6 +352,7 @@ class Module extends ServiceLocator
if ($this->module === null) {
return '1.0';
}
return $this->module->getVersion();
}
@ -393,6 +396,7 @@ class Module extends ServiceLocator
return $module === null ? false : $module->hasModule(substr($id, $pos + 1));
}
return isset($this->_modules[$id]);
}
@ -468,6 +472,7 @@ class Module extends ServiceLocator
return $modules;
}
return $this->_modules;
}
@ -640,6 +645,7 @@ class Module extends ServiceLocator
} elseif (YII_DEBUG) {
throw new InvalidConfigException('Controller class must extend from \\yii\\base\\Controller.');
}
return null;
}
@ -705,4 +711,34 @@ class Module extends ServiceLocator
$this->trigger(self::EVENT_AFTER_ACTION, $event);
return $event->result;
}
/**
* {@inheritdoc}
*
* Since version 2.0.13, if a component isn't defined in the module, it will be looked up in the parent module.
* The parent module may be the application.
*/
public function get($id, $throwException = true)
{
if (!isset($this->module)) {
return parent::get($id, $throwException);
}
$component = parent::get($id, false);
if ($component === null) {
$component = $this->module->get($id, $throwException);
}
return $component;
}
/**
* {@inheritdoc}
*
* Since version 2.0.13, if a component isn't defined in the module, it will be looked up in the parent module.
* The parent module may be the application.
*/
public function has($id, $checkInstance = false)
{
return parent::has($id, $checkInstance) || (isset($this->module) && $this->module->has($id, $checkInstance));
}
}

4
framework/base/Request.php

@ -33,7 +33,7 @@ abstract class Request extends Component
abstract public function resolve();
/**
* Returns a value indicating whether the current request is made via command line
* Returns a value indicating whether the current request is made via command line.
* @return bool the value indicating whether the current request is made via console
*/
public function getIsConsoleRequest()
@ -42,7 +42,7 @@ abstract class Request extends Component
}
/**
* Sets the value indicating whether the current request is made via command line
* Sets the value indicating whether the current request is made via command line.
* @param bool $value the value indicating whether the current request is made via command line
*/
public function setIsConsoleRequest($value)

7
framework/base/Security.php

@ -269,6 +269,7 @@ class Security extends Component
if ($outputKey === false) {
throw new InvalidArgumentException('Invalid parameters to hash_hkdf()');
}
return $outputKey;
}
@ -323,6 +324,7 @@ class Security extends Component
if ($outputKey === false) {
throw new InvalidArgumentException('Invalid parameters to hash_pbkdf2()');
}
return $outputKey;
}
@ -348,6 +350,7 @@ class Security extends Component
if (!$hash) {
throw new InvalidConfigException('Failed to generate HMAC with hash algorithm: ' . $this->macHash);
}
return $hash . $data;
}
@ -375,7 +378,7 @@ class Security extends Component
$hashLength = StringHelper::byteLength($test);
if (StringHelper::byteLength($data) >= $hashLength) {
$hash = StringHelper::byteSubstr($data, 0, $hashLength);
$pureData = StringHelper::byteSubstr($data, $hashLength);
$pureData = StringHelper::byteSubstr($data, $hashLength, null);
$calculatedHash = hash_hmac($this->macHash, $pureData, $key, $rawHash);
@ -383,6 +386,7 @@ class Security extends Component
return $pureData;
}
}
return false;
}
@ -532,6 +536,7 @@ class Security extends Component
if (!is_int($length)) {
return '';
}
return StringHelper::byteSubstr($decoded, $length, $length) ^ StringHelper::byteSubstr($decoded, 0, $length);
}
}

30
framework/base/StaticInstanceInterface.php

@ -0,0 +1,30 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
/**
* StaticInstanceInterface is the interface for providing static instances to classes,
* which can be used to obtain class meta information that can not be expressed in static methods.
* For example: adjustments made by DI or behaviors reveal only at object level, but might be needed
* at class (static) level as well.
*
* To implement the [[instance()]] method you may use [[StaticInstanceTrait]].
*
* @author Paul Klimov <klimov.paul@gmail.com>
* @since 2.0.13
* @see StaticInstanceTrait
*/
interface StaticInstanceInterface
{
/**
* Returns static class instance, which can be used to obtain meta information.
* @param bool $refresh whether to re-create static instance even, if it is already cached.
* @return static class instance.
*/
public static function instance($refresh = false);
}

41
framework/base/StaticInstanceTrait.php

@ -0,0 +1,41 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
use Yii;
/**
* StaticInstanceTrait provides methods to satisfy [[StaticInstanceInterface]] interface.
*
* @see StaticInstanceInterface
*
* @author Paul Klimov <klimov.paul@gmail.com>
* @since 2.0.13
*/
trait StaticInstanceTrait
{
/**
* @var static[] static instances in format: `[className => object]`
*/
private static $_instances = [];
/**
* Returns static class instance, which can be used to obtain meta information.
* @param bool $refresh whether to re-create static instance even, if it is already cached.
* @return static class instance.
*/
public static function instance($refresh = false)
{
$className = get_called_class();
if ($refresh || !isset(self::$_instances[$className])) {
self::$_instances[$className] = Yii::createObject($className);
}
return self::$_instances[$className];
}
}

1
framework/base/Theme.php

@ -153,6 +153,7 @@ class Theme extends Component
}
}
}
return $path;
}

9
framework/base/View.php

@ -319,6 +319,8 @@ class View extends Component
* @param string $_file_ the view file.
* @param array $_params_ the parameters (name-value pairs) that will be extracted and made available in the view file.
* @return string the rendering result
* @throws \Exception
* @throws \Throwable
*/
public function renderPhpFile($_file_, $_params_ = [])
{
@ -371,6 +373,7 @@ class View extends Component
return $placeholder;
}
return $this->evaluateDynamicContent($statements);
}
@ -401,7 +404,8 @@ class View extends Component
/**
* Begins recording a block.
* This method is a shortcut to beginning [[Block]]
*
* This method is a shortcut to beginning [[Block]].
* @param string $id the block ID.
* @param bool $renderInPlace whether to render the block content in place.
* Defaults to false, meaning the captured block will not be displayed.
@ -426,6 +430,7 @@ class View extends Component
/**
* Begins the rendering of content that is to be decorated by the specified view.
*
* This method can be used to implement nested layout. For example, a layout can be embedded
* in another layout file specified as '@app/views/layouts/base.php' like the following:
*
@ -460,6 +465,7 @@ class View extends Component
/**
* Begins fragment caching.
*
* This method will display cached content if it is available.
* If not, it will start caching and would expect an [[endCache()]]
* call to end the cache and save the content into cache.
@ -488,6 +494,7 @@ class View extends Component
return false;
}
return true;
}

2
framework/base/Widget.php

@ -110,6 +110,7 @@ class Widget extends Component implements ViewContextInterface
$result = $widget->afterRun($result);
echo $result;
}
return $widget;
}
@ -212,6 +213,7 @@ class Widget extends Component implements ViewContextInterface
/**
* Renders a view.
*
* The view to be rendered can be specified in one of the following formats:
*
* - [path alias](guide:concept-aliases) (e.g. "@app/views/site/index");

1
framework/behaviors/AttributeTypecastBehavior.php

@ -285,6 +285,7 @@ class AttributeTypecastBehavior extends Behavior
}
}
}
return $attributeTypes;
}

185
framework/behaviors/AttributesBehavior.php

@ -0,0 +1,185 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\behaviors;
use Closure;
use yii\base\Behavior;
use yii\base\Event;
use yii\db\ActiveRecord;
/**
* AttributesBehavior automatically assigns values specified to one or multiple attributes of an ActiveRecord
* object when certain events happen.
*
* To use AttributesBehavior, configure the [[attributes]] property which should specify the list of attributes
* that need to be updated and the corresponding events that should trigger the update. Then configure the
* value of enclosed arrays with a PHP callable whose return value will be used to assign to the current attribute.
* For example,
*
* ```php
* use yii\behaviors\AttributesBehavior;
*
* public function behaviors()
* {
* return [
* [
* 'class' => AttributesBehavior::className(),
* 'attributes' => [
* 'attribute1' => [
* ActiveRecord::EVENT_BEFORE_INSERT => new Expression('NOW()'),
* ActiveRecord::EVENT_BEFORE_UPDATE => \Yii::$app->formatter->asDatetime('2017-07-13'),
* ],
* 'attribute2' => [
* ActiveRecord::EVENT_BEFORE_VALIDATE => [$this, 'storeAttributes'],
* ActiveRecord::EVENT_AFTER_VALIDATE => [$this, 'restoreAttributes'],
* ],
* 'attribute3' => [
* ActiveRecord::EVENT_BEFORE_VALIDATE => $fn2 = [$this, 'getAttribute2'],
* ActiveRecord::EVENT_AFTER_VALIDATE => $fn2,
* ],
* 'attribute4' => [
* ActiveRecord::EVENT_BEFORE_DELETE => function ($event, $attribute) {
* static::disabled() || $event->isValid = false;
* },
* ],
* ],
* ],
* ];
* }
* ```
*
* Because attribute values will be set automatically by this behavior, they are usually not user input and should therefore
* not be validated, i.e. they should not appear in the [[\yii\base\Model::rules()|rules()]] method of the model.
*
* @author Luciano Baraglia <luciano.baraglia@gmail.com>
* @author Qiang Xue <qiang.xue@gmail.com>
* @author Bogdan Stepanenko <bscheshirwork@gmail.com>
* @since 2.0.13
*/
class AttributesBehavior extends Behavior
{
/**
* @var array list of attributes that are to be automatically filled with the values specified via enclosed arrays.
* The array keys are the ActiveRecord attributes upon which the events are to be updated,
* and the array values are the array of corresponding events(s). For this enclosed array:
* the array keys are the ActiveRecord events upon which the attributes are to be updated,
* and the array values are the value that will be assigned to the current attributes. This can be an anonymous function,
* callable in array format (e.g. `[$this, 'methodName']`), an [[\yii\db\Expression|Expression]] object representing a DB expression
* (e.g. `new Expression('NOW()')`), scalar, string or an arbitrary value. If the former, the return value of the
* function will be assigned to the attributes.
*
* ```php
* [
* 'attribute1' => [
* ActiveRecord::EVENT_BEFORE_INSERT => new Expression('NOW()'),
* ActiveRecord::EVENT_BEFORE_UPDATE => \Yii::$app->formatter->asDatetime('2017-07-13'),
* ],
* 'attribute2' => [
* ActiveRecord::EVENT_BEFORE_VALIDATE => [$this, 'storeAttributes'],
* ActiveRecord::EVENT_AFTER_VALIDATE => [$this, 'restoreAttributes'],
* ],
* 'attribute3' => [
* ActiveRecord::EVENT_BEFORE_VALIDATE => $fn2 = [$this, 'getAttribute2'],
* ActiveRecord::EVENT_AFTER_VALIDATE => $fn2,
* ],
* 'attribute4' => [
* ActiveRecord::EVENT_BEFORE_DELETE => function ($event, $attribute) {
* static::disabled() || $event->isValid = false;
* },
* ],
* ]
* ```
*/
public $attributes = [];
/**
* @var array list of order of attributes that are to be automatically filled with the event.
* The array keys are the ActiveRecord events upon which the attributes are to be updated,
* and the array values are represent the order corresponding attributes.
* The rest of the attributes are processed at the end.
* If the [[attributes]] for this attribute do not specify this event, it is ignored
*
* ```php
* [
* ActiveRecord::EVENT_BEFORE_VALIDATE => ['attribute1', 'attribute2'],
* ActiveRecord::EVENT_AFTER_VALIDATE => ['attribute2', 'attribute1'],
* ]
* ```
*/
public $order = [];
/**
* @var bool whether to skip this behavior when the `$owner` has not been modified
*/
public $skipUpdateOnClean = true;
/**
* @var bool whether to preserve non-empty attribute values.
*/
public $preserveNonEmptyValues = false;
/**
* @inheritdoc
*/
public function events()
{
return array_fill_keys(
array_reduce($this->attributes, function ($carry, $item) {
return array_merge($carry, array_keys($item));
}, []),
'evaluateAttributes'
);
}
/**
* Evaluates the attributes values and assigns it to the current attributes.
* @param Event $event
*/
public function evaluateAttributes($event)
{
if ($this->skipUpdateOnClean
&& $event->name === ActiveRecord::EVENT_BEFORE_UPDATE
&& empty($this->owner->dirtyAttributes)
) {
return;
}
$attributes = array_keys(array_filter($this->attributes, function ($carry) use ($event) {
return array_key_exists($event->name, $carry);
}));
if (!empty($this->order[$event->name])) {
$attributes = array_merge(
array_intersect((array) $this->order[$event->name], $attributes),
array_diff($attributes, (array) $this->order[$event->name]));
}
foreach ($attributes as $attribute) {
if ($this->preserveNonEmptyValues && !empty($this->owner->$attribute)) {
continue;
}
$this->owner->$attribute = $this->getValue($attribute, $event);
}
}
/**
* Returns the value for the current attributes.
* This method is called by [[evaluateAttributes()]]. Its return value will be assigned
* to the target attribute corresponding to the triggering event.
* @param string $attribute target attribute name
* @param Event $event the event that triggers the current attribute updating.
* @return mixed the attribute value
*/
protected function getValue($attribute, $event)
{
if (!isset($this->attributes[$attribute][$event->name])) {
return null;
}
$value = $this->attributes[$attribute][$event->name];
if ($value instanceof Closure || (is_array($value) && is_callable($value))) {
return $value($event, $attribute);
}
return $value;
}
}

2
framework/behaviors/SluggableBehavior.php

@ -225,6 +225,7 @@ class SluggableBehavior extends AttributeBehavior
$iteration++;
$uniqueSlug = $this->generateUniqueSlug($slug, $iteration);
}
return $uniqueSlug;
}
@ -264,6 +265,7 @@ class SluggableBehavior extends AttributeBehavior
if (is_callable($this->uniqueSlugGenerator)) {
return call_user_func($this->uniqueSlugGenerator, $baseSlug, $iteration, $this->owner);
}
return $baseSlug . '-' . ($iteration + 1);
}

1
framework/behaviors/TimestampBehavior.php

@ -116,6 +116,7 @@ class TimestampBehavior extends AttributeBehavior
if ($this->value === null) {
return time();
}
return parent::getValue($event);
}

1
framework/caching/ArrayCache.php

@ -64,6 +64,7 @@ class ArrayCache extends SimpleCache
if (isset($this->_cache[$key]) && ($this->_cache[$key][1] === 0 || $this->_cache[$key][1] > microtime(true))) {
return $this->_cache[$key][0];
}
return false;
}

2
framework/caching/Cache.php

@ -306,7 +306,7 @@ class Cache extends Component implements CacheInterface
}
/**
* Deletes a value with the specified key from cache
* Deletes a value with the specified key from cache.
* @param mixed $key a key identifying the value to be deleted from cache. This can be a simple string or
* a complex data structure consisting of factors representing the key.
* @return bool if no error happens during deletion

1
framework/caching/ChainedDependency.php

@ -69,6 +69,7 @@ class ChainedDependency extends Dependency
return false;
}
}
return !$this->dependOnAll;
}
}

1
framework/caching/DbCache.php

@ -188,6 +188,7 @@ class DbCache extends SimpleCache
$this->gc();
return true;
}
return $this->addValue($key, $value, $ttl);
}

4
framework/caching/DbQueryDependency.php

@ -61,7 +61,8 @@ class DbQueryDependency extends Dependency
/**
* Generates the data needed to determine if dependency is changed.
* This method returns the query result
*
* This method returns the query result.
* @param CacheInterface $cache the cache component that is currently evaluating this dependency
* @return mixed the data needed to determine if dependency has been changed.
* @throws InvalidConfigException on invalid configuration.
@ -104,6 +105,7 @@ class DbQueryDependency extends Dependency
if (is_string($this->method)) {
return call_user_func([$query, $this->method], $db);
}
return call_user_func($this->method, $query, $db);
}
}

5
framework/caching/Dependency.php

@ -60,6 +60,8 @@ abstract class Dependency extends \yii\base\BaseObject
/**
* Returns a value indicating whether the dependency has changed.
* @deprecated since version 2.0.11. Will be removed in version 2.1. Use [[isChanged()]] instead.
* @param CacheInterface $cache the cache component that is currently evaluating this dependency
* @return bool whether the dependency has changed.
*/
public function getHasChanged($cache)
{
@ -67,7 +69,7 @@ abstract class Dependency extends \yii\base\BaseObject
}
/**
* Checks whether the dependency is changed
* Checks whether the dependency is changed.
* @param CacheInterface $cache the cache component that is currently evaluating this dependency
* @return bool whether the dependency has changed.
* @since 2.0.11
@ -83,6 +85,7 @@ abstract class Dependency extends \yii\base\BaseObject
} else {
$data = $this->generateDependencyData($cache);
}
return $data !== $this->data;
}

3
framework/caching/migrations/m150909_153426_cache_init.php

@ -10,7 +10,7 @@ use yii\caching\DbCache;
use yii\db\Migration;
/**
* Initializes Cache tables
* Initializes Cache tables.
*
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
* @since 2.0.7
@ -27,6 +27,7 @@ class m150909_153426_cache_init extends Migration
if (!$cache instanceof DbCache) {
throw new InvalidConfigException('You should configure "cache" component to use database before executing this migration.');
}
return $cache;
}

6
framework/captcha/Captcha.php

@ -102,11 +102,7 @@ class Captcha extends InputWidget
public function run()
{
$this->registerClientScript();
if ($this->hasModel()) {
$input = Html::activeTextInput($this->model, $this->attribute, $this->options);
} else {
$input = Html::textInput($this->name, $this->value, $this->options);
}
$input = $this->renderInputHtml('text');
$route = $this->captchaAction;
if (is_array($route)) {
$route['v'] = uniqid();

2
framework/composer.json

@ -73,7 +73,7 @@
"psr/http-message": "~1.0.0",
"ezyang/htmlpurifier": "~4.6",
"cebe/markdown": "~1.0.0 | ~1.1.0",
"bower-asset/jquery": "2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable",
"bower-asset/jquery": "3.2.*@stable | 3.1.*@stable | 2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable",
"bower-asset/punycode": "1.3.*",
"bower-asset/yii2-pjax": "~2.0.1"
},

24
framework/console/Controller.php

@ -131,6 +131,7 @@ class Controller extends \yii\base\Controller
$route = $this->getUniqueId() . '/' . $id;
return Yii::$app->runAction('help', [$route]);
}
return parent::runAction($id, $params);
}
@ -176,7 +177,7 @@ class Controller extends \yii\base\Controller
}
/**
* Formats a string with ANSI codes
* Formats a string with ANSI codes.
*
* You may pass additional parameters using the constants defined in [[\yii\helpers\Console]].
*
@ -196,11 +197,12 @@ class Controller extends \yii\base\Controller
array_shift($args);
$string = Console::ansiFormat($string, $args);
}
return $string;
}
/**
* Prints a string to STDOUT
* Prints a string to STDOUT.
*
* You may optionally format the string with ANSI codes by
* passing additional parameters using the constants defined in [[\yii\helpers\Console]].
@ -221,11 +223,12 @@ class Controller extends \yii\base\Controller
array_shift($args);
$string = Console::ansiFormat($string, $args);
}
return Console::stdout($string);
}
/**
* Prints a string to STDERR
* Prints a string to STDERR.
*
* You may optionally format the string with ANSI codes by
* passing additional parameters using the constants defined in [[\yii\helpers\Console]].
@ -246,11 +249,12 @@ class Controller extends \yii\base\Controller
array_shift($args);
$string = Console::ansiFormat($string, $args);
}
return fwrite(\STDERR, $string);
}
/**
* Prompts the user for input and validates it
* Prompts the user for input and validates it.
*
* @param string $text prompt string
* @param array $options the options to validate the input:
@ -375,6 +379,7 @@ class Controller extends \yii\base\Controller
foreach ($this->options($this->action->id) as $property) {
$properties[$property] = $this->$property;
}
return $properties;
}
@ -389,7 +394,7 @@ class Controller extends \yii\base\Controller
}
/**
* Returns the properties corresponding to the passed options
* Returns the properties corresponding to the passed options.
*
* @return array the properties corresponding to the passed options
*/
@ -399,6 +404,7 @@ class Controller extends \yii\base\Controller
foreach ($this->_passedOptions as $property) {
$properties[$property] = $this->$property;
}
return $properties;
}
@ -449,6 +455,7 @@ class Controller extends \yii\base\Controller
/**
* Returns the help information for the anonymous arguments for the action.
*
* The returned value should be an array. The keys are the argument names, and the values are
* the corresponding help information. Each value must be an array of the following structure:
*
@ -501,11 +508,13 @@ class Controller extends \yii\base\Controller
];
}
}
return $args;
}
/**
* Returns the help information for the options for the action.
*
* The returned value should be an array. The keys are the option names, and the values are
* the corresponding help information. Each value must be an array of the following structure:
*
@ -560,6 +569,7 @@ class Controller extends \yii\base\Controller
];
}
}
return $options;
}
@ -578,6 +588,7 @@ class Controller extends \yii\base\Controller
$this->_reflections[$action->id] = new \ReflectionMethod($action, 'run');
}
}
return $this->_reflections[$action->id];
}
@ -604,6 +615,7 @@ class Controller extends \yii\base\Controller
}
}
}
return $tags;
}
@ -619,6 +631,7 @@ class Controller extends \yii\base\Controller
if (isset($docLines[1])) {
return trim($docLines[1], "\t *");
}
return '';
}
@ -637,6 +650,7 @@ class Controller extends \yii\base\Controller
if ($comment !== '') {
return rtrim(Console::renderColoredString(Console::markdownToAnsi($comment)));
}
return '';
}
}

1
framework/console/ErrorHandler.php

@ -82,6 +82,7 @@ class ErrorHandler extends \yii\base\ErrorHandler
|| Yii::$app instanceof \yii\console\Application && Console::streamSupportsAnsiColors($stream)) {
$message = Console::ansiFormat($message, $format);
}
return $message;
}
}

4
framework/console/Markdown.php

@ -43,7 +43,7 @@ class Markdown extends \cebe\markdown\Parser
/**
* Renders a code block
* Renders a code block.
*
* @param array $block
* @return string
@ -54,7 +54,7 @@ class Markdown extends \cebe\markdown\Parser
}
/**
* Render a paragraph block
* Render a paragraph block.
*
* @param string $block
* @return string

1
framework/console/UnknownCommandException.php

@ -94,6 +94,7 @@ class UnknownCommandException extends Exception
}
}
}
return $this->filterBySimilarity($availableActions, $this->command);
}

1
framework/console/controllers/AssetController.php

@ -760,6 +760,7 @@ EOD;
$realPathParts[] = $pathPart;
}
}
return implode(DIRECTORY_SEPARATOR, $realPathParts);
}

57
framework/console/controllers/BaseMigrateController.php

@ -8,7 +8,9 @@
namespace yii\console\controllers;
use Yii;
use yii\base\BaseObject;
use yii\base\InvalidConfigException;
use yii\base\NotSupportedException;
use yii\console\Controller;
use yii\console\Exception;
use yii\console\ExitCode;
@ -81,6 +83,13 @@ abstract class BaseMigrateController extends Controller
*/
public $templateFile;
/**
* @var bool indicates whether the console output should be compacted.
* If this is set to true, the individual commands ran within the migration will not be output to the console.
* Default is false, in other words the output is fully verbose by default.
* @since 2.0.13
*/
public $compact = false;
/**
* @inheritdoc
@ -89,7 +98,7 @@ abstract class BaseMigrateController extends Controller
{
return array_merge(
parent::options($actionID),
['migrationPath', 'migrationNamespaces'], // global for all actions
['migrationPath', 'migrationNamespaces', 'compact'], // global for all actions
$actionID === 'create' ? ['templateFile'] : [] // action create
);
}
@ -138,6 +147,7 @@ abstract class BaseMigrateController extends Controller
/**
* Upgrades the application by applying new migrations.
*
* For example,
*
* ```
@ -196,6 +206,7 @@ abstract class BaseMigrateController extends Controller
/**
* Downgrades the application by reverting old migrations.
*
* For example,
*
* ```
@ -428,6 +439,31 @@ abstract class BaseMigrateController extends Controller
}
/**
* Truncates the whole database and starts the migration from the beginning.
*
* ```
* yii migrate/fresh
* ```
*
* @since 2.0.13
*/
public function actionFresh()
{
if (YII_ENV_PROD) {
$this->stdout("YII_ENV is set to 'prod'.\nRefreshing migrations is not possible on production systems.\n");
return ExitCode::OK;
}
if ($this->confirm(
"Are you sure you want to reset the database and start the migration from the beginning?\nAll data will be lost irreversibly!")) {
$this->truncateDatabase();
$this->actionUp();
} else {
$this->stdout('Action was cancelled by user. Nothing has been performed.');
}
}
/**
* Checks if given migration version specification matches namespaced migration name.
* @param string $rawVersion raw version specification received from user input.
* @return string|false actual migration version, `false` - if not match.
@ -438,6 +474,7 @@ abstract class BaseMigrateController extends Controller
if (preg_match('/^\\\\?([\w_]+\\\\)+m(\d{6}_?\d{6})(\D.*)?$/is', $rawVersion, $matches)) {
return trim($rawVersion, '\\');
}
return false;
}
@ -452,6 +489,7 @@ abstract class BaseMigrateController extends Controller
if (preg_match('/^m?(\d{6}_?\d{6})(\D.*)?$/is', $rawVersion, $matches)) {
return 'm' . $matches[1];
}
return false;
}
@ -722,7 +760,11 @@ abstract class BaseMigrateController extends Controller
protected function createMigration($class)
{
$this->includeMigrationFile($class);
return new $class();
$migration = new $class();
if ($migration instanceof BaseObject && $migration->canSetProperty('compact')) {
$migration->compact = $this->compact;
}
return $migration;
}
/**
@ -878,6 +920,17 @@ abstract class BaseMigrateController extends Controller
}
/**
* Truncates the database.
* This method should be overwritten in subclasses to implement the task of clearing the database.
* @throws NotSupportedException if not overridden
* @since 2.0.13
*/
protected function truncateDatabase()
{
throw new NotSupportedException('This command is not implemented in ' . get_class($this));
}
/**
* Returns the migration history.
* @param int $limit the maximum number of records in the history to be returned. `null` for "no limit".
* @return array the migration history

52
framework/console/controllers/CacheController.php

@ -93,7 +93,7 @@ class CacheController extends Controller
return ExitCode::OK;
}
if (!$this->confirmClear($foundCaches)) {
if (!$this->confirmFlush($foundCaches)) {
return ExitCode::OK;
}
@ -101,17 +101,17 @@ class CacheController extends Controller
$cachesInfo[] = [
'name' => $name,
'class' => $class,
'is_cleared' => $this->canBeCleared($class) ? Yii::$app->get($name)->clear() : false,
'is_flushed' => $this->canBeFlushed($class) ? Yii::$app->get($name)->flush() : false,
];
}
$this->notifyCleared($cachesInfo);
$this->notifyFlushed($cachesInfo);
}
/**
* Clears all caches registered in the system.
* Flushes all caches registered in the system.
*/
public function actionClearAll()
public function actionFlushAll()
{
$caches = $this->findCaches();
$cachesInfo = [];
@ -125,11 +125,11 @@ class CacheController extends Controller
$cachesInfo[] = [
'name' => $name,
'class' => $class,
'is_cleared' => $this->canBeCleared($class) ? Yii::$app->get($name)->clear() : false,
'is_flushed' => $this->canBeFlushed($class) ? Yii::$app->get($name)->flush() : false,
];
}
$this->notifyCleared($cachesInfo);
$this->notifyFlushed($cachesInfo);
}
/**
@ -137,7 +137,7 @@ class CacheController extends Controller
*
* ```
* # clears cache schema specified by component id: "db"
* yii cache/clear-schema db
* yii cache/flush-schema db
* ```
*
* @param string $db id connection component
@ -147,7 +147,7 @@ class CacheController extends Controller
*
* @since 2.0.1
*/
public function actionClearSchema($db = 'db')
public function actionFlushSchema($db = 'db')
{
$connection = Yii::$app->get($db, false);
if ($connection === null) {
@ -158,32 +158,32 @@ class CacheController extends Controller
if (!$connection instanceof \yii\db\Connection) {
$this->stdout("\"$db\" component doesn't inherit \\yii\\db\\Connection.\n", Console::FG_RED);
return ExitCode::UNSPECIFIED_ERROR;
} elseif (!$this->confirm("Clear cache schema for \"$db\" connection?")) {
} elseif (!$this->confirm("Flush cache schema for \"$db\" connection?")) {
return ExitCode::OK;
}
try {
$schema = $connection->getSchema();
$schema->refresh();
$this->stdout("Schema cache for component \"$db\", was cleared.\n\n", Console::FG_GREEN);
$this->stdout("Schema cache for component \"$db\", was flushed.\n\n", Console::FG_GREEN);
} catch (\Exception $e) {
$this->stdout($e->getMessage() . "\n\n", Console::FG_RED);
}
}
/**
* Notifies user that given caches are found and can be cleared.
* Notifies user that given caches are found and can be flushed.
* @param array $caches array of cache component classes
*/
private function notifyCachesCanBeCleared($caches)
private function notifyCachesCanBeFlushed($caches)
{
$this->stdout("The following caches were found in the system:\n\n", Console::FG_YELLOW);
foreach ($caches as $name => $class) {
if ($this->canBeCleared($class)) {
if ($this->canBeFlushed($class)) {
$this->stdout("\t* $name ($class)\n", Console::FG_GREEN);
} else {
$this->stdout("\t* $name ($class) - can not be cleared via console\n", Console::FG_YELLOW);
$this->stdout("\t* $name ($class) - can not be flushed via console\n", Console::FG_YELLOW);
}
}
@ -216,15 +216,15 @@ class CacheController extends Controller
/**
* @param array $caches
*/
private function notifyCleared($caches)
private function notifyFlushed($caches)
{
$this->stdout("The following cache components were processed:\n\n", Console::FG_YELLOW);
foreach ($caches as $cache) {
$this->stdout("\t* " . $cache['name'] . ' (' . $cache['class'] . ')', Console::FG_GREEN);
if (!$cache['is_cleared']) {
$this->stdout(" - not cleared\n", Console::FG_RED);
if (!$cache['is_flushed']) {
$this->stdout(" - not flushed\n", Console::FG_RED);
} else {
$this->stdout("\n");
}
@ -234,19 +234,19 @@ class CacheController extends Controller
}
/**
* Prompts user with confirmation if caches should be cleared.
* Prompts user with confirmation if caches should be flushed.
* @param array $cachesNames
* @return bool
*/
private function confirmClear($cachesNames)
private function confirmFlush($cachesNames)
{
$this->stdout("The following cache components will be cleared:\n\n", Console::FG_YELLOW);
$this->stdout("The following cache components will be flushed:\n\n", Console::FG_YELLOW);
foreach ($cachesNames as $name) {
$this->stdout("\t* $name \n", Console::FG_GREEN);
}
return $this->confirm("\nClear above cache components?");
return $this->confirm("\nFlush above cache components?");
}
/**
@ -271,6 +271,12 @@ class CacheController extends Controller
$caches[$name] = $component['class'];
} elseif (is_string($component) && $this->isCacheClass($component)) {
$caches[$name] = $component;
} elseif ($component instanceof \Closure) {
$cache = Yii::$app->get($name);
if ($this->isCacheClass($cache)) {
$cacheClass = get_class($cache);
$caches[$name] = $cacheClass;
}
}
}
@ -288,7 +294,7 @@ class CacheController extends Controller
}
/**
* Checks if cache of a certain class can be cleared
* Checks if cache of a certain class can be cleared.
* @param string $className class name.
* @return bool
*/

13
framework/console/controllers/FixtureController.php

@ -88,6 +88,7 @@ class FixtureController extends Controller
/**
* Loads the specified fixture data.
*
* For example,
*
* ```
@ -168,6 +169,7 @@ class FixtureController extends Controller
/**
* Unloads the specified fixtures.
*
* For example,
*
* ```
@ -243,7 +245,7 @@ class FixtureController extends Controller
}
/**
* Notifies user that there are no fixtures to load according input conditions
* Notifies user that there are no fixtures to load according input conditions.
* @param array $foundFixtures array of found fixtures
* @param array $except array of names of fixtures that should not be loaded
*/
@ -265,7 +267,7 @@ class FixtureController extends Controller
}
/**
* Notifies user that there are no fixtures to unload according input conditions
* Notifies user that there are no fixtures to unload according input conditions.
* @param array $foundFixtures array of found fixtures
* @param array $except array of names of fixtures that should not be loaded
*/
@ -425,7 +427,7 @@ class FixtureController extends Controller
/**
* Calculates fixture's name
* Basically, strips [[getFixturePath()]] and `Fixture.php' suffix from fixture's full path
* Basically, strips [[getFixturePath()]] and `Fixture.php' suffix from fixture's full path.
* @see getFixturePath()
* @param string $fullFixturePath Full fixture path
* @return string Relative fixture name
@ -454,10 +456,12 @@ class FixtureController extends Controller
$isNamespaced = (strpos($fixture, '\\') !== false);
// replace linux' path slashes to namespace backslashes, in case if $fixture is non-namespaced relative path
$fixture = str_replace('/', '\\', $fixture);
$fullClassName = $isNamespaced ? $fixture . 'Fixture' : $this->namespace . '\\' . $fixture . 'Fixture';
$fullClassName = $isNamespaced ? $fixture : $this->namespace . '\\' . $fixture;
if (class_exists($fullClassName)) {
$config[] = $fullClassName;
} elseif (class_exists($fullClassName . 'Fixture')) {
$config[] = $fullClassName . 'Fixture';
}
}
@ -466,6 +470,7 @@ class FixtureController extends Controller
/**
* Filters fixtures by splitting them in two categories: one that should be applied and not.
*
* If fixture is prefixed with "-", for example "-User", that means that fixture should not be loaded,
* if it is not prefixed it is considered as one to be loaded. Returns array:
*

3
framework/console/controllers/HelpController.php

@ -131,7 +131,7 @@ class HelpController extends Controller
}
/**
* Displays usage information for $action
* Displays usage information for $action.
*
* @param string $action route to action
* @since 2.0.11
@ -529,6 +529,7 @@ class HelpController extends Controller
return ', -' . $name;
}
}
return '';
}

21
framework/console/controllers/MessageController.php

@ -205,7 +205,7 @@ class MessageController extends \yii\console\Controller
}
/**
* Creates a configuration file for the "extract" command using command line options specified
* Creates a configuration file for the "extract" command using command line options specified.
*
* The generated configuration file contains parameters required
* for source code messages extraction.
@ -336,7 +336,7 @@ EOD;
}
/**
* Saves messages to database
* Saves messages to database.
*
* @param array $messages
* @param Connection $db
@ -458,7 +458,7 @@ EOD;
}
/**
* Extracts messages from a file
* Extracts messages from a file.
*
* @param string $fileName name of the file to extract messages from
* @param string $translator name of the function used to translate messages
@ -572,6 +572,7 @@ EOD;
/**
* The method checks, whether the $category is ignored according to $ignoreCategories array.
*
* Examples:
*
* - `myapp` - will be ignored only `myapp` category;
@ -599,7 +600,7 @@ EOD;
}
/**
* Finds out if two PHP tokens are equal
* Finds out if two PHP tokens are equal.
*
* @param array|string $a
* @param array|string $b
@ -614,11 +615,12 @@ EOD;
if (isset($a[0], $a[1], $b[0], $b[1])) {
return $a[0] === $b[0] && $a[1] == $b[1];
}
return false;
}
/**
* Finds out a line of the first non-char PHP token found
* Finds out a line of the first non-char PHP token found.
*
* @param array $tokens
* @return int|string
@ -631,11 +633,12 @@ EOD;
return $token[2];
}
}
return 'unknown';
}
/**
* Writes messages into PHP files
* Writes messages into PHP files.
*
* @param array $messages
* @param string $dirName name of the directory to write to
@ -658,7 +661,7 @@ EOD;
}
/**
* Writes category messages into PHP file
* Writes category messages into PHP file.
*
* @param array $messages
* @param string $fileName name of the file to write to
@ -740,7 +743,7 @@ EOD;
}
/**
* Writes messages into PO file
* Writes messages into PO file.
*
* @param array $messages
* @param string $dirName name of the directory to write to
@ -836,7 +839,7 @@ EOD;
}
/**
* Writes messages into POT file
* Writes messages into POT file.
*
* @param array $messages
* @param string $dirName name of the directory to write to

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save