Browse Source

Merged branch 'master' into 2.1

tags/3.0.0-alpha1
Alexander Makarov 7 years ago
parent
commit
0afc410d12
No known key found for this signature in database
GPG Key ID: 3617B79C6A325E4A
  1. 12
      composer.json
  2. 51
      composer.lock
  3. 224
      docs/guide-id/README.md
  4. 6
      docs/guide-id/blocktypes.json
  5. 263
      docs/guide-id/start-databases.md
  6. 245
      docs/guide-id/start-forms.md
  7. 139
      docs/guide-id/start-gii.md
  8. 35
      docs/guide-id/start-looking-ahead.md
  9. 119
      docs/guide-id/structure-application-components.md
  10. 609
      docs/guide-id/structure-applications.md
  11. 113
      docs/guide-id/structure-entry-scripts.md
  12. 26
      docs/guide-id/structure-overview.md
  13. 6
      docs/guide-id/translators.json
  14. 2
      docs/guide-ru/README.md
  15. 2
      docs/guide-ru/start-workflow.md
  16. 22
      docs/guide-ru/test-environment-setup.md
  17. 12
      docs/guide-zh-CN/input-validation.md
  18. 2
      docs/guide-zh-CN/output-formatting.md
  19. 2
      docs/guide/concept-autoloading.md
  20. 7
      docs/guide/db-dao.md
  21. 12
      docs/guide/db-migrations.md
  22. 79
      docs/guide/db-query-builder.md
  23. 20
      docs/guide/input-validation.md
  24. 2
      docs/guide/output-client-scripts.md
  25. 14
      docs/guide/output-formatting.md
  26. 3
      docs/guide/runtime-routing.md
  27. 25
      docs/guide/runtime-sessions-cookies.md
  28. 33
      docs/guide/security-authorization.md
  29. 8
      framework/BaseYii.php
  30. 143
      framework/CHANGELOG.md
  31. 7
      framework/UPGRADE.md
  32. 6
      framework/base/Controller.php
  33. 4
      framework/base/Module.php
  34. 2
      framework/base/Request.php
  35. 2
      framework/base/Security.php
  36. 6
      framework/base/Theme.php
  37. 28
      framework/base/View.php
  38. 4
      framework/base/Widget.php
  39. 2
      framework/behaviors/SluggableBehavior.php
  40. 43
      framework/caching/DbCache.php
  41. 2
      framework/caching/FileCache.php
  42. 2
      framework/caching/FileDependency.php
  43. 2
      framework/captcha/CaptchaAction.php
  44. 2
      framework/classes.php
  45. 2
      framework/composer.json
  46. 2
      framework/console/controllers/AssetController.php
  47. 87
      framework/console/controllers/BaseMigrateController.php
  48. 25
      framework/console/controllers/CacheController.php
  49. 28
      framework/console/controllers/FixtureController.php
  50. 7
      framework/console/controllers/MessageController.php
  51. 7
      framework/console/controllers/MigrateController.php
  52. 2
      framework/console/controllers/ServeController.php
  53. 2
      framework/data/ActiveDataProvider.php
  54. 1
      framework/data/BaseDataProvider.php
  55. 2
      framework/data/DataProviderInterface.php
  56. 48
      framework/data/Sort.php
  57. 7
      framework/data/SqlDataProvider.php
  58. 104
      framework/db/ActiveQuery.php
  59. 41
      framework/db/BaseActiveRecord.php
  60. 73
      framework/db/Command.php
  61. 35
      framework/db/Connection.php
  62. 14
      framework/db/Migration.php
  63. 4
      framework/db/Query.php
  64. 3
      framework/db/QueryBuilder.php
  65. 1
      framework/db/cubrid/QueryBuilder.php
  66. 12
      framework/db/mssql/QueryBuilder.php
  67. 56
      framework/db/oci/QueryBuilder.php
  68. 2
      framework/db/pgsql/Schema.php
  69. 1
      framework/db/sqlite/QueryBuilder.php
  70. 7
      framework/di/Instance.php
  71. 33
      framework/filters/AccessControl.php
  72. 88
      framework/filters/AccessRule.php
  73. 30
      framework/filters/RateLimiter.php
  74. 2
      framework/grid/ActionColumn.php
  75. 2
      framework/grid/GridView.php
  76. 22
      framework/helpers/BaseFileHelper.php
  77. 1
      framework/helpers/BaseHtml.php
  78. 36
      framework/i18n/Formatter.php
  79. 6
      framework/log/DbTarget.php
  80. 2
      framework/log/FileTarget.php
  81. 24
      framework/log/Logger.php
  82. 10
      framework/mail/BaseMailer.php
  83. 2
      framework/mail/MailerInterface.php
  84. 1
      framework/messages/el/yii.php
  85. 2
      framework/messages/sk/yii.php
  86. 2
      framework/mutex/FileMutex.php
  87. 5
      framework/rbac/BaseManager.php
  88. 6
      framework/rbac/DbManager.php
  89. 8
      framework/rbac/PhpManager.php
  90. 25
      framework/rest/UrlRule.php
  91. 12
      framework/test/ActiveFixture.php
  92. 2
      framework/test/ArrayFixture.php
  93. 6
      framework/test/BaseActiveFixture.php
  94. 10
      framework/test/FixtureTrait.php
  95. 2
      framework/test/InitDbFixture.php
  96. 7
      framework/validators/DateValidator.php
  97. 63
      framework/validators/ExistValidator.php
  98. 3
      framework/validators/StringValidator.php
  99. 52
      framework/validators/UniqueValidator.php
  100. 26
      framework/validators/Validator.php
  101. Some files were not shown because too many files have changed in this diff Show More

12
composer.json

@ -76,7 +76,7 @@
"ezyang/htmlpurifier": "~4.6",
"cebe/markdown": "~1.0.0 | ~1.1.0",
"bower-asset/jquery": "2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable",
"bower-asset/jquery.inputmask": "~3.2.2 | ~3.3.3",
"bower-asset/jquery.inputmask": "~3.2.2 | ~3.3.5",
"bower-asset/punycode": "1.3.*",
"bower-asset/yii2-pjax": "~2.0.1"
},
@ -107,14 +107,6 @@
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
},
"asset-installer-paths": {
"npm-asset-library": "vendor/npm",
"bower-asset-library": "vendor/bower"
},
"asset-vcs-driver-options": {
"github-no-api": true
},
"asset-pattern-skip-version": "(-build|-patch)"
}
}
}

51
composer.lock generated

@ -4,8 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "db4e038c0e8ca747784fb195c82bfdad",
"content-hash": "cc4b01a602c948040169ebbc1ac30186",
"content-hash": "d33a8eeb49ce13a2e319e70d8d4a2f67",
"packages": [
{
"name": "bower-asset/jquery",
@ -43,12 +42,12 @@
"version": "3.2.7",
"source": {
"type": "git",
"url": "https://github.com/RobinHerbots/jquery.inputmask.git",
"url": "https://github.com/RobinHerbots/Inputmask.git",
"reference": "ec7726993217ee7b01023ad4f7f1b6a51446a39d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/RobinHerbots/jquery.inputmask/zipball/ec7726993217ee7b01023ad4f7f1b6a51446a39d",
"url": "https://api.github.com/repos/RobinHerbots/Inputmask/zipball/ec7726993217ee7b01023ad4f7f1b6a51446a39d",
"reference": "ec7726993217ee7b01023ad4f7f1b6a51446a39d",
"shasum": ""
},
@ -204,7 +203,7 @@
"markdown",
"markdown-extra"
],
"time": "2016-09-14 20:40:20"
"time": "2016-09-14T20:40:20+00:00"
},
{
"name": "ezyang/htmlpurifier",
@ -248,7 +247,7 @@
"keywords": [
"html"
],
"time": "2016-07-16 12:58:58"
"time": "2016-07-16T12:58:58+00:00"
},
{
"name": "yiisoft/yii2-composer",
@ -298,7 +297,7 @@
"extension installer",
"yii2"
],
"time": "2016-12-20 13:26:02"
"time": "2016-12-20T13:26:02+00:00"
}
],
"packages-dev": [
@ -333,7 +332,7 @@
}
],
"description": "a small tool to convert text file indentation",
"time": "2014-05-23 14:40:08"
"time": "2014-05-23T14:40:08+00:00"
},
{
"name": "doctrine/instantiator",
@ -387,7 +386,7 @@
"constructor",
"instantiate"
],
"time": "2015-06-14 21:17:01"
"time": "2015-06-14T21:17:01+00:00"
},
{
"name": "phpdocumentor/reflection-docblock",
@ -436,7 +435,7 @@
"email": "mike.vanriel@naenius.com"
}
],
"time": "2015-02-03 12:10:50"
"time": "2015-02-03T12:10:50+00:00"
},
{
"name": "phpspec/prophecy",
@ -499,7 +498,7 @@
"spy",
"stub"
],
"time": "2016-11-21 14:58:47"
"time": "2016-11-21T14:58:47+00:00"
},
{
"name": "phpunit/php-code-coverage",
@ -561,7 +560,7 @@
"testing",
"xunit"
],
"time": "2015-10-06 15:47:00"
"time": "2015-10-06T15:47:00+00:00"
},
{
"name": "phpunit/php-file-iterator",
@ -608,7 +607,7 @@
"filesystem",
"iterator"
],
"time": "2016-10-03 07:40:28"
"time": "2016-10-03T07:40:28+00:00"
},
{
"name": "phpunit/php-text-template",
@ -649,7 +648,7 @@
"keywords": [
"template"
],
"time": "2015-06-21 13:50:34"
"time": "2015-06-21T13:50:34+00:00"
},
{
"name": "phpunit/php-timer",
@ -693,7 +692,7 @@
"keywords": [
"timer"
],
"time": "2016-05-12 18:03:57"
"time": "2016-05-12T18:03:57+00:00"
},
{
"name": "phpunit/php-token-stream",
@ -742,7 +741,7 @@
"keywords": [
"tokenizer"
],
"time": "2016-11-15 14:06:22"
"time": "2016-11-15T14:06:22+00:00"
},
{
"name": "phpunit/phpunit",
@ -814,7 +813,7 @@
"testing",
"xunit"
],
"time": "2016-12-09 02:45:31"
"time": "2016-12-09T02:45:31+00:00"
},
{
"name": "phpunit/phpunit-mock-objects",
@ -870,7 +869,7 @@
"mock",
"xunit"
],
"time": "2015-10-02 06:51:40"
"time": "2015-10-02T06:51:40+00:00"
},
{
"name": "sebastian/comparator",
@ -934,7 +933,7 @@
"compare",
"equality"
],
"time": "2016-11-19 09:18:40"
"time": "2016-11-19T09:18:40+00:00"
},
{
"name": "sebastian/diff",
@ -986,7 +985,7 @@
"keywords": [
"diff"
],
"time": "2015-12-08 07:14:41"
"time": "2015-12-08T07:14:41+00:00"
},
{
"name": "sebastian/environment",
@ -1036,7 +1035,7 @@
"environment",
"hhvm"
],
"time": "2016-08-18 05:49:44"
"time": "2016-08-18T05:49:44+00:00"
},
{
"name": "sebastian/exporter",
@ -1103,7 +1102,7 @@
"export",
"exporter"
],
"time": "2016-06-17 09:04:28"
"time": "2016-06-17T09:04:28+00:00"
},
{
"name": "sebastian/global-state",
@ -1154,7 +1153,7 @@
"keywords": [
"global state"
],
"time": "2015-10-12 03:26:01"
"time": "2015-10-12T03:26:01+00:00"
},
{
"name": "sebastian/recursion-context",
@ -1207,7 +1206,7 @@
],
"description": "Provides functionality to recursively process PHP variables",
"homepage": "http://www.github.com/sebastianbergmann/recursion-context",
"time": "2015-11-11 19:50:13"
"time": "2015-11-11T19:50:13+00:00"
},
{
"name": "sebastian/version",
@ -1242,7 +1241,7 @@
],
"description": "Library that helps with managing the version number of Git-hosted PHP projects",
"homepage": "https://github.com/sebastianbergmann/version",
"time": "2015-06-21 13:59:46"
"time": "2015-06-21T13:59:46+00:00"
},
{
"name": "symfony/yaml",
@ -1291,7 +1290,7 @@
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
"time": "2017-01-03 13:49:52"
"time": "2017-01-03T13:49:52+00:00"
}
],
"aliases": [],

224
docs/guide-id/README.md

