Browse Source

Merge branch 'master' into json-error-response

# Conflicts:
#	framework/CHANGELOG.md
9899-cache-bug
Alexander Makarov 9 years ago
parent
commit
3b140d9eff
  1. 4
      .travis.yml
  2. 2
      docs/guide-es/start-installation.md
  3. 2
      docs/guide-it/start-installation.md
  4. 13
      docs/guide-ja/concept-di-container.md
  5. 2
      docs/guide-ja/db-migrations.md
  6. 4
      docs/guide-ja/input-multiple-models.md
  7. 29
      docs/guide-ja/input-validation.md
  8. 1
      docs/guide-ja/security-authorization.md
  9. 16
      docs/guide-ja/start-installation.md
  10. 464
      docs/guide-ja/tutorial-i18n.md
  11. 4
      docs/guide-ja/tutorial-performance-tuning.md
  12. 2
      docs/guide-ja/tutorial-start-from-scratch.md
  13. 2
      docs/guide-ja/tutorial-yii-integration.md
  14. 2
      docs/guide-pl/start-installation.md
  15. 2
      docs/guide-pt-BR/start-installation.md
  16. 2
      docs/guide-pt-BR/tutorial-yii-integration.md
  17. 4
      docs/guide-ru/security-authentication.md
  18. 2
      docs/guide-ru/start-installation.md
  19. 4
      docs/guide-ru/test-overview.md
  20. 2
      docs/guide-ru/tutorial-start-from-scratch.md
  21. 2
      docs/guide-ru/tutorial-yii-integration.md
  22. 6
      docs/guide-uk/README.md
  23. 6
      docs/guide-uk/caching-fragment.md
  24. 2
      docs/guide-uk/intro-upgrade-from-v1.md
  25. 4
      docs/guide-uk/start-databases.md
  26. 4
      docs/guide-uk/start-forms.md
  27. 22
      docs/guide-uk/start-gii.md
  28. 6
      docs/guide-uk/start-hello.md
  29. 2
      docs/guide-uk/start-installation.md
  30. 2
      docs/guide-uk/start-looking-ahead.md
  31. 2
      docs/guide-uk/start-workflow.md
  32. 2
      docs/guide-uk/structure-controllers.md
  33. 8
      docs/guide-uk/structure-models.md
  34. 723
      docs/guide-uk/structure-views.md
  35. 2
      docs/guide-uk/tutorial-yii-integration.md
  36. 2
      docs/guide-vi/start-installation.md
  37. 2
      docs/guide-zh-CN/start-installation.md
  38. 30
      docs/guide/concept-di-container.md
  39. 6
      docs/guide/db-migrations.md
  40. 4
      docs/guide/input-multiple-models.md
  41. 4
      docs/guide/security-authorization.md
  42. 23
      docs/guide/start-installation.md
  43. 151
      docs/guide/tutorial-i18n.md
  44. 5
      docs/guide/tutorial-performance-tuning.md
  45. 2
      docs/guide/tutorial-start-from-scratch.md
  46. 2
      docs/guide/tutorial-yii-integration.md
  47. 2
      docs/internals-ja/git-workflow.md
  48. 8
      docs/internals-uk/translation-workflow.md
  49. 2
      docs/internals/git-workflow.md
  50. 16
      framework/CHANGELOG.md
  51. 2
      framework/assets/yii.activeForm.js
  52. 2
      framework/assets/yii.validation.js
  53. 5
      framework/base/Controller.php
  54. 66
      framework/caching/migrations/m150909_153426_cache_init.php
  55. 20
      framework/caching/migrations/schema-mssql.sql
  56. 20
      framework/caching/migrations/schema-mysql.sql
  57. 20
      framework/caching/migrations/schema-oci.sql
  58. 20
      framework/caching/migrations/schema-pgsql.sql
  59. 20
      framework/caching/migrations/schema-sqlite.sql
  60. 1
      framework/composer.json
  61. 19
      framework/console/Controller.php
  62. 2
      framework/console/controllers/MessageController.php
  63. 2
      framework/data/BaseDataProvider.php
  64. 16
      framework/db/Query.php
  65. 4
      framework/filters/AccessRule.php
  66. 4
      framework/grid/ActionColumn.php
  67. 18
      framework/helpers/BaseFileHelper.php
  68. 2
      framework/helpers/BaseJson.php
  69. 20
      framework/i18n/Formatter.php
  70. 8
      framework/i18n/MessageFormatter.php
  71. 2
      framework/messages/config.php
  72. 105
      framework/messages/hr/yii.php
  73. 6
      framework/messages/nl/yii.php
  74. 2
      framework/messages/sr/yii.php
  75. 13
      framework/messages/zh-TW/yii.php
  76. 37
      framework/rbac/DbManager.php
  77. 2
      framework/rbac/ManagerInterface.php
  78. 37
      framework/rbac/PhpManager.php
  79. 7
      framework/rbac/migrations/m140506_102106_rbac_init.php
  80. 14
      framework/validators/Validator.php
  81. 9
      framework/web/Controller.php
  82. 2
      framework/web/Request.php
  83. 35
      framework/web/UnprocessableEntityHttpException.php
  84. 2
      framework/web/UrlManager.php
  85. 6
      framework/widgets/LinkPager.php
  86. 3
      tests/TestCase.php
  87. 86
      tests/framework/console/ControllerTest.php
  88. 56
      tests/framework/console/FakeController.php
  89. 33
      tests/framework/db/QueryBuilderTest.php
  90. 9
      tests/framework/helpers/UrlTest.php
  91. 24
      tests/framework/rbac/ManagerTestCase.php
  92. 12
      tests/framework/rbac/PhpManagerTest.php
  93. 81
      tests/framework/web/ControllerTest.php
  94. 49
      tests/framework/web/FakeController.php
  95. 20
      tests/framework/web/UrlManagerTest.php
  96. 19
      tests/framework/web/stubs/Bar.php
  97. 24
      tests/framework/web/stubs/OtherQux.php

4
.travis.yml

@ -6,7 +6,6 @@ php:
- 5.6
- 7.0
- hhvm
- hhvm-nightly
env:
- CUBRID_VERSION=9.3.0/CUBRID-9.3.0.0206 CUBRID_PDO_VERSION=9.3.0.0001
@ -16,7 +15,6 @@ env:
matrix:
fast_finish: true
allow_failures:
- php: hhvm-nightly
- php: 7.0
services:
@ -38,7 +36,7 @@ addons:
install:
- travis_retry composer self-update && composer --version
- travis_retry composer global require "fxp/composer-asset-plugin:~1.0.0"
- travis_retry composer global require "fxp/composer-asset-plugin:~1.0.3"
- export PATH="$HOME/.composer/vendor/bin:$PATH"
# core framework:
- travis_retry composer install --prefer-dist --no-interaction

2
docs/guide-es/start-installation.md

@ -26,7 +26,7 @@ Si ya tienes composer instalado asegurate que esté actualizado ejecutando `comp
Teniendo Composer instalado, puedes instalar Yii ejecutando los siguientes comandos en un directorio accesible vía Web:
Nota: es posible que en al ejecutar el primer comando te pida tu username
composer global require "fxp/composer-asset-plugin:~1.0.0"
composer global require "fxp/composer-asset-plugin:~1.0.3"
composer create-project --prefer-dist yiisoft/yii2-app-basic basic
El comando anterior instala Yii dentro del directorio `basic`.

2
docs/guide-it/start-installation.md

@ -27,7 +27,7 @@ Se hai già Composer installato assicurati di avere una versione aggiornata. Puo
Una volta installato Composer, puoi installare Yii eseguendo questo comando in una directory accessbile via web:
composer global require "fxp/composer-asset-plugin:~1.0.0"
composer global require "fxp/composer-asset-plugin:~1.0.3"
composer create-project --prefer-dist yiisoft/yii2-app-basic basic
Il primo comando installa il [plugin composer asset](https://github.com/francoispluchino/composer-asset-plugin/)

13
docs/guide-ja/concept-di-container.md

@ -91,7 +91,7 @@ $container->set('Foo', function () {
$foo = $container->get('Foo');
```
新しいオブジェクトを構築するための複雑なロジックを隠蔽するために、PHP コーラブルを返すスタティックなクラスメソッドを使うことが出来ます。
新しいオブジェクトを構築するための複雑なロジックを隠蔽するために、スタティックなクラスメソッドをコーラブルとして使うことが出来ます。
例えば、
```php
@ -99,20 +99,17 @@ class FooBuilder
{
public static function build()
{
return function () {
$foo = new Foo(new Bar);
// ... その他の初期化 ...
return $foo;
};
$foo = new Foo(new Bar);
// ... その他の初期化 ...
return $foo;
}
}
$container->set('Foo', FooBuilder::build());
$container->set('Foo', ['app\helper\FooBuilder', 'build']);
$foo = $container->get('Foo');
```
ご覧のように、PHP コーラブルが `FooBuilder::build()` メソッドによって返されています。
このようにすれば、`Foo` クラスを構成しようとする人は、`Foo` がどのように構築されるかを気にする必要はもうなくなります。

2
docs/guide-ja/db-migrations.md

@ -142,7 +142,7 @@ MySQL の場合は、`TYPE_PK` は `int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY`
> Info|情報: 抽象型と物理型の対応関係は、それぞれの `QueryBuilder` の具象クラスの [[yii\db\QueryBuilder::$typeMap|$typeMap]] プロパティによって定義されています。
バージョン 2.0.6 以降は、スキーマビルダにカラムのスキーマを定義するための更に便利な方法が導入されたため、上記のマイグレーションは次のように書くことが出来るようになっています。
バージョン 2.0.6 以降は、カラムのスキーマを定義するための更に便利な方法を提供するスキーマビルダが新たに導入されているため、上記のマイグレーションは次のように書くことが出来ます。
```php
<?php

4
docs/guide-ja/input-multiple-models.md

@ -34,7 +34,9 @@ class UserController extends Controller
$profile->scenario = 'update';
if ($user->load(Yii::$app->request->post()) && $profile->load(Yii::$app->request->post())) {
if ($user->validate() && $profile->validate()) {
$isValid = $user->validate();
$isValid = $profile->validate() && $isValid;
if ($isValid) {
$user->save(false);
$profile->save(false);
return $this->redirect(['user/view', 'id' => $id]);

29
docs/guide-ja/input-validation.md

@ -349,7 +349,8 @@ class MyForm extends Model
スタンドアロンバリデータは、[[yii\validators\Validator]] またはその子クラスを拡張するクラスです。
[[yii\validators\Validator::validateAttribute()]] メソッドをオーバーライドすることによって、その検証ロジックを実装することが出来ます。
[インラインバリデータ](#inline-validators) でするのと同じように、属性が検証に失敗した場合は、[[yii\base\Model::addError()]] を呼んでエラーメッセージをモデルに保存します。
例えば、
例えば、上記のインラインバリデータは、新しい [[components/validators/CountryValidator]] クラスに作りかえることが出来ます。
```php
namespace app\components;
@ -373,6 +374,32 @@ class CountryValidator extends Validator
と言うのは、前の二つは、デフォルトでは、`validateValue()` を呼び出すことによって実装されているからです。
次の例は、上記のバリデータクラスをあなたのモデルの中でどのように使用することが出来るかを示すものです。
```php
namespace app\models;
use Yii;
use yii\base\Model;
use app\components\validators\CountryValidator;
class EntryForm extends Model
{
public $name;
public $email;
public $country;
public function rules()
{
return [
[['name', 'email'], 'required'],
['country', CountryValidator::className()],
['email', 'email'],
];
}
}
```
## クライアント側での検証 <span id="client-side-validation"></span>
エンドユーザが HTML フォームで値を入力する際には、JavaScript に基づくクライアント側での検証を提供することが望まれます。

1
docs/guide-ja/security-authorization.md

@ -90,6 +90,7 @@ ACF が権限のチェックを実行するときには、規則を一つずつ
* [[yii\filters\AccessRule::controllers|controllers]]: どのコントローラにこの規則が適用されるかを指定します。
これはコントローラ ID の配列でなければなりません。
コントローラがモジュールに属する場合は、モジュール ID をコントローラ ID の前に付けます。
比較は大文字と小文字を区別します。
このオプションが空であるか指定されていない場合は、規則が全てのコントローラに適用されることを意味します。

16
docs/guide-ja/start-installation.md

@ -36,7 +36,7 @@ Composer は `composer self-update` コマンドを実行してアップデー
Composer がインストールされたら、ウェブからアクセスできるフォルダで下記のコマンドを実行することによって Yii をインストールすることが出来ます。
composer global require "fxp/composer-asset-plugin:~1.0.0"
composer global require "fxp/composer-asset-plugin:~1.0.3"
composer create-project --prefer-dist yiisoft/yii2-app-basic basic
最初のコマンドは [composer アセットプラグイン](https://github.com/francoispluchino/composer-asset-plugin/) をインストールします。
@ -89,10 +89,18 @@ Composer がインストールされたら、ウェブからアクセスでき
インストールを検証する <span id="verifying-installation"></span>
----------------------
インストール完了後、下記の URL によって、インストールされた Yii アプリケーションにブラウザを使ってアクセスすることが出来ます。
インストール完了後、あなたのウェブサーバを構成してください (次の説を参照してください)。
あるいは、プロジェクトの `web` ディレクトリで次のコマンドを実行して、
[PHP の内蔵ウェブサーバ](https://secure.php.net/manual/ja/features.commandline.webserver.php) を使ってください。
```
http://localhost/basic/web/index.php
php -S localhost:80
```
下記の URL によって、インストールされた Yii アプリケーションにブラウザを使ってアクセスすることが出来ます。
```
http://localhost/
```
この URL は、あなたが Yii を ウェブサーバのドキュメントルートディレクトリ直下の `basic` という名前のディレクトリにインストールしたこと、
@ -105,7 +113,7 @@ http://localhost/basic/web/index.php
もし表示されなかったら、PHP のインストールが Yii の必要条件を満たしているかどうか、チェックしてください。
最低限の必要条件を満たしているかどうかは、次の方法のどちらかによってチェックすることが出来ます。
* ブラウザを使って URL `http://localhost/basic/requirements.php` にアクセスする。
* `requirements.php``/web/requirements.php` としてコピーし、ブラウザを使って URL `http://localhost/requirements.php` にアクセスする。
* 次のコマンドを実行する。
```

464
docs/guide-ja/tutorial-i18n.md

@ -1,70 +1,77 @@
国際化
======
> Note|注意: この節はまだ執筆中です。
国際化 (I18N) とは、工学的な変更を伴わずにさまざまな言語と地域に順応できるように、ソフトウェアアプリケーションを設計するプロセスを指します。
潜在的なユーザが世界中にいるウェブアプリケーションにとっては、このことは特に重要な意味を持ちます。
Yii は、全ての領域にわたる国際化機能を提供し、メッセージの翻訳、ビューの翻訳、日付と数字の書式設定をサポートします。
Yii は、メッセージの翻訳、数字や日付の書式設定など、ウェブサイトの国際化を手助けするいくつかのツールを提供しています。
ロケールと言語
--------------
## ロケールと言語 <span id="locale-language"></span>
Yii のアプリケーションでは二つの言語が定義されます。
すなわち、[[yii\base\Application::$sourceLanguage|ソース言語]] と [[yii\base\Application::$language|ターゲット言語]] です。
ロケールとは、ユーザの言語、国、そして、ユーザが彼らのユーザインタフェイスにおいて目にすることを期待するすべての変異形式を定義する一連のパラメータです。
ロケールは、通常、言語 ID と地域 ID から成るロケール ID によって定義されます。
例えば、`en-US` は、英語とアメリカ合衆国のロケールを意味します。
Yii アプリケーションで使用される全てのロケール ID は、一貫性のために、`ll-CC` の形式に正規化されなければなりません。
ここで `ll` は [ISO-639](http://www.loc.gov/standards/iso639-2/) に従った小文字二つまたは三つの言語コードであり、`CC` は [ISO-3166](http://www.iso.org/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html) に従った二文字の国コードです。
ロケールに関する更なる詳細は [ICU プロジェクトのドキュメント project](http://userguide.icu-project.org/locale#TOC-The-Locale-Concept) に述べられています。
ソース言語とは、次のように、コードに直接書かれているオリジナルのアプリケーションメッセージの言語です。
Yii では、"言語" という用語でロケールに言及することがしばしばあります。
```php
echo \Yii::t('app', 'I am a message!');
```
Yii のアプリケーションでは二つの言語を使用します。
すなわち、[[yii\base\Application::$sourceLanguage|ソース言語]] と [[yii\base\Application::$language|ターゲット言語]] です。
前者はソースコード中のテキストメッセージが書かれている言語を意味し、後者はコンテントをエンドユーザに表示するのに使用されるべき言語を指します。
いわゆるメッセージ翻訳サービスは、主として、テキストメッセージをソース言語からターゲット言語に翻訳するものです。
ターゲット言語は、現在のページを表示するのに使用されるべき言語、すなわち、オリジナルのメッセージの翻訳先となるべき言語です。
これはアプリケーションの構成情報において、次のように定義されているものです。
アプリケーションの言語は、アプリケーションの構成情報で次のように構成することが出来ます。
```php
return [
'id' => 'applicationID',
'basePath' => dirname(__DIR__),
// ...
'language' => 'ru-RU', // <- ここ !
// ...
]
// ターゲット言語を日本語に設定
'language' => 'ja-JP',
// ソース言語を英語に設定
'sourceLanguage' => 'en-US',
......
];
```
> **Tip**|ヒント: [[yii\base\Application::$sourceLanguage|ソース言語]] のデフォルト値は英語であり、この値は変えないことが推奨されます。
> 理由は、英語から他の言語への翻訳者を見つける方が、非英語から非英語への翻訳者を見つけるより簡単だからです。
[[yii\base\Application::$sourceLanguage|ソース言語]] のデフォルト値は `en-US` であり、合衆国の英語を意味します。
このデフォルト値は変えないことが推奨されます。
なぜなら、通常は、英語から他の言語への翻訳者を見つける方が、非英語から非英語への翻訳者を見つけるより、はるかに簡単だからです。
アプリケーションの言語を実行時に設定して、ユーザが選択した言語をターゲットにすることが可能です。
この操作は、全ての出力に対して正しく効果を発揮するように、まだ出力が何も生成されていない時点で行われなければなりません。
そのためには、アプリケーションのターゲット言語プロパティを望ましい値に変更するだけです。
[[yii\base\Application::$language|ターゲット言語]] は、エンドユーザの言語選択など、さまざまな要因に基づいて、動的に設定しなければならないことがよくあります。
アプリケーションの構成情報で構成するかわりに、次の文を使ってターゲット言語を変更することが出来ます。
```php
// ターゲット言語を中国語に変更
\Yii::$app->language = 'zh-CN';
```
言語/ロケールの書式は `ll-CC` です。ここで `ll` は [ISO-639](http://www.loc.gov/standards/iso639-2/) に従った二文字または三文字の小文字の言語コードであり、`CC` は [ISO-3166](http://www.iso.org/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html) に従った国コードです。
> **Note**|注意: ロケールの概念と構文に関する詳細な情報については、[ICU プロジェクトのドキュメント](http://userguide.icu-project.org/locale#TOC-The-Locale-Concept) を参照してください。
## メッセージ翻訳 <span id="message-translation"></span>
メッセージ翻訳サービスは、テキストメッセージをある言語 (通常は [[yii\base\Application::$sourceLanguage|ソース言語]]) から別の言語 (通常は [[yii\base\Application::$language|ターゲット言語]]) に翻訳するものです。
翻訳は、元のメッセージと翻訳されたメッセージを格納するメッセージソースの中から、翻訳対象となったメッセージを探すことにより行われます。
メッセージが見つかれば、対応する翻訳されたメッセージが返されます。
メッセージが見つからなければ、元のメッセージが翻訳されずに返されます。
メッセージ翻訳
--------------
メッセージ翻訳サービスを使用するためには、主として次の作業をする必要があります。
メッセージ翻訳は、アプリケーションによって出力されたメッセージを別の言語に翻訳して、さまざまな国のユーザが自国語でアプリケーションを使えるようにするために使用されるものです。
* 翻訳する必要のある全てのテキストメッセージを [[Yii::t()]] メソッドの呼び出しの中に包む。
* メッセージ翻訳サービスが翻訳されたメッセージを探すことが出来る一つまたは複数のメッセージソースを構成する。
* 翻訳者にメッセージを翻訳させて、それをメッセージソースに格納する。
Yii におけるメッセージ翻訳機能は、ソース言語からターゲット言語へとメッセージの翻訳を探すという単純な動作をします。
メッセージ翻訳機能を使うためには、オリジナルのメッセージ文字列を [[Yii::t()]] メソッドで包みます。
このメソッドの最初のパラメータは、メッセージの生成元であるアプリケーションのさまざまな部分を区別するためのカテゴリであり、二番目のパラメータはメッセージそのものです。
[[Yii::t()]] メソッドは次のように使います。
```php
echo \Yii::t('app', 'This is a string to translate!');
```
Yii は `i18n` [アプリケーションコンポーネント](structure-application-components.md) に定義されているメッセージソースの中から、現在の [[yii\base\Application::$language|アプリケーション言語]] に従って、適切な翻訳を読み込もうと試みます。
メッセージソースは、翻訳メッセージを提供する一群のファイルまたはデータベースです。
次の構成情報の例は、メッセージを PHP ファイルから取得するメッセージソースを定義するものです。
ここで、二番目のパラメータが翻訳されるべきテキストメッセージを示し、最初のパラメータはメッセージを分類するのに使用されるカテゴリ名を示します。
[[Yii::t()]] メソッドは `i18n` [アプリケーションコンポーネント](structure-application-components.md) の `translate` メソッドを呼んで実際の翻訳作業を実行します。
このコンポーネントはアプリケーションの構成情報の中で次のようにして構成することが出来ます。
```php
'components' => [
@ -85,188 +92,294 @@ Yii は `i18n` [アプリケーションコンポーネント](structure-applica
],
```
上記において `app*` は、このメッセージソースによって扱われるカテゴリを指定するパターンです。
この例では、`app` から始まる全てのカテゴリをこのメッセージソースで処理します。
メッセージファイルは `@app/messages`、すなわち、アプリケーションディレクトリの下の `messages` ディレクトリに配置されています。
[[yii\i18n\PhpMessageSource::fileMap|fileMap]] 配列が、どのカテゴリに対してどのファイルが使われるべきかを定義しています。
`fileMap` を構成する代りに、カテゴリ名をファイル名として使用する規約に依拠することも出来ます
(例えば、`app/error` というカテゴリは、[[yii\i18n\PhpMessageSource::basePath|basePath]] の下の `app/error.php` というファイル名に帰結します) 。
上記のコードにおいては、[[yii\i18n\PhpMessageSource]] によってサポートされるメッセージソースが構成されています。
`app*` は、`app` で始まる全てのメッセージカテゴリがこのメッセージソースを使って翻訳されるべきであることを示しています。
[[yii\i18n\PhpMessageSource]] クラスは、メッセージ翻訳を格納するのに PHP ファイルを使用します。
デフォルトでは、ファイル名はカテゴリ名と同じでなければなりません。
ただし、[[yii\i18n\PhpMessageSource::fileMap|fileMap]] を構成して、別の命名方法によってカテゴリを PHP ファイルに割り付けることも可能です。
上記の例では、(`ja-JP` がターゲット言語であると仮定すると) `app/error` のカテゴリは `@app/messages/ja-JP/error.php` という PHP ファイルに割り付けられます。
`fileMap` を構成しなければ、このカテゴリは `@app/messages/ja-JP/app/error.php` に割り付けられることになります。
`\Yii::t('app', 'This is a string to translate!')` というメッセージを翻訳するとき、アプリケーション言語が `ja-JP` である場合は、Yii は利用できるメッセージのリストを取得するために、まず `@app/messages/ja-JP/app.php` というファイルを探します。
`ja-JP` ディレクトリにファイルが無い場合は、失敗であるとする前に、`ja` ディレクトリも探します。
翻訳メッセージを格納するのには、PHP ファイル以外に、次のメッセージソースを使うことも可能です。
メッセージを PHP ファイルに保存する [[yii\i18n\PhpMessageSource|PhpMessageSource]] に加えて、Yii は二つのクラスを提供しています。
- [[yii\i18n\GettextMessageSource]] - 翻訳メッセージを保持するのに GNU Gettext の MO ファイルまたは PO ファイルを使用する
- [[yii\i18n\DbMessageSource]] - 翻訳メッセージを保存するのにデータベーステーブルを使用する
- [[yii\i18n\GettextMessageSource]] - GNU Gettext の MO ファイルまたは PO ファイルを使用
- [[yii\i18n\DbMessageSource]] - データベースを使用
## メッセージのフォーマット <span id="message-formatting"></span>
> Note|訳注: 以下においては、メッセージ書式の理解を助けるために、原文にはない日本語への翻訳例 (とその出力結果) をコードサンプルに追加しています。
メッセージを翻訳するときには、プレースホルダを埋め込んで、動的なパラメータ値で実行時に置き換えさせることが出来ます。
更には、パラメータ値をターゲット言語に応じてフォーマットさせるための特別なプレースホルダの構文を使うことも出来ます。
この項では、メッセージをフォーマットする様々な方法を説明します。
### 名前付きプレースホルダ
> Note|訳注: 以下においては、メッセージフォーマットの理解を助けるために、原文にはない日本語への翻訳例 (とその出力結果) をコードサンプルに追加しています。
翻訳メッセージには、翻訳後に対応する値に置き換えられるパラメータを追加することが出来ます。
このパラメータの形式は、次の例で示すように、パラメータ名を波括弧で囲むものです。
### メッセージパラメータ <span id="message-parameters"></span>
翻訳対象となるメッセージには、一つまたは複数のパラメータ (プレースホルダとも呼びます) を埋め込んで、与えられたパラメータ値で置き換えられるようにすることが出来ます。
様々なパラメータ値のセットを与えることによって、翻訳されるメッセージを動的に変化させることが出来ます。
次の例では、`'Hello, {username}!'` というメッセージの中のプレースホルダ `{username}``'Alexander'``'Qiang'` にそれぞれ置き換えられます。
```php
$username = 'Alexander';
// username が "Alexander" になった翻訳メッセージを表示
echo \Yii::t('app', 'Hello, {username}!', [
'username' => $username,
]);
$username = 'Qiang';
// username が "Qiang" になった翻訳メッセージを表示
echo \Yii::t('app', 'Hello, {username}!', [
'username' => $username,
]);
```
プレースホルダを持つメッセージを翻訳する時には、プレースホルダはそのままにしておかなければなりません。
これは、プレースホルダは `Yii::t()` を呼んでメッセージを翻訳する時に、実際の値に置き換えられるものだからです。
// 翻訳: '{username} さん、こんにちは!'
```php
// 日本語翻訳: '{username} さん、こんにちは!'
```
パラメータに値を代入するときには波括弧を使わないことに注意してください。
プレースホルダには、*名前付きプレースホルダ* と *序数プレースホルダ* のどちらかを使用する事が出来ます。
ただし、一つのメッセージに両方を使うことは出来ません。
上記の例は名前付きプレースホルダの使い方を示すものです。
すなわち、各プレースホルダは `{name}` という形式で書かれていますが、それに対して、キーが(波括弧なしの)プレースホルダ名であり、値がそのプレースホルダを置き換える値である連想配列を渡す訳です。
### 序数プレースホルダ
序数プレースホルダは、0 ベースの整数の序数をプレースホルダ名として使います。
このプレースホルダは、`Yii::t()` の呼び出しに出現する順序に従って、パラメータ値によって置き換えられます。
次の例では、序数プレースホルダ `{0}`、`{1}` および `{2}` は、それぞれ、`$price`、`$count` および `$subtotal` の値によって置き換えられます。
```php
$sum = 42;
echo \Yii::t('app', 'Balance: {0}', $sum);
$price = 100;
$count = 2;
$subtotal = 200;
echo \Yii::t('app', 'Price: {0}, Count: {1}, Subtotal: {2}', [$price, $count, $subtotal]);
```
// 翻訳: '差引残高: {0}'
```php
// 日本語翻訳: '価格: {0}, 数量: {1}, 小計: {2}'
```
> **Tip**|ヒント: メッセージ文字列の意味が分らなくならないように、あまりに多くの序数プレースホルダを使うことは避けてください。
> 翻訳者にはソース文字列しか無く、従って、各プレースホルダに何が入るのかが一見して明らかでなければならない、ということを忘れないでください。
序数プレースホルダが一つだけの場合は、値を配列に入れずにそのまま指定することができます。
### 高度なプレースホルダの書式設定
```php
echo \Yii::t('app', 'Price: {0}', $price);
```
> Tip|ヒント: たいていの場合は名前付きプレースホルダを使うべきです。
> と言うのは、翻訳者にとっては、パラメータ名がある方が、翻訳すべきメッセージ全体をより良く理解できるからです。
### パラメータのフォーマット <span id="parameter-formatting"></span>
メッセージのプレースホルダにフォーマットの規則を追加して指定し、パラメータ値がプレースホルダを置き換える前に適切にフォーマットされるようにすることが出来ます。
次の例では、`price` のパラメータ値の型は数値として扱われ、通貨の形式でフォーマットされます。
この高度な機能を使うためには、[intl PHP 拡張](http://www.php.net/manual/ja/intro.intl.php) をインストールして有効にする必要があります。
それをインストールして有効にして初めて、プレースホルダのための拡張構文を使うことが出来るようになります。
すなわち、デフォルトの書式を使用する短い構文 `{プレースホルダ名, タイプ}`、あるいは、書式のスタイルを指定できる完全な構文 `{プレースホルダ名, タイプ, スタイル}` を使うことが出来るようになります。
```php
$price = 100;
echo \Yii::t('app', 'Price: {0, number, currency}', $price);
```
> Note|注意: パラメータのフォーマットには、[intl PHP 拡張](http://www.php.net/manual/ja/intro.intl.php) のインストールが必要です。
完全なリファレンスは [ICU ウェブサイト](http://icu-project.org/apiref/icu4c/classMessageFormat.html) で入手可能ですが、以下においてはいくつかの例を示します。
プレースホルダにフォーマット規則を指定するためには、短い構文または完全な構文のどちらかを使うことが出来ます。
#### 数値
```
短い形式: {name, type}
完全な形式: {name, type, style}
```
> Note|注意: `{`、`}`、`'`、`#` などの特殊な文字を使用する必要がある場合は、その部分の文字列を `'` で囲んでください。
>
```php
$sum = 42;
echo Yii::t('app', "Example of string with ''-escaped characters'': '{' '}' '{test}' {count, plural, other{''count'' value is # '#{}'}}", ['count' => 3]);
+```
このようなプレースホルダを指定する方法についての完全な説明は、[ICU ドキュメント](http://icu-project.org/apiref/icu4c/classMessageFormat.html) を参照してください。
以下では、よくある使用方法をいくつか示します。
#### 数値 <span id="number"></span>
```php
$sum = 12345;
echo \Yii::t('app', 'Balance: {0, number}', $sum);
// 翻訳: '差引残高: {0, number}'
// 出力: '差引残高: 12,345'
// 日本語翻訳: '差引残高: {0, number}'
// 日本語出力: '差引残高: 12,345'
```
内蔵のスタイル (`integer`、`currency`、`percent`) の一つを指定することが出来ます。
オプションのパラメータとして、`integer`、`currency`、`percent` のスタイルを指定することが出来ます。
```php
$sum = 42;
$sum = 12345;
echo \Yii::t('app', 'Balance: {0, number, currency}', $sum);
// 翻訳: '差引残高: {0, number, currency}'
// 出力: '差引残高: &yen; 12,345'
// 日本語翻訳: '差引残高: {0, number, currency}'
// 日本語出力: '差引残高: ¥12,345'
```
または、カスタムパターンを指定することも出来ます。
または、数値をフォーマットするカスタムパターンを指定することも出来ます。
```php
$sum = 42;
$sum = 12345;
echo \Yii::t('app', 'Balance: {0, number, ,000,000000}', $sum);
// 翻訳: '差引残高: {0, number, ,000,000000}'
// 出力: '差引残高: 000,012345'
// 日本語翻訳: '差引残高: {0, number, ,000,000000}'
// 日本語出力: '差引残高: 000,012345'
```
[書式のリファレンス](http://icu-project.org/apiref/icu4c/classicu_1_1DecimalFormat.html).
カスタムフォーマットで使用される文字については、[ICU API リファレンス](http://icu-project.org/apiref/icu4c/classicu_1_1DecimalFormat.html) の "Special Pattern Characters" のセクションに記述されています。
数値は常に翻訳先のロケールに従ってフォーマットされます。
つまり、ロケールを変更せずに、小数点や桁区切りを変更することは出来ません。
それらをカスタマイズしたい場合は [[yii\i18n\Formatter::asDecimal()]] や [[yii\i18n\Formatter::asCurrency()]] を使うことが出来ます。
#### 日付
#### 日付 <span id="date"></span>
パラメータ値は日付としてフォーマットされます。例えば、
```php
echo \Yii::t('app', 'Today is {0, date}', time());
// 翻訳: '今日は {0, date} です。'
// 出力: '今日は 2015/01/07 です。'
// 日本語翻訳: '今日は {0, date} です。'
// 日本語出力: '今日は 2015/01/07 です。'
```
内蔵の書式は、`short`、`medium`、`long`、そして `full`す。
オプションのパラメータとして、`short`、`medium`、`long`、そして `full` のスタイルを指定することが出来ます。
```php
echo \Yii::t('app', 'Today is {0, date, short}', time());
// 翻訳: '今日は {0, date, short} です。'
// 出力: '今日は 2015/01/07 です。'
// 日本語翻訳: '今日は {0, date, short} です。'
// 日本語出力: '今日は 2015/01/07 です。'
```
カスタムパターンを指定することも出来ます。
日付の値をフォーマットするカスタムパターンを指定することも出来ます。
```php
echo \Yii::t('app', 'Today is {0, date, yyyy-MM-dd}', time());
// 翻訳: '今日は {0, date, yyyy-MM-dd} です。'
// 出力: '今日は 2015-01-07 です。'
// 日本語翻訳: '今日は {0, date, yyyy-MM-dd} です。'
// 日本語出力: '今日は 2015-01-07 です。'
```
[書式のリファレンス](http://icu-project.org/apiref/icu4c/classicu_1_1SimpleDateFormat.html).
#### 時刻
#### 時刻 <span id="time"></span>
パラメータ値は時刻としてフォーマットされます。例えば、
```php
echo \Yii::t('app', 'It is {0, time}', time());
// 翻訳: '現在 {0, time} です。'
// 出力: '現在 22:37:47 です。'
// 日本語翻訳: '現在 {0, time} です。'
// 日本語出力: '現在 22:37:47 です。'
```
内蔵の書式は、`short`、`medium`、`long`、そして `full`す。
オプションのパラメータとして、`short`、`medium`、`long`、そして `full` のスタイルを指定することが出来ます。
```php
echo \Yii::t('app', 'It is {0, time, short}', time());
// 翻訳: '現在 {0, time, short} です。'
// 出力: '現在 22:37 です。'
// 日本語翻訳: '現在 {0, time, short} です。'
// 日本語出力: '現在 22:37 です。'
```
カスタムパターンを指定することも出来ます。
時刻の値をフォーマットするカスタムパターンを指定することも出来ます。
```php
echo \Yii::t('app', 'It is {0, date, HH:mm}', time());
// 翻訳: '現在 {0, time, HH:mm} です。'
// 出力: '現在 22:37 です。'
// 日本語翻訳: '現在 {0, time, HH:mm} です。'
// 日本語出力: '現在 22:37 です。'
```
[書式のリファレンス](http://icu-project.org/apiref/icu4c/classicu_1_1SimpleDateFormat.html).
#### 綴り
#### 綴り <span id="spellout"></span>
パラメータ値は数値として取り扱われ、綴りとしてフォーマットされます。例えば、
```php
echo \Yii::t('app', '{n, number} is spelled as {n, spellout}', ['n' => 12345]);
// 出力例 : "42 is spelled as forty-two"
echo \Yii::t('app', '{n, number} is spelled as {n, spellout}', ['n' => 42]);
// 翻訳: '{n, number} は、文字で綴ると {n, spellout} です。'
// 出力: '12,345 は、文字で綴ると 一万二千三百四十五 です。'
// 日本語翻訳: '{n, number} は、文字で綴ると {n, spellout} です。'
// 日本語出力: '42 は、文字で綴ると 四十二 です。'
```
#### 序数
デフォルトでは、数値は基数として綴られます。それを変更することは可能です。
```php
// 出力例 : "I am forty-seventh agent"
echo \Yii::t('app', 'I am {n, spellout,%spellout-ordinal} agent', ['n' => 47]);
// 日本語翻訳: '私は{n, spellout,%spellout-ordinal}の工作員です。'
// 日本語出力: '私は第四十七の工作員です。'
```
'spellout,' と '%' の間に空白を入れてはならないことに注意してください。
あなたが使用しているロケールで利用可能なオプションのリストについては、[http://intl.rmcreative.ru/](http://intl.rmcreative.ru/) の "Numbering schemas, Spellout" を参照してください。
#### 序数 <span id="ordinal"></span>
パラメータ値は数値として取り扱われ、順序を表す文字列としてフォーマットされます。例えば、
```php
// 出力: "You are the 42nd visitor here!"
echo \Yii::t('app', 'You are the {n, ordinal} visitor here!', ['n' => 42]);
```
これは、"You are the 42nd visitor here!" というメッセージになります。
序数については、スペイン語などの言語では、さらに多くのフォーマットがサポートされています。
> Note|訳注: 上記のソースメッセージを、プレースホルダの書式指定を守って日本語に翻訳すると、'あなたはこのサイトの {n, ordinal} の訪問者です' となります。
> しかし、その出力結果は、'あなたはこのサイトの 第42 の訪問者です' となり、意味は通じますが、日本語としては若干不自然なものになります。
```php
// 出力: "471ª"
echo \Yii::t('app', '{n, ordinal,%digits-ordinal-feminine}', ['n' => 471]);
```
'ordinal,' と '%' の間に空白を入れてはならないことに注意してください。
あなたが使用しているロケールで利用可能なオプションのリストについては、[http://intl.rmcreative.ru/](http://intl.rmcreative.ru/) の "Numbering schemas, Ordinal" を参照してください。
> Note|訳注: 上記のソースメッセージを、プレースホルダのスタイルを守って日本語に翻訳すると、'あなたはこのサイトの{n, ordinal}の訪問者です' となります。
> しかし、その出力結果は、'あなたはこのサイトの第42の訪問者です' となり、意味は通じますが、日本語としては若干不自然なものになります。
>
> プレースホルダの書式指定自体も、翻訳の対象として、より適切なものに変更することが可能です。
> プレースホルダのスタイル自体も、翻訳の対象として、より適切なものに変更することが可能であることに注意してください
>
> この場合も、'あなたはこのサイトの{n, plural, =1{最初} other{#番目}}の訪問者です' のように翻訳することが出来ます。
> この場合も、'あなたはこのサイトの{n, plural, =1{最初} other{#番目}}の訪問者です' のように翻訳するほうが適切でしょう
#### 継続時間
#### 継続時間 <span id="duration"></span>
パラメータ値は秒数として取り扱われ、継続時間を表す文字列としてフォーマットされます。例えば、
```php
// 出力: "You are here for 47 sec. already!"
echo \Yii::t('app', 'You are here for {n, duration} already!', ['n' => 47]);
```
これは、"You are here for 47 sec. already!" というメッセージになります。
継続時間については、さらに多くのフォーマットがサポートされています。
```php
// 出力: '130:53:47'
echo \Yii::t('app', '{n, duration,%in-numerals}', ['n' => 471227]);
```
'duration,' と '%' の間に空白を入れてはならないことに注意してください。
あなたが使用しているロケールで利用可能なオプションのリストについては、[http://intl.rmcreative.ru/](http://intl.rmcreative.ru/) の "Numbering schemas, Duration" を参照してください。
> Note|訳注: このソースメッセージを 'あなたはこのサイトに既に {n, duration} の間滞在しています' と翻訳した場合の出力結果は、'あなたはこのサイトに既に 47 の間滞在しています' となります。
> ICU ライブラリのバグでしょうか。これも、プレースホルダの書式設定も含めて全体を翻訳し直す方が良いようです。
> Note|訳注: このソースメッセージを 'あなたはこのサイトに既に{n, duration}の間滞在しています' と翻訳した場合の出力結果は、'あなたはこのサイトに既に47の間滞在しています' となります。
> これも、プレースホルダのスタイルも含めて全体を翻訳し直す方が良いでしょう。
> どうも、ICU ライブラリは、ja_JP の数値関連の書式指定においては、割と貧弱な実装にとどまっている印象です。
#### 複数形
#### 複数形 <span id="plural"></span>
言語によって、複数形の語形変化はさまざまに異なります。
Yii は、さまざまな形式の複数形語形変化に対応したメッセージ翻訳のための便利な方法を提供しています。
@ -274,32 +387,50 @@ Yii は、さまざまな形式の複数形語形変化に対応したメッセ
語形変化の規則を直接に処理する代りに、特定の状況における語形変化した言葉の翻訳を提供するだけで十分です。
```php
// $n = 0 の場合の出力: "There are no cats!"
// $n = 1 の場合の出力: "There is one cat!"
// $n = 42 の場合の出: "There are 42 cats!"
echo \Yii::t('app', 'There {n, plural, =0{are no cats} =1{is one cat} other{are # cats}}!', ['n' => $n]);
```
結果は以下のようになります。
上記の複数形規則の引数において、`=` はぴったりその値であることを意味します。
従って、`=0` はぴったりゼロ、`=1` はぴったり 1 を表します。
`other` はそれ以外の数を表します。
`#` は ターゲット言語に従ってフォーマットされた `n` の値によって置き換えられます。
- `$n = 0` の場合は "There are no cats!"
- `$n = 1` の場合は "There is one cat!"
- そして `$n = 42` の場合は "There are 42 cats!"
上記の複数形規則の引数において、`=0` はぴったりゼロ、`=1` はぴったり 1、そして `other` はそれ以外の数を表します。
`#``n` の値によって置き換えられます。
英語以外の言語では、これほど単純ではありません。
例えば、次はロシア語の例です。
複数形の規則が非常に複雑な言語もあります。
例えば、次のロシア語の例では、`=1` が `n = 1` にぴったりと一致するのに対して、`one` が `21``101` などに一致します。
```
Здесь {n, plural, =0{котов нет} =1{есть один кот} one{# кот} few{# кота} many{# котов} other{# кота}}!
```
上の例について言及する価値があると思われるのは、`=1` が `n = 1` にぴったりと一致するのに対して、`one` が `21``101` などに一致する、ということです。
これら `other`、`few`、`many` などの特別な引数の名前は言語によって異なります。
特定のロケールに対してどんな引数を指定すべきかを学ぶためには、[http://intl.rmcreative.ru/](http://intl.rmcreative.ru/) の "Plural Rules, Cardinal" を参照してください。
あるいは、その代りに、[unicode.org の規則のリファレンス](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html) を参照することも出来ます。
注意して欲しいのは、あなたの [[yii\base\Application::$sourceLanguage|ソース言語]] を `ru_RU` に設定しなければ、このロシア語のメッセージを `Yii::t()` の中に直接に書くことは出来ない、ということです。
ただし、ソース言語を `ru_RU` に設定することは推奨されません。
むしろ、このような文字列はメッセージファイルまたは (DB ソースが使われている場合は) メッセージデータベースに入れるべきです。
Yii は翻訳された言語の文字列にある複数形規則を使います。翻訳が入手できない場合にはソース言語の複数形規則にフォールバックします。
> Note|注意: 上記のロシア語のメッセージのサンプルは、主として翻訳メッセージとして使用されるものです。
> アプリケーションの [[yii\base\Application::$sourceLanguage|ソース言語]] を `ru-RU` にしてロシア語から他の言語に翻訳するという設定にしない限り、オリジナルのメッセージとしては使用されることはありません。
>
> `Yii::t()` の呼び出しにおいて、オリジナルのメッセージに対する翻訳が見つからない場合は、[[yii\base\Application::$sourceLanguage|ソース言語]] の複数形規則がオリジナルのメッセージに対して適用されます。
文字列が以下のようなものである場合のために `offset` というパラメータがあります。
```php
$likeCount = 2;
echo Yii::t('app', 'You {likeCount, plural,
offset: 1
=0{did not like this}
=1{liked this}
one{and one other person liked this}
other{and # others liked this}
}', [
'likeCount' => $likeCount
]);
あなたの言語について、どのような語形変化を指定すべきかを学習するためには、[unicode.org にある規則のリファレンス](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html) を参照してください。
// 出力: 'You and one other person liked this'
```
> Note|訳注: 上記のソースメッセージの日本語翻訳は以下のようなものになります。
>
@ -308,28 +439,49 @@ Yii は翻訳された言語の文字列にある複数形規則を使います
> 日本語では単数形と複数形を区別しませんので、たいていの場合、`=0` と `other` を指定するだけで事足ります。
> 横着をして、`{n, plural, ...}` を `{n, number}` に置き換えても、多分、大きな問題は生じないでしょう。
#### 選択肢
キーワードに基づいて表現を選択することが出来ます。
この場合のパターンは、キーワードに対する表現の割り当てを指定し、デフォルトの表現を提供するものです。
#### 序数選択肢 <span id="ordinal-selection">
パラメータのタイプとして `selectordinal` を使うと、翻訳先ロケールの言語規則に基づいて序数のための文字列を選択することが出来ます。
```php
$n = 3;
echo Yii::t('app', 'You are {n, selectordinal, one{#st} two{#nd} few{#rd} other{#th}} visitor', ['n' => $n]);
// 英語の出力
// You are 3rd visitor
// ロシア語の翻訳
'You are {n, selectordinal, one{#st} two{#nd} few{#rd} other{#th}} visitor' => 'Вы {n, selectordinal, other{#-й}} посетитель',
// ロシア語の出力
// Вы 3-й посетитель
```
フォーマットは複数形で使われるものと非常に近いものです。
特定のロケールに対してどんな引数を指定すべきかを学ぶためには、[http://intl.rmcreative.ru/](http://intl.rmcreative.ru/) の "Plural Rules, Ordinal" を参照してください。
あるいは、その代りに、[unicode.org の規則のリファレンス](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html) を参照することも出来ます。
#### 選択肢 <span id="selection"></span>
パラメータのタイプとして `select` を使うと、パラメータの値に基づいて表現を選択することが出来ます。例えば、
```php
// 出力: "Snoopy is a dog and it loves Yii!"
echo \Yii::t('app', '{name} is a {gender} and {gender, select, female{she} male{he} other{it}} loves Yii!', [
'name' => 'Snoopy',
'gender' => 'dog',
]);
```
これは "Snoopy is a dog and it loves Yii!" となります。
上記の式の中で、`female` と `male``gender` が取り得る値であり、`other` がそれらに一致しない値を処理します。
それぞれの取り得る値の後には、波括弧で囲んで対応する表現を指定します。
式の中で、`female` と `male``gender` が取り得る値であり、`other` がそれらに一致しない値を処理します。
波括弧の中の文字列は下位の式であり、単なる文字列でも、さらにプレースホルダを持つ文字列でも構いません。
> Note|訳注: 翻訳: '{name} は {gender} であり、{gender, select, female{彼女} male{彼} other{それ}}は Yii を愛しています。'
> Note|訳注: 日本語翻訳: '{name} は {gender} であり、{gender, select, female{彼女} male{彼} other{それ}}は Yii を愛しています。'
>
> 出力: 'Snoopy は dog であり、それは Yii を愛しています。'
> 日本語出力: 'Snoopy は dog であり、それは Yii を愛しています。'
### デフォルトの翻訳を指定する
### デフォルトの翻訳を指定する <span id="default-translation"></span>
他の翻訳にマッチしないカテゴリのフォールバックとして使用されるデフォルトの翻訳を指定することが出来ます。
この翻訳は `*` によってマークされなければなりません。
@ -356,7 +508,7 @@ echo Yii::t('not_specified_category', 'message from unspecified category');
この場合、メッセージは `@app/messages/<LanguageCode>/not_specified_category.php` から読み込まれます。
### モジュールのメッセージを翻訳する
### モジュールのメッセージを翻訳する <span id="module-translation"></span>
モジュール用のメッセージを翻訳したいけれども、全てのメッセージに対して一つの翻訳ファイルを使うことは避けたい、という場合には、次のようにすることが出来ます。
@ -403,7 +555,7 @@ class Module extends \yii\base\Module
`fileMap` を使わずに、カテゴリを同じ名前のファイルにマップする規約を使って済ませることも出来ます。
以上のようにすれば、直接に `Module::t('validation', 'your custom validation message')``Module::t('form', 'some form label')` などを使用することが出来ます。
### ウィジェットのメッセージを翻訳する
### ウィジェットのメッセージを翻訳する <span id="widget-translation"></span>
モジュールに適用できる同じ規則をウィジェットにも適用することが出来ます。例えば、
@ -456,7 +608,7 @@ class Menu extends Widget
> **Note**|注意: ウィジェットのためには i18n ビューも使うことが出来ます。コントローラのための同じ規則がウィジェットにも適用されます。
### フレームワークメッセージを翻訳する
### フレームワークメッセージを翻訳する <span id="framework-translation"></span>
Yii には、検証エラーとその他いくつかの文字列に対するデフォルトの翻訳メッセージが付属しています。
これらのメッセージは、全て 'yii' というカテゴリの中にあります。
@ -477,7 +629,7 @@ Yii には、検証エラーとその他いくつかの文字列に対するデ
これで、あなたの修正した翻訳を `@app/messages/<language>/yii.php` に置くことが出来ます。
### 欠落している翻訳の処理
### 欠落している翻訳の処理 <span id="missing-translations"></span>
ソースに翻訳が欠落している場合でも、Yii はリクエストされたメッセージの内容を表示します。
この振舞いは、原文のメッセージが正当かつ詳細なテキストである場合には、非常に好都合です。
@ -560,34 +712,31 @@ class TranslationEventHandler
これで、(あなたがファイルベースの翻訳を選択していた場合は) `messagePath` ディレクトリにファイルが出現します。
ビュー
------
## ビューの翻訳 <span id="view-translation"></span>
前の項で説明したようなメッセージの翻訳の代りに、ビューで `i18n` を使ってさまざまな言語に対するサポートを提供することも出来ます。
例えば、`views/site/index.php` というビューがあり、それのロシア語のための特別版を作りたい場合は、現在のコントローラ/ウィジェットのビューパスの下に `ru-RU` フォルダを作って、ロシア語のためのファイルを `views/site/ru-RU/index.php` として置きます。
そうすると、Yii は、現在の言語のためのファイルが存在する場合はそれをロードし、何も見つからなかった場合はオリジナルのビューファイルにフォールバックします。
個々のテキストメッセージを翻訳する代りに、ビュースクリプト全体を翻訳したい場合があるでしょう。
この目的を達するためには、ビューを翻訳して、ターゲット言語と同じ名前のサブディレクトリに保存するだけで大丈夫です。
例えば、`views/site/index.php` というビューをターゲット言語 `ru-RU` に翻訳したい場合は、翻訳したビューを `views/site/ru-RU/index.php` というファイルとして保存します。
このようにすると、[[yii\base\View::renderFile()]] メソッド、または、このメソッドを呼び出す他のメソッド (例えば [[yii\base\Controller::render()]]) を呼んで `views/site/index.php` をレンダリングするたびに、翻訳された `views/site/ru-RU/index.php` が代りにレンダリングされるようになります。
> **Note**|注意: 言語が `en-US` と指定されている場合、対応するビューが無いと、Yii は `en` の下でビューを探して、そこにも無ければ、オリジナルのビューを使います。
> **Note**|注意: [[yii\base\Application::$language|ターゲット言語]] が [[yii\base\Application::$sourceLanguage|ソース言語]] と同じ場合は、翻訳されたビューの有無にかかわらず、オリジナルのビューがレンダリングされます。
数値と日付の値を書式設定する
----------------------------
## 数値と日付の値を書式設定する <span id="date-number"></span>
詳細は [データフォーマッタ](output-formatting.md) の節を参照してください。
PHP 環境をセットアップする <span id="setup-environment"></span>
--------------------------
## PHP 環境をセットアップする <span id="setup-environment"></span>
Yii は、[[yii\i18n\Formatter]] クラスの数値や日付の書式設定や、[[yii\i18n\MessageFormatter]] を使うメッセージのフォーマッティングなど、ほとんどの国際化機能を提供するために [PHP intl 拡張](http://php.net/manual/ja/book.intl.php) を使います。
この二つのクラスは、`intl` がインストールされていない場合に備えて基本的な機能を提供するフォールバックを実装しています。
だだし、このフォールバックの実装は、英語のサイトでのみ十分に機能するものであり、たとえ英語のサイトであっても、PHP intl 拡張によって利用可能になる一連の豊かな機能を提供できるものではありません
従って、PHP intl 拡張のインストールが強く推奨されます。
だだし、このフォールバックの実装は、英語がターゲット言語である場合にのみ十分に機能するものす
従って、国際化機能が必要とされる場合は、`intl` をインストールすることが強く推奨されます。
[PHP intl 拡張](http://php.net/manual/ja/book.intl.php) は、さまざまに異なる全てのロケールについて知識と書式の規則を提供する [ICU ライブラリ](http://site.icu-project.org/) に基礎を置いています。
この事実により、日付や数値の書式設定、また、メッセージのフォーマッティングで利用できる構文は、PHP バイナリとともにコンパイルされる ICU ライブラリのバージョンの違いによって異なってきます。
あなたのウェブサイトが全ての環境で同じ出力をすることを保証するためには、全ての環境において PHP intl 拡張をインストールし、PHP とともにコンパイルされた ICU ライブラリのバージョンが同一であることを確認することが推奨されます。
ICU のバージョンが異なると、日付や数値のフォーマットの結果も異なる場合があります。
あなたのウェブサイトが全ての環境で同じ出力をすることを保証するためには、全ての環境において同じバージョンの PHP intl 拡張 (従って同じバージョンの ICU) をインストールすることが推奨されます。
どのバージョンの ICU が PHP によって使われているかを知るために、次のスクリプトを走らせることが出来ます。
このスクリプトは、使用されている PHP と ICU のバージョンを出力します。
@ -598,11 +747,12 @@ echo "PHP: " . PHP_VERSION . "\n";
echo "ICU: " . INTL_ICU_VERSION . "\n";
```
このドキュメントで説明されている全ての機能を使うことが出来るように、ICU のバージョンが 49 以上であることを推奨します。
49 未満のバージョンに欠落している主要な機能の一つが、複数形規則における `#` プレースホルダです。
さらに、バージョン 49 以上の ICU を使用する事も推奨されます。
そうすることによって、このドキュメントで説明されている全ての機能を使うことが出来るようになります。
例えば、49 未満の ICU は、複数形規則における `#` プレースホルダをサポートしていません。
入手できる ICU バージョン については、<http://site.icu-project.org/download> を参照してください。
バージョン番号の採番方式が 4.8 リリースの後に変更されて、最初の二つの数字が結合されたことに注意してください
すなわち、ICU 4.8、ICU 49、ICU 50 という順序です
バージョン番号の採番方式が 4.8 リリースの後に変更されたことに注意してください
(すなわち、ICU 4.8、ICU 49、ICU 50、等々となっています)
これに加えて、ICU ライブラリとともに出荷されるタイムゾーンデータベースの情報も古くなっている可能性があります。
タイムゾーンデータベースの更新に関する詳細は [ICU マニュアル](http://userguide.icu-project.org/datetime/timezone#TOC-Updating-the-Time-Zone-Data) を参照してください。

4
docs/guide-ja/tutorial-performance-tuning.md

@ -82,7 +82,9 @@ HTTP リクエストの回数、および、これらのアセットの全体と
## セッションのストレージを最適化する <span id="optimizing-session"></span>
デフォルトでは、セッションのデータはファイルに保存されます。
開発と小さなプロジェクトではそれでも構いません。
これは、`session_write_close()` が呼ばれる (Yii では `Yii::$app->session->close()` によって呼び出されます) か、あるいはリクエストの処理が終了して、セッションが閉じられる時点まで、ファイルが開かれるのをロックするという実装になっています。
セッションファイルがロックされている間は、同じセッションを使用しようとする全てのリクエストはブロックされ、最初のリクエストがセッションファイルを解放するのを待たなければなりません。
開発時はこれでも構いません。おそらく、小さなプロジェクトでも、これで大丈夫でしょう。
しかし、大量のリクエストを並列処理するとなると、データベースのような、もっと洗練されたストレージを使う方が良いでしょう。
Yii はさまざまなセッションストレージのサポートを内蔵しています。
これらのストレージは、[アプリケーションの構成情報](concept-configurations.md) の中で `session` コンポーネントを次のように構成することによって使用することが出来ます。

2
docs/guide-ja/tutorial-start-from-scratch.md

@ -54,6 +54,6 @@ Yii の新しいプロジェクトテンプレートを作成するのに必要
これで、あなたのテンプレートを使ってプロジェクトを作成することが出来ます。
```
composer global require "fxp/composer-asset-plugin:~1.0.0"
composer global require "fxp/composer-asset-plugin:~1.0.3"
composer create-project --prefer-dist --stability=dev mysoft/yii2-app-coolone new-project
```

2
docs/guide-ja/tutorial-yii-integration.md

@ -77,7 +77,7 @@ Yii は数多くの優れた機能を提供していますので、サードパ
サードパーティのシステムが Composer を使って依存を管理している場合は、単に下記のコマンドを実行すれば Yii をインストールすることが出来ます。
composer global require "fxp/composer-asset-plugin:~1.0.0"
composer global require "fxp/composer-asset-plugin:~1.0.3"
composer require yiisoft/yii2
composer install

2
docs/guide-pl/start-installation.md

@ -32,7 +32,7 @@ Jeśli posiadałeś już wcześniej zainstalowanego Composer'a, upewnij się, ż
Z zainstalowanym Composer'em możesz przejść do instalacji Yii wywołując poniższe komendy w katalogu dostępnym w sieci web:
composer global require "fxp/composer-asset-plugin:~1.0.0"
composer global require "fxp/composer-asset-plugin:~1.0.3"
composer create-project --prefer-dist yiisoft/yii2-app-basic basic
Pierwsza komenda instaluje [wtyczkę zasobów](https://github.com/francoispluchino/composer-asset-plugin/), która pozwala na zarządzanie zasobami [Bower'a](http://bower.io) oraz [paczkami zależności NPM](https://www.npmjs.com/) przez Composer.

2
docs/guide-pt-BR/start-installation.md

@ -46,7 +46,7 @@ Você pode atualizar o Composer executando o comando `composer self-update`.
Com o Composer instalado, você pode instalar o Yii executando o seguinte comando
em um diretório acessível pela Web:
composer global require "fxp/composer-asset-plugin:~1.0.0"
composer global require "fxp/composer-asset-plugin:~1.0.3"
composer create-project --prefer-dist yiisoft/yii2-app-basic basic
O primeiro comando instaka o [composer asset plugin](https://github.com/francoispluchino/composer-asset-plugin/)

2
docs/guide-pt-BR/tutorial-yii-integration.md

@ -66,7 +66,7 @@ Como o Yii fornece muitas características excelentes, algumas vezes você pode
Se o sistema em questão utilizar o Composer para gerenciar suas dependências, você pode simplesmente executar o seguinte comando para instalar o Yii:
composer global require "fxp/composer-asset-plugin:~1.0.0"
composer global require "fxp/composer-asset-plugin:~1.0.3"
composer require yiisoft/yii2
composer install

4
docs/guide-ru/security-authentication.md

@ -126,9 +126,9 @@ class User extends ActiveRecord implements IdentityInterface
{
......
public function beforeSend($insert)
public function beforeSave($insert)
{
if (parent::beforeSend($insert)) {
if (parent::beforeSave($insert)) {
if ($this->isNewRecord) {
$this->auth_key = \Yii::$app->security->generateRandomString();
}

2
docs/guide-ru/start-installation.md

@ -29,7 +29,7 @@
После установки Composer устанавливать Yii можно запустив следующую команду в папке доступной через веб:
composer global require "fxp/composer-asset-plugin:~1.0.0"
composer global require "fxp/composer-asset-plugin:~1.0.3"
composer create-project --prefer-dist yiisoft/yii2-app-basic basic
Первая команда устанавливает [composer asset plugin](https://github.com/francoispluchino/composer-asset-plugin/),

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

@ -2,7 +2,7 @@
============
Тестирование является важной составляющей разработки программного обеспечения. Мы проводим тестирование непрерывно, осознаем мы это или нет.
Например, когда мы пишем класс на языке PHP, мы может отлаживать его шаг за шагом или просто использовать `echo` или `die` для проверки, что
Например, когда мы пишем класс на языке PHP, мы можем отлаживать его шаг за шагом или просто использовать `echo` или `die` для проверки, что
реализация работает в соответствии с намеченным планом. В случае веб приложения, мы вводим некоторые тестовые данные в форму для того, чтобы
убедиться, что страница взаимодействует с нами, как ожидается.
@ -32,7 +32,7 @@
> **Подсказка** Если вы чувствуете, что вы теряете время выполняя много мелких и простых итераций, попробуйте покрыть это
> вашим тестовым сценарием перед следующим выполнением тестов. Если вы слишком много отлаживаете, попробуйте сделать обратное.
Написание тестов до реализации конкретного функционала позволяет нам нам сосредоточиться на том, что мы хотим достичь и полностью
Написание тестов до реализации конкретного функционала позволяет нам сосредоточиться на том, что мы хотим достичь и полностью
погрузиться в "как это сделать" впоследствии.
Обычно это приводит к лучшим абстракциям и более легкой поддержке тестов, когда речь идет о корректировки фичи или уменьшении связанности компонентов.

2
docs/guide-ru/tutorial-start-from-scratch.md

@ -46,6 +46,6 @@ git clone git@github.com:yiisoft/yii2-app-basic.git
Это все, что требуется для создания нового шаблона проекта в Yii. Сейчас вы можете создавать проекты, использующие ваш шаблон:
```
composer global require "fxp/composer-asset-plugin:~1.0.0"
composer global require "fxp/composer-asset-plugin:~1.0.3"
composer create-project --prefer-dist --stability=dev mysoft/yii2-app-coolone new-project
```

2
docs/guide-ru/tutorial-yii-integration.md

@ -63,7 +63,7 @@ Yii::$classMap['Class2'] = 'path/to/Class2.php';
Если сторонняя система использует для управления зависимостями Composer, Yii можно просто установить с помощью следующих команд:
composer global require "fxp/composer-asset-plugin:~1.0.0"
composer global require "fxp/composer-asset-plugin:~1.0.3"
composer require "yiisoft/yii2:*"
composer install

6
docs/guide-uk/README.md

@ -23,7 +23,7 @@ All Rights Reserved.
* [Говоримо "Привіт"](start-hello.md)
* [Робота з формами](start-forms.md)
* [Робота з базами даних](start-databases.md)
* [Генерація коду за допомогою Gii](start-gii.md)
* [Генерування коду за допомогою Gii](start-gii.md)
* [Наступні кроки](start-looking-ahead.md)
@ -144,8 +144,8 @@ All Rights Reserved.
----------------------
* [Панель налагодження та налагоджувач](https://github.com/yiisoft/yii2-debug/blob/master/docs/guide-uk/README.md)
* [Генерація коду за допомогою Gii](https://github.com/yiisoft/yii2-gii/blob/master/docs/guide-uk/README.md)
* **TBD** [Генерація документації API](https://github.com/yiisoft/yii2-apidoc)
* [Генерування коду за допомогою Gii](https://github.com/yiisoft/yii2-gii/blob/master/docs/guide-uk/README.md)
* **TBD** [Генерування документації API](https://github.com/yiisoft/yii2-apidoc)
Тестування

6
docs/guide-uk/caching-fragment.md

@ -16,10 +16,10 @@ if ($this->beginCache($id)) {
}
```
Таким чином, розташуйте логіку генерації вмісту у комбінацію викликів [[yii\base\View::beginCache()|beginCache()]] та
Таким чином, розташуйте логіку генерування вмісту у комбінацію викликів [[yii\base\View::beginCache()|beginCache()]] та
[[yii\base\View::endCache()|endCache()]]. Якщо вміст буде знайдено у кеші, [[yii\base\View::beginCache()|beginCache()]]
відобразить закешований вміст і поверне false, оминаючи генерацію вмісту.
В іншому випадку, буде виконано логіку генерації вмісту і з викликом [[yii\base\View::endCache()|endCache()]]
відобразить закешований вміст і поверне false, оминаючи генерування вмісту.
В іншому випадку, буде виконано логіку генерування вмісту і з викликом [[yii\base\View::endCache()|endCache()]]
згенерований вміст буде записаний до кешу.
Подібно до [кешування даних](caching-data.md), для кешування фрагментів необхідний унікальний ідентифікатор

2
docs/guide-uk/intro-upgrade-from-v1.md

@ -287,7 +287,7 @@ ActiveForm::end();
контролера, у той час, як іменовані аргументи будуть передані у відповідності із оголошеннями у
[[yii\console\Controller::options()]].
Yii 2.0 підтримує автоматичну генерацію довідкової інформації із блоків коментарів.
Yii 2.0 підтримує автоматичне генерування довідкової інформації із блоків коментарів.
Більш детальна інформація представлена у розділі [Консольні команди](tutorial-console.md).

4
docs/guide-uk/start-databases.md

@ -83,7 +83,7 @@ return [
Створення Active Record <span id="creating-active-record"></span>
-----------------------
Для презентування та отримання даних з таблиці `country` створіть похідний від [Active Record](db-active-record.md)
Для репрезентації та отримання даних з таблиці `country` створіть похідний від [Active Record](db-active-record.md)
клас з іменем `Country`, і збережіть його в файл `models/Country.php`.
```php
@ -251,7 +251,7 @@ http://hostname/index.php?r=country/index&page=2
В цьому розділі ви дізналися, як працювати з базою даних. Ви також дізналися, як вибирати і відображати дані на сторінках
за допомогою [[yii\data\Pagination]] і [[yii\widgets\LinkPager]].
У наступному розділі ви дізнаєтеся, як використовувати потужний інструмент генерації коду, що називається [Gii](https://github.com/yiisoft/yii2-gii/blob/master/docs/guide-uk/README.md),
У наступному розділі ви дізнаєтеся, як використовувати потужний інструмент генерування коду, що називається [Gii](https://github.com/yiisoft/yii2-gii/blob/master/docs/guide-uk/README.md),
який допоможе вам швидко створювати деякі часто необхідні функції, такі як Create-Read-Update-Delete (CRUD)
операції для роботи з даними в таблицях баз даних. Насправді, код, який ви щойно написали,
в Yii можливо автоматично згенерувати за допомогою інструменту Gii.

4
docs/guide-uk/start-forms.md

@ -177,7 +177,7 @@ use yii\widgets\ActiveForm;
[[yii\widgets\ActiveForm|ActiveForm]]. Методи `begin()` і `end()` виводять відкриваючий і закриваючий теги форми
відповідно. Між цими викликами створюються поля для заповнення за допомогою метода
[[yii\widgets\ActiveForm::field()|field()]]. Першим іде поле "name",
другим — "email". Далі для генерації кнопки відправлення даних викликається метод
другим — "email". Далі для генерування кнопки відправлення даних викликається метод
[[yii\helpers\Html::submitButton()]].
@ -235,7 +235,7 @@ http://hostname/index.php?r=site/entry
--------
В даному розділі ви випробували кожну частину шаблона проектування MVC. Ви дізналися, як
створити клас моделі для презентування даних, вказаних користувачем, і як перевіряти ці дані.
створити клас моделі для репрезентації даних, вказаних користувачем, і як перевіряти ці дані.
Також ви дізналися, як отримувати дані від користувачів та як повертати їх для відображення у браузері. Ця задача може займати
багато часу в процесі розробки. Yii надає потужні віджети, які роблять задачу максимально простою.

22
docs/guide-uk/start-gii.md

@ -1,16 +1,16 @@
Генерація коду за допомогою Gii
===============================
Генерування коду за допомогою Gii
=================================
Цей розділ описує, як використовувати [Gii](https://github.com/yiisoft/yii2-gii/blob/master/docs/guide-uk/README.md)
для автоматичної генерації коду, який реалізовує найбільш поширений функціонал для веб-сайту. Використання Gii для
для автоматичного генерування коду, який реалізовує найбільш поширений функціонал для веб-сайту. Використання Gii для
автоматичного створення коду є простою процедурою введення правильної інформації згідно з інструкціями, які містяться
на веб-сторінках Gii.
В даному керівництві ви дізнаєтесь як:
* увімкнути Gii у вашому додатку;
* використовувати Gii для генерації класів Active Record;
* використовувати Gii для генерації коду, який реалізовує операції CRUD для таблиці бази даних;
* використовувати Gii для генерування класів Active Record;
* використовувати Gii для генерування коду, який реалізовує операції CRUD для таблиці бази даних;
* налаштовувати код, що був згенерований Gii.
@ -62,10 +62,10 @@ http://hostname/index.php?r=gii
![Gii](images/start-gii.png)
Генерація класу Active Record <span id="generating-ar"></span>
-----------------------------
Генерування класу Active Record <span id="generating-ar"></span>
-------------------------------
Використовуючи Gii для генерації класу Active Record, виберіть "Model Generator" (натиснувши на посилання на сторінці Gii).
Використовуючи Gii для генерування класу Active Record, виберіть "Model Generator" (натиснувши на посилання на сторінці Gii).
Далі заповніть форму наступними даними:
* Ім’я таблиці: `country`
@ -87,8 +87,8 @@ http://hostname/index.php?r=gii
файл, то побачите повідомлення про те, що він був переписаний і замінений на щойно згенерований код.
Генерація коду CRUD <span id="generating-crud"></span>
-------------------
Генерування коду CRUD <span id="generating-crud"></span>
---------------------
CRUD - це акронім від англійських слів Create, Read, Update, Delete (Створити, Прочитати, Оновити, Видалити), що представляє чотири основні операції над даними на більшості веб-сайтів.
Щоб реалізувати функціонал CRUD використовуючи Gii, оберіть "CRUD Generator" (натиснувши відповідну кнопку на сторінці Gii). Наприклад, для таблиці "country", заповніть форму наступним чином:
@ -133,7 +133,7 @@ http://hostname/index.php?r=country/index
* Моделі: `models/Country.php` і `models/CountrySearch.php`
* Представлення: `views/country/*.php`
> Інформація: Gii - це гнучкий і розширюваний інструмент для генерації коду. При правильному використані, він дозволить
> Інформація: Gii - це гнучкий і розширюваний інструмент для генерування коду. При правильному використані, він дозволить
вам значно прискорити розробку ваших додатків. Для більш докладної інформації, будь ласка, зверніться до розділу
[Gii](https://github.com/yiisoft/yii2-gii/blob/master/docs/guide-uk/README.md).

6
docs/guide-uk/start-hello.md

@ -73,7 +73,7 @@ Yii використовує префікс `action` для того, щоб в
Створення представлення <span id="creating-view"></span>
-----------------------
[Представлення](structure-views.md) є скриптами, які використовуються для генерації вмісту відповіді.
[Представлення](structure-views.md) є скриптами, які використовуються для генерування вмісту відповіді.
Для нашого додатку ви створите представлення `say`, яке буде виводити параметр `message`, отриманий із методу дії:
```php
@ -107,12 +107,12 @@ http://hostname/index.php?r=site/say&message=Привіт+світ
![Привіт, світ](images/start-hello-world.png)
Буде відображена сторінка з надписом "Привіт світ". Вона використовує ту ж шапку і футер, що і решта сторінок додатка.
Буде відображена сторінка з надписом "Привіт світ". Вона використовує ту ж шапку та футер, що і решта сторінок додатка.
Якщо ви не вкажете параметр `message` в URL, то побачите на сторінці лише "Привіт". Це відбувається тому, що `message` передається як параметр в метод `actionSay()`, а коли він не вказаний,
використовується значення за замовчуванням "Привіт".
> Інформація: Нова сторінка використовує ту ж шапку і футер, що й решта сторінок, тому що метод [[yii\web\Controller::render()|render()]]
> Інформація: Нова сторінка використовує ту ж шапку та футер, що й решта сторінок, тому що метод [[yii\web\Controller::render()|render()]]
автоматично підставляє результат формування представлення `say` в, так званий, [макет](structure-views.md#layouts), який в даному
випадку розміщено у `views/layouts/main.php`.

2
docs/guide-uk/start-installation.md

@ -37,7 +37,7 @@
Після встановлення Composer, встановити Yii можна виконавши наступну команду з директорії, яка доступна через Web:
composer global require "fxp/composer-asset-plugin:~1.0.0"
composer global require "fxp/composer-asset-plugin:~1.0.3"
composer create-project --prefer-dist yiisoft/yii2-app-basic basic
Перша команда встановить [плагін ресурсів composer (composer-asset-plugin)](https://github.com/francoispluchino/composer-asset-plugin/),

2
docs/guide-uk/start-looking-ahead.md

@ -4,7 +4,7 @@
Якщо ви прочитали всю главу "Перше знайомство", то, напевно, ви створили повноцінний додаток Yii. У процесі ви дізналися, як реалізувати деякі найбільш часто
використовувані функції, такі, як отримання даних від користувачів за допомогою HTML-форми, вибірка даних з бази даних
і відображення даних із розділенням на сторінки. Також ви дізналися, як використовувати [Gii](https://github.com/yiisoft/yii2-gii/blob/master/docs/guide-uk/README.md)
для автоматичної генерації коду, що перетворює більшу частину процесу веб-розробки у завдання настільки просте, як заповнення деяких форм.
для автоматичного генерування коду, що перетворює більшу частину процесу веб-розробки у завдання настільки просте, як заповнення деяких форм.
У цьому розділі зібрані ресурси пов’язані з Yii, які допоможуть вам бути більш продуктивними при використанні фреймворку.

2
docs/guide-uk/start-workflow.md

@ -22,7 +22,7 @@
* сторінка "Login", на якій відображається форма для аутентифікації користувачів. Спробуйте увійти з логіном/паролем
"admin/admin". Зверніть увагу на зміну пункту "Login" в головному меню на "Logout".
Ці сторінки використовують спільну шапку і футер. Шапка містить головне меню, за
Ці сторінки використовують спільну шапку та футер. Шапка містить головне меню, за
допомогою якого здійснюється навігація по сайту.
У нижній частині вікна ви зможете бачити системні повідомлення Yii - налагоджувальну інформацію,

2
docs/guide-uk/structure-controllers.md

@ -2,7 +2,7 @@
==========
Контролери є частиною архітектури [MVC](http://uk.wikipedia.org/wiki/Модель-вид-контролер). Це об’єкти класів,
успадкованих від [[yii\base\Controller]] та відповідають за обробку запитів і генерацію відповідей.
успадкованих від [[yii\base\Controller]] та відповідають за обробку запитів і генерування відповідей.
Зокрема, після отримання контролю від [додатків](structure-applications.md), контролери проаналізують
вхідні дані, передадуть їх у [моделі](structure-models.md), додадуть результати моделі у
[представлення](structure-views.md), і на сам кінець згенерують вихідні відповіді.

8
docs/guide-uk/structure-models.md

@ -58,7 +58,7 @@ foreach ($model as $name => $value) {
За замовчуванням, якщо ваш клас моделі успадкований безпосередньо від [[yii\base\Model]], усі його *не статичні публічні*
змінні є атрибутами. Наприклад, клас моделі `ContactForm`, наведений нижче, має чотири атрибути: `name`, `email`,
`subject` і `body`. Модель `ContactForm` використовується для презентування вхідних даних, отриманих з HTML-форми.
`subject` і `body`. Модель `ContactForm` використовується для репрезентації вхідних даних, отриманих з HTML-форми.
```php
namespace app\models;
@ -97,7 +97,7 @@ $model = new \app\models\ContactForm;
echo $model->getAttributeLabel('name');
```
За замовчуванням мітки атрибутів генеруються автоматично з імен атрибутів. Генерація виконується
За замовчуванням мітки атрибутів генеруються автоматично з імен атрибутів. Генерування виконується
методом [[yii\base\Model::generateAttributeLabel()]]. Він перетворить імена змінних зі стилю "camel-case" у
декілька слів з першою літерою у кожному слові у верхньому регістрі. Наприклад, `username` стане `Username`,
а `firstName` стане `First Name`.
@ -476,13 +476,13 @@ public function fields()
## Кращі практики <span id="best-practices"></span>
Моделі є центральним місцем презентування бізнес-даних, бізнес-правил і бізнес-логіки. Вони часто потребують повторного
Моделі є центральним місцем репрезентації бізнес-даних, бізнес-правил і бізнес-логіки. Вони часто потребують повторного
використання у різних місцях. В добре організованому додатку моделі зазвичай набагато більші, ніж
[контролери](structure-controllers.md).
В цілому, моделі
* можуть містити атрибути для презентування бізнес-даних;
* можуть містити атрибути для репрезентації бізнес-даних;
* можуть містити правила перевірки для забезпечення коректності та цілісності даних;
* можуть містити методи, які реалізують бізнес-логіку;
* НЕ повинні безпосередньо отримувати доступ до запиту, сесії або будь-яких інших даних середовища. Ці дані повинні бути введені

723
docs/guide-uk/structure-views.md

@ -0,0 +1,723 @@
Представлення
=============
Представлення є частиною архітектури [MVC](http://uk.wikipedia.org/wiki/Модель-вид-контролер).
Це код, який відповідає за відображення даних кінцевим користувачам. У веб-додатку представлення зазвичай створені
у вигляді *шаблонів представлень*, які є файлами скриптів PHP, що містять переважно HTML-код та презентаційний PHP-код.
Управління ними здійснюється за допомогою [компонента додатку](structure-application-components.md) [[yii\web\View|view]], який надає часто використовувані методи
для полегшення компонування та формування представлення. Для простоти, часто шаблони представлень або файли шаблонів представлень називаються
представленнями.
## Створення представлень <span id="creating-views"></span>
Як зазначено вище, представлення є простим скриптом PHP, який містить HTML- та PHP-код. Далі наведено представлення,
що представляє форму входу користувача. Як можна побачити, PHP-код використовується для генерування динамічного вмісту, такого як
заголовку сторінки та форми, тоді як HTML-код організовує їх у презентабельну HTML-сторінку.
```php
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
/* @var $this yii\web\View */
/* @var $form yii\widgets\ActiveForm */
/* @var $model app\models\LoginForm */
$this->title = 'Вхід';
?>
<h1><?= Html::encode($this->title) ?></h1>
<p>Будь ласка, заповніть наступні поля для входу:</p>
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($model, 'username') ?>
<?= $form->field($model, 'password')->passwordInput() ?>
<?= Html::submitButton('Увійти') ?>
<?php ActiveForm::end(); ?>
```
Всередині представлення ви можете використовувати `$this`, що відноситься до [[yii\web\View|компоненту представлення]], який забезпечує керування
цим шаблоном та його формування.
Окрім `$this`, у представленні можуть бути інші попередньо визначені змінні, такі як `$model` у прикладі
вище. Ці змінні представляють дані, які були *передані* у представлення через [контролери](structure-controllers.md)
або інші об’єкти, які спричинили [формування представлення](#rendering-views).
> Підказка: Попередньо визначені змінні перелічені в блоці коментаря у початку представлення, так що вони можуть
бути розпізнані в інтегрованих середовищах розробки (IDE). Це також є хорошим способом документування ваших представлень.
### Безпека <span id="security"></span>
При створенні представлень, які генерують HTML-сторінки, важливо кодувати і/або фільтрувати дані, що надходять
від кінцевих користувачів, перед їх відображенням. В протилежному випадку ваш додаток може стати предметом
атак типу [міжсайтовий скриптінг (XSS)](https://uk.wikipedia.org/wiki/Міжсайтовий_скриптінг).
Для відображення звичайного тексту спершу закодуйте його за допомогою [[yii\helpers\Html::encode()]]. Наприклад, в наступному коді
перед відображенням кодується ім’я користувача:
```php
<?php
use yii\helpers\Html;
?>
<div class="username">
<?= Html::encode($user->name) ?>
</div>
```
Для відображення HTML-вмісту використовуйте [[yii\helpers\HtmlPurifier]], щоб відфільтрувати потенційно небезпечний вміст. Наприклад, в наступному
коді фільтрується вміст публікації перед відображенням:
```php
<?php
use yii\helpers\HtmlPurifier;
?>
<div class="post">
<?= HtmlPurifier::process($post->text) ?>
</div>
```
> Підказка: В той час як HTMLPurifier бездоганно виконує роботу, щоб зробити вивід безпечним, він не є швидким. Вам потрібно розглянути
можливість [кешування](caching-overview.md) результатів фільтрування, якщо ваш додаток потребує високої швидкодії.
### Впорядкування представлень <span id="organizing-views"></span>
Подібно до [контролерів](structure-controllers.md) та [моделей](structure-models.md), існують домовленості щодо впорядкування представлень.
* Представлення, які формуються контролером, повинні бути розміщені в директорії `@app/views/ControllerID` за замовчуванням,
де `ControllerID` відповідає [ідентифікатору контролера](structure-controllers.md#routes). Наприклад, для
класу контролера `PostController` директорія повинна бути `@app/views/post`; для класу `PostCommentController`
директорія повинна бути `@app/views/post-comment`. У випадку, коли контролер належить модулю, директорія
повинна бути `views/ControllerID` у [[yii\base\Module::basePath|директорії модуля]].
* Представлення, які формуються у [віджетах](structure-widgets.md), повинні бути розміщені в директорії `WidgetPath/views` за
замовчуванням, де `WidgetPath` означає шлях до директорії, в якій знаходиться файл класу віджету.
* Для представлень, які формуються іншими об’єктами, рекомендується виконувати домовленості подібно до віджетів.
Ви можете налаштувати ці типові директорії представлень, перевизначивши метод [[yii\base\ViewContextInterface::getViewPath()]]
контролерів або віджетів.
## Формування представлень <span id="rendering-views"></span>
Ви можете формувати представлення в [контролерах](structure-controllers.md), [віджетах](structure-widgets.md) чи в будь-яких
інших місцях за допомогою виклику методів формування представлення. Усі ці методи мають подібну сигнатуру, що наведена нижче:
```
/**
* @param string $view ім’я представлення або шлях до файлу, в залежності від того, який метод формування використовується
* @param array $params дані, які передаються представленню
* @return string результат формування
*/
methodName($view, $params = [])
```
### Формування в контролерах <span id="rendering-in-controllers"></span>
Всередині [контролерів](structure-controllers.md), ви можете викликати наступні методи контролера для формування представлень:
* [[yii\base\Controller::render()|render()]]: формує [іменоване представлення](#named-views) та застосовує [макет](#layouts)
до результату формування.
* [[yii\base\Controller::renderPartial()|renderPartial()]]: формує [іменоване представлення](#named-views) без будь-якого макету.
* [[yii\web\Controller::renderAjax()|renderAjax()]]: формує [іменоване представлення](#named-views) без будь-якого макету
та включає усі зареєстровані скрипти і файли JS/CSS. Це зазвичай використовується у відповіді на веб-запити AJAX.
* [[yii\base\Controller::renderFile()|renderFile()]]: формує представлення визначене шляхом файлу представлення або
[псевдонімом](concept-aliases.md).
* [[yii\base\Controller::renderContent()|renderContent()]]: формує статичний текстовий рядок, включаючи його в
поточний застосовний [макет](#layouts). Цей метод доступний починаючи з версії 2.0.1.
Наприклад:
```php
namespace app\controllers;
use Yii;
use app\models\Post;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
class PostController extends Controller
{
public function actionView($id)
{
$model = Post::findOne($id);
if ($model === null) {
throw new NotFoundHttpException;
}
// формує представлення з ім’ям "view" та застосовує макет до нього
return $this->render('view', [
'model' => $model,
]);
}
}
```
### Формування у віджетах <span id="rendering-in-widgets"></span>
Всередині [віджетів](structure-widgets.md), ви можете викликати наступні методи віджету для формування представлень.
* [[yii\base\Widget::render()|render()]]: формує [іменоване представлення](#named-views).
* [[yii\base\Widget::renderFile()|renderFile()]]: формує представлення визначене шляхом файлу представлення або
[псевдонімом](concept-aliases.md).
Наприклад:
```php
namespace app\components;
use yii\base\Widget;
use yii\helpers\Html;
class ListWidget extends Widget
{
public $items = [];
public function run()
{
// формує представлення з ім’ям "list"
return $this->render('list', [
'items' => $this->items,
]);
}
}
```
### Формування у представленнях <span id="rendering-in-views"></span>
Ви можете формувати представлення всередині іншого представлення за допомогою виклику одного з наступних методів наданих [[yii\base\View|компонентом представлення]]:
* [[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).
Наприклад, наступний код у представленні формує файл представлення `_overview.php`, який знаходиться в тій самій директорії,
що й представлення, яке зараз формується. Запам’ятайте, що `$this` у представленні відноситься до компонента [[yii\base\View|представлення]]:
```php
<?= $this->render('_overview') ?>
```
### Формування в інших місцях <span id="rendering-in-other-places"></span>
В будь-якому місці ви можете отримати доступ до компонента додатка [[yii\base\View|представлення]] за допомогою виразу
`Yii::$app->view` та потім викликати його вищезгадані методи для формування представлення. Наприклад:
```php
// відображає файл представлення "@app/views/site/license.php"
echo \Yii::$app->view->renderFile('@app/views/site/license.php');
```
### Іменовані представлення <span id="named-views"></span>
При формуванні представлення ви можете визначити його, використовуючи ім’я представлення або шлях/псевдонім до файлу представлення. У більшості випадків
ви будете використовувати перший варіант, тому що він більш лаконічний та гнучкий. Представлення, визначені за допомогою імен називаються *іменованими представленнями*.
Ім’я представлення перетворюється у відповідний шлях до файлу представлення за наступними правилами:
* Ім’я представлення можна вказувати без розширення імені файлу. У цьому випадку в якості розширення буде використовуватись `.php`. Наприклад,
ім’я представлення `about` відповідає імені файлу `about.php`.
* Якщо ім’я представлення починається з двох слешів `//`, то відповідним шляхом до файлу представлення буде `@app/views/ViewName`.
Це означає, що представлення шукається в [[yii\base\Application::viewPath|директорії представлень додатку]].
Наприклад, `//site/about` буде перетворено в `@app/views/site/about.php`.
* Якщо ім’я представлення починається з одного слешу `/`, то шлях до файлу представлення складатиметься з імені представлення та префіксу
у вигляді [[yii\base\Module::viewPath|директорії представлень]] поточного активного [модулю](structure-modules.md).
Якщо немає активного модулю, то буде використовуватись `@app/views/ViewName`. Наприклад, `/user/create` буде перетворено в
`@app/modules/user/views/user/create.php`, якщо поточним активним модулем є `user`. Якщо немає активного модулю,
то шляхом до файлу представлення буде `@app/views/user/create.php`.
* Якщо представлення формується з [[yii\base\View::context|контекстом]] і контекст має реалізований інтерфейс [[yii\base\ViewContextInterface]],
то шлях до файлу представлення складатиметься з префікса у вигляді [[yii\base\ViewContextInterface::getViewPath()|директорії представлень]]
контексту та з імені представлення. Це частіше застосовується до представлень, які формуються всередині контролерів або віджетів. Наприклад,
`about` буде перетворено в `@app/views/site/about.php`, якщо контекстом є контролер `SiteController`.
* Якщо представлення формується в середині іншого представлення, директорія, що містить інше представлення буде додана перед
іменем представлення, що формується, для створення актуального шляху до файлу. Наприклад, `item` перетвориться в `@app/views/post/item.php`,
якщо буде формуватись із представлення `@app/views/post/index.php`.
Згідно з наведеними правилами, виклик `$this->render('view')` у контролері `app\controllers\PostController` буде
формувати представлення з файлу `@app/views/post/view.php`, в той час як виклик `$this->render('_overview')` у тому представленні
буде формувати представлення з файлу `@app/views/post/_overview.php`.
### Доступ до даних у представленнях <span id="accessing-data-in-views"></span>
Є два підходи при доступові до даних в середині представлення: "вштовхування" та "витягування".
Передаючи дані другим параметром у методи формування представлення, ви використовуєте підхід "вштовхування".
Дані повинні бути надані у вигляді масиву пар ключ-значення. Під час формування представлення буде викликана функція PHP
`extract()` на цьому масиві, видобувши таким чином змінні у представлення.
Наприклад, наступний код формування представлення у контролері "вштовхне" дві змінні до представлення `report`:
`$foo = 1` та `$bar = 2`.
```php
echo $this->render('report', [
'foo' => 1,
'bar' => 2,
]);
```
Підхід "витягування" активно здобуває дані з [[yii\base\View|компоненту представлення]] або інших об’єктів, доступних
у представленнях (наприклад, `Yii::$app`). Використовуючи нижче наведений код як приклад, всередині представлення можна отримати об’єкт
за допомогою виразу `$this->context`. У результаті, стає можливим доступ до усіх властивостей та методів
контролера у представленні `report`, як, наприклад, ідентифікатору контролера, що наведений у прикладі:
```php
Ідентифікатор контролера: <?= $this->context->id ?>
```
Підхід "вштовхування" є бажанішим шляхом для доступу до даних у представленнях, тому що він робить представлення менш залежними
від об’єктів контексту, але його недоліком є необхідність весь час будувати масив даних вручну, що може
стати стомливим та збільшує вірогідність допустити помилку, якщо представлення використовується та формується у різних місцях.
### Обмін даними між представленнями <span id="sharing-data-among-views"></span>
[[yii\base\View|Компонент представлення]] надає властивість [[yii\base\View::params|params]], яку можна використовувати
для обміну даними між представленнями.
Наприклад, в представленні `about`, ви можете мати наступний код, який визначає поточну частину
"хлібних крихт".
```php
$this->params['breadcrumbs'][] = 'Про нас';
```
Потім у файлі [макету](#layouts), який також є представленням, ви можете відобразити "хлібні крихти", використовуючи дані
передані через [[yii\base\View::params|params]]:
```php
<?= yii\widgets\Breadcrumbs::widget([
'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [],
]) ?>
```
## Макети <span id="layouts"></span>
Макети - особливий тип представлень, які представляють спільні частини для інших представлень. Наприклад, сторінки
більшості веб-додатків мають однакові шапку та футер. Ви можете повторювати однакові шапку та футер сторінки
у кожному представленні, але краще зробити це один раз у макеті та розмістити результат формування вкладеного представлення
у відповідному місці макету.
### Створення макетів <span id="creating-layouts"></span>
Оскільки макети є представленнями, вони можуть бути створенні тим самим шляхом, як і звичайні представлення. За замовчуванням, макети
зберігаються в директорії `@app/views/layouts`. Макети, які використовуються у [модулі](structure-modules.md),
повинні зберігатись в директорії `views/layouts` під [[yii\base\Module::basePath|директорією модуля]].
Ви можете налаштувати типову директорію для макетів сконфігурувавши властивість [[yii\base\Module::layoutPath]]
додатку або модулів.
Наступний приклад показує як виглядає макет. Майте на увазі, що для кращого сприйняття код у макеті дуже спрощений.
На практиці, ви можливо захочете додати більше вмісту до нього, такого як теги секції `<head>`, головне меню та інше.
```php
<?php
use yii\helpers\Html;
/* @var $this yii\web\View */
/* @var $content string */
?>
<?php $this->beginPage() ?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<?= Html::csrfMetaTags() ?>
<title><?= Html::encode($this->title) ?></title>
<?php $this->head() ?>
</head>
<body>
<?php $this->beginBody() ?>
<header>Моя компанія</header>
<?= $content ?>
<footer>Моя компанія &copy; 2014</footer>
<?php $this->endBody() ?>
</body>
</html>
<?php $this->endPage() ?>
```
Як ви можете бачити, макет генерує HTML-теги, які є спільними для всіх сторінок. У секції `<body>`
макет виводить змінну `$content`, яка містить результат формування вкладених представлень та "вштовхується"
у макет під час виклику методу [[yii\base\Controller::render()]].
В більшості макетів наступні методи будуть викликатись як показано у вищенаведеному коді. Ці методи здебільшого породжують події,
пов’язані з процесом формування, щоб скрипти та теги, які зареєстровані в інших місцях могли бути правильно включенні в
місцях, де ці методи викликаються.
- [[yii\base\View::beginPage()|beginPage()]]: Цей метод повинен викликатись на самому початку макету.
Він породжує подію [[yii\base\View::EVENT_BEGIN_PAGE|EVENT_BEGIN_PAGE]], яка слугує ознакою початку сторінки.
- [[yii\base\View::endPage()|endPage()]]: Цей метод повинен викликатись в кінці макету.
Він породжує подію [[yii\base\View::EVENT_END_PAGE|EVENT_END_PAGE]], яка слугує ознакою кінця сторінки.
- [[yii\web\View::head()|head()]]: Цей метод повинен викликатись всередині секції `<head>` HTML-сторінки.
Він генерує заповнювач, який буде замінено зареєстрованим HTML-кодом (наприклад, теги link і meta),
коли сторінка буде повністю сформована.
- [[yii\web\View::beginBody()|beginBody()]]: Цей метод повинен викликатись на початку секції `<body>`.
Він породжує подію [[yii\web\View::EVENT_BEGIN_BODY|EVENT_BEGIN_BODY]] та генерує заповнювач, який
буде замінено зареєстрованим HTML-кодом (наприклад, JavaScript) на початку секції `<body>`.
- [[yii\web\View::endBody()|endBody()]]: Цей метод повинен викликатись у кінці секції `<body>`.
Він породжує подію [[yii\web\View::EVENT_END_BODY|EVENT_END_BODY]] та генерує заповнювач, який
буде замінено зареєстрованим HTML-кодом (наприклад, JavaScript) у кінці секції `<body>`.
### Доступ до даних у макетах <span id="accessing-data-in-layouts"></span>
Всередині макету ви маєте доступ до двох попередньо визначених змінних: `$this` та `$content`. Перша посилається на
компонент [[yii\base\View|представлення]], як і у звичайних представленнях, в той час як друга містить результат формування вкладеного
представлення, який формується викликом методу [[yii\base\Controller::render()|render()]] у контролерах.
Якщо ви бажаєте мати доступ до інших даних у макетах, то вам потрібно використовувати підхід "витягування", описаний в
підрозділі [Доступ до даних у представленнях](#accessing-data-in-views). Якщо ви бажаєте отримати дані з вкладеного представлення
у макеті, то можете використати підхід описаний у підрозділі [Обмін даними між представленнями](#sharing-data-among-views).
### Використання макетів <span id="using-layouts"></span>
Як описано в підрозділі [Формування в контролерах](#rendering-in-controllers), під час формування представлення
через виклик методу [[yii\base\Controller::render()|render()]] у контролері, буде застосовний макет
до результату формування. За замовчуванням, буде використовуватись макет `@app/views/layouts/main.php`.
Ви можете використовувати інший макет сконфігурувавши властивість [[yii\base\Application::layout]] або [[yii\base\Controller::layout]].
Перша відповідає за макет, який використовується усіма контролерами, друга ж перекриває першу для окремих контролерів.
Наприклад, наступний код налаштовує контролер `post` на використання макету `@app/views/layouts/post.php`
під час формування його представлень. Інші контролери, за умови, що їх властивість `layout` не встановлена, будуть надалі
використовувати типовий макет `@app/views/layouts/main.php`.
```php
namespace app\controllers;
use yii\web\Controller;
class PostController extends Controller
{
public $layout = 'post';
// ...
}
```
Для контролерів, що належать модулю, ви можете також сконфігурувати властивість модуля [[yii\base\Module::layout|layout]], щоб
використовувати окремий макет для цих контролерів.
Оскільки властивість `layout` може бути сконфігурована на різних рівнях (контролери, моделі, додаток),
"за лаштунками" Yii виконує два кроки, щоб визначити, який файл макету є актуальним для окремого контролера.
На першому кроці, визначається значення `layout` та контекстний модуль:
- Якщо властивість контролера [[yii\base\Controller::layout]] відмінна від `null`, використовується вона і
[[yii\base\Controller::module|модуль]] контролера як контекстний модуль.
- Якщо [[yii\base\Controller::layout|layout]] не визначено (дорівнює `null`), здійснюється пошук у всіх батьківських модулях (включаючи сам додаток) контролера та
знаходиться перший модуль, властивість [[yii\base\Module::layout|layout]] якого не дорівнює `null`. Використовується значення цього модуля
[[yii\base\Module::layout|layout]] та сам модуль як контекстний модуль.
Якщо такого модуля не знайдено, це означає, що макет не буде застосовано.
На другому кроці, визначається актуальний файл макету відповідно до значення `layout` та контекстного модулю,
визначених на першому кроці. Значенням `layout` може бути:
- псевдонім шляху (наприклад, `@app/views/layouts/main`);
- абсолютний шлях (наприклад, `/main`): значення `layout` починається зі слешу. Актуальний файл макету буде
шукатись під [[yii\base\Application::layoutPath|директорією макетів]] додатка, яка типово дорівнює
`@app/views/layouts`;
- відносний шлях (наприклад, `main`): актуальний файл макету буде шукатись під
[[yii\base\Module::layoutPath|директорією макетів]] контекстного модуля, яка типово є директорією `views/layouts` під
[[yii\base\Module::basePath|директорією модуля]];
- логічне значення `false`: макет не буде застосовано.
Якщо значення `layout` не містить розширення файлу, то буде використане типове розширення `.php`.
### Вкладені макети <span id="nested-layouts"></span>
Іноді потрібно вкласти один макет в інший. Наприклад, у різних розділах веб-сайту ви
захочете використовувати різні макети, які мають однаковий базовий макет, що генерує загальну
структуру HTML5-сторінки. Це можна зробити за допомогою викликів [[yii\base\View::beginContent()|beginContent()]] та
[[yii\base\View::endContent()|endContent()]] в дочірніх макетах як наведено нижче:
```php
<?php $this->beginContent('@app/views/layouts/base.php'); ?>
...вміст дочірнього макету...
<?php $this->endContent(); ?>
```
Як показано вище, вміст дочірнього макету повинен бути замкнений між [[yii\base\View::beginContent()|beginContent()]] та
[[yii\base\View::endContent()|endContent()]]. Параметр, який передається в [[yii\base\View::beginContent()|beginContent()]]
визначає батьківський макет. Цей може бути файл макету чи псевдонім шляху.
Використовуючи цей підхід, можна вкладати макети більше, ніж на один рівень.
### Використання блоків <span id="using-blocks"></span>
Блоки дозволяють визначати вміст представлення в одному місці, а відображати в іншому. Вони часто використовуються разом
з макетами. Наприклад, ви можете визначити блок у вкладеному представленні та відобразити його у макеті.
Виклики [[yii\base\View::beginBlock()|beginBlock()]] та [[yii\base\View::endBlock()|endBlock()]] визначають блок.
Потім блок може бути доступним через `$view->blocks[$blockID]`, де `$blockID` означає унікальний ідентифікатор, який ви призначаєте
блоку під час його визначення.
Нижченаведений приклад показує як ви можете використовувати блоки у вкладеному представленні для налаштовування окремих частин макету.
Спершу, у вкладеному представленні, визначається один чи більше блоків:
```php
...
<?php $this->beginBlock('block1'); ?>
...вміст блоку 1...
<?php $this->endBlock(); ?>
...
<?php $this->beginBlock('block3'); ?>
...вміст блоку 3...
<?php $this->endBlock(); ?>
```
Потім, у макеті, формуються блоки, якщо вони присутні, або відображається деякий типовий вміст, якщо блок
не визначено.
```php
...
<?php if (isset($this->blocks['block1'])): ?>
<?= $this->blocks['block1'] ?>
<?php else: ?>
... типовий вміст для блоку 1 ...
<?php endif; ?>
...
<?php if (isset($this->blocks['block2'])): ?>
<?= $this->blocks['block2'] ?>
<?php else: ?>
... типовий вміст для блоку 2 ...
<?php endif; ?>
...
<?php if (isset($this->blocks['block3'])): ?>
<?= $this->blocks['block3'] ?>
<?php else: ?>
... типовий вміст для блоку 3 ...
<?php endif; ?>
...
```
## Використання компонентів представлення <span id="using-view-components"></span>
[[yii\base\View|Компоненти представлення]] надають багато можливостей, пов’язаних із представленням. Ви можете отримувати компоненти представлення
за допомогою створення індивідуальних екземплярів [[yii\base\View]] або його дочірніх класів, але у більшості випадків ви переважно будете використовувати
компонент `view` додатку. Ви можете сконфігурувати цей компонент у [конфігураціях додатку](structure-applications.md#application-configurations)
як наведено нижче:
```php
[
// ...
'components' => [
'view' => [
'class' => 'app\components\View',
],
// ...
],
]
```
Компоненти представлення надають наступні корисні можливості, пов’язані з представленням, які описані більш детально в окремих розділах:
* [темізація](output-theming.md): дозволяє проектувати та змінювати тему для веб-сайту;
* [кешування фрагментів](caching-fragment.md): дозволяє кешувати фрагменти веб-сторінки;
* [опрацювання клієнтських скриптів](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/).
Ви також можете часто використовувати наступні другорядні, але корисні, можливості в процесі розробки веб-сторінок.
### Встановлення заголовків сторінок <span id="setting-page-titles"></span>
Кожна веб-сторінка повинна мати заголовок. Звичайно тег заголовку виводиться в [макеті](#layouts). Однак, на практиці
заголовок часто визначається у вкладених представленнях, а не в макетах. Для вирішення цієї проблеми, компонент [[yii\web\View]] надає
властивість [[yii\web\View::title|title]], за допомогою якої можна передавати з вкладеного представлення до макетів інформацію заголовку.
Для використання цієї можливості, в кожному вкладеному представленні ви можете задати заголовок як наведено нижче:
```php
<?php
$this->title = 'Мій заголовок сторінки';
?>
```
Потім переконайтесь, що маєте наступний код в секції `<head>` у макеті:
```php
<title><?= Html::encode($this->title) ?></title>
```
### Реєстрація мета-тегів <span id="registering-meta-tags"></span>
Для веб-сторінок зазвичай потрібно генерувати різноманітні мета-теги, які мають різне цільове призначення. Подібно до заголовків сторінок, мета-теги
фігурують в секції `<head>` та зазвичай генеруються в макетах.
Якщо ви бажаєте визначити, які мета-теги генерувати у вкладених представленнях, ви можете викликати [[yii\web\View::registerMetaTag()]]
у вкладеному представленні, подібно до наведеного:
```php
<?php
$this->registerMetaTag(['name' => 'keywords', 'content' => 'yii, framework, php']);
?>
```
В коді вище реєструється мета-тег "keywords" у компоненті представлення. Зареєстрований мета-тег
формується після закінчення формування макету. Наступний HTML-код буде згенеровано та вставлено
в місці, де ви викличете [[yii\web\View::head()]] у макеті:
```php
<meta name="keywords" content="yii, framework, php">
```
Зауважте, якщо викликати [[yii\web\View::registerMetaTag()]] декілька разів, в результаті цього зареєструється кілька мета-тегів,
не зважаючи на те, чи мета-теги однакові чи ні.
Щоб мати лише один екземпляр специфічного типу мета-тегу, потрібно визначати ключ в другому параметрі під час виклику методу.
Наприклад, наступний код реєструє два мета-теги "description". Однак, лише другий буде сформовано.
```html
$this->registerMetaTag(['name' => 'description', 'content' => 'Це мій класний веб-сайт, який створено за допомогою Yii!'], 'description');
$this->registerMetaTag(['name' => 'description', 'content' => 'Цей веб-сайт про смішних єнотів.'], 'description');
```
### Реєстрація тегів link <span id="registering-link-tags"></span>
Так само як і [мета-теги](#registering-meta-tags), теги link є корисними у багатьох випадках, як, наприклад, налаштування favicon, посилання на
стрічку новин (RSS) або делегування OpenID іншому серверу. Ви можете працювати з тегами link подібним шляхом як і з мета-тегами,
використовуючи [[yii\web\View::registerLinkTag()]]. Наприклад, у вкладеному представленні, ви можете зареєструвати тег link наступним чином,
```php
$this->registerLinkTag([
'title' => 'Свіжі новини про Yii',
'rel' => 'alternate',
'type' => 'application/rss+xml',
'href' => 'http://www.yiiframework.com/rss.xml/',
]);
```
Результатом вищенаведеного коду буде
```html
<link title="Свіжі новини про Yii" rel="alternate" type="application/rss+xml" href="http://www.yiiframework.com/rss.xml/">
```
Подібно до [[yii\web\View::registerMetaTag()|registerMetaTags()]], ви можете визначати ключ під час виклику
[[yii\web\View::registerLinkTag()|registerLinkTag()]] для запобігання генерування повторних тегів link одного типу.
## Події у представленнях <span id="view-events"></span>
[[yii\base\View|Компоненти представлення]] породжують кілька подій в процесі формування представлення. Ви можете призначити обробники
на ці події для вставлення вмісту в представлення або для опрацювання сформованих результатів перед їх відправленням кінцевим користувачам.
- Подія [[yii\base\View::EVENT_BEFORE_RENDER|EVENT_BEFORE_RENDER]]: породжується на початку формування файлу
в контролері. Обробники цієї події можуть встановлювати значення властивості [[yii\base\ViewEvent::isValid]] рівним `false` для скасування процесу формування.
- Подія [[yii\base\View::EVENT_AFTER_RENDER|EVENT_AFTER_RENDER]]: породжується після формування файлу викликом [[yii\base\View::afterRender()]].
Обробники цієї події можуть отримати результат формування через властивість [[yii\base\ViewEvent::output]] та можуть модифікувати
її для зміни результату формування.
- Подія [[yii\base\View::EVENT_BEGIN_PAGE|EVENT_BEGIN_PAGE]]: породжується викликом [[yii\base\View::beginPage()]] у макетах.
- Подія [[yii\base\View::EVENT_END_PAGE|EVENT_END_PAGE]]: породжується викликом [[yii\base\View::endPage()]] у макетах.
- Подія [[yii\web\View::EVENT_BEGIN_BODY|EVENT_BEGIN_BODY]]: породжується викликом [[yii\web\View::beginBody()]] у макетах.
- Подія [[yii\web\View::EVENT_END_BODY|EVENT_END_BODY]]: породжується викликом [[yii\web\View::endBody()]] у макетах.
Наприклад, наступний код вставить поточну дату в кінці секції `<body>` сторінки:
```php
\Yii::$app->view->on(View::EVENT_END_BODY, function () {
echo date('Y-m-d');
});
```
## Формування статичних сторінок <span id="rendering-static-pages"></span>
До статичних сторінок відносяться ті веб-сторінки, в яких основний вміст здебільшого статичний та не потребує доступу
до динамічних даних, що передаються з контролерів.
Можна виводити статичні сторінки, розмістивши їх код у представленні, а потім використовуючи код подібний до наведеного у контролері:
```php
public function actionAbout()
{
return $this->render('about');
}
```
Якщо веб-сайт містить багато статичних сторінок, було б дуже стомливим повторювати схожий код багато разів.
Для вирішення цієї проблеми можна впровадити [автономну дію](structure-controllers.md#standalone-actions)
[[yii\web\ViewAction]] у контролері. Наприклад,
```php
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
public function actions()
{
return [
'page' => [
'class' => 'yii\web\ViewAction',
],
];
}
}
```
Тепер, якщо створити представлення з ім’ям `about` у директорії `@app/views/site/pages`, стане можливим
відображення цього представлення за наступною URL-адресою:
```
http://localhost/index.php?r=site/page&view=about
```
Параметр `view` із запиту `GET` вказує автономній дії [[yii\web\ViewAction]], яке представлення запитане. Потім дія здійснює пошук
цього представлення в директорії `@app/views/site/pages`. Ви можете сконфігурувати [[yii\web\ViewAction::viewPrefix]],
щоб змінити директорію для пошуку цих представлень.
## Кращі практики <span id="best-practices"></span>
Представлення відповідають за репрезентацію моделей у форматі зрозумілому кінцевим користувачам. В цілому, представлення
* повинні здебільшого містити презентаційний код, такий як HTML та простий PHP-код для подання, форматування та формування даних;
* не повинні містити код, який виконує запити до БД. Такий код повинен бути в моделях;
* повинні уникати безпосереднього доступу до даних запиту, таких як `$_GET`, `$_POST`. Це обов’язок контролерів.
У випадку необхідності дані запиту повинні бути передані в представлення через контролери;
* можуть читати властивості моделі, але не повинні змінювати їх.
Щоб зробити представлення більш контрольованими, уникайте створення представлень, які є дуже складними або містять забагато надлишкового коду.
Використовуйте наступні техніки, щоб досягнути цього:
* використовуйте [макети](#layouts) для відображення спільних презентаційних секцій (наприклад, шапка та футер сторінки);
* розділяйте складне представлення на декілька менших. Менші представлення можуть бути сформовані та складені у більше
за допомогою методів формування описаних раніше у цьому розділі;
* створюйте та використовуйте [віджети](structure-widgets.md) як будівельні блоки представлень;
* створюйте та використовуйте класи-хелпери для перетворення та форматування даних у представленнях.

2
docs/guide-uk/tutorial-yii-integration.md

@ -83,7 +83,7 @@ Yii::$classMap['Class2'] = 'path/to/Class2.php';
Якщо стороння система використовує управління залежностями Composer, ви можете встановити Yii за допомогою наступних команд:
composer global require "fxp/composer-asset-plugin:~1.0.0"
composer global require "fxp/composer-asset-plugin:~1.0.3"
composer require yiisoft/yii2
composer install

2
docs/guide-vi/start-installation.md

@ -36,7 +36,7 @@ Nếu bạn đã cài Composer rồi, hãy chắc chắn rằng bạn đang sử
Sau khi cài đặt Composer, bạn có thể cài đặt Yii bằng cách chạy lệnh sau ở thư mục Web mà ứng dụng cần chạy:
composer global require "fxp/composer-asset-plugin:~1.0.0"
composer global require "fxp/composer-asset-plugin:~1.0.3"
composer create-project --prefer-dist yiisoft/yii2-app-basic basic
Câu lệnh đầu tiên sẽ cài đặt [composer asset plugin](https://github.com/francoispluchino/composer-asset-plugin/)

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

@ -22,7 +22,7 @@
Composer 安装后,切换到一个可通过 Web 访问的目录,执行如下命令即可安装 Yii :
composer global require "fxp/composer-asset-plugin:~1.0.0"
composer global require "fxp/composer-asset-plugin:~1.0.3"
composer create-project --prefer-dist yiisoft/yii2-app-basic basic
第一条命令安装 [Composer asset plugin](https://github.com/francoispluchino/composer-asset-plugin/),它是通过 Composer 管理 bower 和 npm 包所必须的,此命令全局生效,一劳永逸。

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

@ -95,31 +95,41 @@ $container->set('Foo', function () {
$foo = $container->get('Foo');
```
To hide the complex logic for building a new object, you may use a static class method to return the PHP
callable. For example,
To hide the complex logic for building a new object, you may use a static class method as callable. For example,
```php
class FooBuilder
{
public static function build()
{
return function () {
$foo = new Foo(new Bar);
// ... other initializations ...
return $foo;
};
$foo = new Foo(new Bar);
// ... other initializations ...
return $foo;
}
}
$container->set('Foo', FooBuilder::build());
$container->set('Foo', ['app\helper\FooBuilder', 'build']);
$foo = $container->get('Foo');
```
As you can see, the PHP callable is returned by the `FooBuilder::build()` method. By doing so, the person
who wants to configure the `Foo` class no longer needs to be aware of how it is built.
By doing so, the person who wants to configure the `Foo` class no longer needs to be aware of how it is built.
### Controller action injection
Controller action injection is a special type of DI where dependecies are resolved per action which is useful for
keeping dependencies number low in MVC controllers.
```php
public function actionSend($email, EmailValidator $validator)
{
if ($validator->validate($email)) {
// ... send email
}
}
```
Registering Dependencies <span id="registering-dependencies"></span>
------------------------

6
docs/guide/db-migrations.md

@ -152,8 +152,8 @@ to `Schema::TYPE_STRING` to specify that the column cannot be null.
> Info: The mapping between abstract types and physical types is specified by
the [[yii\db\QueryBuilder::$typeMap|$typeMap]] property in each concrete `QueryBuilder` class.
Since version 2.0.6 schema builder which provides more convenient way defining column schema was introduced so migration above
could be written like the following:
Since version 2.0.6, you can make use of the newly introduced schema builder which provides more convenient way of defining column schema.
So the migration above could be written like the following:
```php
<?php
@ -185,7 +185,7 @@ A list of all available methods for defining the column types is available in th
While performing complex DB migrations, it is important to ensure each migration to either succeed or fail as a whole
so that the database can maintain integrity and consistency. To achieve this goal, it is recommended that you
enclose the DB operations of each migration in a [transaction](db-dao.md#performing-transactions-).
enclose the DB operations of each migration in a [transaction](db-dao.md#performing-transactions).
An even easier way of implementing transactional migrations is to put migration code in the `safeUp()` and `safeDown()`
methods. These two methods differ from `up()` and `down()` in that they are enclosed implicitly in a transaction.

4
docs/guide/input-multiple-models.md

@ -37,7 +37,9 @@ class UserController extends Controller
$profile->scenario = 'update';
if ($user->load(Yii::$app->request->post()) && $profile->load(Yii::$app->request->post())) {
if ($user->validate() && $profile->validate()) {
$isValid = $user->validate();
$isValid = $profile->validate() && $isValid;
if ($isValid) {
$user->save(false);
$profile->save(false);
return $this->redirect(['user/view', 'id' => $id]);

4
docs/guide/security-authorization.md

@ -88,8 +88,8 @@ be an array of action IDs. The comparison is case-sensitive. If this option is e
it means the rule applies to all actions.
* [[yii\filters\AccessRule::controllers|controllers]]: specifies which controllers this rule
matches. This should be an array of controller IDs. The comparison is case-sensitive. If this option is
empty or not set, it means the rule applies to all controllers.
matches. This should be an array of controller IDs. Each controller ID is prefixed with the module ID (if any).
The comparison is case-sensitive. If this option is empty or not set, it means the rule applies to all controllers.
* [[yii\filters\AccessRule::roles|roles]]: specifies which user roles that this rule matches.
Two special roles are recognized, and they are checked via [[yii\web\User::isGuest]]:

23
docs/guide/start-installation.md

@ -90,21 +90,26 @@ But there are other installation options available:
Verifying the Installation <span id="verifying-installation"></span>
--------------------------
After installation, you can use your browser to access the installed Yii application with the following URL:
After installation is done, either configure your web server (see next section) or use
[built-in PHP web server](https://secure.php.net/manual/en/features.commandline.webserver.php) by running the following
console command while in the project `web` directory:
```
http://localhost/basic/web/index.php
php -S localhost:80
```
This URL assumes you have installed Yii in a directory named `basic`, directly under the Web server's document root directory,
and that the Web server is running on your local machine (`localhost`). You may need to adjust it to your installation environment.
You can use your browser to access the installed Yii application with the following URL:
```
http://localhost/
```
![Successful Installation of Yii](images/start-app-installed.png)
You should see the above "Congratulations!" page in your browser. If not, please check if your PHP installation satisfies
Yii's requirements. You can check if the minimum requirements are met using one of the following approaches:
* Use a browser to access the URL `http://localhost/basic/requirements.php`
* Copy `/requirements.php` to `/web/requirements.php` and then use a browser to access it via `http://localhost/requirements.php`
* Run the following commands:
```
@ -112,9 +117,9 @@ Yii's requirements. You can check if the minimum requirements are met using one
php requirements.php
```
You should configure your PHP installation so that it meets the minimum requirements of Yii. Most importantly, you should have PHP 5.4 or above. You should also install
the [PDO PHP Extension](http://www.php.net/manual/en/pdo.installation.php) and a corresponding database driver
(such as `pdo_mysql` for MySQL databases), if your application needs a database.
You should configure your PHP installation so that it meets the minimum requirements of Yii. Most importantly, you
should have PHP 5.4 or above. You should also install the [PDO PHP Extension](http://www.php.net/manual/en/pdo.installation.php)
and a corresponding database driver (such as `pdo_mysql` for MySQL databases), if your application needs a database.
Configuring Web Servers <span id="configuring-web-servers"></span>

151
docs/guide/tutorial-i18n.md

@ -16,7 +16,7 @@ For consistency, all locale IDs used in Yii applications should be canonicalized
`ll-CC`, where `ll` is a two- or three-letter lowercase language code according to
[ISO-639](http://www.loc.gov/standards/iso639-2/) and `CC` is a two-letter country code according to
[ISO-3166](http://www.iso.org/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html).
More details about locale can be found in check the
More details about locale can be found in the
[documentation of the ICU project](http://userguide.icu-project.org/locale#TOC-The-Locale-Concept).
In Yii, we often use the term "language" to refer to a locale.
@ -65,7 +65,7 @@ To use the message translation service, you mainly need to do the following work
* Wrap every text message that needs to be translated in a call to the [[Yii::t()]] method;
* Configure one or multiple message sources in which the message translation service can look for translated messages;
* Let the translators to translate messages and store them in the message source(s).
* Let the translators translate messages and store them in the message source(s).
The method [[Yii::t()]] can be used like the following,
@ -76,8 +76,8 @@ echo \Yii::t('app', 'This is a string to translate!');
where the second parameter refers to the text message to be translated, while the first parameter refers to
the name of the category which is used to categorize the message.
The [[Yii::t()]] method will call the `i18n` [application component](structure-application-components.md)
to perform the actual translation work. The component can be configured in the application configuration as follows,
The [[Yii::t()]] method will call the `i18n` [application component](structure-application-components.md) `translate`
method to perform the actual translation work. The component can be configured in the application configuration as follows,
```php
'components' => [
@ -122,8 +122,8 @@ In this subsection, we will describe different ways of formatting messages.
### Message Parameters <span id="message-parameters"></span>
In a message to be translated, you can embed one or multiple placeholders so that they can be replaced by the given
parameter values. By giving different sets of parameter values, you can variate the translated message dynamically.
In a message to be translated, you can embed one or multiple parameters (also called placeholders) so that they can be
replaced by the given values. By giving different sets of values, you can variate the translated message dynamically.
In the following example, the placeholder `{username}` in the message `'Hello, {username}!'` will be replaced
by `'Alexander'` and `'Qiang'`, respectively.
@ -142,15 +142,15 @@ echo \Yii::t('app', 'Hello, {username}!', [
```
While translating a message containing placeholders, you should leave the placeholders as is. This is because the placeholders
will be replaced with the actual parameter values when you call `Yii::t()` to translate a message.
will be replaced with the actual values when you call `Yii::t()` to translate a message.
You can use either *named placeholders* or *positional placeholders*, but not both, in a single message.
The previous example shows how you can use named placeholders. That is, each placeholder is written in the format of
`{ParameterName}`, and you provide the parameters as an associative array whose keys are the parameter names
(without the curly brackets) and whose values are the corresponding parameter values.
`{name}`, and you provide an associative array whose keys are the placeholder names
(without the curly brackets) and whose values are the corresponding values placeholder to be replaced with.
Positional placeholders use zero-based integer sequence as placeholders which are replaced by the parameter values
Positional placeholders use zero-based integer sequence as names which are replaced by the provided values
according to their positions in the call of `Yii::t()`. In the following example, the positional placeholders
`{0}`, `{1}` and `{2}` will be replaced by the values of `$price`, `$count` and `$subtotal`, respectively.
@ -158,10 +158,16 @@ according to their positions in the call of `Yii::t()`. In the following example
$price = 100;
$count = 2;
$subtotal = 200;
echo \Yii::t('app', 'Price: {0}, Count: {1}, Subtotal: {2}', $price, $count, $subtotal);
echo \Yii::t('app', 'Price: {0}, Count: {1}, Subtotal: {2}', [$price, $count, $subtotal]);
```
> Tip: In most cases you should use named placeholders. This is because the parameter names will make the translators
In case of a single positional parameter its value could be specified without wrapping it into array:
```php
echo \Yii::t('app', 'Price: {0}', $price);
```
> Tip: In most cases you should use named placeholders. This is because the names will make the translators
> understand better the whole messages being translated.
@ -181,13 +187,17 @@ echo \Yii::t('app', 'Price: {0, number, currency}', $price);
You can use either the short form or the full form to specify a placeholder with formatting:
```
short form: {PlaceholderName, ParameterType}
full form: {PlaceholderName, ParameterType, ParameterStyle}
short form: {name, type}
full form: {name, type, style}
```
Please refer to the [ICU documentation](http://icu-project.org/apiref/icu4c/classMessageFormat.html) for the complete
instructions on how to specify such placeholders.
> Note: If you need to use special characters such as `{`, `}`, `'`, `#`, wrap them in `'`:
>
```php
echo Yii::t('app', "Example of string with ''-escaped characters'': '{' '}' '{test}' {count, plural, other{''count'' value is # '#{}'}}", ['count' => 3]);
```
Complete format is described in the [ICU documentation](http://icu-project.org/apiref/icu4c/classMessageFormat.html).
In the following we will show some common usages.
@ -214,8 +224,14 @@ $sum = 42;
echo \Yii::t('app', 'Balance: {0, number, ,000,000000}', $sum);
```
[Formatting reference](http://icu-project.org/apiref/icu4c/classicu_1_1DecimalFormat.html).
Characters used in the custom format could be found in
[ICU API reference](http://icu-project.org/apiref/icu4c/classicu_1_1DecimalFormat.html) under "Special Pattern Characters"
section.
The value is always formatted according to the locale you are translating to i.e. you cannot change decimal or thousands
separators, currency symbol etc. without changing translation locale. If you need to customize these you can
use [[yii\i18n\Formatter::asDecimal()]] and [[yii\i18n\Formatter::asCurrency()]].
#### Date <span id="date"></span>
@ -272,6 +288,18 @@ The parameter value should be treated as a number and formatted as a spellout. F
echo \Yii::t('app', '{n,number} is spelled as {n, spellout}', ['n' => 42]);
```
By default the number is spelled out as cardinal. It could be changed:
```php
// may produce "I am forty-seventh agent"
echo \Yii::t('app', 'I am {n, spellout,%spellout-ordinal} agent', ['n' => 47]);
```
Note that there should be no space after `spellout,` and before `%`.
To get a list of options available for locale you're using check
"Numbering schemas, Spellout" at [http://intl.rmcreative.ru/](http://intl.rmcreative.ru/).
#### Ordinal <span id="ordinal"></span>
The parameter value should be treated as a number and formatted as an ordinal name. For example,
@ -281,6 +309,17 @@ The parameter value should be treated as a number and formatted as an ordinal na
echo \Yii::t('app', 'You are the {n, ordinal} visitor here!', ['n' => 42]);
```
Ordinal supports more ways of formatting for languages such as Spanish:
```php
// may produce 471ª
echo \Yii::t('app', '{n, ordinal,%digits-ordinal-feminine}', ['n' => 471]);
```
Note that there should be no space after `ordinal,` and before `%`.
To get a list of options available for locale you're using check
"Numbering schemas, Ordinal" at [http://intl.rmcreative.ru/](http://intl.rmcreative.ru/).
#### Duration <span id="duration"></span>
@ -291,6 +330,17 @@ The parameter value should be treated as the number of seconds and formatted as
echo \Yii::t('app', 'You are here for {n, duration} already!', ['n' => 47]);
```
Duration supports more ways of formatting:
```php
// may produce 130:53:47
echo \Yii::t('app', '{n, duration,%in-numerals}', ['n' => 471227]);
```
Note that there should be no space after `duration,` and before `%`.
To get a list of options available for locale you're using check
"Numbering schemas, Duration" at [http://intl.rmcreative.ru/](http://intl.rmcreative.ru/).
#### Plural <span id="plural"></span>
@ -305,8 +355,8 @@ it is sufficient to provide the translation of inflected words in certain situat
echo \Yii::t('app', 'There {n, plural, =0{are no cats} =1{is one cat} other{are # cats}}!', ['n' => $n]);
```
In the plural rule arguments above, `=0` means exactly zero, `=1` means exactly one, and `other` is for any other value.
`#` is replaced with the value of `n`.
In the plural rule arguments above, `=` means explicit value. So `=0` means exactly zero, `=1` means exactly one.
`other` stands for any other value. `#` is replaced with the value of `n` formatted according to target language.
Plural forms can be very complicated in some languages. In the following Russian example, `=1` matches exactly `n = 1`
while `one` matches `21` or `101`:
@ -315,15 +365,54 @@ while `one` matches `21` or `101`:
Здесь {n, plural, =0{котов нет} =1{есть один кот} one{# кот} few{# кота} many{# котов} other{# кота}}!
```
Note that the above message is mainly used as a translated message, not an original message, unless you set
the [[yii\base\Application::$sourceLanguage|source language]] of your application as `ru-RU`.
These `other`, `few`, `many` and other special argument names vary depending on language. To learn which ones you should
specify for a particular locale, please refer to "Plural Rules, Cardinal" at [http://intl.rmcreative.ru/](http://intl.rmcreative.ru/).
Alternatively you can refer to [rules reference at unicode.org](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html).
> Note: The above example Russian message is mainly used as a translated message, not an original message, unless you set
> the [[yii\base\Application::$sourceLanguage|source language]] of your application as `ru-RU` and translating from Russian.
>
> When a translation is not found for an original message specified in `Yii::t()` call, the plural rules for the
> [[yii\base\Application::$sourceLanguage|source language]] will be applied to the original message.
There's an `offset` parameter for the cases when the string is like the following:
```php
$likeCount = 2;
echo Yii::t('app', 'You {likeCount, plural,
offset: 1
=0{did not like this}
=1{liked this}
one{and one other person liked this}
other{and # others liked this}
}', [
'likeCount' => $likeCount
]);
// You and one other person liked this
```
#### Ordinal selection <span id="ordinal-selection">
When a translation is not found for an original message, the plural rules for the [[yii\base\Application::$sourceLanguage|source language]]
will be applied to the original message.
The parameter type of `selectordinal` is meant to choose a string based on language rules for ordinals for the
locale you are translating to:
To learn which inflection forms you should specify for a particular language, please refer to the
[rules reference at unicode.org](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html).
```php
$n = 3;
echo Yii::t('app', 'You are the {n, selectordinal, one{#st} two{#nd} few{#rd} other{#th}} visitor', ['n' => $n]);
// For English it outputs:
// You are the 3rd visitor
// Translation
'You are the {n, selectordinal, one{#st} two{#nd} few{#rd} other{#th}} visitor' => 'Вы {n, selectordinal, other{#-й}} посетитель',
// For Russian translation it outputs:
// Вы 3-й посетитель
```
The format is very close to what's used for plurals. To learn which arguments you should specify for a particular locale,
please refer to "Plural Rules, Ordinal" at [http://intl.rmcreative.ru/](http://intl.rmcreative.ru/).
Alternatively you can refer to [rules reference at unicode.org](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html).
#### Selection <span id="selection"></span>
@ -342,7 +431,7 @@ do not match either one of them. Following each possible parameter value, you sh
it in a pair of curly brackets.
### Specifying default translation
### Specifying default translation <span id="default-translation"></span>
You can specify default translations that will be used as a fallback for categories that don't match any other translation.
This translation should be marked with `*`. In order to do it add the following to the application config:
@ -368,7 +457,7 @@ echo Yii::t('not_specified_category', 'message from unspecified category');
The message will be loaded from `@app/messages/<LanguageCode>/not_specified_category.php`.
### Translating module messages
### Translating module messages <span id="module-translation"></span>
If you want to translate the messages for a module and avoid using a single translation file for all the messages, you can do it like the following:
@ -415,7 +504,7 @@ In the example above we are using wildcard for matching and then filtering each
use the convention of the category mapping to the same named file.
Now you can use `Module::t('validation', 'your custom validation message')` or `Module::t('form', 'some form label')` directly.
### Translating widgets messages
### Translating widgets messages <span id="widget-translation"></span>
The same rule as applied for Modules above can be applied for widgets too, for example:
@ -468,7 +557,7 @@ Now you can use `Menu::t('messages', 'new messages {messages}', ['{messages}' =>
> **Note**: For widgets you also can use i18n views, with the same rules as for controllers being applied to them too.
### Translating framework messages
### Translating framework messages <span id="framework-translation"></span>
Yii comes with the default translation messages for validation errors and some other strings. These messages are all
in the category `yii`. Sometimes you want to correct the default framework message translation for your application.
@ -488,7 +577,7 @@ In order to do so, configure the `i18n` [application component](structure-applic
Now you can place your adjusted translations to `@app/messages/<language>/yii.php`.
### Handling missing translations
### Handling missing translations <span id="missing-translations"></span>
Even if the translation is missing from the source, Yii will display the requested message content. Such behavior is very convenient
in case your raw message is a valid verbose text. However, sometimes it is not enough.

5
docs/guide/tutorial-performance-tuning.md

@ -88,7 +88,10 @@ please refer to the [Assets](structure-assets.md) section.
## Optimizing Session Storage <span id="optimizing-session"></span>
By default session data are stored in files. This is fine for development and small projects. But when it comes
By default session data are stored in files. The implementation is locking a file from opening a session to the point it's
closed either by `session_write_close()` (in Yii it could be done as `Yii::$app->session->close()`) or at the end of request.
While session file is locked all other requests which are trying to use the same session are blocked i.e. waiting for the
initial request to release session file. This is fine for development and probably small projects. But when it comes
to handling massive concurrent requests, it is better to use more sophisticated storage, such as database. Yii supports
a variety of session storage out of box. You can use these storage by configuring the `session` component in the
[application configuration](concept-configurations.md) like the following,

2
docs/guide/tutorial-start-from-scratch.md

@ -50,6 +50,6 @@ Use the Template
That's all that's required to create a new Yii project template. Now you can create projects using your template:
```
composer global require "fxp/composer-asset-plugin:~1.0.0"
composer global require "fxp/composer-asset-plugin:~1.0.3"
composer create-project --prefer-dist --stability=dev mysoft/yii2-app-coolone new-project
```

2
docs/guide/tutorial-yii-integration.md

@ -82,7 +82,7 @@ take two steps: install Yii, and bootstrap Yii.
If the third-party system uses Composer to manage its dependencies, you can simply run the following commands
to install Yii:
composer global require "fxp/composer-asset-plugin:~1.0.0"
composer global require "fxp/composer-asset-plugin:~1.0.3"
composer require yiisoft/yii2
composer install

2
docs/internals-ja/git-workflow.md

@ -33,7 +33,7 @@ git remote add upstream git://github.com/yiisoft/yii2.git
- `composer update` を実行して、依存パッケージをインストールします ([composer をグローバルにインストール](https://getcomposer.org/doc/00-intro.md#globally) したものと仮定しています)。
> Note|注意: `Problem 1 The requested package bower-asset/jquery could not be found in any version, there may be a typo in the package name.` というようなエラーが生ずる場合は、`composer global require "fxp/composer-asset-plugin:~1.0.0"` を実行する必要があります。
> Note|注意: `Problem 1 The requested package bower-asset/jquery could not be found in any version, there may be a typo in the package name.` というようなエラーが生ずる場合は、`composer global require "fxp/composer-asset-plugin:~1.0.3"` を実行する必要があります。
- `php build/build dev/app basic` を実行して、ベーシックアプリケーションをクローンし、その依存パッケージをインストールします。
このコマンドは外部 composer パッケージは通常どおりインストールしますが、yii2 レポジトリは現在チェックアウトされているものをリンクします。

8
docs/internals-uk/translation-workflow.md

@ -76,7 +76,7 @@ php build translation "../docs/guide" "../docs/guide-uk" "Ukrainian guide transl
[Англійсько-українські словники](http://e2u.org.ua)
- action — дія;
- active record — (не перекладається);
- Active Record — (не перекладається);
- Advanced/Basic Project Template — Розширений/Базовий шаблон проекту;
- alias — псевдонім;
- alphanumeric — буквено-цифровий;
@ -93,7 +93,7 @@ php build translation "../docs/guide" "../docs/guide-uk" "Ukrainian guide transl
- branch — гілка;
- browser — браузер;
- (asset) bundle — колекція (ресурсів);
- cache — кеш;
- cache, caching — кеш, кешування;
- camel case — (не перекладається);
- case-sensitive — регістр-залежний;
- column — колонка;
@ -101,6 +101,7 @@ php build translation "../docs/guide" "../docs/guide-uk" "Ukrainian guide transl
- concatenation — конкатенація;
- configuration — конфігурація;
- content — вміст;
- content view — вкладене представлення;
- contributor — учасник;
- cookies — кукі;
- customization — (тонке) налаштування;
@ -130,6 +131,7 @@ php build translation "../docs/guide" "../docs/guide-uk" "Ukrainian guide transl
- getter — геттер;
- (event) handler — обробник (події);
- hash — хеш;
- header — шапка;
- help — довідка;
- helper — хелпер;
- id — ідентифікатор;
@ -181,12 +183,14 @@ php build translation "../docs/guide" "../docs/guide-uk" "Ukrainian guide transl
- sub-directory — під-директорія;
- substitution — підставлення/заміщення;
- tabular input — табличний ввід;
- tag — тег;
- template engine — шаблонізатор;
- theming — темізація;
- third party — сторонній;
- thumbnail — мініатюра;
- tracing — трасування;
- trait — трейт;
- trigger event — породжувати подію;
- Twitter — Твіттер;
- Unicode — (не перекладається);
- unit tests — модульні тести;

2
docs/internals/git-workflow.md

@ -35,7 +35,7 @@ The following steps are not necessary if you want to work only on translations o
- run `composer update` to install dependencies (assuming you have [composer installed globally](https://getcomposer.org/doc/00-intro.md#globally)).
> Note: If you see errors like `Problem 1 The requested package bower-asset/jquery could not be found in any version, there may be a typo in the package name.`, you will need to run `composer global require "fxp/composer-asset-plugin:~1.0.0"`
> Note: If you see errors like `Problem 1 The requested package bower-asset/jquery could not be found in any version, there may be a typo in the package name.`, you will need to run `composer global require "fxp/composer-asset-plugin:~1.0.3"`
- run `php build/build dev/app basic` to clone the basic app and install composer dependencies for the basic app.
This command will install foreign composer packages as normal but will link the yii2 repo to

16
framework/CHANGELOG.md

@ -6,11 +6,25 @@ Yii Framework 2 Change Log
- Bug #8723: Fixed `yii\helpers\VarDumper::export()` unable to export circle referenced objects with `Closure` (klimov-paul)
- Bug #9108: Negative number resulted in no formatting when using `Formatter::asSize()` or `Formatter::asShortSize` (nxnx, cebe)
- Bug #9288: Fixed `FileHelper::createDirectory` directory creation to be concurrency friendly (dynasource)
- Bug #9314: Fixed `yii\rbac\DbManager::getPermissionsByUser()` not returning permissions directly assigned to a user (hesna)
- Bug #9323: Fixed `yii\console\controllers\MessageController` not using database connection specified in config (raccoon69, samdark)
- Bug #9415: Fixed regression in 2.0.6 where on Oracle DB `PDO::ATTR_CASE = PDO::CASE_LOWER` did not work anymore (cebe)
- Bug #9442: Fixed `yii\db\Migration::renameTable()` caused fatal error when using SQLite driver (fetus-hina)
- Bug: Server response on invalid JSON request included a wrong message about "Internal Server Error" with status 500 (cebe)
- Bug #9583: Server response on invalid JSON request included a wrong message about "Internal Server Error" with status 500 (cebe)
- Bug #9591: Fixed `yii.validation.js` code so it is compressable by YUICompressor (samdark, hofrob)
- Bug #9596: Fixed `\yii\web\UrlManager::createAbsoluteUrl(['site/index', '#' => 'testHash'])` losing hash (alchimik, samdark)
- Bug #9678: `I18N::format()` wasn't able to handle named placeholder in "selectordinal" (samdark)
- Bug #9681: `Json::encode()` was erroring under CYGWIN (samdark)
- Bug #9714: Fixed `yii\rbac\PhpManager::updateItem()` unable to save users assignments (rezident1307)
- Bug #9754: Fixed `yii\web\Request` error when path info is empty (dynasource)
- Chg #9369: `Yii::$app->user->can()` now returns `false` instead of erroring in case `authManager` component is not configured (creocoder)
- Chg #9411: `DetailView` now automatically sets container tag ID in case it's not specified (samdark)
- Enh #2106: Added Unprocessable Entity HTTP Exception (janfrs)
- Enh #9476: Added DI injection via controller action method signature (mdmunir)
- Enh #9635: Added default CSS class for `\yii\grid\ActionColumn` header (arogachev, dynasource)
- Enh #9643: Added migrations for DB cache (mdmunir)
- Enh #9711: Added `yii\widgets\LinkPager::$pageCssClass` that allows to set default page class (ShNURoK42)
2.0.6 August 05, 2015

2
framework/assets/yii.activeForm.js

@ -135,7 +135,7 @@
name: undefined,
// the jQuery selector of the container of the input field
container: undefined,
// the jQuery selector of the input field under the context of the container
// the jQuery selector of the input field under the context of the form
input: undefined,
// the jQuery selector of the error tag under the context of the container
error: '.help-block',

2
framework/assets/yii.validation.js

@ -36,7 +36,7 @@ yii.validation = (function ($) {
}
},
boolean: function (value, messages, options) {
'boolean': function (value, messages, options) {
if (options.skipOnEmpty && pub.isEmpty(value)) {
return;
}

5
framework/base/Controller.php

@ -244,11 +244,14 @@ class Controller extends Component implements ViewContextInterface
* ```php
* public function beforeAction($action)
* {
* // your custom code here, if you want the code to run before action filters,
* // wich are triggered on the [[EVENT_BEFORE_ACTION]] event, e.g. PageCache or AccessControl
*
* if (!parent::beforeAction($action)) {
* return false;
* }
*
* // your custom code here
* // other custom code here
*
* return true; // or false to not run the action
* }

66
framework/caching/migrations/m150909_153426_cache_init.php

@ -0,0 +1,66 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
use yii\base\InvalidConfigException;
use yii\caching\DbCache;
use yii\db\Migration;
/**
* Initializes Cache tables
*
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
* @since 2.0
*/
class m150909_153426_cache_init extends Migration
{
/**
* @throws yii\base\InvalidConfigException
* @return DbCache
*/
protected function getCache()
{
$cache = Yii::$app->getCache();
if (!$cache instanceof DbCache) {
throw new InvalidConfigException('You should configure "cache" component to use database before executing this migration.');
}
return $cache;
}
/**
* @inheritdoc
*/
public function up()
{
$cache = $this->getCache();
$this->db = $cache->db;
$tableOptions = null;
if ($this->db->driverName === 'mysql') {
// http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci
$tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
}
$this->createTable($cache->cacheTable, [
'id' => $this->string(128)->notNull(),
'expire' => $this->integer(),
'data' => $this->binary(),
'PRIMARY KEY ([[id]])',
], $tableOptions);
}
/**
* @inheritdoc
*/
public function down()
{
$cache = $this->getCache();
$this->db = $cache->db;
$this->dropTable($cache->cacheTable);
}
}

20
framework/caching/migrations/schema-mssql.sql

@ -0,0 +1,20 @@
/**
* Database schema required by \yii\caching\DbCache.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
* @link http://www.yiiframework.com/
* @copyright 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
* @since 2.0
*/
drop table if exists [cache];
create table [cache]
(
[id] varchar(128) not null,
[expire] integer,
[data] BLOB,
primary key ([id])
);

20
framework/caching/migrations/schema-mysql.sql

@ -0,0 +1,20 @@
/**
* Database schema required by \yii\caching\DbCache.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
* @link http://www.yiiframework.com/
* @copyright 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
* @since 2.0
*/
drop table if exists `cache`;
create table `cache`
(
`id` varchar(128) not null,
`expire` integer,
`data` LONGBLOB,
primary key (`id`)
) engine InnoDB;

20
framework/caching/migrations/schema-oci.sql

@ -0,0 +1,20 @@
/**
* Database schema required by \yii\caching\DbCache.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
* @link http://www.yiiframework.com/
* @copyright 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
* @since 2.0
*/
drop table if exists "cache";
create table "cache"
(
"id" varchar(128) not null,
"expire" integer,
"data" BYTEA,
primary key ("id")
);

20
framework/caching/migrations/schema-pgsql.sql

@ -0,0 +1,20 @@
/**
* Database schema required by \yii\caching\DbCache.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
* @link http://www.yiiframework.com/
* @copyright 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
* @since 2.0
*/
drop table if exists "cache";
create table "cache"
(
"id" varchar(128) not null,
"expire" integer,
"data" BLOB,
primary key ("id")
);

20
framework/caching/migrations/schema-sqlite.sql

@ -0,0 +1,20 @@
/**
* Database schema required by \yii\caching\DbCache.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
* @link http://www.yiiframework.com/
* @copyright 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
* @since 2.0
*/
drop table if exists "cache";
create table "cache"
(
"id" varchar(128) not null,
"expire" integer,
"data" BLOB,
primary key ("id")
);

1
framework/composer.json

@ -54,6 +54,7 @@
"require": {
"php": ">=5.4.0",
"ext-mbstring": "*",
"ext-ctype": "*",
"lib-pcre": "*",
"yiisoft/yii2-composer": "*",
"ezyang/htmlpurifier": "4.6.*",

19
framework/console/Controller.php

@ -109,14 +109,25 @@ class Controller extends \yii\base\Controller
$method = new \ReflectionMethod($action, 'run');
}
$args = array_values($params);
$params = array_values($params);
$args = [];
$missing = [];
foreach ($method->getParameters() as $i => $param) {
if ($param->isArray() && isset($args[$i])) {
$args[$i] = preg_split('/\s*,\s*/', $args[$i]);
if (($class = $param->getClass()) !== null) {
$name = $param->getName();
$className = $class->getName();
if (Yii::$app->has($name) && ($obj = Yii::$app->get($name)) instanceof $className) {
$args[$i] = $obj;
} else {
$args[$i] = Yii::$container->get($className);
}
continue;
}
if (!isset($args[$i])) {
$value = array_shift($params);
if (isset($value)) {
$args[$i] = $param->isArray() ? preg_split('/\s*,\s*/', $value) : $value;
} else {
if ($param->isDefaultValueAvailable()) {
$args[$i] = $param->getDefaultValue();
} else {

2
framework/console/controllers/MessageController.php

@ -172,7 +172,7 @@ class MessageController extends Controller
$q = new \yii\db\Query;
$current = [];
foreach ($q->select(['id', 'category', 'message'])->from($sourceMessageTable)->all() as $row) {
foreach ($q->select(['id', 'category', 'message'])->from($sourceMessageTable)->all($db) as $row) {
$current[$row['category']][$row['id']] = $row['message'];
}

2
framework/data/BaseDataProvider.php

@ -33,7 +33,7 @@ abstract class BaseDataProvider extends Component implements DataProviderInterfa
/**
* @var string an ID that uniquely identifies the data provider among all data providers.
* You should set this property if the same page contains two or more different data providers.
* Otherwise, the [[pagination]] and [[sort]] mainly not work properly.
* Otherwise, the [[pagination]] and [[sort]] may not work properly.
*/
public $id;

16
framework/db/Query.php

@ -478,6 +478,22 @@ class Query extends Component implements QueryInterface
* Use a Query object to represent a sub-query. In this case, the corresponding array key will be used
* as the alias for the sub-query.
*
* Here are some examples:
*
* ```php
* // SELECT * FROM `user` `u`, `profile`;
* $query = (new \yii\db\Query)->from(['u' => 'user', 'profile']);
*
* // SELECT * FROM (SELECT * FROM `user` WHERE `active` = 1) `activeusers`;
* $subquery = (new \yii\db\Query)->from('user')->where(['active' => true])
* $query = (new \yii\db\Query)->from(['activeusers' => $subquery]);
*
* // subquery can also be a string with plain SQL wrapped in parenthesis
* // SELECT * FROM (SELECT * FROM `user` WHERE `active` = 1) `activeusers`;
* $subquery = "(SELECT * FROM `user` WHERE `active` = 1)";
* $query = (new \yii\db\Query)->from(['activeusers' => $subquery]);
* ```
*
* @return $this the query object itself
*/
public function from($tables)

4
framework/filters/AccessRule.php

@ -31,8 +31,8 @@ class AccessRule extends Component
*/
public $actions;
/**
* @var array list of controller IDs that this rule applies to. The comparison is case-sensitive.
* If not set or empty, it means this rule applies to all controllers.
* @var array list of the controller IDs that this rule applies to. Each controller ID is prefixed with the module ID (if any).
* The comparison is case-sensitive. If not set or empty, it means this rule applies to all controllers.
*/
public $controllers;
/**

4
framework/grid/ActionColumn.php

@ -33,6 +33,10 @@ use yii\helpers\Url;
class ActionColumn extends Column
{
/**
* @inheritdoc
*/
public $headerOptions = ['class' => 'action-column'];
/**
* @var string the ID of the controller that should handle the actions specified here.
* If not set, it will use the currently active controller. This property is mainly used by
* [[urlCreator]] to create URLs for different actions. The value of this property will be prefixed

18
framework/helpers/BaseFileHelper.php

@ -447,7 +447,7 @@ class BaseFileHelper
* @param integer $mode the permission to be set for the created directory.
* @param boolean $recursive whether to create parent directories if they do not exist.
* @return boolean whether the directory is created successfully
* @throws \yii\base\Exception if the directory could not be created.
* @throws \yii\base\Exception if the directory could not be created (i.e. php error due to parallel changes)
*/
public static function createDirectory($path, $mode = 0775, $recursive = true)
{
@ -459,13 +459,19 @@ class BaseFileHelper
static::createDirectory($parentDir, $mode, true);
}
try {
$result = mkdir($path, $mode);
chmod($path, $mode);
if (!mkdir($path, $mode)) {
return false;
}
} catch (\Exception $e) {
throw new \yii\base\Exception("Failed to create directory '$path': " . $e->getMessage(), $e->getCode(), $e);
if (!is_dir($path)) {// https://github.com/yiisoft/yii2/issues/9288
throw new \yii\base\Exception("Failed to create directory \"$path\": " . $e->getMessage(), $e->getCode(), $e);
}
}
try {
return chmod($path, $mode);
} catch (\Exception $e) {
throw new \yii\base\Exception("Failed to change permissions for directory \"$path\": " . $e->getMessage(), $e->getCode(), $e);
}
return $result;
}
/**

2
framework/helpers/BaseJson.php

@ -35,7 +35,7 @@ class BaseJson
public static function encode($value, $options = 320)
{
$expressions = [];
$value = static::processData($value, $expressions, uniqid('', false));
$value = static::processData($value, $expressions, uniqid('', true));
$json = json_encode($value, $options);
static::handleJsonError(json_last_error());

20
framework/i18n/Formatter.php

@ -95,7 +95,7 @@ class Formatter extends Component
*
* It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime#TOC-Date-Time-Format-Syntax).
* Alternatively this can be a string prefixed with `php:` representing a format that can be recognized by the
* PHP [date()](http://php.net/manual/de/function.date.php)-function.
* PHP [date()](http://php.net/manual/en/function.date.php)-function.
*
* For example:
*
@ -111,7 +111,7 @@ class Formatter extends Component
*
* It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime#TOC-Date-Time-Format-Syntax).
* Alternatively this can be a string prefixed with `php:` representing a format that can be recognized by the
* PHP [date()](http://php.net/manual/de/function.date.php)-function.
* PHP [date()](http://php.net/manual/en/function.date.php)-function.
*
* For example:
*
@ -128,7 +128,7 @@ class Formatter extends Component
* It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime#TOC-Date-Time-Format-Syntax).
*
* Alternatively this can be a string prefixed with `php:` representing a format that can be recognized by the
* PHP [date()](http://php.net/manual/de/function.date.php)-function.
* PHP [date()](http://php.net/manual/en/function.date.php)-function.
*
* For example:
*
@ -196,7 +196,7 @@ class Formatter extends Component
* Please refer to the [PHP manual](http://php.net/manual/en/class.numberformatter.php#intl.numberformatter-constants.unumberformatsymbol)
* for the possible options.
*
* For example to choose a custom currency symbol, e.g. [U+20BD](http://unicode-table.com/de/20BD/) instead of `руб.` for Russian Ruble:
* For example to choose a custom currency symbol, e.g. [U+20BD](http://unicode-table.com/en/20BD/) instead of `руб.` for Russian Ruble:
*
* ```php
* [
@ -447,7 +447,7 @@ class Formatter extends Component
* It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime).
*
* Alternatively this can be a string prefixed with `php:` representing a format that can be recognized by the
* PHP [date()](http://php.net/manual/de/function.date.php)-function.
* PHP [date()](http://php.net/manual/en/function.date.php)-function.
*
* @return string the formatted result.
* @throws InvalidParamException if the input value can not be evaluated as a date value.
@ -479,7 +479,7 @@ class Formatter extends Component
* It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime).
*
* Alternatively this can be a string prefixed with `php:` representing a format that can be recognized by the
* PHP [date()](http://php.net/manual/de/function.date.php)-function.
* PHP [date()](http://php.net/manual/en/function.date.php)-function.
*
* @return string the formatted result.
* @throws InvalidParamException if the input value can not be evaluated as a date value.
@ -511,7 +511,7 @@ class Formatter extends Component
* It can also be a custom format as specified in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime).
*
* Alternatively this can be a string prefixed with `php:` representing a format that can be recognized by the
* PHP [date()](http://php.net/manual/de/function.date.php)-function.
* PHP [date()](http://php.net/manual/en/function.date.php)-function.
*
* @return string the formatted result.
* @throws InvalidParamException if the input value can not be evaluated as a date value.
@ -1170,9 +1170,9 @@ class Formatter extends Component
/**
* Normalizes a numeric input value
*
* - everything [empty](http://php.net/manual/de/function.empty.php) will result in `0`
* - a [numeric](http://php.net/manual/de/function.is-numeric.php) string will be casted to float
* - everything else will be returned if it is [numeric](http://php.net/manual/de/function.is-numeric.php),
* - everything [empty](http://php.net/manual/en/function.empty.php) will result in `0`
* - a [numeric](http://php.net/manual/en/function.is-numeric.php) string will be casted to float
* - everything else will be returned if it is [numeric](http://php.net/manual/en/function.is-numeric.php),
* otherwise an exception is thrown.
*
* @param mixed $value the input value

8
framework/i18n/MessageFormatter.php

@ -93,11 +93,9 @@ class MessageFormatter extends Component
return $this->fallbackFormat($pattern, $params, $language);
}
if (version_compare(PHP_VERSION, '5.5.0', '<') || version_compare(INTL_ICU_VERSION, '4.8', '<')) {
// replace named arguments
$pattern = $this->replaceNamedArguments($pattern, $params, $newParams);
$params = $newParams;
}
// replace named arguments (https://github.com/yiisoft/yii2/issues/9678)
$pattern = $this->replaceNamedArguments($pattern, $params, $newParams);
$params = $newParams;
$formatter = new \MessageFormatter($language, $pattern);
if ($formatter === null) {

2
framework/messages/config.php

@ -7,7 +7,7 @@ return [
'messagePath' => __DIR__,
// array, required, list of language codes that the extracted messages
// should be translated to. For example, ['zh-CN', 'de'].
'languages' => ['ar', 'az', 'bg', 'bs', 'ca', 'cs', 'da', 'de', 'el', 'es', 'et', 'fa', 'fi', 'fr', 'he', 'hu', 'id', 'it', 'ja', 'ka', 'kk', 'ko', 'lt', 'lv', 'ms', 'nb-NO', 'nl', 'pl', 'pt', 'pt-BR', 'ro', 'ru', 'sk', 'sl', 'sr', 'sr-Latn', 'sv', 'th', 'tj', 'uk', 'vi', 'zh-CN','zh-TW'],
'languages' => ['ar', 'az', 'bg', 'bs', 'ca', 'cs', 'da', 'de', 'el', 'es', 'et', 'fa', 'fi', 'fr', 'he', 'hr', 'hu', 'id', 'it', 'ja', 'ka', 'kk', 'ko', 'lt', 'lv', 'ms', 'nb-NO', 'nl', 'pl', 'pt', 'pt-BR', 'ro', 'ru', 'sk', 'sl', 'sr', 'sr-Latn', 'sv', 'th', 'tj', 'uk', 'vi', 'zh-CN','zh-TW'],
// string, the name of the function for translating messages.
// Defaults to 'Yii::t'. This is used as a mark to find the messages to be
// translated. You may use a string for single function name or an array for

105
framework/messages/hr/yii.php

@ -0,0 +1,105 @@
<?php
/**
* Message translations.
*
* This file is automatically generated by 'yii message' command.
* It contains the localizable messages extracted from source code.
* You may modify this file by translating the extracted messages.
*
* Each array element represents the translation (value) of a message (key).
* If the value is empty, the message is considered as not translated.
* Messages that no longer need translation will have their translations
* enclosed between a pair of '@@' marks.
*
* Message string can be used with plural forms format. Check i18n section
* of the guide for details.
*
* NOTE: this file must be saved in UTF-8 encoding.
*/
return [
'(not set)' => '(nije postavljeno)',
'An internal server error occurred.' => 'Došlo je to interne pogreške servera.',
'Are you sure you want to delete this item' => 'Želiš li to obrisati?',
'Delete' => 'Obrisati',
'Error' => 'Pogreška',
'File upload failed.' => 'Upload podatka nije uspio.',
'Home' => 'Home',
'Invalid data received for parameter "{param}".' => 'Nevažeći podaci primljeni za parametar "{param}"',
'Login Required' => 'Prijava potrebna',
'Missing required arguments: {params}' => 'Nedostaju potrebni argunenti: {params}',
'Missing required parameters: {params}' => 'Falten paràmetres requerits: {params}',
'No' => 'Ne',
'No help for unknown command "{command}".' => 'Nema pomoći za nepoznatu naredbu "{command}"',
'No help for unknown sub-command "{command}".' => 'Nema pomoći za nepoznatu pod-naredbu "{command}"',
'No results found.' => 'Nema rezultata.',
'Only files with these MIME types are allowed: {mimeTypes}.' => 'Samo datoteke s ovim MIME vrstama su dopuštene: {mimeTypes}.',
'Only files with these extensions are allowed: {extensions}.' => 'Samo datoteke s ovim eksentinzijama su dopuštene:: {extensions}',
'Page not found.' => 'Stranica nije pronađena.',
'Please fix the following errors:' => 'Molimo vas ispravite pogreške:',
'Please upload a file.' => 'Molimo vas da uploadate datoteku.',
'Showing <b>{begin, number}-{end, number}</b> of <b>{totalCount, number}</b> {totalCount, plural, one{item} other{items}}.' => 'Prikazuj <b>{begin, number}-{end, number}</b> od <b>{totalCount, number}</b> {totalCount, plural, one{red} other{redova}}.',
'The file "{file}" is not an image.' => 'Podatak "{file}" nije slika.',
'The file "{file}" is too big. Its size cannot exceed {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'Podatak "{file}" je prevelik.Nesmije biti veči od {limit, number} {limit, plural, one{byte} other{bytes}}.',
'The file "{file}" is too small. Its size cannot be smaller than {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'Podatak "{file}" je premalen. Nesmije biti manji od {limit, number} {limit, plural, one{byte} other{bytes}}.',
'The format of {attribute} is invalid.' => 'Format od {attribute} je nevažeći.',
'The image "{file}" is too large. The height cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Slika "{file}" je prevelika. Visina slike nesmije biti veča od {limit, number} {limit, plural, one{piksel} other{piksela}}.',
'The image "{file}" is too large. The width cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Slika "{file}" je prevelika. Širina slike nesmije biti veča od {limit, number} {limit, plural, one{piksel} other{piksela}}.',
'The image "{file}" is too small. The height cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Slika "{file}" je premalena. Visina slike nesmije biti manja od {limit, number} {limit, plural, one{piksel} other{piksela}}.',
'The image "{file}" is too small. The width cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Slika "{file}" je premalena. Širina slike nesmije biti manja od {limit, number} {limit, plural, one{piksel} other{piksela}}.',
'The verification code is incorrect.' => 'Kod za provjeru nije točan.',
'Total <b>{count, number}</b> {count, plural, one{item} other{items}}.' => 'Ukupni <b>{count, number}</b> {count, plural, one{red} other{redova}}.',
'Unable to verify your data submission.' => 'Nije moguće provjeriti podnesene podatke.',
'Unknown command "{command}".' => 'Nepoznata naredba "{command}".',
'Unknown option: --{name}' => 'Nepoznata opcija: --{name}',
'Update' => 'Actualitzar',
'View' => 'Pregled',
'Yes' => 'Da',
'You are not allowed to perform this action.' => 'Nije vam dopušteno obavljati tu radnju.',
'You can upload at most {limit, number} {limit, plural, one{file} other{files}}.' => 'Najviše možete uploadat {limit, number} {limit, plural, one{arxiu} other{arxius}}.',
'in {delta, plural, =1{a day} other{# days}}' => 'u {delta, plural, =1{un dia} other{# dies}}',
'in {delta, plural, =1{a minute} other{# minutes}}' => 'u {delta, plural, =1{un minut} other{# minuts}}',
'in {delta, plural, =1{a month} other{# months}}' => 'u {delta, plural, =1{un mes} other{# mesos}}',
'in {delta, plural, =1{a second} other{# seconds}}' => 'u {delta, plural, =1{un segon} other{# segons}}',
'in {delta, plural, =1{a year} other{# years}}' => 'u {delta, plural, =1{un any} other{# anys}}',
'in {delta, plural, =1{an hour} other{# hours}}' => 'u {delta, plural, =1{una hora} other{# hores}}',
'the input value' => 'ulazna vrijednost',
'{attribute} "{value}" has already been taken.' => '{attribute} "{value}" već se koristi.',
'{attribute} cannot be blank.' => '{attribute} nesmije biti prazno.',
'{attribute} is invalid.' => '{attribute} je neispravan.',
'{attribute} is not a valid URL.' => '{attribute} nije valjan URL.',
'{attribute} is not a valid email address.' => '{attribute} nije valjana email adresa.',
'{attribute} must be "{requiredValue}".' => '{attribute} mora biti "{requiredValue}".',
'{attribute} must be a number.' => '{attribute} mora biti broj.',
'{attribute} must be a string.' => '{attribute} mora biti string(riječ,tekst).',
'{attribute} must be an integer.' => '{attribute} mora biti cijeli broj.',
'{attribute} must be either "{true}" or "{false}".' => '{attribute} mora biti "{true}" ili "{false}".',
'{attribute} must be greater than "{compareValue}".' => '{attribute} mora biti veči od "{compareValue}',
'{attribute} must be greater than or equal to "{compareValue}".' => '{attribute} mora biti veči ili jednak "{compareValue}".',
'{attribute} must be less than "{compareValue}".' => '{attribute} mora biti manji od "{compareValue}".',
'{attribute} must be less than or equal to "{compareValue}".' => '{attribute} mora biti jednak "{compareValue}".',
'{attribute} must be no greater than {max}.' => '{attribute} nesmije biti veči od {max}.',
'{attribute} must be no less than {min}.' => '{attribute} nesmije biti manji od {min}.',
'{attribute} must be repeated exactly.' => '{attribute} mora biti ponovljeno.',
'{attribute} must not be equal to "{compareValue}".' => '{attribute} nesmije biti jednnak "{compareValue}".',
'{attribute} should contain at least {min, number} {min, plural, one{character} other{characters}}.' => '{attribute} mora najmanje sadržavati {min, number} {min, plural, one{znak} other{znakova}}.',
'{attribute} should contain at most {max, number} {max, plural, one{character} other{characters}}.' => '{attribute} moze sadržavati do {max, number} {max, plural, one{znak} other{znakova}}.',
'{attribute} should contain {length, number} {length, plural, one{character} other{characters}}.' => '{attribute} mora sadržavati {length, number} {length, plural, one{znak} other{znakova}}.',
'{delta, plural, =1{a day} other{# days}} ago' => '{delta, plural, =1{dan} other{# dana}}',
'{delta, plural, =1{a minute} other{# minutes}} ago' => '{delta, plural, =1{minuta} other{# minuta}}',
'{delta, plural, =1{a month} other{# months}} ago' => '{delta, plural, =1{mjesec} other{# mjeseci}}',
'{delta, plural, =1{a second} other{# seconds}} ago' => '{delta, plural, =1{sekunda} other{# sekundi}}',
'{delta, plural, =1{a year} other{# years}} ago' => '{delta, plural, =1{un godine} other{# godina}}',
'{delta, plural, =1{an hour} other{# hours}} ago' => ' {delta, plural, =1{sat} other{# sati}}',
'{n, plural, =1{# byte} other{# bytes}}' => '{n, plural, =1{# byte} other{# bytes}}',
'{n, plural, =1{# gigabyte} other{# gigabytes}}' => '{n, plural, =1{# gigabyte} other{# gigabytes}}',
'{n, plural, =1{# kilobyte} other{# kilobytes}}' => '{n, plural, =1{# kilobyte} other{# kilobytes}}',
'{n, plural, =1{# megabyte} other{# megabytes}}' => '{n, plural, =1{# megabyte} other{# megabytes}}',
'{n, plural, =1{# petabyte} other{# petabytes}}' => '{n, plural, =1{# petabyte} other{# petabytes}}',
'{n, plural, =1{# terabyte} other{# terabytes}}' => '{n, plural, =1{# terabyte} other{# terabytes}}',
'{n} B' => '{n} B',
'{n} GB' => '{n} GB',
'{n} KB' => '{n} KB',
'{n} MB' => '{n} MB',
'{n} PB' => '{n} PB',
'{n} TB' => '{n} TB',
];

6
framework/messages/nl/yii.php

@ -19,7 +19,7 @@
return [
'(not set)' => '(niet ingesteld)',
'An internal server error occurred.' => 'Er is een interne serverfout opgetreden.',
'Are you sure you want to delete this item?' => 'Ben je zeker dat je dit item wilt verwijderen?',
'Are you sure you want to delete this item?' => 'Weet je zeker dat je dit item wilt verwijderen?',
'Delete' => 'Verwijderen',
'Error' => 'Fout',
'File upload failed.' => 'Bestand uploaden mislukt.',
@ -30,7 +30,7 @@ return [
'Missing required parameters: {params}' => 'Ontbrekende vereiste parameters: {params}',
'No' => 'Nee',
'No results found.' => 'Geen resultaten gevonden',
'Only files with these MIME types are allowed: {mimeTypes}.' => 'Alleen bestanden met de volgende MIME types zijn toegelaten: {mimeTypes}',
'Only files with these MIME types are allowed: {mimeTypes}.' => 'Alleen bestanden met de volgende MIME types zijn toegestaan: {mimeTypes}',
'Only files with these extensions are allowed: {extensions}.' => 'Alleen bestanden met de volgende extensies zijn toegestaan: {extensions}.',
'Page not found.' => 'Pagina niet gevonden.',
'Please fix the following errors:' => 'Corrigeer de volgende fouten:',
@ -59,7 +59,7 @@ return [
'in {delta, plural, =1{a month} other{# months}}' => 'binnen {delta, plural, =1{een maand} other{# maanden}}',
'in {delta, plural, =1{a second} other{# seconds}}' => 'binnen {delta, plural, =1{een seconde} other{# seconden}}',
'in {delta, plural, =1{a year} other{# years}}' => 'binnen {delta, plural, =1{een jaar} other{# jaren}}',
'in {delta, plural, =1{an hour} other{# hours}}' => 'binnen {delta, plural, =1{een uur} other{# uren}}',
'in {delta, plural, =1{an hour} other{# hours}}' => 'binnen {delta, plural, =1{een uur} other{# uur}}',
'just now' => 'zojuist',
'the input value' => 'de invoerwaarde',
'{attribute} "{value}" has already been taken.' => '{attribute} "{value}" is reeds in gebruik.',

2
framework/messages/sr/yii.php

@ -63,7 +63,7 @@ return [
'Page not found.' => 'Страница није пронађена.',
'Please fix the following errors:' => 'Молимо вас исправите следеће грешке:',
'Please upload a file.' => 'Молимо вас поставите фајл.',
'Showing <b>{begin, number}-{end, number}</b> of <b>{totalCount, number}</b> {totalCount, plural, one{item} other{items}}.' => 'Приказано <b>{begin, number}-{end, number}</b> од <b>{totalCount, plural, =1{# ставке} one{# ставкe} few{# ставке} many{# ставки} other{# ставки}}</b>.',
'Showing <b>{begin, number}-{end, number}</b> of <b>{totalCount, number}</b> {totalCount, plural, one{item} other{items}}.' => 'Приказано <b>{begin, number}-{end, number}</b> од <b>{totalCount, number}</b> {totalCount, plural, one{ред} other{редова}}.',
'The file "{file}" is not an image.' => 'Фајл "{file}" није слика.',
'The file "{file}" is too big. Its size cannot exceed {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'Фајл "{file}" је превелик. Величина не може бити већа од {limit, number} {limit, plural, one{бајт} few{бајтa} other{бајтa}}.',
'The file "{file}" is too small. Its size cannot be smaller than {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'Фајл "{file}" је премали. Величина не може бити мања од {limit, number} {limit, plural, one{бајт} few{бајтa} other{бајтa}}.',

13
framework/messages/zh-TW/yii.php

@ -77,4 +77,17 @@ return [
'{attribute} should contain at least {min, number} {min, plural, one{character} other{characters}}.' => '{attribute} 應該包含至少 {min, number} 個字符。',
'{attribute} should contain at most {max, number} {max, plural, one{character} other{characters}}.' => '{attribute} 只能包含最多 {max, number} 個字符。',
'{attribute} should contain {length, number} {length, plural, one{character} other{characters}}.' => '{attribute} 應該包含 {length, number} 個字符。',
'in {delta, plural, =1{a year} other{# years}}' => '{delta}年後',
'in {delta, plural, =1{a month} other{# months}}' => '{delta}個月後',
'in {delta, plural, =1{a day} other{# days}}' => '{delta}天後',
'in {delta, plural, =1{an hour} other{# hours}}' => '{delta}小時後',
'in {delta, plural, =1{a minute} other{# minutes}}' => '{delta}分鐘後',
'in {delta, plural, =1{a second} other{# seconds}}' => '{delta}秒後',
'{delta, plural, =1{a year} other{# years}} ago' => '{delta}年前',
'{delta, plural, =1{a month} other{# months}} ago' => '{delta}個月前',
'{delta, plural, =1{a day} other{# days}} ago' => '{delta}天前',
'{delta, plural, =1{an hour} other{# hours}} ago' => '{delta}小時前',
'{delta, plural, =1{a minute} other{# minutes}} ago' => '{delta}分鐘前',
'just now' => '剛剛',
'{delta, plural, =1{a second} other{# seconds}} ago' => '{delta}秒前',
];

37
framework/rbac/DbManager.php

@ -501,6 +501,43 @@ class DbManager extends BaseManager
return [];
}
$directPermission = $this->getDirectPermissionsByUser($userId);
$inheritedPermission = $this->getInheritedPermissionsByUser($userId);
return array_merge($directPermission, $inheritedPermission);
}
/**
* Returns all permissions that are directly assigned to user.
* @param string|integer $userId the user ID (see [[\yii\web\User::id]])
* @return Permission[] all direct permissions that the user has. The array is indexed by the permission names.
*
* @since 2.0.7
*/
protected function getDirectPermissionsByUser($userId)
{
$query = (new Query)->select('b.*')
->from(['a' => $this->assignmentTable, 'b' => $this->itemTable])
->where('{{a}}.[[item_name]]={{b}}.[[name]]')
->andWhere(['a.user_id' => (string) $userId])
->andWhere(['b.type' => Item::TYPE_PERMISSION]);
$permissions = [];
foreach ($query->all($this->db) as $row) {
$permissions[$row['name']] = $this->populateItem($row);
}
return $permissions;
}
/**
* Returns all permissions that the user inherits from the roles assigned to him.
* @param string|integer $userId the user ID (see [[\yii\web\User::id]])
* @return Permission[] all inherited permissions that the user has. The array is indexed by the permission names.
*
* @since 2.0.7
*/
protected function getInheritedPermissionsByUser($userId)
{
$query = (new Query)->select('item_name')
->from($this->assignmentTable)
->where(['user_id' => (string) $userId]);

2
framework/rbac/ManagerInterface.php

@ -84,7 +84,7 @@ interface ManagerInterface
* Returns the roles that are assigned to the user via [[assign()]].
* Note that child roles that are not assigned directly to the user will not be returned.
* @param string|integer $userId the user ID (see [[\yii\web\User::id]])
* @return Role[] all roles directly or indirectly assigned to the user. The array is indexed by the role names.
* @return Role[] all roles directly assigned to the user. The array is indexed by the role names.
*/
public function getRolesByUser($userId);

37
framework/rbac/PhpManager.php

@ -426,6 +426,41 @@ class PhpManager extends BaseManager
*/
public function getPermissionsByUser($userId)
{
$directPermission = $this->getDirectPermissionsByUser($userId);
$inheritedPermission = $this->getInheritedPermissionsByUser($userId);
return array_merge($directPermission, $inheritedPermission);
}
/**
* Returns all permissions that are directly assigned to user.
* @param string|integer $userId the user ID (see [[\yii\web\User::id]])
* @return Permission[] all direct permissions that the user has. The array is indexed by the permission names.
*
* @since 2.0.7
*/
protected function getDirectPermissionsByUser($userId)
{
$permissions = [];
foreach ($this->getAssignments($userId) as $name => $assignment) {
$permission = $this->items[$assignment->roleName];
if ($permission->type === Item::TYPE_PERMISSION) {
$permissions[$name] = $permission;
}
}
return $permissions;
}
/**
* Returns all permissions that the user inherits from the roles assigned to him.
* @param string|integer $userId the user ID (see [[\yii\web\User::id]])
* @return Permission[] all inherited permissions that the user has. The array is indexed by the permission names.
*
* @since 2.0.7
*/
protected function getInheritedPermissionsByUser($userId)
{
$assignments = $this->getAssignments($userId);
$result = [];
foreach (array_keys($assignments) as $roleName) {
@ -594,9 +629,11 @@ class PhpManager extends BaseManager
foreach ($this->assignments as &$assignments) {
if (isset($assignments[$name])) {
$assignments[$item->name] = $assignments[$name];
$assignments[$item->name]->roleName = $item->name;
unset($assignments[$name]);
}
}
$this->saveAssignments();
}
}

7
framework/rbac/migrations/m140506_102106_rbac_init.php

@ -6,7 +6,6 @@
*/
use yii\base\InvalidConfigException;
use yii\db\Schema;
use yii\rbac\DbManager;
/**
@ -30,6 +29,9 @@ class m140506_102106_rbac_init extends \yii\db\Migration
return $authManager;
}
/**
* @inheritdoc
*/
public function up()
{
$authManager = $this->getAuthManager();
@ -79,6 +81,9 @@ class m140506_102106_rbac_init extends \yii\db\Migration
], $tableOptions);
}
/**
* @inheritdoc
*/
public function down()
{
$authManager = $this->getAuthManager();

14
framework/validators/Validator.php

@ -156,7 +156,8 @@ class Validator extends Component
/**
* @var string a JavaScript function name whose return value determines whether this validator should be applied
* on the client side. The signature of the function should be `function (attribute, value)`, where
* `attribute` is the name of the attribute being validated and `value` the current value of the attribute.
* `attribute` is an object describing the attribute being validated (see [[clientValidateAttribute()]])
* and `value` the current value of the attribute.
*
* This property is mainly provided to support conditional validation on the client side.
* If this property is not set, this validator will be always applied on the client side.
@ -300,10 +301,19 @@ class Validator extends Component
*
* The following JavaScript variables are predefined and can be used in the validation code:
*
* - `attribute`: the name of the attribute being validated.
* - `attribute`: an object describing the the attribute being validated.
* - `value`: the value being validated.
* - `messages`: an array used to hold the validation error messages for the attribute.
* - `deferred`: an array used to hold deferred objects for asynchronous validation
* - `$form`: a jQuery object containing the form element
*
* The `attribute` object contains the following properties:
* - `id`: a unique ID identifying the attribute (e.g. "loginform-username") in the form
* - `name`: attribute name or expression (e.g. "[0]content" for tabular input)
* - `container`: the jQuery selector of the container of the input field
* - `input`: the jQuery selector of the input field under the context of the form
* - `error`: the jQuery selector of the error tag under the context of the container
* - `status`: status of the input field, 0: empty, not entered before, 1: validated, 2: pending validation, 3: validating
*
* @param \yii\base\Model $model the data model being validated
* @param string $attribute the name of the attribute to be validated.

9
framework/web/Controller.php

@ -71,7 +71,14 @@ class Controller extends \yii\base\Controller
$actionParams = [];
foreach ($method->getParameters() as $param) {
$name = $param->getName();
if (array_key_exists($name, $params)) {
if (($class = $param->getClass()) !== null) {
$className = $class->getName();
if (Yii::$app->has($name) && ($obj = Yii::$app->get($name)) instanceof $className) {
$args[] = $actionParams[$name] = $obj;
}else{
$args[] = $actionParams[$name] = Yii::$container->get($className);
}
} elseif (array_key_exists($name, $params)) {
if ($param->isArray()) {
$args[] = $actionParams[$name] = (array) $params[$name];
} elseif (!is_array($params[$name])) {

2
framework/web/Request.php

@ -723,7 +723,7 @@ class Request extends \yii\base\Request
throw new InvalidConfigException('Unable to determine the path info of the current request.');
}
if ($pathInfo[0] === '/') {
if (substr($pathInfo, 0, 1) === '/') {
$pathInfo = substr($pathInfo, 1);
}

35
framework/web/UnprocessableEntityHttpException.php

@ -0,0 +1,35 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\web;
/**
* UnprocessableEntityHttpException represents an "Unprocessable Entity" HTTP
* exception with status code 422.
*
* Use this exception to inform that the server understands the content type of
* the request entity and the syntax of that request entity is correct but the server
* was unable to process the contained instructions. For example, to return form
* validation errors.
*
* @link http://www.webdav.org/specs/rfc2518.html#STATUS_422
* @author Jan Silva <janfrs3@gmail.com>
* @since 2.0.7
*/
class UnprocessableEntityHttpException extends HttpException
{
/**
* Constructor.
* @param string $message error message
* @param integer $code error code
* @param \Exception $previous The previous exception used for the exception chaining.
*/
public function __construct($message = null, $code = 0, \Exception $previous = null)
{
parent::__construct(422, $message, $code, $previous);
}
}

2
framework/web/UrlManager.php

@ -343,7 +343,7 @@ class UrlManager extends Component
if ($url !== false) {
if (strpos($url, '://') !== false) {
if ($baseUrl !== '' && ($pos = strpos($url, '/', 8)) !== false) {
return substr($url, 0, $pos) . $baseUrl . substr($url, $pos);
return substr($url, 0, $pos) . $baseUrl . substr($url, $pos) . $anchor;
} else {
return $url . $baseUrl . $anchor;
}

6
framework/widgets/LinkPager.php

@ -44,6 +44,10 @@ class LinkPager extends Widget
*/
public $linkOptions = [];
/**
* @var string the CSS class for the each page button.
*/
public $pageCssClass = null;
/**
* @var string the CSS class for the "first" page button.
*/
public $firstPageCssClass = 'first';
@ -204,7 +208,7 @@ class LinkPager extends Widget
*/
protected function renderPageButton($label, $page, $class, $disabled, $active)
{
$options = ['class' => $class === '' ? null : $class];
$options = ['class' => empty($class) ? $this->pageCssClass : $class];
if ($active) {
Html::addCssClass($options, $this->activePageCssClass);
}

3
tests/TestCase.php

@ -81,6 +81,9 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase
*/
protected function destroyApplication()
{
if (\Yii::$app && \Yii::$app->has('session', true)) {
\Yii::$app->session->close();
}
\Yii::$app = null;
}

86
tests/framework/console/ControllerTest.php

@ -0,0 +1,86 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yiiunit\framework\console;
use Yii;
use yiiunit\TestCase;
use yiiunit\framework\di\stubs\Qux;
use yiiunit\framework\web\stubs\Bar;
use yiiunit\framework\web\stubs\OtherQux;
/**
* @group console
*/
class ControllerTest extends TestCase
{
public function testBindActionParams()
{
$this->mockApplication([
'components' => [
'barBelongApp' => [
'class' => Bar::className(),
'foo' => 'belong_app'
],
'quxApp' => [
'class' => OtherQux::className(),
'b' => 'belong_app'
]
]
]);
$controller = new FakeController('fake', Yii::$app);
Yii::$container->set('yiiunit\framework\di\stubs\QuxInterface', [
'class' => Qux::className(),
'a' => 'D426'
]);
Yii::$container->set(Bar::className(), [
'foo' => 'independent'
]);
$params = ['from params'];
list($bar, $fromParam, $other) = $controller->run('aksi1', $params);
$this->assertTrue($bar instanceof Bar);
$this->assertNotEquals($bar, Yii::$app->barBelongApp);
$this->assertEquals('independent', $bar->foo);
$this->assertEquals('from params', $fromParam);
$this->assertEquals('default', $other);
$params = [];
list($barBelongApp, $qux) = $controller->run('aksi2', $params);
$this->assertTrue($barBelongApp instanceof Bar);
$this->assertEquals($barBelongApp, Yii::$app->barBelongApp);
$this->assertEquals('belong_app', $barBelongApp->foo);
$this->assertTrue($qux instanceof Qux);
$this->assertEquals('D426', $qux->a);
$params = [];
list($quxApp) = $controller->run('aksi3', $params);
$this->assertTrue($quxApp instanceof OtherQux);
$this->assertEquals($quxApp, Yii::$app->quxApp);
$this->assertEquals('belong_app', $quxApp->b);
$params = ['d426,mdmunir', 'single'];
$result = $controller->runAction('aksi4', $params);
$this->assertEquals(['independent', 'other_qux', ['d426', 'mdmunir'], 'single'], $result);
$params = ['d426'];
$result = $controller->runAction('aksi5', $params);
$this->assertEquals(['d426', 'independent', 'other_qux'], $result);
$params = ['mdmunir'];
$result = $controller->runAction('aksi6', $params);
$this->assertEquals(['mdmunir', false, true], $result);
$params = ['avaliable'];
$message = Yii::t('yii', 'Missing required arguments: {params}', ['params' => implode(', ', ['missing'])]);
$this->setExpectedException('yii\console\Exception', $message);
$result = $controller->runAction('aksi7', $params);
}
}

56
tests/framework/console/FakeController.php

@ -0,0 +1,56 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yiiunit\framework\console;
use yii\console\Controller;
use yiiunit\framework\di\stubs\QuxInterface;
use yiiunit\framework\web\stubs\Bar;
use yii\validators\EmailValidator;
/**
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
* @since 2.0
*/
class FakeController extends Controller
{
public function actionAksi1(Bar $bar, $fromParam, $other = 'default')
{
return[$bar, $fromParam, $other];
}
public function actionAksi2(Bar $barBelongApp, QuxInterface $qux)
{
return[$barBelongApp, $qux];
}
public function actionAksi3(QuxInterface $quxApp)
{
return[$quxApp];
}
public function actionAksi4(Bar $bar, QuxInterface $quxApp, array $values, $value)
{
return [$bar->foo, $quxApp->quxMethod(), $values, $value];
}
public function actionAksi5($q, Bar $bar, QuxInterface $quxApp)
{
return [$q, $bar->foo, $quxApp->quxMethod()];
}
public function actionAksi6($q, EmailValidator $validator)
{
return [$q, $validator->validate($q), $validator->validate('misbahuldmunir@gmail.com')];
}
public function actionAksi7(Bar $bar, $avaliable, $missing)
{
}
}

33
tests/framework/db/QueryBuilderTest.php

@ -517,4 +517,37 @@ class QueryBuilderTest extends DatabaseTestCase
];
(new Query())->from('customer')->where($condition)->all($this->getConnection());
}
public function testFromSubquery()
{
// query subquery
$subquery = (new Query)->from('user')->where('account_id = accounts.id');
$query = (new Query)->from(['activeusers' => $subquery]);
// SELECT * FROM (SELECT * FROM `user` WHERE `active` = 1) `activeusers`;
list ($sql, $params) = $this->getQueryBuilder()->build($query);
$expected = $this->replaceQuotes('SELECT * FROM (SELECT * FROM `user` WHERE account_id = accounts.id) `activeusers`');
$this->assertEquals($expected, $sql);
$this->assertEmpty($params);
// query subquery with params
$subquery = (new Query)->from('user')->where('account_id = :id', ['id' => 1]);
$query = (new Query)->from(['activeusers' => $subquery])->where('abc = :abc', ['abc' => 'abc']);
// SELECT * FROM (SELECT * FROM `user` WHERE `active` = 1) `activeusers`;
list ($sql, $params) = $this->getQueryBuilder()->build($query);
$expected = $this->replaceQuotes('SELECT * FROM (SELECT * FROM `user` WHERE account_id = :id) `activeusers` WHERE abc = :abc');
$this->assertEquals($expected, $sql);
$this->assertEquals([
'id' => 1,
'abc' => 'abc',
],$params);
// simple subquery
$subquery = "(SELECT * FROM user WHERE account_id = accounts.id)";
$query = (new Query)->from(['activeusers' => $subquery]);
// SELECT * FROM (SELECT * FROM `user` WHERE `active` = 1) `activeusers`;
list ($sql, $params) = $this->getQueryBuilder()->build($query);
$expected = $this->replaceQuotes('SELECT * FROM (SELECT * FROM user WHERE account_id = accounts.id) `activeusers`');
$this->assertEquals($expected, $sql);
$this->assertEmpty($params);
}
}

9
tests/framework/helpers/UrlTest.php

@ -205,4 +205,13 @@ class UrlTest extends TestCase
$this->assertEquals('http://example.com/base/index.php?r=page%2Fview&id=10', Url::canonical());
$this->removeMockedAction();
}
public function testIsRelative()
{
$this->assertTrue(Url::isRelative('/test/index.php'));
$this->assertTrue(Url::isRelative('index.php'));
$this->assertFalse(Url::isRelative('//example.com/'));
$this->assertFalse(Url::isRelative('http://example.com/'));
$this->assertFalse(Url::isRelative('https://example.com/'));
}
}

24
tests/framework/rbac/ManagerTestCase.php

@ -158,6 +158,7 @@ abstract class ManagerTestCase extends TestCase
'createPost' => true,
'readPost' => true,
'updatePost' => true,
'deletePost' => true,
'updateAnyPost' => false,
],
'admin C' => [
@ -194,6 +195,10 @@ abstract class ManagerTestCase extends TestCase
$readPost->description = 'read a post';
$this->auth->add($readPost);
$deletePost = $this->auth->createPermission('deletePost');
$deletePost->description = 'delete a post';
$this->auth->add($deletePost);
$updatePost = $this->auth->createPermission('updatePost');
$updatePost->description = 'update a post';
$updatePost->ruleName = $rule->name;
@ -222,28 +227,29 @@ abstract class ManagerTestCase extends TestCase
$this->auth->assign($reader, 'reader A');
$this->auth->assign($author, 'author B');
$this->auth->assign($deletePost, 'author B');
$this->auth->assign($admin, 'admin C');
}
public function testGetPermissionsByRole()
{
$this->prepareData();
$roles = $this->auth->getPermissionsByRole('admin');
$permissions = $this->auth->getPermissionsByRole('admin');
$expectedPermissions = ['createPost', 'updatePost', 'readPost', 'updateAnyPost'];
$this->assertEquals(count($roles), count($expectedPermissions));
foreach ($expectedPermissions as $permission) {
$this->assertTrue($roles[$permission] instanceof Permission);
$this->assertEquals(count($expectedPermissions), count($permissions));
foreach ($expectedPermissions as $permissionName) {
$this->assertTrue($permissions[$permissionName] instanceof Permission);
}
}
public function testGetPermissionsByUser()
{
$this->prepareData();
$roles = $this->auth->getPermissionsByUser('author B');
$expectedPermissions = ['createPost', 'updatePost', 'readPost'];
$this->assertEquals(count($roles), count($expectedPermissions));
foreach ($expectedPermissions as $permission) {
$this->assertTrue($roles[$permission] instanceof Permission);
$permissions = $this->auth->getPermissionsByUser('author B');
$expectedPermissions = ['deletePost', 'createPost', 'updatePost', 'readPost'];
$this->assertEquals(count($expectedPermissions), count($permissions));
foreach ($expectedPermissions as $permissionName) {
$this->assertTrue($permissions[$permissionName] instanceof Permission);
}
}

12
tests/framework/rbac/PhpManagerTest.php

@ -139,4 +139,16 @@ class PhpManagerTest extends ManagerTestCase
$permission->name = 'createPost';
$this->auth->update($name, $permission);
}
public function testSaveAssignments()
{
$this->auth->removeAll();
$role = $this->auth->createRole('Admin');
$this->auth->add($role);
$this->auth->assign($role, 13);
$this->assertContains('Admin', file_get_contents($this->getAssignmentFile()));
$role->name = 'NewAdmin';
$this->auth->update('Admin', $role);
$this->assertContains('NewAdmin', file_get_contents($this->getAssignmentFile()));
}
}

81
tests/framework/web/ControllerTest.php

@ -0,0 +1,81 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yiiunit\framework\web;
use Yii;
use yiiunit\TestCase;
use yiiunit\framework\di\stubs\Qux;
use yiiunit\framework\web\stubs\Bar;
use yiiunit\framework\web\stubs\OtherQux;
use yii\base\InlineAction;
/**
* @group web
*/
class ControllerTest extends TestCase
{
public function testBindActionParams()
{
$this->mockApplication([
'components'=>[
'barBelongApp'=>[
'class'=> Bar::className(),
'foo'=>'belong_app'
],
'quxApp'=>[
'class' => OtherQux::className(),
'b' => 'belong_app'
]
]
]);
$controller = new FakeController('fake', Yii::$app);
$aksi1 = new InlineAction('aksi1', $controller, 'actionAksi1');
$aksi2 = new InlineAction('aksi2', $controller, 'actionAksi2');
$aksi3 = new InlineAction('aksi3', $controller, 'actionAksi3');
Yii::$container->set('yiiunit\framework\di\stubs\QuxInterface', [
'class' => Qux::className(),
'a' => 'D426'
]);
Yii::$container->set(Bar::className(),[
'foo' => 'independent'
]);
$params = ['fromGet'=>'from query params','q'=>'d426','validator'=>'avaliable'];
list($bar, $fromGet, $other) = $controller->bindActionParams($aksi1, $params);
$this->assertTrue($bar instanceof Bar);
$this->assertNotEquals($bar, Yii::$app->barBelongApp);
$this->assertEquals('independent', $bar->foo);
$this->assertEquals('from query params', $fromGet);
$this->assertEquals('default', $other);
list($barBelongApp, $qux) = $controller->bindActionParams($aksi2, $params);
$this->assertTrue($barBelongApp instanceof Bar);
$this->assertEquals($barBelongApp, Yii::$app->barBelongApp);
$this->assertEquals('belong_app', $barBelongApp->foo);
$this->assertTrue($qux instanceof Qux);
$this->assertEquals('D426', $qux->a);
list($quxApp) = $controller->bindActionParams($aksi3, $params);
$this->assertTrue($quxApp instanceof OtherQux);
$this->assertEquals($quxApp, Yii::$app->quxApp);
$this->assertEquals('belong_app', $quxApp->b);
$result = $controller->runAction('aksi4', $params);
$this->assertEquals(['independent', 'other_qux', 'd426'], $result);
$result = $controller->runAction('aksi5', $params);
$this->assertEquals(['d426', 'independent', 'other_qux'], $result);
$result = $controller->runAction('aksi6', $params);
$this->assertEquals(['d426', false, true], $result);
}
}

49
tests/framework/web/FakeController.php

@ -0,0 +1,49 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yiiunit\framework\web;
use yii\web\Controller;
use yiiunit\framework\di\stubs\QuxInterface;
use yiiunit\framework\web\stubs\Bar;
use yii\validators\EmailValidator;
/**
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
* @since 2.0
*/
class FakeController extends Controller
{
public $enableCsrfValidation = false;
public function actionAksi1(Bar $bar, $fromGet, $other = 'default')
{
}
public function actionAksi2(Bar $barBelongApp, QuxInterface $qux)
{
}
public function actionAksi3(QuxInterface $quxApp)
{
}
public function actionAksi4(Bar $bar, QuxInterface $quxApp, $q)
{
return [$bar->foo, $quxApp->quxMethod(), $q];
}
public function actionAksi5($q, Bar $bar, QuxInterface $quxApp)
{
return [$q, $bar->foo, $quxApp->quxMethod()];
}
public function actionAksi6($q, EmailValidator $validator)
{
return [$q, $validator->validate($q), $validator->validate('misbahuldmunir@gmail.com')];
}
}

20
tests/framework/web/UrlManagerTest.php

@ -389,4 +389,24 @@ class UrlManagerTest extends TestCase
unset($_SERVER['REQUEST_METHOD']);
}
/**
* Tests if hash-anchor present
*
* https://github.com/yiisoft/yii2/pull/9596
*/
public function testHash()
{
$manager = new UrlManager([
'enablePrettyUrl' => true,
'cache' => null,
'rules' => [
'http://example.com/testPage' => 'site/test',
],
'hostInfo' => 'http://example.com',
'scriptUrl' => '/index.php',
]);
$url = $manager->createAbsoluteUrl(['site/test', '#' => 'testhash']);
$this->assertEquals('http://example.com/index.php/testPage#testhash', $url);
}
}

19
tests/framework/web/stubs/Bar.php

@ -0,0 +1,19 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yiiunit\framework\web\stubs;
use yii\base\Object;
/**
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
* @since 2.0
*/
class Bar extends Object
{
public $foo;
}

24
tests/framework/web/stubs/OtherQux.php

@ -0,0 +1,24 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yiiunit\framework\web\stubs;
use yii\base\Object;
use yiiunit\framework\di\stubs\QuxInterface;
/**
* @author Misbahul D Munir <misbahuldmunir@gmail.com>
* @since 2.0
*/
class OtherQux extends Object implements QuxInterface
{
public $b;
public function quxMethod()
{
return 'other_qux';
}
}
Loading…
Cancel
Save