@ -1,7 +1,7 @@
Panduan Definitif Untuk Yii 2.0
===============================
Tutorial ini dirilis di bawah [Persyaratan Dokumentasi Yii] (http://www.yiiframework.com/doc/terms/).
Tutorial ini dirilis di bawah [Persyaratan Dokumentasi Yii](http://www.yiiframework.com/doc/terms/).
Seluruh hak cipta dilindungi.
@ -11,188 +11,190 @@ Seluruh hak cipta dilindungi.
Pengantar
------------
* [Tentang Yii] (intro-yii.md)
* [Upgrade dari Versi 1.1] (intro-upgrade-from-v1.md)
* [Tentang Yii](intro-yii.md)
* [Upgrade dari Versi 1.1](intro-upgrade-from-v1.md)
Mulai
---------------
* [Instalasi Yii] (start-installation.md)
* [Menjalankan Aplikasi] (start-workflow.md)
* [Mengatakan Hello] (start-hello.md)
* [Bekerja dengan Form] (start-forms.md)
* [Bekerja dengan Database] (start-databases.md)
* [Membuat Kode Otomatis dengan Gii] (start-gii.md)
* [Menatap ke Depan] (start-looking-ahead.md)
* [Instalasi Yii](start-installation.md)
* [Menjalankan Aplikasi](start-workflow.md)
* [Mengatakan Hello](start-hello.md)
* [Bekerja dengan Form](start-forms.md)
* [Bekerja dengan Database](start-databases.md)
* [Membuat Kode Otomatis dengan Gii](start-gii.md)
* [Menatap ke Depan](start-looking-ahead.md)
Struktur Aplikasi
---------------------
* [Tinjauan] (structure-overview.md)
* [Script Masuk] (structure-entry-scripts.md)
* [Aplikasi] (structure-applications.md)
* [Komponen Aplikasi] (structure-application-components.md)
* [Controller] (structure-controllers.md)
* [Model] (structure-models.md)
* [Views] (structure-views.md)
* [Modul] (structure-modules.md)
* [Filter] (structure-filters.md)
* [Widgets] (structure-widgets.md)
* [Aset] (structure-assets.md)
* [Ekstensi] (structure-extensions.md)
* [Tinjauan](structure-overview.md)
* [Script Masuk](structure-entry-scripts.md)
* [Aplikasi](structure-applications.md)
* [Komponen Aplikasi](structure-application-components.md)
* [Controller](structure-controllers.md)
* [Model](structure-models.md)
* [Views](structure-views.md)
* [Modul](structure-modules.md)
* [Filter](structure-filters.md)
* [Widgets](structure-widgets.md)
* [Aset](structure-assets.md)
* [Ekstensi](structure-extensions.md)
Penanganan Permintaan
-----------------
* [Tinjauan] (runtime-overview.md)
* [Bootstrap] (runtime-bootstrapping.md)
* [Routing dan Pembuatan URL] (runtime-routing.md)
* [Permintaan] (runtime-requests.md)
* [Tanggapan] (runtime-responses.md)
* [Sesi dan Cookies] (runtime-sessions-cookies.md)
* [Penanganan Kesalahan] (runtime-handling-errors.md)
* [Logging] (runtime-logging.md)
* [Tinjauan](runtime-overview.md)
* [Bootstrap](runtime-bootstrapping.md)
* [Routing dan Pembuatan URL](runtime-routing.md)
* [Permintaan](runtime-requests.md)
* [Tanggapan](runtime-responses.md)
* [Sesi dan Cookies](runtime-sessions-cookies.md)
* [Penanganan Kesalahan](runtime-handling-errors.md)
* [Logging](runtime-logging.md)
Konsep Pokok
------------
* [Komponen] (concept-components.md)
* [Properti] (concept-properties.md)
* [Event] (concept-events.md)
* [Perilaku] (concept-behaviors.md)
* [Konfigurasi] (concept-configurations.md)
* [Alias] (concept-aliases.md)
* [Class Autoloading] (concept-autoloading.md)
* [Layanan Locator] (concept-service-locator.md)
* [Dependency Injection] (concept-di-container.md)
* [Komponen](concept-components.md)
* [Properti](concept-properties.md)
* [Event](concept-events.md)
* [Perilaku](concept-behaviors.md)
* [Konfigurasi](concept-configurations.md)
* [Alias](concept-aliases.md)
* [Class Autoloading](concept-autoloading.md)
* [Layanan Locator](concept-service-locator.md)
* [Dependency Injection](concept-di-container.md)
Bekerja dengan Database
----------------------
* [Data Access Objects] (db-dao.md): Menghubungkan ke database, query dasar, transaksi, dan manipulasi skema
* [Query Builder] (db-query-builder.md): Query database menggunakan lapisan abstraksi sederhana
* [Active Record] (db-active-record.md): ORM Active Record, mengambil dan memanipulasi catatan, dan mendefinisikan hubungan
* [Migrasi] (db-migrations.md): Terapkan kontrol versi untuk database Anda dalam lingkungan pengembangan tim
* [Sphinx] (https://github.com/yiisoft/yii2-sphinx/blob/master/docs/guide/README.md)
* [Redis] (https://github.com/yiisoft/yii2-redis/blob/master/docs/guide/README.md)
* [MongoDB] (https://github.com/yiisoft/yii2-mongodb/blob/master/docs/guide/README.md)
* [ElasticSearch] (https://github.com/yiisoft/yii2-elasticsearch/blob/master/docs/guide/README.md)
* [Data Access Objects](db-dao.md): Menghubungkan ke database, query dasar, transaksi, dan manipulasi skema
* [Query Builder](db-query-builder.md): Query database menggunakan lapisan abstraksi sederhana
* [Active Record](db-active-record.md): ORM Active Record, mengambil dan memanipulasi catatan, dan mendefinisikan hubungan
* [Migrasi](db-migrations.md): Terapkan kontrol versi untuk database Anda dalam lingkungan pengembangan tim
* [Sphinx](https://github.com/yiisoft/yii2-sphinx/blob/master/docs/guide/README.md)
* [Redis](https://github.com/yiisoft/yii2-redis/blob/master/docs/guide/README.md)
* [MongoDB](https://github.com/yiisoft/yii2-mongodb/blob/master/docs/guide/README.md)
* [ElasticSearch](https://github.com/yiisoft/yii2-elasticsearch/blob/master/docs/guide/README.md)
Mendapatkan Data dari Pengguna
-----------------------
* [Membuat Formulir] (input-forms.md)
* [Memvalidasi Masukan] (input-validation.md)
* [Mengunggah File] (input-file-upload.md)
* [Mengumpulkan Masukan Tabel] (input-tabular-input.md)
* [Mendapatkan Data untuk Beberapa Model] (input-multiple-models.md)
* [Membuat Formulir](input-forms.md)
* [Memvalidasi Masukan](input-validation.md)
* [Mengunggah File](input-file-upload.md)
* [Mengumpulkan Masukan Tabel](input-tabular-input.md)
* [Mendapatkan Data untuk Beberapa Model](input-multiple-models.md)
Menampilkan Data
---------------
* [Pemformatan Data] (output-formatting.md)
* [Pagination] (output-pagination.md)
* [Pengurutan] (output-sorting.md)
* [Penyedia Data] (output-data-providers.md)
* [Data Widget] (output-data-widgets.md)
* [Bekerja dengan Script Client] (output-client-scripts.md)
* [Tema] (output-theming.md)
* [Pemformatan Data](output-formatting.md)
* [Pagination](output-pagination.md)
* [Pengurutan](output-sorting.md)
* [Penyedia Data](output-data-providers.md)
* [Data Widget](output-data-widgets.md)
* [Bekerja dengan Script Client](output-client-scripts.md)
* [Tema](output-theming.md)
Keamanan
--------
* [Otentikasi] (security-authentication.md)
* [Otorisasi] (security-authorization.md)
* [Bekerja dengan Kata Sandi] (security-passwords.md)
* [Otentikasi Klien] (https://github.com/yiisoft/yii2-authclient/blob/master/docs/guide/README.md)
* [Praktik Terbaik] (security-best-practices.md)
* [Tinjauan](security-overview.md)
* [Otentikasi](security-authentication.md)
* [Otorisasi](security-authorization.md)
* [Bekerja dengan Kata Sandi](security-passwords.md)
* [Kriptografi](security-cryptography.md)
* [Otentikasi Klien](https://github.com/yiisoft/yii2-authclient/blob/master/docs/guide/README.md)
* [Praktik Terbaik](security-best-practices.md)
Caching
-------
* [Tinjauan] (caching-overview.md)
* [Caching Data] (caching-data.md)
* [Caching Fragmen] (caching-fragment.md)
* [Caching Halaman] (caching-page.md)
* [Caching HTTP] (caching-http.md)
* [Tinjauan](caching-overview.md)
* [Caching Data](caching-data.md)
* [Caching Fragmen](caching-fragment.md)
* [Caching Halaman](caching-page.md)
* [Caching HTTP](caching-http.md)
Layanan Web RESTful
--------------------
* [Quick Start] (rest-quick-start.md)
* [Sumber Daya] (rest-resources.md)
* [Controller] (rest-controllers.md)
* [Routing] (rest-routing.md)
* [Penformatan Respon] (rest-response-formatting.md)
* [Otentikasi] (rest-authentication.md)
* [Pembatasan Laju] (rest-rate-limiting.md)
* [Versi] (rest-versioning.md)
* [Penanganan Kesalahan] (rest-error-handling.md)
* [Quick Start](rest-quick-start.md)
* [Sumber Daya](rest-resources.md)
* [Controller](rest-controllers.md)
* [Routing](rest-routing.md)
* [Penformatan Respon](rest-response-formatting.md)
* [Otentikasi](rest-authentication.md)
* [Pembatasan Laju](rest-rate-limiting.md)
* [Versi](rest-versioning.md)
* [Penanganan Kesalahan](rest-error-handling.md)
Alat Pengembangan
-----------------
* [Debug Toolbar dan Debugger] (https://github.com/yiisoft/yii2-debug/blob/master/docs/guide/README.md)
* [Membuat Kode Otomatis dengan Gii] (https://github.com/yiisoft/yii2-gii/blob/master/docs/guide/README.md)
* ** TBD ** [Membuat API Documentation] (https://github.com/yiisoft/yii2-apidoc)
* [Debug Toolbar dan Debugger](https://github.com/yiisoft/yii2-debug/blob/master/docs/guide/README.md)
* [Membuat Kode Otomatis dengan Gii](https://github.com/yiisoft/yii2-gii/blob/master/docs/guide/README.md)
* [Membuat API Documentation](https://github.com/yiisoft/yii2-apidoc)
Pengujian
-------
* [Tinjauan] (test-overview.md)
* [Persiapan Lingkungan Pengujian] (test-environment-setup.md)
* [Tes Satuan] (test-unit.md)
* [Tes Fungsional] (test-functional.md)
* [Tes Penerimaan] (test-acceptance.md)
* [Jadwal] (test-fixtures.md)
* [Tinjauan](test-overview.md)
* [Persiapan Lingkungan Pengujian](test-environment-setup.md)
* [Tes Satuan](test-unit.md)
* [Tes Fungsional](test-functional.md)
* [Tes Penerimaan](test-acceptance.md)
* [Jadwal](test-fixtures.md)
Topik Khusus
--------------
* [Cetakan Proyek Lanjutan] (https://github.com/yiisoft/yii2-app-advanced/blob/master/docs/guide/README.md)
* [Membangun Aplikasi dari Awal] (tutorial-start-from-scratch.md)
* [Console Commands] (tutorial-console.md)
* [Validator Inti] (tutorial-core-validators.md)
* [Internasionalisasi] (tutorial-i18n.md)
* [Mailing] (tutorial-mailing.md)
* [Penyetelan Performa] (tutorial-performance-tuning.md)
* [Lingkungan Shared Hosting] (tutorial-shared-hosting.md)
* [Template Engine] (tutorial-template-engines.md)
* [Bekerja dengan Kode Pihak Ketiga] (tutorial-yii-integration.md)
* [Cetakan Proyek Lanjutan](https://github.com/yiisoft/yii2-app-advanced/blob/master/docs/guide/README.md)
* [Membangun Aplikasi dari Awal](tutorial-start-from-scratch.md)
* [Console Commands](tutorial-console.md)
* [Validator Inti](tutorial-core-validators.md)
* [Internasionalisasi](tutorial-i18n.md)
* [Mailing](tutorial-mailing.md)
* [Penyetelan Performa](tutorial-performance-tuning.md)
* [Lingkungan Shared Hosting](tutorial-shared-hosting.md)
* [Template Engine](tutorial-template-engines.md)
* [Bekerja dengan Kode Pihak Ketiga](tutorial-yii-integration.md)
Widget
-------
* GridView: ** TBD ** Link ke demo halaman
* ListView: ** TBD ** Link ke halaman demo
* DetailView: ** TBD ** Link ke halaman demo
* ActiveForm: ** TBD ** Link ke halaman demo
* Pjax: ** TBD ** Link ke demo halaman
* Menu: ** TBD ** Link ke halaman demo
* LinkPager: ** TBD ** Link ke halaman demo
* LinkSorter: ** TBD ** Link ke halaman demo
* [Bootstrap Widgets] (https://github.com/yiisoft/yii2-bootstrap/blob/master/docs/guide/README.md)
* [JQuery UI Widgets] (https://github.com/yiisoft/yii2-jui/blob/master/docs/guide/README.md)
* [GridView](http://www.yiiframework.com/doc-2.0/yii-grid-gridview.html)
* [ListView](http://www.yiiframework.com/doc-2.0/yii-widgets-listview.html)
* [DetailView](http://www.yiiframework.com/doc-2.0/yii-widgets-detailview.html)
* [ActiveForm](http://www.yiiframework.com/doc-2.0/guide-input-forms.html#activerecord-based-forms-activeform)
* [Pjax](http://www.yiiframework.com/doc-2.0/yii-widgets-pjax.html)
* [Menu](http://www.yiiframework.com/doc-2.0/yii-widgets-menu.html)
* [LinkPager](http://www.yiiframework.com/doc-2.0/yii-widgets-linkpager.html)
* [LinkSorter](http://www.yiiframework.com/doc-2.0/yii-widgets-linksorter.html)
* [Bootstrap Widgets](https://github.com/yiisoft/yii2-bootstrap/blob/master/docs/guide/README.md)
* [JQuery UI Widgets](https://github.com/yiisoft/yii2-jui/blob/master/docs/guide/README.md)
Alat Bantu
---------
* [Tinjauan] (helper-overview.md)
* [ArrayHelper] (helper-array.md)
* [Html] (helper-html.md)
* [Url] (helper-url.md)
* [Tinjauan](helper-overview.md)
* [ArrayHelper](helper-array.md)
* [Html](helper-html.md)
* [Url](helper-url.md)

6
docs/guide-id/blocktypes.json

@ -0,0 +1,6 @@
{
"Warning:": "Perhatian:",
"Note:": "Catatan:",
"Info:": "Info:",
"Tip:": "Tips:"
}

263
docs/guide-id/start-databases.md

@ -0,0 +1,263 @@
Bekerja dengan Database
======================
Bagian ini akan memaparkan bagaimana membuat halaman yang menampilkan daftar data negara yang diambil dari
tabel `country` pada database. Untuk menyelesaikan tugas ini, anda akan melakukan konfigurasi koneksi ke database,
membuat class [Active Record](db-active-record.md), membuat [action](structure-controllers.md),
dan membuat [view](structure-views.md).
Sepanjang tutorial ini, anda akan mempelajari bagaimana cara untuk:
* konfigurasi koneksi ke database,
* membuat class _ActiveRecord_,
* mengambil _(query)_ data menggunakan class _ActiveRecord_,
* menampilkan data ke view dengan halaman per halaman.
Sebagai catatan untuk menyelesaikan bagian ini, anda harus memiliki pengetahuan dan pengalaman dasar dalam menggunakan database.
Secara khusus, anda harus mengetahui cara membuat database, dan cara menjalankan perintah SQL menggunakan aplikasi klien database.
Menyiapkan Database <span id="preparing-database"></span>
----------------------
Untuk memulai, buatlah database dengan nama `yii2basic`, yang akan digunakan untuk mengambil data dalam aplikasi anda.
Anda bisa membuat database SQLite, MySQL, PostgreSQL, MSSQL, atau Oracle, dimana Yii mendukung banyak aplikasi database. Untuk memudahkan, database yang digunakan adalah MySQL.
Selanjutnya, buat tabel dengan nama `country` pada database, dan _insert_ beberapa data sampel. Anda bisa menjalankan perintah SQL dibawah untuk memudahkan:
```sql
CREATE TABLE `country` (
`code` CHAR(2) NOT NULL PRIMARY KEY,
`name` CHAR(52) NOT NULL,
`population` INT(11) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `country` VALUES ('AU','Australia',24016400);
INSERT INTO `country` VALUES ('BR','Brazil',205722000);
INSERT INTO `country` VALUES ('CA','Canada',35985751);
INSERT INTO `country` VALUES ('CN','China',1375210000);
INSERT INTO `country` VALUES ('DE','Germany',81459000);
INSERT INTO `country` VALUES ('FR','France',64513242);
INSERT INTO `country` VALUES ('GB','United Kingdom',65097000);
INSERT INTO `country` VALUES ('IN','India',1285400000);
INSERT INTO `country` VALUES ('RU','Russia',146519759);
INSERT INTO `country` VALUES ('US','United States',322976000);
```
Hingga saat ini, anda memiliki database bernama `yii2basic`, dan didalamnya terdapat tabel `country` dengan tiga kolom, berisi 10 baris data.
Konfigurasi Koneksi Database <span id="configuring-db-connection"></span>
---------------------------
Sebelum melanjutkan, pastikan anda memasang ekstensi PHP [PDO](http://www.php.net/manual/en/book.pdo.php) dan
driver PDO untuk database yang anda gunakan (misal, `pdo_mysql` untuk MySQL). Ini adalah kebutuhan mendasar
jika aplikasi anda menggunakan _relational database_.
Jika sudah terpasang, buka file `config/db.php` dan sesuaikan parameter yang sesuai untuk database anda. Secara default,
isi file konfigurasi tersebut adalah:
```php
<?php
return [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=yii2basic',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
];
```
File `config/db.php` adalah tipikal [konfigurasi](concept-configurations.md) yang menggunakan file. File konfigurasi seperti ini menentukan parameter-parameter
yang dibutuhkan untuk membuat dan menginisialisasi objek [[yii\db\Connection]], dimana anda dapat menjalankan perintah SQL
dengan database yang dituju.
Konfigurasi koneksi database di atas dapat diakses pada kode aplikasi melalui _expression_ `Yii::$app->db`.
> Info: File `config/db.php` akan di _include_ oleh konfigurasi aplikasi utama `config/web.php`,
yang berfungsi sebagai konfigurasi untuk inisialisasi objek [aplikasi](structure-applications.md).
Untuk penjelasan lebih lengkap, silahkan lihat bagian [Konfigurasi](concept-configurations.md).
Jika anda membutuhkan dukungan database yang tidak didukung oleh Yii, silahkan cek _extensions_ di bawah ini:
- [Informix](https://github.com/edgardmessias/yii2-informix)
- [IBM DB2](https://github.com/edgardmessias/yii2-ibm-db2)
- [Firebird](https://github.com/edgardmessias/yii2-firebird)
Membuat Active Record <span id="creating-active-record"></span>
-------------------------
Untuk mengambil data di tabel `country`, buat class turunan [Active Record](db-active-record.md)
dengan nama `Country`, dan simpan pada file `models/Country.php`.
```php
<?php
namespace app\models;
use yii\db\ActiveRecord;
class Country extends ActiveRecord
{
}
```
_Class_ `Country` di _extends_ dari [[yii\db\ActiveRecord]]. Anda tidak perlu untuk menulis kode di dalamnya! Hanya dengan kode di atas,
Yii akan mengetahui nama tabel yang dimaksud dari nama _class_ tersebut.
> Info: Jika nama _class_ tidak sesuai dengan nama tabel, anda dapat meng-_override_
method [[yii\db\ActiveRecord::tableName()]] untuk menentukan nama tabel secara eksplisit.
Menggunakan class `Country`, anda bisa memanipulasi data pada tabel `country` dengan mudah, sebagaimana yang ditunjukkan pada kode di bawah ini:
```php
use app\models\Country;
// mengambil semua negara dari tabel country, dan mengurutkan berdasarkan "name" (nama)
$countries = Country::find()->orderBy('name')->all();
// mengambil negara yang memiliki primary key "US"
$country = Country::findOne('US');
// menampilkan "United States"
echo $country->name;
// Mengganti nama negara menjadi "U.S.A." dan menyimpan ke database
$country->name = 'U.S.A.';
$country->save();
```
> Info: _Active Record_ adalah cara yang efektif untuk mengakses dan memanipulasi data dari database secara _object-oriented_.
Anda bisa mengetahui lebih banyak lagi pada bagian [Active Record](db-active-record.md). Sebagai alternatif, anda mungkin berinteraksi dengan database menggunakan metode data akses yang lebih mendasar yang disebut [Data Access Objects](db-dao.md).
Membuat Action <span id="creating-action"></span>
------------------
Untuk menampilkan data negara ke pengguna, anda harus membuat _action_. Dibanding menempatkan _action_ baru ini pada _controller_ `site`
seperti yang sudah anda lakukan pada bagian sebelumnya, sekarang ini ada baiknya membuat spesifik _controller_
untuk semua _action_ yang berhubungan dengan data negara. Namakan _controller_ baru ini dengan `CountryController`, dan buat
_action_ `index` pada controller tersebut, seperti yang ditunjukkan di bawah ini.
```php
<?php
namespace app\controllers;
use yii\web\Controller;
use yii\data\Pagination;
use app\models\Country;
class CountryController extends Controller
{
public function actionIndex()
{
$query = Country::find();
$pagination = new Pagination([
'defaultPageSize' => 5,
'totalCount' => $query->count(),
]);
$countries = $query->orderBy('name')
->offset($pagination->offset)
->limit($pagination->limit)
->all();
return $this->render('index', [
'countries' => $countries,
'pagination' => $pagination,
]);
}
}
```
Simpan kode di atas pada file `controllers/CountryController.php`.
_Action_ `index` memanggil `Country::find()`. _Method_ _Active Record_ ini membuat _query_ ke database dan mengambil semua data negara dari tabel `country`.
Untuk membatasi jumlah negara yang didapatkan pada setiap pengambilan data, _query_ tersebut dipecah menjadi halaman per halaman dengan bantuan dari
objek [[yii\data\Pagination]]. Objek `Pagination` diperuntukkan untuk dua tujuan:
* Menentukan klausa `offset` dan `limit` pada perintah SQL yang digunakan untuk _query_ agar mengambil
hanya satu halaman data dalam sekali perintah (pada umumnya akan mengambil 5 baris dalam satu halaman).
* Digunakan pada _view_ untuk menampilkan tombol halaman yang terdiri dari tombol-tombol nomor halaman, yang selanjutnya akan dijelaskan
pada sub bagian berikutnya.
Di akhir kode, _action_ `index` me-_render_ _view_ dengan nama `index`, dan mengirimkan data negara beserta dengan informasi
halaman dari data tersebut.
Membuat View <span id="creating-view"></span>
---------------
Di dalam folder `views`, pertama-tama buatlah sub-folder dengan nama `country`. Folder ini akan digunakan untuk menyimpan semua
_view_ yang akan di _render_ oleh _controller_ `country`. Di dalam folder `views/country`, buatlah file dengan nama `index.php`
berisi kode di bawah ini:
```php
<?php
use yii\helpers\Html;
use yii\widgets\LinkPager;
?>
<h1>Countries</h1>
<ul>
<?php foreach ($countries as $country): ?>
<li>
<?= Html::encode("{$country->name} ({$country->code})") ?>:
<?= $country->population ?>
</li>
<?php endforeach; ?>
</ul>
<?= LinkPager::widget(['pagination' => $pagination]) ?>
```
Terkait dengan tampilan data negara, _view_ ini terdiri dari dua bagian. Bagian pertama, dilakukan perulangan _(looping)_ pada data negara yang tersedia dan di-_render_ sebagai _unordered list_ HTML.
Bagian kedua, _widget_ [[yii\widgets\LinkPager]] di-_render_ menggunakan informasi halaman _(pagination)_ yang dikirimkan dari _action_.
_Widget_ `LinkPager` menampilkan tombol-tombol halaman. Mengklik pada salah satu tombol tersebut akan melakukan pengambilan data negara
terkait dengan halaman yang diklik.
Mari Kita Coba <span id="trying-it-out"></span>
-------------
Untuk melihat bagaimana kode-kode di atas bekerja, gunakan browser anda untuk mengakses URL ini:
```
http://hostname/index.php?r=country%2Findex
```
![Daftar Country](images/start-country-list.png)
Awalnya, anda akan melihat sebuah halaman yang menampilkan 5 negara. Dibawah daftar negara tersebut, anda akan melihat tombol halaman yang berjumlah empat tombol.
Jika anda mengklik tombol "2", anda akan melihat halaman tersebut menampilkan 5 negara lain pada database: halaman kedua pada record.
Silahkan melakukan observasi secara perlahan-lahan dan anda akan mengetahui bahwa URL pada browser juga akan berganti menjadi
```
http://hostname/index.php?r=country%2Findex&page=2
```
Di belakang layar, [[yii\data\Pagination|Pagination]] menyediakan semua kebutuhkan untuk memecah data menjadi halaman per halaman:
* Pertama-tama, [[yii\data\Pagination|Pagination]] menampilkan halaman pertama, dimana menjalankan perintah SELECT pada tabel `country`
dengan klausa `LIMIT 5 OFFSET 0`. Hasilnya, 5 negara pertama akan diambil dan ditampilkan.
* _Widget_ [[yii\widgets\LinkPager|LinkPager]] me-_render_ tombol halaman menggunakan URL
yang dibentuk oleh method [[yii\data\Pagination::createUrl()|Pagination]]. URL tersebut mengandung _query string_ `page`, yang
merupakan representasi dari nomor halaman.
* Jika anda mengklik tombol halaman "2", sebuah _request_ yang mengarah ke _route_ `country/index` akan dijalankan hingga selesai.
[[yii\data\Pagination|Pagination]] membaca _query string_ `page` dari URL dan kemudian menentukan halaman sekarang adalah halaman 2.
Query data negara yang baru mengandung klausa `LIMIT 5 OFFSET 5` dan mengambil 5 data negara selanjutnya untuk
kemudian ditampilkan.
Rangkuman <span id="summary"></span>
-------
Pada bagian ini, anda mempelajari bagaimana bekerja dengan database. Anda juga mempelajari bagaimana cara mengambil dan membagi
data dengan halaman per halaman dengan bantuan [[yii\data\Pagination]] dan [[yii\widgets\LinkPager]].
Di bagian selanjutnya, anda akan mempelajari bagaimana menggunakan _generator_ kode yang disebut [Gii](https://github.com/yiisoft/yii2-gii/blob/master/docs/guide/README.md),
untuk membantu anda mengimplementasikan fitur-fitur umum pada aplikasi secara instan, seperti operasi _Create_-_Read_-_Update_-_Delete_ (CRUD)
untuk bekerja dengan data yang terdapat pada tabel di sebuah database. Sebenarnya, kode-kode yang barusan anda tulis, semuanya bisa
di _generate_ secara otomatis oleh Yii menggunakan tool Gii.

245
docs/guide-id/start-forms.md

@ -0,0 +1,245 @@
Bekerja dengan Form
==================
Bagian ini memaparkan bagaimana membuat halaman dengan form untuk mengambil data dari pengguna.
Halaman akan menampilkan form dengan input field Nama dan Email.
Setelah mendapatkan dua data dari pengguna, halaman akan menampilkan kembali data yang diinput pada form sebagai konfirmasi.
Untuk mencapai tujuan, disamping membuat sebuah [_action_](structure-controllers.md), dan
dua [_view_](structure-views.md), anda juga harus membuat [_model_](structure-models.md).
Sepanjang tutorial ini, anda akan mempelajari bagaimana cara untuk:
* Membuat sebuah [model](structure-models.md) sebagai representasi data yang diinput oleh pengguna melalui form,
* Membuat _rules_ untuk memvalidasi data yang telah diinput.
* Membuat form HTML di dalam [view](structure-views.md).
Membuat Model <span id="creating-model"></span>
----------------
Data yang akan diambil dari pengguna akan direpresentasikan oleh class model `EntryForm` sebagaimana ditunjukkan di bawah dan
di simpan pada file `models/EntryForm.php`. Silahkan membaca bagian [Class Autoloading](concept-autoloading.md)
untuk penjelasan lengkap mengenai penamaan file class.
```php
<?php
namespace app\models;
use Yii;
use yii\base\Model;
class EntryForm extends Model
{
public $name;
public $email;
public function rules()
{
return [
[['name', 'email'], 'required'],
['email', 'email'],
];
}
}
```
Class di _extends_ dari [[yii\base\Model]], class standar yang disediakan oleh Yii, yang secara umum digunakan
untuk representasi data dari form.
> Info: [[yii\base\Model]] digunakan sebagai _parent_ untuk class model yang tidak berhubungan dengan database.
[[yii\db\ActiveRecord]] normalnya digunakan sebagai _parent_ untuk class model yang berhubungan dengan tabel di database.
Class `EntryForm` terdiri dari dua _public property_, `name` dan `email`, dimana akan digunakan untuk menyimpan
data yang diinput oleh pengguna. Class ini juga terdapat _method_ yang dinamakan `rules()`, yang akan mengembalikan (_return_) sejumlah
pengaturan (_rules_) untuk memvalidasi data. Pengaturan validasi (_Validation Rules_) yang di deklarasikan harus mendeskripsikan bahwa
* kedua field, yaitu `name` and `email` wajib di input
* data `email` harus merupakan alamat email yang valid
Jika anda memiliki objek `EntryForm` yang sudah mengandung data yang di input oleh pengguna, anda boleh memanggil
method [[yii\base\Model::validate()|validate()]] untuk melaksanakan validasi data. Kegagalan validasi data
akan menentukan (_set_) property [[yii\base\Model::hasErrors|hasErrors]] menjadi `true`, dan anda dapat mengetahui pesan kegagalan validasi
melalui [[yii\base\Model::getErrors|errors]].
```php
<?php
$model = new EntryForm();
$model->name = 'Qiang';
$model->email = 'bad';
if ($model->validate()) {
// Valid!
} else {
// Tidak Valid!
// Panggil $model->getErrors()
}
```
Membuat Action <span id="creating-action"></span>
------------------
Selanjutnya, anda harus membuat `entry` _action_ pada controller `site` yang akan memanfaatkan model yang baru saja dibuat. Proses
membuat dan menggunakan _action_ dijelaskan pada bagian [Mengatakan Hello](start-hello.md).
```php
<?php
namespace app\controllers;
use Yii;
use yii\web\Controller;
use app\models\EntryForm;
class SiteController extends Controller
{
// ...kode lain...
public function actionEntry()
{
$model = new EntryForm();
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
// data yang valid diperoleh pada $model
// lakukan sesuatu terhadap $model di sini ...
return $this->render('entry-confirm', ['model' => $model]);
} else {
// menampilkan form pada halaman, ada atau tidaknya kegagalan validasi tidak masalah
return $this->render('entry', ['model' => $model]);
}
}
}
```
Pertama-tama, _action_ membuat objek `EntryForm`. Kemudian objek tersebut membangun model
menggunakan data dari `$_POST`, yang disediakan oleh Yii dengan method [[yii\web\Request::post()]].
Jika model berhasil dibuat (misal, jika pengguna telah mengirim form HTML), _action_ akan memanggil method
[[yii\base\Model::validate()|validate()]] untuk memastikan data yang di input tersebut valid.
> Info : _Expression_ `Yii::$app` adalah representasi dari objek [aplikasi](structure-applications.md),
dimana objek tersebut adalah _singleton_ yang bebas diakses secara global. Objek tersebut juga merupakan [service locator](concept-service-locator.md) yang
menyediakan _components_ seperti `request`, `response`, `db`, dll. untuk mendukung pekerjaan yang spesifik.
Pada kode di atas, _component_ `request` dari objek aplikasi digunakan untuk mengakses data `$_POST`.
Jika tidak ada error, _action_ akan me-_render_ _view_ bernama `entry-confirm` untuk menginformasikan ke pengguna bahwa pengiriman
data tersebut berhasil. Jika tidak ada data yang dikirim atau data tersebut tidak valid, _view_ `entry` yang akan di _render_,
dimana form HTML akan ditampilkan, beserta informasi kegagalan pengiriman form tersebut.
> Note: Pada contoh sederhana ini kita hanya me-_render_ halaman konfirmasi jika data yang dikirim tersebut valid. Pada prakteknya,
anda harus pertimbangkan untuk menggunakan [[yii\web\Controller::refresh()|refresh()]] atau [[yii\web\Controller::redirect()|redirect()]]
untuk mencegah [permasalahan pengiriman form](http://en.wikipedia.org/wiki/Post/Redirect/Get).
Membuat View <span id="creating-views"></span>
--------------
Terakhir, buatlah dua file _view_ dengan nama `entry-confirm` dan `entry`. _View_ ini akan di-_render_ oleh _action_ `entry`,
yang sebelumnya dibahas.
_View_ `entry-confirm` hanya menampilkan data nama dan email. File _view_ tersebut harus di simpan di `views/site/entry-confirm.php`.
```php
<?php
use yii\helpers\Html;
?>
<p>You have entered the following information:</p>
<ul>
<li><label>Name</label>: <?= Html::encode($model->name) ?></li>
<li><label>Email</label>: <?= Html::encode($model->email) ?></li>
</ul>
```
_View_ `entry` akan menampilkan form HTML. File _view_ tersebut harus di simpan di `views/site/entry.php`.
```php
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
?>
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($model, 'name') ?>
<?= $form->field($model, 'email') ?>
<div class="form-group">
<?= Html::submitButton('Submit', ['class' => 'btn btn-primary']) ?>
</div>
<?php ActiveForm::end(); ?>
```
_View_ ini menggunakan [_widget_](structure-widgets.md) yaitu [[yii\widgets\ActiveForm|ActiveForm]] untuk
membangun form HTML. _Method_ `begin()` dan `end()` dari _widget_ masing-masing berfungsi untuk me-_render_ tag pembuka dan penutup
dari form tag. Diantara dua method tersebut, akan dibuat field input oleh
method [[yii\widgets\ActiveForm::field()|field()]]. Input field yang pertama diperuntukkan untuk data "name",
dan yang kedua diperuntukkan untuk data "email". Setelah field input, _method_ [[yii\helpers\Html::submitButton()]]
akan dipanggil untuk me-_render_ tombol pengiriman data.
Mari kita uji <span id="trying-it-out"></span>
-------------
Untuk melihat bagaimana prosesnya, gunakan browser anda untuk mengakses URL ini :
```
http://hostname/index.php?r=site%2Fentry
```
Anda akan melihat halaman yang menampilkan form dengan dua field input. Dibagian atas dari semua input field, ada label yang menginformasikan data yang mana yang akan diinput. Jika anda menekan tombol pengiriman data tanpa
menginput apapun, atau anda tidak menginput email address yang tidak valid, anda akan melihat pesan kegagalan yang di tampilkan di bagian bawah field input yang bermasalah.
![Form yang validasinya gagal](images/start-form-validation.png)
Setelah menginput nama dan alamat email yang benar dan menekan tombol kirim, anda akan melihat halaman baru
yang menampilkan data yang barusan anda input.
![Konfirmasi penginputan data](images/start-entry-confirmation.png)
### Penjelasan <span id="magic-explained"></span>
Anda mungkin bertanya-tanya bagaimana form HTML bekerja dibelakang layar, sepertinya tampak ajaib karna form tersebut mampu
menampilkan label di setiap field input dan menampilkan pesan kegagalan jika anda tidak menginput data dengan benar
tanpa me-_reload_ halaman.
Betul, validasi data sebenarnya dilakukan di sisi klien menggunakan Javascript, dan selanjutnya dilakukan lagi di sisi server menggunakan PHP.
[[yii\widgets\ActiveForm]] cukup cerdas untuk menerjemahkan pengaturan validasi yang anda deklarasikan pada class `EntryForm`,
kemudian merubahnya menjadi kode Javascript, dan menggunakan Javascript untuk melakukan validasi data. Jika saja anda menonaktifkan
Javascript pada browser anda, validasi tetap akan dilakukan di sisi server, sepertinya yang ditunjukkan pada
_method_ `actionEntry`. Hal ini memastikan bahwa data akan divalidasi dalam segala kondisi.
> Warning: Validasi melalui sisi klien akan membuat pengalaman pengguna lebih baik. Validasi di sisi server
harus selalu dilakukan, walaupun validasi melalui sisi klien digunakan atau tidak.
Label untuk field input dibuat oleh method `field()`, menggunakan nama _property_ dari model.
Contoh, label `Name` akan dibuat untuk _property_ `name`.
Anda boleh memodifikasi label di dalam view menggunakan
kode seperti di bawah ini:
```php
<?= $form->field($model, 'name')->label('Your Name') ?>
<?= $form->field($model, 'email')->label('Your Email') ?>
```
> Info: Yii menyediakan banyak _widget_ untuk membantu anda dalam membangun _view_ yang kompleks dan dinamis.
Sebentar lagi anda akan mengetahui, bahwa menulis _widget_ juga sangat mudah. Anda mungkin akan mengganti sebagian besar
dari kode _view_ anda menjadi _widget-widget_ yang mampu digunakan ulang untuk menyederhanakan penulisan _view_ ke depannya.
Rangkuman <span id="summary"></span>
-------
Pada bagian kali ini, anda telah mengetahui semua bagian dari pola arsitektur MVC. Anda sudah mempelajari bagaimana
untuk membuat class model sebagai representasi data pengguna dan memvalidasinya.
Anda juga mempelajari bagaimana mengambil data dari pengguna dan bagaimana menampilkan kembali data tersebut ke browser. Pekerjaan seperti ini
biasanya memakan waktu lama pada saat mengembangkan aplikasi, tetapi Yii menyediakan _widget_ yang bermanfaat
yang akan membuat pekerjaan ini menjadi lebih mudah.
Di bagian selanjutnya, anda akan mempelajari bagaimana untuk bekerja dengan database, dimana hal tersebut hampir sangat dibutuhkan pada setiap aplikasi.

139
docs/guide-id/start-gii.md

@ -0,0 +1,139 @@
Membuat Kode menggunakan Gii
========================
Bagian ini akan menjelaskan bagaimana cara menggunakan [Gii](https://github.com/yiisoft/yii2-gii/blob/master/docs/guide/README.md) untuk membuat kode secara otomatis
yang mengimplementasikan fitur-fitur yang bersifat umum dalam sebuah web site. Menggunakan Gii untuk membuat kode sesederhana menginput informasi yang sesuai per satu instruksi seperti yang diterangkan pada halaman web Gii.
Sepanjang bagian ini, anda akan mempelajari bagaimana cara untuk:
* Mengaktifkan Gii pada aplikasi anda,
* Menggunakan Gii untuk membuat _class ActiveRecord_
* Menggunakan Gii untuk membuat kode yang mengoperasikan CRUD untuk database,
* Memodifikasi kode yang sudah dibuat oleh Gii.
Memulai Gii <span id="starting-gii"></span>
------------
[Gii](https://github.com/yiisoft/yii2-gii/blob/master/docs/guide/README.md) telah disediakan oleh Yii sebagai [module](structure-modules.md). Anda dapat mengaktifkan Gii
dengan mengatur konfigurasi Gii pada properti [[yii\base\Application::modules|modules]] dari objek aplikasi. Tergantung bagaimana anda mengatur aplikasi anda, kode di bawah ini sudah disediakan pada file konfigurasi `config/web.php`:
```php
$config = [ ... ];
if (YII_ENV_DEV) {
$config['bootstrap'][] = 'gii';
$config['modules']['gii'] = [
'class' => 'yii\gii\Module',
];
}
```
Konfigurasi di atas menyatakan bahwa, ketika mode [development environment](concept-configurations.md#environment-constants) aktif,
maka aplikasi harus mengikutkan module yang bernama `gii`, dimana objek tersebut merupakan class [[yii\gii\Module]].
Jika anda melihat [_entry script_](structure-entry-scripts.md) `web/index.php` pada aplikasi anda, anda akan
menemukan baris dibawah ini, yang menyatakan secara explisit bahwa `YII_ENV_DEV` sama dengan `true`.
```php
defined('YII_ENV') or define('YII_ENV', 'dev');
```
Karna baris tersebut, aplikasi anda harusnya sudah berada pada mode _development_, dan secara otomatis mengaktifkan Gii karena konfigurasi sebelumnya. Anda dapat mengakses Gii melalui URL di bawah ini:
```
http://hostname/index.php?r=gii
```
> Note: Jika anda mengakses Gii melalui komputer diluar komputer localhost anda, secara default akses tidak akan diperbolehkan
> karna alasan keamanan. Anda dapat mengatur Gii untuk menambah alamat IP yang di perbolehkan seperti ini,
>
```php
'gii' => [
'class' => 'yii\gii\Module',
'allowedIPs' => ['127.0.0.1', '::1', '192.168.0.*', '192.168.178.20'] // adjust this to your needs
],
```
![Gii](images/start-gii.png)
Membuat class _Active Record_ <span id="generating-ar"></span>
---------------------------------
Untuk menggunakan Gii dalam membuat class Active Record, pilih "Model Generator" (dengan cara mengklik link pada halaman index Gii). Kemudian isi form dengan data berikut:
* Table Name: `country`
* Model Class: `Country`
![Pembuat Model](images/start-gii-model.png)
Selanjutnya, klik pada tombol "Preview". Anda akan melihat `models/Country.php` pada daftar class yang akan dibuat. Anda bisa mengklik nama dari class tersebut untuk melihat isi kodenya.
Pada saat menggunakan Gii, jika anda sudah membuat file dengan nama yang sama sebelumnya dan akan menimpanya, klik
tombol `diff` disebelah nama file untuk melihat perbedaan antara kode yang akan dibuat
dengan kode yang ada saat ini.
![Preview Pembuat Model](images/start-gii-model-preview.png)
Jika akan menimpa file yang sudah ada, centang kotak di sebelah tulisan "overwrite" dan kemudian klik tombol "Generate". Jika anda membuat file baru, anda cukup mengklik tombol "Generate".
Selanjutnya, anda akan melihat
halaman konfirmasi yang memberitahui bahwa kode berhasil dibuat. Jika sebelumnya anda sudah mempunyai file yang sama, anda juga akan melihat pesan yang memberitahukan bahwa file tersebut sudah ditimpa dengan file yang baru.
Membuat CRUD <span id="generating-crud"></span>
--------------------
_CRUD_ adalah _Create, Read, Update,_ dan _Delete_, yang merepresentasikan empat tugas umum yang melibatkan website secara umum. Untuk membuat _CRUD_ menggunakan Gii, pilih tombol "CRUD Generator" (dengan cara mengklik pada halaman index Gii). Untuk contoh "negara", isi form yang ditampilkan dengan data berikut:
* Model Class: `app\models\Country`
* Search Model Class: `app\models\CountrySearch`
* Controller Class: `app\controllers\CountryController`
![Pembuat CRUD](images/start-gii-crud.png)
Selanjutnya, klik tombol "Preview". Anda akan melihat daftar file-file yang akan dibuat, seperti gambar dibawah ini.
![Preview Pembuat CRUD](images/start-gii-crud-preview.png)
Jika anda sebelumnya sudah membuat file `controllers/CountryController.php` dan
`views/country/index.php` (pada bagian bekerja dengan database), centang kotak "overwrite" untuk menimpa file tersebut. (File pada bagian bekerja dengan database tidak memiliki dukungan CRUD secara penuh.)
Mari kita coba <span id="trying-it-out"></span>
-------------
Untuk melihat bagaimana proses kerjanya, gunakan browser anda untuk mengakses URL dibawah ini:
```
http://hostname/index.php?r=country%2Findex
```
Anda akan melihat tabel data yang menampilkan negara dari tabel pada database. Anda dapat mengurutkan tabel,
atau memfilter dengan menginput pencarian filter pada baris judul kolom.
Disetiap negara yang tampil pada tabel, anda dapat memilih apakah akan melihat (_view_) detail, memperbaharui (_update_), atau menghapus (_delete_) data tersebut,
anda juga dapat mengklik tombol "Create Country" yang berada di atas tabel tersebut untuk menampilkan form untuk membuat data negara yang baru.
![Tabel data negara](images/start-gii-country-grid.png)
![Memperbaharui data negara](images/start-gii-country-update.png)
Dibawah ini adalah daftar file yang dihasilkan oleh Gii, mungkin saja anda ingin melakukan observasi bagaimana fitur-fitur ini di implementasikan,
atau melakukan modifikasi terhadap file-file yang dihasilkan:
* Controller: `controllers/CountryController.php`
* Model: `models/Country.php` dan `models/CountrySearch.php`
* View: `views/country/*.php`
> Info: Gii di desain agar mudah di modifikasi, dan dikembangkan. Menggunakan Gii
dapat membuat pengembangan aplikasi anda menjadi lebih cepat. Untuk informasi lebih lanjut, silahkan melihat
bagian [Gii](https://github.com/yiisoft/yii2-gii/blob/master/docs/guide/README.md).
Penutup <span id="summary"></span>
-------
Pada bagian ini, anda telah mengetahui bagaimana cara menggunakan Gii untuk membuat kode yang mengimplementasikan
fungsi CRUD secara lengkap dalam mengelola data yang tersimpan pada database.

35
docs/guide-id/start-looking-ahead.md

@ -0,0 +1,35 @@
Menatap ke Depan
================
Jika anda membaca sepanjang bab "Mulai", sekarang anda sudah membuat aplikasi dengan Yii. Pada proses ini, anda sudah mempelajari bagaimana mengimplementasikan fitur-fitur umum
yang dibutuhkan, seperti mengambil data dari pengguna melalui form HTML, mengambil data dari database, dan
menampilkan data dengan halaman per halaman. Anda juga sudah mempelajari bagaimana menggunakan [Gii](https://github.com/yiisoft/yii2-gii/blob/master/docs/guide/README.md) untuk membuat
kode secara otomatis. Menggunakan Gii dalam membuat kode, mengubah tugas-tugas pengembangan web yang cukup banyak menjadi satu tugas sederhana, sesederhana mengisi form.
Bagian ini akan merangkum bacaan Yii yang tersedia untuk membantu anda menjadi lebih produktif dalam menggunakan framework ini.
* Dokumentasi
- [Panduan Definitif](http://www.yiiframework.com/doc-2.0/guide-README.html):
Sesuai dengan judulnya, panduan ini merincikan bagaimana Yii seharusnya bekerja dan menyediakan petunjuk umum
tentang menggunakan Yii. Panduan ini sangat-sangat penting, dan panduan ini yang harus anda baca
sebelum menulis kode Yii.
- [Referensi Class](http://www.yiiframework.com/doc-2.0/index.html):
Ini menjelaskan bagaimana menggunakan semua class yang disediakan oleh Yii. Pada umumnya anda akan menggunakan ini ketika anda sedang menulis
kode dan ingin memahami bagaimana penggunaan _class, method, property_. Sebaiknya anda membaca referensi class ini ketika anda memilik pemahaman dasar tentang seluruh bagian framework.
- [Artikel Wiki](http://www.yiiframework.com/wiki/?tag=yii2):
Artikel wiki ditulis oleh para pengguna Yii berdasarkan pengalaman pribadi masing-masing. Kebanyakan dari artikel ini ditulis
seperti layaknya panduan memasak, dan menunjukkan bagaimana menyelesaikan beberapa masalah dengan menggunakan Yii. Walaupun kualitas artikel-artikel ini
mungkin tidak selengkap Panduan Definitif, tetapi artikel ini terkadang lebih bermanfaat karna membahas topik yang cukup luas
dan mungkin mampu menyediakan solusi-solusi yang sederhana.
- [Buku](http://www.yiiframework.com/doc/)
* [Extensions](http://www.yiiframework.com/extensions/):
Yang harus dibanggakan adalah Yii memiliki ribuan library extension yang dibuat oleh pengguna yang dapat dipasang di aplikasi anda dengan mudah, dan akan membuat pengembangan aplikasi anda lebih mudah dan cepat.
* Komunitas
- Forum: <http://www.yiiframework.com/forum/>
- IRC: Kanal #yii di freenode (<irc://irc.freenode.net/yii>)
- Gitter: <https://gitter.im/yiisoft/yii2>
- GitHub: <https://github.com/yiisoft/yii2>
- Facebook: <https://www.facebook.com/groups/yiitalk/>
- Twitter: <https://twitter.com/yiiframework>
- LinkedIn: <https://www.linkedin.com/groups/yii-framework-1483367>
- Stackoverflow: <http://stackoverflow.com/questions/tagged/yii2>

119
docs/guide-id/structure-application-components.md

@ -0,0 +1,119 @@
Komponen Aplikasi
=================
Objek Aplikasi _(Application)_ adalah [service locators](concept-service-locator.md). Objek ini menampung seperangkat
apa yang kita sebut sebagai *komponen aplikasi* yang menyediakan berbagai layanan untuk menangani proses _request_. Sebagai contoh,
_component_ `urlManager` bertanggung jawab untuk menentukan _route_ dari _request_ menuju _controller_ yang sesuai;
_component_ `db` menyediakan layanan terkait database; dan sebagainya.
Setiap _component_ aplikasi memiliki sebuah ID yang mengidentifikasi dirinya secara unik dengan _component_ aplikasi lainnya
di dalam aplikasi yang sama. Anda dapat mengakses _component_ aplikasi melalui _expression_ berikut ini:
```php
\Yii::$app->componentID
```
Sebagai contoh, anda dapat menggunakan `\Yii::$app->db` untuk mengambil [[yii\db\Connection|koneksi ke DB]],
dan `\Yii::$app->cache` untuk mengambil [[yii\caching\Cache|cache utama]] yang terdaftar dalam aplikasi.
Sebuah _component_ aplikasi dibuat pertama kali pada saat objek tersebut pertama diakses menggunakan _expression_ di atas. Pengaksesan
berikutnya akan mengembalikan objek _component_ yang sama.
_Component_ aplikasi bisa merupakan objek apa saja. Anda dapat mendaftarkannya dengan mengatur
_property_ [[yii\base\Application::components]] pada [konfigurasi aplikasi](structure-applications.md#application-configurations).
Sebagai contoh,
```php
[
'components' => [
// mendaftarkan component "cache" menggunakan nama class
'cache' => 'yii\caching\ApcCache',
// mendaftaran component "db" menggunakan konfigurasi array
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=demo',
'username' => 'root',
'password' => '',
],
// mendaftaran component "search" menggunakan anonymous function
'search' => function () {
return new app\components\SolrService;
},
],
]
```
> Info: Walaupun anda dapat mendaftarkan _component_ aplikasi sebanyak yang anda inginkan, anda harus bijaksana dalam melakukan hal ini.
_Component_ aplikasi seperti layaknya variabel global. Menggunakan _component_ aplikasi yang terlalu banyak dapat berpotensi
membuat kode anda menjadi rumit untuk diujicoba dan dikelola. Dalam banyak kasus, anda cukup membuat _component_ lokal
dan menggunakannya pada saat diperlukan.
## _Bootstrap Components_ <span id="bootstrapping-components"></span>
Seperti yang disebutkan di atas, sebuah _component_ aplikasi akan dibuat ketika _component_ diakses pertama kali.
Jika tidak diakses sepanjang _request_ diproses, objek tersebut tidak akan dibuat. Terkadang, anda ingin
membuat objek _component_ aplikasi tersebut untuk setiap _request_, walaupun _component_ tersebut tidak diakses secara eksplisit.
Untuk melakukannya, anda dapat memasukkan ID _component_ tersebut ke _property_ [[yii\base\Application::bootstrap|bootstrap]] dari objek _Application_.
Sebagai contoh, konfigurasi aplikasi di bawah ini memastikan bahwa objek _component_ `log` akan selalu dibuat disetiap _request_:
```php
[
'bootstrap' => [
'log',
],
'components' => [
'log' => [
// Konfigurasi untuk component "log"
],
],
]
```
## _Component_ Aplikasi Inti <span id="core-application-components"></span>
Yii menentukan seperangkat _component_ aplikasi inti dengan ID tetap dan konfigurasi default. Sebagai contoh,
_component_ [[yii\web\Application::request|request]] digunakan untuk memperoleh informasi tentang
_request_ dari pengguna dan merubahnya menjadi [route](runtime-routing.md). _Component_ [[yii\base\Application::db|db]]
merepresentasikan sebuah koneksi ke database yang bisa anda gunakan untuk menjalankan _query_ ke database.
Dengan bantuan _component_ inti inilah maka aplikasi Yii bisa menangani _request_ dari pengguna.
Dibawah ini adalah daftar dari _component_ aplikasi inti. Anda dapat mengatur dan memodifikasinya
seperti _component_ aplikasi pada umumnya. Ketika anda mengatur _component_ aplikasi inti,
jika anda tidak mendefinisikan _class_-nya, maka _class_ default yang akan digunakan.
* [[yii\web\AssetManager|assetManager]]: mengatur bundel aset _(asset bundles)_ dan publikasi aset _(asset publishing)_.
Harap melihat bagian [Pengelolaan Aset](structure-assets.md) untuk informasi lebih lanjut.
* [[yii\db\Connection|db]]: merepresentasikan sebuah koneksi database yang bisa anda gunakan untuk melakukan _query_ ke database.
Sebagai catatan, ketika anda mengatur _component_ ini, anda harus menentukan nama _class_ dari _component_ dan _property_ lain dari
_component_ yang dibutuhkan, seperti [[yii\db\Connection::dsn]].
Harap melihat bagian [Data Access Objects](db-dao.md) untuk informasi lebih lanjut.
* [[yii\base\Application::errorHandler|errorHandler]]: menangani error PHP dan _exception_.
Harap melihat bagian [Menangani Error](runtime-handling-errors.md) untuk informasi lebih lanjut.
* [[yii\i18n\Formatter|formatter]]: memformat data ketika data tersebut ditampilkan ke pengguna. Sebagai contoh, sebuah angka
mungkin ditampilkan menggunakan separator ribuan, dan tanggal mungkin diformat dalam format panjang.
Harap melihat bagian [Memformat Data](output-formatting.md) untuk informasi lebih lanjut.
* [[yii\i18n\I18N|i18n]]: mendukung penerjemahan dan format pesan _(message)_.
Harap melihat bagian [Internasionalisasi](tutorial-i18n.md) untuk informasi lebih lanjut.
* [[yii\log\Dispatcher|log]]: mengelola target log.
Harap melihat bagian [Log](runtime-logging.md) untuk informasi lebih lanjut.
* [[yii\swiftmailer\Mailer|mailer]]: mendukung pembuatan dan pengiriman email.
Harap melihat bagian [Mail](tutorial-mailing.md) untuk informasi lebih lanjut.
* [[yii\base\Application::response|response]]: merepresentasikan _response_ yang dikirimkan ke pengguna.
Harap melihat bagian [Response](runtime-responses.md) untuk informasi lebih lanjut.
* [[yii\base\Application::request|request]]: merepresentasikan _request_ yang diterima dari pengguna.
Harap melihat bagian [Request](runtime-requests.md) untuk informasi lebih lanjut.
* [[yii\web\Session|session]]: merepresentasikan informasi _session_. _Component_ ini hanya tersedia pada
objek [[yii\web\Application|Aplikasi Web]].
Harap melihat bagian [Session dan Cookie](runtime-sessions-cookies.md) untuk informasi lebih lanjut.
* [[yii\web\UrlManager|urlManager]]: mendukung penguraian dan pembuatan URL.
Harap melihat bagian [Route dan Pembuatan URL](runtime-routing.md) untuk informasi lebih lanjut.
* [[yii\web\User|user]]: merepresentasikan informasi otentikasi dari pengguna. _Component_ ini hanya tersedia pada
objek [[yii\web\Application|Aplikasi Web]].
Harap melihat bagian [Otentikasi](security-authentication.md) untuk informasi lebih lanjut.
* [[yii\web\View|view]]: mendukung proses _render view_.
Harap melihat bagian [View](structure-views.md) untuk informasi lebih lanjut.

609
docs/guide-id/structure-applications.md

@ -0,0 +1,609 @@
Aplikasi
========
Aplikasi _(Application)_ adalah objek yang mengelola semua struktur dan siklus dari sistem aplikasi Yii.
Setiap aplikasi sistem Yii mengandung satu objek aplikasi yang dibuat dalam
[skrip masuk](structure-entry-scripts.md) dan mampu diakses secara global melalui _expression_ `\Yii::$app`.
> Info: Jika kami mengatakan "sebuah aplikasi", itu bisa diartikan sebagai sebuah objek aplikasi
atau sebuah sistem aplikasi, tergantung bagaimana konteksnya.
Terdapat dua tipe aplikasi: [[yii\web\Application|Aplikasi Web]] dan
[[yii\console\Application|Aplikasi Konsol]]. Sesuai dengan namanya, yang pertama bertujuan untuk menangani
_web request_, sedangkan yang kedua menangani _request_ perintah pada konsol.
## Konfigurasi Aplikasi <span id="application-configurations"></span>
Ketika [skrip masuk](structure-entry-scripts.md) membuat objek aplikasi, objek ini akan mengambil dan memuat
sebuah [array konfigurasi](concept-configurations.md) dan menerapkannya pada objek aplikasi seperti berikut ini:
```php
require(__DIR__ . '/../vendor/autoload.php');
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
// memuat konfigurasi aplikasi
$config = require(__DIR__ . '/../config/web.php');
// membuat objek aplikasi & menerapkan konfigurasi
(new yii\web\Application($config))->run();
```
Seperti layaknya [konfigurasi](concept-configurations.md) normal, konfigurasi aplikasi menentukan bagaimana
proses inisialisasi _property_ dari objek aplikasi. Karena konfigurasi aplikasi pada umumnya
sangat kompleks, oleh karena itu konfigurasi tersebut di simpan dalam [file konfigurasi](concept-configurations.md#configuration-files),
seperti file `web.php` pada contoh di atas.
## _Property_ Aplikasi <span id="application-properties"></span>
Terdapat cukup banyak _property_ aplikasi penting yang harus anda atur dalam konfigurasi aplikasi.
_Property_ ini secara khusus menjelaskan _environment_ yang sedang dijalankan oleh aplikasi.
Sebagai contoh, aplikasi ingin mengetahui bagaimana cara memuat [controller](structure-controllers.md),
dimana seharusnya aplikasi menyimpan file-file yang bersifat sementara _(temporary files)_, dll. Kami akan meringkas _property_ tersebut dibawah ini:
### _Property_ Wajib <span id="required-properties"></span>
Dalam aplikasi apapun, anda harus menentukan setidaknya dua _property_:[[yii\base\Application::id|id]]
dan [[yii\base\Application::basePath|basePath]].
#### [[yii\base\Application::id|id]] <span id="id"></span>
_Property_ [[yii\base\Application::id|id]] menentukan ID unik yang membedakan objek aplikasi
dengan yang lainnya. Ini pada umumnya digunakan secara programatik. Walaupun hal ini bukanlah sebuah keharusan, karena persoalan pertukaran informasi,
anda sangat direkomendasikan hanya menggunakan karakter alfanumerik ketika menentukan ID dari sebuah aplikasi.
#### [[yii\base\Application::basePath|basePath]] <span id="basePath"></span>
_Property_ [[yii\base\Application::basePath|basePath]] menentukan direktori _root_ dari sebuah aplikasi.
Yaitu direktori yang menyimpan semua sumber kode aplikasi sistem, dan aksesnya diproteksi dari luar. Didalam direktori ini,
anda akan melihat sub-direktori seperti `models`, `views`, dan `controllers` yang menyimpan sumber kode
dari pola MVC.
Anda dapat menentukan _property_ [[yii\base\Application::basePath|basePath]] menggunakan _directory path_
atau [path alias](concept-aliases.md). Kedua bentuk ini, direktori yang dimaksud harus benar-benar ada, jika tidak maka sebuah _exception_
akan di-_throw_. _Path_ akan dinormalkan dengan memanggil _function_ `realpath()`.
_Property_ [[yii\base\Application::basePath|basePath]] pada umumnya digunakan untuk mengambil _path_ penting
lainnya (contoh _runtime path_). Karna itulah _alias path_ yang dinamakan `@app` disediakan untuk merepresentasikan _path_
ini. _Path-path_ lainnya boleh dipanggil menggunakan alias ini (contoh: `@app/runtime` untuk merujuk ke direktori runtime).
### _Property_ Penting <span id="important-properties"></span>
_Property_ yang dijelaskan di sub-bagian ini cenderung harus di tentukan karena mereka digunakan secara berbeda
di lintas aplikasi.
#### [[yii\base\Application::aliases|Alias]] <span id="aliases"></span>
_Property_ ini memungkinkan anda untuk menentukan seperangkat [alias](concept-aliases.md) dalam bentuk _array_.
_Array Key_ merupakan nama alias, dan _Array Value_ adalah definisi path yang dimaksud.
Sebagai contoh:
```php
[
'aliases' => [
'@nama1' => 'path/menuju/ke/path1',
'@nama2' => 'path/menuju/ke/path2',
],
]
```
Karna tersedianya _property_ ini, anda bisa menentukan beberapa alias pada konfigurasi aplikasi dibanding
dengan memanggil _method_ [[Yii::setAlias()]].
#### [[yii\base\Application::bootstrap|bootstrap]] <span id="bootstrap"></span>
_Property_ ini merupakan _property_ yang bermanfaat. _Property_ ini memungkinkan anda untuk menentukan _component_ berbentuk _array_ yang harus
dijalankan dalam [[yii\base\Application::bootstrap()|proses bootstrap]].
Sebagai contoh, jika anda memerintahkan sebuah [module](structure-modules.md) untuk merubah [pengaturan URL](runtime-routing.md),
anda dapat menyusun ID-nya sebagai elemen dari _property_ ini.
Setiap _component_ yang terdaftar pada _property_ ini dapat ditentukan berdasarkan salah satu dari format berikut ini:
- ID dari _Component_ aplikasi yang ditentukan melalui [component](#components),
- ID dari _module_ yang ditentukan melalui [module](#modules),
- Nama _class_,
- Konfigurasi _array_,
- _anonymous function_ yang membuat dan mengembalikan _(return)_ sebuah _component_.
Sebagai contoh:
```php
[
'bootstrap' => [
// Component ID atau Module ID
'demo',
// Nama Class
'app\components\Profiler',
// Konfigurasi dalam bentuk array
[
'class' => 'app\components\Profiler',
'level' => 3,
],
// anonymous function
function () {
return new app\components\Profiler();
}
],
]
```
> Info: Jika ID _module_ tersebut sama dengan ID _component_ aplikasi, _component_ aplikasi tersebut yang akan dipakai
> pada saat proses _boostrap_. Jika anda ingin menggunakan _module_, anda dapat menentukannya melalui _anonymous function_
> seperti berikut ini:
>
> ```php
> [
> function () {
> return Yii::$app->getModule('user');
> },
> ]
> ```
Sepanjang proses _bootstrap_, setiap _component_ akan dibuat objeknya. Jika _class component_
mengimplementasikan _method interface_ [[yii\base\BootstrapInterface]], _method_ [[yii\base\BootstrapInterface::bootstrap()|bootstrap()]] dari class tersebut
juga akan dipanggil.
Salah satu contoh praktis lainnya adalah konfigurasi aplikasi untuk [Template Proyek Dasar](start-installation.md),
dimana _module_ `debug` dan `gii` ditentukan sebagai _component bootstrap_ ketika aplikasi sedang dijalankan
dalam mode pengembangan:
```php
if (YII_ENV_DEV) {
// penyesuaian konfigurasi untuk environment 'dev'
$config['bootstrap'][] = 'debug';
$config['modules']['debug'] = 'yii\debug\Module';
$config['bootstrap'][] = 'gii';
$config['modules']['gii'] = 'yii\gii\Module';
}
```
> Note: Menentukan terlalu banyak _component_ pada `bootstrap` akan menurunkan performa dari aplikasi anda, dikarenakan
_component_ yang sama tersebut harus dijalakan dalam setiap _request_. Jadi gunakanlah _component bootstrap_ dengan bijaksana.
#### [[yii\web\Application::catchAll|catchAll]] <span id="catchAll"></span>
_Property_ ini hanya dikenali oleh [[yii\web\Application|Web applications]]. _Property_ ini menentukan
sebuah [action dari controller](structure-controllers.md) yang ditugaskan menangani semua _request_ dari pengguna. _Property_ ini biasanya
digunakan ketika aplikasi dalam mode pemeliharaan _(maintenance)_ yang mengarahkan semua _request_ menuju satu _action_.
Konfigurasinya yaitu sebuah _array_ dimana elemen pertama menentukan _route_ dari _action_.
Element lainnya _(sepasang key-value)_ menentukan parameter yang akan diteruskan ke _action_. Sebagai contoh:
```php
[
'catchAll' => [
'offline/notice',
'param1' => 'value1',
'param2' => 'value2',
],
]
```
> Info: Panel _Debug_ pada _development environment_ tidak akan berfungsi ketika _property_ ini diisi.
#### [[yii\base\Application::components|components]] <span id="components"></span>
_Property_ ini adalah salah satu _property_ yang sangat penting. _Property_ ini memperbolehkan anda mendaftarkan beberapa _component_
yang disebut [_component_ aplikasi](structure-application-components.md) yang bisa anda gunakan di tempat lain. Sebagai contoh:
```php
[
'components' => [
'cache' => [
'class' => 'yii\caching\FileCache',
],
'user' => [
'identityClass' => 'app\models\User',
'enableAutoLogin' => true,
],
],
]
```
Setiap _component_ aplikasi ditentukan dengan sepasang _key-value_ ke dalam _array_. _Key_ merepresentasikan ID _component_,
dimana _value_ merepresentasikan nama class dari _component_ atau [konfigurasi _array_](concept-configurations.md).
Anda dapat mendaftaran _component_ apapun ke dalam objek aplikasi, dan nantinya _component_ tersebut dapat diakses secara global
menggunakan _expression_ `\Yii::$app->componentID`.
Harap membaca bagian [_Component_ Aplikasi](structure-application-components.md) untuk penjelasan lebih lanjut.
#### [[yii\base\Application::controllerMap|controllerMap]] <span id="controllerMap"></span>
_Property_ ini memperbolehkan anda untuk melakukan _mapping_ sebuah ID _controller_ ke class _controller_ yang anda inginkan. Secara default, Yii melakukan mapping
ID _controller_ ke _class controller_ berdasarkan [kaidah yang ditentukan](#controllerNamespace) (Contoh: ID `post` akan di _mapping_
ke `app\controllers\PostController`). Dengan menentukan _property_ ini, anda diperbolehkan untuk tidak mengikuti kaidah untuk
spesifik _controller_. Pada contoh dibawah ini, `account` akan di _mapping_ ke
`app\controllers\UserController`, sedangkan `article` akan di _mapping_ ke `app\controllers\PostController`.
```php
[
'controllerMap' => [
'account' => 'app\controllers\UserController',
'article' => [
'class' => 'app\controllers\PostController',
'enableCsrfValidation' => false,
],
],
]
```
_Key array_ dari _property_ ini merepresentasikan ID _controller_, sedangkan _value_ merepresentasikan nama _class
yang dimaksud atau [konfigurasi _array_](concept-configurations.md).
#### [[yii\base\Application::controllerNamespace|controllerNamespace]] <span id="controllerNamespace"></span>
_Property_ ini menentukan _namespace_ default dimana _class controller_ tersebut harus dicari. Default ke
`app\controllers`. Jika ID _controller_ adalah `post`, secara kaidah, nama _class controller_-nya (tanpa
_namespace_) adalah `PostController`, dan `app\controllers\PostController` adalah nama class lengkapnya _(Fully Qualified Class Name)_.
_class controller_ juga boleh disimpan dalam sub-direktori dari direktori yang dimaksud _namespace_ ini.
Sebagai contoh, jika ada ID _controller_ `admin/post`, nama class lengkap yang dimaksud adalah
`app\controllers\admin\PostController`.
Sangatlah penting bahwa nama class lengkap dari _controller_ tersebut [bisa di-autoload](concept-autoloading.md)
dan _namespace_ dari _class controller_ anda cocok dengan nilai dari _property_ ini. Jika tidak,
anda akan melihat error "Halaman tidak ditemukan" ketika mengakses aplikasi.
Jika saja anda tidak ingin mengikut kaidah-kaidah yang dijelaskan di atas, anda boleh menentukan _property_
[controllerMap](#controllerMap).
#### [[yii\base\Application::language|language]] <span id="language"></span>
_Property_ ini menentukan bahasa apa yang seharusnya ditampilkan pada konten aplikasi ke pengguna.
Nilai default dari _property_ ini adalah `en`, yang merupakan Bahasa Inggris. Anda harus menentukan _property_ ini
jika aplikasi anda menyediakan konten dalam berbagai bahasa.
Nilai dari _property_ ini menentukan banyak aspek dari [internasionalisasi](tutorial-i18n.md),
termasuk penerjemahan pesan, format tanggal, format penomoran, dll. Sebagai contoh, _widget_ [[yii\jui\DatePicker]]
akan menggunakan _property_ ini secara _default_ untuk menentukan bahasa apa yang digunakan pada kalender yang ditampilkan dan bagaimana
format tanggal pada kalender tersebut.
Disarankan agar anda menentukan bahasa dalam format [Tag Bahasa IETF](http://en.wikipedia.org/wiki/IETF_language_tag).
Sebagai contoh, `en` berarti Bahasa Inggris, sedangkan `en-US` berarti Bahasa Inggris yang digunakan di Amerika Serikat.
Informasi selengkapnya mengenai _property_ ini dapat dipelajari di bagian [Internasionalisasi](tutorial-i18n.md).
#### [[yii\base\Application::modules|modules]] <span id="modules"></span>
_Property_ ini menentukan [module](structure-modules.md) apa yang akan digunakan oleh aplikasi.
_Property_ ini ditentukan menggunakan _array_ dari _class class modul_ atau [konfigurasi _array_](concept-configurations.md) dimana _array key_
merupakan ID dari _module_ tersebut. Berikut contohnya:
```php
[
'modules' => [
// modul "booking" dengan class module yang ditentukan
'booking' => 'app\modules\booking\BookingModule',
// modul "comment" yang ditentukan menggunakan konfigurasi array
'comment' => [
'class' => 'app\modules\comment\CommentModule',
'db' => 'db',
],
],
]
```
Silahkan melihat bagian [Modules](structure-modules.md) untuk informasi lebih lanjut.
#### [[yii\base\Application::name|name]] <span id="name"></span>
_Property_ ini menentukan nama aplikasi yang bisa ditampilkan ke pengguna. Berbeda dengan
_property_ [[yii\base\Application::id|id]], yang mengharuskan nilainya unik, nilai dari _property_ ini secara umum bertujuan untuk
keperluan tampilan saja; tidak perlu unik.
Anda tidak perlu menentukan _property_ ini jika memang tidak ada kode anda yang akan menggunakannya.
#### [[yii\base\Application::params|params]] <span id="params"></span>
_Property_ ini menentukan parameter berbentuk _array_ yang bisa diakses secara global oleh aplikasi. Dibanding menuliskan secara manual
angka dan _string_ di kode anda, merupakan hal yang bagus jika anda menentukan hal tersebut sebagai parameter-parameter aplikasi
di satu tempat yang sama, dan menggunakannya pada tempat dimana dia dibutuhkan. Sebagai contoh, anda mungkin menentukan ukuran _thumbnail_
sebagai parameter seperti contoh dibawah ini:
```php
[
'params' => [
'thumbnail.size' => [128, 128],
],
]
```
Kemudian, pada kode dimana anda akan menggunakan ukuran tersebut, anda cukup menggunakannya seperti kode dibawah ini:
```php
$size = \Yii::$app->params['thumbnail.size'];
$width = \Yii::$app->params['thumbnail.size'][0];
```
Jika di suatu hari anda memutuskan untuk mengganti ukuran _thumbnail_ tersebut, anda cukup menggantinya di konfigurasi aplikasi;
anda tidak perlu mengganti di semua kode dimana anda menggunakannya.
#### [[yii\base\Application::sourceLanguage|sourceLanguage]] <span id="sourceLanguage"></span>
_Property_ ini menentukan bahasa apa yang digunakan dalam menulis kode aplikasi. Nilai default-nya adalah `'en-US'`,
yang berarti Bahasa Inggris (Amerika Serikat). Anda sebaiknya menentukan _property_ ini jika teks pada kode anda bukanlah Bahasa Inggris.
Seperti layaknya _property_ [language](#language), anda seharusnya menentukan _property_ ini dalam
format [Tag Bahasa IETF](http://en.wikipedia.org/wiki/IETF_language_tag). Sebagai contoh, `en` berarti Bahasa Inggris,
sedangkan `en-US` berarti Bahasa Inggris (Amerika Serikat).
Untuk informasi lebih lanjut mengenai _property_ ini bisa anda pelajari pada bagian [Internasionalisasi](tutorial-i18n.md).
#### [[yii\base\Application::timeZone|timeZone]] <span id="timeZone"></span>
_Property_ ini disediakan sebagai cara alternatif untuk menentukan zona waktu default dari _PHP runtime_.
Dengan menentukan _property_ ini, pada dasarnya anda memanggil _function_ PHP
[date_default_timezone_set()](http://php.net/manual/en/function.date-default-timezone-set.php). Sebagi contoh:
```php
[
'timeZone' => 'America/Los_Angeles',
]
```
#### [[yii\base\Application::version|version]] <span id="version"></span>
_Property_ ini menentukan versi dari aplikasi anda. Secara default nilainya adalah `'1.0'`. Anda tidak harus menentukan
_property_ ini jika tidak ada kode anda yang akan menggunakannya.
### _Property_ yang Bermanfaat <span id="useful-properties"></span>
_Property_ yang dijelaskan pada sub-bagian ini tidak secara umum digunakan karena nilai default-nya
sudah ditentukan berdasarkan kaidah-kaidah yang umum digunakan. Tetapi anda boleh menentukannya sendiri jikalau anda tidak ingin mengikuti kaidah-kaidah tersebut.
#### [[yii\base\Application::charset|charset]] <span id="charset"></span>
_Property_ ini menentukan _charset_ yang digunakan oleh aplikasi. Nilai default-nya adalah `'UTF-8'`, dimana harus
digunakan sebisa mungkin pada kebanyakan aplikasi, kecuali anda sedang membangun sistem lama yang banyak menggunakan data yang tidak termasuk dalam _Unicode_.
#### [[yii\base\Application::defaultRoute|defaultRoute]] <span id="defaultRoute"></span>
_Property_ ini menentukan [route](runtime-routing.md) yang harus aplikasi gunakan ketika sebuah _request_
tidak memiliki _route_. _Route_ dapat terdiri dari ID _child module_, ID _controller_, dan/atau ID _action_.
Sebagai contoh, `help`, `post/create`, atau `admin/post/create`. Jika ID _action_ tidak diberikan, maka _property_ ini akan mengambil
nilai default yang ditentukan di [[yii\base\Controller::defaultAction]].
Untuk [[yii\web\Application|aplikasi Web]], nilai default dari _property_ ini adalah `'site'`, yang berarti
_controller_ `SiteController` dan default _action_-nya yang akan digunakan. Hasilnya, jika anda mengakses
aplikasi tanpa menentukan _route_ yang spesifik, maka akan menampilkan output dari `app\controllers\SiteController::actionIndex()`.
Untuk [[yii\console\Application|aplikasi konsol]], nilai default-nya adalah `'help'`, yang berarti akan menggunakan
[[yii\console\controllers\HelpController::actionIndex()]] sebagai perintah utamanya. Hasilnya, jika anda menjalankan perintah `yii`
tanpa memasukkan argumen, maka akan menampilkan informasi bantuan penggunaan.
#### [[yii\base\Application::extensions|extensions]] <span id="extensions"></span>
_Property_ ini menentukan daftar dari [extension](structure-extensions.md) yang terpasang dan digunakan oleh aplikasi.
Secara default, akan mengambil _array_ yang dikembalikan oleh file `@vendor/yiisoft/extensions.php`. File `extensions.php`
dibuat dan dikelola secara otomatis jika anda menggunakan [Composer](https://getcomposer.org) untuk memasang _extensions_.
Secara umum, anda tidak perlu menentukan _property_ ini.
Dalam kasus khusus jika anda ingin mengelola _extension_ secara manual, anda boleh menentukan _property_ ini seperti kode dibawah ini:
```php
[
'extensions' => [
[
'name' => 'extension name',
'version' => 'version number',
'bootstrap' => 'BootstrapClassName', // Tidak wajib, bisa juga berupa konfigurasi array
'alias' => [ // Tidak Wajib
'@alias1' => 'to/path1',
'@alias2' => 'to/path2',
],
],
// ... extension lain yang ditentukan seperti kode di atas ...
],
]
```
Seperti yang anda lihat, _property_ ini menerima spesifikasi _extension_ dalam bentuk _array_. Setiap _extension_ ditentukan dengan _array_
yang terdiri dari elemen `name` dan `version`. Jika _extension_ harus dijalankan ketika proses [bootstrap](runtime-bootstrapping.md)
, elemen `bootstrap` dapat dispesifikasikan dengan nama _class bootstrap_-nya atau [konfigurasi array](concept-configurations.md)
. _Extension_ juga dapat menentukan beberapa [alias](concept-aliases.md).
#### [[yii\base\Application::layout|layout]] <span id="layout"></span>
_Property_ ini menentukan nama dari default layout yang akan digunakan ketika me-render sebuah [view](structure-views.md).
Nilai default-nya adalah `'main'`, yang berarti akan menggunakan file layout `main.php` yang disimpan di [layout path](#layoutPath).
Jika kedua dari [layout path](#layoutPath) dan [view path](#viewPath) mengambil nilai default,
maka representasi file layoutnya adalah _path alias_ `@app/views/layouts/main.php`.
Anda dapat menentukan nilai _property_ ini menjadi `false` jika anda ingin menonaktifkan layout secara default, tetapi anda seharusnya tidak memerlukannya.
#### [[yii\base\Application::layoutPath|layoutPath]] <span id="layoutPath"></span>
_Property_ ini menentukan path dimana sistem akan mencari file layout. Nilai default-nya adalah
sub-direktori `layouts` di dalam [view path](#viewPath). Jika [view path](#viewPath) mengambil
nilai defaultnya, maka path layout defaultnya adalah path alias `@app/views/layouts`.
Anda dapat menentukannya sebagai direktori atau path [alias](concept-aliases.md).
#### [[yii\base\Application::runtimePath|runtimePath]] <span id="runtimePath"></span>
_Property_ ini menentukan dimana path file yang bersifat sementara, seperti file _log_ dan _cache_.
Nilai default-nya adalah direktori yang direpresentasikan oleh alias `@app/runtime`.
Anda dapat menentukan nilainya dengan direktori atau path [alias](concept-aliases.md). Sebagai catatan, _path runtime_ wajib
memiliki akses tulis _(writeable)_ oleh _web server_ yang menjalankan aplikasi. Dan path tersebut sebaiknya diproteksi aksesnya dari
pengguna, karena file yang bersifat sementara di dalamnya mungkin mengandung informasi sensitif.
Untuk menyederhanakan akses ke path ini, Yii sudah menentukan path alias dengan nama `@runtime`.
#### [[yii\base\Application::viewPath|viewPath]] <span id="viewPath"></span>
_Property_ ini menentukan direktori _root_ dimana file-file _view_ akan disimpan. Nilai default-nya adalah direktori
yang di representasikan oleh alias `@app/views`. Anda dapat menentukan nilainya dengan direktori atau path [alias](concept-aliases.md).
#### [[yii\base\Application::vendorPath|vendorPath]] <span id="vendorPath"></span>
_Property_ ini menentukan direktori _vendor_ yang di kelola oleh [Composer](https://getcomposer.org). Direktori ini akan
menyimpan semua _library_ pihak ketiga yang digunakan oleh aplikasi anda, termasuk Yii _framework_. Nilai default-nya adalah
direktori yang di representasikan oleh alias `@app/vendor`.
Anda dapat menentukan nilai _property_ ini dengan direktori atau path [alias](concept-aliases.md). Jika anda mengganti
nilai _property_ ini, pastikan anda juga menyesuaikan konfigurasi Composer.
Untuk memudahkan akses ke path ini, Yii sudah menentukan path alias dengan nama `@vendor`.
#### [[yii\console\Application::enableCoreCommands|enableCoreCommands]] <span id="enableCoreCommands"></span>
_Property_ ini hanya dikenali oleh [[yii\console\Application|console applications]]. _Property_ ini menentukan
apakah perintah inti yang dibawa oleh rilisan Yii harus diaktifkan. Nilai default-nya adalah `true`.
## _Event_ Aplikasi <span id="application-events"></span>
Sebuah objek _aplikasi_ menjalankan beberapa _event_ sepanjang siklus penanganan _request_. Anda dapat menempelkan penanganan _event_
untuk _event-event_ ini di dalam konfigurasi aplikasi seperti di bawah ini:
```php
[
'on beforeRequest' => function ($event) {
// ...
},
]
```
Penggunaan dari sintaks `on eventName` akan dijelaskan pada bagian
[Konfigurasi](concept-configurations.md#configuration-format).
Sebagai alternatif, anda dapat menempelkan penanganan _event_ ke dalam [proses bootstrap](runtime-bootstrapping.md)
setelah objek aplikasi telah dibuat. Sebagai contoh:
```php
\Yii::$app->on(\yii\base\Application::EVENT_BEFORE_REQUEST, function ($event) {
// ...
});
```
### [[yii\base\Application::EVENT_BEFORE_REQUEST|EVENT_BEFORE_REQUEST]] <span id="beforeRequest"></span>
_Event_ ini dijalankan *sebelum* objek aplikasi menangani sebuah _request_. Nama _event_-nya adalah `beforeRequest`.
Ketika _event_ ini dijalankan, objek aplikasi sudah dibuat dan di inisialisasi. Jadi waktu ini merupakan waktu yang tepat
untuk memasukkan kode anda melalui mekanisme _event_ untuk mengintervensi penanganan _request_. Sebagai contoh,
di penanganan _event_, anda dapat menentukan _property_ [[yii\base\Application::language]] secara dinamis berdasarkan parameter tertentu.
### [[yii\base\Application::EVENT_AFTER_REQUEST|EVENT_AFTER_REQUEST]] <span id="afterRequest"></span>
_Event_ ini dijalankan *setelah* objek aplikasi menyelesaikan penanganan sebuah _request_ tetapi *sebelum* mengirimkan _response_.
Ketika _event_ ini dijalankan, proses penanganan _request_ sudah selesai dan anda dapat menggunakan kesempatan untuk melakukan beberapa tugas
untuk memodifikasi _request_ atau _response_.
Sebagai catatan, _component_ [[yii\web\Response|response]] juga menjalankan beberapa _event_ pada saat mengirim
isi _response_ ke pengguna. _Event_ tersebut akan dijalankan *setelah* _event_ ini.
### [[yii\base\Application::EVENT_BEFORE_ACTION|EVENT_BEFORE_ACTION]] <span id="beforeAction"></span>
_Event_ ini dijalankan *sebelum* semua [action dari controller](structure-controllers.md) diproses.
Nama _event_-nya adalah `beforeAction`.
Parameter _event_ merupakan objek dari [[yii\base\ActionEvent]]. Sebuah penanganan _event_ boleh menentukan
_property_ [[yii\base\ActionEvent::isValid]] menjadi `false` untuk memberhentikan proses jalannya _action_.
Sebagai contoh:
```php
[
'on beforeAction' => function ($event) {
if (kondisi tertentu) {
$event->isValid = false;
} else {
}
},
]
```
Sebagai catatan, _event_ `beforeAction` yang sama juga dijalankan oleh [module](structure-modules.md)
dan [controller](structure-controllers.md). _Event_ pada objek aplikasi yang menjalankan _event_ ini
untuk pertama kali, dilanjutkan oleh _module_ (jika ada), dan terakhir oleh _controller_. Jika sebuah penanganan _event_
menentukan _property_ [[yii\base\ActionEvent::isValid]] menjadi `false`, semua _event_ selanjutnya TIDAK akan dijalankan.
### [[yii\base\Application::EVENT_AFTER_ACTION|EVENT_AFTER_ACTION]] <span id="afterAction"></span>
_Event_ ini dijalankan *setelah* menjalankan seluruh [action dari controller](structure-controllers.md).
Nama _event_-nya adalah `afterAction`.
Parameter _event_ adalah objek dari [[yii\base\ActionEvent]]. Menggunakan
_property_ [[yii\base\ActionEvent::result]], _method_ penanganan _event_ dapat mengakses atau merubah hasil dari _action_.
Sebagai contoh:
```php
[
'on afterAction' => function ($event) {
if (kondisi tertentu) {
// rubah nilai dari $event->result
} else {
}
},
]
```
Sebagai catatan, _event_ `afterAction` yang sama juga dijalankan oleh [module](structure-modules.md)
dan [controllers](structure-controllers.md). Objek-objek ini menjalankan _event_ ini sama seperti `beforeAction`,
hanya saja urutannya merupakan kebalikan dari urutan di _event_ `beforeAction`. _Controller_ adalah objek pertama yang menjalankan _event_ ini,
setelah itu _module_ (jika ada), dan terakhir di level aplikasi.
## Application Lifecycle <span id="application-lifecycle"></span>
![Siklus Aplikasi](images/application-lifecycle.png)
Ketika [skrip masuk](structure-entry-scripts.md) sedang dijalankan untuk menangani sebuah _request_,
aplikasi akan melewati proses siklus dibawah ini:
1. Skrip masuk mengambil konfigurasi aplikasi dalam bentuk array.
2. Skrip masuk membuat objek aplikasi:
* [[yii\base\Application::preInit()|preInit()]] dipanggil, dimana akan mengatur beberapa _property_ aplikasi
yang sangat penting seperti [[yii\base\Application::basePath|basePath]].
* Mendaftarkan [[yii\base\Application::errorHandler|penanganan error]].
* Mengatur _property_ aplikasi.
* [[yii\base\Application::init()|init()]] dipanggil, yang selanjutnya memanggil
[[yii\base\Application::bootstrap()|bootstrap()]] untuk menjalankan proses _bootstrap component_.
3. Skrip masuk memanggil [[yii\base\Application::run()]] untuk menjalankan aplikasi:
* Menjalankan _event_ [[yii\base\Application::EVENT_BEFORE_REQUEST|EVENT_BEFORE_REQUEST]].
* Menangani _request_: memproses _request_ menjadi [route](runtime-routing.md) dan parameter-parameternya;
membuat objek _module_, _controller_, dan _action_ yang dispesifikasikan oleh _route_; dan menjalankan _action_.
* Menjalankan _event_ [[yii\base\Application::EVENT_AFTER_REQUEST|EVENT_AFTER_REQUEST]].
* Mengirim _response_ ke pengguna.
4. Skrip masuk mendapatkan _status exit_ dari aplikasi dan menyelesaikan proses penanganan _request_.

113
docs/guide-id/structure-entry-scripts.md

@ -0,0 +1,113 @@
Skrip Masuk
===========
Skrip masuk adalah langkah pertama pada proses _bootstrap_ aplikasi. Dalam sebuah aplikasi (apakah
itu aplikasi web atau aplikasi konsol) memiliki satu skrip masuk. Pengguna mengirim _request_ ke
skrip masuk dimana skrip tersebut membangun objek aplikasi dan meneruskan _request_ ke objek tersebut.
Skrip masuk untuk aplikasi web harus disimpan pada direktori yang dapat diakses dari web sehingga
dapat di akses oleh pengguna. Secara umum, skrip tersebut diberi nama `index.php`, tetapi boleh menggunakan nama lain,
selama _web server_ bisa mengakses skrip tersebut.
Skrip masuk untuk aplikasi konsol pada umumnya disimpan di dalam [base path](structure-applications.md)
dari objek aplikasi dan diberi nama `yii` (dengan suffix `.php`). Skrip tersebut harus memiliki akses _execute_
sehingga pengguna dapat menjalan aplikasi konsol menggunakan perintah `./yii <route> [argument] [option]`.
Skrip masuk umumnya mengerjakan tugas berikut ini:
* Menentukan _global constant_;
* Mendaftarkan [autoloader Composer](https://getcomposer.org/doc/01-basic-usage.md#autoloading);
* Memasukkan file _class_ [[Yii]];
* Mengambil konfigurasi aplikasi, dan memuatnya;
* Membuat dan mengatur objek [application](structure-applications.md);
* Memanggil [[yii\base\Application::run()]] untuk memproses _request_ yang diterima;
## Aplikasi Web<span id="web-applications"></span>
Kode berikut ini adalah kode yang terdapat pada skrip masuk [Template Proyek Dasar](start-installation.md).
```php
<?php
defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');
// mendaftarkan autoloader Composer
require(__DIR__ . '/../vendor/autoload.php');
// memasukkan file class Yii
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
// Mengambil konfigurasi aplikasi
$config = require(__DIR__ . '/../config/web.php');
// Membuat, mengkonfigurasi, dan menjalankan aplikasi
(new yii\web\Application($config))->run();
```
## Aplikasi Konsol <span id="console-applications"></span>
Demikian juga dengan aplikasi konsol, kode berikut ini adalah kode yang terdapat pada skrip masuk aplikasi konsol :
```php
#!/usr/bin/env php
<?php
/**
* Yii console bootstrap file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');
// mendaftarkan autoloader composer
require(__DIR__ . '/vendor/autoload.php');
// memasukkan file class Yii
require(__DIR__ . '/vendor/yiisoft/yii2/Yii.php');
// Mengambil konfigurasi aplikasi
$config = require(__DIR__ . '/config/console.php');
$application = new yii\console\Application($config);
$exitCode = $application->run();
exit($exitCode);
```
## Menentukan _Constant_ <span id="defining-constants"></span>
Skrip masuk adalah file yang tepat untuk menentukan _global constant_. Yii mengenali tiga _constant_ berikut ini:
* `YII_DEBUG`: untuk menentukan apakah aplikasi sedang dalam mode _debug_. Pada saat mode _debug_, aplikasi
akan menyimpan informasi log lebih banyak, dan akan menampilkan detail error urutan pemanggilan _(error call stack)_ jika ada _exception_ yang di-_throw_. Alasan inilah,
kenapa mode _debug_ sebaiknya digunakan pada tahap pengembangan. Nilai _default_ dari `YII_DEBUG` adalah `false`.
* `YII_ENV`: untuk menentukan pada mode _environment_ manakah aplikasi ini dijalankan. _Constant_ ini akan dijelaskan lebih lanjut di
bagian [Konfigurasi](concept-configurations.md#environment-constants).
Nilai _default_ dari `YII_ENV` adalah `prod`, yang berarti aplikasi sedang dijalankan pada _production environment_.
* `YII_ENABLE_ERROR_HANDLER`: untuk menentukan apakah akan mengaktifkan penanganan eror yang disediakan oleh Yii. Nilai _default_
dari _constant_ ini adalah `true`.
Untuk menentukan _constant_, kita biasanya menggunakan kode berikut ini:
```php
defined('YII_DEBUG') or define('YII_DEBUG', true);
```
kode di atas memiliki tujuan yang sama dengan kode berikut ini:
```php
if (!defined('YII_DEBUG')) {
define('YII_DEBUG', true);
}
```
Jelas, kode yang pertama lah yang lebih ringkas dan lebih mudah untuk dimengerti.
Penentuan _constant_ sebaiknya ditulis di baris-baris awal pada skrip masuk sehingga akan berfungsi
ketika file PHP lain akan dimasukkan _(include)_.

26
docs/guide-id/structure-overview.md

@ -0,0 +1,26 @@
Tinjauan
========
Aplikasi Yii diorganisir berdasarkan pola arsitektur [model-view-controller (MVC)](http://wikipedia.org/wiki/Model-view-controller).
[Model](structure-models.md) merepresentasikan data, pengaturan dan proses bisnis; [view](structure-views.md)
adalah output yang merepresentasikan model; dan [controller](structure-controllers.md) mengelola input dan merubahnya
menjadi perintah-perintah untuk [model](structure-models.md) dan [view](structure-views.md).
Selain MVC, aplikasi Yii juga memiliki entitas berikut:
* [entry scripts](structure-entry-scripts.md): Ini adalah skrip PHP yang diakses secara langsung oleh pengguna.
Ini bertugas untuk memulai siklus penanganan _request_.
* [applications](structure-applications.md): Ini adalah objek yang dapat diakses secara global, yang mengelola _component_ aplikasi
dan mengaturnya untuk memenuhi sebuah _request_.
* [application components](structure-application-components.md): Ini adalah objek-objek yang didaftarkan pada objek _application_ dan
menyediakan beragam layanan untuk memenuhi _request_.
* [modules](structure-modules.md): Ini adalah paket _(package)_ mandiri yang berisikan MVC lengkap.
Sebuah aplikasi boleh diistilahkan sebagai module-module yang telah diorganisir.
* [filters](structure-filters.md): Ini merepresentaikan kode yang mutlak untuk dijalakan sebelum dan sesudah
penanganan dari tiap-tiap _request_ yang dikelola oleh _controller_.
* [widgets](structure-widgets.md): Ini adalah objek-objek yang dapat ditanam kedalam [views](structure-views.md). Ini
dapat mengandung logika _controller_ dan dapat digunakan berulang-ulang pada _view_ yang berbeda.
Diagram dibawah ini menunjukkan struktur statis dari sebuah aplikasi:
![Struktur Statis Aplikasi](images/application-structure.png)

6
docs/guide-id/translators.json

@ -0,0 +1,6 @@
[
"Misbahul D. Munir",
"Muhammad Cahya",
"Seto Kuslaksono",
"Novrian Y.F."
]

2
docs/guide-ru/README.md

@ -102,7 +102,7 @@ All Rights Reserved.
* [Сортировка](output-sorting.md)
* [Провайдеры данных](output-data-providers.md)
* [Виджеты для данных](output-data-widgets.md)
* [Работа с клиентскими скриптами](output-client-scripts.md)
* Работа с клиентскими скриптами
* [Темизация](output-theming.md)

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

@ -54,7 +54,7 @@ basic/ корневой каталог приложения
yii скрипт выполнения консольного приложения Yii
```
В целом, приложение Yii можно разделить на две категории файлов: расположенные в `basic/web` и расположенные в других директориях. Первая категория доступна через Web (например, браузером), вторая не доступна из вне и не должна быть доступной т.к. содержит служебную информацию.
В целом, приложение Yii можно разделить на две категории файлов: расположенные в `basic/web` и расположенные в других директориях. Первая категория доступна через Web (например, браузером), вторая не доступна извне и не должна быть доступной т.к. содержит служебную информацию.
В Yii реализован [архитектурный паттерн MVC](http://ru.wikipedia.org/wiki/Model-View-Controller),
которая соответствует структуре директорий приложения. В директории `models` находятся [Модели](structure-models.md),

22
docs/guide-ru/test-environment-setup.md

@ -47,3 +47,25 @@ Changed current directory to <directory>
путём запуска команды `codecept` без указания пути. Тем не менее, данный подход может не подойти. К примеру, в двух
разных проектах может потребоваться установить разные версии Codeception. Для простоты все команды в разделах про
тестирование используются так, будто Codeception установлен глобально.
### Настройка веб-сервера Apache
Если вы используете Apache и настроили его как описано в разделе «[Установка Yii](start-installation.md)», то для тестов вам необходимо создать отдельный виртуальный хост который будет работать с той же папкой, но использовать входной скрипт `index-test.php`:
```
<VirtualHost *:80>
DocumentRoot "path/to/basic/webb"
ServerName mysite-test
<Directory "path/to/basic/web">
Order Allow,Deny
Allow from all
AddDefaultCharset utf-8
DirectoryIndex index-test.php
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index-test.php
</Directory>
</VirtualHost>
```
Так мы укажем веб серверу перенаправлять все запросы на скрипт `index-test.php`.
> Note: Обратите внимание, что здесь мы указываем параметр `DirectoryIndex`, помимо тех параметров, которые были указаны для первого хоста. Это сделано с той целью, чтобы при обращении к главной странице по адресу `mysite-test` также использовался бы скрипт `index-test.php`.

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

@ -160,6 +160,18 @@ return [
如你所见,这些验证规则并不真的对输入数据进行任何验证。而是,对输入数据进行一些处理,然后把它们存回当前被验证的模型特性。
下面的代码示例展示了对用户输入的完整处理,这将确保只将整数值存储在一个属性中:
```php
['age', 'trim'],
['age', 'default', 'value' => null],
['age', 'integer', 'integerOnly' => true, 'min' => 0],
['age', 'filter', 'filter' => 'intval', 'skipOnEmpty' => true],
```
以上代码将对输入执行以下操作:
1. 从输入值中去除前后空白。
2. 确保空输入在数据库中存储为`null`;我们区分 `未设置` 值和实际值为 `0` 之间的区别。如果值不允许为`null`,则可以在此处设置另一个默认值。
3. 如果该值不为空,则验证该值是否为大于0的整数。大多数验证器的 [[yii\validators\Validator::$skipOnEmpty|$skipOnEmpty]] 属性都被设置为`true`。
4. 确保该值为整数类型,例如将字符串 `'42'` 转换为整数 `42`。在这里,我们将 [[yii\validators\FilterValidator::$skipOnEmpty|$skipOnEmpty]] 设置为 `true`,默认情况下,在 [[yii\validators\FilterValidator|filter]] 验证器里这个属性是 `false`
### 处理空输入 <span id="handling-empty-inputs"></span>

2
docs/guide-zh-CN/output-formatting.md

@ -143,7 +143,7 @@ For formatting numeric values the formatter class provides the following methods
属性来调整数字格式化的格式,默认和当前区域相同。
更多高级配置, [[yii\i18n\Formatter::numberFormatterOptions]] 和 [[yii\i18n\Formatter::numberFormatterTextOptions]]
可用于配置内部使用 [Numberformatter class](http://php.net/manual/en/class.numberformatter.php)
可用于配置内部使用 [NumberFormatter class](http://php.net/manual/en/class.numberformatter.php)
为调整数字的小数部分的最大值和最小值,可配置如下属性:

2
docs/guide/concept-autoloading.md

@ -37,6 +37,8 @@ the front-end tier has a root alias `@frontend`, while the back-end tier root al
you may put the front-end classes under the namespace `frontend` while the back-end classes are under `backend`. This will
allow these classes to be autoloaded by the Yii autoloader.
To add a custom namespace to the autoloader you need to define an alias for the base directory of the namespace using [[Yii::setAlias()]].
For example to load classes in the `foo` namespace that are located in the `path/to/foo` directory you will call `Yii::setAlias('@foo', 'path/to/foo')`.
Class Map <span id="class-map"></span>
---------

7
docs/guide/db-dao.md

@ -209,6 +209,11 @@ Notice that you bind the placeholder to the `$id` variable before the execution,
before each subsequent execution (this is often done with loops). Executing queries in this manner can be vastly
more efficient than running a new query for every different parameter value.
> Info: Parameter binding is only used in places where values need to be inserted into strings that contain plain SQL.
> In many places in higher abstraction layers like [query builder](db-query-builder.md) and [active record](db-active-record.md)
> you often specify an array of values which will be transformed into SQL. In these places parameter binding is done by Yii
> internally, so there is no need to specify params manually.
### Executing Non-SELECT Queries <span id="non-select-queries"></span>
@ -381,7 +386,7 @@ Yii provides four constants for the most common isolation levels:
- [[\yii\db\Transaction::SERIALIZABLE]] - the strongest level, avoids all of the above named problems.
Besides using the above constants to specify isolation levels, you may also use strings with a valid syntax supported
by the DBMS that you are using. For example, in PostgreSQL, you may use `SERIALIZABLE READ ONLY DEFERRABLE`.
by the DBMS that you are using. For example, in PostgreSQL, you may use `"SERIALIZABLE READ ONLY DEFERRABLE"`.
Note that some DBMS allow setting the isolation level only for the whole connection. Any subsequent transactions
will get the same isolation level even if you do not specify any. When using this feature

12
docs/guide/db-migrations.md

@ -835,9 +835,10 @@ The migration command comes with a few command-line options that can be used to
When this is `true`, the user will be prompted before the command performs certain actions.
You may want to set this to `false` if the command is being used in a background process.
* `migrationPath`: string (defaults to `@app/migrations`), specifies the directory storing all migration
* `migrationPath`: string|array (defaults to `@app/migrations`), specifies the directory storing all migration
class files. This can be specified as either a directory path or a path [alias](concept-aliases.md).
Note that the directory must exist, or the command may trigger an error.
Note that the directory must exist, or the command may trigger an error. Since version 2.0.12 an array can be
specified for loading migrations from multiple sources.
* `migrationTable`: string (defaults to `migration`), specifies the name of the database table for storing
migration history information. The table will be automatically created by the command if it does not exist.
@ -933,6 +934,11 @@ yii migrate/create 'app\\migrations\\createUserTable'
contain a namespace, namespaced migration can be applied only via [[yii\console\controllers\MigrateController::migrationNamespaces]]
property.
Since version 2.0.12 the [[yii\console\controllers\MigrateController::migrationPath|migrationPath]] property
also accepts an array for specifying multiple directories that contain migrations without a namespace.
This is mainly added to be used in existing projects which use migrations from different locations. These migrations mainly come
from external sources, like Yii extensions developed by other developers,
which can not be changed to use namespaces easily when starting to use the new approach.
### Separated Migrations <span id="separated-migrations"></span>
@ -951,12 +957,14 @@ return [
'class' => 'yii\console\controllers\MigrateController',
'migrationNamespaces' => ['app\migrations'],
'migrationTable' => 'migration_app',
'migrationPath' => null,
],
// Migrations for the specific project's module
'migrate-module' => [
'class' => 'yii\console\controllers\MigrateController',
'migrationNamespaces' => ['module\migrations'],
'migrationTable' => 'migration_module',
'migrationPath' => null,
],
// Migrations for the specific extension
'migrate-rbac' => [

79
docs/guide/db-query-builder.md

@ -652,10 +652,9 @@ value which will be used as the index value for the current row.
### Batch Query <span id="batch-query"></span>
When working with large amounts of data, methods such as [[yii\db\Query::all()]] are not suitable
because they require loading all data into the memory. To keep the memory requirement low, Yii
provides the so-called batch query support. A batch query makes use of the data cursor and fetches
data in batches.
When working with large amounts of data, methods such as [[yii\db\Query::all()]] are not suitable because they require loading the whole query result into the client's memory. To solve this issue Yii provides batch query support. The server holds the query result, and the client uses a cursor to iterate over the result set one batch at a time.
> Warning: There are known limitations and workarounds for the MySQL implementation of batch queries. See below.
Batch query can be used like the following:
@ -670,23 +669,23 @@ foreach ($query->batch() as $users) {
// $users is an array of 100 or fewer rows from the user table
}
// or if you want to iterate the row one by one
// or to iterate the row one by one
foreach ($query->each() as $user) {
// $user represents one row of data from the user table
// data is being fetched from the server in batches of 100,
// but $user represents one row of data from the user table
}
```
The method [[yii\db\Query::batch()]] and [[yii\db\Query::each()]] return an [[yii\db\BatchQueryResult]] object
which implements the `Iterator` interface and thus can be used in the `foreach` construct.
During the first iteration, a SQL query is made to the database. Data are then fetched in batches
The method [[yii\db\Query::batch()]] and [[yii\db\Query::each()]] return an [[yii\db\BatchQueryResult]] object which implements the `Iterator` interface and thus can be used in the `foreach` construct.
During the first iteration, a SQL query is made to the database. Data is then fetched in batches
in the remaining iterations. By default, the batch size is 100, meaning 100 rows of data are being fetched in each batch.
You can change the batch size by passing the first parameter to the `batch()` or `each()` method.
Compared to the [[yii\db\Query::all()]], the batch query only loads 100 rows of data at a time into the memory.
If you process the data and then discard it right away, the batch query can help reduce memory usage.
If you specify the query result to be indexed by some column via [[yii\db\Query::indexBy()]], the batch query
will still keep the proper index. For example,
If you specify the query result to be indexed by some column via [[yii\db\Query::indexBy()]], the batch query will still keep the proper index.
For example:
```php
$query = (new \yii\db\Query())
@ -701,3 +700,59 @@ foreach ($query->each() as $username => $user) {
// ...
}
```
#### Limitations of batch query in MySQL <span id="batch-query-mysql"></span>
MySQL implementation of batch queries relies on the PDO driver library. By default, MySQL queries are [`buffered`](http://php.net/manual/en/mysqlinfo.concepts.buffering.php). This defeats the purpose of using the cursor to get the data, because it doesn't prevent the whole result set from being loaded into the client's memory by the driver.
> Note: When `libmysqlclient` is used (typical of PHP5), PHP's memory limit won't count the memory used for result sets. It may seem that batch queries work correctly, but in reality the whole dataset is loaded into client's memory, and has the potential of using it up.
To disable buffering and reduce client memory requirements, PDO connection property `PDO::MYSQL_ATTR_USE_BUFFERED_QUERY` must be set to `false`. However, until the whole dataset has been retrieved, no other query can be made through the same connection. This may prevent `ActiveRecord` from making a query to get the table schema when it needs to. If this is not a problem (the table schema is cached already), it is possible to switch the original connection into unbuffered mode, and then roll back when the batch query is done.
```php
Yii::$app->db->pdo->setAttribute(\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
// Do batch query
Yii::$app->db->pdo->setAttribute(\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
```
> Note: In the case of MyISAM, for the duration of the batch query, the table may become locked, delaying or denying write access for other connections. When using unbuffered queries, try to keep the cursor open for as little time as possible.
If the schema is not cached, or it is necessary to run other queries while the batch query is being processed, you can create a separate unbuffered connection to the database:
```php
$unbufferedDb = new \yii\db\Connection([
'dsn' => Yii::$app->db->dsn,
'username' => Yii::$app->db->username,
'password' => Yii::$app->db->password,
'charset' => Yii::$app->db->charset,
]);
$unbufferedDb->open();
$unbufferedDb->pdo->setAttribute(\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
```
If you want to ensure that the `$unbufferedDb` has exactly the same PDO attributes like the original buffered `$db` but the `PDO::MYSQL_ATTR_USE_BUFFERED_QUERY` is `false`, [consider a deep copy of `$db`](https://github.com/yiisoft/yii2/issues/8420#issuecomment-301423833), set it to false manually.
Then, queries are created normally. The new connection is used to run batch queries and retrieve results either in batches or one by one:
```php
// getting data in batches of 1000
foreach ($query->batch(1000, $unbufferedDb) as $users) {
// ...
}
// data is fetched from server in batches of 1000, but is iterated one by one
foreach ($query->each(1000, $unbufferedDb) as $user) {
// ...
}
```
When the connection is no longer necessary and the result set has been retrieved, it can be closed:
```php
$unbufferedDb->close();
```
> Note: unbuffered query uses less memory on the PHP-side, but can increase the load on the MySQL server. It is recommended to design your own code with your production practice for extra massive data, [for example, divide the range for integer keys, loop them with Unbuffered Queries](https://github.com/yiisoft/yii2/issues/8420#issuecomment-296109257).

20
docs/guide/input-validation.md

@ -215,6 +215,26 @@ data filtering.
As you can see, these validation rules do not really validate the inputs. Instead, they will process the values
and save them back to the attributes being validated.
A complete processing of user input is shown in the following example code, which will ensure only integer
values are stored in an attribute:
```php
['age', 'trim'],
['age', 'default', 'value' => null],
['age', 'integer', 'integerOnly' => true, 'min' => 0],
['age', 'filter', 'filter' => 'intval', 'skipOnEmpty' => true],
```
The above code will perform the following operations on the input:
1. Trim whitespace from the input value.
2. Make sure empty input is stored as `null` in the database; we differentiate between a value being "not set"
and the actual value `0`. If `null` is not allowed you can set another default value here.
3. Validate that the value is an integer greater than 0 if it is not empty. Normal validators have
[[yii\validators\Validator::$skipOnEmpty|$skipOnEmpty]] set to `true`.
4. Make sure the value is of type integer, e.g. casting a string `'42'` to integer `42`.
Here we set [[yii\validators\FilterValidator::$skipOnEmpty|$skipOnEmpty]] to `true`, which is `false` by default
on the [[yii\validators\FilterValidator|filter]] validator.
### Handling Empty Inputs <span id="handling-empty-inputs"></span>

2
docs/guide/output-client-scripts.md

@ -56,7 +56,7 @@ An external script can be added like the following:
```php
$this->registerJsFile(
'@web/js/main.js',
['depends' => [\yii\web\JqueryAsset::className()]]
['depends' => [\yii\web\JqueryAsset::class]]
);
```

14
docs/guide/output-formatting.md

@ -97,6 +97,20 @@ echo Yii::$app->formatter->asDate('now', 'yyyy-MM-dd'); // 2014-10-06
echo Yii::$app->formatter->asDate('now', 'php:Y-m-d'); // 2014-10-06
```
> Info: Some letters of the PHP format syntax are not supported by ICU and thus the PHP intl extension and can not be used
> in Yii formatter. Most of these (`w`, `t`, `L`, `B`, `u`, `I`, `Z`) are not really useful for formatting dates but rather
> used when doing date math. `S` and `U` however may be useful. Their behavior can be achived by doing the following:
>
> - for `S`, which is the English ordinal suffix for the day of the month (e.g. st, nd, rd or th.), the following replacement can be used:
>
> ```php
> $f = Yii::$app->formatter;
> $d = $f->asOrdinal($f->asDate('2017-05-15', 'php:j'));
> echo "On the $d day of the month."; // prints "On the 15th day of the month."
> ```
>
> - for `U`, the Unix Epoch, you can use the [[yii\i18n\Formatter::asTimestamp()|timestamp]] format.
When working with applications that need to support multiple languages, you often need to specify different date
and time formats for different locales. To simplify this task, you may use format shortcuts (e.g. `long`, `short`), instead.
The formatter will turn a format shortcut into an appropriate format according to the currently active [[yii\i18n\Formatter::locale|locale]].

3
docs/guide/runtime-routing.md

@ -435,6 +435,9 @@ The above rule can be used to parse or create any of the following URLs:
Without using optional parameters, you would have to create 4 rules to achieve the same result.
> Note: If [[yii\web\UrlRule::$pattern|pattern]] contains only optional parameters and slashes, first parameter could be omitted
only if all other parameters are omitted.
### Rules with Server Names <span id="rules-with-server-names"></span>

25
docs/guide/runtime-sessions-cookies.md

@ -178,6 +178,31 @@ where 'BLOB' refers to the BLOB-type of your preferred DBMS. Below are the BLOB
the length of the `id` column. For example, if `session.hash_function=sha256`, you should use a
length 64 instead of 40.
Alternatively, this can be accomplished with the following migration:
```php
<?php
use yii\db\Migration;
class m170529_050554_create_table_session extends Migration
{
public function up()
{
$this->createTable('{{%session}}', [
'id' => $this->char(64)->notNull(),
'expire' => $this->integer(),
'data' => $this->binary()
]);
$this->addPrimaryKey('pk-id', '{{%session}}', 'id');
}
public function down()
{
$this->dropTable('{{%session}}');
}
}
```
### Flash Data <span id="flash-data"></span>

33
docs/guide/security-authorization.md

@ -100,6 +100,9 @@ The comparison is case-sensitive. If this option is empty or not set, it means t
Using other role names will trigger the invocation of [[yii\web\User::can()]], which requires enabling RBAC
(to be described in the next subsection). If this option is empty or not set, it means this rule applies to all roles.
* [[yii\filters\AccessRule::roleParams|roleParams]]: specifies the parameters that will be passed to [[yii\web\User::can()]].
See the section below describing RBAC rules to see how it can be used. If this option is empty or not set, then no parameters will be passed.
* [[yii\filters\AccessRule::ips|ips]]: specifies which [[yii\web\Request::userIP|client IP addresses]] this rule matches.
An IP address can contain the wildcard `*` at the end so that it matches IP addresses with the same prefix.
For example, '192.168.*' matches all IP addresses in the segment '192.168.'. If this option is empty or not set,
@ -356,6 +359,7 @@ created previously author cannot edit his own post. Let's fix it. First we need
namespace app\rbac;
use yii\rbac\Rule;
use app\models\Post;
/**
* Checks if authorID matches user passed via params
@ -487,6 +491,35 @@ public function behaviors()
If all the CRUD operations are managed together then it's a good idea to use a single permission, like `managePost`, and
check it in [[yii\web\Controller::beforeAction()]].
In the above example, no parameters are passed with the roles specified for accessing an action, but in case of the
`updatePost` permission, we need to pass a `post` parameter for it to work properly.
You can pass parameters to [[yii\web\User::can()]] by specifying [[yii\filters\AccessRule::roleParams|roleParams]] on
the access rule:
```php
[
'allow' => true,
'actions' => ['update'],
'roles' => ['updatePost'],
'roleParams' => function() {
return ['post' => Post::findOne(Yii::$app->request->get('id'))];
},
],
```
In the above example, [[yii\filters\AccessRule::roleParams|roleParams]] is a Closure that will be evaluated when
the access rule is checked, so the model will only be loaded when needed.
If the creation of role parameters is a simple operation, you may just specify an array, like so:
```php
[
'allow' => true,
'actions' => ['update'],
'roles' => ['updatePost'],
'roleParams' => ['postId' => Yii::$app->request->get('id')];
],
```
### Using Default Roles <span id="using-default-roles"></span>
A default role is a role that is *implicitly* assigned to *all* users. The call to [[yii\rbac\ManagerInterface::assign()]]

8
framework/BaseYii.php

@ -62,7 +62,7 @@ class BaseYii
/**
* @var array class map used by the Yii autoloading mechanism.
* The array keys are the class names (without leading backslashes), and the array values
* are the corresponding class file paths (or path aliases). This property mainly affects
* are the corresponding class file paths (or [path aliases](guide:concept-aliases)). This property mainly affects
* how [[autoload()]] works.
* @see autoload()
*/
@ -93,7 +93,7 @@ class BaseYii
*/
public static function getVersion()
{
return '2.0.12-dev';
return '2.0.13-dev';
}
/**
@ -119,6 +119,8 @@ class BaseYii
*
* Note, this method does not check if the returned path exists or not.
*
* See the [guide article on aliases](guide:concept-aliases) for more information.
*
* @param string $alias the alias to be translated.
* @param bool $throwException whether to throw an exception if the given alias is invalid.
* If this is false and an invalid alias is given, false will be returned by this method.
@ -196,6 +198,8 @@ class BaseYii
*
* Any trailing '/' and '\' characters in the given path will be trimmed.
*
* See the [guide article on aliases](guide:concept-aliases) for more information.
*
* @param string $alias the alias name (e.g. "@yii"). It must start with a '@' character.
* It may contain the forward slash '/' which serves as boundary character when performing
* alias translation by [[getAlias()]].

143
framework/CHANGELOG.md

@ -21,80 +21,126 @@ Yii Framework 2 Change Log
- Chg: Moved masked input field widget into separate extension https://github.com/yiisoft/yii2-maskedinput (samdark)
- Chg #12089: Behavior of `yii\grid\DataColumn::$filterInputOptions` changed when default value is overwritten (bvanleeuwen, cebe)
2.0.13 under development
------------------------
2.0.11 under development
2.0.12 under development
--------------------------
- Bug #14248: `yii\console\controllers\MessageController` no longer outputs colorized filenames when console does not support text colorization (PowerGamer1)
- Bug #14264: Fixed a bug where `yii\log\Logger::calculateTimings()` was not accepting messages with array tokens (bizley)
- Chg #14201: `yii\console\controllers\MessageController::extractMessagesFromTokens()` is now protected (faenir)
- Enh #13787: Added `yii\db\Migration::$maxSqlOutputLength` that allows limiting number of characters for outputting SQL (thiagotalma)
- Bug #13694: `yii\widgets\Pjax` now sends `X-Pjax-Url` header with response to fix redirect (wleona3, Faryshta)
- Bug #14012: `yii\db\pgsql\Schema::findViewNames()` was skipping materialized views (insolita)
- Bug #13362: Fixed return value of `yii\caching\MemCache::setValues()` (masterklavi)
- Enh #13963: Added tests for yii\behaviors\TimestampBehavior (vladis84)
- Enh #13820: Add new HTTP status code 451 (yyxx9988)
- Bug #13671: Fixed error handler trace to work correctly with XDebug (samdark)
- Bug #13657: Fixed `yii\helpers\StringHelper::truncateHtml()` skip extra tags at the end (sam002)
2.0.12 June 05, 2017
--------------------
- Bug #4408: Add support for unicode word characters and `+` character in attribute names (sammousa, kmindi)
- Bug #5442: Fixed problem on load fixture dependencies with database related tests (leandrogehlen)
- Bug #7946: Fixed a bug when the `form` attribute was not propagated to the hidden input of the checkbox (Kolyunya)
- Bug #13087: Fixed getting active validators for safe attribute (developeruz)
- Bug #13571: Fix `yii\db\mssql\QueryBuilder::checkIntegrity` for all tables (boboldehampsink)
- Bug #8120: Fixes LIKE special characters escaping for Cubrid/MSSQL/Oracle/SQLite in `yii\db\QueryBuilder` (sergeymakinen)
- Bug #9669: AssetManager and `FileHelper::copyDirectory()` were copying empty directories when using `only` or `except` options. Added an option to disable this (cebe)
- Bug #10305: Oracle SQL queries with `IN` condition and more than 1000 parameters are working now (silverfire)
- Bug #10346: Fixed "DOMException: Invalid Character Error" in `yii\web\XmlResponseFormatter::buildXml()` (sasha-ch)
- Bug #10372: Fixed console controller including complex typed arguments in help (sammousa)
- Bug #11230: Include `defaultRoles` in `yii\rbac\DbManager->getRolesByUser()` results (developeruz)
- Enh #13243: Added support for unicode attribute names in `yii\widgets\DetailView` (arogachev)
- Bug #11404: `yii\base\Model::loadMultiple()` returns true even if `yii\base\Model::load()` returns false (zvook)
- Bug #11719: Fixed `yii\db\Connection::$enableQueryCache` caused infinite loop when the same connection was used for `yii\caching\DbCache` (michaelarnauts)
- Bug #12715: Exception `SAVEPOINT LEVEL1 does not exist` instead of deadlock exception (Vovan-VE)
- Bug #13058: Fixed caught exception thrown during view file rendering produces wrong output (klimov-paul)
- Bug #13086, #13656: Fixed bug with optional parameters at the beginning of pattern in `yii\web\UrlRule` (rob006)
- Bug #13087: Fixed getting active validators for safe attribute (developeruz, klimov-paul)
- Bug #13306: Wildcard in `reloadableScripts` in `yii.js` allows 0 characters (arogachev)
- Bug #13340: Fixed `yii\db\Connection::useMaster()` - Exception within callback completely disables slaves (Vovan-VE)
- Bug #13340: Fixed `yii\db\Connection::useMaster()` - exception within callback completely disables slaves (Vovan-VE)
- Bug #13343: Fixed `yii\i18n\Formatter::asTime()` to process time-only values without time zone conversion (bizley)
- Bug #13418: Fixed `QueryBuilder::batchInsert()` if $rows is `\Generator` (lav45)
- Bug #13350: Fixed bug with incorrect caching of `yii\web\UrlRule::createUrl()` results in `yii\web\UrlManager` (rob006)
- Bug #13362: Fixed return value of `yii\caching\MemCache::setValues()` (masterklavi)
- Bug #13379: Fixed `applyFilter()` function in `yii.gridView.js` to work correctly when params in `filterUrl` are indexed (SilverFire, arogachev)
- Bug #13418: Fixed `QueryBuilder::batchInsert()` if `$rows` is `\Generator` (lav45)
- Bug #13494: Fixed `yii\console\controllers\MessageConstroller::saveMessagesToDb()` to work on different DBMS correctly (silverfire)
- Bug #13513: Fixed RBAC migration to work correctly on Oracle DBMS (silverfire)
- Bug #13537: Fixed `yii\web\CacheSession::destroySession()` to work correctly when session is not written yet (silverfire, papalapa)
- Bug #13538: Fixed `yii\db\BaseActiveRecord::deleteAll()` changes method signature declared by `yii\db\ActiveRecordInterface::deleteAll()` (klimov-paul)
- Bug #13551: Fixed `FixtureController` to load fixtures from subdirectories (d1rtyf1ng3rs, silverfire)
- Bug #13571: Fix `yii\db\mssql\QueryBuilder::checkIntegrity` for all tables (boboldehampsink)
- Bug #13577: `yii\db\QueryBuilder::truncateTable` should work consistent over all databases (boboldehampsink)
- Bug #13582: PK column in `yii\db\pgsql\QueryBuilder::resetSequence()` was not quoted properly (boboldehampsink)
- Bug #13592: Fixes Oracle’s `yii\db\oci\Schema::setTransactionIsolationLevel()` (sergeymakinen)
- Bug #13592: Fixes `yii\db\oci\Schema::setTransactionIsolationLevel()` in Oracle (sergeymakinen)
- Bug #13594: Fixes insufficient quoting in `yii\db\QueryBuilder::prepareInsertSelectSubQuery()` (sergeymakinen)
- Bug #8120: Fixes LIKE special characters escaping for Cubrid/MSSQL/Oracle/SQLite in `yii\db\QueryBuilder` (sergeymakinen)
- Bug #12715: Exception `SAVEPOINT LEVEL1 does not exist` instead of deadlock exception (Vovan-VE)
- Bug #13649: Fixes issue where `['uncheck' => false]` and `['label' => false]` options for `ActiveRadio` and `ActiveCheckbox` were ignored (Alex-Code)
- Bug #13657: Fixed `yii\helpers\StringHelper::truncateHtml()` skip extra tags at the end (sam002)
- Bug #13670: Fixed alias option from console when it includes `-` or `_` in option name (pana1990)
- Bug #13671: Fixed error handler trace to work correctly with XDebug (samdark)
- Bug #13689: Fixed handling of errors in closures (mikehaertl)
- Bug #13694: `yii\widgets\Pjax` now sends `X-Pjax-Url` header with response to fix redirect (wleona3, Faryshta)
- Bug #13704: Fixed `yii\validators\UniqueValidator` to prefix attribute name with model's database table name (vladis84)
- Bug #13707: Fixed `yii\web\ErrorHandler` and `yii\web\ErrorAction` not setting correct response code to response object before rendering error view (samdark)
- Bug #13728: Fixed the bug when `yii\behaviors\SluggableBehavior` wasn't preserving immutable slug values (Kolyunya)
- Bug #13738: Fixed `getQueryParams()` method in `yii.js` to correctly parse URL with question mark and no query parameters (vladdnepr)
- Bug #13776: Fixed setting precision and scale for decimal columns in MSSQL (arturf)
- Bug #13790: Fixed error in `\yii\widgets\MaskedInput` JavaScript by raising version required (samdark)
- Bug #13807: Fixed `yii\db\QueryBuilder` to inherit subquery params when building a `INSERT INTO ... SELECT` query (sergeymakinen)
- Bug #13842: Fixed ambiguous table SQL error while using `yii\validators\ExistValidator` and `yii\validators\UniqueValidator` (vladis84, samdark)
- Bug #13846: Fixed `Query::count()` issue with `orderBy` (Alex-Code)
- Bug #13848: `yii\di\Instance::ensure()` wasn't throwing an exception when `$type` is specified and `$reference` object isn't instance of `$type` (c-jonua)
- Bug #13890: `yii\log\DbTarget` log messages where not written when a database transaction was rolled back, added support for cloning a `yii\db\Connection` (shirase, cebe)
- Bug #13901: Fixed passing unused parameter to `formatMessage()` call in `\yii\validators\IpValidator` (Kolyunya)
- Bug #13961: Fixed `unserialize()` error during RBAC rule retrieving from PostgreSQL DBMS (vsguts, nanodesu88, cebe)
- Bug #14012: `yii\db\pgsql\Schema::findViewNames()` was skipping materialized views (insolita)
- Bug #14033: Fixed `yii\filters\AccessRule::matchIp()` erroring in case IP is not defined under HHVM (Kolyunya)
- Bug #14042: Fixed ambiguous column name in SELECT in UniqueValidator (cebe)
- Bug #14052: Fixed processing parse errors on PHP 7 since these are instances of `\ParseError` (samdark)
- Bug #14072: Fixed a bug where `\yii\db\Command::createTable()`, `addForeignKey()`, `dropForeignKey()`, `addCommentOnColumn()`, and `dropCommentFromColumn()` weren't refreshing the table cache on `yii\db\Schema` (brandonkelly)
- Bug #14074: Fixed default value of `yii\console\controllers\FixtureController::$globalFixtures` to contain valid class name (lynicidn)
- Bug #14094: Fixed bug when single `yii\web\UrlManager::createUrl()` call my result multiple calls of `yii\web\UrlRule::createUrl()` for the same rule (rossoneri)
- Bug #14133: Fixed bug when calculating timings with mixed nested profile begin and end in `yii\log\Logger::calculateTimings()` (bizley)
- Enh #4793: `yii\filters\AccessControl` now can be used without `user` component (bizley)
- Enh #4999: Added support for wildcards at `yii\filters\AccessRule::$controllers` (klimov-paul)
- Enh #5108: `yii\validators\DateValidator` now resets `$timestampAttribute` value on empty validated attribute value (klimov-paul)
- Enh #8426: `yii\filters\AccessRule` now allows passing parameters to the role checking function (fsateler, cebe, Faryshta)
- Enh #8641: Enhanced `yii\console\Request::resolve()` to prevent passing parameters, that begin from digits (silverfire)
- Enh #11288: Added support for caching of `yii\web\UrlRule::createUrl()` results in `yii\web\UrlManager` for rules with defaults (rob006)
- Enh #12528: Added option to disable query logging and profiling in DB command (cebe)
- Enh #13144: Refactored `yii\db\Query::queryScalar()` (Alex-Code)
- Enh #13179: Added `yii\data\Sort::parseSortParam` allowing to customize sort param in descendant class (leandrogehlen)
- Enh #13221: Make `\yii\db\QueryTrait::limit()` and `\yii\db\QueryTrait::offset()` methods work with `\yii\db\Expression` (Ni-san)
- Enh #13226: `yii cache` command now warns about the fact that it's not able to flush APC cache from console (samdark)
- Enh #13240: Client scripts registration in `yii\widgets\ActiverForm` was moved to the separate `registerClientScript()` method (uaoleg, silverfire)
- Enh #13243: Added support for unicode attribute names in `yii\widgets\DetailView` (arogachev)
- Enh #13254: Core validators no longer require `Yii::$app` to be set (sammousa)
- Enh #13260: Added support for sorting by expression to `\yii\data\Sort` (LAV45, klimov-paul)
- Enh #13278: `yii\caching\DbQueryDependency` created allowing specification of the cache dependency via `yii\db\QueryInterface` (klimov-paul)
- Enh #13352: Added option to not render empty row in `yii\grid\GridView` when data is empty and `emptyText` set to `false` (arogachev)
- Enh #13356: Support multiple paths in `MigrateController::$migrationPath` to load non-namespaced migrations for BC with existing applications and extensions (schmunk42, cebe)
- Enh #13360: Added Dockerized test setup for the framework tests (schmunk42)
- Enh #13369: Added ability to render current `yii\widgets\LinkPager` page disabled (aquy)
- Enh #13376: Data provider now automatically sets an ID so there is no need to set it manually in case multiple data providers are used with pagination (SamMousa)
- Enh #13407: Added URL-safe base64 encode/decode methods to `StringHelper` (andrewnester)
- Enh #13467: `yii\data\ActiveDataProvider` no longer queries models if models count is zero (kLkA, Kolyunya)
- Enh #13523: Plural rule for pasta (developeruz)
- Enh #13550: Refactored unset call order in `yii\di\ServiceLocator::set()` (Lanrik)
- Enh #13523: Fixed pluralization and singularization for words `pasta`, `currency` (developeruz, silverfire)
- Enh #13550: Refactored `unset()` call order in `yii\di\ServiceLocator::set()` (Lanrik)
- Enh #13560: Refactored `\yii\widgets\FragmentCache::getCachedContent()`, added tests (Kolyunya)
- Enh #13576: Added support of `srcset` to `yii\helpers\Html::img()` (Kolyunya)
- Enh #13577: Implemented `yii\db\mssql\QueryBuilder::resetSequence()` (boboldehampsink)
- Enh #13582: Added tests for all `yii\db\QueryBuilder::resetSequence` implementations, fixed SQLite implementation (boboldehampsink)
- Enh #13407: Added URL-safe base64 encode/decode methods to `StringHelper` (andrewnester)
- Bug #13649: Fixes issue where `['uncheck' => false]` and `['label' => false]` options for `ActiveRadio` and `ActiveCheckbox` were ignored (Alex-Code)
- Enh #13221: Make `\yii\db\QueryTrait::limit()` and `\yii\db\QueryTrait::offset()` methods work with `\yii\db\Expression` (Ni-san)
- Enh #13144: Refactored `yii\db\Query::queryScalar()` (Alex-Code)
- Enh #13360: Added Dockerized test setup for the framework tests (schmunk42)
- Bug #13379: Fixed `applyFilter` function in `yii.gridView.js` to work correctly when params in `filterUrl` are indexed (SilverFire, arogachev)
- Enh #13582: Added tests for all `yii\db\QueryBuilder::resetSequence()` implementations, fixed SQLite implementation (boboldehampsink)
- Enh #13642: Allow overriding the function for creating related queries in ActiveRecord by adding `createRelationQuery()` (leandrogehlen)
- Enh #13650: Improved `yii\base\Security::hkdf()` to take advantage of native `hash_hkdf()` implementation in PHP >= 7.1.2 (charlesportwoodii)
- Bug #13670: Fixed alias option from console when it includes `-` or `_` in option name (pana1990)
- Enh: Added `yii\di\Instance::__set_state()` method to restore object after serialization using `var_export()` function (silvefire)
- Enh #13695: `\yii\web\Response::setStatusCode()` method now returns the Response object itself (kyle-mccarthy)
- Bug #13728: Fixed the bug when `yii\behaviors\SluggableBehavior` wasn't preserving immutable slug values (Kolyunya)
- Bug #13707: Fixed `\yii\web\ErrorHandler` and `\yii\web\ErrorAction` not setting correct response code to response object before rendering error view (samdark)
- Enh #13695: `yii\web\Response::setStatusCode()` method now returns the Response object itself (kyle-mccarthy)
- Enh #13698: `yii\grid\DataColumn` filter is automatically generated as dropdown list in case of `format` set to `boolean` (bizley)
- Enh #13254: Core validators no longer require Yii::$app to be set (sammousa)
- Bug #4408: Add support for unicode word characters and `+` character in attribute names (sammousa, kmindi)
- Bug #10372: Fixed console controller including complex typed arguments in help (sammousa)
- Bug #13738: Fixed `getQueryParams()` method in `yii.js` to correctly parse URL with question mark and no query parameters (vladdnepr)
- Bug #13776: Fixed setting precision and scale for decimal columns in MSSQL (arturf)
- Bug #13704: Fixed `yii\validators\UniqueValidator` to prefix attribute name with model's database table name (vladis84)
- Enh #13770: Added support for `yii\widgets\Menu` item classes definition in the form of an array (Kolyunya)
- Enh #13820: Add new HTTP status code 451 (yyxx9988)
- Enh #13823: Refactored migrations template (Kolyunya)
- Bug #13807: Fixed `yii\db\QueryBuilder` to inherit subquery params when building a `INSERT INTO ... SELECT` query (sergeymakinen)
- Enh #13845: `mt_rand()` is used instead of `rand()` in `yii\captcha\CaptchaAction` (kalessil)
- Enh #13883: `\yii\data\SqlDataProvider` now provides automatic fallback for the case when `totalCount` is not specified (SamMousa)
- Enh #13376: Data provider now automatically sets an ID so there is no need to set it manually in case multiple data providers are used with pagination (SamMousa)
- Enh #13369: Added ability to render current `yii\widgets\LinkPager` page disabled (aquy)
- Enh #13837: Refactored masking of CSRF tokens (sammousa)
- Enh #13560: Refactored `\yii\widgets\FragmentCache::getCachedContent()`, added tests (Kolyunya)
- Bug #13901: Fixed passing unused parameter to `formatMessage()` call in `\yii\validators\IpValidator` (Kolyunya)
- Enh #13845: `mt_rand()` is used instead of `rand()` in `yii\captcha\CaptchaAction` (kalessil)
- Enh #13883: `yii\data\SqlDataProvider` now provides automatic fallback for the case when `totalCount` is not specified (SamMousa)
- Enh #13911: Significantly enhanced MSSQL schema reading performance (paulzi, WebdevMerlion)
- Enh #13945: Removed Courier New from error page fonts list since it looks bad on Linux (samdark)
- Bug #13961: RBAC Rules: PostgreSQL: PHP Warning "unserialize() expects parameter 1 to be string, resource given" was fixed (vsguts)
- Enh #13976: Disabled IPv6 check on `\yii\validators\IpValidator` as it turns out it is not needed for inet_* methods to work (mikk150)
- Enh #13963: Added tests for `yii\behaviors\TimestampBehavior` (vladis84)
- Enh #13976: Disabled IPv6 check on `\yii\validators\IpValidator` as it turns out it is not needed for `inet_*` methods to work (mikk150)
- Enh #13981: `yii\caching\Cache::getOrSet()` now supports both `Closure` and `callable` (silverfire)
- Enh #13911: Significantly enhanced MSSQL schema reading performance (paulzi, WebdevMerlion)
- Enh #13994: Refactored `yii\filters\RateLimiter`. Added tests (vladis84)
- Enh #14059: Removed unused AR instantiating for calling of static methods (ElisDN)
- Enh #14067: `yii\web\View::clear()` sets populated arrays to empty arrays instead of null, also changed default values to empty array (craiglondon)
- Enh #14098: `yii\helpers\BaseFileHelper::normalizeOptions()` is now protected (brandonkelly)
- Enh: Added `yii\di\Instance::__set_state()` method to restore object after serialization using `var_export()` function (silvefire)
2.0.11.2 February 08, 2017
--------------------------
@ -1845,4 +1891,3 @@ Yii Framework 2 Change Log
- [Smarty View Renderer](https://github.com/yiisoft/yii2-smarty)
- [Twig View Renderer](https://github.com/yiisoft/yii2-twig)

7
framework/UPGRADE.md

@ -72,7 +72,14 @@ Upgrade from Yii 2.0.11
* The signature of `yii\cache\Cache::getOrSet()` has been adjusted to also accept a callable and not only `Closure`.
If you extend this method, make sure to adjust your code.
* `yii\web\UrlManager` now checks if rules implement `getCreateUrlStatus()` method in order to decide whether to use
internal cache for `createUrl()` calls. Ensure that all your custom rules implement this method in order to fully
benefit from the acceleration provided by this cache.
* `yii\filters\AccessControl` now can be used without `user` component.
In this case `yii\filters\AccessControl::denyAccess()` throws `yii\web\ForbiddenHttpException` and using `AccessRule`
matching a role throws `yii\base\InvalidConfigException`.
Upgrade from Yii 2.0.10
-----------------------

6
framework/base/Controller.php

@ -342,7 +342,7 @@ class Controller extends Component implements ViewContextInterface
*
* The view to be rendered can be specified in one of the following formats:
*
* - path alias (e.g. "@app/views/site/index");
* - [path alias](guide:concept-aliases) (e.g. "@app/views/site/index");
* - absolute path within application (e.g. "//site/index"): the view name starts with double slashes.
* The actual view file will be looked for under the [[Application::viewPath|view path]] of the application.
* - absolute path within module (e.g. "/site/index"): the view name starts with a single slash.
@ -362,7 +362,7 @@ class Controller extends Component implements ViewContextInterface
* 2. In the second step, it determines the actual layout file according to the previously found layout name
* and context module. The layout name can be:
*
* - a path alias (e.g. "@app/views/layouts/main");
* - a [path alias](guide:concept-aliases) (e.g. "@app/views/layouts/main");
* - an absolute path (e.g. "/main"): the layout name starts with a slash. The actual layout file will be
* looked for under the [[Application::layoutPath|layout path]] of the application;
* - a relative path (e.g. "main"): the actual layout file will be looked for under the
@ -413,7 +413,7 @@ class Controller extends Component implements ViewContextInterface
/**
* Renders a view file.
* @param string $file the view file to be rendered. This can be either a file path or a path alias.
* @param string $file the view file to be rendered. This can be either a file path or a [path alias](guide:concept-aliases).
* @param array $params the parameters (name-value pairs) that should be made available in the view.
* @return string the rendering result.
* @throws InvalidArgumentException if the view file does not exist.

4
framework/base/Module.php

@ -231,7 +231,7 @@ class Module extends ServiceLocator
/**
* Sets the root directory of the module.
* This method can only be invoked at the beginning of the constructor.
* @param string $path the root directory of the module. This can be either a directory name or a path alias.
* @param string $path the root directory of the module. This can be either a directory name or a [path alias](guide:concept-aliases).
* @throws InvalidArgumentException if the directory does not exist.
*/
public function setBasePath($path)
@ -294,7 +294,7 @@ class Module extends ServiceLocator
/**
* Sets the directory that contains the layout files.
* @param string $path the root directory or path alias of layout files.
* @param string $path the root directory or [path alias](guide:concept-aliases) of layout files.
* @throws InvalidArgumentException if the directory is invalid
*/
public function setLayoutPath($path)

2
framework/base/Request.php

@ -73,7 +73,7 @@ abstract class Request extends Component
* The entry script file path can normally be determined based on the `SCRIPT_FILENAME` SERVER variable.
* However, for some server configurations, this may not be correct or feasible.
* This setter is provided so that the entry script file path can be manually specified.
* @param string $value the entry script file path. This can be either a file path or a path alias.
* @param string $value the entry script file path. This can be either a file path or a [path alias](guide:concept-aliases).
* @throws InvalidConfigException if the provided entry script file path is invalid.
*/
public function setScriptFile($value)

2
framework/base/Security.php

@ -276,7 +276,7 @@ class Security extends Component
if (function_exists('hash_hkdf')) {
$outputKey = hash_hkdf($algo, $inputKey, $length, $info, $salt);
if ($outputKey === false) {
throw new InvalidParamException('Invalid parameters to hash_hkdf()');
throw new InvalidArgumentException('Invalid parameters to hash_hkdf()');
}
return $outputKey;
}

6
framework/base/Theme.php

@ -76,7 +76,7 @@ class Theme extends Component
/**
* @var array the mapping between view directories and their corresponding themed versions.
* This property is used by [[applyTo()]] when a view is trying to apply the theme.
* Path aliases can be used when specifying directories.
* [Path aliases](guide:concept-aliases) can be used when specifying directories.
* If this property is empty or not set, a mapping [[Application::basePath]] to [[basePath]] will be used.
*/
public $pathMap;
@ -94,7 +94,7 @@ class Theme extends Component
}
/**
* @param string $url the base URL or path alias for this theme. All resources of this theme are considered
* @param string $url the base URL or [path alias](guide:concept-aliases) for this theme. All resources of this theme are considered
* to be under this base URL.
*/
public function setBaseUrl($url)
@ -114,7 +114,7 @@ class Theme extends Component
}
/**
* @param string $path the root path or path alias of this theme. All resources of this theme are located
* @param string $path the root path or [path alias](guide:concept-aliases) of this theme. All resources of this theme are located
* under this directory.
* @see pathMap
*/

28
framework/base/View.php

@ -126,7 +126,7 @@ class View extends Component
*
* The view to be rendered can be specified in one of the following formats:
*
* - path alias (e.g. "@app/views/site/index");
* - [path alias](guide:concept-aliases) (e.g. "@app/views/site/index");
* - absolute path within application (e.g. "//site/index"): the view name starts with double slashes.
* The actual view file will be looked for under the [[Application::viewPath|view path]] of the application.
* - absolute path within current module (e.g. "/site/index"): the view name starts with a single slash.
@ -154,7 +154,7 @@ class View extends Component
/**
* Finds the view file based on the given view name.
* @param string $view the view name or the path alias of the view file. Please refer to [[render()]]
* @param string $view the view name or the [path alias](guide:concept-aliases) of the view file. Please refer to [[render()]]
* on how to specify this parameter.
* @param object $context the context to be assigned to the view and can later be accessed via [[context]]
* in the view. If the context implements [[ViewContextInterface]], it may also be used to locate
@ -322,12 +322,28 @@ class View extends Component
*/
public function renderPhpFile($_file_, $_params_ = [])
{
$_obInitialLevel_ = ob_get_level();
ob_start();
ob_implicit_flush(false);
extract($_params_, EXTR_OVERWRITE);
require($_file_);
return ob_get_clean();
try {
require($_file_);
return ob_get_clean();
} catch (\Exception $e) {
while (ob_get_level() > $_obInitialLevel_) {
if (!@ob_end_clean()) {
ob_clean();
}
}
throw $e;
} catch (\Throwable $e) {
while (ob_get_level() > $_obInitialLevel_) {
if (!@ob_end_clean()) {
ob_clean();
}
}
throw $e;
}
}
/**
@ -427,7 +443,7 @@ class View extends Component
* ```
*
* @param string $viewFile the view file that will be used to decorate the content enclosed by this widget.
* This can be specified as either the view file path or path alias.
* This can be specified as either the view file path or [path alias](guide:concept-aliases).
* @param array $params the variables (name => value) to be extracted and made available in the decorative view.
* @return ContentDecorator the ContentDecorator widget instance
* @see ContentDecorator

4
framework/base/Widget.php

@ -214,7 +214,7 @@ class Widget extends Component implements ViewContextInterface
* Renders a view.
* The view to be rendered can be specified in one of the following formats:
*
* - path alias (e.g. "@app/views/site/index");
* - [path alias](guide:concept-aliases) (e.g. "@app/views/site/index");
* - absolute path within application (e.g. "//site/index"): the view name starts with double slashes.
* The actual view file will be looked for under the [[Application::viewPath|view path]] of the application.
* - absolute path within module (e.g. "/site/index"): the view name starts with a single slash.
@ -236,7 +236,7 @@ class Widget extends Component implements ViewContextInterface
/**
* Renders a view file.
* @param string $file the view file to be rendered. This can be either a file path or a path alias.
* @param string $file the view file to be rendered. This can be either a file path or a [path alias](guide:concept-aliases).
* @param array $params the parameters (name-value pairs) that should be made available in the view.
* @return string the rendering result.
* @throws InvalidArgumentException if the view file does not exist.

2
framework/behaviors/SluggableBehavior.php

@ -66,7 +66,7 @@ class SluggableBehavior extends AttributeBehavior
public $slugAttribute = 'slug';
/**
* @var string|array|null the attribute or list of attributes whose value will be converted into a slug
* or `null` meaning that the `$value` property will be used to generate a slug.
* or `null` meaning that the `$value` property will be used to generate a slug.
*/
public $attribute;
/**

43
framework/caching/DbCache.php

@ -136,9 +136,8 @@ class DbCache extends Cache
$this->db->enableQueryCache = true;
return $result;
} else {
return $query->createCommand($this->db)->queryScalar();
}
return $query->createCommand($this->db)->queryScalar();
}
/**
@ -187,19 +186,21 @@ class DbCache extends Cache
*/
protected function setValue($key, $value, $duration)
{
$command = $this->db->createCommand()
->update($this->cacheTable, [
'expire' => $duration > 0 ? $duration + time() : 0,
'data' => [$value, \PDO::PARAM_LOB],
], ['id' => $key]);
$result = $this->db->noCache(function (Connection $db) use ($key, $value, $duration) {
$command = $db->createCommand()
->update($this->cacheTable, [
'expire' => $duration > 0 ? $duration + time() : 0,
'data' => [$value, \PDO::PARAM_LOB],
], ['id' => $key]);
return $command->execute();
});
if ($command->execute()) {
if ($result) {
$this->gc();
return true;
} else {
return $this->addValue($key, $value, $duration);
}
return $this->addValue($key, $value, $duration);
}
/**
@ -216,12 +217,14 @@ class DbCache extends Cache
$this->gc();
try {
$this->db->createCommand()
->insert($this->cacheTable, [
'id' => $key,
'expire' => $duration > 0 ? $duration + time() : 0,
'data' => [$value, \PDO::PARAM_LOB],
])->execute();
$this->db->noCache(function (Connection $db) use ($key, $value, $duration) {
$db->createCommand()
->insert($this->cacheTable, [
'id' => $key,
'expire' => $duration > 0 ? $duration + time() : 0,
'data' => [$value, \PDO::PARAM_LOB],
])->execute();
});
return true;
} catch (\Exception $e) {
@ -237,9 +240,11 @@ class DbCache extends Cache
*/
protected function deleteValue($key)
{
$this->db->createCommand()
->delete($this->cacheTable, ['id' => $key])
->execute();
$this->db->noCache(function (Connection $db) use ($key) {
$db->createCommand()
->delete($this->cacheTable, ['id' => $key])
->execute();
});
return true;
}

2
framework/caching/FileCache.php

@ -35,7 +35,7 @@ class FileCache extends Cache
*/
public $keyPrefix = '';
/**
* @var string the directory to store cache files. You may use path alias here.
* @var string the directory to store cache files. You may use [path alias](guide:concept-aliases) here.
* If not set, it will use the "cache" subdirectory under the application runtime path.
*/
public $cachePath = '@runtime/cache';

2
framework/caching/FileDependency.php

@ -24,7 +24,7 @@ use yii\base\InvalidConfigException;
class FileDependency extends Dependency
{
/**
* @var string the file path or path alias whose last modification time is used to
* @var string the file path or [path alias](guide:concept-aliases) whose last modification time is used to
* check if the dependency has been changed.
*/
public $fileName;

2
framework/captcha/CaptchaAction.php

@ -87,7 +87,7 @@ class CaptchaAction extends Action
*/
public $offset = -2;
/**
* @var string the TrueType font file. This can be either a file path or path alias.
* @var string the TrueType font file. This can be either a file path or [path alias](guide:concept-aliases).
*/
public $fontFile = '@yii/captcha/SpicyRice.ttf';
/**

2
framework/classes.php

@ -66,6 +66,7 @@ return [
'yii\caching\ChainedDependency' => YII2_PATH . '/caching/ChainedDependency.php',
'yii\caching\DbCache' => YII2_PATH . '/caching/DbCache.php',
'yii\caching\DbDependency' => YII2_PATH . '/caching/DbDependency.php',
'yii\caching\DbQueryDependency' => YII2_PATH . '/caching/DbQueryDependency.php',
'yii\caching\Dependency' => YII2_PATH . '/caching/Dependency.php',
'yii\caching\DummyCache' => YII2_PATH . '/caching/DummyCache.php',
'yii\caching\ExpressionDependency' => YII2_PATH . '/caching/ExpressionDependency.php',
@ -114,6 +115,7 @@ return [
'yii\db\StaleObjectException' => YII2_PATH . '/db/StaleObjectException.php',
'yii\db\TableSchema' => YII2_PATH . '/db/TableSchema.php',
'yii\db\Transaction' => YII2_PATH . '/db/Transaction.php',
'yii\db\ViewFinderTrait' => YII2_PATH . '/db/ViewFinderTrait.php',
'yii\db\cubrid\ColumnSchemaBuilder' => YII2_PATH . '/db/cubrid/ColumnSchemaBuilder.php',
'yii\db\cubrid\QueryBuilder' => YII2_PATH . '/db/cubrid/QueryBuilder.php',
'yii\db\cubrid\Schema' => YII2_PATH . '/db/cubrid/Schema.php',

2
framework/composer.json

@ -71,7 +71,7 @@
"ezyang/htmlpurifier": "~4.6",
"cebe/markdown": "~1.0.0 | ~1.1.0",
"bower-asset/jquery": "2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable",
"bower-asset/jquery.inputmask": "~3.2.2 | ~3.3.3",
"bower-asset/jquery.inputmask": "~3.2.2 | ~3.3.5",
"bower-asset/punycode": "1.3.*",
"bower-asset/yii2-pjax": "~2.0.1"
},

2
framework/console/controllers/AssetController.php

@ -32,7 +32,7 @@ use yii\web\AssetManager;
*
* 4. Adjust your web application config to use compressed assets.
*
* Note: in the console environment some path aliases like `@webroot` and `@web` may not exist,
* Note: in the console environment some [path aliases](guide:concept-aliases) like `@webroot` and `@web` may not exist,
* so corresponding paths inside the configuration should be specified directly.
*
* Note: by default this command relies on an external tools to perform actual files compression,

87
framework/console/controllers/BaseMigrateController.php

@ -13,6 +13,7 @@ use yii\console\Exception;
use yii\console\Controller;
use yii\helpers\Console;
use yii\helpers\FileHelper;
use yii\helpers\StringHelper;
/**
* BaseMigrateController is the base class for migrate controllers.
@ -32,22 +33,33 @@ abstract class BaseMigrateController extends Controller
*/
public $defaultAction = 'up';
/**
* @var string the directory containing the migration classes. This can be either
* a path alias or a directory path.
* @var string|array the directory containing the migration classes. This can be either
* a [path alias](guide:concept-aliases) or a directory path.
*
* Migration classes located at this path should be declared without a namespace.
* Use [[migrationNamespaces]] property in case you are using namespaced migrations.
*
* If you have set up [[migrationNamespaces]], you may set this field to `null` in order
* to disable usage of migrations that are not namespaced.
*
* Since version 2.0.12 you may also specify an array of migration paths that should be searched for
* migrations to load. This is mainly useful to support old extensions that provide migrations
* without namespace and to adopt the new feature of namespaced migrations while keeping existing migrations.
*
* In general, to load migrations from different locations, [[migrationNamespaces]] is the preferable solution
* as the migration name contains the origin of the migration in the history, which is not the case when
* using multiple migration paths.
*
* @see $migrationNamespaces
*/
public $migrationPath = '@app/migrations';
public $migrationPath = ['@app/migrations'];
/**
* @var array list of namespaces containing the migration classes.
*
* Migration namespaces should be resolvable as a path alias if prefixed with `@`, e.g. if you specify
* Migration namespaces should be resolvable as a [path alias](guide:concept-aliases) if prefixed with `@`, e.g. if you specify
* the namespace `app\migrations`, the code `Yii::getAlias('@app/migrations')` should be able to return
* the file path to the directory this namespace refers to.
* This corresponds with the [autoloading conventions](guide:concept-autoloading) of Yii.
*
* For example:
*
@ -59,11 +71,12 @@ abstract class BaseMigrateController extends Controller
* ```
*
* @since 2.0.10
* @see $migrationPath
*/
public $migrationNamespaces = [];
/**
* @var string the template file for generating new migrations.
* This can be either a path alias (e.g. "@app/migrations/template.php")
* This can be either a [path alias](guide:concept-aliases) (e.g. "@app/migrations/template.php")
* or a file path.
*/
public $templateFile;
@ -99,7 +112,11 @@ abstract class BaseMigrateController extends Controller
$this->migrationNamespaces[$key] = trim($value, '\\');
}
if ($this->migrationPath !== null) {
if (is_array($this->migrationPath)) {
foreach($this->migrationPath as $i => $path) {
$this->migrationPath[$i] = Yii::getAlias($path);
}
} elseif ($this->migrationPath !== null) {
$path = Yii::getAlias($this->migrationPath);
if (!is_dir($path)) {
if ($action->id !== 'create') {
@ -187,8 +204,8 @@ abstract class BaseMigrateController extends Controller
* yii migrate/down all # revert all migrations
* ```
*
* @param int $limit the number of migrations to be reverted. Defaults to 1,
* meaning the last applied migration will be reverted.
* @param int|string $limit the number of migrations to be reverted. Defaults to 1,
* meaning the last applied migration will be reverted. When value is "all", all migrations will be reverted.
* @throws Exception if the number of the steps specified is less than 1.
*
* @return int the status of the action execution. 0 means normal, other values mean abnormal.
@ -249,8 +266,8 @@ abstract class BaseMigrateController extends Controller
* yii migrate/redo all # redo all migrations
* ```
*
* @param int $limit the number of migrations to be redone. Defaults to 1,
* meaning the last applied migration will be redone.
* @param int|string $limit the number of migrations to be redone. Defaults to 1,
* meaning the last applied migration will be redone. When equals "all", all migrations will be redone.
* @throws Exception if the number of the steps specified is less than 1.
*
* @return int the status of the action execution. 0 means normal, other values mean abnormal.
@ -446,7 +463,7 @@ abstract class BaseMigrateController extends Controller
* yii migrate/history all # showing the whole history
* ```
*
* @param int $limit the maximum number of migrations to be displayed.
* @param int|string $limit the maximum number of migrations to be displayed.
* If it is "all", the whole migration history will be displayed.
* @throws \yii\console\Exception if invalid limit value passed
*/
@ -490,7 +507,7 @@ abstract class BaseMigrateController extends Controller
* yii migrate/new all # showing all new migrations
* ```
*
* @param int $limit the maximum number of new migrations to be displayed.
* @param int|string $limit the maximum number of new migrations to be displayed.
* If it is `all`, all available new migrations will be displayed.
* @throws \yii\console\Exception if invalid limit value passed
*/
@ -616,7 +633,7 @@ abstract class BaseMigrateController extends Controller
private function findMigrationPath($namespace)
{
if (empty($namespace)) {
return $this->migrationPath;
return is_array($this->migrationPath) ? reset($this->migrationPath) : $this->migrationPath;
}
if (!in_array($namespace, $this->migrationNamespaces, true)) {
@ -700,13 +717,36 @@ abstract class BaseMigrateController extends Controller
*/
protected function createMigration($class)
{
$this->includeMigrationFile($class);
return new $class();
}
/**
* Includes the migration file for a given migration class name.
*
* This function will do nothing on namespaced migrations, which are loaded by
* autoloading automatically. It will include the migration file, by searching
* [[migrationPath]] for classes without namespace.
* @param string $class the migration class name.
* @since 2.0.12
*/
protected function includeMigrationFile($class)
{
$class = trim($class, '\\');
if (strpos($class, '\\') === false) {
$file = $this->migrationPath . DIRECTORY_SEPARATOR . $class . '.php';
require_once($file);
if (is_array($this->migrationPath)) {
foreach($this->migrationPath as $path) {
$file = $path . DIRECTORY_SEPARATOR . $class . '.php';
if (is_file($file)) {
require_once($file);
break;
}
}
} else {
$file = $this->migrationPath . DIRECTORY_SEPARATOR . $class . '.php';
require_once($file);
}
}
return new $class();
}
/**
@ -776,15 +816,20 @@ abstract class BaseMigrateController extends Controller
}
$migrationPaths = [];
if (!empty($this->migrationPath)) {
$migrationPaths[''] = $this->migrationPath;
if (is_array($this->migrationPath)) {
foreach($this->migrationPath as $path) {
$migrationPaths[] = [$path, ''];
}
} elseif (!empty($this->migrationPath)) {
$migrationPaths[] = [$this->migrationPath, ''];
}
foreach ($this->migrationNamespaces as $namespace) {
$migrationPaths[$namespace] = $this->getNamespacePath($namespace);
$migrationPaths[] = [$this->getNamespacePath($namespace), $namespace];
}
$migrations = [];
foreach ($migrationPaths as $namespace => $migrationPath) {
foreach ($migrationPaths as $item) {
list($migrationPath, $namespace) = $item;
if (!file_exists($migrationPath)) {
continue;
}

25
framework/console/controllers/CacheController.php

@ -8,6 +8,7 @@
namespace yii\console\controllers;
use Yii;
use yii\caching\ApcCache;
use yii\console\Controller;
use yii\caching\Cache;
use yii\helpers\Console;
@ -32,7 +33,7 @@ use yii\console\Exception;
* configured are different from web application, web application cache won't be cleared. In order to fix it please
* duplicate web application cache components in console config. You can use any component names.
*
* Both APC and OpCache aren't shared between PHP processes so flushing cache from command line has no effect on web.
* APC is not shared between PHP processes so flushing cache from command line has no effect on web.
* Flushing web cache could be either done by:
*
* - Putting a php file under web root and calling it via HTTP
@ -99,7 +100,7 @@ class CacheController extends Controller
$cachesInfo[] = [
'name' => $name,
'class' => $class,
'is_flushed' => Yii::$app->get($name)->flush(),
'is_flushed' => $this->canBeFlushed($class) ? Yii::$app->get($name)->flush() : false,
];
}
@ -123,7 +124,7 @@ class CacheController extends Controller
$cachesInfo[] = [
'name' => $name,
'class' => $class,
'is_flushed' => Yii::$app->get($name)->flush(),
'is_flushed' => $this->canBeFlushed($class) ? Yii::$app->get($name)->flush() : false,
];
}
@ -178,7 +179,11 @@ class CacheController extends Controller
$this->stdout("The following caches were found in the system:\n\n", Console::FG_YELLOW);
foreach ($caches as $name => $class) {
$this->stdout("\t* $name ($class)\n", Console::FG_GREEN);
if ($this->canBeFlushed($class)) {
$this->stdout("\t* $name ($class)\n", Console::FG_GREEN);
} else {
$this->stdout("\t* $name ($class) - can not be flushed via console\n", Console::FG_YELLOW);
}
}
$this->stdout("\n");
@ -256,7 +261,7 @@ class CacheController extends Controller
$findAll = ($cachesNames === []);
foreach ($components as $name => $component) {
if (!$findAll && !in_array($name, $cachesNames)) {
if (!$findAll && !in_array($name, $cachesNames, true)) {
continue;
}
@ -281,4 +286,14 @@ class CacheController extends Controller
{
return is_subclass_of($className, Cache::class);
}
/**
* Checks if cache of a certain class can be flushed
* @param string $className class name.
* @return bool
*/
private function canBeFlushed($className)
{
return !is_a($className, ApcCache::class, true) || php_sapi_name() !== "cli";
}
}

28
framework/console/controllers/FixtureController.php

@ -15,7 +15,7 @@ use yii\console\Exception;
use yii\helpers\Console;
use yii\helpers\FileHelper;
use yii\test\FixtureTrait;
use yii\test\InitDb;
use yii\test\InitDbFixture;
/**
* Manages fixture data loading and unloading.
@ -58,7 +58,9 @@ class FixtureController extends Controller
* @var array global fixtures that should be applied when loading and unloading. By default it is set to `InitDbFixture`
* that disables and enables integrity check, so your data can be safely loaded.
*/
public $globalFixtures = [InitDb::class];
public $globalFixtures = [
InitDbFixture::class,
];
/**
@ -414,13 +416,31 @@ class FixtureController extends Controller
$foundFixtures = [];
foreach ($files as $fixture) {
$foundFixtures[] = basename($fixture, 'Fixture.php');
$foundFixtures[] = $this->getFixtureRelativeName($fixture);
}
return $foundFixtures;
}
/**
* Calculates fixture's name
* Basically, strips [[getFixturePath()]] and `Fixture.php' suffix from fixture's full path
* @see getFixturePath()
* @param string $fullFixturePath Full fixture path
* @return string Relative fixture name
*/
private function getFixtureRelativeName($fullFixturePath)
{
$fixturesPath = FileHelper::normalizePath($this->getFixturePath());
$fullFixturePath = FileHelper::normalizePath($fullFixturePath);
$relativeName = substr($fullFixturePath, strlen($fixturesPath)+1);
$relativeDir = dirname($relativeName) === '.' ? '' : dirname($relativeName) . DIRECTORY_SEPARATOR;
return $relativeDir . basename($fullFixturePath, 'Fixture.php');
}
/**
* Returns valid fixtures config that can be used to load them.
* @param array $fixtures fixtures to configure
* @return array
@ -431,6 +451,8 @@ class FixtureController extends Controller
foreach ($fixtures as $fixture) {
$isNamespaced = (strpos($fixture, '\\') !== false);
// replace linux' path slashes to namespace backslashes, in case if $fixture is non-namespaced relative path
$fixture = str_replace('/', '\\', $fixture);
$fullClassName = $isNamespaced ? $fixture . 'Fixture' : $this->namespace . '\\' . $fixture . 'Fixture';
if (class_exists($fullClassName)) {

7
framework/console/controllers/MessageController.php

@ -482,8 +482,9 @@ EOD;
*/
protected function extractMessages($fileName, $translator, $ignoreCategories = [])
{
$coloredFileName = Console::ansiFormat($fileName, [Console::FG_CYAN]);
$this->stdout("Extracting messages from $coloredFileName...\n");
$this->stdout("Extracting messages from ");
$this->stdout($fileName, Console::FG_CYAN);
$this->stdout("...\n");
$subject = file_get_contents($fileName);
$messages = [];
@ -506,7 +507,7 @@ EOD;
* @param array $ignoreCategories message categories to ignore.
* @return array messages.
*/
private function extractMessagesFromTokens(array $tokens, array $translatorTokens, array $ignoreCategories)
protected function extractMessagesFromTokens(array $tokens, array $translatorTokens, array $ignoreCategories)
{
$messages = [];
$translatorTokensCount = count($translatorTokens);

7
framework/console/controllers/MigrateController.php

@ -182,12 +182,7 @@ class MigrateController extends BaseMigrateController
*/
protected function createMigration($class)
{
$class = trim($class, '\\');
if (strpos($class, '\\') === false) {
$file = $this->migrationPath . DIRECTORY_SEPARATOR . $class . '.php';
require_once($file);
}
$this->includeMigrationFile($class);
return new $class(['db' => $this->db]);
}

2
framework/console/controllers/ServeController.php

@ -32,7 +32,7 @@ class ServeController extends Controller
*/
public $port = 8080;
/**
* @var string path or path alias to directory to serve
* @var string path or [path alias](guide:concept-aliases) to directory to serve
*/
public $docroot = '@app/web';
/**

2
framework/data/ActiveDataProvider.php

@ -133,7 +133,7 @@ class ActiveDataProvider extends BaseDataProvider
return $keys;
} elseif ($this->query instanceof ActiveQueryInterface) {
/* @var $class \yii\db\ActiveRecord */
/* @var $class \yii\db\ActiveRecordInterface */
$class = $this->query->modelClass;
$pks = $class::primaryKey();
if (count($pks) === 1) {

1
framework/data/BaseDataProvider.php

@ -51,6 +51,7 @@ abstract class BaseDataProvider extends Component implements DataProviderInterfa
private $_models;
private $_totalCount;
/**
* @inheritdoc
*/

2
framework/data/DataProviderInterface.php

@ -66,7 +66,7 @@ interface DataProviderInterface
public function getSort();
/**
* @return Pagination the pagination object. If this is false, it means the pagination is disabled.
* @return Pagination|false the pagination object. If this is false, it means the pagination is disabled.
*/
public function getPagination();
}

48
framework/data/Sort.php

@ -112,6 +112,15 @@ class Sort extends Object
* ]
* ```
*
* Since 2.0.12 particular sort direction can be also specified as direct sort expression, like following:
*
* ```php
* 'name' => [
* 'asc' => '[[last_name]] ASC NULLS FIRST', // PostgreSQL specific feature
* 'desc' => '[[last_name]] DESC NULLS LAST',
* ]
* ```
*
* The `name` attribute is a composite attribute:
*
* - The `name` key represents the attribute name which will appear in the URLs leading
@ -215,8 +224,12 @@ class Sort extends Object
foreach ($attributeOrders as $attribute => $direction) {
$definition = $this->attributes[$attribute];
$columns = $definition[$direction === SORT_ASC ? 'asc' : 'desc'];
foreach ($columns as $name => $dir) {
$orders[$name] = $dir;
if (is_array($columns) || $columns instanceof \Traversable) {
foreach ($columns as $name => $dir) {
$orders[$name] = $dir;
}
} else {
$orders[] = $columns;
}
}
@ -243,8 +256,8 @@ class Sort extends Object
$request = Yii::$app->getRequest();
$params = $request instanceof Request ? $request->getQueryParams() : [];
}
if (isset($params[$this->sortParam]) && is_scalar($params[$this->sortParam])) {
$attributes = explode($this->separator, $params[$this->sortParam]);
if (isset($params[$this->sortParam])) {
$attributes = $this->parseSortParam($params[$this->sortParam]);
foreach ($attributes as $attribute) {
$descending = false;
if (strncmp($attribute, '-', 1) === 0) {
@ -269,6 +282,33 @@ class Sort extends Object
}
/**
* Parses the value of [[sortParam]] into an array of sort attributes.
*
* The format must be the attribute name only for ascending
* or the attribute name prefixed with `-` for descending.
*
* For example the following return value will result in ascending sort by
* `category` and descending sort by `created_at`:
*
* ```php
* [
* 'category',
* '-created_at'
* ]
* ```
*
* @param string $param the value of the [[sortParam]].
* @return array the valid sort attributes.
* @since 2.0.12
* @see $separator for the attribute name separator.
* @see $sortParam
*/
protected function parseSortParam($param)
{
return is_scalar($param) ? explode($this->separator, $param) : [];
}
/**
* Sets up the currently sort information.
* @param array|null $attributeOrders sort directions indexed by attribute names.
* Sort direction can be either `SORT_ASC` for ascending order or

7
framework/data/SqlDataProvider.php

@ -132,7 +132,7 @@ class SqlDataProvider extends BaseDataProvider
$offset = $pagination->getOffset();
}
$sql = $this->db->getQueryBuilder()->buildOrderByAndLimit($sql, $orders, $limit, $offset);
$sql = $this->db->getQueryBuilder()->buildOrderByAndLimit($sql, $orders, $limit, $offset, $params);
return $this->db->createCommand($sql, $this->params)->queryAll();
}
@ -163,6 +163,9 @@ class SqlDataProvider extends BaseDataProvider
*/
protected function prepareTotalCount()
{
return (new Query())->from(['sub' => "({$this->sql})"])->count('*', $this->db);
return (new Query([
'from' => ['sub' => "({$this->sql})"],
'params' => $this->params
]))->count('*', $this->db);
}
}

104
framework/db/ActiveQuery.php

@ -66,6 +66,8 @@ use yii\base\InvalidConfigException;
* marks a relation as inverse of another relation and [[onCondition()]] which adds a condition that
* is to be added to relational query join condition.
*
* @property string[] $tablesUsedInFrom Table names indexed by aliases. This property is read-only.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
@ -148,10 +150,7 @@ class ActiveQuery extends Query implements ActiveQueryInterface
}
if (empty($this->from)) {
/* @var $modelClass ActiveRecord */
$modelClass = $this->modelClass;
$tableName = $modelClass::tableName();
$this->from = [$tableName];
$this->from = [$this->getPrimaryTableName()];
}
if (empty($this->select) && !empty($this->join)) {
@ -559,9 +558,7 @@ class ActiveQuery extends Query implements ActiveQueryInterface
private function getTableNameAndAlias()
{
if (empty($this->from)) {
/* @var $modelClass ActiveRecord */
$modelClass = $this->modelClass;
$tableName = $modelClass::tableName();
$tableName = $this->getPrimaryTableName();
} else {
$tableName = '';
foreach ($this->from as $alias => $tableName) {
@ -783,9 +780,7 @@ class ActiveQuery extends Query implements ActiveQueryInterface
list($tableName, ) = $this->getTableNameAndAlias();
$this->from = [$alias => $tableName];
} else {
/* @var $modelClass ActiveRecord */
$modelClass = $this->modelClass;
$tableName = $modelClass::tableName();
$tableName = $this->getPrimaryTableName();
foreach ($this->from as $key => $table) {
if ($table === $tableName) {
@ -796,4 +791,93 @@ class ActiveQuery extends Query implements ActiveQueryInterface
}
return $this;
}
/**
* Returns table names used in [[from]] indexed by aliases.
* Both aliases and names are enclosed into {{ and }}.
* @return string[] table names indexed by aliases
* @throws \yii\base\InvalidConfigException
* @since 2.0.12
*/
public function getTablesUsedInFrom()
{
if (empty($this->from)) {
$tableNames = [$this->getPrimaryTableName()];
} elseif (is_array($this->from)) {
$tableNames = $this->from;
} elseif (is_string($this->from)) {
$tableNames = preg_split('/\s*,\s*/', trim($this->from), -1, PREG_SPLIT_NO_EMPTY);
} else {
throw new InvalidConfigException(gettype($this->from) . ' in $from is not supported.');
}
// Clean up table names and aliases
$cleanedUpTableNames = [];
foreach ($tableNames as $alias => $tableName) {
if (!is_string($alias)) {
$pattern = <<<PATTERN
~
^
\s*
(
(?:['"`\[]|{{)
.*?
(?:['"`\]]|}})
|
.*?
)
(?:
(?:
\s+
(?:as)?
\s*
)
(
(?:['"`\[]|{{)
.*?
(?:['"`\]]|}})
|
.*?
)
)?
\s*
$
~iux
PATTERN;
if (preg_match($pattern, $tableName, $matches)) {
if (isset($matches[1])) {
if (isset($matches[2])) {
list(, $tableName, $alias) = $matches;
} else {
$tableName = $alias = $matches[1];
}
if (strncmp($alias, '{{', 2) !== 0) {
$alias = '{{' . $alias . '}}';
}
if (strncmp($tableName, '{{', 2) !== 0) {
$tableName = '{{' . $tableName . '}}';
}
}
}
}
$tableName = str_replace(["'", '"', '`', '[', ']'], '', $tableName);
$alias = str_replace(["'", '"', '`', '[', ']'], '', $alias);
$cleanedUpTableNames[$alias] = $tableName;
}
return $cleanedUpTableNames;
}
/**
* @return string primary table name
* @since 2.0.12
*/
protected function getPrimaryTableName()
{
/* @var $modelClass ActiveRecord */
$modelClass = $this->modelClass;
return $modelClass::tableName();
}
}

41
framework/db/BaseActiveRecord.php

@ -370,13 +370,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface
*/
public function hasOne($class, $link)
{
/* @var $class ActiveRecordInterface */
/* @var $query ActiveQuery */
$query = $class::find();
$query->primaryModel = $this;
$query->link = $link;
$query->multiple = false;
return $query;
return $this->createRelationQuery($class, $link, false);
}
/**
@ -411,12 +405,27 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface
*/
public function hasMany($class, $link)
{
return $this->createRelationQuery($class, $link, true);
}
/**
* Creates a query instance for `has-one` or `has-many` relation.
* @param string $class the class name of the related record.
* @param array $link the primary-foreign key constraint.
* @param bool $multiple whether this query represents a relation to more than one record.
* @return ActiveQueryInterface the relational query object.
* @since 2.0.12
* @see hasOne()
* @see hasMany()
*/
protected function createRelationQuery($class, $link, $multiple)
{
/* @var $class ActiveRecordInterface */
/* @var $query ActiveQuery */
$query = $class::find();
$query->primaryModel = $this;
$query->link = $link;
$query->multiple = true;
$query->multiple = $multiple;
return $query;
}
@ -909,12 +918,12 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface
* ```php
* public function beforeSave($insert)
* {
* if (parent::beforeSave($insert)) {
* // ...custom code here...
* return true;
* } else {
* if (!parent::beforeSave($insert)) {
* return false;
* }
*
* // ...custom code here...
* return true;
* }
* ```
*
@ -964,12 +973,12 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface
* ```php
* public function beforeDelete()
* {
* if (parent::beforeDelete()) {
* // ...custom code here...
* return true;
* } else {
* if (!parent::beforeDelete()) {
* return false;
* }
*
* // ...custom code here...
* return true;
* }
* ```
*

73
framework/db/Command.php

@ -472,6 +472,13 @@ class Command extends Component
* $connection->createCommand()->update('user', ['status' => 1], 'age > 30')->execute();
* ```
*
* or with using parameter binding for the condition:
*
* ```php
* $minAge = 30;
* $connection->createCommand()->update('user', ['status' => 1], 'age > :minAge', [':minAge' => $minAge])->execute();
* ```
*
* The method will properly escape the column names and bind the values to be updated.
*
* Note that the created command is not executed until [[execute()]] is called.
@ -498,6 +505,13 @@ class Command extends Component
* $connection->createCommand()->delete('user', 'status = 0')->execute();
* ```
*
* or with using parameter binding for the condition:
*
* ```php
* $status = 0;
* $connection->createCommand()->delete('user', 'status = :status', [':status' => $status])->execute();
* ```
*
* The method will properly escape the table and column names.
*
* Note that the created command is not executed until [[execute()]] is called.
@ -537,7 +551,7 @@ class Command extends Component
{
$sql = $this->db->getQueryBuilder()->createTable($table, $columns, $options);
return $this->setSql($sql);
return $this->setSql($sql)->requireTableSchemaRefresh($table);
}
/**
@ -680,7 +694,7 @@ class Command extends Component
{
$sql = $this->db->getQueryBuilder()->addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete, $update);
return $this->setSql($sql);
return $this->setSql($sql)->requireTableSchemaRefresh($table);
}
/**
@ -693,7 +707,7 @@ class Command extends Component
{
$sql = $this->db->getQueryBuilder()->dropForeignKey($name, $table);
return $this->setSql($sql);
return $this->setSql($sql)->requireTableSchemaRefresh($table);
}
/**
@ -771,7 +785,7 @@ class Command extends Component
{
$sql = $this->db->getQueryBuilder()->addCommentOnColumn($table, $column, $comment);
return $this->setSql($sql);
return $this->setSql($sql)->requireTableSchemaRefresh($table);
}
/**
@ -801,7 +815,7 @@ class Command extends Component
{
$sql = $this->db->getQueryBuilder()->dropCommentFromColumn($table, $column);
return $this->setSql($sql);
return $this->setSql($sql)->requireTableSchemaRefresh($table);
}
/**
@ -828,10 +842,7 @@ class Command extends Component
public function execute()
{
$sql = $this->getSql();
$rawSql = $this->getRawSql();
Yii::info($rawSql, __METHOD__);
list($profile, $rawSql) = $this->logQuery(__METHOD__);
if ($sql == '') {
return 0;
@ -839,21 +850,40 @@ class Command extends Component
$this->prepare(false);
$token = $rawSql;
try {
Yii::beginProfile($token, __METHOD__);
$profile and Yii::beginProfile($rawSql, __METHOD__);
$this->pdoStatement->execute();
$n = $this->pdoStatement->rowCount();
Yii::endProfile($token, __METHOD__);
$profile and Yii::endProfile($rawSql, __METHOD__);
$this->refreshTableSchema();
return $n;
} catch (\Exception $e) {
Yii::endProfile($token, __METHOD__);
throw $this->db->getSchema()->convertException($e, $rawSql);
$profile and Yii::endProfile($rawSql, __METHOD__);
throw $this->db->getSchema()->convertException($e, $rawSql ?: $this->getRawSql());
}
}
/**
* Logs the current database query if query logging is enabled and returns
* the profiling token if profiling is enabled.
* @param string $category the log category.
* @return array array of two elements, the first is boolean of whether profiling is enabled or not.
* The second is the rawSql if it has been created.
*/
private function logQuery($category)
{
if ($this->db->enableLogging) {
$rawSql = $this->getRawSql();
Yii::info($rawSql, $category);
}
if (!$this->db->enableProfiling) {
return [false, isset($rawSql) ? $rawSql : null];
} else {
return [true, isset($rawSql) ? $rawSql : $this->getRawSql()];
}
}
@ -868,9 +898,7 @@ class Command extends Component
*/
protected function queryInternal($method, $fetchMode = null)
{
$rawSql = $this->getRawSql();
Yii::info($rawSql, 'yii\db\Command::query');
list($profile, $rawSql) = $this->logQuery('yii\db\Command::query');
if ($method !== '') {
$info = $this->db->getQueryCacheInfo($this->queryCacheDuration, $this->queryCacheDependency);
@ -883,7 +911,7 @@ class Command extends Component
$fetchMode,
$this->db->dsn,
$this->db->username,
$rawSql,
$rawSql ?: $rawSql = $this->getRawSql(),
];
$result = $cache->get($cacheKey);
if (is_array($result) && isset($result[0])) {
@ -895,9 +923,8 @@ class Command extends Component
$this->prepare(true);
$token = $rawSql;
try {
Yii::beginProfile($token, 'yii\db\Command::query');
$profile and Yii::beginProfile($rawSql, 'yii\db\Command::query');
$this->pdoStatement->execute();
@ -911,10 +938,10 @@ class Command extends Component
$this->pdoStatement->closeCursor();
}
Yii::endProfile($token, 'yii\db\Command::query');
$profile and Yii::endProfile($rawSql, 'yii\db\Command::query');
} catch (\Exception $e) {
Yii::endProfile($token, 'yii\db\Command::query');
throw $this->db->getSchema()->convertException($e, $rawSql);
$profile and Yii::endProfile($rawSql, 'yii\db\Command::query');
throw $this->db->getSchema()->convertException($e, $rawSql ?: $this->getRawSql());
}
if (isset($cache, $cacheKey, $info)) {

35
framework/db/Connection.php

@ -156,7 +156,7 @@ class Connection extends Component
* Please refer to the [PHP manual](http://php.net/manual/en/pdo.construct.php) on
* the format of the DSN string.
*
* For [SQLite](http://php.net/manual/en/ref.pdo-sqlite.connection.php) you may use a path alias
* For [SQLite](http://php.net/manual/en/ref.pdo-sqlite.connection.php) you may use a [path alias](guide:concept-aliases)
* for specifying the database path, e.g. `sqlite:@app/data/db.sql`.
*
* @see charset
@ -373,6 +373,22 @@ class Connection extends Component
* @see masters
*/
public $shuffleMasters = true;
/**
* @var bool whether to enable logging of database queries. Defaults to true.
* You may want to disable this option in a production environment to gain performance
* if you do not need the information being logged.
* @since 2.0.12
* @see enableProfiling
*/
public $enableLogging = true;
/**
* @var bool whether to enable profiling of database queries. Defaults to true.
* You may want to disable this option in a production environment to gain performance
* if you do not need the information being logged.
* @since 2.0.12
* @see enableLogging
*/
public $enableProfiling = true;
/**
* @var Transaction the currently active transaction
@ -1065,4 +1081,21 @@ class Connection extends Component
$this->close();
return array_keys((array) $this);
}
/**
* Reset the connection after cloning.
*/
public function __clone()
{
parent::__clone();
$this->_master = false;
$this->_slave = false;
$this->_schema = null;
$this->_transaction = null;
if (strncmp($this->dsn, 'sqlite::memory:', 15) !== 0) {
// reset PDO connection, unless its sqlite in-memory, which can only have one connection
$this->pdo = null;
}
}
}

14
framework/db/Migration.php

@ -9,6 +9,7 @@ namespace yii\db;
use yii\base\Component;
use yii\di\Instance;
use yii\helpers\StringHelper;
/**
* Migration is the base class for representing a database migration.
@ -65,6 +66,12 @@ class Migration extends Component implements MigrationInterface
*/
public $db = 'db';
/**
* @var int max number of characters of the SQL outputted. Useful for reduction of long statements and making
* console output more compact.
* @since 2.0.13
*/
public $maxSqlOutputLength;
/**
* Initializes the migration.
@ -198,7 +205,12 @@ class Migration extends Component implements MigrationInterface
*/
public function execute($sql, $params = [])
{
echo " > execute SQL: $sql ...";
$sqlOutput = $sql;
if ($this->maxSqlOutputLength !== null) {
$sqlOutput = StringHelper::truncate($sql, $this->maxSqlOutputLength, '[... hidden]');
}
echo " > execute SQL: $sqlOutput ...";
$time = microtime(true);
$this->db->createCommand($sql)->bindValues($params)->execute();
echo ' done (time: ' . sprintf('%.3f', microtime(true) - $time) . "s)\n";

4
framework/db/Query.php

@ -413,18 +413,20 @@ class Query extends Component implements QueryInterface
&& empty($this->groupBy)
&& empty($this->having)
&& empty($this->union)
&& empty($this->orderBy)
) {
$select = $this->select;
$order = $this->orderBy;
$limit = $this->limit;
$offset = $this->offset;
$this->select = [$selectExpression];
$this->orderBy = null;
$this->limit = null;
$this->offset = null;
$command = $this->createCommand($db);
$this->select = $select;
$this->orderBy = $order;
$this->limit = $limit;
$this->offset = $offset;

3
framework/db/QueryBuilder.php

@ -82,6 +82,7 @@ class QueryBuilder extends \yii\base\Object
*/
protected $likeEscapeCharacter;
/**
* Constructor.
* @param Connection $connection the database connection.
@ -194,7 +195,7 @@ class QueryBuilder extends \yii\base\Object
* @param array $params the parameters to be bound to the generated SQL statement. These parameters will
* be included in the result with the additional parameters generated during the query building process.
* @return array
* @throws InvalidParamException if query's select does not contain named parameters only.
* @throws InvalidArgumentException if query's select does not contain named parameters only.
* @since 2.0.11
*/
protected function prepareInsertSelectSubQuery($columns, $schema, $params = [])

1
framework/db/cubrid/QueryBuilder.php

@ -57,6 +57,7 @@ class QueryBuilder extends \yii\db\QueryBuilder
'!' => '!!',
];
/**
* Creates a SQL statement for resetting the sequence value of a table's primary key.
* The sequence will be reset such that the primary key of the next new row inserted

12
framework/db/mssql/QueryBuilder.php

@ -56,6 +56,7 @@ class QueryBuilder extends \yii\db\QueryBuilder
'\\' => '[\\]',
];
/**
* @inheritdoc
*/
@ -185,7 +186,7 @@ class QueryBuilder extends \yii\db\QueryBuilder
* @param mixed $value the value for the primary key of the next new row inserted. If this is not set,
* the next new row's primary key will have a value 1.
* @return string the SQL statement for resetting sequence
* @throws InvalidParamException if the table does not exist or there is no sequence associated with the table.
* @throws InvalidArgumentException if the table does not exist or there is no sequence associated with the table.
*/
public function resetSequence($tableName, $value = null)
{
@ -201,9 +202,9 @@ class QueryBuilder extends \yii\db\QueryBuilder
return "DBCC CHECKIDENT ('{$tableName}', RESEED, {$value})";
} elseif ($table === null) {
throw new InvalidParamException("Table not found: $tableName");
throw new InvalidArgumentException("Table not found: $tableName");
} else {
throw new InvalidParamException("There is not sequence associated with table '$tableName'.");
throw new InvalidArgumentException("There is not sequence associated with table '$tableName'.");
}
}
@ -278,9 +279,8 @@ class QueryBuilder extends \yii\db\QueryBuilder
if (!$modelClass) {
return null;
}
/* @var $model \yii\db\ActiveRecord */
$model = new $modelClass;
$schema = $model->getTableSchema();
/* @var $modelClass \yii\db\ActiveRecord */
$schema = $modelClass::getTableSchema();
return array_keys($schema->columns);
}

56
framework/db/oci/QueryBuilder.php

@ -61,6 +61,7 @@ class QueryBuilder extends \yii\db\QueryBuilder
'!' => '!!',
];
/**
* @inheritdoc
*/
@ -331,4 +332,59 @@ EOD;
}
return parent::buildLikeCondition($operator, $operands, $params);
}
/**
* @inheritdoc
*/
public function buildInCondition($operator, $operands, &$params)
{
$splitCondition = $this->splitInCondition($operator, $operands, $params);
if ($splitCondition !== null) {
return $splitCondition;
}
return parent::buildInCondition($operator, $operands, $params);
}
/**
* Oracle DBMS does not support more than 1000 parameters in `IN` condition.
* This method splits long `IN` condition into series of smaller ones.
*
* @param string $operator
* @param array $operands
* @param array $params
* @return null|string null when split is not required. Otherwise - built SQL condition.
* @throws Exception
* @since 2.0.12
*/
protected function splitInCondition($operator, $operands, &$params)
{
if (!isset($operands[0], $operands[1])) {
throw new Exception("Operator '$operator' requires two operands.");
}
list($column, $values) = $operands;
if ($values instanceof \Traversable) {
$values = iterator_to_array($values);
}
if (!is_array($values)) {
return null;
}
$maxParameters = 1000;
$count = count($values);
if ($count <= $maxParameters) {
return null;
}
$condition = [($operator === 'IN') ? 'OR' : 'AND'];
for ($i = 0; $i < $count; $i += $maxParameters) {
$condition[] = [$operator, $column, array_slice($values, $i, $maxParameters)];
}
return $this->buildCondition(['AND', $condition], $params);
}
}

2
framework/db/pgsql/Schema.php

@ -16,8 +16,6 @@ use yii\db\ViewFinderTrait;
* Schema is the class for retrieving metadata from a PostgreSQL database
* (version 9.x and above).
*
* @property string[] $viewNames All view names in the database. This property is read-only.
*
* @author Gevik Babakhani <gevikb@gmail.com>
* @since 2.0
*/

1
framework/db/sqlite/QueryBuilder.php

@ -53,6 +53,7 @@ class QueryBuilder extends \yii\db\QueryBuilder
*/
protected $likeEscapeCharacter = '\\';
/**
* Generates a batch INSERT SQL statement.
* For example,

7
framework/di/Instance.php

@ -116,7 +116,12 @@ class Instance
$container = Yii::$container;
}
unset($reference['class']);
return $container->get($class, [], $reference);
$component = $container->get($class, [], $reference);
if ($type === null || $component instanceof $type) {
return $component;
} else {
throw new InvalidConfigException('Invalid data type: ' . $class .'. ' . $type . ' is expected.');
}
} elseif (empty($reference)) {
throw new InvalidConfigException('The required component is not specified.');
}

33
framework/filters/AccessControl.php

@ -57,8 +57,9 @@ use yii\web\User;
class AccessControl extends ActionFilter
{
/**
* @var User|array|string the user object representing the authentication status or the ID of the user application component.
* @var User|array|string|false the user object representing the authentication status or the ID of the user application component.
* Starting from version 2.0.2, this can also be a configuration array for creating the object.
* Starting from version 2.0.12, you can set it to `false` to explicitly switch this component support off for the filter.
*/
public $user = 'user';
/**
@ -88,6 +89,23 @@ class AccessControl extends ActionFilter
*/
public $rules = [];
/**
* Initializes the [[rules]] array by instantiating rule objects from configurations.
*/
public function init()
{
parent::init();
if ($this->user !== false) {
$this->user = Instance::ensure($this->user, User::class);
}
foreach ($this->rules as $i => $rule) {
if (is_array($rule)) {
$this->rules[$i] = Yii::createObject(array_merge($this->ruleConfig, $rule));
}
}
}
/**
* This method is invoked right before an action is to be executed (after all possible filters.)
* You may override this method to do last-minute preparation for the action.
@ -96,13 +114,10 @@ class AccessControl extends ActionFilter
*/
public function beforeAction($action)
{
$user = $this->user = Instance::ensure($this->user, User::class);
$user = $this->user;
$request = Yii::$app->getRequest();
/* @var $rule AccessRule */
foreach ($this->rules as $key => $rule) {
if (!is_object($rule)) {
$rule = $this->rules[$key] = Yii::createObject(array_merge($this->ruleConfig, $rule));
}
foreach ($this->rules as $rule) {
if ($allow = $rule->allows($action, $user, $request)) {
return true;
} elseif ($allow === false) {
@ -128,12 +143,12 @@ class AccessControl extends ActionFilter
* Denies the access of the user.
* The default implementation will redirect the user to the login page if he is a guest;
* if the user is already logged, a 403 HTTP exception will be thrown.
* @param User $user the current user
* @throws ForbiddenHttpException if the user is already logged in.
* @param User|false $user the current user or boolean `false` in case of detached User component
* @throws ForbiddenHttpException if the user is already logged in or in case of detached User component.
*/
protected function denyAccess($user)
{
if ($user->getIsGuest()) {
if ($user !== false && $user->getIsGuest()) {
$user->loginRequired();
} else {
throw new ForbiddenHttpException(Yii::t('yii', 'You are not allowed to perform this action.'));

88
framework/filters/AccessRule.php

@ -7,8 +7,10 @@
namespace yii\filters;
use Closure;
use yii\base\Component;
use yii\base\Action;
use yii\base\InvalidConfigException;
use yii\web\User;
use yii\web\Request;
use yii\base\Controller;
@ -41,11 +43,13 @@ class AccessRule extends Component
* The comparison is case-sensitive.
*
* If not set or empty, it means this rule applies to all controllers.
*
* Since version 2.0.12 controller IDs can be specified as wildcards, e.g. `module/*`.
*/
public $controllers;
/**
* @var array list of roles that this rule applies to. Two special roles are recognized, and
* they are checked via [[User::isGuest]]:
* @var array list of roles that this rule applies to (requires properly configured User component).
* Two special roles are recognized, and they are checked via [[User::isGuest]]:
*
* - `?`: matches a guest user (not authenticated yet)
* - `@`: matches an authenticated user
@ -54,9 +58,44 @@ class AccessRule extends Component
* In this case, [[User::can()]] will be called to check access.
*
* If this property is not set or empty, it means this rule applies to all roles.
* @see $roleParams
*/
public $roles;
/**
* @var array|Closure parameters to pass to the [[User::can()]] function for evaluating
* user permissions in [[$roles]].
*
* If this is an array, it will be passed directly to [[User::can()]]. For example for passing an
* ID from the current request, you may use the following:
*
* ```php
* ['postId' => Yii::$app->request->get('id')]
* ```
*
* You may also specify a closure that returns an array. This can be used to
* evaluate the array values only if they are needed, for example when a model needs to be
* loaded like in the following code:
*
* ```php
* 'rules' => [
* [
* 'allow' => true,
* 'actions' => ['update'],
* 'roles' => ['updatePost'],
* 'roleParams' => function($rule) {
* return ['post' => Post::findOne(Yii::$app->request->get('id'))];
* },
* ],
* ],
* ```
*
* A reference to the [[AccessRule]] instance will be passed to the closure as the first parameter.
*
* @see $roles
* @since 2.0.12
*/
public $roleParams = [];
/**
* @var array list of user IP addresses that this rule applies to. An IP address
* can contain the wildcard `*` at the end so that it matches IP addresses with the same prefix.
* For example, '192.168.*' matches all IP addresses in the segment '192.168.'.
@ -101,9 +140,9 @@ class AccessRule extends Component
/**
* Checks whether the Web user is allowed to perform the specified action.
* @param Action $action the action to be performed
* @param User $user the user object
* @param User|false $user the user object or `false` in case of detached User component
* @param Request $request
* @return bool|null true if the user is allowed, false if the user is denied, null if the rule does not apply to the user
* @return bool|null `true` if the user is allowed, `false` if the user is denied, `null` if the rule does not apply to the user
*/
public function allows($action, $user, $request)
{
@ -115,9 +154,9 @@ class AccessRule extends Component
&& $this->matchCustom($action)
) {
return $this->allow ? true : false;
} else {
return null;
}
return null;
}
/**
@ -135,18 +174,33 @@ class AccessRule extends Component
*/
protected function matchController($controller)
{
return empty($this->controllers) || in_array($controller->uniqueId, $this->controllers, true);
if (empty($this->controllers)) {
return true;
}
$id = $controller->getUniqueId();
foreach ($this->controllers as $pattern) {
if (fnmatch($pattern, $id)) {
return true;
}
}
return false;
}
/**
* @param User $user the user object
* @return bool whether the rule applies to the role
* @throws InvalidConfigException if User component is detached
*/
protected function matchRole($user)
{
if (empty($this->roles)) {
return true;
}
if ($user === false) {
throw new InvalidConfigException('The user application component must be available to specify roles in AccessRule.');
}
foreach ($this->roles as $role) {
if ($role === '?') {
if ($user->getIsGuest()) {
@ -156,8 +210,13 @@ class AccessRule extends Component
if (!$user->getIsGuest()) {
return true;
}
} elseif ($user->can($role)) {
return true;
} else {
if (!isset($roleParams)) {
$roleParams = $this->roleParams instanceof Closure ? call_user_func($this->roleParams, $this) : $this->roleParams;
}
if ($user->can($role, $roleParams)) {
return true;
}
}
}
@ -165,7 +224,7 @@ class AccessRule extends Component
}
/**
* @param string $ip the IP address
* @param string|null $ip the IP address
* @return bool whether the rule applies to the IP address
*/
protected function matchIP($ip)
@ -174,7 +233,14 @@ class AccessRule extends Component
return true;
}
foreach ($this->ips as $rule) {
if ($rule === '*' || $rule === $ip || (($pos = strpos($rule, '*')) !== false && !strncmp($ip, $rule, $pos))) {
if ($rule === '*' ||
$rule === $ip ||
(
$ip !== null &&
($pos = strpos($rule, '*')) !== false &&
strncmp($ip, $rule, $pos) === 0
)
) {
return true;
}
}

30
framework/filters/RateLimiter.php

@ -65,22 +65,34 @@ class RateLimiter extends ActionFilter
/**
* @inheritdoc
*/
public function init()
{
if ($this->request === null) {
$this->request = Yii::$app->getRequest();
}
if ($this->response === null) {
$this->response = Yii::$app->getResponse();
}
}
/**
* @inheritdoc
*/
public function beforeAction($action)
{
$user = $this->user ? : (Yii::$app->getUser() ? Yii::$app->getUser()->getIdentity(false) : null);
if ($user instanceof RateLimitInterface) {
if ($this->user === null && Yii::$app->getUser()) {
$this->user = Yii::$app->getUser()->getIdentity(false);
}
if ($this->user instanceof RateLimitInterface) {
Yii::trace('Check rate limit', __METHOD__);
$this->checkRateLimit(
$user,
$this->request ? : Yii::$app->getRequest(),
$this->response ? : Yii::$app->getResponse(),
$action
);
} elseif ($user) {
$this->checkRateLimit($this->user, $this->request, $this->response, $action);
} elseif ($this->user) {
Yii::info('Rate limit skipped: "user" does not implement RateLimitInterface.', __METHOD__);
} else {
Yii::info('Rate limit skipped: user not logged in.', __METHOD__);
}
return true;
}

2
framework/grid/ActionColumn.php

@ -189,7 +189,7 @@ class ActionColumn extends Column
* Creates a URL for the given action and model.
* This method is called for each button and each row.
* @param string $action the button name (or action ID)
* @param \yii\db\ActiveRecord $model the data model
* @param \yii\db\ActiveRecordInterface $model the data model
* @param mixed $key the key associated with the data model
* @param int $index the current row index
* @return string the created URL

2
framework/grid/GridView.php

@ -484,7 +484,7 @@ class GridView extends BaseListView
}
}
if (empty($rows)) {
if (empty($rows) && $this->emptyText !== false) {
$colspan = count($this->columns);
return "<tbody>\n<tr><td colspan=\"$colspan\">" . $this->renderEmpty() . "</td></tr>\n</tbody>";

22
framework/helpers/BaseFileHelper.php

@ -249,6 +249,10 @@ class BaseFileHelper
* - afterCopy: callback, a PHP callback that is called after each sub-directory or file is successfully copied.
* The signature of the callback should be: `function ($from, $to)`, where `$from` is the sub-directory or
* file copied from, while `$to` is the copy target.
* - copyEmptyDirectories: boolean, whether to copy empty directories. Set this to false to avoid creating directories
* that do not contain files. This affects directories that do not contain files initially as well as directories that
* do not contain files at the target destination because files have been filtered via `only` or `except`.
* Defaults to true. This option is available since version 2.0.12. Before 2.0.12 empty directories are always copied.
* @throws \yii\base\InvalidArgumentException if unable to open directory
*/
public static function copyDirectory($src, $dst, $options = [])
@ -259,8 +263,10 @@ class BaseFileHelper
if ($src === $dst || strpos($dst, $src . DIRECTORY_SEPARATOR) === 0) {
throw new InvalidArgumentException('Trying to copy a directory to itself or a subdirectory.');
}
if (!is_dir($dst)) {
$dstExists = is_dir($dst);
if (!$dstExists && (!isset($options['copyEmptyDirectories']) || $options['copyEmptyDirectories'])) {
static::createDirectory($dst, isset($options['dirMode']) ? $options['dirMode'] : 0775, true);
$dstExists = true;
}
$handle = opendir($src);
@ -270,7 +276,7 @@ class BaseFileHelper
if (!isset($options['basePath'])) {
// this should be done only once
$options['basePath'] = realpath($src);
$options = self::normalizeOptions($options);
$options = static::normalizeOptions($options);
}
while (($file = readdir($handle)) !== false) {
if ($file === '.' || $file === '..') {
@ -283,6 +289,11 @@ class BaseFileHelper
continue;
}
if (is_file($from)) {
if (!$dstExists) {
// delay creation of destination directory until the first file is copied to avoid creating empty directories
static::createDirectory($dst, isset($options['dirMode']) ? $options['dirMode'] : 0775, true);
$dstExists = true;
}
copy($from, $to);
if (isset($options['fileMode'])) {
@chmod($to, $options['fileMode']);
@ -372,7 +383,7 @@ class BaseFileHelper
* If the pattern does not contain a slash (`/`), it is treated as a shell glob pattern
* and checked for a match against the pathname relative to `$dir`.
* Otherwise, the pattern is treated as a shell glob suitable for consumption by `fnmatch(3)`
* `with the `FNM_PATHNAME` flag: wildcards in the pattern will not match a `/` in the pathname.
* with the `FNM_PATHNAME` flag: wildcards in the pattern will not match a `/` in the pathname.
* For example, `views/*.php` matches `views/index.php` but not `views/controller/index.php`.
* A leading slash matches the beginning of the pathname. For example, `/*.php` matches `index.php` but not `views/start/index.php`.
* An optional prefix `!` which negates the pattern; any matching file excluded by a previous pattern will become included again.
@ -396,7 +407,7 @@ class BaseFileHelper
if (!isset($options['basePath'])) {
// this should be done only once
$options['basePath'] = realpath($dir);
$options = self::normalizeOptions($options);
$options = static::normalizeOptions($options);
}
$list = [];
$handle = opendir($dir);
@ -698,8 +709,9 @@ class BaseFileHelper
/**
* @param array $options raw options
* @return array normalized options
* @since 2.0.12
*/
private static function normalizeOptions(array $options)
protected static function normalizeOptions(array $options)
{
if (!array_key_exists('caseSensitive', $options)) {
$options['caseSensitive'] = true;

1
framework/helpers/BaseHtml.php

@ -24,7 +24,6 @@ use yii\base\Model;
*/
class BaseHtml
{
/**
* @var string Regular expression used for attribute name validation.
* @since 2.0.12

36
framework/i18n/Formatter.php

@ -86,6 +86,9 @@ class Formatter extends Component
*
* It defaults to `UTC` so you only have to adjust this value if you store datetime values in another time zone in your database.
*
* Note that a UNIX timestamp is always in UTC by its definition. That means that specifying a default time zone different from
* UTC has no effect on date values given as UNIX timestamp.
*
* @since 2.0.1
*/
public $defaultTimeZone = 'UTC';
@ -183,7 +186,7 @@ class Formatter extends Component
public $thousandSeparator;
/**
* @var array a list of name value pairs that are passed to the
* intl [Numberformatter::setAttribute()](http://php.net/manual/en/numberformatter.setattribute.php) method of all
* intl [NumberFormatter::setAttribute()](http://php.net/manual/en/numberformatter.setattribute.php) method of all
* the number formatter objects created by [[createNumberFormatter()]].
* This property takes only effect if the [PHP intl extension](http://php.net/manual/en/book.intl.php) is installed.
*
@ -202,7 +205,7 @@ class Formatter extends Component
public $numberFormatterOptions = [];
/**
* @var array a list of name value pairs that are passed to the
* intl [Numberformatter::setTextAttribute()](http://php.net/manual/en/numberformatter.settextattribute.php) method of all
* intl [NumberFormatter::setTextAttribute()](http://php.net/manual/en/numberformatter.settextattribute.php) method of all
* the number formatter objects created by [[createNumberFormatter()]].
* This property takes only effect if the [PHP intl extension](http://php.net/manual/en/book.intl.php) is installed.
*
@ -220,7 +223,7 @@ class Formatter extends Component
public $numberFormatterTextOptions = [];
/**
* @var array a list of name value pairs that are passed to the
* intl [Numberformatter::setSymbol()](http://php.net/manual/en/numberformatter.setsymbol.php) method of all
* intl [NumberFormatter::setSymbol()](http://php.net/manual/en/numberformatter.setsymbol.php) method of all
* the number formatter objects created by [[createNumberFormatter()]].
* This property takes only effect if the [PHP intl extension](http://php.net/manual/en/book.intl.php) is installed.
*
@ -466,10 +469,15 @@ class Formatter extends Component
* @param int|string|DateTime $value the value to be formatted. The following
* types of value are supported:
*
* - an integer representing a UNIX timestamp
* - an integer representing a UNIX timestamp. A UNIX timestamp is always in UTC by its definition.
* - a string that can be [parsed to create a DateTime object](http://php.net/manual/en/datetime.formats.php).
* The timestamp is assumed to be in [[defaultTimeZone]] unless a time zone is explicitly given.
* - a PHP [DateTime](http://php.net/manual/en/class.datetime.php) object
* - a PHP [DateTime](http://php.net/manual/en/class.datetime.php) object. You may set the time zone
* for the DateTime object to specify the source time zone.
*
* The formatter will convert date values according to [[timeZone]] before formatting it.
* If no timezone conversion should be performed, you need to set [[defaultTimeZone]] and [[timeZone]] to the same value.
* Also no conversion will be performed on values that have no time information, e.g. `"2017-06-05"`.
*
* @param string $format the format used to convert the value into a date string.
* If null, [[dateFormat]] will be used.
@ -498,10 +506,14 @@ class Formatter extends Component
* @param int|string|DateTime $value the value to be formatted. The following
* types of value are supported:
*
* - an integer representing a UNIX timestamp
* - an integer representing a UNIX timestamp. A UNIX timestamp is always in UTC by its definition.
* - a string that can be [parsed to create a DateTime object](http://php.net/manual/en/datetime.formats.php).
* The timestamp is assumed to be in [[defaultTimeZone]] unless a time zone is explicitly given.
* - a PHP [DateTime](http://php.net/manual/en/class.datetime.php) object
* - a PHP [DateTime](http://php.net/manual/en/class.datetime.php) object. You may set the time zone
* for the DateTime object to specify the source time zone.
*
* The formatter will convert date values according to [[timeZone]] before formatting it.
* If no timezone conversion should be performed, you need to set [[defaultTimeZone]] and [[timeZone]] to the same value.
*
* @param string $format the format used to convert the value into a date string.
* If null, [[timeFormat]] will be used.
@ -530,10 +542,14 @@ class Formatter extends Component
* @param int|string|DateTime $value the value to be formatted. The following
* types of value are supported:
*
* - an integer representing a UNIX timestamp
* - an integer representing a UNIX timestamp. A UNIX timestamp is always in UTC by its definition.
* - a string that can be [parsed to create a DateTime object](http://php.net/manual/en/datetime.formats.php).
* The timestamp is assumed to be in [[defaultTimeZone]] unless a time zone is explicitly given.
* - a PHP [DateTime](http://php.net/manual/en/class.datetime.php) object
* - a PHP [DateTime](http://php.net/manual/en/class.datetime.php) object. You may set the time zone
* for the DateTime object to specify the source time zone.
*
* The formatter will convert date values according to [[timeZone]] before formatting it.
* If no timezone conversion should be performed, you need to set [[defaultTimeZone]] and [[timeZone]] to the same value.
*
* @param string $format the format used to convert the value into a date string.
* If null, [[dateFormat]] will be used.
@ -656,7 +672,7 @@ class Formatter extends Component
* whether the timestamp has date information.
* This parameter is available since version 2.0.1.
* @return DateTime|array the normalized datetime value.
* Since version 2.0.1 this may also return an array if `$checkTimeInfo` is true.
* Since version 2.0.1 this may also return an array if `$checkDateTimeInfo` is true.
* The first element of the array is the normalized timestamp and the second is a boolean indicating whether
* the timestamp has time information or it is just a date value.
* Since version 2.0.12 the array has third boolean element indicating whether the timestamp has date information

6
framework/log/DbTarget.php

@ -60,6 +60,12 @@ class DbTarget extends Target
*/
public function export()
{
if ($this->db->getTransaction()) {
// create new database connection, if there is an open transaction
// to ensure insert statement is not affected by a rollback
$this->db = clone $this->db;
}
$tableName = $this->db->quoteTableName($this->logTable);
$sql = "INSERT INTO $tableName ([[level]], [[category]], [[log_time]], [[prefix]], [[message]])
VALUES (:level, :category, :log_time, :prefix, :message)";

2
framework/log/FileTarget.php

@ -26,7 +26,7 @@ use yii\helpers\FileHelper;
class FileTarget extends Target
{
/**
* @var string log file path or path alias. If not set, it will use the "@runtime/logs/app.log" file.
* @var string log file path or [path alias](guide:concept-aliases). If not set, it will use the "@runtime/logs/app.log" file.
* The directory containing the log files will be automatically created if not existing.
*/
public $logFile;

24
framework/log/Logger.php

@ -281,20 +281,22 @@ class Logger extends Component
list($token, $level, $category, $timestamp, $traces) = $log;
$memory = isset($log[5]) ? $log[5] : 0;
$log[6] = $i;
$hash = md5(serialize($token));
if ($level == Logger::LEVEL_PROFILE_BEGIN) {
$stack[] = $log;
} elseif ($level == self::LEVEL_PROFILE_END) {
if (($last = array_pop($stack)) !== null && $last[0] === $token) {
$timings[$last[6]] = [
'info' => $last[0],
'category' => $last[2],
'timestamp' => $last[3],
'trace' => $last[4],
'level' => count($stack),
'duration' => $timestamp - $last[3],
$stack[$hash] = $log;
} elseif ($level == Logger::LEVEL_PROFILE_END) {
if (isset($stack[$hash])) {
$timings[$stack[$hash][6]] = [
'info' => $stack[$hash][0],
'category' => $stack[$hash][2],
'timestamp' => $stack[$hash][3],
'trace' => $stack[$hash][4],
'level' => count($stack) - 1,
'duration' => $timestamp - $stack[$hash][3],
'memory' => $memory,
'memoryDiff' => $memory - (isset($last[5]) ? $last[5] : 0),
'memoryDiff' => $memory - (isset($stack[$hash][5]) ? $stack[$hash][5] : 0),
];
unset($stack[$hash]);
}
}
}

10
framework/mail/BaseMailer.php

@ -47,7 +47,7 @@ abstract class BaseMailer extends Component implements MailerInterface, ViewCont
* The property can take the following values:
*
* - a relative view name: a view file relative to [[viewPath]], e.g., 'layouts/html'.
* - a path alias: an absolute view file path specified as a path alias, e.g., '@app/mail/html'.
* - a [path alias](guide:concept-aliases): an absolute view file path specified as a path alias, e.g., '@app/mail/html'.
* - a boolean false: the layout is disabled.
*/
public $htmlLayout = 'layouts/html';
@ -155,7 +155,7 @@ abstract class BaseMailer extends Component implements MailerInterface, ViewCont
*
* @param string|array|null $view the view to be used for rendering the message body. This can be:
*
* - a string, which represents the view name or path alias for rendering the HTML body of the email.
* - a string, which represents the view name or [path alias](guide:concept-aliases) for rendering the HTML body of the email.
* In this case, the text body will be generated by applying `strip_tags()` to the HTML body.
* - an array with 'html' and/or 'text' elements. The 'html' element refers to the view name or path alias
* for rendering the HTML body, while 'text' element is for rendering the text body. For example,
@ -291,9 +291,9 @@ abstract class BaseMailer extends Component implements MailerInterface, ViewCont
/**
* Renders the specified view with optional parameters and layout.
* The view will be rendered using the [[view]] component.
* @param string $view the view name or the path alias of the view file.
* @param string $view the view name or the [path alias](guide:concept-aliases) of the view file.
* @param array $params the parameters (name-value pairs) that will be extracted and made available in the view file.
* @param string|bool $layout layout view name or path alias. If false, no layout will be applied.
* @param string|bool $layout layout view name or [path alias](guide:concept-aliases). If false, no layout will be applied.
* @return string the rendering result.
*/
public function render($view, $params = [], $layout = false)
@ -359,7 +359,7 @@ abstract class BaseMailer extends Component implements MailerInterface, ViewCont
/**
* @param string $path the directory that contains the view files for composing mail messages
* This can be specified as an absolute path or a path alias.
* This can be specified as an absolute path or a [path alias](guide:concept-aliases).
*/
public function setViewPath($path)
{

2
framework/mail/MailerInterface.php

@ -33,7 +33,7 @@ interface MailerInterface
*
* @param string|array|null $view the view to be used for rendering the message body. This can be:
*
* - a string, which represents the view name or path alias for rendering the HTML body of the email.
* - a string, which represents the view name or [path alias](guide:concept-aliases) for rendering the HTML body of the email.
* In this case, the text body will be generated by applying `strip_tags()` to the HTML body.
* - an array with 'html' and/or 'text' elements. The 'html' element refers to the view name or path alias
* for rendering the HTML body, while 'text' element is for rendering the text body. For example,

1
framework/messages/el/yii.php

@ -17,6 +17,7 @@
* NOTE: this file must be saved in UTF-8 encoding.
*/
return [
' and ' => ' και ',
'(not set)' => '(μη ορισμένο)',
'An internal server error occurred.' => 'Υπήρξε ένα εσωτερικό σφάλμα του διακομιστή.',
'Are you sure you want to delete this item?' => 'Είστε σίγουροι για τη διαγραφή του αντικειμένου;',

2
framework/messages/sk/yii.php

@ -79,7 +79,7 @@ return [
'{attribute} must be a string.' => '{attribute} musí byť reťazec.',
'{attribute} must be a valid IP address.' => '{attribute} musí byť platná IP adresa.',
'{attribute} must be an IP address with specified subnet.' => '{attribute} musí byť IP adresa so špecifikovanou podsieťou.',
'{attribute} must be an integer.' => '{attribute} musí byť integer.',
'{attribute} must be an integer.' => '{attribute} musí byť celé číslo.',
'{attribute} must be either "{true}" or "{false}".' => '{attribute} musí byť "{true}" alebo "{false}".',
'{attribute} must be equal to "{compareValueOrAttribute}".' => '{attribute} musí byť "{compareValueOrAttribute}".',
'{attribute} must be greater than "{compareValueOrAttribute}".' => '{attribute} musí byť väčšie ako "{compareValueOrAttribute}".',

2
framework/mutex/FileMutex.php

@ -41,7 +41,7 @@ use yii\helpers\FileHelper;
class FileMutex extends Mutex
{
/**
* @var string the directory to store mutex files. You may use path alias here.
* @var string the directory to store mutex files. You may use [path alias](guide:concept-aliases) here.
* Defaults to the "mutex" subdirectory under the application runtime path.
*/
public $mutexPath = '@runtime/mutex';

5
framework/rbac/BaseManager.php

@ -16,6 +16,9 @@ use yii\base\InvalidArgumentException;
*
* For more details and usage information on DbManager, see the [guide article on security authorization](guide:security-authorization).
*
* @property Role[] $defaultRoleInstances Default roles. The array is indexed by the role names. This property
* is read-only.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
@ -194,7 +197,7 @@ abstract class BaseManager extends Component implements ManagerInterface
* @since 2.0.12
* @return Role[] default roles. The array is indexed by the role names
*/
public function getDefaultRoles()
public function getDefaultRoleInstances()
{
$result = [];
foreach ($this->defaultRoles as $roleName) {

6
framework/rbac/DbManager.php

@ -436,7 +436,7 @@ class DbManager extends BaseManager
{
$class = $row['type'] == Item::TYPE_PERMISSION ? Permission::class : Role::class;
if (!isset($row['data']) || ($data = @unserialize($row['data'])) === false) {
if (!isset($row['data']) || ($data = @unserialize(is_resource($row['data']) ? stream_get_contents($row['data']) : $row['data'])) === false) {
$data = null;
}
@ -466,7 +466,7 @@ class DbManager extends BaseManager
->andWhere(['a.user_id' => (string) $userId])
->andWhere(['b.type' => Item::TYPE_ROLE]);
$roles = $this->getDefaultRoles();
$roles = $this->getDefaultRoleInstances();
foreach ($query->all($this->db) as $row) {
$roles[$row['name']] = $this->populateItem($row);
}
@ -1008,7 +1008,7 @@ class DbManager extends BaseManager
/**
* Returns all role assignment information for the specified role.
* @param string $roleName
* @return Assignment[] the assignments. An empty array will be
* @return string[] the ids. An empty array will be
* returned if role is not assigned to any user.
* @since 2.0.7
*/

8
framework/rbac/PhpManager.php

@ -38,7 +38,7 @@ class PhpManager extends BaseManager
{
/**
* @var string the path of the PHP script that contains the authorization items.
* This can be either a file path or a path alias to the file.
* This can be either a file path or a [path alias](guide:concept-aliases) to the file.
* Make sure this file is writable by the Web server process if the authorization needs to be changed online.
* @see loadFromFile()
* @see saveToFile()
@ -46,7 +46,7 @@ class PhpManager extends BaseManager
public $itemFile = '@app/rbac/items.php';
/**
* @var string the path of the PHP script that contains the authorization assignments.
* This can be either a file path or a path alias to the file.
* This can be either a file path or a [path alias](guide:concept-aliases) to the file.
* Make sure this file is writable by the Web server process if the authorization needs to be changed online.
* @see loadFromFile()
* @see saveToFile()
@ -54,7 +54,7 @@ class PhpManager extends BaseManager
public $assignmentFile = '@app/rbac/assignments.php';
/**
* @var string the path of the PHP script that contains the authorization rules.
* This can be either a file path or a path alias to the file.
* This can be either a file path or a [path alias](guide:concept-aliases) to the file.
* Make sure this file is writable by the Web server process if the authorization needs to be changed online.
* @see loadFromFile()
* @see saveToFile()
@ -393,7 +393,7 @@ class PhpManager extends BaseManager
*/
public function getRolesByUser($userId)
{
$roles = $this->getDefaultRoles();
$roles = $this->getDefaultRoleInstances();
foreach ($this->getAssignments($userId) as $name => $assignment) {
$role = $this->items[$assignment->roleName];
if ($role->type === Item::TYPE_ROLE) {

25
framework/rest/UrlRule.php

@ -11,6 +11,8 @@ use Yii;
use yii\base\InvalidConfigException;
use yii\helpers\Inflector;
use yii\web\CompositeUrlRule;
use yii\web\UrlRule as WebUrlRule;
use yii\web\UrlRuleInterface;
/**
* UrlRule is provided to simplify the creation of URL rules for RESTful API support.
@ -187,7 +189,7 @@ class UrlRule extends CompositeUrlRule
* @param string $pattern
* @param string $prefix
* @param string $action
* @return \yii\web\UrlRuleInterface
* @return UrlRuleInterface
*/
protected function createRule($pattern, $prefix, $action)
{
@ -204,7 +206,7 @@ class UrlRule extends CompositeUrlRule
$config['pattern'] = rtrim($prefix . '/' . strtr($pattern, $this->tokens), '/');
$config['route'] = $action;
if (!empty($verbs) && !in_array('GET', $verbs)) {
$config['mode'] = \yii\web\UrlRule::PARSING_ONLY;
$config['mode'] = WebUrlRule::PARSING_ONLY;
}
$config['suffix'] = $this->suffix;
@ -220,7 +222,7 @@ class UrlRule extends CompositeUrlRule
foreach ($this->rules as $urlName => $rules) {
if (strpos($pathInfo, $urlName) !== false) {
foreach ($rules as $rule) {
/* @var $rule \yii\web\UrlRule */
/* @var $rule WebUrlRule */
$result = $rule->parseRequest($manager, $request);
if (YII_DEBUG) {
Yii::trace([
@ -244,17 +246,24 @@ class UrlRule extends CompositeUrlRule
*/
public function createUrl($manager, $route, $params)
{
$this->createStatus = WebUrlRule::CREATE_STATUS_SUCCESS;
foreach ($this->controller as $urlName => $controller) {
if (strpos($route, $controller) !== false) {
foreach ($this->rules[$urlName] as $rule) {
/* @var $rule \yii\web\UrlRule */
if (($url = $rule->createUrl($manager, $route, $params)) !== false) {
return $url;
}
/* @var $rules UrlRuleInterface[] */
$rules = $this->rules[$urlName];
$url = $this->iterateRules($rules, $manager, $route, $params);
if ($url !== false) {
return $url;
}
} else {
$this->createStatus |= WebUrlRule::CREATE_STATUS_ROUTE_MISMATCH;
}
}
if ($this->createStatus === WebUrlRule::CREATE_STATUS_SUCCESS) {
// create status was not changed - there is no rules configured
$this->createStatus = WebUrlRule::CREATE_STATUS_PARSING_ONLY;
}
return false;
}
}

12
framework/test/ActiveFixture.php

@ -40,7 +40,7 @@ class ActiveFixture extends BaseActiveFixture
*/
public $tableName;
/**
* @var string|bool the file path or path alias of the data file that contains the fixture data
* @var string|bool the file path or [path alias](guide:concept-aliases) of the data file that contains the fixture data
* to be returned by [[getData()]]. If this is not set, it will default to `FixturePath/data/TableName.php`,
* where `FixturePath` stands for the directory containing this fixture class, and `TableName` stands for the
* name of the table associated with this fixture. You can set this property to be false to prevent loading any data.
@ -75,7 +75,6 @@ class ActiveFixture extends BaseActiveFixture
*/
public function load()
{
$this->resetTable();
$this->data = [];
$table = $this->getTableSchema();
foreach ($this->getData() as $alias => $row) {
@ -107,6 +106,15 @@ class ActiveFixture extends BaseActiveFixture
}
/**
* @inheritdoc
*/
public function unload()
{
$this->resetTable();
parent::unload();
}
/**
* Removes all existing data from the specified table and resets sequence number to 1 (if any).
* This method is called before populating fixture data into the table associated with this fixture.
*/

2
framework/test/ArrayFixture.php

@ -28,7 +28,7 @@ class ArrayFixture extends Fixture implements \IteratorAggregate, \ArrayAccess,
*/
public $data = [];
/**
* @var string|bool the file path or path alias of the data file that contains the fixture data
* @var string|bool the file path or [path alias](guide:concept-aliases) of the data file that contains the fixture data
* to be returned by [[getData()]]. You can set this property to be false to prevent loading any data.
*/
public $dataFile;

6
framework/test/BaseActiveFixture.php

@ -32,7 +32,7 @@ abstract class BaseActiveFixture extends DbFixture implements \IteratorAggregate
*/
public $data = [];
/**
* @var string|bool the file path or path alias of the data file that contains the fixture data
* @var string|bool the file path or [path alias](guide:concept-aliases) of the data file that contains the fixture data
* to be returned by [[getData()]]. You can set this property to be false to prevent loading any data.
*/
public $dataFile;
@ -65,10 +65,8 @@ abstract class BaseActiveFixture extends DbFixture implements \IteratorAggregate
$row = $this->data[$name];
/* @var $modelClass \yii\db\ActiveRecord */
$modelClass = $this->modelClass;
/* @var $model \yii\db\ActiveRecord */
$model = new $modelClass;
$keys = [];
foreach ($model->primaryKey() as $key) {
foreach ($modelClass::primaryKey() as $key) {
$keys[$key] = isset($row[$key]) ? $row[$key] : null;
}

10
framework/test/FixtureTrait.php

@ -125,6 +125,16 @@ trait FixtureTrait
}
/**
* Initialize the fixtures
* @since 2.0.12
*/
public function initFixtures()
{
$this->unloadFixtures();
$this->loadFixtures();
}
/**
* Returns the fixture objects as specified in [[globalFixtures()]] and [[fixtures()]].
* @return Fixture[] the loaded fixtures for the current test case
*/

2
framework/test/InitDbFixture.php

@ -30,7 +30,7 @@ class InitDbFixture extends DbFixture
{
/**
* @var string the init script file that should be executed when loading this fixture.
* This should be either a file path or path alias. Note that if the file does not exist,
* This should be either a file path or [path alias](guide:concept-aliases). Note that if the file does not exist,
* no error will be raised.
*/
public $initScript = '@app/tests/fixtures/initdb.php';

7
framework/validators/DateValidator.php

@ -266,6 +266,13 @@ class DateValidator extends Validator
public function validateAttribute($model, $attribute)
{
$value = $model->$attribute;
if ($this->isEmpty($value)) {
if ($this->timestampAttribute !== null) {
$model->{$this->timestampAttribute} = null;
}
return;
}
$timestamp = $this->parseDateValue($value);
if ($timestamp === false) {
if ($this->timestampAttribute === $attribute) {

63
framework/validators/ExistValidator.php

@ -9,6 +9,9 @@ namespace yii\validators;
use Yii;
use yii\base\InvalidConfigException;
use yii\base\Model;
use yii\db\ActiveQuery;
use yii\db\ActiveRecord;
/**
* ExistValidator validates that the attribute value exists in a table.
@ -137,14 +140,28 @@ class ExistValidator extends Validator
if ($this->allowArray) {
throw new InvalidConfigException('The "targetAttribute" property must be configured as a string.');
}
$params = [];
$conditions = [];
foreach ($targetAttribute as $k => $v) {
$params[$v] = is_int($k) ? $model->$v : $model->$k;
$conditions[$v] = is_int($k) ? $model->$v : $model->$k;
}
} else {
$params = [$targetAttribute => $model->$attribute];
$conditions = [$targetAttribute => $model->$attribute];
}
return $params;
if (!$model instanceof ActiveRecord) {
return $conditions;
}
return $this->prefixConditions($model, $conditions);
}
/**
* @param Model $model the data model to be validated
* @return string Target class name
*/
private function getTargetClass($model)
{
return $this->targetClass === null ? get_class($model) : $this->targetClass;
}
/**
@ -189,4 +206,42 @@ class ExistValidator extends Validator
return $query;
}
/**
* Returns conditions with alias
* @param ActiveQuery $query
* @param array $conditions array of condition, keys to be modified
* @param null|string $alias set empty string for no apply alias. Set null for apply primary table alias
* @return array
*/
private function applyTableAlias($query, $conditions, $alias = null)
{
if ($alias === null) {
$alias = array_keys($query->getTablesUsedInFrom())[0];
}
$prefixedConditions = [];
foreach ($conditions as $columnName => $columnValue) {
$prefixedColumn = "{$alias}.[[" . preg_replace(
'/^' . preg_quote($alias) . '\.(.*)$/',
"$1",
$columnName) . "]]";
$prefixedConditions[$prefixedColumn] = $columnValue;
}
return $prefixedConditions;
}
/**
* Prefix conditions with aliases
*
* @param ActiveRecord $model
* @param array $conditions
* @return array
*/
private function prefixConditions($model, $conditions)
{
$targetModelClass = $this->getTargetClass($model);
/** @var ActiveRecord $targetModelClass */
return $this->applyTableAlias($targetModelClass::find(), $conditions);
}
}

3
framework/validators/StringValidator.php

@ -159,6 +159,9 @@ class StringValidator extends Validator
return 'yii.validation.string(value, messages, ' . json_encode($options, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . ');';
}
/**
* @inheritdoc
*/
public function getClientOptions($model, $attribute)
{
$label = $model->getAttributeLabel($attribute);

52
framework/validators/UniqueValidator.php

@ -180,7 +180,8 @@ class UniqueValidator extends Validator
// if current $model is in the database already we can't use exists()
if ($query instanceof \yii\db\ActiveQuery) {
// only select primary key to optimize query
$query->select($targetClass::primaryKey());
$columnsCondition = array_flip($targetClass::primaryKey());
$query->select(array_flip($this->applyTableAlias($query, $columnsCondition)));
}
$models = $query->limit(2)->asArray()->all();
$n = count($models);
@ -254,16 +255,7 @@ class UniqueValidator extends Validator
return $conditions;
}
// Add table prefix for column
$targetClass = $this->getTargetClass($model);
$tableName = $targetClass::tableName();
$conditionsWithTableName = [];
foreach ($conditions as $columnName => $columnValue) {
$prefixedColumnName = "{$tableName}.$columnName";
$conditionsWithTableName[$prefixedColumnName] = $columnValue;
}
return $conditionsWithTableName;
return $this->prefixConditions($model, $conditions);
}
/**
@ -289,4 +281,42 @@ class UniqueValidator extends Validator
'values' => implode('-', $valueCombo)
]);
}
/**
* Returns conditions with alias
* @param ActiveQuery $query
* @param array $conditions array of condition, keys to be modified
* @param null|string $alias set empty string for no apply alias. Set null for apply primary table alias
* @return array
*/
private function applyTableAlias($query, $conditions, $alias = null)
{
if ($alias === null) {
$alias = array_keys($query->getTablesUsedInFrom())[0];
}
$prefixedConditions = [];
foreach ($conditions as $columnName => $columnValue) {
$prefixedColumn = "{$alias}.[[" . preg_replace(
'/^' . preg_quote($alias) . '\.(.*)$/',
"$1",
$columnName) . "]]";
$prefixedConditions[$prefixedColumn] = $columnValue;
}
return $prefixedConditions;
}
/**
* Prefix conditions with aliases
*
* @param ActiveRecord $model
* @param array $conditions
* @return array
*/
private function prefixConditions($model, $conditions)
{
$targetModelClass = $this->getTargetClass($model);
/** @var ActiveRecord $targetModelClass */
return $this->applyTableAlias($targetModelClass::find(), $conditions);
}
}

26
framework/validators/Validator.php

@ -49,6 +49,8 @@ use yii\captcha\CaptchaValidator;
*
* For more details and usage information on Validator, see the [guide article on validators](guide:input-validation).
*
* @property array $attributeNames Attribute names. This property is read-only.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
@ -103,11 +105,6 @@ class Validator extends Component
*/
public $attributes = [];
/**
* @var array cleaned attribute names. Contains attribute names without `!` character at the beginning
* @since 2.0.12
*/
private $_attributeNames = [];
/**
* @var string the user-defined error message. It may contain the following placeholders which
* will be replaced accordingly by the validator:
*
@ -239,7 +236,6 @@ class Validator extends Component
$this->attributes = (array) $this->attributes;
$this->on = (array) $this->on;
$this->except = (array) $this->except;
$this->setAttributeNames((array)$this->attributes);
}
/**
@ -357,7 +353,7 @@ class Validator extends Component
* @param string $attribute the name of the attribute to be validated.
* @param \yii\web\View $view the view object that is going to be used to render views or view files
* containing a model form with this validator applied.
* @return string the client-side validation script. Null if the validator does not support
* @return string|null the client-side validation script. Null if the validator does not support
* client-side validation.
* @see getClientOptions()
* @see \yii\widgets\ActiveForm::enableClientValidation
@ -460,23 +456,13 @@ class Validator extends Component
/**
* Returns cleaned attribute names without the `!` character at the beginning
* @return array
* @return array attribute names.
* @since 2.0.12
*/
public function getAttributeNames()
{
return $this->_attributeNames;
}
/**
* Saves attribute names without `!` character at the beginning
* @param array $attributeNames
* @since 2.0.12
*/
private function setAttributeNames($attributeNames)
{
$this->_attributeNames = array_map(function($attribute) {
return array_map(function($attribute) {
return ltrim($attribute, '!');
}, $attributeNames);
}, $this->attributes);
}
}

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

Loading…
Cancel
Save