Browse Source

Merge branch 'master' of github.com:yiisoft/yii2

tags/2.0.2
Paul Klimov 10 years ago
parent
commit
c745e4166e
  1. 5
      apps/advanced/common/models/User.php
  2. 1
      apps/advanced/console/migrations/m130524_201442_init.php
  3. 5
      apps/advanced/frontend/models/SignupForm.php
  4. 4
      apps/advanced/frontend/widgets/Alert.php
  5. 48
      apps/basic/tests/README.md
  6. 20
      apps/basic/tests/codeception.yml
  7. 91
      build/controllers/ReleaseController.php
  8. 25
      docs/guide-es/README.md
  9. 291
      docs/guide-es/concept-events.md
  10. 470
      docs/guide-es/db-query-builder.md
  11. 377
      docs/guide-es/helper-html.md
  12. 156
      docs/guide-es/helper-url.md
  13. 99
      docs/guide-es/output-theming.md
  14. 72
      docs/guide-ja/README.md
  15. 126
      docs/guide-ja/concept-aliases.md
  16. 88
      docs/guide-ja/concept-autoloading.md
  17. 332
      docs/guide-ja/concept-behaviors.md
  18. 90
      docs/guide-ja/concept-components.md
  19. 260
      docs/guide-ja/concept-configurations.md
  20. 326
      docs/guide-ja/concept-di-container.md
  21. 279
      docs/guide-ja/concept-events.md
  22. 77
      docs/guide-ja/concept-properties.md
  23. 83
      docs/guide-ja/concept-service-locator.md
  24. 1000
      docs/guide-ja/db-active-record.md
  25. 4
      docs/guide-ja/db-dao.md
  26. 6
      docs/guide-ja/db-elasticsearch.md
  27. 361
      docs/guide-ja/db-migrations.md
  28. 6
      docs/guide-ja/db-mongodb.md
  29. 6
      docs/guide-ja/db-redis.md
  30. 6
      docs/guide-ja/db-sphinx.md
  31. 254
      docs/guide-ja/input-file-upload.md
  32. 191
      docs/guide-ja/input-forms.md
  33. 6
      docs/guide-ja/input-multiple-models.md
  34. 610
      docs/guide-ja/input-validation.md
  35. 4
      docs/guide-ja/intro-yii.md
  36. 98
      docs/guide-ja/output-client-scripts.md
  37. 133
      docs/guide-ja/output-data-providers.md
  38. 517
      docs/guide-ja/output-data-widgets.md
  39. 190
      docs/guide-ja/output-formatter.md
  40. 6
      docs/guide-ja/output-pagination.md
  41. 6
      docs/guide-ja/output-sorting.md
  42. 102
      docs/guide-ja/output-theming.md
  43. 2
      docs/guide-ja/runtime-routing.md
  44. 6
      docs/guide-ja/security-auth-clients.md
  45. 92
      docs/guide-ja/security-authentication.md
  46. 482
      docs/guide-ja/security-authorization.md
  47. 163
      docs/guide-ja/security-best-practices.md
  48. 152
      docs/guide-ja/security-passwords.md
  49. 1
      docs/guide-ja/start-looking-ahead.md
  50. 2
      docs/guide-ja/structure-applications.md
  51. 2
      docs/guide-ja/structure-controllers.md
  52. 6
      docs/guide-ja/structure-extensions.md
  53. 2
      docs/guide-ja/structure-models.md
  54. 2
      docs/guide-ja/structure-modules.md
  55. 2
      docs/guide-ja/structure-views.md
  56. 2
      docs/guide-ja/structure-widgets.md
  57. 26
      docs/guide-pt-BR/README.md
  58. 38
      docs/guide-pt-BR/start-installation.md
  59. 483
      docs/guide-pt-BR/structure-controllers.md
  60. 578
      docs/guide-pt-BR/structure-models.md
  61. 4
      docs/guide-ru/tutorial-advanced-app.md
  62. 8
      docs/guide-uk/README.md
  63. 512
      docs/guide-uk/images/application-lifecycle.graphml
  64. BIN
      docs/guide-uk/images/application-lifecycle.png
  65. BIN
      docs/guide-uk/images/start-app-installed.png
  66. 153
      docs/guide-uk/start-installation.md
  67. 110
      docs/guide-uk/structure-application-components.md
  68. 364
      docs/guide-uk/structure-applications.md
  69. 300
      docs/guide-uk/structure-controllers.md
  70. 49
      docs/guide-uk/structure-entry-scripts.md
  71. 28
      docs/guide-uk/structure-overview.md
  72. 334
      docs/guide-zh-CN/db-dao.md
  73. 2
      docs/guide/README.md
  74. 12
      docs/guide/db-active-record.md
  75. 4
      docs/guide/db-dao.md
  76. 53
      docs/guide/helper-html.md
  77. 89
      docs/guide/input-file-upload.md
  78. 2
      docs/guide/input-forms.md
  79. 21
      docs/guide/input-validation.md
  80. 28
      docs/guide/output-data-widgets.md
  81. 6
      docs/guide/output-formatter.md
  82. 11
      docs/guide/output-theming.md
  83. 24
      docs/guide/security-authorization.md
  84. 168
      docs/guide/security-best-practices.md
  85. 1
      docs/guide/start-looking-ahead.md
  86. 12
      docs/guide/tutorial-core-validators.md
  87. 4
      docs/guide/widget-jui.md
  88. 16
      docs/internals-pt-BR/translation-workflow.md
  89. 1
      docs/internals/translation-teams.md
  90. 8
      extensions/apidoc/CHANGELOG.md
  91. 3
      extensions/apidoc/models/PropertyDoc.php
  92. 3
      extensions/apidoc/templates/bootstrap/assets/JsSearchAsset.php
  93. 8
      extensions/authclient/CHANGELOG.md
  94. 9
      extensions/bootstrap/CHANGELOG.md
  95. 41
      extensions/bootstrap/Dropdown.php
  96. 8
      extensions/codeception/CHANGELOG.md
  97. 8
      extensions/composer/CHANGELOG.md
  98. 3
      extensions/composer/Installer.php
  99. 9
      extensions/debug/CHANGELOG.md
  100. 15
      extensions/debug/controllers/DefaultController.php
  101. Some files were not shown because too many files have changed in this diff Show More

5
apps/advanced/common/models/User.php

@ -16,7 +16,6 @@ use yii\web\IdentityInterface;
* @property string $password_reset_token
* @property string $email
* @property string $auth_key
* @property integer $role
* @property integer $status
* @property integer $created_at
* @property integer $updated_at
@ -26,7 +25,6 @@ class User extends ActiveRecord implements IdentityInterface
{
const STATUS_DELETED = 0;
const STATUS_ACTIVE = 10;
const ROLE_USER = 10;
/**
* @inheritdoc
@ -54,9 +52,6 @@ class User extends ActiveRecord implements IdentityInterface
return [
['status', 'default', 'value' => self::STATUS_ACTIVE],
['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]],
['role', 'default', 'value' => self::ROLE_USER],
['role', 'in', 'range' => [self::ROLE_USER]],
];
}

1
apps/advanced/console/migrations/m130524_201442_init.php

@ -20,7 +20,6 @@ class m130524_201442_init extends Migration
'password_hash' => Schema::TYPE_STRING . ' NOT NULL',
'password_reset_token' => Schema::TYPE_STRING,
'email' => Schema::TYPE_STRING . ' NOT NULL',
'role' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 10',
'status' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 10',
'created_at' => Schema::TYPE_INTEGER . ' NOT NULL',

5
apps/advanced/frontend/models/SignupForm.php

@ -48,8 +48,9 @@ class SignupForm extends Model
$user->email = $this->email;
$user->setPassword($this->password);
$user->generateAuthKey();
$user->save();
return $user;
if ($user->save()) {
return $user;
}
}
return null;

4
apps/advanced/frontend/widgets/Alert.php

@ -58,12 +58,12 @@ class Alert extends \yii\bootstrap\Widget
foreach ($flashes as $type => $data) {
if (isset($this->alertTypes[$type])) {
$data = (array) $data;
foreach ($data as $message) {
foreach ($data as $i => $message) {
/* initialize css class for each alert box */
$this->options['class'] = $this->alertTypes[$type] . $appendCss;
/* assign unique id to each alert box */
$this->options['id'] = $this->getId() . '-' . $type;
$this->options['id'] = $this->getId() . '-' . $type . '-' . $i;
echo \yii\bootstrap\Alert::widget([
'body' => $message,

48
apps/basic/tests/README.md

@ -59,5 +59,53 @@ codecept run functional
codecept run unit
```
Code coverage support
---------------------
By default, code coverage is disabled in `codeception.yml` configuration file, you should uncomment needed rows to be able
to collect code coverage. You can run your tests and collect coverage with the following command:
```
#collect coverage for all tests
codecept run --coverage-html --coverage-xml
#collect coverage only for unit tests
codecept run unit --coverage-html --coverage-xml
#collect coverage for unit and functional tests
codecept run functional,unit --coverage-html --coverage-xml
```
You can see code coverage output under the `tests/_output` directory.
###Remote code coverage
When you run your tests not in the same process where code coverage is collected, then you should uncomment `remote` option and its
related options, to be able to collect code coverage correctly. To setup remote code coverage you should follow [instructions](http://codeception.com/docs/11-Codecoverage)
from codeception site.
1. install `Codeception c3` remote support `composer require "codeception/c3:*"`;
2. copy `c3.php` file under your `web` directory;
3. include `c3.php` file in your `index-test.php` file before application run, so it can catch needed requests.
Configuration options that are used by remote code coverage:
- c3_url: url pointing to entry script that includes `c3.php` file, so `Codeception` will be able to produce code coverage;
- remote: whether to enable remote code coverage or not;
- remote_config: path to the `codeception.yml` configuration file, from the directory where `c3.php` file is located. This is needed
so that `Codeception` can create itself instance and collect code coverage correctly.
By default `c3_url` and `remote_config` setup correctly, you only need to copy and include `c3.php` file in your `index-test.php`
After that you should be able to collect code coverage from tests that run through `PhpBrowser` or `WebDriver` with same command
as for other tests:
```
#collect coverage from remote
codecept run acceptance --coverage-html --coverage-xml
```
Please refer to [Codeception tutorial](http://codeception.com/docs/01-Introduction) for
more details about writing and running acceptance, functional and unit tests.

20
apps/basic/tests/codeception.yml

@ -1,4 +1,24 @@
actor: Tester
#coverage:
# #c3_url: http://localhost:8080/index-test.php/
# enabled: true
# #remote: true
# #remote_config: '../tests/codeception.yml'
# white_list:
# include:
# - ../models/*
# - ../controllers/*
# - ../commands/*
# - ../mail/*
# blacklist:
# include:
# - ../assets/*
# - ../config/*
# - ../runtime/*
# - ../vendor/*
# - ../views/*
# - ../web/*
# - ../tests/*
paths:
tests: codeception
log: codeception/_output

91
build/controllers/ReleaseController.php

@ -8,6 +8,7 @@
namespace yii\build\controllers;
use Yii;
use yii\base\Exception;
use yii\console\Controller;
/**
@ -30,6 +31,8 @@ class ReleaseController extends Controller
*/
public function actionPrepare($version)
{
$this->resortChangelogs($version);
$this->mergeChangelogs($version);
$this->closeChangelogs($version);
$this->composerSetStability($version);
$this->updateYiiVersion($version);
@ -77,9 +80,95 @@ class ReleaseController extends Controller
}
}
protected function resortChangelogs($version)
{
foreach($this->getChangelogs() as $file) {
// split the file into relevant parts
list($start, $changelog, $end) = $this->splitChangelog($file, $version);
$changelog = $this->resortChangelog($changelog);
file_put_contents($file, implode("\n", array_merge($start, $changelog, $end)));
}
}
protected function mergeChangelogs($version)
{
$file = $this->getFrameworkChangelog();
// split the file into relevant parts
list($start, $changelog, $end) = $this->splitChangelog($file, $version);
$changelog = $this->resortChangelog($changelog);
$changelog[] = '';
$extensions = $this->getExtensionChangelogs();
asort($extensions);
foreach($extensions as $changelogFile) {
if (!preg_match('~extensions/([a-z]+)/CHANGELOG\\.md~', $changelogFile, $m)) {
throw new Exception("Illegal extension changelog file: " . $changelogFile);
}
list( , $extensionChangelog, ) = $this->splitChangelog($changelogFile, $version);
$name = $m[1];
$ucname = ucfirst($name);
$changelog[] = "### $ucname Extension (yii2-$name)";
$changelog = array_merge($changelog, $extensionChangelog);
}
file_put_contents($file, implode("\n", array_merge($start, $changelog, $end)));
}
/**
* Extract changelog content for a specific version
*/
protected function splitChangelog($file, $version)
{
$lines = explode("\n", file_get_contents($file));
// split the file into relevant parts
$start = [];
$changelog = [];
$end = [];
$state = 'start';
foreach($lines as $l => $line) {
// starting from the changelogs headline
if (isset($lines[$l-2]) && strpos($lines[$l-2], $version) !== false &&
isset($lines[$l-1]) && strncmp($lines[$l-1], '---', 3) === 0) {
$state = 'changelog';
}
if ($state === 'changelog' && isset($lines[$l+1]) && strncmp($lines[$l+1], '---', 3) === 0) {
$state = 'end';
}
${$state}[] = $line;
}
return [$start, $changelog, $end];
}
/**
* Ensure sorting of the changelog lines
*/
protected function resortChangelog($changelog)
{
// cleanup whitespace
foreach($changelog as $i => $line) {
$changelog[$i] = rtrim($line);
}
// TODO sorting
return $changelog;
}
protected function getChangelogs()
{
return array_merge([YII2_PATH . '/CHANGELOG.md'], glob(dirname(YII2_PATH) . '/extensions/*/CHANGELOG.md'));
return array_merge([$this->getFrameworkChangelog()], $this->getExtensionChangelogs());
}
protected function getFrameworkChangelog()
{
return YII2_PATH . '/CHANGELOG.md';
}
protected function getExtensionChangelogs()
{
return glob(dirname(YII2_PATH) . '/extensions/*/CHANGELOG.md');
}
protected function composerSetStability($version)

25
docs/guide-es/README.md

@ -62,7 +62,7 @@ Conceptos clave
* [Componentes](concept-components.md)
* [Propiedades](concept-properties.md)
* **TBD** [Eventos](concept-events.md)
* [Eventos](concept-events.md)
* [Comportamientos (Behaviors)](concept-behaviors.md)
* [Configuraciones](concept-configurations.md)
* [Alias](concept-aliases.md)
@ -72,12 +72,16 @@ Conceptos clave
Trabajar con bases de datos
-----------------------------
* [Objeto de acceso a datos](db-dao.md) - Conexión a una base de datos, consultas básicas, transacciones y manipulación de esquemas
* **TBD** [Constructor de consultas](db-query-builder.md) - Consulta de la base de datos utilizando una simple capa de abstracción
* **TBD** [Active Record](db-active-record.md) - ORM Active Record, recuperación y manipulación de registros y definición de relaciones
* **TBD** [Migraciones](db-migrations.md) - Control de versiones de bases de datos en el entorno de desarrollo en equipo
---------------------------
* [Objeto de acceso a datos](db-dao.md) - Conexión a una base de datos, consultas básicas, transacciones y
manipulación de esquemas
* [Constructor de consultas](db-query-builder.md) - Consulta de la base de datos utilizando una simple capa de
abstracción
* **TBD** [Active Record](db-active-record.md) - ORM Active Record, recuperación y manipulación de registros y
definición de relaciones
* **TBD** [Migraciones](db-migrations.md) - Control de versiones de bases de datos en el entorno de desarrollo en
equipo
* **TBD** [Sphinx](db-sphinx.md)
* **TBD** [Redis](db-redis.md)
* **TBD** [MongoDB](db-mongodb.md)
@ -102,7 +106,7 @@ Visualizar datos
* **TBD** [Proveedores de datos](output-data-providers.md)
* **TBD** [Widgets de datos](output-data-widgets.md)
* **TBD** [Trabajar con scripts de cliente](output-client-scripts.md)
* **TBD** [Utilización de temas](output-theming.md)
* [Temas](output-theming.md)
Seguridad
@ -193,7 +197,6 @@ Clases auxiliares
* **TBD** [Información general](helper-overview.md)
* **TBD** [ArrayHelper](helper-array.md)
* **TBD** [Html](helper-html.md)
* **TBD** [Url](helper-url.md)
* [Html](helper-html.md)
* [Url](helper-url.md)
* **TBD** [Security](helper-security.md)

291
docs/guide-es/concept-events.md

@ -0,0 +1,291 @@
Eventos
=======
Los eventos permiten inyectar código dentro de otro código existente en ciertos puntos de ejecución. Se pueden adjuntar
código personalizado a un evento, cuando se lance (triggered), el código se ejecutará automáticamente. Por ejemplo, un
objeto `mailer` puede lanzar el evento `messageSent` cuando se envía un mensaje correctamente. Si se quiere rastrear
el correcto envío del mensaje, se puede, simplemente, añadir un código de seguimiento al evento `messageSent`.
Yii introduce una clase base [[yii\base\Component]] para soportar eventos. Si una clase necesita lanzar un evento,
este debe extender a [[yii\base\Component]] o a una clase hija.
Gestor de Eventos <a name="event-handlers"></a>
-----------------
Un gestor de eventos es una
[llamada de retorno PHP (PHP callback)](http://php.net/manual/es/language.types.callable.php) que se ejecuta cuando se
lanza el evento al que corresponde. Se puede usar cualquier llamada de retorno de las enumeradas a continuación:
- una función de PHP global especificada como una cadena de texto (sin paréntesis), p. ej. `'trim'`;
- un método de objeto especificado como un array de un objeto y un nombre de método como una cadena de texto
(sin paréntesis), p. ej. `[$object, 'methodNAme']`;
- un método de clase estático especificado como un array de un nombre de clase y un método como una cadena de texto
(sin paréntesis), p. ej. `[$class, 'methodName']`;
- una función anónima, p. ej. `function ($event) { ... }`.
La firma de un gestor de eventos es:
```php
function ($event) {
// $event es un objeto de yii\base\Event o de una clase hija
}
```
Un gestor de eventos puede obtener la siguiente información acerca de un evento ya sucedido mediante el parámetro
`$event`:
- [[yii\base\Event::name|event name]]
- [[yii\base\Event::sender|event sender]]: el objeto desde el que se ha ejecutado `trigger()`
- [[yii\base\Event::data|custom data]]: los datos que se proporcionan al adjuntar el gestor de eventos
(se explicará más adelante)
Añadir Gestores de Eventos <a name="attaching-event-handlers"></a>
--------------------------
Se puede añadir un gestor a un evento llamando al método [[yii\base\Component::on()]]. Por ejemplo:
```php
$foo = new Foo;
// este gestor es una función global
$foo->on(Foo::EVENT_HELLO, 'function_name');
// este gestor es un método de objeto
$foo->on(Foo::EVENT_HELLO, [$object, 'methodName']);
// este gestor es un método de clase estática
$foo->on(Foo::EVENT_HELLO, ['app\components\Bar', 'methodName']);
// este gestor es una función anónima
$foo->on(Foo::EVENT_HELLO, function ($event) {
// event handling logic
});
```
También se pueden adjuntar gestores de eventos mediante [configuraciones](concept-configurations.md). Se pueden
encontrar más de talles en la sección [Configuraciones](concept-configurations.md#configuration-format).
Cuando se adjunta un gestor de eventos, se pueden proporcionar datos adicionales como tercer parámetro de
[[yii\base\Component::on()]]. El gestor podrá acceder a los datos cuando se lance el evento y se ejecute el gestor.
Por ejemplo:
```php
// El siguiente código muestra "abc" cuando se lanza el evento
// ya que $event->data contiene los datos enviados en el tercer parámetro de "on"
$foo->on(Foo::EVENT_HELLO, 'function_name', 'abc');
function function_name($event) {
echo $event->data;
}
```
Ordenación de Gestores de Eventos
---------------------------------
Se puede adjuntar uno o más gestores a un único evento. Cuando se lanza un evento, se ejecutarán los gestores adjuntos
en el orden que se hayan añadido al evento. Si un gestor necesita parar la invocación de los gestores que le siguen,
se puede establecer la propiedad [[yii\base\Event::handled]] del parámetro `$event` para que sea `true`:
```php
$foo->on(Foo::EVENT_HELLO, function ($event) {
$event->handled = true;
});
```
De forma predeterminada, cada nuevo gestor añadido se pone a la cola de la lista de gestores del evento. Por lo tanto,
el gestor se ejecutará en el último lugar cuando se lance el evento. Para insertar un nuevo gestor al principio de la
cola de gestores para que sea ejecutado primero, se debe llamar a [[yii\base\Component::on()]], pasando al cuarto
parámetro `$append` el valor `false`:
```php
$foo->on(Foo::EVENT_HELLO, function ($event) {
// ...
}, $data, false);
```
Lanzamiento de Eventos <a name="triggering-events"></a>
----------------------
Los eventos se lanzan llamando al método [[yii\base\Component::trigger()]]. El método requiere un *nombre de evento*,
y de forma opcional un objeto de evento que describa los parámetros que se enviarán a los gestores de eventos. Por
ejemplo:
```php
namespace app\components;
use yii\base\Component;
use yii\base\Event;
class Foo extends Component
{
const EVENT_HELLO = 'hello';
public function bar()
{
$this->trigger(self::EVENT_HELLO);
}
}
```
Con el código anterior, cada llamada a `bar()` lanzará un evento llamado `hello`
> Consejo: Se recomienda usar las constantes de clase para representar nombres de eventos. En el anterior ejemplo, la
constante `EVENT_HELLO` representa el evento `hello`. Este enfoque proporciona tres beneficios. Primero, previene
errores tipográficos. Segundo, puede hacer que los IDEs reconozcan los eventos en las funciones de auto-completado.
Tercero, se puede ver que eventos soporta una clase simplemente revisando la declaración de constantes.
A veces cuando se lanza un evento se puede querer pasar información adicional al gestor de eventos. Por ejemplo, un
`mailer` puede querer enviar la información del mensaje para que los gestores del evento `messageSent` para que los
gestores puedan saber las particularidades del mensaje enviado. Para hacerlo, se puede proporcionar un objeto de tipo
evento como segundo parámetro al método [[yii\base\Component::trigger()]]. El objeto de tipo evento debe ser una
instancia de la clase [[yii\base\Event]] o de sus hijas. Por ejemplo:
```php
namespace app\components;
use yii\base\Component;
use yii\base\Event;
class MessageEvent extends Event
{
public $message;
}
class Mailer extends Component
{
const EVENT_MESSAGE_SENT = 'messageSent';
public function send($message)
{
// ...enviando $message...
$event = new MessageEvent;
$event->message = $message;
$this->trigger(self::EVENT_MESSAGE_SENT, $event);
}
}
```
Cuando se lanza el método [[yii\base\Component::trigger()]], se ejecutarán todos los gestores adjuntos al evento.
Desadjuntar Gestores de Evento <a name="detaching-event-handlers"></a>
------------------------------
Para desadjuntar un gestor de un evento, se puede ejecutar el método [[yii\base\Component::off()]]. Por ejemplo:
```php
// el gestor es una función global
$foo->off(Foo::EVENT_HELLO, 'function_name');
// el gestor es un método de objeto
$foo->off(Foo::EVENT_HELLO, [$object, 'methodName']);
// el gestor es un método estático de clase
$foo->off(Foo::EVENT_HELLO, ['app\components\Bar', 'methodName']);
// el gestor es una función anónima
$foo->off(Foo::EVENT_HELLO, $anonymousFunction);
```
Tenga en cuenta que en general no se debe intentar desadjuntar las funciones anónimas a no ser que se almacene donde
se ha adjuntado al evento. En el anterior ejemplo, se asume que la función anónima se almacena como variable
`$anonymousFunction`.
Para desadjuntar TODOS los gestores de un evento, se puede llamar [[yii\base\Component::off()]] sin el segundo
parámetro:
```php
$foo->off(Foo::EVENT_HELLO);
```
Nivel de Clase (Class-Level) Gestores de Eventos <a name="class-level-event-handlers"></a>
------------------------------------------------
En las subsecciones anteriores se ha descrito como adjuntar un gestor a un evento a *nivel de instancia*. A veces, se
puede querer que un gestor responda todos los eventos de *todos* las instancias de una clase en lugar de una instancia
especifica. En lugar de adjuntar un gestor de eventos a una instancia, se puede adjuntar un gestor a *nivel de clase*
llamando al método estático [[yii\base\Event::on()]].
Por ejemplo, un objeto de tipo [Active Record](db-active-record.md) lanzará un evento
[[yii\db\BaseActiveRecord::EVENT_AFTER_INSERT|EVENT_AFTER_INSERT]] cada vez que inserte un nuevo registro en la base
de datos. Para poder registrar las inserciones efectuadas por *todos* los objetos
[Active Record](db-active-record.md), se puede usar el siguiente código:
```php
use Yii;
use yii\base\Event;
use yii\db\ActiveRecord;
Event::on(ActiveRecord::className(), ActiveRecord::EVENT_AFTER_INSERT, function ($event) {
Yii::trace(get_class($event->sender) . ' is inserted');
});
```
Se invocará al gestor de eventos cada vez que una instancia de [[yii\db\ActiveRecord|ActiveRecord]], o de uno de sus
clases hijas, lance un evento de tipo [[yii\db\BaseActiveRecord::EVENT_AFTER_INSERT|EVENT_AFTER_INSERT]]. Se puede
obtener el objeto que ha lanzado el evento mediante `$event->sender` en el gestor.
Cuando un objeto lanza un evento, primero llamará los gestores a nivel de instancia, y a continuación los gestores a
nivel de clase.
Se puede lanzar un evento de tipo *nivel de clase* llamando al método estático [[yii\base\Event::trigger()]]. Un
evento de nivel de clase no se asocia a un objeto en particular. Como resultado, esto provocará solamente la
invocación de los gestores de eventos a nivel de clase.
```php
use yii\base\Event;
Event::on(Foo::className(), Foo::EVENT_HELLO, function ($event) {
echo $event->sender; // displays "app\models\Foo"
});
Event::trigger(Foo::className(), Foo::EVENT_HELLO);
```
Tenga en cuenta que en este caso, el `$event->sender` hace referencia al nombre de la clase que lanza el evento en
lugar de a la instancia del objeto.
> Nota: Debido a que los gestores a nivel de clase responderán a los eventos lanzados por cualquier instancia de la
clase, o cualquier clase hija, se debe usar con cuidado, especialmente en las clases de bajo nivel (low-level), tales
como [[yii\base\Object]].
Para desadjuntar un gestor de eventos a nivel de clase, se tiene que llamar a [[yii\base\Event::off()]]. Por ejemplo:
```php
// desadjunta $handler
Event::off(Foo::className(), Foo::EVENT_HELLO, $handler);
// desadjunta todos los gestores de Foo::EVENT_HELLO
Event::off(Foo::className(), Foo::EVENT_HELLO);
```
Eventos Globales <a name="global-events"></a>
----------------
Yii soporta los llamados *eventos globales*, que en realidad es un truco basado en el gestor de eventos descrito
anteriormente. El evento global requiere un Singleton globalmente accesible, tal como la instancia de
[aplicación](structure-applications.md) en si misma.
Para crear un evento global, un evento remitente (event sender) llama al método `trigger()` del Singleton para lanzar
el evento, en lugar de llamar al propio método `trigger()` del remitente. De forma similar, los gestores de eventos se
adjuntan al evento del Singleton. Por ejemplo:
```php
use Yii;
use yii\base\Event;
use app\components\Foo;
Yii::$app->on('bar', function ($event) {
echo get_class($event->sender); // muestra "app\components\Foo"
});
Yii::$app->trigger('bar', new Event(['sender' => new Foo]));
```
Un beneficio de usar eventos globales es que no se necesita un objeto cuando se adjuntan gestores a un evento para que
sean lanzados por el objeto. En su lugar, los gestores adjuntos y el lanzamiento de eventos se efectúan en el
Singleton (p. ej. la instancia de la aplicación).
Sin embargo, debido a que los `namespaces` de los eventos globales son compartidos por todas partes, se les deben
asignar nombres bien pensados, como puede ser la introducción de algún `namespace`
(p. ej. "frontend.mail.sent", "backend.mail.sent").

470
docs/guide-es/db-query-builder.md

@ -0,0 +1,470 @@
Constructor de Consultas
========================
> Nota: Esta sección está en desarrollo.
Yii proporciona una capa de acceso básico a bases de datos como se describe en la sección
[Objetos de Acceso a Bases de Datos](db-dao.md). La capa de acceso a bases de datos proporciona un método de bajo
nivel (low-level) para interaccionar con la base de datos. Aunque a veces puede ser útil la escritura de sentencias
SQLs puras, en otras situaciones puede ser pesado y propenso a errores. Otra manera de tratar con bases de datos puede
ser el uso de Constructores de Consultas (Query Builder). El Constructor de Consultas proporciona un medio orientado a
objetos para generar las consultas que se ejecutarán.
Un uso típico de Constructor de Consultas puede ser el siguiente:
```php
$rows = (new \yii\db\Query())
->select('id, name')
->from('user')
->limit(10)
->all();
// que es equivalente al siguiente código:
$query = (new \yii\db\Query())
->select('id, name')
->from('user')
->limit(10);
// Crear un comando. Se puede obtener la consulta SQL actual utilizando $command->sql
$command = $query->createCommand();
// Ejecutar el comando:
$rows = $command->queryAll();
```
Métodos de Consulta
-------------------
Como se puede observar, primero se debe tratar con [[yii\db\Query]]. En realidad, `Query` sólo se encarga de
representar diversa información de la consulta. La lógica para generar la consulta se efectúa mediante
[[yii\db\QueryBuilder]] cuando se llama al método `createCommand()`, y la ejecución de la consulta la efectúa
[[yii\db\Command]].
Se ha establecido, por convenio, que [[yii\db\Query]] proporcione un conjunto de métodos de consulta comunes que
construirán la consulta, la ejecutarán, y devolverán el resultado. Por ejemplo:
- [[yii\db\Query::all()|all()]]: construye la consulta, la ejecuta y devuelve todos los resultados en formato de array.
- [[yii\db\Query::one()|one()]]: devuelve la primera fila del resultado.
- [[yii\db\Query::column()|column()]]: devuelve la primera columna del resultado.
- [[yii\db\Query::scalar()|scalar()]]: devuelve la primera columna en la primera fila del resultado.
- [[yii\db\Query::exists()|exists()]]: devuelve un valor indicando si la el resultado devuelve algo.
- [[yii\db\Query::count()|count()]]: devuelve el resultado de la consulta `COUNT`. Otros métodos similares incluidos
son `sum($q)`, `average($q)`, `max($q)`, `min($q)`, que soportan las llamadas funciones de agregación. El parámetro
`$q` es obligatorio en estos métodos y puede ser el nombre de la columna o expresión.
Construcción de Consultas
-------------------------
A continuación se explicará como construir una sentencia SQL que incluya varias clausulas. Para simplificarlo, usamos
`$query` para representar el objeto [[yii\db\Query]]:
### `SELECT`
Para formar una consulta `SELECT` básica, se necesita especificar que columnas y de que tablas se seleccionarán:
```php
$query->select('id, name')
->from('user');
```
Las opciones de select se pueden especificar como una cadena de texto (string) separada por comas o como un array. La
sintaxis del array es especialmente útil cuando se forma la selección dinámicamente.
```php
$query->select(['id', 'name'])
->from('user');
```
> Información: Se debe usar siempre el formato array si la clausula `SELECT` contiene expresiones SQL. Esto se debe a
que una expresión SQL como `CONCAT(first_name, last_name) AS full_name` puede contener comas. Si se junta con otra
cadena de texto de otra columna, puede ser que la expresión se divida en varias partes por comas, esto puede
conllevar a errores.
Cuando se especifican columnas, se pueden incluir los prefijos de las tablas o alias de columnas, p. ej. `user.id`,
`user.id AS user_id`. Si se usa un array para especificar las columnas, también se pueden usar las claves del array
para especificar los alias de columna, p. ej. `['user_id' => 'user.id', 'user_name' => 'user.name']`.
A partir de la versión 2.0.1, también se pueden seleccionar subconsultas como columnas. Por ejemplo:
```php
$subQuery = (new Query)->select('COUNT(*)')->from('user');
$query = (new Query)->select(['id', 'count' => $subQuery])->from('post');
// $query representa la siguiente sentencia SQL:
// SELECT `id`, (SELECT COUNT(*) FROM `user`) AS `count` FROM `post`
```
Para seleccionar filas distintas, se puede llamar a `distinct()`, como se muestra a continuación:
```php
$query->select('user_id')->distinct()->from('post');
```
### `FROM`
Para especificar de que tabla(s) se quieren seleccionar los datos, se llama a `from()`:
```php
$query->select('*')->from('user');
```
Se pueden especificar múltiples tablas usando una cadena de texto separado por comas o un array. Los nombres de tablas
pueden contener prefijos de esquema (p. ej. `'public.user'`) y/o alias de tablas (p. ej. `'user u'). El método
entrecomillara automáticamente los nombres de tablas a menos que contengan algún paréntesis (que significa que se
proporciona la tabla como una subconsulta o una expresión de BD). Por ejemplo:
```php
$query->select('u.*, p.*')->from(['user u', 'post p']);
```
Cuando se especifican las tablas como un array, también se pueden usar las claves de los arrays como alias de tablas
(si una tabla no necesita alias, no se usa una clave en formato texto). Por ejemplo:
```php
$query->select('u.*, p.*')->from(['u' => 'user', 'p' => 'post']);
```
Se puede especificar una subconsulta usando un objeto `Query`. En este caso, la clave del array correspondiente se
usará como alias para la subconsulta.
```php
$subQuery = (new Query())->select('id')->from('user')->where('status=1');
$query->select('*')->from(['u' => $subQuery]);
```
### `WHERE`
Habitualmente se seleccionan los datos basándose en ciertos criterios. El Constructor de Consultas tiene algunos
métodos útiles para especificarlos, el más poderoso de estos es `where`, y se puede usar de múltiples formas.
La manera más simple para aplicar una condición es usar una cadena de texto:
```php
$query->where('status=:status', [':status' => $status]);
```
Cuando se usan cadenas de texto, hay que asegurarse que se unen los parámetros de la consulta, no crear una consulta
mediante concatenación de cadenas de texto. El enfoque anterior es seguro, el que se muestra a continuación, no lo es:
```php
$query->where("status=$status"); // Peligroso!
```
En lugar de enlazar los valores de estado inmediatamente, se puede hacer usando `params` o `addParams`:
```php
$query->where('status=:status');
$query->addParams([':status' => $status]);
```
Se pueden establecer múltiples condiciones en `where` usando el *formato hash*.
```php
$query->where([
'status' => 10,
'type' => 2,
'id' => [4, 8, 15, 16, 23, 42],
]);
```
El código generará la el siguiente SQL:
```sql
WHERE (`status` = 10) AND (`type` = 2) AND (`id` IN (4, 8, 15, 16, 23, 42))
```
El valor NULO es un valor especial en las bases de datos, y el Constructor de Consultas lo gestiona inteligentemente.
Este código:
```php
$query->where(['status' => null]);
```
da como resultado la siguiente cláusula WHERE:
```sql
WHERE (`status` IS NULL)
```
También se pueden crear subconsultas con objetos de tipo `Query` como en el siguiente ejemplo:
```php
$userQuery = (new Query)->select('id')->from('user');
$query->where(['id' => $userQuery]);
```
que generará el siguiente código SQL:
```sql
WHERE `id` IN (SELECT `id` FROM `user`)
```
Otra manera de usar el método es el formato de operando que es `[operator, operand1, operand2, ...]`.
El operando puede ser uno de los siguientes (ver también [[yii\db\QueryInterface::where()]]):
- `and`: los operandos deben concatenerase usando `AND`. por ejemplo, `['and', 'id=1', 'id=2']` generará
`id=1 AND id=2`. Si el operando es un array, se convertirá en una cadena de texto usando las reglas aquí descritas.
Por ejemplo, `['and', 'type=1', ['or', 'id=1', 'id=2']]` generará `type=1 AND (id=1 OR id=2)`. El método no
ejecutará ningún filtrado ni entrecomillado.
- `or`: similar al operando `and` exceptuando que los operando son concatenados usando `OR`.
- `between`: el operando 1 debe ser el nombre de columna, y los operandos 2 y 3 deben ser los valores iniciales y
finales del rango en el que se encuentra la columna. Por ejemplo, `['between', 'id', 1, 10]` generará
`id BETWEEN 1 AND 10`.
- `not between`: similar a `between` exceptuando que `BETWEEN` se reemplaza por `NOT BETWEEN` en la condición
generada.
- `in`: el operando 1 debe ser una columna o una expresión de BD. El operando 2 puede ser un array o un objeto de tipo
`Query`. Generará una condición `IN`. Si el operando 2 es un array, representará el rango de valores que puede
albergar la columna o la expresión de BD; Si el operando 2 es un objeto de tipo `Query`, se generará una subconsulta
y se usará como rango de la columna o de la expresión de BD. Por ejemplo, `['in', 'id', [1, 2, 3]]` generará
`id IN (1, 2, 3)`. El método entrecomillará adecuadamente el nombre de columna y filtrará los valores del rango. El
operando `in` también soporta columnas compuestas. En este caso, el operando 1 debe se un array de columnas,
mientras que el operando 2 debe ser un array de arrays o un objeto de tipo `Query` que represente el rango de las
columnas.
- `not in`: similar que el operando `in` exceptuando que `IN` se reemplaza por `NOT IN` en la condición generada.
- `like`: el operando 1 debe ser una columna o una expresión de BD, y el operando 2 debe ser una cadena de texto o un
array que represente los valores a los que tienen que asemejarse la columna o la expresión de BD.Por ejemplo,
`['like', 'name', 'tester']` generará `name LIKE '%tester%'`. Cuando se da el valor rango como un array, se
generarán múltiples predicados `LIKE` y se concatenaran usando `AND`. Por ejemplo,
`['like', 'name', ['test', 'sample']]` generará `name LIKE '%test%' AND name LIKE '%sample%'`. También se puede
proporcionar un tercer operando opcional para especificar como deben filtrarse los caracteres especiales en los
valores. El operando debe se un array que mapeen los caracteres especiales a sus caracteres filtrados asociados. Si
no se proporciona este operando, se aplicará el mapeo de filtrado predeterminado. Se puede usar `false` o un array
vacío para indicar que los valores ya están filtrados y no se necesita aplicar ningún filtro. Hay que tener en
cuenta que cuando se usa un el mapeo de filtrado (o no se especifica el tercer operando), los valores se encerraran
automáticamente entre un par de caracteres de porcentaje.
> Nota: Cuando se usa PostgreSQL también se puede usar
[`ilike`](http://www.postgresql.org/docs/8.3/static/functions-matching.html#FUNCTIONS-LIKE) en lugar de `like` para
filtrar resultados insensibles a mayúsculas (case-insensitive).
- `or like`: similar al operando `like` exceptuando que se usa `OR` para concatenar los predicados `LIKE` cuando haya
un segundo operando en un array.
- `not like`: similar al operando `like` exceptuando que se usa `LIKE` en lugar de `NOT LIKE` en las condiciones
generadas.
- `or not like`: similar al operando `not like` exceptuando que se usa `OR` para concatenar los predicados `NOT LIKE`.
- `exists`: requiere un operando que debe ser una instancia de [[yii\db\Query]] que represente la subconsulta. Esto
generará una expresión `EXISTS (sub-query)`.
- `not exists`: similar al operando `exists` y genera una expresión `NOT EXISTS (sub-query)`.
Adicionalmente se puede especificar cualquier cosa como operando:
```php
$query->select('id')
->from('user')
->where(['>=', 'id', 10]);
```
Cuyo resultado será:
```sql
SELECT id FROM user WHERE id >= 10;
```
Si se construyen partes de una condición dinámicamente, es muy convenientes usar `andWhere()` y `orWhere()`:
```php
$status = 10;
$search = 'yii';
$query->where(['status' => $status]);
if (!empty($search)) {
$query->andWhere(['like', 'title', $search]);
}
```
En el caso que `$search` no este vacío, se generará el siguiente código SQL:
```sql
WHERE (`status` = 10) AND (`title` LIKE '%yii%')
```
#### Construcción de Condiciones de Filtro
Cuando se generan condiciones de filtro basadas en datos recibidos de usuarios (inputs), a menudo se quieren gestionar
de forma especial las "datos vacíos" para ignorarlos en los filtros. Por ejemplo, teniendo un formulario HTML que
obtiene el nombre de usuario y la dirección de correo electrónico. Si el usuario solo rellena el campo de nombre de
usuario, se puede querer generar una consulta para saber si el nombre de usuario recibido es valido. Se puede usar
`filterWhere()` para conseguirlo:
```php
// $username y $email son campos de formulario rellenados por usuarios
$query->filterWhere([
'username' => $username,
'email' => $email,
]);
```
El método `filterWhere()` es muy similar al método `where()`. La principal diferencia es que el `filterWhere()`
eliminará los valores vacíos de las condiciones proporcionadas. Por lo tanto si `$email` es "vació", la consulta
resultante será `...WHERE username=:username`; y si tanto `$username` como `$email` son "vacías", la consulta no
tendrá `WHERE`.
Decimos que un valor es *vacío* si es nulo, una cadena de texto vacía, una cadena de texto que consista en espacios en
blanco o un array vacío.
También se pueden usar `andFilterWhere()` y `orFilterWhere()` para añadir más condiciones de filtro.
### `ORDER BY`
Se pueden usar `orderBy` y `addOrderBy` para ordenar resultados:
```php
$query->orderBy([
'id' => SORT_ASC,
'name' => SORT_DESC,
]);
```
Aquí estamos ordenando por `id` ascendente y después por `name` descendente.
### `GROUP BY` and `HAVING`
Para añadir `GROUP BY` al SQL generado se puede usar el siguiente código:
```php
$query->groupBy('id, status');
```
Si se quieren añadir otro campo después de usar `groupBy`:
```php
$query->addGroupBy(['created_at', 'updated_at']);
```
Para añadir la condición `HAVING` se pueden usar los métodos `having` y `andHaving` y `orHaving`. Los parámetros para
ellos son similares a los del grupo de métodos `where`:
```php
$query->having(['status' => $status]);
```
### `LIMIT` and `OFFSET`
Para limitar el resultado a 10 filas se puede usar `limit`:
```php
$query->limit(10);
```
Para saltarse las 100 primeras filas, se puede usar:
```php
$query->offset(100);
```
### `JOIN`
Las clausulas `JOIN` se generan en el Constructor de Consultas usando el método join aplicable:
- `innerJoin()`
- `leftJoin()`
- `rightJoin()`
Este left join selecciona los datos desde dos tablas relacionadas en una consulta:
```php
$query->select(['user.name AS author', 'post.title as title'])
->from('user')
->leftJoin('post', 'post.user_id = user.id');
```
En el código, el primer parámetro del método `leftjoin` especifica la tabla a la que aplicar el join. El segundo
parámetro, define la condición del join.
Si la aplicación de bases de datos soporta otros tipos de joins, se pueden usar mediante el método `join` genérico:
```php
$query->join('FULL OUTER JOIN', 'post', 'post.user_id = user.id');
```
El primer argumento es el tipo de join a realizar. El segundo es la tabla a la que aplicar el join, y el tercero es la condición:
Como en `FROM`, también se pueden efectuar joins con subconsultas. Para hacerlo, se debe especificar la subconsulta
como un array que tiene que contener un elemento. El valor del array tiene que ser un objeto de tipo `Query` que
represente la subconsulta, mientras que la clave del array es el alias de la subconsulta. Por ejemplo:
```php
$query->leftJoin(['u' => $subQuery], 'u.id=author_id');
```
### `UNION`
En SQL `UNION` agrega resultados de una consulta a otra consulta. Las columnas devueltas por ambas consultas deben
coincidir. En Yii para construirla, primero se pueden formar dos objetos de tipo query y después usar el método
`union`:
```php
$query = new Query();
$query->select("id, category_id as type, name")->from('post')->limit(10);
$anotherQuery = new Query();
$anotherQuery->select('id, type, name')->from('user')->limit(10);
$query->union($anotherQuery);
```
Consulta por Lotes
---------------
Cuando se trabaja con grandes cantidades de datos, los métodos como [[yii\db\Query::all()]] no son adecuados ya que
requieren la carga de todos los datos en memoria. Para mantener los requerimientos de memoria reducidos, Yii
proporciona soporte a las llamadas consultas por lotes (batch query). Una consulta por lotes usa un cursor de datos y
recupera los datos en bloques.
Las consultas por lotes se pueden usar del siguiente modo:
```php
use yii\db\Query;
$query = (new Query())
->from('user')
->orderBy('id');
foreach ($query->batch() as $users) {
// $users is an array of 100 or fewer rows from the user table
}
// o si se quieren iterar las filas una a una
foreach ($query->each() as $user) {
// $user representa uno fila de datos de la tabla user
}
```
Los métodos [[yii\db\Query::batch()]] y [[yii\db\Query::each()]] devuelven un objeto [[yii\db\BatchQueryResult]] que
implementa una interfaz `Iterator` y así se puede usar en el constructor `foreach`. Durante la primera iteración, se
efectúa una consulta SQL a la base de datos. Desde entonces, los datos se recuperan por lotes en las iteraciones. El
tamaño predeterminado de los lotes es 100, que significa que se recuperan 100 filas de datos en cada lote. Se puede
modificar el tamaño de los lotes pasando pasando un primer parámetro a los métodos `batch()` o `each()`.
En comparación con [[yii\db\Query::all()]], las consultas por lotes sólo cargan 100 filas de datos en memoria cada
vez. Si el procesan los datos y después se descartan inmediatamente, las consultas por lotes, pueden ayudar a mantener
el uso de memora bajo un limite.
Si se especifica que el resultado de la consulta tiene que ser indexado por alguna columna mediante
[[yii\db\Query::indexBy()]], las consultas por lotes seguirán manteniendo el indice adecuado. Por ejemplo,
```php
use yii\db\Query;
$query = (new Query())
->from('user')
->indexBy('username');
foreach ($query->batch() as $users) {
// $users esta indexado en la columna "username"
}
foreach ($query->each() as $username => $user) {
}
```

377
docs/guide-es/helper-html.md

@ -0,0 +1,377 @@
Clase auxiliar Html (Html helper)
=================================
Todas las aplicaciones web generan grandes cantidades de marcado HTML (HTML markup). Si el marcado es estático, se
puede realizar de forma efectiva
[mezclando PHP y HTML en un mismo archivo](http://php.net/manual/es/language.basic-syntax.phpmode.php) pero cuando se
generan dinámicamente empieza a complicarse su gestion sin ayuda extra. Yii proporciona esta ayuda que proporciona un
conjunto de métodos estáticos para gestionar las etiquetas HTML usadas más comúnmente, sus opciones y contenidos.
> Nota: Si el marcado es casi estático, es preferible usar HTML directamente. No es necesario encapsularlo todo con
llamadas a la clase auxiliar Html.
Lo fundamental <a name="basics"></a>
--------------
Teniendo en cuenta que la construcción de HTML dinámico mediante la concatenación de cadenas de texto se complica
rápidamente, Yii proporciona un conjunto de métodos para manipular las opciones de etiquetas y la construcción de las
mismas basadas en estas opciones.
### Generación de etiquetas
El código de generación de etiquetas es similar al siguiente:
```php
<?= Html::tag('p', Html::encode($user->name), ['class' => 'username']) ?>
```
El primer argumento es el nombre de la etiqueta. El segundo es el contenido que se ubicara entre la etiqueta de
apertura y la de cierre. Hay que tener en cuenta que estamos usando `Html::encode`. Esto es debido a que el contenido
no se codifica automáticamente para permitir usar HTML cuando se necesite. La tercera opción es un array de opciones
HTML o, en otras palabras, los atributos de las etiquetas. En este array la clave representa el nombre del atributo
como podría ser `class`, `href` o `target` y el valor es su valor.
El código anterior generara el siguiente HTML:
```html
<p class="username">samdark</p>
```
Si se necesita solo la apertura o el cierre de una etiqueta, se pueden usar los métodos `Html::beginTag()` y
`Html::endTag()`.
Las opciones se usan en muchos métodos de la clase auxiliar Html y en varios widgets. En todos estos casos hay cierta
gestión adicional que se debe conocer:
- Si un valor es `null`, el correspondiente atributo no se renderizará.
- Los atributos cuyos valores son de tipo booleano serán tratados como
[atributos booleanos](http://www.w3.org/TR/html5/infrastructure.html#boolean-attributes).
- Los valores de los atributos se codificaran en HTML usando [[yii\helpers\Html::encode()|Html::encode()]].
- El atributo "data" puede recibir un array. En este caso, se "expandirá" y se renderizará una lista de atributos
`data` p. ej. `'data' => ['id' => 1, 'name' => 'yii']` se convierte en `data-id="1" data-name="yii"`.
- El atributo "data" puede recibir JSON. Se gestionará de la misma manera que un array p. ej.
`'data' => ['params' => ['id' => 1, 'name' => 'yii'], 'status' => 'ok']` se convierte en
`data-params='{"id":1,"name":"yii"}' data-status="ok"`.
### Formación de clases y estilos dinámicamente
Cuando se construyen opciones para etiquetas HTML, a menudo nos encontramos con valores predeterminados que hay que
modificar. Para añadir o eliminar clases CSS se puede usar el siguiente ejemplo:
```php
$options = ['class' => 'btn btn-default'];
if ($type === 'success') {
Html::removeCssClass($options, 'btn-default');
Html::addCssClass($options, 'btn-success');
}
echo Html::tag('div', 'Pwede na', $options);
// cuando $type sea 'success' se renderizará
// <div class="btn btn-success">Pwede na</div>
```
Para hacer lo mismo con los estilos para el atributo `style`:
```php
$options = ['style' => ['width' => '100px', 'height' => '100px']];
// devuelve style="width: 100px; height: 200px; position: absolute;"
Html::addCssStyle($options, 'height: 200px; positon: absolute;');
// devuelve style="position: absolute;"
Html::removeCssStyle($options, ['width', 'height']);
```
Cuando se usa [[yii\helpers\Html::addCssStyle()|addCssStyle()]] se puede especificar si un array de pares clave-valor
corresponde a nombres y valores de la propiedad CSS correspondiente o a una cadena de texto como por ejemplo
`width: 100px; height: 200px;`. Estos formatos se pueden "hacer" y "deshacer" usando
[[yii\helpers\Html::cssStyleFromArray()|cssStyleFromArray()]] y
[[yii\helpers\Html::cssStyleToArray()|cssStyleToArray()]]. El método
[[yii\helpers\Html::removeCssStyle()|removeCssStyle()]] un array de propiedades que se eliminarán. Si sólo se
eliminará una propiedad, se puede especificar como una cadena de texto.
Codificación y Descodificación de contenido <a name="encoding-and-decoding-content"></a>
-------------------------------------------
Para que el contenido se muestre correctamente y de forma segura en caracteres especiales HTML el contenido debe ser
codificado. En PHP esto se hace con [htmlspecialchars](http://www.php.net/manual/en/function.htmlspecialchars.php) y
[htmlspecialchars_decode](http://www.php.net/manual/en/function.htmlspecialchars-decode.php). El problema con el uso
de estos métodos directamente es que se tiene que especificar la codificación y opciones extra cada vez. Ya que las
opciones siempre son las mismas y la codificación debe coincidir con la de la aplicación para prevenir problemas de
seguridad, Yii proporciona dos métodos simples y compactos:
```php
$userName = Html::encode($user->name);
echo $userName;
$decodedUserName = Html::decode($userName);
```
Formularios
-----------
El trato con el marcado de formularios es una tarea repetitiva y propensa a errores. Por esto hay un grupo de métodos
para ayudar a gestionarlos.
> Nota: hay que considerar la opción de usar [[yii\widgets\ActiveForm|ActiveForm]] en caso que se gestionen
formularios que requieran validaciones.
### Abrir y cerrar un formulario
Se puede abrir un formulario con el metodo [[yii\helpers\Html::beginForm()|beginForm()]] como se muestra a
continuación:
```php
<?= Html::beginForm(['order/update', 'id' => $id], 'post', ['enctype' => 'multipart/form-data']) ?>
```
El primer argumento es la URL a la que se enviaran los datos del formulario. Se puede especificar en formato de ruta
de Yii con los parámetros aceptados por [[yii\helpers\Url::to()|Url::to()]]. El segundo es el método que se usara.
`post` es el método predeterminado. El tercero es un array de opciones para la etiqueta `form`. En este caso cambiamos
el método de codificación del formulario de `data` en una petición POST a `multipart/form-data`. Esto se requiere
cuando se quieren subir archivos.
El cierre de la etiqueta `form` es simple:
```php
<?= Html::endForm() ?>
```
### Botones
Para generar botones se puede usar el siguiente código:
```php
<?= Html::button('Press me!', ['class' => 'teaser']) ?>
<?= Html::submitButton('Submit', ['class' => 'submit']) ?>
<?= Html::resetButton('Reset', ['class' => 'reset']) ?>
```
El primer argumento para los tres métodos es el titulo del botón y el segundo son las opciones. El titulo no esta
codificado pero si se usan datos recibidos por el usuario, deben codificarse mediante
[[yii\helpers\Html::encode()|Html::encode()]].
### Inputs
Hay dos grupos en los métodos input. Unos empiezan con `active` y se llaman inputs activos y los otros no empiezan
así. Los inputs activos obtienen datos del modelo y del atributo especificado y los datos de los inputs normales se
especifica directamente.
Los métodos más genéricos son:
```php
type, input name, input value, options
<?= Html::input('text', 'username', $user->name, ['class' => $username]) ?>
type, model, model attribute name, options
<?= Html::activeInput('text', $user, 'name', ['class' => $username]) ?>
```
Si se conoce el tipo de input de antemano, es conveniente usar los atajos de métodos:
- [[yii\helpers\Html::buttonInput()]]
- [[yii\helpers\Html::submitInput()]]
- [[yii\helpers\Html::resetInput()]]
- [[yii\helpers\Html::textInput()]], [[yii\helpers\Html::activeTextInput()]]
- [[yii\helpers\Html::hiddenInput()]], [[yii\helpers\Html::activeHiddenInput()]]
- [[yii\helpers\Html::passwordInput()]] / [[yii\helpers\Html::activePasswordInput()]]
- [[yii\helpers\Html::fileInput()]], [[yii\helpers\Html::activeFileInput()]]
- [[yii\helpers\Html::textarea()]], [[yii\helpers\Html::activeTextarea()]]
Los botones de opción (Radios) y las casillas de verificación (checkboxes) se especifican de forma un poco diferente:
```php
<?= Html::radio('agree', true, ['label' => 'I agree']);
<?= Html::activeRadio($model, 'agree', ['class' => 'agreement'])
<?= Html::checkbox('agree', true, ['label' => 'I agree']);
<?= Html::activeCheckbox($model, 'agree', ['class' => 'agreement'])
```
Las listas desplegables (dropdown list) se pueden renderizar como se muestra a continuación:
```php
<?= Html::dropDownList('list', $currentUserId, ArrayHelper::map($userModels, 'id', 'name')) ?>
<?= Html::activeDropDownList($users, 'id', ArrayHelper::map($userModels, 'id', 'name')) ?>
<?= Html::listBox('list', $currentUserId, ArrayHelper::map($userModels, 'id', 'name')) ?>
<?= Html::activeListBox($users, 'id', ArrayHelper::map($userModels, 'id', 'name')) ?>
```
El primer argumento es el nombre del input, el segundo es el valor seleccionado actualmente y el tercero es el array
de pares clave-valor donde la clave es al lista de valores y el valor del array es la lista a mostrar.
Si se quiere habilitar la selección múltiple, se puede usar la lista seleccionable (checkbox list):
```php
<?= Html::checkboxList('roles', [16, 42], ArrayHelper::map($roleModels, 'id', 'name')) ?>
<?= Html::activeCheckboxList($user, 'role', ArrayHelper::map($roleModels, 'id', 'name')) ?>
```
Si no, se puede usar la lista de opciones (radio list):
```php
<?= Html::radioList('roles', [16, 42], ArrayHelper::map($roleModels, 'id', 'name')) ?>
<?= Html::activeRadioList($user, 'role', ArrayHelper::map($roleModels, 'id', 'name')) ?>
```
### Labels y errores
De forma parecida que en los imputs hay dos métodos para generar labels. El activo que obtiene los datos del modelo y
el no-activo que acepta datos directamente:
```php
<?= Html::label('User name', 'username', ['class' => 'label username']) ?>
<?= Html::activeLabel($user, 'username', ['class' => 'label username'])
```
Para mostrar los errores de un modelo o más en forma de resumen:
```php
<?= Html::errorSummary($posts, ['class' => 'errors']) ?>
```
Para mostrar un error individual:
```php
<?= Html::error($post, 'title', ['class' => 'error']) ?>
```
### Nombres y valores
Existen métodos para obtener nombres, IDs y valores para los campos de entrada (inputs) basados en el modelo. Estos se
usan principalmente internamente pero a veces pueden resultar prácticos:
```php
// Post[title]
echo Html::getInputName($post, 'title');
// post-title
echo Html::getInputId($post, 'title');
// mi primer post
echo Html::getAttributeValue($post, 'title');
// $post->authors[0]
echo Html::getAttributeValue($post, '[0]authors[0]');
```
En el ejemplo anterior, el primer argumento es el modelo y el segundo es el atributo de expresión. En su forma más
simple es su nombre de atributo pero podría ser un nombre de atributo prefijado y/o añadido como sufijo con los
indices de un array, esto se usa principalmente para mostrar inputs en formatos de tablas:
- `[0]content` se usa en campos de entrada de datos en formato de tablas para representar el atributo "content" para
el primer modelo del input en formato de tabla;
- `dates[0]` representa el primer elemento del array del atributo "dates";
- `[0]dates[0]` representa el primer elemento del array del atributo "dates" para el primer modelo en formato de tabla.
Para obtener el nombre de atributo sin sufijos o prefijos se puede usar el siguiente código:
```php
// dates
echo Html::getAttributeName('dates[0]');
```
Estilos y scripts
-----------------
Existen dos métodos para generar etiquetas que envuelvan estilos y scripts incrustados (embebbed):
```php
<?= Html::style('.danger { color: #f00; }') ?>
Genera
<style>.danger { color: #f00; }</style>
<?= Html::script('alert("Hello!");', ['defer' => true]);
Genera
<script defer>alert("Hello!");</script>
```
Si se quiere enlazar un estilo externo desde un archivo CSS:
```php
<?= Html::cssFile('@web/css/ie5.css', ['condition' => 'IE 5']) ?>
genera
<!--[if IE 5]>
<link href="http://example.com/css/ie5.css" />
<![endif]-->
```
El primer argumento es la URL. El segundo es un array de opciones. Adicionalmente, para regular las opciones se puede
especificar:
- `condition` para envolver `<link` con los comentarios condicionales con condiciones especificas. Esperamos que sean
necesarios los comentarios condicionales ;)
- `noscript` se puede establecer como `true` para envolver `<link` con la etiqueta `<noscript>` por lo que el sólo se
incluirá si el navegador no soporta JavaScript o si lo ha deshabilitado el usuario.
Para enlazar un archivo JavaScript:
```php
<?= Html::jsFile('@web/js/main.js') ?>
```
Es igual que con las CSS, el primer argumento especifica el enlace al fichero que se quiere incluir. Las opciones se
pueden pasar como segundo argumento. En las opciones se puede especificar `condition` del mismo modo que se puede usar
para `cssFile`.
Enlaces
-------
Existe un método para generar hipervínculos a conveniencia:
```php
<?= Html::a('Profile', ['user/view', 'id' => $id], ['class' => 'profile-link']) ?>
```
El primer argumento es el titulo. No está codificado por lo que si se usan datos enviados por el usuario se tienen que
codificar usando `Html::encode()`. El segundo argumento es el que se introducirá en `href` de la etiqueta `<a`. Se
puede revisar [Url::to()](helper-url.md) para obtener más detalles de los valores que acepta. El tercer argumento es
un array de las propiedades de la etiqueta.
Si se requiere generar enlaces de tipo `mailto` se puede usar el siguiente código:
```php
<?= Html::mailto('Contact us', 'admin@example.com') ?>
```
Imagenes
--------
Para generar una etiqueta de tipo imagen se puede usar el siguiente ejemplo:
```php
<?= Html::img('@web/images/logo.png', ['alt' => 'My logo']) ?>
genera
<img src="http://example.com/images/logo.png" alt="My logo" />
```
Aparte de los [aliases](concept-aliases.md) el primer argumento puede aceptar rutas, parámetros y URLs. Del mismo modo
que [Url::to()](helper-url.md).
Listas
------
Las listas desordenadas se puede generar como se muestra a continuación:
```php
<?= Html::ul($posts, ['item' => function($item, $index) {
return Html::tag(
'li',
$this->render('post', ['item' => $item]),
['class' => 'post']
);
}]) ?>
```
Para generar listas ordenadas se puede usar `Html::ol()` en su lugar.

156
docs/guide-es/helper-url.md

@ -0,0 +1,156 @@
Clase Auxiliar URL (URL Helper)
===============================
La clase auxiliar URL proporciona un conjunto de métodos estáticos para gestionar URLs.
Obtener URLs Comunes
--------------------
Se pueden usar dos métodos para obtener URLs comunes: URL de inicio (home URL) y URL base (base URL) de la petición
(request) actual. Para obtener la URL de inicio se puede usar el siguiente código:
```php
$relativeHomeUrl = Url::home();
$absoluteHomeUrl = Url::home(true);
$httpsAbsoluteHomeUrl = Url::home('https');
```
Si no se pasan parámetros, las URLs generadas son relativas. Se puede pasar `true`para obtener la URL absoluta del
esquema actual o especificar el esquema explícitamente (`https`, `http`).
Para obtener la URL base de la petición actual, se puede usar el siguiente código:
```php
$relativeBaseUrl = Url::base();
$absoluteBaseUrl = Url::base(true);
$httpsAbsoluteBaseUrl = Url::base('https');
```
El único parámetro del método funciona exactamente igual que para `Url::home()`.
Creación de URLs
----------------
Para crear una URL para una ruta determinada se puede usar `Url::toRoute()`. El metodo utiliza [[\yii\web\UrlManager]]
para crear una URL:
```php
$url = Url::toRoute(['product/view', 'id' => 42]);
```
Se puede especificar la ruta como una cadena de texto, p. ej. `site/index`. También se puede usar un array si se
quieren especificar parámetros para la URL que se esta generando. El formato del array debe ser:
```php
// genera: /index.php?r=site/index&param1=value1&param2=value2
['site/index', 'param1' => 'value1', 'param2' => 'value2']
```
Si se quiere crear una URL con un enlace, se puede usar el formato de array con el parámetro `#`. Por ejemplo,
```php
// genera: /index.php?r=site/index&param1=value1#name
['site/index', 'param1' => 'value1', '#' => 'name']
```
Una ruta puede ser absoluta o relativa. Una ruta absoluta tiene una barra al principio (p. ej. `/site/index`),
mientras que una ruta relativa no la tiene (p. ej. `site/index` o `index`). Una ruta relativa se convertirá en una
ruta absoluta siguiendo las siguientes normas:
- Si la ruta es una cadena vacía, se usará la [[\yii\web\Controller::route|route]] actual;
- Si la ruta no contiene barras (p. ej. `index`), se considerará que es el ID de una acción del controlador actual y
se antepondrá con [[\yii\web\Controller::uniqueId]];
- Si la ruta no tiene barra inicial (p. ej. `site/index`), se considerará que es una ruta relativa del modulo actual y
se le antepondrá el [[\yii\base\Module::uniqueId|uniqueId]] del modulo.
A continuación se muestran varios ejemplos del uso de este método:
```php
// /index?r=site/index
echo Url::toRoute('site/index');
// /index?r=site/index&src=ref1#name
echo Url::toRoute(['site/index', 'src' => 'ref1', '#' => 'name']);
// http://www.example.com/index.php?r=site/index
echo Url::toRoute('site/index', true);
// https://www.example.com/index.php?r=site/index
echo Url::toRoute('site/index', 'https');
```
El otro método `Url::to()` es muy similar a [[toRoute()]]. La única diferencia es que este método requiere que la ruta
especificada sea un array. Si se pasa una cadena de texto, se tratara como una URL.
El primer argumento puede ser:
- un array: se llamará a [[toRoute()]] para generar la URL. Por ejemplo: `['site/index']`,
`['post/index', 'page' => 2]`. Se puede revisar [[toRoute()]] para obtener más detalles acerca de como especificar
una ruta.
- una cadena que empiece por `@`: se tratará como un alias, y se devolverá la cadena correspondiente asociada a este
alias.
- una cadena vacía: se devolverá la URL de la petición actual;
- una cadena de texto: se devolverá sin alteraciones.
Cuando se especifique `$schema` (tanto una cadena de text como `true`), se devolverá una URL con información del host
(obtenida mediante [[\yii\web\UrlManager::hostInfo]]). Si `$url` ya es una URL absoluta, su esquema se reemplazará con
el especificado.
A continuación se muestran algunos ejemplos de uso:
```php
// /index?r=site/index
echo Url::to(['site/index']);
// /index?r=site/index&src=ref1#name
echo Url::to(['site/index', 'src' => 'ref1', '#' => 'name']);
// la URL solicitada actualmente
echo Url::to();
// /images/logo.gif
echo Url::to('@web/images/logo.gif');
// images/logo.gif
echo Url::to('images/logo.gif');
// http://www.example.com/images/logo.gif
echo Url::to('@web/images/logo.gif', true);
// https://www.example.com/images/logo.gif
echo Url::to('@web/images/logo.gif', 'https');
```
Recordar la URL para utilizarla más adelante
--------------------------------------------
Hay casos en que se necesita recordar la URL y después usarla durante el procesamiento de una de las peticiones
secuenciales. Se puede logar de la siguiente manera:
```php
// Recuerda la URL actual
Url::remember();
// Recuerda la URL especificada. Revisar Url::to() para ver formatos de argumentos.
Url::remember(['product/view', 'id' => 42]);
// Recuerda la URL especificada con un nombre asignado
Url::remember(['product/view', 'id' => 42], 'product');
```
En la siguiente petición se puede obtener la URL memorizada de la siguiente manera:
```php
$url = Url::previous();
$productUrl = Url::previous('product');
```
Reconocer la relatividad de URLs
--------------------------------
Para descubrir si una URL es relativa, es decir, que no contenga información del host, se puede utilizar el siguiente
código:
```php
$isRelative = Url::isRelative('test/it');
```

99
docs/guide-es/output-theming.md

@ -0,0 +1,99 @@
Temas
=====
> Nota: Esta sección está en desarrollo.
Un tema (theme) es un directorio de archivos y de vistas (views) y layouts. Cada archivo de este directorio
sobrescribe el archivo correspondiente de una aplicación cuando se renderiza. Una única aplicación puede usar
múltiples temas para que pueden proporcionar experiencias totalmente diferentes. Solo se puede haber un único tema
activo.
> Nota: Los temas no están destinados a ser redistribuidos ya que están demasiado ligados a la aplicación. Si se
quiere redistribuir una apariencia personalizada, se puede considerar la opción de
[asset bundles](structure-assets.md) de archivos CSS y Javascript.
Configuración de un Tema
------------------------
La configuración de un tema se especifica a través del componente `view` de la aplicación. Para establecer que un tema
trabaje con vistas de aplicación básicas, la configuración de la aplicación debe contener lo siguiente:
```php
'components' => [
'view' => [
'theme' => [
'pathMap' => ['@app/views' => '@app/themes/basic'],
'baseUrl' => '@web/themes/basic',
],
],
],
```
En el ejemplo anterior, el `pathMap` define un mapa (map) de las rutas a las que se aplicará el tema mientras que
`baseUrl` define la URL base para los recursos a los que hacen referencia los archivos del tema.
En nuestro caso `pathMap` es `['@app/views' => '@app/themes/basic']`. Esto significa que cada vista de `@app/views`
primero se buscará en `@app/themes/basic` y si existe, se usará la vista del directorio del tema en lugar de la vista
original.
Por ejemplo, con la configuración anterior, la versión del tema para la vista `@app/views/site/index.php` será
`@app/themes/basic/site/index.php`. Básicamente se reemplaza `@app/views` en `@app/views/site/index.php` por
`@app/themes/basic`.
### Temas para Módulos
Para utilizar temas en los módulos, el `pathMap` debe ser similar al siguiente:
```php
'components' => [
'view' => [
'theme' => [
'pathMap' => [
'@app/views' => '@app/themes/basic',
'@app/modules' => '@app/themes/basic/modules', // <-- !!!
],
],
],
],
```
Esto permite aplicar el tema a `@app/modules/blog/views/comment/index.php` con la vista
`@app/themes/basic/modules/blog/views/comment/index.php`.
### Temas para Widgets
Para utilizar un tema en una vista que se encuentre en `@app/widgets/currency/views/index.php`, se debe aplicar la
siguiente configuración para el componente vista, tema:
```php
'components' => [
'view' => [
'theme' => [
'pathMap' => ['@app/widgets' => '@app/themes/basic/widgets'],
],
],
],
```
Con la configuración anterior, se puede crear una versión de la vista `@app/widgets/currency/index.php` para que se
aplique el tema en `@app/themes/basic/widgets/currency/index.php`.
Uso de Multiples Rutas
----------------------
Es posible mapear una única ruta a múltiples rutas de temas. Por ejemplo:
```php
'pathMap' => [
'@app/views' => [
'@app/themes/christmas',
'@app/themes/basic',
],
]
```
En este caso, primero se buscara la vista en `@app/themes/christmas/site/index.php`, si no se encuentra, se intentará
en `@app/themes/basic/site/index.php`. Si la vista no se encuentra en ninguna de rutas especificadas, se usará la
vista de aplicación.
Esta capacidad es especialmente útil si se quieren sobrescribir algunas rutas temporal o condicionalmente.

72
docs/guide-ja/README.md

@ -96,7 +96,7 @@ All Rights Reserved.
データの表示
------------
* [データの書式設定](output-formatter.md)
* [データのフォーマット](output-formatter.md)
* **TBD** [ページネーション](output-pagination.md)
* **TBD** [並べ替え](output-sorting.md)
* [データプロバイダ](output-data-providers.md)
@ -109,10 +109,10 @@ All Rights Reserved.
------------
* [認証](security-authentication.md)
* [権限](security-authorization.md)
* [権限付与](security-authorization.md)
* [パスワードを扱う](security-passwords.md)
* **TBD** [Auth クライアント](security-auth-clients.md)
* **TBD** [最善の慣行](security-best-practices.md)
* [ベストプラクティス](security-best-practices.md)
キャッシュ
@ -128,49 +128,49 @@ All Rights Reserved.
RESTful ウェブサービス
----------------------
* [クイックスタート](rest-quick-start.md)
* [リソース](rest-resources.md)
* [コントローラ](rest-controllers.md)
* [ルーティング](rest-routing.md)
* [レスポンスの書式設定](rest-response-formatting.md)
* [認証](rest-authentication.md)
* [転送レート制限](rest-rate-limiting.md)
* [バージョン管理](rest-versioning.md)
* [エラー処理](rest-error-handling.md)
* **翻訳未着手** [クイックスタート](rest-quick-start.md)
* **翻訳未着手** [リソース](rest-resources.md)
* **翻訳未着手** [コントローラ](rest-controllers.md)
* **翻訳未着手** [ルーティング](rest-routing.md)
* **翻訳未着手** [レスポンスの書式設定](rest-response-formatting.md)
* **翻訳未着手** [認証](rest-authentication.md)
* **翻訳未着手** [転送レート制限](rest-rate-limiting.md)
* **翻訳未着手** [バージョン管理](rest-versioning.md)
* **翻訳未着手** [エラー処理](rest-error-handling.md)
開発ツール
----------
* [デバッグツールバーとデバッガ](tool-debugger.md)
* [Gii を使ってコードを生成する](tool-gii.md)
* **翻訳未着手** [デバッグツールバーとデバッガ](tool-debugger.md)
* **翻訳未着手** [Gii を使ってコードを生成する](tool-gii.md)
* **TBD** [API ドキュメントを生成する](tool-api-doc.md)
テスト
------
* [概要](test-overview.md)
* [テスト環境の構築](test-environment-setup.md)
* [ユニットテスト](test-unit.md)
* [機能テスト](test-functional.md)
* [承認テスト](test-acceptance.md)
* [フィクスチャ](test-fixtures.md)
* **翻訳未着手** [概要](test-overview.md)
* **翻訳未着手** [テスト環境の構築](test-environment-setup.md)
* **翻訳未着手** [ユニットテスト](test-unit.md)
* **翻訳未着手** [機能テスト](test-functional.md)
* **翻訳未着手** [承認テスト](test-acceptance.md)
* **翻訳未着手** [フィクスチャ](test-fixtures.md)
スペシャルトピック
------------------
* [アドバンストアプリケーションテンプレート](tutorial-advanced-app.md)
* [アプリケーションを一から構築する](tutorial-start-from-scratch.md)
* [コンソールコマンド](tutorial-console.md)
* [コアのバリデータ](tutorial-core-validators.md)
* [国際化](tutorial-i18n.md)
* [メール](tutorial-mailing.md)
* [パフォーマンスチューニング](tutorial-performance-tuning.md)
* [共有ホスト環境](tutorial-shared-hosting.md)
* [テンプレートエンジン](tutorial-template-engines.md)
* [サードパーティのコードを扱う](tutorial-yii-integration.md)
* **翻訳未着手** [アドバンストアプリケーションテンプレート](tutorial-advanced-app.md)
* **翻訳未着手** [アプリケーションを一から構築する](tutorial-start-from-scratch.md)
* **翻訳未着手** [コンソールコマンド](tutorial-console.md)
* **翻訳未着手** [コアのバリデータ](tutorial-core-validators.md)
* **翻訳未着手** [国際化](tutorial-i18n.md)
* **翻訳未着手** [メール](tutorial-mailing.md)
* **翻訳未着手** [パフォーマンスチューニング](tutorial-performance-tuning.md)
* **翻訳未着手** [共有ホスト環境](tutorial-shared-hosting.md)
* **翻訳未着手** [テンプレートエンジン](tutorial-template-engines.md)
* **翻訳未着手** [サードパーティのコードを扱う](tutorial-yii-integration.md)
ウィジェット
@ -184,16 +184,16 @@ RESTful ウェブサービス
* Menu: **TBD** link to demo page
* LinkPager: **TBD** link to demo page
* LinkSorter: **TBD** link to demo page
* [Bootstrap ウィジェット](widget-bootstrap.md)
* [Jquery UI ウィジェット](widget-jui.md)
* **翻訳未着手** [Bootstrap ウィジェット](widget-bootstrap.md)
* **翻訳未着手** [Jquery UI ウィジェット](widget-jui.md)
ヘルパ
------
* [概要](helper-overview.md)
* [ArrayHelper](helper-array.md)
* **TBD** [Html](helper-html.md)
* [Url](helper-url.md)
* **翻訳未着手** [概要](helper-overview.md)
* **翻訳未着手** [ArrayHelper](helper-array.md)
* **翻訳未着手** [Html](helper-html.md)
* **翻訳未着手** [Url](helper-url.md)
* **TBD** [Security](helper-security.md)

126
docs/guide-ja/concept-aliases.md

@ -0,0 +1,126 @@
エイリアス
=======
ファイルパスや URL を表すのにエイリアスを使用すると、あなたはプロジェクト内で絶対パスや URL をハードコードする必要がなくなります。エイリアスは、通常のファイルパスや URL と区別するために、 `@` 文字で始まる必要があります。Yii はすでに利用可能な多くの事前定義エイリアスを持っています。
たとえば、 `@yii` というエイリアスは Yii フレームワークのインストールパスを表し、 `@web` は現在実行中の Web アプリケーションのベース URL を表します。
エイリアスの定義 <a name="defining-aliases"></a>
----------------
[[Yii::setAlias()]] を呼び出すことにより、ファイルパスまたは URL のエイリアスを定義することができます。
```php
// ファイルパスのエイリアス
Yii::setAlias('@foo', '/path/to/foo');
// URL のエイリアス
Yii::setAlias('@bar', 'http://www.example.com');
```
> 補足: エイリアスされているファイルパスやURLは、必ずしも実在するファイルまたはリソースを参照しない場合があります。
定義済みのエイリアスがあれば、スラッシュ `/` に続けて 1 つ以上のパスセグメントを追加することで([[Yii::setAlias()]]
の呼び出しを必要とせずに) 新しいエイリアスを導出することができます。 [[Yii::setAlias()]] を通じて定義されたエイリアスは
*ルートエイリアス* となり、それから派生したエイリアスは *派生エイリアス* になります。たとえば、 `@foo` がルートエイリアスなら、
`@foo/bar/file.php` は派生エイリアスです。
エイリアスを、他のエイリアス (ルートまたは派生のいずれか) を使用して定義することができます:
```php
Yii::setAlias('@foobar', '@foo/bar');
```
ルートエイリアスは通常、 [ブートストラップ](runtime-bootstrapping.md) 段階で定義されます。
たとえば、[エントリスクリプト](structure-entry-scripts.md) で [[Yii::setAlias()]] を呼び出すことができます。
便宜上、 [アプリケーション](structure-applications.md) は、`aliases` という名前の書き込み可能なプロパティを提供しており、
それをアプリケーションの [構成情報](concept-configurations.md) で設定することが可能です。
```php
return [
// ...
'aliases' => [
'@foo' => '/path/to/foo',
'@bar' => 'http://www.example.com',
],
];
```
エイリアスの解決 <a name="resolving-aliases"></a>
-----------------
[[Yii::getAlias()]] を呼び出して、ルートエイリアスが表すファイルパスまたはURLを解決することができます。
同メソッドで、対応するファイルパスまたはURLに派生するエイリアスを解決することもできます。
```php
echo Yii::getAlias('@foo'); // /path/to/foo を表示
echo Yii::getAlias('@bar'); // http://www.example.com を表示
echo Yii::getAlias('@foo/bar/file.php'); // /path/to/foo/bar/file.php を表示
```
派生エイリアスによって表されるパスやURLは、派生エイリアス内のルートエイリアス部分を、対応するパス/URL
で置換して決定されます。
> 補足: [[Yii::getAlias()]] メソッドは、 結果のパスやURLが実在するファイルやリソースを参照しているかをチェックしません。
ルートエイリアス名にはスラッシュ `/` 文字を含むことができます。 [[Yii::getAlias()]] メソッドは、
エイリアスのどの部分がルートエイリアスであるかを賢く判別し、正確に対応するファイルパスやURLを決定します:
```php
Yii::setAlias('@foo', '/path/to/foo');
Yii::setAlias('@foo/bar', '/path2/bar');
Yii::getAlias('@foo/test/file.php'); // /path/to/foo/test/file.php を表示
Yii::getAlias('@foo/bar/file.php'); // /path2/bar/file.php を表示
```
もし `@foo/bar` がルートエイリアスとして定義されていなければ、最後のステートメントは `/path/to/foo/bar/file.php` を表示します。
エイリアスの使用 <a name="using-aliases"></a>
-------------
エイリアスは、それをパスやURLに変換するための [[Yii::getAlias()]] の呼び出しがなくても、Yiiの多くの場所でみられます。
たとえば、 [[yii\caching\FileCache::cachePath]] ファイルパスとファイルパスを表すエイリアスの両方を受け入れることができ、
`@` プレフィックスによって、エイリアスとファイルパスを区別することができます。
```php
use yii\caching\FileCache;
$cache = new FileCache([
'cachePath' => '@runtime/cache',
]);
```
プロパティやメソッドのパラメータがエイリアスをサポートしているかどうかは、API ドキュメントに注意を払ってください。
事前定義されたエイリアス <a name="predefined-aliases"></a>
------------------
Yii では、一般的に使用されるファイルのパスと URL を簡単に参照できるよう、エイリアスのセットが事前に定義されています:
- `@yii`, `BaseYii.php` ファイルがあるディレクトリ (フレームワークディレクトリとも呼ばれます)
- `@app`, 現在実行中のアプリケーションの [[yii\base\Application::basePath|ベースパス]]
- `@runtime`, 現在実行中のアプリケーションの [[yii\base\Application::runtimePath|ランタイムパス]] 。デフォルトは `@app/runtime`
- `@webroot`, 現在実行中の Web アプリケーションの Web ルートディレクトリ。エントリスクリプトを含むディレクトリをもとに決定されます。
- `@web`, 現在実行中の Web アプリケーションのベース URL。これは、 [[yii\web\Request::baseUrl]] と同じ値を持ちます。
- `@vendor`, [[yii\base\Application::vendorPath|Composerのベンダーディレクトリ]] 。デフォルトは `@app/vendor`
- `@bower`, [bower パッケージ](http://bower.io/) が含まれるルートディレクトリ。デフォルトは `@vendor/bower`
- `@npm`, [npm パッケージ](https://www.npmjs.org/) が含まれるルートディレクトリ。デフォルトは `@vendor/npm`
`@yii` エイリアスは [エントリスクリプト](structure-entry-scripts.md) に `Yii.php` ファイルを読み込んだ時点で定義されます。
エイリアスの残りの部分は、アプリケーションのコンストラクタ内で、アプリケーションの [構成情報](concept-configurations.md) を適用するときに定義されます。
エクステンションのエイリアス <a name="extension-aliases"></a>
-----------------
Composer でインストールされる各 [エクステンション](structure-extensions.md) ごとに、エイリアスが自動的に定義されます。
各エイリアスは、その `composer.json` ファイルで宣言された、エクステンションのルート名前空間にちなんで名付けられており、
それらは、パッケージのルートディレクトリを表します。たとえば、あなたが `yiisoft/yii2-jui` エクステンションをインストールしたとすると、
自動的に `@yii/jui` というエイリアスができ、 [ブートストラップ](runtime-bootstrapping.md) 段階で、次のと同等のものとして定義されます:
```php
Yii::setAlias('@yii/jui', 'VendorPath/yiisoft/yii2-jui');
```

88
docs/guide-ja/concept-autoloading.md

@ -0,0 +1,88 @@
クラスのオートローディング
=================
Yiiは、必要となるすべてのクラスファイルを、特定してインクルードするにあたり、 [クラスのオートローディングメカニズム](http://www.php.net/manual/en/language.oop5.autoload.php)
を頼りにします。[PSR-4 標準](https://github.com/php-fig/fig-standards/blob/master/proposed/psr-4-autoloader/psr-4-autoloader.md) に準拠した、高性能なクラスのオートローダーを提供します。
このオートローダーは、あなたが `Yii.php` ファイルをインクルードするときにインストールされます。
> 補足: 説明を簡単にするため、このセクションではクラスのオートローディングについてのみお話しします。しかし、
ここに記述されている内容は、同様に、インタフェースとトレイトのオートロードにも適用されることに注意してください。
Yii オートローダーの使用 <a name="using-yii-autoloader"></a>
------------------------
Yii のクラスオートローダーを使用するには、自分のクラスを作成して名前を付けるとき、次の2つの単純なルールに従わなければなりません:
* 各クラスは名前空間の下になければなりません (例 `foo\bar\MyClass`)
* 各クラスは次のアルゴリズムで決定される個別のファイルに保存されなければなりません:
```php
// $className は先頭にバックスラッシュを持つ完全修飾名
$classFile = Yii::getAlias('@' . str_replace('\\', '/', $className) . '.php');
```
たとえば、クラス名と名前空間が `foo\bar\MyClass` であれば、対応するクラスファイルのパスの [エイリアス](concept-aliases.md) は、
`@foo/bar/MyClass.php` になります。このエイリアスがファイルパスになるようにするには、`@foo` または `@foo/bar`
のどちらかが、 [ルートエイリアス](concept-aliases.md#defining-aliases) でなければなりません。
[Basic Application Template](start-basic.md) を使用している場合、最上位の名前空間 `app` の下にクラスを置くことができ、
そうすると、新しいエイリアスを定義しなくても、Yii によってそれらをオートロードできるようになります。これは `@app`
が [事前定義されたエイリアス](concept-aliases.md#predefined-aliases) であるためで、`app\components\MyClass` のようなクラス名を
今説明したアルゴリズムに従って、クラスファイル `AppBasePath/components/MyClass.php` だと解決できるのです。
[Advanced Application Template](tutorial-advanced-app.md) では、各階層にそれ自身のルートエイリアスを持っています。たとえば、
フロントエンド層はルートエイリアス `@frontend` を持ち、バックエンド層は `@backend` です。その結果、名前空間 `frontend` の下に
フロントエンドクラスを置き、バックエンドクラスを `backend` の下に置けます。これで、これらのクラスは Yii のオートローダーによって
オートロードできるようになります。
クラスマップ <a name="class-map"></a>
---------
Yii のクラスオートローダーは、 *クラスマップ* 機能をサポートしており、クラス名を対応するクラスファイルのパスにマップできます。
オートローダーがクラスをロードしているとき、クラスがマップに見つかるかどうかを最初にチェックします。もしあれば、対応する
ファイルのパスは、それ以上チェックされることなく、直接インクルードされます。これでクラスのオートローディングを非常に高速化できます。
実際に、すべての Yii のコアクラスは、この方法でオートロードされています。
次の方法で、 `Yii::$classMap` に格納されるクラスマップにクラスを追加できます:
```php
Yii::$classMap['foo\bar\MyClass'] = 'path/to/MyClass.php';
```
クラスファイルのパスを指定するのに、 [エイリアス](concept-aliases.md) を使うことができます。クラスが使用される前にマップが準備できるように、
[ブートストラップ](runtime-bootstrapping.md) プロセス内でクラスマップを設定する必要があります。
他のオートローダーの使用 <a name="using-other-autoloaders"></a>
-----------------------
Yii はパッケージ依存関係マネージャとして Composer を包含しているので、Composer のオートローダーもインストールすることをお勧めします。
あなたが独自のオートローダーを持つサードパーティライブラリを使用している場合、それらもインストールする必要があります。
Yii オートローダーを他のオートローダーと一緒に使うときは、他のすべてのオートローダーがインストールされた *後で*`Yii.php`
ファイルをインクルードする必要があります。これで Yii のオートローダーが、任意クラスのオートローディング要求に応答する最初のものになります。
たとえば、次のコードは [Basic Application Template](start-basic.md) の [エントリスクリプト](structure-entry-scripts.md) から抜粋したものです。
最初の行は、Composer のオートローダーをインストールしており、二行目は Yii のオートローダーをインストールしています。
```php
require(__DIR__ . '/../vendor/autoload.php');
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
```
あなたは Yii のオートローダーを使わず、Composer のオートローダーだけを単独で使用することもできます。しかし、そうすることによって、
あなたのクラスのオートローディングのパフォーマンスは低下し、クラスをオートロード可能にするために Composer が設定したルールに従わなければならなくなります。
> Info: Yiiのオートローダーを使用したくない場合は、 `Yii.php` ファイルの独自のバージョンを作成し、
それを [エントリスクリプト](structure-entry-scripts.md) でインクルードする必要があります。
エクステンションクラスのオートロード <a name="autoloading-extension-classes"></a>
-----------------------------
Yii のオートローダーは、 [エクステンション](structure-extensions.md) クラスのオートロードが可能です。唯一の要件は、
エクステンションがその `composer.json` ファイルに正しく `autoload` セクションを指定していることです。
`autoload` 指定方法の詳細については [Composer のドキュメント](https://getcomposer.org/doc/04-schema.md#autoload) 参照してください。
Yii のオートローダーを使用しない場合でも、まだ Composer のオートローダーはエクステンションクラスをオートロード可能です。

332
docs/guide-ja/concept-behaviors.md

@ -0,0 +1,332 @@
ビヘイビア
=========
ビヘイビアは [[yii\base\Behavior]] 、あるいはその子クラスのインスタンスです。ビヘイビアは
[ミックスイン](http://en.wikipedia.org/wiki/Mixin) としても知られ、既存の [[yii\base\Component|component]] クラスの
機能を、クラスの継承を変更せずに拡張することができます。コンポーネントにビヘイビアをアタッチすると、その
コンポーネントにはビヘイビアのメソッドとプロパティが "注入" され、それらのメソッドとプロパティは、
コンポーネントクラス自体に定義されているかのようにアクセスできるようになります。また、ビヘイビアは、
コンポーネントによってトリガされた [イベント](concept-events.md) に応答することができるので、
ビヘイビアでコンポーネントの通常のコード実行をカスタマイズすることができます。
ビヘイビアの定義 <a name="defining-behaviors"></a>
------------------
ビヘイビアを定義するには、 [[yii\base\Behavior]] あるいは子クラスを継承するクラスを作成します。たとえば:
```php
namespace app\components;
use yii\base\Behavior;
class MyBehavior extends Behavior
{
public $prop1;
private $_prop2;
public function getProp2()
{
return $this->_prop2;
}
public function setProp2($value)
{
$this->_prop2 = $value;
}
public function foo()
{
// ...
}
}
```
上のコードは、 `app\components\MyBehavior` という、2つのプロパティ -- `prop1``prop2` -- と
`foo()` メソッドを持つビヘイビアクラスを定義します。`prop2` プロパティは、 `getProp2()` getter メソッドと `setProp2()` setter メソッドで定義されることに着目してください。
[[yii\base\Behavior]] は [[yii\base\Object]] を継承しているので、getter と setter による [プロパティ](concept-properties.md) 定義をサポートします。
このクラスはビヘイビアなので、コンポーネントにアタッチされると、そのコンポーネントは `prop1``prop2` プロパティ、それと `foo()` メソッドを持つようになります。
> Tip: ビヘイビア内から、[[yii\base\Behavior::owner]] プロパティを介して、ビヘイビアをアタッチしたコンポーネントにアクセスすることができます。
コンポーネントイベントのハンドリング
------------------
ビヘイビアが、アタッチされたコンポーネントがトリガするイベントに応答する必要がある場合は、
[[yii\base\Behavior::events()]] メソッドをオーバーライドしましょう。たとえば:
```php
namespace app\components;
use yii\db\ActiveRecord;
use yii\base\Behavior;
class MyBehavior extends Behavior
{
// ...
public function events()
{
return [
ActiveRecord::EVENT_BEFORE_VALIDATE => 'beforeValidate',
];
}
public function beforeValidate($event)
{
// ...
}
}
```
[[yii\base\Behavior::events()]] メソッドは、イベントとそれに対応するハンドラのリストを返します。
上の例では [[yii\db\ActiveRecord::EVENT_BEFORE_VALIDATE|EVENT_BEFORE_VALIDATE]] イベントがあること、
そのハンドラ定義である `beforeValidate()` を宣言しています。イベントハンドラを指定するときは、以下の表記方法が使えます:
* ビヘイビアクラスのメソッド名を参照する文字列 (上の例など)
* オブジェクトまたはクラス名と文字列のメソッド名 (括弧なし) 例 `[$object, 'methodName']`
* 無名関数
イベントハンドラのシグネチャは次のようにしてください。`$event` はイベントのパラメータを参照します。イベントの詳細については
[イベント](concept-events.md) セクションを参照してください。
```php
function ($event) {
}
```
ビヘイビアのアタッチ <a name="attaching-behaviors"></a>
-------------------
[[yii\base\Component|component]] へのビヘイビアのアタッチは、静的にも動的にも可能です。実際は、前者のほうがより一般的ですが。
ビヘイビアを静的にアタッチするには、ビヘイビアをアタッチしたいコンポーネントクラスの [[yii\base\Component::behaviors()|behaviors()]] メソッドをオーバーライドします。
[[yii\base\Component::behaviors()|behaviors()]] メソッドは、ビヘイビアの [構成](concept-configurations.md) のリストを返さなければなりません。
各ビヘイビアの構成内容は、ビヘイビアのクラス名でも、構成情報配列でもかまいません。
```php
namespace app\models;
use yii\db\ActiveRecord;
use app\components\MyBehavior;
class User extends ActiveRecord
{
public function behaviors()
{
return [
// 無名ビヘイビア ビヘイビアクラス名のみ
MyBehavior::className(),
// 名前付きビヘイビア ビヘイビアクラス名のみ
'myBehavior2' => MyBehavior::className(),
// 無名ビヘイビア 構成情報配列
[
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop2' => 'value2',
],
// 名前付きビヘイビア 構成情報配列
'myBehavior4' => [
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop2' => 'value2',
]
];
}
}
```
ビヘイビア構成に対応する配列のキーを指定することによって、ビヘイビアに名前を関連付けることができます。この場合、ビヘイビアは *名前付きビヘイビア* と呼ばれます。上の例では、2つの名前付きビヘイビア
`myBehavior2``myBehavior4` があります。ビヘイビアが名前と関連付けられていない場合は、 *無名ビヘイビア* と呼ばれます。
ビヘイビアを動的にアタッチするには、ビヘイビアをアタッチしようとしているコンポーネントの [[yii\base\Component::attachBehavior()]] メソッドを呼びます:
```php
use app\components\MyBehavior;
// ビヘイビアオブジェクトをアタッチ
$component->attachBehavior('myBehavior1', new MyBehavior);
// ビヘイビアクラスをアタッチ
$component->attachBehavior('myBehavior2', MyBehavior::className());
// 構成情報配列をアタッチ
$component->attachBehavior('myBehavior3', [
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop2' => 'value2',
]);
```
[[yii\base\Component::attachBehaviors()]] メソッドを使うと、いちどに複数のビヘイビアをアタッチできます:
```php
$component->attachBehaviors([
'myBehavior1' => new MyBehavior, // 名前付きビヘイビア
MyBehavior::className(), // 無名ビヘイビア
]);
```
次のように、 [構成情報](concept-configurations.md) を通じてビヘイビアをアタッチすることもできます:
```php
[
'as myBehavior2' => MyBehavior::className(),
'as myBehavior3' => [
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop2' => 'value2',
],
]
```
詳しくは [構成情報](concept-configurations.md#configuration-format) セクションを参照してください。
ビヘイビアの使用 <a name="using-behaviors"></a>
---------------
ビヘイビアを使用するには、まず上記の方法に従って [[yii\base\Component|コンポーネント]] にアタッチします。ビヘイビアがコンポーネントにアタッチされれば、その使用方法はシンプルです。
あなたは、アタッチされているコンポーネントを介して、ビヘイビアの *パブリック* メンバ変数、または getter や setter によって定義されたプロパティにアクセスすることができます:
```php
// "prop1" はビヘイビアクラス内で定義されたプロパティ
echo $component->prop1;
$component->prop1 = $value;
```
また同様に、ビヘイビアの *パブリック* メソッドも呼ぶことができます:
```php
// foo() はビヘイビアクラス内で定義されたパブリックメソッド
$component->foo();
```
ご覧のように、 `$component``prop1``foo()` を定義していないにもかかわらず、
アタッチされたビヘイビアによって、それらをコンポーネント定義の一部であるかのように使うことができるのです。
もし2つのビヘイビアが同じプロパティやメソッドを定義し、かつ両方とも同じコンポーネントにアタッチされている場合は、
プロパティやメソッドのアクセス時に、*最初に* コンポーネントにアタッチされたビヘイビアが優先されます。
ビヘイビアはコンポーネントにアタッチされるとき、名前と関連付けられているかもしれません。その場合、
その名前を使用してビヘイビアオブジェクトにアクセスすることができます:
```php
$behavior = $component->getBehavior('myBehavior');
```
また、コンポーネントにアタッチされた全てのビヘイビアを取得することもできます:
```php
$behaviors = $component->getBehaviors();
```
ビヘイビアのデタッチ <a name="detaching-behaviors"></a>
-------------------
ビヘイビアをデタッチするには、ビヘイビアに付けられた名前とともに [[yii\base\Component::detachBehavior()]] を呼び出します:
```php
$component->detachBehavior('myBehavior1');
```
*全ての* ビヘイビアをデタッチすることもできます:
```php
$component->detachBehaviors();
```
`TimestampBehavior` の利用 <a name="using-timestamp-behavior"></a>
-------------------------
しめくくりに、[[yii\behaviors\TimestampBehavior]] を見てみましょう。このビヘイビアは、
保存時 (つまり挿入や更新) に、[[yii\db\ActiveRecord|アクティブレコード]] モデルの
タイムスタンプ属性の自動更新をサポートします。
まず、使用しようと考えている [[yii\db\ActiveRecord|アクティブレコード]] クラスに、このビヘイビアをアタッチします:
```php
namespace app\models\User;
use yii\db\ActiveRecord;
use yii\behaviors\TimestampBehavior;
class User extends ActiveRecord
{
// ...
public function behaviors()
{
return [
[
'class' => TimestampBehavior::className(),
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => ['created_at', 'updated_at'],
ActiveRecord::EVENT_BEFORE_UPDATE => ['updated_at'],
],
],
];
}
}
```
上のビヘイビア構成は、レコードが:
* 挿入されるとき、ビヘイビアは現在のタイムスタンプを `created_at``updated_at` 属性に割り当てます
* 更新されるとき、ビヘイビアは現在のタイムスタンプを `updated_at` 属性に割り当てます
所定の位置にそのコードを使用すると、もし `User` オブジェクトを設け、それを保存しようとしたら、そこで、
`created_at``updated_at` が自動的に現在のタイムスタンプで埋められます。
```php
$user = new User;
$user->email = 'test@example.com';
$user->save();
echo $user->created_at; // 現在のタイムスタンプが表示される
```
[[yii\behaviors\TimestampBehavior|TimestampBehavior]] は、指定された属性に現在のタイムスタンプを割り当てて
それをデータベースに保存する、便利なメソッド [[yii\behaviors\TimestampBehavior::touch()|touch()]] を提供します。
```php
$user->touch('login_time');
```
ビヘイビアとトレイトの比較 <a name="comparison-with-traits"></a>
----------------------
ビヘイビアは、主となるクラスにそのプロパティやメソッドを「注入する」という点で [トレイト](http://www.php.net/traits)
に似ていますが、これらは多くの面で異なります。以下に説明するように、それらは互いに長所と短所を持っています。
それらは代替手段というよりも、むしろ相互補完関係のようなものです。
### ビヘイビアを使う理由 <a name="pros-for-behaviors"></a>
ビヘイビアは通常のクラスのように、継承をサポートしています。いっぽうトレイトは、
言語サポートされたコピー&ペーストとみなすことができます。トレイトは継承をサポートしません。
ビヘイビアは、コンポーネントクラスの変更を必要とせずに、動的なコンポーネントへのアタッチとデタッチが可能です。トレイトを使用するには、クラスをトレイトを使って書き換える必要があります。
ビヘイビアは構成可能ですがトレイトは不可能です。
ビヘイビアは、イベントに応答することで、コンポーネントのコード実行をカスタマイズできます。
同じコンポーネントにアタッチされた異なるビヘイビア間で名前の競合がある場合、その競合は自動的に、
先にコンポーネントにアタッチされたものを優先することで解消されます。
別のトレイトが起こした名前競合の場合、影響を受けるプロパティやメソッドの名前変更による、手動での解決が必要です。
### トレイトを使う理由 <a name="pros-for-traits"></a>
ビヘイビアは時間もメモリも食うオブジェクトなので、トレイトはビヘイビアよりはるかに効率的です。
トレイトは言語構造であるため、IDE との相性に優れています。

90
docs/guide-ja/concept-components.md

@ -0,0 +1,90 @@
コンポーネント
==========
コンポーネントは、Yiiアプリケーションの主要な構成ブロックです。コンポーネントは [[yii\base\Component]] 、
またはその派生クラスのインスタンスです。コンポーネントが他のクラスに提供する主な機能は次の 3 つです:
* [プロパティ](concept-properties.md)
* [イベント](concept-events.md)
* [ビヘイビア](concept-behaviors.md)
個々にでも、組み合わせでも、これらの機能は Yii のクラスのカスタマイズ性と使いやすさをとても高めてくれます。たとえば、[[yii\jui\DatePicker|日付選択]] を行うユーザインターフェース·コンポーネントは、
対話型の日付選択UIを生成するとき、ビューで次のように使用することができます:
```php
use yii\jui\DatePicker;
echo DatePicker::widget([
'language' => 'ja',
'name' => 'country',
'clientOptions' => [
'dateFormat' => 'yy-mm-dd',
],
]);
```
クラスが [[yii\base\Component]] を継承しているおかげで、ウィジェットのプロパティは簡単に記述できます。
コンポーネントは非常に強力ですが、 [イベント](concept-events.md) と [ビヘイビア](concept-behaviors.md) をサポートするため、
余分にメモリとCPU時間を要し、通常のオブジェクトよりも少し重くなります。
あなたのコンポーネントがこれら2つの機能を必要としない場合、[[yii\base\Component]] の代わりに、 [[yii\base\Object]] からコンポーネントクラスを派生することを検討してもよいでしょう。
そうすることで、あなたのコンポーネントは、 [プロパティ](concept-properties.md) のサポートが維持されたまま、通常のPHPオブジェクトのように効率的になります。
[[yii\base\Component]] または [[yii\base\Object]] からクラスを派生するときは、次の規約に従うことが推奨されます:
- コンストラクタをオーバーライドする場合は、コンストラクタの *最後の* パラメータとして `$config` パラメータを指定し、親のコンストラクタにこのパラメータを渡すこと。
- 自分がオーバーライドしたコンストラクタの *最後で* 、必ず親クラスのコンストラクタを呼び出すこと。
- [[yii\base\Object::init()]] メソッドをオーバーライドする場合は、自分の `init` メソッドの *最初に* 、必ず `init` の親実装を呼び出すようにすること。
例:
```php
namespace yii\components\MyClass;
use yii\base\Object;
class MyClass extends Object
{
public $prop1;
public $prop2;
public function __construct($param1, $param2, $config = [])
{
// ... 構成前の初期化
parent::__construct($config);
}
public function init()
{
parent::init();
// ... 構成後の初期化
}
}
```
このガイドラインに従うことで、あなたのコンポーネントは生成時に [コンフィグ可能](concept-configurations.md) になります。例:
```php
$component = new MyClass(1, 2, ['prop1' => 3, 'prop2' => 4]);
// とする代わりに
$component = \Yii::createObject([
'class' => MyClass::className(),
'prop1' => 3,
'prop2' => 4,
], [1, 2]);
```
> 補足: [[Yii::createObject()]] を呼び出すアプローチは複雑に見えますが、より強力です。というのも、それが [依存性注入コンテナ](concept-di-container.md) 上に実装されているからです。
[[yii\base\Object]] クラスには、次のオブジェクトライフサイクルが適用されます:
1. コンストラクタ内の事前初期化。ここでデフォルトのプロパティ値を設定することができます。
2. `$config` によるオブジェクトの構成。構成情報は、コンストラクタ内で設定されたデフォルト値を上書きすることがあります。
3. [[yii\base\Object::init()|init()]] 内の事後初期化。サニティ・チェックやプロパティの正規化を行いたいときは、このメソッドをオーバーライドします。
4. オブジェクトのメソッド呼び出し。
最初の 3 つのステップは、すべてのオブジェクトのコンストラクタ内で発生します。これは、あなたがクラスインスタンス (つまり、オブジェクト) を得たときには、
すでにそのオブジェクトが適切な、信頼性の高い状態に初期化されていることを意味します。

260
docs/guide-ja/concept-configurations.md

@ -0,0 +1,260 @@
構成情報
==============
新しいオブジェクトを作成したり、既存のオブジェクトを初期化するとき、Yiiでは構成情報が広く使用されています。構成情報は通常、作成されるオブジェクトのクラス名、およびオブジェクトの [プロパティ](concept-properties.md)
に割り当てられる初期値のリストを含みます。構成情報は、オブジェクトの [イベント](concept-events.md) にアタッチされるハンドラのリストや、オブジェクトにアタッチされる
[ビヘイビア](concept-behaviors.md) のリストを含むこともできます。
以下では、データベース接続を作成して初期化するために、構成情報が使用されています:
```php
$config = [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
];
$db = Yii::createObject($config);
```
[[Yiiの::CreateObject()]] メソッドは引数に構成情報の配列を受け取り、構成情報で名前指定されたクラスをインスタンス化してオブジェクトを作成します。オブジェクトがインスタンス化されるとき、その他の設定は、
オブジェクトのプロパティ、イベントハンドラ、およびビヘイビアを初期化するのに使われます。
すでにオブジェクトがある場合は、構成情報配列でオブジェクトのプロパティを初期化するのに [[Yii::configure()]] を使用することができます:
```php
Yii::configure($object, $config);
```
なお、この場合には、構成情報配列に `class` 要素を含んではいけません。
## 構成情報の形式 <a name="configuration-format"></a>
構成情報の形式は、フォーマルには次のように説明できます:
```php
[
'class' => 'ClassName',
'propertyName' => 'propertyValue',
'on eventName' => $eventHandler,
'as behaviorName' => $behaviorConfig,
]
```
ここで
* `class` 要素は、作成されるオブジェクトの完全修飾クラス名を指定します。
* `propertyName` 要素は、名前で指定されたプロパティの初期値を指定します。キーはプロパティ名で、値はそれに対応する初期値です。
パブリックメンバ変数と getter/setter によって定義されている [プロパティ](concept-properties.md) のみを設定することができます。
* `on eventName` 要素は、どのようなハンドラがオブジェクトの [イベント](concept-events.md) にアタッチされるかを指定します。
配列のキーが `on` に続けてイベント名という書式になることに注意してください。サポートされているイベントハンドラの形式については、
[イベント](concept-events.md) のセクションを参照してください。
* `as behaviorName` 要素は、どのような [ビヘイビア](concept-behaviors.md) がオブジェクトにアタッチされるかを指定します。
配列のキーが `as` に続けてビヘイビア名という書式になり、 `$behaviorConfig` で示される値が、ここで説明する一般的な構成情報のような、
ビヘイビアを作成するための構成情報になることに注意してください。
下記は、初期プロパティ値、イベントハンドラ、およびビヘイビアでの構成を示した例です:
```php
[
'class' => 'app\components\SearchEngine',
'apiKey' => 'xxxxxxxx',
'on search' => function ($event) {
Yii::info("Keyword searched: " . $event->keyword);
},
'as indexer' => [
'class' => 'app\components\IndexerBehavior',
// ... プロパティ初期値 ...
],
]
```
## 構成情報の使用 <a name="using-configurations"></a>
構成情報は Yii の多くの場所で使用されています。このセクションの冒頭では、 [[Yii::createObject()]]
を使って、構成情報に応じてオブジェクトを作成する方法を示しました。このサブセクションでは、
アプリケーションの構成とウィジェットの構成という、2つの主要な構成情報の用途を説明します。
### アプリケーションの構成 <a name="application-configurations"></a>
[アプリケーション](structure-applications.md) の構成は、おそらく Yii の中で最も複雑な配列のひとつです。
それは [[yii\web\Application|application]] クラスが、設定可能なプロパティとイベントを数多く持つためです。
さらに重要なことは、その [[yii\web\Application::components|components]] プロパティが、アプリケーションに登録されている
コンポーネント生成用の構成情報配列を受け取ることができることです。以下は、 [basic application template](start-basic.md)
のアプリケーション構成ファイルの概要です。
```php
$config = [
'id' => 'basic',
'basePath' => dirname(__DIR__),
'extensions' => require(__DIR__ . '/../vendor/yiisoft/extensions.php'),
'components' => [
'cache' => [
'class' => 'yii\caching\FileCache',
],
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
],
'log' => [
'class' => 'yii\log\Dispatcher',
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
],
],
],
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=stay2',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
],
],
];
```
この構成情報には、 `class` キーがありません。それは、[エントリスクリプト](structure-entry-scripts.md) で以下のように、
クラス名が既に与えられて使用されているためです。
```php
(new yii\web\Application($config))->run();
```
アプリケーションの `components` プロパティ構成の詳細については、 [アプリケーション](structure-applications.md) セクションと [サービスロケータ](concept-service-locator.md) セクションにあります。
### ウィジェットの構成 <a name="widget-configurations"></a>
[ウィジェット](structure-widgets.md) を使用するときは、多くの場合、ウィジェットのプロパティをカスタマイズするために、構成情報を使用する必要があります。
[[yii\base\Widget::widget()]] と [[yii\base\Widget::begin()]] の両メソッドを使って、ウィジェットを作成できます。それらは、以下のような構成情報配列を取ります。
```php
use yii\widgets\Menu;
echo Menu::widget([
'activateItems' => false,
'items' => [
['label' => 'ホーム', 'url' => ['site/index']],
['label' => '製品', 'url' => ['product/index']],
['label' => 'ログイン', 'url' => ['site/login'], 'visible' => Yii::$app->user->isGuest],
],
]);
```
上記のコードは、 `Menu` ウィジェットを作成し、その `activateItems` プロパティが `false` になるよう初期化します。
`items` プロパティも、表示されるメニュー項目で構成されます。
クラス名がすでに与えられているので、構成情報配列が `class` キーを持つべきではないことに注意してください。
## 構成情報ファイル <a name="configuration-files"></a>
構成情報がとても複雑になる場合、一般的な方法は、 *構成情報ファイル* と呼ばれる、ひとつまたは複数の PHP ファイルにそれを格納することです。
構成情報ファイルは、構成情報を表す PHP 配列を return します。
たとえば、次のように、 `web.php` と名づけたファイルにアプリケーション構成を保持することができます。
```php
return [
'id' => 'basic',
'basePath' => dirname(__DIR__),
'extensions' => require(__DIR__ . '/../vendor/yiisoft/extensions.php'),
'components' => require(__DIR__ . '/components.php'),
];
```
`components` の構成もまた複雑になるため、上記のように、 `components.php` と呼ぶ別のファイルにそれを格納し `web.php` でそのファイルを "require" しています。
この `components.php` の内容は、次のようになっています。
```php
return [
'cache' => [
'class' => 'yii\caching\FileCache',
],
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
],
'log' => [
'class' => 'yii\log\Dispatcher',
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
],
],
],
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=stay2',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
],
];
```
構成情報ファイルに格納されている構成情報を取得するには、以下のように、それを "require" するだけです:
```php
$config = require('path/to/web.php');
(new yii\web\Application($config))->run();
```
## デフォルト設定 <a name="default-configurations"></a>
[[Yii::createObject()]] メソッドは、 [依存性注入コンテナ](concept-di-container.md) をベースに実装されています。
そのため、指定されたクラスが [[Yii::createObject()]] を使用して作成されるとき、そのすべてのインスタンスに適用される、
いわゆる *デフォルト設定* のセットを指定することができます。デフォルト設定は、
[ブートストラップ](runtime-bootstrapping.md) コード内の `Yii::$container->set()` を呼び出すことで指定することができます。
たとえばあなたが、すべてのリンクページャーが最大で5つのページボタン (デフォルト値は10) を伴って表示されるよう
[[yii\widgets\LinkPager]] をカスタマイズしたいとき、その目標を達成するには次のコードを使用することができます。
```php
\Yii::$container->set('yii\widgets\LinkPager', [
'maxButtonCount' => 5,
]);
```
デフォルト設定を使用しなければ、あなたは、リンクページャーを使うすべての箇所で `maxButtonCount` を設定しなければなりません。
## 環境定数 <a name="environment-constants"></a>
構成情報は、多くの場合、アプリケーションが実行される環境に応じて変化します。たとえば、
開発環境では `mydb_dev` という名前のデータベースを使用し、本番サーバー上では `mydb_prod` データベースを
使用したいかもしれません。環境の切り替えを容易にするために、Yii は、あなたのアプリケーションの
[エントリスクリプト](structure-entry-scripts.md) で定義可能な `YII_ENV` という名前の定数を提供します。
たとえば:
```php
defined('YII_ENV') or define('YII_ENV', 'dev');
```
`YII_ENV` を次のいずれかの値と定義することができます:
- `prod`: 本番環境。定数 `YII_ENV_PROD` は true と評価されます。
とくに定義しない場合、これが `YII_ENV` のデフォルト値です。
- `dev`: 開発環境。定数 `YII_ENV_DEV` は true と評価されます。
- `test`: テスト環境。定数 `YII_ENV_TEST` は true と評価されます。
これらの環境定数を使用すると、現在の環境に基づいて条件付きで構成情報を指定することもできます。
たとえば、アプリケーション構成情報には、開発環境での [デバッグツールバーとデバッガ](tool-debugger.md)
を有効にするために、次のコードを含むことができます。
```php
$config = [...];
if (YII_ENV_DEV) {
// 'dev' 環境用に構成情報を調整
$config['bootstrap'][] = 'debug';
$config['modules']['debug'] = 'yii\debug\Module';
}
return $config;
```

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

@ -0,0 +1,326 @@
依存性注入コンテナ
==============================
依存性注入 (DI) コンテナは、オブジェクトとそのすべての依存オブジェクトを、インスタンス化し、設定する方法を知っているオブジェクトです。
なぜ DI コンテナが便利なのかは、[Martin の記事](http://martinfowler.com/articles/injection.html) の説明がわかりやすいでしょう。
ここでは、主に Yii の提供する DI コンテナの使用方法を説明します。
依存性注入 <a name="dependency-injection"></a>
--------------------
Yii は [[yii\di\Container]] クラスを通して DI コンテナの機能を提供します。これは、次の種類の依存性注入をサポートしています:
* コンストラクタ·インジェクション
* セッター/プロパティ·インジェクション
* PHP コーラブル·インジェクション
### コンストラクタ·インジェクション <a name="constructor-injection"></a>
DI コンテナは、コンストラクタパラメータの型ヒントの助けを借りた、コンストラクタ·インジェクションをサポートしています。
型ヒントは、クラスやインタフェースが新しいオブジェクトの作成で使用されるさい、どれが依存であるのかということをコンテナに教えます。
コンテナは、依存クラスやインタフェースのインスタンスを取得し、コンストラクタを通して、新しいオブジェクトにそれらの注入を試みます。
たとえば
```php
class Foo
{
public function __construct(Bar $bar)
{
}
}
$foo = $container->get('Foo');
// これは下記と等価:
$bar = new Bar;
$foo = new Foo($bar);
```
### セッター/プロパティ·インジェクション <a name="setter-and-property-injection"></a>
セッター/プロパティ·インジェクションは、[構成情報](concept-configurations.md) を通してサポートされます。
依存関係を登録するときや、新しいオブジェクトを作成するとき、コンテナが使用する構成情報を提供することができ、
それに対応するセッターまたはプロパティを通じて依存関係が注入されます。たとえば
```php
use yii\base\Object;
class Foo extends Object
{
public $bar;
private $_qux;
public function getQux()
{
return $this->_qux;
}
public function setQux(Qux $qux)
{
$this->_qux = $qux;
}
}
$container->get('Foo', [], [
'bar' => $container->get('Bar'),
'qux' => $container->get('Qux'),
]);
```
### PHP コーラブル・インジェクション <a name="php-callable-injection"></a>
この場合、コンテナは、登録された PHP のコーラブルオブジェクトを使用し、クラスの新しいインスタンスを構築します。
コーラブルは、依存関係を解決し、新しく作成されたオブジェクトに適切にそれらを注入する責任があります。たとえば
```php
$container->set('Foo', function () {
return new Foo(new Bar);
});
$foo = $container->get('Foo');
```
依存関係の登録 <a name="registering-dependencies"></a>
------------------------
あなたは、[[yii\di\Container::set()]] 使って依存関係を登録することができます。登録には依存関係の名前だけでなく、
依存関係の定義が必要です。依存関係の名前は、クラス名、インタフェース名、エイリアス名を指定することができます。
依存関係の定義には、クラス名、構成情報配列、PHPのコーラブルを指定できます。
```php
$container = new \yii\di\Container;
// クラス名そのまま。これはなくてもかまいません。
$container->set('yii\db\Connection');
// インターフェースの登録
// クラスがインターフェースに依存する場合、対応するクラスが依存オブジェクトとしてインスタンス化されます
$container->set('yii\mail\MailInterface', 'yii\swiftmailer\Mailer');
// エイリアス名の登録。$container->get('foo') を使って Connection のインスタンスを作成できます
$container->set('foo', 'yii\db\Connection');
// 構成情報をともなうクラスの登録。クラスが get() でインスタンス化されるとき構成情報が適用されます
$container->set('yii\db\Connection', [
'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
]);
// クラスの構成情報をともなうエイリアス名の登録
// この場合、クラスを指定する "class" 要素が必要です
$container->set('db', [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
]);
// PHP コーラブルの登録
// このコーラブルは $container->get('db') が呼ばれるたびに実行されます
$container->set('db', function ($container, $params, $config) {
return new \yii\db\Connection($config);
});
// コンポーネントインスタンスの登録
// $container->get('pageCache') は呼ばれるたびに毎回同じインスタンスを返します
$container->set('pageCache', new FileCache);
```
> 補足: 依存関係名が、対応する依存関係の定義と同じである場合は、それを DI コンテナに登録する必要はありません。
`set()` を介して登録された依存性は、依存性が必要とされるたびにインスタンスを生成します。
[[yii\di\Container::setSingleton()]] を使うと、単一のインスタンスをひとつだけ生成する依存関係を登録することができます:
```php
$container->setSingleton('yii\db\Connection', [
'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
]);
```
依存関係の解決 <a name="resolving-dependencies"></a>
----------------------
依存関係を登録すると、新しいオブジェクトを作成するのに DI コンテナを使用することができ、
コンテナが自動的に、依存性をインスタンス化して新しく作成されたオブジェクトに注入することで、
依存関係を解決します。依存関係の解決は再帰的、つまり、ある依存性が他の依存関係を持っている場合、
それらの依存関係も自動的に解決されます。
[[yii\di\Container::get()]] を使って、新しいオブジェクトを作成することができます。
このメソッドは、クラス名、インタフェース名、エイリアス名で指定できる依存関係の名前を受け取ります。
依存関係名は、 `set()``setSingleton()` を介して登録されていたりされていなかったりする
可能性があります。オプションで、クラスのコンストラクタのパラメータのリストや、新しく作成された
オブジェクトを設定するための [設定情報](concept-configurations.md) を渡すことができます。
たとえば
```php
// "db" は事前に登録されたエイリアス名
$db = $container->get('db');
// これと同じ意味: $engine = new \app\components\SearchEngine($apiKey, ['type' => 1]);
$engine = $container->get('app\components\SearchEngine', [$apiKey], ['type' => 1]);
```
見えないところで、DIコンテナは、単に新しいオブジェクトを作成するよりもはるかに多くの作業を行います。
コンテナは、最初の依存クラスまたはインタフェースの名前を見つけるために、クラスのコンストラクタを検査し、
自動的にそれらの依存関係を再帰で解決します。
次のコードでより洗練された例を示します。 `UserLister` クラスは `UserFinderInterface`
インタフェースを実装するオブジェクトに依存します。 `UserFinder` クラスはこのインターフェイスを実装していて、かつ、
`Connection` オブジェクトに依存します。これらのすべての依存関係は、クラスのコンストラクタのパラメータのタイプヒンティングで宣言されています。
プロパティ依存性の登録をすれば、DI コンテナは自動的にこれらの依存関係を解決し、単純に `get('userLister')`
を呼び出すだけで新しい `UserLister` インスタンスを作成できます。
```php
namespace app\models;
use yii\base\Object;
use yii\db\Connection;
use yii\di\Container;
interface UserFinderInterface
{
function findUser();
}
class UserFinder extends Object implements UserFinderInterface
{
public $db;
public function __construct(Connection $db, $config = [])
{
$this->db = $db;
parent::__construct($config);
}
public function findUser()
{
}
}
class UserLister extends Object
{
public $finder;
public function __construct(UserFinderInterface $finder, $config = [])
{
$this->finder = $finder;
parent::__construct($config);
}
}
$container = new Container;
$container->set('yii\db\Connection', [
'dsn' => '...',
]);
$container->set('app\models\UserFinderInterface', [
'class' => 'app\models\UserFinder',
]);
$container->set('userLister', 'app\models\UserLister');
$lister = $container->get('userLister');
// と、いうのはこれと同じ:
$db = new \yii\db\Connection(['dsn' => '...']);
$finder = new UserFinder($db);
$lister = new UserLister($finder);
```
実際の使いかた <a name="practical-usage"></a>
---------------
あなたのアプリケーションの [エントリスクリプト](structure-entry-scripts.md) で `Yii.php` ファイルをインクルードするとき、
Yii は DI コンテナを作成します。この DI コンテナは [[Yii::$container]] を介してアクセス可能です。 [[Yii::createObject()]] を呼び出したとき、
このメソッドは実際には、新しいオブジェクトを作成ために、コンテナの [[yii\di\Container::get()|get()]] メソッドを呼び出しています。
前述のとおり、DI コンテナは(もしあれば)自動的に依存関係を解決し、新しく作成されたオブジェクトにそれらを注入します。
Yii は、新しいオブジェクトを作成するさいそのコアコードのほとんどで [[Yii::createObject()]] を使用しているため、これは、
[[Yii::$container]] を扱えばグローバルにオブジェクトをカスタマイズすることができることを意味しています。
たとえば、 [[yii\widgets\LinkPager]] のページネーションボタンのデフォルト個数をグローバルにカスタマイズすることができます:
```php
\Yii::$container->set('yii\widgets\LinkPager', ['maxButtonCount' => 5]);
```
次のコードでビューでウィジェットを使用すれば、 `maxButtonCount` プロパティは、
クラスで定義されているデフォルト値 10 の代わりに 5 で初期化されます。
```php
echo \yii\widgets\LinkPager::widget();
```
DIコンテナを経由して設定された値は、こうやって、まだまだ上書きすることができます:
```php
echo \yii\widgets\LinkPager::widget(['maxButtonCount' => 20]);
```
DI コンテナの自動コンストラクタ・インジェクションの利点を活かす別の例です。
あなたのコントローラクラスが、ホテル予約サービスのような、いくつかの他のオブジェクトに依存するとします。
あなたは、コンストラクタパラメータを通して依存関係を宣言して、DI コンテナにあなたの課題を解決させることができます。
```php
namespace app\controllers;
use yii\web\Controller;
use app\components\BookingInterface;
class HotelController extends Controller
{
protected $bookingService;
public function __construct($id, $module, BookingInterface $bookingService, $config = [])
{
$this->bookingService = $bookingService;
parent::__construct($id, $module, $config);
}
}
```
あなたがブラウザからこのコントローラにアクセスすると、 `BookingInterface` をインスタンス化できませんという
不具合報告エラーが表示されるでしょう。これは、この依存関係に対処する方法を DI コンテナに教える必要があるからです:
```php
\Yii::$container->set('app\components\BookingInterface', 'app\components\BookingService');
```
これで、あなたが再びコントローラにアクセスするときは、 `app\components\BookingService`
のインスタンスが作成され、コントローラのコンストラクタに3番目のパラメータとして注入されるようになります。
依存関係を登録するときに <a name="when-to-register-dependencies"></a>
-----------------------------
依存関係は、新しいオブジェクトが作成されるとき必要とされるので、それらの登録は可能な限り早期に行われるべきです。
推奨プラクティス以下のとおりです:
* あなたがアプリケーションの開発者である場合、アプリケーションの [エントリスクリプト](structure-entry-scripts.md) 内、
またはエントリスクリプトにインクルードされるスクリプト内で、依存関係を登録することができます。
* あなたが再配布可能な [エクステンション](structure-extensions.md) の開発者である場合は、エクステンションのブートストラップクラス内で
依存関係を登録することができます。
まとめ <a name="summary"></a>
-------
依存性注入と [サービスロケータ](concept-service-locator.md) はともに、疎結合でよりテストしやすい方法でのソフトウェア構築を可能にする、
定番のデザインパターンです。依存性注入とサービスロケータへのより深い理解を得るために、 [Martin の記事](http://martinfowler.com/articles/injection.html)
を読むことを強くお勧めします。
Yiiはその [サービスロケータ](concept-service-locator.md) を、依存性注入(DI)コンテナの上に実装しています。
サービスロケータは、新しいオブジェクトのインスタンスを作成しようとしたとき、DI コンテナに呼び出しを転送します。
後者は、依存関係を、上で説明したように自動的に解決します。

279
docs/guide-ja/concept-events.md

@ -0,0 +1,279 @@
イベント
======
イベントを使うと、既存のコードの特定の実行ポイントに、カスタムコードを挿入することができます。イベントにカスタムコードを添付すると、
イベントがトリガされたときにコードが自動的に実行されます。たとえば、メーラーオブジェクトがメッセージを正しく送信できたとき、
`messageSent` イベントをトリガするとします。もしメッセージの送信がうまく行ったことを知りたければ、単に `messageSent`
イベントにトラッキングコードを付与すするだけで、それが可能になります。
Yiiはイベントをサポートするために、 [[yii\base\Component]] と呼ばれる基底クラスを導入してします。クラスがイベントをトリガする必要がある場合は、
[[yii\base\Component]] もしくはその子クラスを継承する必要があります。
イベントハンドラ <a name="event-handlers"></a>
--------------
イベントハンドラとは、関連するイベントがトリガされたときに実行される、 [PHP コールバック](http://www.php.net/manual/en/language.types.callable.php)
です。次のコールバックのいずれも使用可能です:
- 文字列で指定されたグローバル PHP 関数 (括弧を除く) `'trim'` など
- オブジェクトとメソッド名文字列の配列で指定された、オブジェクトのメソッド (括弧を除く) `[$object, 'methodName']` など
- クラス名文字列とメソッド名文字列の配列で指定された、静的なクラスメソッド `[$class, 'methodName']` など
- 無名関数 `function ($event) { ... }` など
イベントハンドラのシグネチャはこのようになります:
```php
function ($event) {
// $event は yii\base\Event またはその子クラスのオブジェクト
}
```
`$event` パラメータを介して、イベントハンドラは発生したイベントに関して次の情報を得ることができます:
- [[yii\base\Event::name|イベント名]]
- [[yii\base\Event::sender|イベント送信元]]: `trigger()` メソッドを呼び出したオブジェクト
- [[yii\base\Event::data|カスタムデータ]]: イベントハンドラを接続するときに提供されたデータ (後述)
イベントハンドラのアタッチ <a name="attaching-event-handlers"></a>
------------------------
イベントハンドラは [[yii\base\Component::on()]] を呼び出すことでアタッチできます。たとえば:
```php
$foo = new Foo;
// このハンドラはグローバル関数です
$foo->on(Foo::EVENT_HELLO, 'function_name');
// このハンドラはオブジェクトのメソッドです
$foo->on(Foo::EVENT_HELLO, [$object, 'methodName']);
// このハンドラは静的なクラスメソッドです
$foo->on(Foo::EVENT_HELLO, ['app\components\Bar', 'methodName']);
// このハンドラは無名関数です
$foo->on(Foo::EVENT_HELLO, function ($event) {
// イベント処理ロジック
});
```
また、 [構成情報](concept-configurations.md) を通じてイベントハンドラをアタッチすることもできます。詳細については
[構成情報](concept-configurations.md) の章を参照してください。
イベントハンドラをアタッチするとき、 [[yii\base\Component::on()]] の3番目のパラメータとして、付加的なデータを提供することができます。
そのデータは、イベントがトリガされてハンドラが呼び出されるときに、ハンドラ内で利用きます。たとえば:
```php
// 次のコードはイベントがトリガされたとき "abc" を表示します
// "on" に3番目の引数として渡されたデータを $event->data が保持しているからです
$foo->on(Foo::EVENT_HELLO, 'function_name', 'abc');
function function_name($event) {
echo $event->data;
}
```
イベントハンドラの順序
-------------------
ひとつのイベントには、ひとつだけでなく複数のハンドラをアタッチすることができます。イベントがトリガされると、アタッチされたハンドラは、
それらがイベントにアタッチされた順序どおりに呼び出されます。あるハンドラがその後に続くハンドラの呼び出しを停止する必要がある場合は、
`$event` パラメータの [[yii\base\Event::handled]] プロパティを true に設定します:
```php
$foo->on(Foo::EVENT_HELLO, function ($event) {
$event->handled = true;
});
```
デフォルトでは、新たに接続されたハンドラは、イベントの既存のハンドラのキューに追加されます。その結果、
イベントがトリガされたとき、そのハンドラは一番最後に呼び出されます。もし、そのハンドラが最初に呼び出されるよう、
ハンドラのキューの先頭に新しいハンドラを挿入したい場合は、[[yii\base\Component::on()]] を呼び出とき、4番目のパラメータ `$append` に false を渡します:
```php
$foo->on(Foo::EVENT_HELLO, function ($event) {
// ...
}, $data, false);
```
イベントのトリガー <a name="triggering-events"></a>
-----------------
イベントは、 [[yii\base\Component::trigger()]] メソッドを呼び出すことでトリガされます。このメソッドには **イベント名** が必須で、
オプションで、イベントハンドラに渡されるパラメータを記述したイベントオブジェクトを渡すこともできます。たとえば:
```php
namespace app\components;
use yii\base\Component;
use yii\base\Event;
class Foo extends Component
{
const EVENT_HELLO = 'hello';
public function bar()
{
$this->trigger(self::EVENT_HELLO);
}
}
```
上記のコードでは、すべての `bar()` の呼び出しは、 `hello` という名前のイベントをトリガします。
> Tip: イベント名を表すときはクラス定数を使用することをお勧めします。上記の例では、定数 `EVENT_HELLO`
`hello` イベントを表しています。このアプローチには 3 つの利点があります。まず、タイプミスを防ぐことができます。次に、IDE の自動補完サポートでイベントを
認識できるようになります。第 3 に、クラスでどんなイベントがサポートされているかを表したいとき、定数の宣言をチェックするだけで済みます。
イベントをトリガするとき、イベントハンドラに追加情報を渡したいことがあります。たとえば、メーラーが `messageSent` イベントのハンドラに
メッセージ情報を渡して、ハンドラが送信されたメッセージの詳細を知ることができるようにしたいかもしれません。
これを行うために、 [[yii\base\Component::trigger()]] メソッドの2番目のパラメータとして、イベントオブジェクトを与えることができます。
イベントオブジェクトは [[yii\base\Event]] クラスあるいはその子クラスのインスタンスでなければなりません。たとえば:
```php
namespace app\components;
use yii\base\Component;
use yii\base\Event;
class MessageEvent extends Event
{
public $message;
}
class Mailer extends Component
{
const EVENT_MESSAGE_SENT = 'messageSent';
public function send($message)
{
// ... $message 送信 ...
$event = new MessageEvent;
$event->message = $message;
$this->trigger(self::EVENT_MESSAGE_SENT, $event);
}
}
```
[[yii\base\Component::trigger()]] メソッドが呼び出されたとき、この名前を付けられたイベントに
アタッチされたハンドラがすべて呼び出されます。
イベントハンドラのデタッチ <a name="detaching-event-handlers"></a>
------------------------
イベントからハンドラを取り外すには、 [[yii\base\Component::off()]] メソッドを呼び出します。たとえば:
```php
// このハンドラはグローバル関数です
$foo->off(Foo::EVENT_HELLO, 'function_name');
// このハンドラはオブジェクトのメソッドです
$foo->off(Foo::EVENT_HELLO, [$object, 'methodName']);
// このハンドラは静的なクラスメソッドです
$foo->off(Foo::EVENT_HELLO, ['app\components\Bar', 'methodName']);
// このハンドラは無名関数です
$foo->off(Foo::EVENT_HELLO, $anonymousFunction);
```
一般的には、イベントにアタッチされたときどこかに保存してある場合を除き、無名関数を取り外そうとはしないでください。
上記の例は、無名関数は変数 `$anonymousFunction` として保存されていたものとしています。
イベントからすべてのハンドラを取り外すには、単純に、第 2 パラメータを指定せずに [[yii\base\Component::off()]] を呼び出します。
```php
$foo->off(Foo::EVENT_HELLO);
```
クラスレベル・イベントハンドラ <a name="class-level-event-handlers"></a>
--------------------------
ここまでの項では、 *インスタンスレベル* でのイベントにハンドラをアタッチする方法を説明してきました。
場合によっては、特定のインスタンスだけではなく、クラスのすべてのインスタンスがトリガした
イベントに応答したいことがあります。すべてのインスタンスにイベントハンドラをアタッチする代わりに、静的メソッド
[[yii\base\Event::on()]] を呼び出すことで、 *クラスレベル* でハンドラをアタッチすることができます。
たとえば、[アクティブレコード](db-active-record.md) オブジェクトは、データベースに新しいレコードを挿入するたびに、
[[yii\db\BaseActiveRecord::EVENT_AFTER_INSERT|EVENT_AFTER_INSERT]] イベントをトリガします。 *すべての*
[アクティブレコード](db-active-record.md) オブジェクトによって行われる挿入を追跡するには、次のコードが使えます:
```php
use Yii;
use yii\base\Event;
use yii\db\ActiveRecord;
Event::on(ActiveRecord::className(), ActiveRecord::EVENT_AFTER_INSERT, function ($event) {
Yii::trace(get_class($event->sender) . ' が挿入されました');
});
```
[[yii\db\ActiveRecord|ActiveRecord]] またはその子クラスのいずれかが、 [[yii\db\BaseActiveRecord::EVENT_AFTER_INSERT|EVENT_AFTER_INSERT]]
をトリガーするといつでも、このイベントハンドラが呼び出されます。ハンドラの中では、 `$event->sender` を通して、
イベントをトリガしたオブジェクトを取得することができます。
オブジェクトがイベントをトリガするときは、最初にインスタンスレベルのハンドラを呼び出し、続いてクラスレベルのハンドラとなります。
静的メソッド [[yii\base\Event::trigger()]] を呼び出すことによって、 *クラスレベル* でイベントをトリガすることができます。
クラスレベルでのイベントは、特定のオブジェクトに関連付けられていません。そのため、これはクラスレベルのイベントハンドラだけを
呼び出します。たとえば:
```php
use yii\base\Event;
Event::on(Foo::className(), Foo::EVENT_HELLO, function ($event) {
echo $event->sender; // "app\models\Foo" を表示
});
Event::trigger(Foo::className(), Foo::EVENT_HELLO);
```
この場合、`$event->sender` は、オブジェクトインスタンスではなく、イベントをトリガーするクラスの名前を指すことに注意してください。
> 注: クラスレベルのハンドラは、そのクラスのあらゆるインスタンス、またはあらゆる子クラスのインスタンスがトリガしたイベントに応答
してしまうため、よく注意して使わなければなりません。 [[yii\base\Object]] のように、クラスが低レベルの基底クラスの場合は特にそうです。
クラスレベルのイベントハンドラを取り外すときは、 [[yii\base\Event::off()]] を呼び出します。たとえば:
```php
// $handler をデタッチ
Event::off(Foo::className(), Foo::EVENT_HELLO, $handler);
// Foo::EVENT_HELLO のすべてのハンドラをデタッチ
Event::off(Foo::className(), Foo::EVENT_HELLO);
```
グローバル・イベント <a name="global-events"></a>
-------------
Yiiは、実際に上記のイベントメカニズムに基づいたトリックである、いわゆる *グローバル・イベント* をサポートしています。
グローバル・イベントは、 [アプリケーション](structure-applications.md) インスタンス自身などの、グローバルにアクセス可能なシングルトンを必要とします。
グローバルイベントを作成するには、イベント送信者は、送信者の自前の `trigger()` メソッドを呼び出す代わりに、シングルトンの
`trigger()` メソッドを呼び出してイベントをトリガします。同じく、イベントハンドラも、シングルトンのイベントにアタッチされます。たとえば:
```php
use Yii;
use yii\base\Event;
use app\components\Foo;
Yii::$app->on('bar', function ($event) {
echo get_class($event->sender); // "app\components\Foo" を表示
});
Yii::$app->trigger('bar', new Event(['sender' => new Foo]));
```
グローバルイベントを使用する利点は、オブジェクトによってトリガされるイベントハンドラを設けたいとき、オブジェクトがなくてもいい
ということです。その代わりに、ハンドラのアタッチとイベントのトリガはともに、(アプリケーションのインスタンスなど) シングルトンを
介して行われます。
しかし、グローバルイベントの名前空間はあらゆる部分から共有されているので、名前空間の整理 ("frontend.mail.sent"、"backend.mail.sent" など)
を導入するというような、賢いグローバルイベントの名前付けをする必要があります。

77
docs/guide-ja/concept-properties.md

@ -0,0 +1,77 @@
プロパティ
==========
PHPでは、クラスのメンバ変数は *プロパティ* とも呼ばれます。これらの変数は、クラス定義の一部で、クラスのインスタンスの状態を表すために
(すなわち、クラスのあるインスタンスを別のものと区別するために) 使用されます。現実によく、特別な方法でこのプロパティの読み書きを扱いたい
場合があります。たとえば、`label` プロパティに割り当てられる文字列が常にトリミングされるようにしたい、など。その仕事を成し遂げるために、
あなたは次のようなコードを使ってきたのではありませんか:
```php
$object->label = trim($label);
```
上記のコードの欠点は、 `label` プロパティを設定するすべてのコードで、`trim()` を呼び出す必要があるということです。もし将来的に、
`label` プロパティに、最初の文字を大文字にしなければならない、といった新たな要件が発生したら、 `label` に値を代入するすべてのコードを変更しなければなりません。コードの繰り返しはバグを誘発するので、できれば避けたいところです。
この問題を解決するために、Yii は *getter* メソッドと *setter* メソッドをベースにしたプロパティ定義をサポートする、 [[yii\base\Object]] 基底クラスを提供します。
クラスがその機能を必要とするなら、 [[yii\base\Object]] またはその子クラスを継承しましょう。
> 補足: Yiiのフレームワークのほぼすべてのコアクラスは、 [[yii\base\Object]] またはその子クラスを継承しています。
これは、コアクラスに getter または setter があれば、それをプロパティのように使用できることを意味します。
getter メソッドは、名前が `get` で始まるメソッドで、setter メソッドは、`set` で始まるメソッドです。
`get` または `set` プレフィクスの後の名前で、プロパティ名を定義します。次のコードに示すように、たとえば、`getLabel()` という getter と `setLabel()` という setter は、
`label` という名前のプロパティを定義します:
```php
namespace app\components;
use yii\base\Object;
class Foo extends Object
{
private $_label;
public function getLabel()
{
return $this->_label;
}
public function setLabel($value)
{
$this->_label = trim($value);
}
}
```
(詳しく言うと、getter および setter メソッドは、この場合には、内部的に `_label` と名付けられた private 属性を参照する `label` プロパティを作っています。)
getter と setter によって定義されたプロパティは、クラスのメンバ変数のように使用することができます。主な違いは、
それらのプロパティが読み取りアクセスされるときは、対応する getter ソッドが呼び出されることであり、プロパティに値が割り当てられるときには、
対応する setter メソッドが呼び出されるということです。例:
```php
// $label = $object->getLabel(); と同じ
$label = $object->label;
// $object->setLabel('abc'); と同じ
$object->label = 'abc';
```
setter なしの getter で定義されたプロパティは、 *読み取り専用* です。そのようなプロパティに値を代入しようとすると、
[[yii\base\InvalidCallException|InvalidCallException]] が発生します。同様に、getter なしの setter で定義されたプロパティは、
*書き込み専用* で、そのようなプロパティを読み取りしようとしても、例外が発生します。書き込み専用のプロパティを持つのは一般的ではありませんが。
getter と setter で定義されたプロパティには、いくつかの特別なルールと制限があります:
* この種のプロパティでは、名前の *大文字と小文字を区別しません* 。たとえば、 `$object->label``$object->Label` は同じです。
これは、PHPのメソッド名が大文字と小文字を区別しないためです。
* この種のプロパティの名前と、クラスのメンバ変数の名前とが同じである場合、後者が優先されます。
たとえば、上記の `Foo` クラスがもしメンバ変数 `label` を持っているとすると、`$object->label = 'abc'`
という代入は *メンバ変数の* `label` に作用することになり、その行で `setLabel()` setter メソッドは呼び出されなくなります。
* これらのプロパティは可視性をサポートしていません。プロパティが public、protected、private であるかどうかで、
getter または setter メソッドの定義に違いは生じません。
* プロパティは、 *静的でない* getter および setter でしか定義できません。静的メソッドは同じようには扱われません。
このガイドの冒頭で説明した問題に戻ると、 `label` に値が代入されているあらゆる箇所で `trim()` を呼ぶのではなく、もう `setLabel()` という setter の内部だけで `trim()` を呼べば済むのです。
さらに、新しい要求でラベルの先頭を大文字にする必要が発生しても、他のいっさいのコードに触れることなく、すぐに `setLabel()` メソッドを変更することができます。一箇所の変更は、すべての `label` への代入に普遍的に作用します。

83
docs/guide-ja/concept-service-locator.md

@ -0,0 +1,83 @@
サービスロケータ
===============
サービスロケータは、アプリケーションが必要とする可能性のある各種のサービス (またはコンポーネント) を提供する方法を知っているオブジェクトです。
サービスロケータ内では、各コンポーネントは単一のインスタンスとして存在し、IDによって一意に識別されます。
あなたは、このIDを使用してサービスロケータからコンポーネントを取得できます。
Yii では、サービスロケータは単純に [[yii\di\ServiceLocator]] のインスタンス、または子クラスのインスタンスです。
Yii の中で最も一般的に使用されるサービスロケータは、 *アプリケーション* オブジェクトで、 `\Yii::$app`
を通じてアクセスできます。それが提供するサービスは、 *アプリケーションコンポーネント* と呼ばれ、それは `request`
`response``urlManager` のようなコンポーネントです。あなたはサービスロケータによって提供される機能を通じて、
簡単に、これらのコンポーネントを構成、あるいは独自の実装に置き換え、といったことができます。
アプリケーションオブジェクトの他に、各モジュールオブジェクトもまたサービスロケータです。
サービスロケータを使用する最初のステップは、コンポーネントを登録することです。コンポーネントは、 [[yii\di\ServiceLocator::set()]]
を通じて登録することができます。次のコードは、コンポーネントを登録するさまざまな方法を示しています。
```php
use yii\di\ServiceLocator;
use yii\caching\FileCache;
$locator = new ServiceLocator;
// コンポーネントの作成に使われるクラス名を使用して "cache" を登録
$locator->set('cache', 'yii\caching\ApcCache');
// コンポーネントの作成に使われる構成情報配列を使用して "db" を登録
$locator->set('db', [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=demo',
'username' => 'root',
'password' => '',
]);
// コンポーネントを構築する匿名関数を使って "search" を登録
$locator->set('search', function () {
return new app\components\SolrService;
});
// コンポーネントを使って "pageCache" を登録
$locator->set('pageCache', new FileCache);
```
いったんコンポーネントが登録されたら、次の 2 つの方法のいずれかで、その ID を使ってそれにアクセスすることができます:
```php
$cache = $locator->get('cache');
// または代わりに
$cache = $locator->cache;
```
以上のように、 [[yii\di\ServiceLocator]] はコンポーネント ID を使用したプロパティのように、コンポーネントにアクセスすることができます。
あなたが最初にコンポーネントにアクセスしたとき、 [[yii\di\ServiceLocator]] はコンポーネントの登録情報を使用してコンポーネントの新しいインスタンスを作成し、
それを返します。後でそのコンポーネントが再度アクセスされた場合、サービスロケータは同じインスタンスを返します。
[[yii\di\ServiceLocator::has()]] を使って、コンポーネント ID がすでに登録されているかをチェックできます。
無効なIDで [[yii\di\ServiceLocator::get()]] を呼び出した場合、例外がスローされます。
サービスロケータは多くの場合、 [構成情報](concept-configurations.md) で作成されるため、
[[yii\di\ServiceLocator::setComponents()|components]] という名前の書き込み可能プロパティが提供されています。
これで一度に複数のコンポーネントを設定して登録することができます。次のコードはアプリケーションを構成する構成情報配列を示しており、
"db" と "cache" と "search" コンポーネントの登録もしています:
```php
return [
// ...
'components' => [
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=demo',
'username' => 'root',
'password' => '',
],
'cache' => 'yii\caching\ApcCache',
'search' => function () {
return new app\components\SolrService;
},
],
];
```

1000
docs/guide-ja/db-active-record.md

File diff suppressed because it is too large Load Diff

4
docs/guide-ja/db-dao.md

@ -18,7 +18,7 @@ Yii はデフォルトで下記の DBMS をサポートしています。
- [CUBRID](http://www.cubrid.org/): バージョン 9.3 以上。(cubrid PDO 拡張の [バグ](http://jira.cubrid.org/browse/APIS-658)
のために、値を引用符で囲む機能が動作しません。そのため、サーバだけでなくクライアントも CUBRID 9.3 が必要になります)
- [Oracle](http://www.oracle.com/us/products/database/overview/index.html)
- [MSSQL](https://www.microsoft.com/en-us/sqlserver/default.aspx): バージョン 2005 以上。
- [MSSQL](https://www.microsoft.com/en-us/sqlserver/default.aspx): バージョン 2008 以上。
構成
@ -199,7 +199,7 @@ $connection->createCommand()->update('user', ['status' => 1], 'age > 30')->execu
$connection->createCommand()->delete('user', 'status = 0')->execute();
```
テーブルとカラムの名前を引用符で囲む
テーブルとカラムの名前を引用符で囲む <a name="quoting-table-and-column-names"></a>
------------------------------------
テーブルとカラムの名前をクエリの中で安全に使えるようにするために、Yii にそれらの名前を引用符で適切に囲ませることが出来ます。

6
docs/guide-ja/db-elasticsearch.md

@ -0,0 +1,6 @@
Elasticsearch
=============
> Note|注意: この節はまだ執筆中です。
>
> まだ内容がありません。

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

@ -0,0 +1,361 @@
データベースマイグレーション
============================
> Note|注意: この節はまだ執筆中です。
ソースコードと同じように、データベースの構造も、データベース駆動型のアプリケーションが開発され保守されるにともなって徐々に発展していきます。
例えば、開発中に新しいテーブルが追加されることもあるでしょうし、アプリケーションが実運用に移行した後になって追加のインデックスが必要であることが発見されることもあるでしょう。
このようなデータベースの構造的な変更 (**マイグレーション** と呼ばれます) を追跡記録することが重要であるのは、ソースコードに対する変更がバージョン管理を使って追跡記録されるのと全く同じことです。
ソースコードとデータベースの同期が失われると、バグが発生するか、アプリケーション全体が動かなくなるかします。
こうした理由によって、データベースマイグレーションツールを提供して、データベースマイグレーションの履歴の追跡管理、新しいマイグレーションの適用、また、既存のマイグレーションの取消が出来るようにしています。
下記のステップは、開発中にチームによってデータベースマイグレーションが使用される例を示すものです。
1. Tim が新しいマイグレーション (例えば、新しいテーブルを作成したり、カラムの定義を変更したりなど) を作る。
2. Tim が新しいマイグレーションをソースコントロールシステム (例えば Git や Mercurial) にコミットする。
3. Doug がソースコントロールシステムから自分のレポジトリを更新して新しいマイグレーションを受け取る。
4. Doug がマイグレーションを彼のローカルの開発用データベースに適用し、Tim が行った変更を反映して、自分のデータベースを同期する。
Yii はデータベースマイグレーションを `yii migrate` コマンドラインツールによってサポートします。
このツールは、以下の機能をサポートしています。
* 新しいマイグレーションの作成
* マイグレーションの適用、取消、再適用
* マイグレーションの履歴と新規マイグレーションの閲覧
マイグレーションを作成する
--------------------------
新しいマイグレーションを作成するためには、次のコマンドを実行します。
```
yii migrate/create <name>
```
要求される `name` パラメータには、マイグレーションの非常に短い説明を指定します。
例えば、マイグレーションが *news* という名前のテーブルを作成するものである場合は、コマンドを次のようにして使います。
```
yii migrate/create create_news_table
```
すぐ後で説明するように、マイグレーションでは、この `name` パラメータは PHP のクラス名の一部として使用されます。
したがって、アルファベット、数字、および/または、アンダースコアだけを含まなければなりません。
上記のコマンドは、`m101129_185401_create_news_table.php` という名前の新しいファイルを作成します。
このファイルは `@app/migrations` ディレクトリに作成されます。
初期状態では、このマイグレーションファイルは以下のコードを含んでいます。
```php
class m101129_185401_create_news_table extends \yii\db\Migration
{
public function up()
{
}
public function down()
{
echo "m101129_185401_create_news_table cannot be reverted.\n";
return false;
}
}
```
クラス名はファイル名と同じであり、`m<timestamp>_<name>` というパターンに従います。ここで、
* `<timestamp>` は、マイグレーションが作成された (`yymmdd_hhmmss` という書式の) UTC タイムスタンプであり、
* `<name>` は、コマンドの `name` パラメータから取られた文字列です。
クラスの中では、`up()` メソッドが、実際のデータベースマイグレーションを実装するコードを含むべきメソッドです。
言い換えると、`up()` メソッドが実際にデータベースを変更するコードを実行します。
`down()` メソッドは、`up()` によって加えられた変更を取り消すコードを含むことが出来ます。
場合によっては、`down()` がデータベースマイグレーションを取り消すことが出来ないことがあります。
例えば、マイグレーションがテーブルの行やテーブル全体を削除した場合は、そのデータを `down()` メソッドで復旧することは出来ません。
そのような場合には、マイグレーションは不可逆であると呼ばれ、データベースを以前の状態にロールバックすることは出来ません。
マイグレーションが不可逆である場合は、生成された上記のコードのように、`down()` メソッドは `false` を返して、マイグレーションが取り消せないものであることを示します。
例として、新しいテーブルを作成するマイグレーションを示しましょう。
```php
use yii\db\Schema;
class m101129_185401_create_news_table extends \yii\db\Migration
{
public function up()
{
$this->createTable('news', [
'id' => 'pk',
'title' => Schema::TYPE_STRING . ' NOT NULL',
'content' => Schema::TYPE_TEXT,
]);
}
public function down()
{
$this->dropTable('news');
}
}
```
基底クラスである [[\yii\db\Migration]] が、データベース接続を `db` プロパティによって提供しています。
これを使って、データベースのデータとスキーマを操作することが出来ます。
この例で使われているカラムのタイプは抽象的なタイプであり、Yii によって、あなたが使用するデータベース管理システムに応じて、対応するタイプに置き換えられます。
抽象的なタイプを使うと、データベースに依存しないマイグレーションを書くことが出来ます。
例えば、`pk` は、MySQL では `int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY` に置き換えられ、sqlite では `integer PRIMARY KEY AUTOINCREMENT NOT NULL` に置き換えられます。
さらに詳細な説明と、利用可能なタイプについては、[[yii\db\QueryBuilder::getColumnType()]] のドキュメントを参照してください。
また、カラムのタイプを定義するのに、[[yii\db\Schema]] で定義されている定数を使うことも出来ます。
> Note|注意: テーブル定義の最後に、単純な文字列として指定された、制約やその他の特別なテーブルオプションを追加することが出来ます。
> 例えば、上記のマイグレーションでは、`content` 属性の定義の後に、`'CONSTRAINT ...'` やその他の特別なオプションを書くことが出来ます。
トランザクションを使うマイグレーション
--------------------------------------
複雑な DB マイグレーションを実行するときは、通常、データベースの一貫性と整合性を保つために、個々のマイグレーションが全体として成功または失敗することを保証する必要があります。
この目的を達成するために、DB トランザクションを利用することが出来ます。
この目的のためには、`safeUp` と `safeDown` という特別なメソッドを使います。
```php
use yii\db\Schema;
class m101129_185401_create_news_table extends \yii\db\Migration
{
public function safeUp()
{
$this->createTable('news', [
'id' => 'pk',
'title' => Schema::TYPE_STRING . ' NOT NULL',
'content' => Schema::TYPE_TEXT,
]);
$this->createTable('user', [
'id' => 'pk',
'login' => Schema::TYPE_STRING . ' NOT NULL',
'password' => Schema::TYPE_STRING . ' NOT NULL',
]);
}
public function safeDown()
{
$this->dropTable('news');
$this->dropTable('user');
}
}
```
使用するクエリが一つだけでない場合は、`safeUp` と `safeDown` を使うことを推奨します。
> Note|注意: 全ての DBMS がトランザクションをサポートしている訳ではありません。
> また、トランザクションに入れることが出来ない DB クエリもあります。
> その場合には、代りに、`up()` と `down()` を実装しなければなりません。
> また、MySQL の場合は、[暗黙のコミット](http://dev.mysql.com/doc/refman/5.1/en/implicit-commit.html) を引き起こす SQL 文があります。
マイグレーションを適用する
--------------------------
利用できる全ての新しいマイグレーションを適用する (すなわち、ローカルのデータベースを最新の状態にする) ためには、次のコマンドを実行します。
```
yii migrate
```
コマンドを実行すると、すべての新しいマイグレーションが一覧表示されます。
マイグレーションを適用することを確認すると、クラス名のタイムスタンプの値の順に、一つずつ、すべての新しいマイグレーションクラスの `up()` メソッドが実行されます。
マイグレーションを適用した後に、マイグレーションツールは `migration` という名前のデータベーステーブルに記録を残します。
これによって、ツールは、どのマイグレーションが適用済みで、どのマイグレーションが適用されていないかを特定することが出来ます。
`migration` テーブルが存在しない場合は、ツールは `db` [アプリケーションコンポーネント](structure-application-components.md)によって指定されたデータベースの中にテーブルを自動的に作成します。
時として、新しいマイグレーションを一個また数個だけ適用したい場合があります。その場合は、次のコマンドを使うことが出来ます。
```
yii migrate/up 3
```
このコマンドは、次の新しいマイグレーションを 3 個適用します。3 という値を変更して、適用されるマイグレーションの数を変更することが出来ます。
また、下記のコマンドを使って、特定のバージョンまでデータベースをマイグレートすることも可能です。
```
yii migrate/to 101129_185401
```
すなわち、マイグレーション名のタイムスタンプ部分を使って、データベースをマイグレートして到達したいバージョンを指定します。
最後に適用されたマイグレーションと指定されたマイグレーションの間に複数のマイグレーションがある場合は、それらのマイグレーションがすべて適用されます。
指定されたマイグレーションが適用済みである場合は、その後に適用されたすべてのマイグレーションが取り消されます (次の節で説明します)。
マイグレーションを取り消す
--------------------------
適用された最後のマイグレーション (一個または複数個) を取り消したい場合は、下記のコマンドを使うことが出来ます。
```
yii migrate/down [step]
```
ここで、オプションの `step` パラメータは何個のマイグレーションを取り消すかを指定するものです。
デフォルト値は 1 で、適用された最後のマイグレーションだけが取り消すされることを意味します。
前に説明したように、全てのマイグレーションが取り消せるとは限りません。
取り消せないマイグレーションを取り消そうとすると例外が投げられて、取り消しのプロセス全体が終了させられます。
マイグレーションを再適用する
----------------------------
マイグレーションの再適用とは、指定されたマイグレーションを最初に取り消してから、再度適用することを意味します。
これは次のコマンドによって実行することが出来ます。
```
yii migrate/redo [step]
```
ここで、オプションの `step` パラメータは何個のマイグレーションを再適用するかを指定するものです。
デフォルト値は 1 で、最後のマイグレーションだけが再適用されることを意味します。
マイグレーション情報を表示する
------------------------------
マイグレーションを適用したり取り消したりする他に、マイグレーションツールはマイグレーションの履歴、および、まだ適用されていない新しいマイグレーションを表示することも出来ます。
```
yii migrate/history [limit]
yii migrate/new [limit]
```
ここで、オプションの `limit` パラメータは、何個のマイグレーションを表示するかを指定するものです。
`limit` が指定されない場合は、利用可能な全てのマイグレーションが表示されます。
最初のコマンドは適用済みのマイグレーションを表示し、第二のコマンドはまだ適用されていないマイグレーションを表示します。
マイグレーション履歴を修正する
------------------------------
時として、実際には関係のあるマイグレーションを適用または取り消すことなく、マイグレーション履歴を特定のマイグレーションバージョンに修正したい場合があります。
このことは新しいマイグレーションを開発するときにしばしば起ります。
次のコマンドを使ってこの目的を達することが出来ます。
```
yii migrate/mark 101129_185401
```
このコマンドは `yii migrate/to` コマンドと非常によく似ていますが、マイグレーションを適用または取り消すことなく、マイグレーション履歴テーブルを指定されたバージョンに修正することだけを行うという点で違っています。
マイグレーションコマンドをカスタマイズする
------------------------------------------
マイグレーションコマンドをカスタマイズする方法がいくつかあります。
### コマンドラインオプションを使う
マイグレーションコマンドには、コマンドラインで指定できるいくつかのオプションがあります。
* `interactive`: 真偽値。マイグレーションを対話モードで実行するかどうかを指定します。
デフォルト値は true で、指定されたマイグレーションを実行するときに、ユーザは何らかの入力を促されます。
このオプションを false にセットして、マイグレーションがバックグラウンドプロセスとして実行されるようにすることが出来ます。
* `migrationPath`: 文字列。全てのマイグレーションクラスファイルを保存しているディレクトリを指定します。
このパスは、パスエイリアスの形式で指定されなければならず、また、対応するディレクトリが存在する必要があります。
このオプションが指定されない場合は、アプリケーションのベースパスの下の `migrations` サブディレクトリが使われます。
* `migrationTable`: 文字列。マイグレーション履歴の情報を保存するためのデータベーステーブル名を指定します。
デフォルト値は `migration` です。このテーブルは、`version varchar(255) primary key, apply_time integer` という構造を持ちます。
* `db`: 文字列。データベース [アプリケーションコンポーネント](structure-application-components.md) の ID を指定します。
デフォルト値は 'db' です。
* `templateFile`: 文字列。マイグレーションクラスを生成するためのコードテンプレートとして使われるファイルのパスを指定します。
このパスは、パスエイリアスの形式で指定しなければなりません (例えば、`application.migrations.template`)。
指定されない場合は、内部テンプレートが使用されます。
テンプレートの中の `{ClassName}` というトークンが実際のマイグレーションクラス名によって置き換えられます。
これらのオプションを指定するためには、下記の書式を使って migrate コマンドを実行します。
```
yii migrate/up --option1=value1 --option2=value2 ...
```
例えば、`forum` モジュールのためのマイグレーションを実行するときに、マイグレーションファイルがモジュールの `migrations` ディレクトリに置かれている場合には、下記のコマンドを使うことが出来ます。
```
yii migrate/up --migrationPath=@app/modules/forum/migrations
```
### コマンドをグローバルに構成する
コマンドラインオプションを使ってマイグレーションコマンドをその場その場で構成することも出来ますが、場合によっては、一度にまとめてコマンドを構成しておきたいこともあります。
例えば、マイグレーションの履歴を保存するのに別のテーブルを使用したいとか、カスタマイズしたマイグレーションテンプレートを使用したいとかです。
そうするためには、コンソールアプリケーションの構成情報ファイルを以下のように修正します。
```php
'controllerMap' => [
'migrate' => [
'class' => 'yii\console\controllers\MigrateController',
'migrationTable' => 'my_custom_migrate_table',
],
]
```
これで、`migrate` コマンドを実行すると、上記の構成情報が効果を発揮して、毎回コマンドラインオプションを入力する必要がなくなります。
その他のコマンドラインオプションも、このようにして構成することが出来ます。
### 複数のデータベースのマイグレーション
既定では、マイグレーションは `db` [アプリケーションコンポーネント](structure-application-components.md) によって指定されるデータベースに対して適用されます。
これは、`--db` オプションを指定することによって変更することが出来ます。例えば、
```
yii migrate --db=db2
```
上記のコマンドは、既定のマイグレーションパスに置かれている *全ての* マイグレーションを `db2` データベースに適用するものです。
アプリケーションが複数のデータベースを扱っている場合は、いくつかのマイグレーションはあるデータベースに適用されなければならず、他のマイグレーションは別のデータベースに適用されなければならない、ということがあり得ます。
そのような場合には、異なるデータベースごとに基底マイグレーションクラスを作成して、下記のように [[yii\db\Migration::init()]] メソッドをオーバーライドすることを推奨します。
```php
public function init()
{
$this->db = 'db2';
parent::init();
}
```
こうすると、特定のデータベースに適用されるべきマイグレーションを作成するためには、対応する基底マイグレーションクラスから拡張するだけで済みます。
これで、`yii migrate` コマンドを実行すると、全てのマイグレーションはそれぞれ対応するデータベースに対して適用されるようになります。
> Info|情報: それぞれのマイグレーションはハードコードされた DB 接続を使用しますので、`migrate` コマンドの `--db` オプションは効果を持ちません。
また、マイグレーション履歴はデフォルトの `db` データベースに保存されることに注意してください。
`--db` オプションによる DB 接続の変更をサポートしたい場合は、次のような別の方法で複数のデータベースを扱うことが出来ます。
それぞれのデータベースについて、マイグレーションパスを作成し、対応する全てのマイグレーションクラスをそこに保存します。
マイグレーションを適用するためには、次のようなコマンドを実行します。
```
yii migrate --migrationPath=@app/migrations/db1 --db=db1
yii migrate --migrationPath=@app/migrations/db2 --db=db2
...
```
> Info|情報: 上記の方法では、マイグレーション履歴は `--db` オプションによって指定された別々のデータベースに保存されます。

6
docs/guide-ja/db-mongodb.md

@ -0,0 +1,6 @@
Mongo DB
========
> Note|注意: この節はまだ執筆中です。
>
> まだ内容がありません。

6
docs/guide-ja/db-redis.md

@ -0,0 +1,6 @@
Redis
=====
> Note|注意: この節はまだ執筆中です。
>
> まだ内容がありません。

6
docs/guide-ja/db-sphinx.md

@ -0,0 +1,6 @@
Sphinx Search
=============
> Note|注意: この節はまだ執筆中です。
>
> まだ内容がありません。

254
docs/guide-ja/input-file-upload.md

@ -0,0 +1,254 @@
ファイルをアップロードする
==========================
Yii におけるファイルのアップロードは、フォームモデル、その検証規則、そして、いくらかのコントローラコードによって行われます。
アップロードを適切に処理するために何が必要とされるのか、見ていきましよう。
一つのファイルをアップロードする
--------------------------------
まず最初に、ファイルのアップロードを処理するモデルを作成する必要があります。
次の内容を持つ `models/UploadForm.php` を作って作成してください。
```php
namespace app\models;
use yii\base\Model;
use yii\web\UploadedFile;
/**
* UploadForm がアップロードのフォームの背後にあるモデルである。
*/
class UploadForm extends Model
{
/**
* @var UploadedFile file 属性
*/
public $file;
/**
* @return array 検証規則
*/
public function rules()
{
return [
[['file'], 'file'],
];
}
}
```
上記のコードにおいて作成した `UploadForm` というモデルは、HTML フォームで `<input type="file">` となる `$file` という属性を持ちます。
この属性は [[yii\validators\FileValidator|FileValidator]] を使用する `file` という検証規則を持ちます。
### フォームのビュー
次に、フォームを表示するビューを作成します。
```php
<?php
use yii\widgets\ActiveForm;
?>
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]) ?>
<?= $form->field($model, 'file')->fileInput() ?>
<button>送信</button>
<?php ActiveForm::end() ?>
```
ファイルのアップロードを可能にする `'enctype' => 'multipart/form-data'` は不可欠です。
`fileInput()` がフォームの入力フィールドを表します。
### コントローラ
そして、フォームとモデルを結び付けるコントローラを作成します。
```php
namespace app\controllers;
use Yii;
use yii\web\Controller;
use app\models\UploadForm;
use yii\web\UploadedFile;
class SiteController extends Controller
{
public function actionUpload()
{
$model = new UploadForm();
if (Yii::$app->request->isPost) {
$model->file = UploadedFile::getInstance($model, 'file');
if ($model->file && $model->validate()) {
$model->file->saveAs('uploads/' . $model->file->baseName . '.' . $model->file->extension);
}
}
return $this->render('upload', ['model' => $model]);
}
}
```
`model->load(...)` の代りに `UploadedFile::getInstance(...)` を使っています。
[[\yii\web\UploadedFile|UploadedFile]] はモデルの検証を実行せず、アップロードされたファイルに関する情報を提供するだけです。
そのため、`$model->validate()` を手作業で実行して、[[yii\validators\FileValidator|FileValidator]] を起動する必要があります。
[[yii\validators\FileValidator|FileValidator]] は、下記のコアコードが示しているように、属性がファイルであることを要求します。
```php
if (!$file instanceof UploadedFile || $file->error == UPLOAD_ERR_NO_FILE) {
return [$this->uploadRequired, []]; // "ファイルをアップロードしてください。" というエラーメッセージ
}
```
検証が成功したら、ファイルを保存します。
```php
$model->file->saveAs('uploads/' . $model->file->baseName . '.' . $model->file->extension);
```
「ベーシック」アプリケーションテンプレートを使っている場合は、`uploads` フォルダを `web` の下に作成しなければなりません。
以上です。ページをロードして、アップロードを試して見てください。ファイルは `basic/web/uploads` にアップロードされます。
検証
----
たいていの場合、検証規則を調整して、特定のファイルだけを受け取るようにしたり、アップロードを必須としたりする必要があります。
下記で、よく使われる規則の構成を見てみましよう。
### Required
ファイルのアップロードを必須とする必要がある場合は、次のように `skipOnEmpty``false` に設定します。
```php
public function rules()
{
return [
[['file'], 'file', 'skipOnEmpty' => false],
];
}
```
### MIME タイプ
アップロードされるファイルのタイプを検証することは賢明なことです。
`FileValidator` はこの目的のための `extensions` プロパティを持っています。
```php
public function rules()
{
return [
[['file'], 'file', 'extensions' => 'gif, jpg',],
];
}
```
ただし、ファイル拡張子が検証されるだけで、実際のファイルの中身は検証されないことを憶えておいてください。
ファイルの中身も検証するためには、`FileValidator` の `mimeType` プロパティを使います。
```php
public function rules()
{
return [
[['file'], 'file', 'extensions' => 'jpg, png', 'mimeTypes' => 'image/jpeg, image/png',],
];
}
```
[一般的なメディアタイプの一覧表](http://en.wikipedia.org/wiki/Internet_media_type#List_of_common_media_types)
### 画像のプロパティ
画像をアップロードするときは、[[yii\validators\ImageValidator|ImageValidator]] が重宝するでしょう。
このバリデータは、属性が有効な画像を受け取ったか否かを検証します。
その画像は、[Imagine エクステンション](https://github.com/yiisoft/yii2/tree/master/extensions/imagine) によって、保存するか、または、処理することが出来ます。
複数のファイルをアップロードする
--------------------------------
複数のファイルを一度にアップロードする必要がある場合は、少し修正が必要になります。
モデル:
```php
class UploadForm extends Model
{
/**
* @var UploadedFile|Null ファイル属性
*/
public $file;
/**
* @return array 検証規則
*/
public function rules()
{
return [
[['file'], 'file', 'maxFiles' => 10], // <--- ここ !
];
}
}
```
ビュー:
```php
<?php
use yii\widgets\ActiveForm;
$form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]);
?>
<?= $form->field($model, 'file[]')->fileInput(['multiple' => true]) ?>
<button>送信</button>
<?php ActiveForm::end(); ?>
```
違いがあるのは、次の行です。
```php
<?= $form->field($model, 'file[]')->fileInput(['multiple' => true]) ?>
```
コントローラ:
```php
namespace app\controllers;
use Yii;
use yii\web\Controller;
use app\models\UploadForm;
use yii\web\UploadedFile;
class SiteController extends Controller
{
public function actionUpload()
{
$model = new UploadForm();
if (Yii::$app->request->isPost) {
$model->file = UploadedFile::getInstances($model, 'file');
if ($model->file && $model->validate()) {
foreach ($model->file as $file) {
$file->saveAs('uploads/' . $file->baseName . '.' . $file->extension);
}
}
}
return $this->render('upload', ['model' => $model]);
}
}
```
単一のファイルのアップロードとは、二つの点で異なります。
最初の違いは、`UploadedFile::getInstance($model, 'file');` の代りに `UploadedFile::getInstances($model, 'file');` が使用されることです。
前者が一つのインスタンスを返すだけなのに対して、後者はアップロードされた **全ての** ファイルのインスタンスを返します。
第二の違いは、`foreach` によって、全てのファイルをそれぞれ保存している点です。

191
docs/guide-ja/input-forms.md

@ -0,0 +1,191 @@
フォームを扱う
==============
> Note|注意: この節はまだ執筆中です。
Yii においてフォームを使用する主たる方法は [[yii\widgets\ActiveForm]] によるものです。
フォームがモデルに基づくものである場合はこの方法を優先すべきです。
これに加えて、[[yii\helpers\Html]] にはいくつかの有用なメソッドがあり、通常は、あらゆるフォームにボタンやヘルプテキストを追加するのに使うことが出来ます。
モデルに基づくフォームを作成する場合、最初のステップは、モデルそのものを定義することです。
モデルは、アクティブレコードクラス、あるいは、もっと汎用的な Model クラスから派生させることが出来ます。
このログインフォームの例では、汎用的なモデルを使用します。
```php
use yii\base\Model;
class LoginForm extends Model
{
public $username;
public $password;
/**
* @return array 検証規則
*/
public function rules()
{
return [
// username と password はともに必須
[['username', 'password'], 'required'],
// password は validatePassword() によって検証される
['password', 'validatePassword'],
];
}
/**
* パスワードを検証する
* このメソッドがパスワードのインライン検証に使用される
*/
public function validatePassword()
{
$user = User::findByUsername($this->username);
if (!$user || !$user->validatePassword($this->password)) {
$this->addError('password', 'Incorrect username or password.');
}
}
/**
* 提供された username と password でユーザをログインさせる。
* @return boolean ユーザのログインが成功したかどうか
*/
public function login()
{
if ($this->validate()) {
$user = User::findByUsername($this->username);
return true;
} else {
return false;
}
}
}
```
コントローラはこのモデルのインスタンスをビューに渡し、ビューでは [[yii\widgets\ActiveForm|ActiveForm]] ウィジェットが使われます。
```php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
<?php $form = ActiveForm::begin([
'id' => 'login-form',
'options' => ['class' => 'form-horizontal'],
]) ?>
<?= $form->field($model, 'username') ?>
<?= $form->field($model, 'password')->passwordInput() ?>
<div class="form-group">
<div class="col-lg-offset-1 col-lg-11">
<?= Html::submitButton('ログイン', ['class' => 'btn btn-primary']) ?>
</div>
</div>
<?php ActiveForm::end() ?>
```
上記のコードでは、[[yii\widgets\ActiveForm::begin()|ActiveForm::begin()]] がフォームのインスタンスを作成するだけでなく、フォームの開始をマークしています。
[[yii\widgets\ActiveForm::begin()|ActiveForm::begin()]] と [[yii\widgets\ActiveForm::end()|ActiveForm::end()]] の間に置かれた全てのコンテントが `<form>` タグによって囲まれます。
その他のウィジェットと同じように、ウィジェットをどのように構成すべきかに関するオプションを指定するために、`begin` メソッドに配列を渡すことが出来ます。
この例では、追加の CSS クラスと要素を特定するための ID が渡されて、開始 `<form>` タグに適用されています。
フォームの中で、フォームの要素を作成するために、ActiveForm ウィジェットの [[yii\widgets\ActiveForm::field()|ActiveForm::field()]] メソッドが呼ばれています。このメソッドは、要素のラベルと、適用できる JavaScript の検証メソッドがあれば、それらも追加します。
このメソッドの呼び出し結果を直接にエコーすると、結果は通常の (text の) インプットになります。
出力結果をカスタマイズするためには、このメソッドの呼び出しに追加のメソッドをチェーンします。
```php
<?= $form->field($model, 'password')->passwordInput() ?>
// または
<?= $form->field($model, 'username')->textInput()->hint('お名前を入力してください')->label('お名前') ?>
```
これで、フォームのフィールドによって定義されたテンプレートに従って、`<label>`、`<input>` など、全てのタグが生成されます。
これらのタグを自分で追加するためには、`Html` ヘルパクラスを使うことが出来ます。
HTML5 のフィールドを使いたい場合は、次のように、インプットのタイプを直接に指定することが出来ます。
```php
<?= $form->field($model, 'email')->input('email') ?>
```
モデルの属性を指定するためには、もっと洗練された方法を使うことも出来ます。
例えば、複数のファイルをアップロードしたり、複数の項目を選択したりする場合に、属性の名前に `[]` を付けて、属性が配列の値を取り得ることを指定することが出来ます。
```php
// 複数のファイルのアップロードを許可する
echo $form->field($model, 'uploadFile[]')->fileInput(['multiple'=>'multiple']);
// 複数の項目をチェックすることを許可する
echo $form->field($model, 'items[]')->checkboxList(['a' => 'Item A', 'b' => 'Item B', 'c' => 'Item C']);
```
> **tip**|**ヒント**: 必須フィールドをアスタリスク付きのスタイルにするために、次の CSS を使うことが出来ます。
>
```css
div.required label:after {
content: " *";
color: red;
}
```
一つのフォームで複数のモデルを扱う
----------------------------------
時として、一つのフォームで同じ種類の複数のモデルを扱わなければならないことがあります。
例えば、それぞれが「名前-値」の形で保存され、`Setting` モデルとして表される複数の設定項目を扱うフォームです。
以下に、これを Yii で実装する方法を示します。
コントローラアクションから始めましよう。
```php
namespace app\controllers;
use Yii;
use yii\base\Model;
use yii\web\Controller;
use app\models\Setting;
class SettingsController extends Controller
{
// ...
public function actionUpdate()
{
$settings = Setting::find()->indexBy('id')->all();
if (Model::loadMultiple($settings, Yii::$app->request->post()) && Model::validateMultiple($settings)) {
foreach ($settings as $setting) {
$setting->save(false);
}
return $this->redirect('index');
}
return $this->render('update', ['settings' => $settings]);
}
}
```
上記のコードでは、データベースからモデルを読み出すときに `indexBy` を使って、モデルの ID でインデックスされた配列にモデルを代入しています。
このインデックスが、後で、フォームフィールドを特定するために使われます。
`loadMultiple` が POST から来るフォームデータを複数のモデルに代入し、`validateMultiple` が全てのモデルを一度に検証します。
保存するときの検証をスキップするために、`save` のパラメータに `false` を渡しています。
次に、`update` ビューにあるフォームです。
```php
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
$form = ActiveForm::begin();
foreach ($settings as $index => $setting) {
echo Html::encode($setting->name) . ': ' . $form->field($setting, "[$index]value");
}
ActiveForm::end();
```
ここで全ての設定項目について、それぞれ、名前と値を入れたインプットをレンダリングしています。
インプットの名前に適切なインデックスを追加することが肝腎です。
というのは、`loadMultiple` がそれを見て、どのモデルにどの値を代入するかを決定するからです。

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

@ -0,0 +1,6 @@
複数のモデルを扱う複雑なフォーム
================================
> Note|注意: この節はまだ執筆中です。
>
> まだ内容がありません。

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

@ -0,0 +1,610 @@
入力を検証する
==============
大まかに言うなら、エンドユーザから受信したデータは決して信用せず、利用する前に検証しなければならない、ということです。
[モデル](structure-models.md) にユーザの入力が投入されたら、モデルの [[yii\base\Model::validate()]] メソッドを呼んで入力を検証することが出来ます。
このメソッドはバリデーションが成功したか否かを示す真偽値を返します。
バリデーションが失敗した場合は、[[yii\base\Model::errors]] プロパティからエラーメッセージを取得することが出来ます。
例えば、
```php
$model = new \app\models\ContactForm;
// モデルの属性にユーザ入力を投入する
$model->attributes = \Yii::$app->request->post('ContactForm');
if ($model->validate()) {
// 全ての入力が有効
} else {
// バリデーションが失敗。$errors はエラーメッセージを含む配列
$errors = $model->errors;
}
```
## 規則を宣言する <a name="declaring-rules"></a>
`validate()` を現実に動作させるためには、検証する予定の属性に対してバリデーション規則を宣言しなければなりません。
規則は [[yii\base\Model::rules()]] メソッドをオーバーライドすることで宣言します。
次の例は、`ContactForm` モデルに対してバリデーション規則を宣言する方法を示すものです。
```php
public function rules()
{
return [
// 名前、メールアドレス、主題、本文が必須項目
[['name', 'email', 'subject', 'body'], 'required'],
// email 属性は有効なメールアドレスでなければならない
['email', 'email'],
];
}
```
[[yii\base\Model::rules()|rules()]] メソッドは配列を返すべきものですが、配列の各要素は次の形式の配列でなければなりません。
```php
[
// 必須。この規則によって検証されるべき属性を指定する。
// 属性が一つだけの場合は、配列の中に入れずに、属性の名前を直接に書いてもよい。
['属性1', '属性2', ...],
// 必須。この規則のタイプを指定する。
// クラス名、バリデータのエイリアス、または、バリデーションメソッドの名前。
'バリデータ',
// オプション。この規則が適用されるべき一つまたは複数のシナリオを指定する。
// 指定しない場合は、この規則が全てのシナリオに適用されることを意味する。
// "except" オプションを構成して、列挙したシナリオを除く全てのシナリオに
// この規則が適用されるべきことを指定することも出来る。
'on' => ['シナリオ1', 'シナリオ2', ...],
// オプション。バリデータオブジェクトに対する追加の構成情報を指定する。
'プロパティ1' => '値1', 'プロパティ2' => '値2', ...
]
```
各規則について、最低限、規則がどの属性に適用されるか、そして、規則がどのタイプであるかを指定しなければなりません。
規則のタイプは、次に挙げる形式のどれか一つを選ぶことが出来ます。
* コアバリデータのエイリアス。例えば、`required`、`in`、`date`、等々。
コアバリデータの完全なリストは [コアバリデータ](tutorial-core-validators.md) を参照してください。
* モデルクラス内のバリデーションメソッドの名前、または無名関数。詳細は、[インラインバリデータ](#inline-validators) の項を参照してください。
* 完全修飾のバリデータクラス名。詳細は [スタンドアロンバリデータ](#standalone-validators) の項を参照してください。
一つの規則は、一つまたは複数の属性を検証するために使用することが出来ます。
そして、一つの属性は、一つまたは複数の規則によって検証され得ます。
`on` オプションを指定することで、規則を特定の [シナリオ](structure-models.md#scenarios) においてのみ適用することが出来ます。
`on` オプションを指定しない場合は、規則が全てのシナリオに適用されることになります。
`validate()` メソッドが呼ばれると、次のステップを踏んでバリデーションが実行されます。
1. 現在の [[yii\base\Model::scenario|シナリオ]] を使って [[yii\base\Model::scenarios()]] から属性のリストを取得し、どの属性が検証されるべきかを決定します。
検証されるべき属性が *アクティブな属性* と呼ばれます。
2. 現在の [[yii\base\Model::scenario|シナリオ]] を使って [[yii\base\Model::rules()]] から規則のリストを取得し、どのバリデーション規則が使用されるべきかを決定します。
使用されるべき規則が *アクティブな規則* と呼ばれます。
3. 全てのアクティブな規則を一つずつ使って、その規則に関連付けられた全てのアクティブな属性を一つずつ検証します。
バリデーション規則はリストに挙げられている順に評価されます。
属性は、上記のバリデーションのステップに従って、`scenarios()` でアクティブな属性であると宣言されており、かつ、`rules()` で宣言された一つまたは複数のアクティブな規則と関連付けられている場合に、また、その場合に限って、検証されます。
### エラーメッセージをカスタマイズする <a name="customizing-error-messages"></a>
たいていのバリデータはデフォルトのエラーメッセージを持っていて、属性のバリデーションが失敗した場合にそれを検証の対象であるモデルに追加します。
例えば、[[yii\validators\RequiredValidator|required]] バリデータは、このバリデータを使って `username` 属性を検証したとき、規則に合致しない場合は「ユーザ名は空ではいけません。」というエラーメッセージをモデルに追加します。
規則のエラーメッセージは、次に示すように、規則を宣言するときに `message` プロパティを指定することによってカスタマイズすることが出来ます。
```php
public function rules()
{
return [
['username', 'required', 'message' => 'ユーザ名を選んでください。'],
];
}
```
バリデータの中には、バリデーションを失敗させたさまざまな原因をより詳しく説明するための追加のエラーメッセージをサポートしているものがあります。
例えば、[[yii\validators\NumberValidator|number]] バリデータは、検証される値が大きすぎたり小さすぎたりしたときにバリデーションの失敗を説明するために、それぞれ、[[yii\validators\NumberValidator::tooBig|tooBig]] および [[yii\validators\NumberValidator::tooSmall|tooSmall]] のメッセージをサポートしています。
これらのエラーメッセージも、バリデータの他のプロパティと同様、バリデーション規則の中で構成することが出来ます。
### バリデーションのイベント <a name="validation-events"></a>
[[yii\base\Model::validate()]] は、呼び出されると、バリデーションプロセスをカスタマイズするためにオーバーライドできる二つのメソッドを呼び出します。
* [[yii\base\Model::beforeValidate()]]: 既定の実装は [[yii\base\Model::EVENT_BEFORE_VALIDATE]] イベントをトリガするものです。
このメソッドをオーバーライドするか、または、イベントに反応して、バリデーションが実行される前に、何らかの前処理 (例えば入力されたデータの正規化) をすることが出来ます。
このメソッドは、バリデーションを続行すべきか否かを示す真偽値を返さなくてはなりません。
* [[yii\base\Model::afterValidate()]]: 既定の実装は [[yii\base\Model::EVENT_AFTER_VALIDATE]] イベントをトリガするものです。
このメソッドをオーバーライドするか、または、イベントに反応して、バリデーションが完了した後に、何らかの後処理をすることが出来ます。
### 条件付きバリデーション <a name="conditional-validation"></a>
特定の条件が満たされる場合に限って属性を検証したい場合、例えば、ある属性のバリデーションが他の属性の値に依存する場合には、[[yii\validators\Validator::when|when]] プロパティを使って、そのような条件を定義することが出来ます。
例えば、
```php
[
['state', 'required', 'when' => function($model) {
return $model->country == 'USA';
}],
]
```
[[yii\validators\Validator::when|when]] プロパティは、次のシグニチャを持つ PHP コーラブルを値として取ります。
```php
/**
* @param Model $model 検証されるモデル
* @param string $attribute 検証される属性
* @return boolean 規則が適用されるか否か
*/
function ($model, $attribute)
```
クライアント側でも条件付きバリデーションをサポートする必要がある場合は、[[yii\validators\Validator::whenClient|whenClient]] プロパティを構成しなければなりません。
このプロパティは、規則を適用すべきか否かを返す JavaScript 関数を表す文字列を値として取ります。
例えば、
```php
[
['state', 'required', 'when' => function ($model) {
return $model->country == 'USA';
}, 'whenClient' => "function (attribute, value) {
return $('#country').val() == 'USA';
}"],
]
```
### データのフィルタリング <a name="data-filtering"></a>
ユーザ入力をフィルタまたは前処理する必要があることがよくあります。
例えば、`username` の入力値の前後にある空白を除去したいというような場合です。
この目的を達するためにバリデーション規則を使うことが出来ます。
次の例では、入力値の前後にある空白を除去して、空の入力値を null に変換することを、[trim](tutorial-core-validators.md#trim) および [default](tutorial-core-validators.md#default) のコアバリデータで行っています。
```php
[
[['username', 'email'], 'trim'],
[['username', 'email'], 'default'],
]
```
もっと汎用的な [filter](tutorial-core-validators.md#filter) バリデータを使って、もっと複雑なデータフィルタリングをすることも出来ます。
お分かりかと思いますが、これらのバリデーション規則は実際には入力を検証しません。そうではなくて、検証される属性の値を処理して書き戻すのです。
### 空の入力値を扱う <a name="handling-empty-inputs"></a>
HTML フォームから入力データが送信されたとき、入力値が空である場合には何らかのデフォルト値を割り当てなければならないことがよくあります。
[default](tutorial-core-validators.md#default) バリデータを使ってそうすることが出来ます。
例えば、
```php
[
// 空の時は "username" と "email" を null にする
[['username', 'email'], 'default'],
// 空の時は "level" を 1 にする
['level', 'default', 'value' => 1],
]
```
既定では、入力値が空であると見なされるのは、それが、空文字列であるか、空配列であるか、null であるときです。
空を検知するこのデフォルトのロジックは、[[yii\validators\Validator::isEmpty]] プロパティを PHP コーラブルで構成することによって、カスタマイズすることが出来ます。
例えば、
```php
[
['agree', 'required', 'isEmpty' => function ($value) {
return empty($value);
}],
]
```
> Note|注意: たいていのバリデータは、[[yii\base\Validator::skipOnEmpty]] プロパティがデフォルト値 `true` を取っている場合は、空の入力値を処理しません。
そのようなバリデータは、関連付けられた属性が空の入力値を受け取ったときは、バリデーションの過程ではスキップされるだけになります。
[コアバリデータ](tutorial-core-validators.md) の中では、`captcha`、`default`、`filter`、`required`、そして `trim` だけが空の入力値を処理します。
## アドホックなバリデーション <a name="ad-hoc-validation"></a>
時として、何らかのモデルに結び付けられていない値に対する *アドホックなバリデーション* を実行しなければならない場合があります。
実行する必要があるバリデーションが一種類 (例えば、メールアドレスの検証) だけである場合は、使いたいバリデータの [[yii\validators\Validator::validate()|validate()]] メソッドを次のように呼び出すことが出来ます。
```php
$email = 'test@example.com';
$validator = new yii\validators\EmailValidator();
if ($validator->validate($email, $error)) {
echo 'メールアドレスは有効。';
} else {
echo $error;
}
```
> Note|注意: 全てのバリデータがこの種のバリデーションをサポートしている訳ではありません。
その一例が [unique](tutorial-core-validators.md#unique) コアバリデータであり、これはモデルとともに使用されることだけを念頭にして設計されています。
いくつかの値に対して複数のバリデーションを実行する必要がある場合は、属性と規則の両方をその場で宣言することが出来る [[yii\base\DynamicModel]] を使うことが出来ます。
これは、次のような使い方をします。
```php
public function actionSearch($name, $email)
{
$model = DynamicModel::validateData(compact('name', 'email'), [
[['name', 'email'], 'string', 'max' => 128],
['email', 'email'],
]);
if ($model->hasErrors()) {
// バリデーションが失敗
} else {
// バリデーションが成功
}
}
```
[[yii\base\DynamicModel::validateData()]] メソッドは `DynamicModel` のインスタンスを作成し、与えられた値 (この例では `name``email`) を使って属性を定義し、そして、与えられた規則で [[yii\base\Model::validate()]] を呼び出します。
別の選択肢として、次のように、もっと「クラシック」な構文を使って、アドホックなデータバリデーションを実行することも出来ます。
```php
public function actionSearch($name, $email)
{
$model = new DynamicModel(compact('name', 'email'));
$model->addRule(['name', 'email'], 'string', ['max' => 128])
->addRule('email', 'email')
->validate();
if ($model->hasErrors()) {
// バリデーションが失敗
} else {
// バリデーションが成功
}
}
```
検証を実行した後は、通常のモデルで行うのと同様に、バリデーションが成功したか否かを [[yii\base\DynamicModel::hasErrors()|hasErrors()]] メソッドを呼んでチェックして、[[yii\base\DynamicModel::errors|errors]] プロパティからバリデーションエラーを取得することが出来ます。
また、このモデルのインスタンスによって定義された動的な属性に対しても、例えば `$model->name``$model->email` のようにして、アクセスすることが出来ます。
## バリデータを作成する <a name="creating-validators"></a>
Yii のリリースに含まれている [コアバリデータ](tutorial-core-validators.md) を使う以外に、あなた自身のバリデータを作成することも出来ます。
インラインバリデータとスタンドアロンバリデータを作ることが出来ます。
### インラインバリデータ <a name="inline-validators"></a>
インラインバリデータは、モデルのメソッドまたは無名関数として定義されるバリデータです。
メソッド/関数 のシグニチャは、
```php
/**
* @param string $attribute 現在検証されている属性
* @param array $params 規則に与えられる追加の「名前-値」のペア
*/
function ($attribute, $params)
```
属性がバリデーションに失敗した場合は、メソッド/関数 は [[yii\base\Model::addError()]] を呼んでエラーメッセージをモデルに保存し、後で読み出してエンドユーザに示ことが出来るようにしなければなりません。
下記にいくつかの例を示します。
```php
use yii\base\Model;
class MyForm extends Model
{
public $country;
public $token;
public function rules()
{
return [
// モデルメソッド validateCountry() として定義されるインラインバリデータ
['country', 'validateCountry'],
// 無名関数として定義されるインラインバリデータ
['token', function ($attribute, $params) {
if (!ctype_alnum($this->$attribute)) {
$this->addError($attribute, 'トークンは英数字で構成しなければなりません。');
}
}],
];
}
public function validateCountry($attribute, $params)
{
if (!in_array($this->$attribute, ['USA', 'Web'])) {
$this->addError($attribute, '国は "USA" または "Web" でなければなりません。');
}
}
}
```
> Note|注意: 既定では、インラインバリデータは、関連付けられている属性が空の入力値を受け取ったり、既に何らかのバリデーション規則に失敗したりしている場合には、適用されません。
> 規則が常に適用されることを保証したい場合は、規則の宣言において [[yii\validators\Validator::skipOnEmpty|skipOnEmpty]] および/または [[yii\validators\Validator::skipOnError|skipOnError]] のプロパティを false に設定することが出来ます。
> 例えば、
>
> ```php
> [
> ['country', 'validateCountry', 'skipOnEmpty' => false, 'skipOnError' => false],
> ]
> ```
### スタンドアロンバリデータ <a name="standalone-validators"></a>
スタンドアロンバリデータは、[[yii\validators\Validator]] またはその子クラスを拡張するクラスです。
[[yii\validators\Validator::validateAttribute()]] メソッドをオーバーライドすることによって、その検証ロジックを実装することが出来ます。
[インラインバリデータ](#inline-validators) でするのと同じように、属性がバリデーションに失敗した場合は、[[yii\base\Model::addError()]] を呼んでエラーメッセージをモデルに保存します。
例えば、
```php
namespace app\components;
use yii\validators\Validator;
class CountryValidator extends Validator
{
public function validateAttribute($model, $attribute)
{
if (!in_array($model->$attribute, ['USA', 'Web'])) {
$this->addError($model, $attribute, '国は "USA" または "Web" でなければなりません。');
}
}
}
```
あなたのバリデータで、モデル無しの値のバリデーションをサポートしたい場合は、[[yii\validators\Validator::validate()]] もオーバーライドしなければなりません。
または、`validateAttribute()` と `validate()` の代りに、[[yii\validators\Validator::validateValue()]] をオーバーライドしても構いません。
と言うのは、前の二つは、デフォルトでは、`validateValue()` を呼び出すことによって実装されているからです。
## クライアント側でのバリデーション <a name="client-side-validation"></a>
エンドユーザが HTML フォームで値を入力する際には、JavaScript に基づくクライアント側でのバリデーションを提供することが望まれます。
というのは、クライアント側でのバリデーションは、ユーザが入力のエラーを早く見つけることが出来るようにすることによって、より良いユーザ体験を提供するものだからです。
あなたも、サーバ側でのバリデーション *に加えて* クライアント側でのバリデーションをサポートするバリデータを使用したり実装したりすることが出来ます。
> Info|情報: クライアント側でのバリデーションは望ましいものですが、不可欠なものではありません。
その主たる目的は、ユーザにより良い体験を提供することにあります。
エンドユーザから来る入力値と同じように、クライアント側でのバリデーションを決して信用してはいけません。
この理由により、これまでの項で説明したように、常に [[yii\base\Model::validate()]] を呼び出してサーバ側でのバリデーションを実行しなければなりません。
### クライアント側でのバリデーションを使う <a name="using-client-side-validation"></a>
多くの [コアバリデータ](tutorial-core-validators.md) は、そのままで、クライアント側でのバリデーションをサポートしています。
あなたがする必要があるのは、[[yii\widgets\ActiveForm]] を使って HTML フォームを作るということだけです。
例えば、下の `LoginForm` は二つの規則を宣言しています。
一つは、[required](tutorial-core-validators.md#required) コアバリデータを使っていますが、これはクライアント側とサーバ側の両方でサポートされています。
もう一つは `validatePassword` インラインバリデータを使っていますが、こちらはサーバ側でのみサポートされています。
```php
namespace app\models;
use yii\base\Model;
use app\models\User;
class LoginForm extends Model
{
public $username;
public $password;
public function rules()
{
return [
// username と password はともに必須
[['username', 'password'], 'required'],
// password は validatePassword() によって検証される
['password', 'validatePassword'],
];
}
public function validatePassword()
{
$user = User::findByUsername($this->username);
if (!$user || !$user->validatePassword($this->password)) {
$this->addError('password', 'ユーザ名またはパスワードが違います。');
}
}
}
```
次のコードによって構築される HTML フォームは、`username` と `password` の二つの入力フィールドを含みます。
何も入力せずにこのフォームを送信すると、何かを入力するように要求するエラーメッセージが、サーバと少しも交信することなく、ただちに表示されることに気付くでしょう。
```php
<?php $form = yii\widgets\ActiveForm::begin(); ?>
<?= $form->field($model, 'username') ?>
<?= $form->field($model, 'password')->passwordInput() ?>
<?= Html::submitButton('ログイン') ?>
<?php yii\widgets\ActiveForm::end(); ?>
```
舞台裏では、[[yii\widgets\ActiveForm]] がモデルで宣言されているバリデーション規則を読んで、クライアント側のバリデーションをサポートするバリデータのために適切な JavaScript コードを生成します。
ユーザが入力フィールドの値を変更したりフォームを送信したりすると、クライアント側バリデーションの JavaScript が起動されます。
クライアント側のバリデーションを完全に無効にしたい場合は、[[yii\widgets\ActiveForm::enableClientValidation]] プロパティを false に設定することが出来ます。
また、個々の入力フィールドごとにクライアント側のバリデーションを無効にしたい場合は、入力フィールドの [[yii\widgets\ActiveField::enableClientValidation]] プロパティを false に設定することも出来ます。
### クライアント側バリデーションを実装する <a name="implementing-client-side-validation"></a>
クライアント側バリデーションをサポートするバリデータを作成するためには、クライアント側でのバリデーションを実行する JavaScript コードを返す [[yii\validators\Validator::clientValidateAttribute()]] メソッドを実装しなければなりません。
その JavaScript の中では、次の事前定義された変数を使用することが出来ます。
- `attribute`: 検証される属性の名前。
- `value`: 検証される値。
- `messages`: 属性に対する検証のエラーメッセージを保持するために使用される配列。
- `deferred`: Deferred オブジェクトをプッシュして入れることが出来る配列 (次の項で説明します)。
次の例では、既存のステータスのデータに含まれる有効な値が入力されたかどうかを検証する `StatusValidator` を作成します。
このバリデータは、サーバ側とクライアント側の両方のバリデーションをサポートします。
```php
namespace app\components;
use yii\validators\Validator;
use app\models\Status;
class StatusValidator extends Validator
{
public function init()
{
parent::init();
$this->message = '無効なステータスが入力されました。';
}
public function validateAttribute($model, $attribute)
{
$value = $model->$attribute;
if (!Status::find()->where(['id' => $value])->exists()) {
$model->addError($attribute, $this->message);
}
}
public function clientValidateAttribute($model, $attribute, $view)
{
$statuses = json_encode(Status::find()->select('id')->asArray()->column());
$message = json_encode($this->message, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
return <<<JS
if (!$.inArray(value, $statuses)) {
messages.push($message);
}
JS;
}
}
```
> Tip|ヒント: 上記のコード例の主たる目的は、クライアント側バリデーションをサポートする方法を説明することにあります。
> 実際の仕事では、[in](tutorial-core-validators.md#in) コアバリデータを使って、同じ目的を達することが出来ます。
> 次のようにバリデーション規則を書けばよいのです。
>
> ```php
> [
> ['status', 'in', 'range' => Status::find()->select('id')->asArray()->column()],
> ]
> ```
### Deferred バリデーション <a name="deferred-validation"></a>
非同期のクライアント側バリデーションをサポートする必要がある場合は、[Defered オブジェクト](http://api.jquery.com/category/deferred-object/) を作成することが出来ます。
例えば、AJAX によるカスタムバリデーションを実行するために、次のコードを使うことが出来ます。
```php
public function clientValidateAttribute($model, $attribute, $view)
{
return <<<JS
deferred.push($.get("/check", {value: value}).done(function(data) {
if ('' !== data) {
messages.push(data);
}
}));
JS;
}
```
上のコードにおいて、`deferred` は Yii が提供する変数で、Deferred オブジェクトの配列です。
jQuery の `$.get()` メソッドによって作成された Deferred オブジェクトが `deferred` 配列にプッシュされています。
Deferred オブジェクトを明示的に作成して、非同期のコールバックが呼ばれたときに、Deferred オブジェクトの `resolve()` メソッドを呼ぶことも出来ます。
次の例は、アップロードされる画像ファイルの大きさをクライアント側で検証する方法を示すものです。
```php
public function clientValidateAttribute($model, $attribute, $view)
{
return <<<JS
var def = $.Deferred();
var img = new Image();
img.onload = function() {
if (this.width > 150) {
messages.push('画像の幅が大きすぎます。');
}
def.resolve();
}
var reader = new FileReader();
reader.onloadend = function() {
img.src = reader.result;
}
reader.readAsDataURL(file);
deferred.push(def);
JS;
}
```
> Note|注意: 属性が検証された後に、`resolve()` メソッドを呼び出さなければなりません。
そうしないと、主たるフォームのバリデーションが完了しません。
簡潔に記述できるように、`deferred` 配列はショートカットメソッド `add()` を装備しており、このメソッドを使うと、自動的に Deferred オブジェクトを作成して `deferred` 配列に追加することが出来ます。
このメソッドを使えば、上記の例は次のように簡潔に記すことが出来ます。
```php
public function clientValidateAttribute($model, $attribute, $view)
{
return <<<JS
deferred.add(function(def) {
var img = new Image();
img.onload = function() {
if (this.width > 150) {
messages.push('画像の幅が大きすぎます。');
}
def.resolve();
}
var reader = new FileReader();
reader.onloadend = function() {
img.src = reader.result;
}
reader.readAsDataURL(file);
});
JS;
}
```
### AJAX バリデーション <a name="ajax-validation"></a>
場合によっては、サーバだけが必要な情報を持っているために、サーバ側でしか検証が実行できないことがあります。
例えば、ユーザ名がユニークであるか否かを検証するためには、サーバ側で user テーブルを調べることが必要になります。
このような場合には、AJAX ベースのバリデーションを使うことが出来ます。
AJAX バリデーションは、通常のクライアント側でのバリデーションと同じユーザ体験を保ちながら、入力値を検証するためにバックグラウンドで AJAX リクエストを発行します。
AJAX バリデーションをフォーム全体に対して有効にするためには、[[yii\widgets\ActiveForm::enableAjaxValidation]] プロパティを `true` に設定して、`id` にフォームを特定するユニークな ID を設定しなければなりません。
```php
<?php $form = yii\widgets\ActiveForm::begin([
'id' => 'contact-form',
'enableAjaxValidation' => true,
]); ?>
```
個別の入力フィールドについても、[[yii\widgets\ActiveField::enableAjaxValidation]] プロパティを設定して、AJAX バリデーションを有効にしたり無効にしたりすることが出来ます。
また、サーバ側では、AJAX バリデーションのリクエストを処理できるように準備しておく必要があります。
これは、コントローラのアクションにおいて、次のようなコード断片を使用することで達成できます。
```php
if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
Yii::$app->response->format = Response::FORMAT_JSON;
return ActiveForm::validate($model);
}
```
上記のコードは、現在のリクエストが AJAX であるかどうかをチェックします。
もし AJAX であるなら、リクエストに応えてバリデーションを実行し、エラーを JSON 形式で返します。
> Info|情報: AJAX バリデーションを実行するためには、[Deferred バリデーション](#deferred-validation) を使うことも出来ます。
しかし、ここで説明された AJAX バリデーションの機能の方がより体系化されており、コーディングの労力も少なくて済みます。

4
docs/guide-ja/intro-yii.md

@ -29,8 +29,8 @@ Yii を他のフレームワークと比べるとどうか?
- 高性能であることは常に Yii の主たる目標です。
Yii はワンマンショーではありません。Yii は [強力なコア開発チーム][] および Yii 開発に間断なく貢献してくれるプロフェッショナルの大きなコミュニティーに支えられたプロジェクトです。
Yii 開発チームは最新のウェブ開発の潮流や、他のフレームワークやプロジェクトに見られる最善の慣行と機能から目を離しません。
他のところで見出された関連性の高い最善の慣行と機能は、定期的にコアフレームワークに組み込まれ、シンプルかつエレガントなインターフェイスを通じて公開されます。
Yii 開発チームは最新のウェブ開発の潮流や、他のフレームワークやプロジェクトに見られるベストプラクティスと機能から目を離しません。
他のところで見出された関連性の高いベストプラクティスと機能は、定期的にコアフレームワークに組み込まれ、シンプルかつエレガントなインターフェイスを通じて公開されます。
[強力なコア開発チーム]: http://www.yiiframework.com/about/

98
docs/guide-ja/output-client-scripts.md

@ -0,0 +1,98 @@
クライアントスクリプトを扱う
============================
> Note|注意: この節はまだ執筆中です。
### スクリプトを登録する
[[yii\web\View]] オブジェクトに対してスクリプトを登録することが出来ます。
このための専用のメソッドが二つあります。
すなわち、インラインスクリプトのための [[yii\web\View::registerJs()|registerJs()]] と、外部スクリプトのための [[yii\web\View::registerJsFile()|registerJsFile()]] です。
インラインスクリプトは、設定のためや、動的に生成されるコードのために有用なものです。
次のようにして、これらを追加するメソッドを使うことが出来ます。
```php
$this->registerJs("var options = ".json_encode($options).";", View::POS_END, 'my-options');
```
最初の引数は、ページに挿入したい実際の JS コードです。
二番目の引数は、スクリプトがページのどの場所に挿入されるべきかを決定します。
取りうる値は以下のとおりです。
- [[yii\web\View::POS_HEAD|View::POS_HEAD]] - head セクション。
- [[yii\web\View::POS_BEGIN|View::POS_BEGIN]] - 開始の `<body>` の直後。
- [[yii\web\View::POS_END|View::POS_END]] - 終了の `</body>` の直前。
- [[yii\web\View::POS_READY|View::POS_READY]] - ドキュメントの `ready` イベントで実行するコード。これを指定すると、[[yii\web\JqueryAsset|jQuery]] が自動的に登録されます。
- [[yii\web\View::POS_LOAD|View::POS_LOAD]] - ドキュメントの `load` イベントで実行するコード。これを指定すると、[[yii\web\JqueryAsset|jQuery]] が自動的に登録されます。
最後の引数は、スクリプトのユニークな ID です。これによってコードブロックを一意に特定し、同じ ID のスクリプトが既にある場合は、新しいものを追加するのでなく、それを置き換えます。
ID を指定しない場合は、JS コードそれ自身が ID として扱われます。
外部スクリプトは次のようにして追加することが出来ます。
```php
$this->registerJsFile('http://example.com/js/main.js', ['depends' => [JqueryAsset::className()]]);
```
[[yii\web\View::registerJsFile()|registerJsFile()]] の引数は [[yii\web\View::registerCssFile()|registerCssFile()]] のそれと同じです。
上記の例では、`main.js` ファイルを `JqueryAsset` に依存するものとして登録しています。
これは、`main.js` ファイルが `jquery.js` の後に追加されるようになることを意味します。
この依存関係を指定しない場合は、`main.js` と `jquery.js` の相対的な順序は未定義となります。
[[yii\web\View::registerCssFile()|registerCssFile()]] と同じように、外部 JS ファイルを登録するのに [[yii\web\View::registerJsFile()|registerJsFile()]] を使わずに、[アセットバンドル](structure-assets.md) を使うことが強く推奨されます。
### アセットバンドルを登録する
既に述べたように、CSS と JavaScript を直接に使う代りにアセットバンドルを使うことが望まれます。
アセットバンドルを定義する方法の詳細は、ガイドの [アセットマネージャ](structure-assets.md) の節で知ることが出来ます。
既に定義されているアセットバンドルを使うことについては、次のように非常に簡明です。
```php
\frontend\assets\AppAsset::register($this);
```
### CSS を登録する
[[yii\web\View::registerCss()|registerCss()]] またはr [[yii\web\View::registerCssFile()|registerCssFile()]] を使って CSS を登録することが出来ます。
前者は CSS のコードブロックを登録し、後者は外部 CSS ファイルを登録します。
例えば、
```php
$this->registerCss("body { background: #f00; }");
```
上記のコードは、以下の内容をページの head セクションに追加する結果となります。
```html
<style>
body { background: #f00; }
</style>
```
`style` タグに追加のプロパティを指定したい場合は、三番目の引数として「名前-値」のペアの配列を渡します。
`style` タグが一つだけになることを保証する必要がある場合は、メタタグの説明で言及したように、4番目の引数を使います。
```php
$this->registerCssFile("http://example.com/css/themes/black-and-white.css", [
'depends' => [BootstrapAsset::className()],
'media' => 'print',
], 'css-print-theme');
```
上記のコードは、ページの head セクションに CSS ファイルへのリンクを追加します。
* 最初の引数が登録されるべき CSS ファイルを指定します。
* 二番目の引数は、結果として生成される `<link>` タグの HTML 属性を指定するものです。
ただし、`depends` オプションは特別な処理を受けます。
このオプションは、この CSS ファイルが依存するアセットバンドルを指定するものです。
この例では、依存するアセットバンドルは [[yii\bootstrap\BootstrapAsset|BootstrapAsset]] です。
これは、この CSS ファイルが、[[yii\bootstrap\BootstrapAsset|BootstrapAsset]] に含まれる CSS ファイルの *後* に追加されることを意味します。
* 最後の引数は、この CSS ファイルを特定するための ID を指定するものです。
指定されていない場合は、CSS ファイルの URL が代りに ID として使用されます。
外部 CSS ファイルを登録するためには、[[yii\web\View::registerCssFile()|registerCssFile()]] を使うのではなく、[アセットバンドル](structure-assets.md) を使うことが強く推奨されます。
アセットバンドルを使うと、複数の CSS ファイルを結合して圧縮することが可能になります。
トラフィックの多いウェブサイトではそうすることが望まれます。

133
docs/guide-ja/output-data-providers.md

@ -0,0 +1,133 @@
データプロバイダ
================
> Note|注意: この節はまだ執筆中です。
データプロバイダは、 [[yii\data\DataProviderInterface]] によってデータセットを抽象化し、ページネーションと並べ替えを処理します。
[グリッドやリストなどのデータウィジェット](output-data-widgets.md) で使用することが出来ます。
Yii は三つのデータプロバイダを内蔵しています。すなわち、[[yii\data\ActiveDataProvider]]、[[yii\data\ArrayDataProvider]] そして [[yii\data\SqlDataProvider]] です。
アクティブデータプロバイダ
--------------------------
`ActiveDataProvider` は [[yii\db\Query]] および [[yii\db\ActiveQuery]] を使って DB クエリを実行して、データを提供します。
次のコードは、これを使って、ActiveRecord のインスタンスを提供する例です。
```php
$provider = new ActiveDataProvider([
'query' => Post::find(),
'pagination' => [
'pageSize' => 20,
],
]);
// 現在のページの投稿を取得する
$posts = $provider->getModels();
```
そして次の例は、ActiveRecord なしで ActiveDataProvider を使う方法を示すものです。
```php
$query = new Query();
$provider = new ActiveDataProvider([
'query' => $query->from('post'),
'sort' => [
// デフォルトのソートを name ASC, created_at DESC とする
'defaultOrder' => [
'name' => SORT_ASC,
'created_at' => SORT_DESC
]
],
'pagination' => [
'pageSize' => 20,
],
]);
// 現在のページの投稿を取得する
$posts = $provider->getModels();
```
配列データプロバイダ
--------------------
ArrayDataProvider はデータの配列に基づいたデータプロバイダを実装するものです。
[[yii\data\ArrayDataProvider::$allModels]] プロパティが、並べ替えやページネーションの対象となるデータの全てのモデルを含みます。
ArrayDataProvider は、並べ替えとページネーションを実行した後に、データを提供します。
[[yii\data\ArrayDataProvider::$sort]] および [[yii\data\ArrayDataProvider::$pagination]] のプロパティを構成して、並べ替えとページネーションの動作をカスタマイズすることが出来ます。
[[yii\data\ArrayDataProvider::$allModels]] 配列の要素は、オブジェクト (例えば、モデルのオブジェクト) であるか、連想配列 (例えば、DAO のクエリ結果) であるかの、どちらかです。
[[yii\data\ArrayDataProvider::$key]] プロパティには、必ず、データレコードを一意的に特定出来るフィールドの名前をセットするか、そのようなフィールドがない場合は `false` をセットするかしなければなりません。
`ActiveDataProvider` と比較すると、`ArrayDataProvider` は、[[yii\data\ArrayDataProvider::$allModels]] を準備して持たなければならないため、効率が良くありません。
`ArrayDataProvider` は次のようにして使用することが出来ます。
```php
$query = new Query();
$provider = new ArrayDataProvider([
'allModels' => $query->from('post')->all(),
'sort' => [
'attributes' => ['id', 'username', 'email'],
],
'pagination' => [
'pageSize' => 10,
],
]);
// 現在のページの投稿を取得する
$posts = $provider->getModels();
```
> Note|注意: 並べ替えの機能を使いたいときは、どのカラムがソート出来るかをプロバイダが知ることが出来るように、[[sort]] プロパティを構成しなければなりません。
SQL データプロバイダ
--------------------
SqlDataProvider は、素の SQL 文に基づいたデータプロバイダを実装するものです。
これは、各要素がクエリ結果の行を表す配列の形式でデータを提供します。
他のプロバイダ同様に、SqlDataProvider も、並べ替えとページネーションをサポートしています。
並べ替えとページネーションは、与えられた [[yii\data\SqlDataProvider::$sql]] 文を "ORDER BY" 句および "LIMIT" 句で修正することによって実行されます。
[[yii\data\SqlDataProvider::$sort]] および [[yii\data\SqlDataProvider::$pagination]] のプロパティを構成して、並べ替えとページネーションの動作をカスタマイズすることが出来ます。
`SqlDataProvider` は次のようにして使用することが出来ます。
```php
$count = Yii::$app->db->createCommand('
SELECT COUNT(*) FROM user WHERE status=:status
', [':status' => 1])->queryScalar();
$dataProvider = new SqlDataProvider([
'sql' => 'SELECT * FROM user WHERE status=:status',
'params' => [':status' => 1],
'totalCount' => $count,
'sort' => [
'attributes' => [
'age',
'name' => [
'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC],
'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC],
'default' => SORT_DESC,
'label' => 'Name',
],
],
],
'pagination' => [
'pageSize' => 20,
],
]);
// 現在のページの user のレコードを取得する
$models = $dataProvider->getModels();
```
> Note|注意: ページネーションの機能を使いたい場合は、[[yii\data\SqlDataProvider::$totalCount]] プロパティに (ページネーション無しの) 総行数を設定しなければなりません。
そして、並べ替えの機能を使いたい場合は、どのカラムがソート出来るかをプロバイダが知ることが出来るように、[[yii\data\SqlDataProvider::$sort]] プロパティを構成しなければなりません。
あなた自身のカスタムデータプロバイダを実装する
----------------------------------------------
(内容未定)

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

@ -0,0 +1,517 @@
データウィジェット
==================
> Note|注意: この節はまだ執筆中です。
ListView
--------
DetailView
----------
DetailView は単一のデータ [[yii\widgets\DetailView::$model|モデル]] の詳細を表示します。
モデルを標準的な書式で表示する場合 (例えば、全てのモデル属性をそれぞれテーブルの一行として表示する場合) に最も適しています。
モデルは [[\yii\base\Model]] のインスタンスか連想配列かのどちらかを取り得ます。
DetailView は [[yii\widgets\DetailView::$attributes]] プロパティを使って、モデルのどの属性をどのように表示すべきかを決定します。
次に DetailView の典型的な用例を示します。
```php
echo DetailView::widget([
'model' => $model,
'attributes' => [
'title', // title 属性 (平文テキストで)
'description:html', // description 属性は HTML
[ // モデルの所有者の名前
'label' => '所有者',
'value' => $model->owner->name,
],
],
]);
```
GridView
--------
データグリッドすなわち GridView は Yii の最も強力なウィジェットの一つです。
これは、システムの管理セクションを素速く作らねばならない時に、この上なく便利なものです。
このウィジェットは [データプロバイダ](output-data-providers.md) からデータを受けて、テーブルの形式で、行ごとに一組のカラムを使ってデータを表示します。
テーブルの各行が一つのデータアイテムを表し、カラムは通常はアイテムの属性を表します (カラムの中には、複数の属性を組み合わせた複雑な式に対応するものや、静的なテキストを表すものもあります)。
グリッドビューはデータアイテムの並べ替えとページネーションの両方をサポートします。
並べ替えとページネーションは、AJAX モードで、あるいは、通常のページリクエストとして、実行することが出来ます。
GridView を使用することの利点は、ユーザが JavaScript を無効化しても、並べ替えとページネーションが自動的に通常のページリクエストにグレードダウンして、引き続き期待通りの動作をするという点にあります。
GridView を使うために必要な最小限のコードは次のようなものです。
```php
use yii\grid\GridView;
use yii\data\ActiveDataProvider;
$dataProvider = new ActiveDataProvider([
'query' => Post::find(),
'pagination' => [
'pageSize' => 20,
],
]);
echo GridView::widget([
'dataProvider' => $dataProvider,
]);
```
上記のコードは、最初にデータプロバイダを作成し、次に GridView を使って、データプロバイダから受け取る全ての行の全ての属性を表示するものです。
そして、表示されたテーブルには、並べ替えとページネーションの機能が装備されます。
### グリッドカラム
Yii のグリッドは数多くのカラムから構成されます。
それらのカラムは、タイプや設定に応じて、さまざまな形でデータを表示することが出来ます。
カラムは、GridView の構成情報の `columns` の部分において、以下のように定義されます。
```php
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
// $dataProvider に含まれるデータによって定義される単純なカラム
// モデルのカラムのデータが使われる
'id',
'username',
// 複雑なカラム定義
[
'class' => 'yii\grid\DataColumn', // 省略可。これが既定値。
'value' => function ($data) {
return $data->name; // 配列データの場合は $data['name']。例えば、SqlDataProvider を使う場合。
},
],
],
]);
```
構成情報の `columns` の部分が指定されない場合は、Yii は、可能な限り、データプロバイダのモデルの全てのカラムを表示しようとすることに注意してください。
### カラムクラス
グリッドのカラムは、いろいろなカラムクラスを使うことでカスタマイズすることが出来ます。
```php
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
[
'class' => 'yii\grid\SerialColumn', // <-- ここ
// ここで追加のプロパティを構成することが出来ます
],
```
Yii によって提供されるカラムクラスを以下で見ていきますが、それらに加えて、あなた自身のカラムクラスを作成することも出来ます。
全てのカラムクラスは [[\yii\grid\Column]] を拡張するものですので、グリッドのカラムを構成するときに設定できる共通のオプションがいくつかあります。
- `header` によって、ヘッダ行のコンテントを設定することが出来ます。
- `footer` によって、振った行のコンテントを設定することが出来ます。
- `visible` はカラムの可視性を定義します。
- `content` によって、行のデータを返す有効な PHP コールバックを渡すことが出来ます。書式は以下の通りです。
```php
function ($model, $key, $index, $column) {
return '文字列';
}
```
下記のオプションに配列を渡して、コンテナ要素のさまざまな HTML オプションを指定することが出来ます。
- `headerOptions`
- `footerOptions`
- `filterOptions`
- `contentOptions`
#### データカラム <a name="data-column"></a>
データカラムは、データの表示と並べ替えに使用されます。
これがデフォルトのカラムタイプですので、これを使用するときはクラスの指定を省略することが出来ます。
データカラムの主要な設定項目は、その書式です。
書式は `format` 属性によって定義することが出来ます。
その値は、デフォルトでは [[\yii\i18n\Formatter|Formatter]] である `formatter` [アプリケーションコンポーネント](structure-application-components.md) のメソッドと対応するものです。
```php
echo GridView::widget([
'columns' => [
[
'attribute' => 'name',
'format' => 'text'
],
[
'attribute' => 'birthday',
'format' => ['date', 'php:Y-m-d']
],
],
]);
```
上記において、`text` は [[\yii\i18n\Formatter::asText()]] に対応し、カラムの値が最初の引数として渡されます。
二番目のカラムの定義では、`date` が [[\yii\i18n\Formatter::asDate()]] に対応します。
カラムの値が、ここでも、最初の引数として渡され、'php:Y-m-d' が二番目の引数の値として渡されます。
利用できるフォーマッタの一覧については、[データのフォーマット](output-formatter.md) の節を参照してください。
#### アクションカラム
アクションカラムは、各行について、更新や削除などのアクションボタンを表示します。
```php
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
[
'class' => 'yii\grid\ActionColumn',
// ここで追加のプロパティを構成することが出来ます
],
```
構成が可能なプロパティは、以下の通りです。
- `controller` は、アクションを処理すべきコントローラの ID です。設定されていない場合は、現在アクティブなコントローラが使われます。
- `template` は、アクションカラムの各セルを構成するのに使用されるテンプレートを定義します。
波括弧に囲まれたトークンは、コントローラのアクション ID として扱われます (アクションカラムのコンテキストでは *ボタンの名前* とも呼ばれます)。
これらは、[[yii\grid\ActionColumn::$buttons|buttons]] によって定義される、対応するボタン表示コールバックによって置き換えられます。
例えば、`{view}` というトークンは、`buttons['view']` のコールバックの結果によって置き換えられます。
コールバックが見つからない場合は、トークンは空文字列によって置き換えられます。
デフォルトのテンプレートは `{view} {update} {delete}` です。
- `buttons` はボタン表示コールバックの配列です。
配列のキーはボタンの名前 (波括弧を除く) であり、値は対応するボタン表示コールバックです。
コールバックは下記のシグニチャを使わなければなりません。
```php
function ($url, $model, $key) {
// ボタンの HTML コードを返す
}
```
上記のコードで、`$url` はカラムがボタンのために生成する URL、`$model` は現在の行に表示されるモデルオブジェクト、そして `$key` はデータプロバイダ配列のモデルのキーです。
- `urlCreator` は、指定されたモデルの情報を使って、ボタンの URL を生成するコールバックです。
コールバックのシグニチャは [[yii\grid\ActionColumn::createUrl()]] のそれと同じでなければなりません。
このプロパティが設定されていないときは、ボタンの URL は [[yii\grid\ActionColumn::createUrl()]] を使って生成されます。
#### チェックボックスカラム
CheckboxColumn はチェックボックスのカラムを表示します。
[[yii\grid\GridView]] に CheckboxColumn を追加するためには、以下のようにして、[[yii\grid\GridView::$columns|columns]] 構成情報にカラムを追加します。
```php
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
// ...
[
'class' => 'yii\grid\CheckboxColumn',
// ここで追加のプロパティを構成することが出来ます
],
],
```
ユーザはチェックボックスをクリックして、グリッドの行を選択することが出来ます。
選択された行は、次の JavaScript コードを呼んで取得することが出来ます。
```javascript
var keys = $('#grid').yiiGridView('getSelectedRows');
// keys は選択された行と関連付けられたキーの配列
```
#### シリアルカラム
シリアルカラムは、`1` から始まる行番号を表示します。
使い方は、次のように、とても簡単です。
```php
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
['class' => 'yii\grid\SerialColumn'], // <-- ここ
// ...
```
### データを並べ替える
- https://github.com/yiisoft/yii2/issues/1576
### データをフィルタリングする
データをフィルタリングするためには、GridView は、フィルタリングのフォームから入力を受け取り、検索基準に合わせてデータプロバイダのクエリを調整するための [モデル](structure-models.md) を必要とします。
[アクティブレコード](db-active-record.md) を使用している場合は、必要な機能を提供する検索用のモデルクラスを作成するのが一般的なプラクティスです (あなたに代って Gii が生成してくれます)。
このクラスは、検索のためのバリデーション規則を定義し、データプロバイダを返す `search()` メソッドを提供するものです。
`Post` モデルに対して検索機能を追加するために、次の例のようにして、`PostSearch` モデルを作成することが出来ます。
```php
<?php
namespace app\models;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
class PostSearch extends Post
{
public function rules()
{
// rules() にあるフィールドだけが検索可能
return [
[['id'], 'integer'],
[['title', 'creation_date'], 'safe'],
];
}
public function scenarios()
{
// 親クラスの scenarios() の実装をバイパスする
return Model::scenarios();
}
public function search($params)
{
$query = Post::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
// 検索フォームのデータをロードして検証する
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
// フィルタを追加してクエリを調整する
$query->andFilterWhere(['id' => $this->id]);
$query->andFilterWhere(['like', 'title', $this->title])
->andFilterWhere(['like', 'creation_date', $this->creation_date]);
return $dataProvider;
}
}
```
この `search()` メソッドをコントローラで使用して、GridView のためのデータプロバイダを取得することが出来ます。
```php
$searchModel = new PostSearch();
$dataProvider = $searchModel->search(Yii::$app->request->get());
return $this->render('myview', [
'dataProvider' => $dataProvider,
'searchModel' => $searchModel,
]);
```
そしてビューでは、`$dataProvider` と `$searchModel` を GridView に与えます。
```php
echo GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
]);
```
### モデルのリレーションを扱う
GridView でアクティブレコードを表示するときに、リレーションのカラムの値、例えば、単に投稿者の `id` というのではなく、投稿者の名前を表示するという場合に遭遇するかも知れません。
`Post` モデルが `author` という名前のリレーションを持っていて、その投稿者のモデルが `name` という属性を持っているなら、カラムの属性名を `author.name` と定義します。
そうすれば、GridView が投稿者の名前を表示するようになります。
ただし、並べ替えとフィルタリングは、既定では有効になりません。
これらの機能を追加するためには、前の項で導入した `PostSearch` モデルを調整しなければなりません。
リレーションのカラムによる並べ替えを有効にするためには、リレーションのテーブルを結合し、データプロバイダの Sort コンポーネントに並べ替えの規則を追加します。
```php
$query = Post::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
// リレーション `author` を結合します。これはテーブル `users` に対するリレーションであり、
// テーブルエイリアスを `author` とします。
$query->joinWith(['author' => function($query) { $query->from(['author' => 'users']); }]);
// リレーションのカラムによる並べ替えを有効にします。
$dataProvider->sort->attributes['author.name'] = [
'asc' => ['author.name' => SORT_ASC],
'desc' => ['author.name' => SORT_DESC],
];
// ...
```
フィルタリングも上記と同じ joinWith の呼び出しを必要とします。また、次のように、`attributes` と `rules` の中で、検索可能なカラムを追加で定義する必要があります。
```php
public function attributes()
{
// 検索可能な属性にリレーションのフィールドを追加する
return array_merge(parent::attributes(), ['author.name']);
}
public function rules()
{
return [
[['id'], 'integer'],
[['title', 'creation_date', 'author.name'], 'safe'],
];
}
```
`search()` メソッドでは、次のように、もう一つのフィルタ条件を追加するだけです。
```php
$query->andFilterWhere(['LIKE', 'author.name', $this->getAttribute('author.name')]);
```
> Info|情報: 上の例では、リレーション名とテーブルエイリアスに同じ文字列を使用しています。
> しかし、エイリアスとリレーション名が異なる場合は、どこでエイリアスを使い、どこでリレーション名を使うかに注意を払わなければなりません。
> これに関する簡単な規則は、データベースクエリを構築するために使われる全ての場所でエイリアスを使い、`attributes()` や `rules()` など、その他の全ての定義においてリレーション名を使う、というものです。
>
> 例えば、投稿者のリレーションテーブルに `au` というエイリアスを使う場合は、joinWith の文は以下のようになります。
>
> ```php
> $query->joinWith(['author' => function($query) { $query->from(['au' => 'users']); }]);
> ```
> リレーションの定義においてエイリアスが定義されている場合は、単に `$query->joinWith(['author']);` として呼び出すことも可能です。
>
> フィルタ条件においてはエイリアスが使われなければなりませんが、属性の名前はリレーション名のままで変りません。
>
> ```php
> $query->andFilterWhere(['LIKE', 'au.name', $this->getAttribute('author.name')]);
> ```
>
> 並べ替えの定義についても同じことです。
>
> ```php
> $dataProvider->sort->attributes['author.name'] = [
> 'asc' => ['au.name' => SORT_ASC],
> 'desc' => ['au.name' => SORT_DESC],
> ];
> ```
>
> さらに、並べ替えの [[yii\data\Sort::defaultOrder|defaultOrder]] を指定するときも、エイリアスではなくリレーション名を使う必要があります。
>
> ```php
> $dataProvider->sort->defaultOrder = ['author.name' => SORT_ASC];
> ```
> Info|情報: `joinWith` およびバックグラウンドで実行されるクエリの詳細については、[アクティブレコード - リレーションを使ってテーブルを結合する](db-active-record.md#joining-with-relations) を参照してください。
#### SQL ビューを使って、データのフィルタリング・並べ替え・表示をする
もう一つ別に、もっと高速で便利な手法があります。SQL ビューです。
例えば、ユーザとユーザのプロファイルを一緒にグリッドビューに表示する必要がある場合、次のような SQL ビューを作成することが出来ます。
```sql
CREATE OR REPLACE VIEW vw_user_info AS
SELECT user.*, user_profile.lastname, user_profile.firstname
FROM user, user_profile
WHERE user.id = user_profile.user_id
```
そして、このビューを表す ActiveRecord を作成します。
```php
namespace app\models\views\grid;
use yii\db\ActiveRecord;
class UserView extends ActiveRecord
{
/**
* @inheritdoc
*/
public static function tableName()
{
return 'vw_user_info';
}
public static function primaryKey()
{
return ['id'];
}
/**
* @inheritdoc
*/
public function rules()
{
return [
// ここで規則を定義
];
}
/**
* @inheritdoc
*/
public static function attributeLabels()
{
return [
// ここで属性のラベルを定義
];
}
}
```
このようにした後は、この UserView アクティブレコードを検索用のモデルとともに使うことが出来ます。
並べ替えやフィルタリングの属性を追加で定義する必要はありません。
全ての属性がそのままで動作します。
この手法にはいくつかの長所と短所があることに注意してください。
- 並べ替えとフィルタリングの条件をいろいろと定義する必要はありません。全てそのままで動きます。- データサイズが小さく、実行される SQL クエリの数が少ない (通常なら全てのリレーションについて一つずつ必要になる追加のクエリが要らない) ため、非常に高速になり得ます。
- これは SQL ビューにかぶせた単純な UI に過ぎないもので、エンティティに含まれるドメインロジックを欠いています。
従って、`isActive` や `isDeleted` などのような UI に影響するメソッドがある場合は、それらをこのクラスの中に複製する必要があります。
### 一つのページに複数のグリッドビュー
単一のページで二つ以上のグリッドビューを使うことが出来ますが、お互いが干渉しないように、追加の構成がいくつか必要になります。
グリッドビューの複数のインスタンスを使う場合は、並べ替えとページネーションのリンクが違うパラメータ名を持って生成されるように構成して、それぞれのグリッドビューが独立した並べ替えとページネーションを持つことが出来るようにしなければなりません。
そのためには、データプロバイダの [[yii\data\BaseDataProvider::$sort|sort]] と [[yii\data\BaseDataProvider::$pagination|pagination]] インスタンスの [[yii\data\Sort::sortParam|sortParam]] と [[yii\data\Pagination::pageParam|pageParam]] を設定します。
`Post``User` のリストを表示するために、二つのプロバイダ、`$userProvider` と `$postProvider` を準備済みであると仮定します。
```php
use yii\grid\GridView;
$userProvider->pagination->pageParam = 'user-page';
$userProvider->sort->sortParam = 'user-sort';
$postProvider->pagination->pageParam = 'post-page';
$postProvider->sort->sortParam = 'post-sort';
echo '<h1>ユーザ</h1>';
echo GridView::widget([
'dataProvider' => $userProvider,
]);
echo '<h1>投稿</h1>';
echo GridView::widget([
'dataProvider' => $postProvider,
]);
```
### GridView を Pjax とともに使う
(内容未定)

190
docs/guide-ja/output-formatter.md

@ -0,0 +1,190 @@
データフォーマッタ
==================
出力をフォーマットするために、Yii はデータをユーザにとってより読みやすいものにするためのフォーマッタクラスを提供しています。
デフォルトでは、[[yii\i18n\Formatter]] というヘルパクラスが、`formatter` という名前の [アプリケーションコンポーネント](structure-application-components.md) として登録されます。
このヘルパが、日付/時刻、数字、その他のよく使われる形式について、データをローカライズしてフォーマットするための一連のメソッドを提供します。
フォーマッタは、二つの異なる方法で使うことが出来ます。
1. フォーマットメソッド (全て `as` という接頭辞を持ちます) を直接に使用する。
```php
echo Yii::$app->formatter->asDate('2014-01-01', 'long'); // 出力: January 1, 2014
echo Yii::$app->formatter->asPercent(0.125, 2); // 出力: 12.50%
echo Yii::$app->formatter->asEmail('cebe@example.com'); // 出力: <a href="mailto:cebe@example.com">cebe@example.com</a>
echo Yii::$app->formatter->asBoolean(true); // 出力: Yes
// null 値の表示も処理します。
echo Yii::$app->formatter->asDate(null); // 出力: (Not set)
```
2. [[yii\i18n\Formatter::format()|format()]] メソッドとフォーマット名を使う。
[[yii\grid\GridView]] や [[yii\widgets\DetailView]] のようなウィジェットでは、構成情報でカラムのデータの書式を指定することが出来ますが、これらウィジェットでもこのメソッドが使われています。
```php
echo Yii::$app->formatter->format('2014-01-01', 'date'); // 出力: January 1, 2014
// 配列を使って、フォーマットメソッドのパラメータを指定することも出来ます。
// `2` は asPercent() メソッドの $decimals パラメータの値です。
echo Yii::$app->formatter->format(0.125, ['percent', 2]); // 出力: 12.50%
```
[PHP intl 拡張](http://php.net/manual/ja/book.intl.php) がインストールされているときは、フォーマッタの全ての出力がローカライズされます。
これのために [[yii\i18n\Formatter::locale|locale]] プロパティを構成することが出来ます。
これが構成されていないときは、アプリケーションの [[yii\base\Application::language|language]] がロケールとして用いられます。
詳細は [国際化](tutorial-i18n.md) の節を参照してください。
フォーマッタはロケールに従って、正しい日付や数字の形式を選択し、月や曜日の名称もカレントの言語に翻訳します。
日付の形式は [[yii\i18n\Formatter::timeZone|timeZone]] によっても左右されます。
[[yii\i18n\Formatter::timeZone|timeZone]] も、明示的に構成されていない場合は、アプリケーションの [[yii\base\Application::timeZone|timeZone]] から取られます。
例えば、日付のフォーマットを呼ぶと、ロケールによってさまざまな結果を出力します。
```php
Yii::$app->formatter->locale = 'en-US';
echo Yii::$app->formatter->asDate('2014-01-01'); // 出力: January 1, 2014
Yii::$app->formatter->locale = 'de-DE';
echo Yii::$app->formatter->asDate('2014-01-01'); // 出力: 1. Januar 2014
Yii::$app->formatter->locale = 'ru-RU';
echo Yii::$app->formatter->asDate('2014-01-01'); // 出力: 1 января 2014 г.
Yii::$app->formatter->locale = 'ja-JP';
echo Yii::$app->formatter->asDate('2014-01-01'); // 出力: 2014/01/01
```
> Note|注意: フォーマットの仕方は、PHP とともにコンパイルされた ICU ライブラリのバージョンの違いによって異なる可能性がありますし、[PHP intl 拡張](http://php.net/manual/ja/book.intl.php) がインストールされているか否かという事実によっても異なってきます。
> 従って、あなたのウェブサイトが全ての環境で同じ出力を表示することを保証するために、全ての環境に PHP intl 拡張をインストールして、ICU ライブラリのバージョンが同じであることを確認する事を推奨します。
> [PHP 環境を国際化のために設定する](tutorial-i18n.md#setup-environment) も参照してください。
フォーマッタを構成する <a name="configuring-format"></a>
----------------------
フォーマットメソッドによって使われるデフォルトの書式は、[[yii\i18n\Formatter|フォーマッタクラス]] のプロパティを使って調整することが出来ます。
プロパティの値をアプリケーション全体にわたって調整するために、[アプリケーションの構成情報](concept-configurations.md#application-configurations) において、`formatter` コンポーネントを構成することが出来ます。
構成の例を下記に示します。
利用できるプロパティの詳細については、[[yii\i18n\Formatter|Formatter クラスの API ドキュメント]] と、後続の項を参照してください。
```php
'components' => [
'formatter' => [
'dateFormat' => 'dd.MM.yyyy',
'decimalSeparator' => ',',
'thousandSeparator' => ' ',
'currencyCode' => 'EUR',
],
],
```
日時の値をフォーマットする <a name="date-and-time"></a>
--------------------------
フォーマッタクラスは日時の値をフォーマットするさまざまなメソッドを提供しています。すなわち、
- [[yii\i18n\Formatter::asDate()|date]] - 値は日付としてフォーマットされます。例えば `2014/01/01`
- [[yii\i18n\Formatter::asTime()|time]] - 値は時刻としてフォーマットされます。例えば `14:23`
- [[yii\i18n\Formatter::asDatetime()|datetime]] - 値は日付および時刻としてフォーマットされます。例えば `2014/01/01 14:23`
- [[yii\i18n\Formatter::asTimestamp()|timestamp]] - 値は [unix タイムスタンプ](http://en.wikipedia.org/wiki/Unix_time) としてフォーマットされます。例えば `1412609982`
- [[yii\i18n\Formatter::asRelativeTime()|relativeTime]] - 値は、その日時と現在との間隔として、人間に分かりやすい言葉でフォーマットされます。例えば `1 時間後`
[[yii\i18n\Formatter::asDate()|date]]、[[yii\i18n\Formatter::asTime()|time]]、[[yii\i18n\Formatter::asDatetime()|datetime]] メソッドの日時の書式は、フォーマッタのプロパティ [[yii\i18n\Formatter::$dateFormat|$dateFormat]]、[[yii\i18n\Formatter::$timeFormat|$timeFormat]]、[[yii\i18n\Formatter::$datetimeFormat|$datetimeFormat]] を構成することで、グローバルに指定することが出来ます。
デフォルトでは、フォーマッタが使う書式は、ショートカット形式で指定します。
これは、日付と時刻をユーザの国と言語にとって一般的な形式でフォーマット出来るように、現在アクティブなロケールに従ってさまざまに解釈されるものです。
四つの異なるショートカット形式が利用できます。
- `short` は、`en_GB` ロケールでは、例えば、日付を `06/10/2014`、時刻を `15:58` と表示します。
- `medium` は、 `6 Oct 2014` および `15:58:42`
- `long` は、`6 October 2014` および `15:58:42 GMT`
- そして `full``Monday, 6 October 2014` および `15:58:42 GMT` を表示します。
> Info:情報| `ja_JP` ロケールでは、次のようになります。
>
> - `short` ... `2014/10/06` および `15:58`
> - `medium` ... `2014/10/06` および `15:58:42`
> - `long` ... `2014年10月6日` および `15:58:42 JST`
> - `full` ... `2014年10月6日月曜日` および `15時58分42秒 日本標準時`
これに加えて、[ICU プロジェクト](http://site.icu-project.org/) によって定義された構文を使うカスタム書式を指定することが出来ます。
この構文を説明する ICU マニュアルが下記の URL にあります: <http://userguide.icu-project.org/formatparse/datetime>
別の選択肢として、`php:` という接頭辞を付けた文字列を使って、PHP の [date()](http://php.net/manual/ja/function.date.php) 関数が認識する構文を使うことも出来ます。
```php
// ICU 形式
echo Yii::$app->formatter->asDate('now', 'yyyy-MM-dd'); // 2014-10-06
// PHP date() 形式
echo Yii::$app->formatter->asDate('now', 'php:Y-m-d'); // 2014-10-06
```
### タイムゾーン <a name="time-zones"></a>
日時の値をフォーマットするときに、Yii はその値を [[yii\i18n\Formatter::timeZone|設定されたタイムゾーン]] に変換します。
従って、入力値は、タイムゾーンが明示的に指定されていなければ、UTC であると見なされます。
この理由により、全ての日時の値を UTC、それも、なるべくなら、定義によって UTC であることが保証されている UNIX タイムスタンプで保存することが推奨されます。
入力値が UTC とは異なるタイムゾーンに属する場合は、次の例のように、タイムゾーンを明示的に記述しなければなりません。
```php
// Yii::$app->timeZone は 'Asia/Tokyo' であるとします。
echo Yii::$app->formatter->asTime(1412599260); // 21:41:00
echo Yii::$app->formatter->asTime('2014-10-06 12:41:00'); // 21:41:00
echo Yii::$app->formatter->asTime('2014-10-06 21:41:00 JST'); // 21:41:00
```
バージョン 2.0.1 からは、上記のコードの二番目の例のようにタイムゾーン識別子を含まないタイムスタンプに対して適用されるタイムゾーンを設定することも可能になりました。
[[yii\i18n\Formatter::defaultTimeZone]] を設定して、データストレージに使用しているタイムゾーンに合せることが出来ます。
> Note|注意: タイムゾーンは世界中のさまざまな政府によって作られる規則に従うものであり、頻繁に変更されるものであるため、あなたのシステムにインストールされたタイムゾーンのデータベースが最新の情報を持っていない可能性が大いにあります。
> タイムゾーンデータベースの更新についての詳細は、[ICU マニュアル](http://userguide.icu-project.org/datetime/timezone#TOC-Updating-the-Time-Zone-Data) で参照することが出来ます。
> [PHP 環境を国際化のために設定する](tutorial-i18n.md#setup-environment) も参照してください。
数値をフォーマットする <a name="numbers"></a>
----------------------
数値をフォーマットするために、フォーマッタクラスは次のメソッドを提供しています。
- [[yii\i18n\Formatter::asInteger()|integer]] - 値は整数としてフォーマットされます。例えば `42`
- [[yii\i18n\Formatter::asDecimal()|decimal]] - 値は小数点と三桁ごとの区切りを使って十進数としてフォーマットされます。例えば `2,542.123` または `2.542,123`
- [[yii\i18n\Formatter::asPercent()|percent]] - 値は百分率としてフォーマットされます。例えば `42%`
- [[yii\i18n\Formatter::asScientific()|scientific]] - 値は科学記法による数値としてフォーマットされます。例えば `4.2E4`
- [[yii\i18n\Formatter::asCurrency()|currency]] - 値は通貨の値としてフォーマットされます。例えば `£420.00`
- [[yii\i18n\Formatter::asSize()|size]] - バイト数である値が人間にとって読みやすいサイズとしてフォーマットされます。例えば `410 キビバイト`
- [[yii\i18n\Formatter::asShortSize()|shortSize]] - [[yii\i18n\Formatter::asSize()|size]] の短いバージョンです。例えば `410 KiB`
数値のフォーマットに使われる書式は、デフォルトではロケールに従って設定される [[yii\i18n\Formatter::decimalSeparator|decimalSeparator]] と [[yii\i18n\Formatter::thousandSeparator|thousandSeparator]] を使って調整することが出来ます。
更に高度な設定のためには、[[yii\i18n\Formatter::numberFormatterOptions]] と [[yii\i18n\Formatter::numberFormatterTextOptions]] を使って、内部的に使用される [NumberFormatter クラス](http://php.net/manual/ja/class.numberformatter.php) を構成することが出来ます。
例えば、小数部の最大桁数と最小桁数を調整するためには、次のように [[yii\i18n\Formatter::numberFormatterOptions]] プロパティを構成します。
```php
'numberFormatterOptions' => [
NumberFormatter::MIN_FRACTION_DIGITS => 0,
NumberFormatter::MAX_FRACTION_DIGITS => 2,
]
```
その他のフォーマッタ <a name="other"></a>
--------------------
日付、時刻、そして、数値の他にも、Yii はさまざまな状況で使える一連のフォーマッタを提供しています。
- [[yii\i18n\Formatter::asRaw()|raw]] - 値はそのまま出力されます。`null` 値が [[nullDisplay]] を使ってフォーマットされる以外は、何の効果のない擬似フォーマッタです。
- [[yii\i18n\Formatter::asText()|text]] - 値は HTML エンコードされます。
これは [GridView DataColumn](output-data-widgets.md#data-column) で使われるデフォルトの形式です。
- [[yii\i18n\Formatter::asNtext()|ntext]] - 値は HTML エンコードされ、改行文字が強制改行に変換された平文テキストとしてフォーマットされ、ます。
- [[yii\i18n\Formatter::asParagraphs()|paragraphs]] - 値は HTML エンコードされ、`<p>` タグに囲まれた段落としてフォーマットされます。
- [[yii\i18n\Formatter::asHtml()|html]] - 値は XSS 攻撃を避けるために [[HtmlPurifier]] を使って浄化されます。
`['html', ['Attr.AllowedFrameTargets' => ['_blank']]]` のような追加のオプションを渡すことが出来ます。
- [[yii\i18n\Formatter::asEmail()|email]] - 値は `mailto` リンクとしてフォーマットされます。
- [[yii\i18n\Formatter::asImage()|image]] - 値は `image` タグとしてフォーマットされます。
- [[yii\i18n\Formatter::asUrl()|url]] - 値はハイパーリンクとしてフォーマットされます。
- [[yii\i18n\Formatter::asBoolean()|boolean]] - 値は真偽値としてフォーマットされます。
デフォルトでは、`true` は `Yes`、`false` は `No` とレンダリングされ、現在のアプリケーションの言語に翻訳されます。
この振る舞いは [[yii\i18n\Formatter::booleanFormat]] プロパティを構成して調整できます。
`null`<a name="null-values"></a>
---------
PHP において `null` である値に対して、フォーマッタクラスは空文字ではなくプレースホルダを表示します。
`null` のプレースホルダは、デフォルトでは `(not set)` であり、それが現在のアプリケーションの言語に翻訳されます。
[[yii\i18n\Formatter::nullDisplay|nullDisplay]] プロパティを構成して、カスタムのプレースホルダを設定することが出来ます。
`null` 値の特別な扱いをしたくない場合は、[[yii\i18n\Formatter::nullDisplay|nullDisplay]] を `null` に設定することが出来ます。

6
docs/guide-ja/output-pagination.md

@ -0,0 +1,6 @@
ページネーション
================
> Note|注意: この節はまだ執筆中です。
>
> まだ内容がありません。

6
docs/guide-ja/output-sorting.md

@ -0,0 +1,6 @@
並べ替え
========
> Note|注意: この節はまだ執筆中です。
>
> まだ内容がありません。

102
docs/guide-ja/output-theming.md

@ -0,0 +1,102 @@
テーマ
======
> Note|注意: この節はまだ執筆中です。
テーマとは、あるディレクトリの下に集められたビューとレイアウトのファイルです。
テーマの各ファイルが、アプリケーションの対応するファイルをレンダリングの際にオーバーライドします。
一つのアプリケーションは複数のテーマを使用することが可能で、それぞれのテーマはまったく異なるユーザ体験を提供することが出来ます。
いつでも一つのテーマだけがアクティブになり得ます。
> Note|注意: ビューはアプリケーションの固有性が強いものですので、通常は、テーマを再配布可能なものとして作ることはしません。
カスタマイズしたルックアンドフィールを再配布したい場合は、テーマの代りに、[アセットバンドル](structure-assets.md) の形で CSS と JavaScript のファイルを再配布することを検討してください。
テーマを構成する
----------------
テーマの構成情報は、アプリケーションの `view` コンポーネントを通じて指定します。
`basic application` のビューに対して働くテーマをセットアップするためには、アプリケーションの構成情報ファイルに以下のように記述しなければなりません。
```php
'components' => [
'view' => [
'theme' => [
'pathMap' => ['@app/views' => '@app/themes/basic'],
'baseUrl' => '@web/themes/basic',
],
],
],
```
上記においては、`pathMap` が元のパスからテーマのパスへの割り付けを定義し、`baseUrl` がテーマのファイルによって参照されるリソースのベース URL を定義しています。
私たちの例では、`pathMap` は `['@app/views' => '@app/themes/basic']` です。
これは、`@app/views` の全てのビューは、最初に `@app/themes/basic` の下で探され、そのテーマのディレクトリにビューが存在していれば、それが元のビューの代りに使われる、ということを意味します。
例えば、上記の構成においては、ビューファイル `@app/views/site/index.php` のテーマ版は `@app/themes/basic/site/index.php` になります。
基本的には、`@app/views/site/index.php` の `@app/views``@app/themes/basic` に置き換えるわけです。
ランタイムにおいてテーマを構成するためには、ビューをレンダリングする前に次のコードを使用することが出来ます。
典型的には、コントローラの中に次のコードを置きます。
```php
$this->getView()->theme = Yii::createObject([
'class' => '\yii\base\Theme',
'pathMap' => ['@app/views' => '@app/themes/basic'],
'baseUrl' => '@web/themes/basic',
]);
```
### モジュールにテーマを適用する
モジュールにテーマを適用するためには、`pathMap` を次のようなものにすることが出来ます。
```php
'components' => [
'view' => [
'theme' => [
'pathMap' => [
'@app/views' => '@app/themes/basic',
'@app/modules' => '@app/themes/basic/modules', // <-- !!!
],
],
],
],
```
これによって、`@app/modules/blog/views/comment/index.php` に `@app/themes/basic/modules/blog/views/comment/index.php` というテーマを適用することが出来ます。
### ウィジェットにテーマを適用する
`@app/widgets/currency/views/index.php` に配置されているウィジェットのビューにテーマを適用するためには、ビューコンポーネントのテーマに、次のような構成情報を設定する必要があります。
```php
'components' => [
'view' => [
'theme' => [
'pathMap' => ['@app/widgets' => '@app/themes/basic/widgets'],
],
],
],
```
上記の構成によって、`@app/widgets/currency/index.php` ビューのテーマ版を `@app/themes/basic/widgets/currency/index.php` として作成することが出来るようになります。
複数のパスを使う
----------------
一つのパスを複数のテーマパスに割り付けることが出来ます。例えば、
```php
'pathMap' => [
'@app/views' => [
'@app/themes/christmas',
'@app/themes/basic',
],
]
```
この場合、最初に `@app/themes/christmas/site/index.php` というビューファイルが探され、それが見つからない場合は、次に `@app/themes/basic/site/index.php` が探されます。
そして、そこにもビューがない場合は、アプリケーションのビューが使用されます。
この機能は、いくつかのビューを一時的または条件的にオーバーライドしたい場合に、特に役立ちます。

2
docs/guide-ja/runtime-routing.md

@ -438,7 +438,7 @@ URL 規則のパターンには、ウェブサーバ名を含むことが出来
> Tip|ヒント: URL が全てスラッシュで終るようにするためには、URL 接尾辞として `/` を設定することが出来ます。
> Note|注意: URL 接尾辞を構成すると、リクエストされた URL が接尾辞を持たない場合は、認識できない URL であると見なされるようになります。
SEO の目的からも、これが推奨される慣行です。
SEO の目的からも、これが推奨されるプラクティスです。
場合によっては、URL によって異なる接尾辞を使いたいことがあるでしょう。
その目的は、個々の URL 規則の [[yii\web\UrlRule::suffix|suffix]] プロパティを構成することによって達成できます。

6
docs/guide-ja/security-auth-clients.md

@ -0,0 +1,6 @@
Auth クライアント
=================
> Note|注意: この節はまだ執筆中です。
>
> まだ内容がありません。

92
docs/guide-ja/security-authentication.md

@ -0,0 +1,92 @@
認証
====
> Note|注意: この節はまだ執筆中です。
認証はユーザが誰であるかを確認する行為であり、ログインプロセスの基礎となるものです。
典型的には、認証は、識別子 (ユーザ名またはメールアドレス) とパスワードの組み合わせを使用します。
ユーザはこれらの値をフォームを通じて送信し、アプリケーションは送信された情報を以前に (例えば、ユーザ登録時に) 保存された情報と比較します。
Yii では、このプロセス全体が半自動的に実行されます。
開発者に残されているのは、認証システムにおいて最も重要なクラスである [[yii\web\IdentityInterface]] を実装することだけです。
典型的には、`IdentityInterface` の実装は `User` モデルを使って達成されます。
十分な機能を有する認証の実例を [アドバンストアプリケーションテンプレート](tutorial-advanced-app.md) の中に見出すことが出来ます。
下記にインターフェイスのメソッドだけをリストします。
```php
class User extends ActiveRecord implements IdentityInterface
{
// ...
/**
* 与えられた ID によって識別子を探す
*
* @param string|integer $id 探すための ID
* @return IdentityInterface|null 与えられた ID に合致する識別子オブジェクト
*/
public static function findIdentity($id)
{
return static::findOne($id);
}
/**
* 与えられたトークンによって識別子を探す
*
* @param string $token 探すためのトークン
* @return IdentityInterface|null 与えられたトークンに合致する識別子オブジェクト
*/
public static function findIdentityByAccessToken($token, $type = null)
{
return static::findOne(['access_token' => $token]);
}
/**
* @return int|string 現在のユーザの ID
*/
public function getId()
{
return $this->id;
}
/**
* @return string 現在のユーザの認証キー
*/
public function getAuthKey()
{
return $this->auth_key;
}
/**
* @param string $authKey
* @return boolean 認証キーが現在のユーザに対して有効か否か
*/
public function validateAuthKey($authKey)
{
return $this->getAuthKey() === $authKey;
}
}
```
概要を述べたメソッドのうち、二つは単純なものです。
`findIdentity` は ID の値を受け取って、その ID と関連付けられたモデルのインスタンスを返します。
`getId` メソッドは ID そのものを返します。
その他のメソッドのうち、二つのもの - `getAuthKey``validateAuthKey` - は、「次回から自動ログイン ("remember me")」のクッキーに対して追加のセキュリティを提供するために使われます。
`getAuthKey` メソッドは全てのユーザに対してユニークな文字列を返さなければなりません。
`Yii::$app->getSecurity()->generateRandomString()` を使うと、信頼性の高い方法でユニークな文字列を生成することが出来ます。
これをユーザのレコードの一部として保存しておくのが良いアイデアです。
```php
public function beforeSave($insert)
{
if (parent::beforeSave($insert)) {
if ($this->isNewRecord) {
$this->auth_key = Yii::$app->getSecurity()->generateRandomString();
}
return true;
}
return false;
}
```
`validateAuthKey` メソッドでは、パラメータとして渡された `$authKey` 変数 (これ自体はクッキーから読み出されます) をデータベースから読み出された値と比較する必要があるだけです。

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

@ -0,0 +1,482 @@
権限付与
========
> Note|注意: この節はまだ執筆中です。
権限付与は、ユーザが何かをするのに十分な許可を得ているか否かを確認するプロセスです。
Yii は二つの権限付与の方法を提供しています。すなわち、アクセス制御フィルタ (ACF) と、ロールベースアクセス制御 (RBAC) です。
アクセス制御フィルタ (ACF)
--------------------------
アクセス制御フィルタ (ACF) は、何らかの単純なアクセス制御だけを必要とするアプリケーションで使うのに最も適した、単純な権限付与の方法です。
その名前が示すように、ACF は、コントローラまたはモジュールにビヘイビアとしてアタッチすることが出来るアクションフィルタです。
ACF は一連の [[yii\filters\AccessControl::rules|アクセス規則]] をチェックして、現在のユーザがリクエストしたアクションにアクセスすることが出来るかどうかを確認します。
下記のコードは、[[yii\filters\AccessControl]] として実装された ACF の使い方を示すものです。
```php
use yii\filters\AccessControl;
class SiteController extends Controller
{
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['login', 'logout', 'signup'],
'rules' => [
[
'allow' => true,
'actions' => ['login', 'signup'],
'roles' => ['?'],
],
[
'allow' => true,
'actions' => ['logout'],
'roles' => ['@'],
],
],
],
];
}
// ...
}
```
上記のコードにおいて、ACF は `site` コントローラにビヘイビアとしてアタッチされています。
これはアクションフィルタを使用する典型的な方法です。
`only` オプションは、ACF が `login`、`logout`、`signup` のアクションにのみ適用されるべきであることを指定しています。
`rules` オプションは [[yii\filters\AccessRule|アクセス規則]] を指定するものであり、以下のように読むことが出来ます。
- 全てのゲストユーザ (まだ認証されていないユーザ) に、'login' と 'singup' のアクションにアクセスすることを許可します。
`roles` オプションに疑問符 `?` が含まれていますが、これは「ゲスト」として認識される特殊なトークンです。
- 認証されたユーザに、'logout' アクションにアクセスすることを許可します。
`@` という文字はもう一つの特殊なトークンで、認証されたユーザとして認識されるものです。
ACF が権限のチェックを実行するときには、規則を一つずつ上から下へ、適用されるものを見つけるまで調べます。
そして、適用される規則の `allow` の値が、ユーザが権限を有するか否かを判断するのに使われます。
適用される規則が一つもなかった場合は、ユーザが権限をもたないことを意味し、ACF はアクションの継続を中止します。
デフォルトでは、ユーザが現在のアクションにアクセスする権限を持っていないと判定した場合は、ACF は以下のことだけを行います。
* ユーザがゲストである場合は、[[yii\web\User::loginRequired()]] を呼び出します。
このメソッドで、ブラウザをログインページにリダイレクトすることが出来ます。
* ユーザが既に認証されている場合は、[[yii\web\ForbiddenHttpException]] を投げます。
この動作は、[[yii\filters\AccessControl::denyCallback]] プロパティを構成することによって、カスタマイズすることが出来ます。
```php
[
'class' => AccessControl::className(),
'denyCallback' => function ($rule, $action) {
throw new \Exception('このページにアクセスする権限がありません。');
}
]
```
[[yii\filters\AccessRule|アクセス規則]] は多くのオプションをサポートしています。
以下はサポートされているオプションの要約です。
[[yii\filters\AccessRule]] を拡張して、あなた自身のカスタマイズしたアクセス規則のクラスを作ることも出来ます。
* [[yii\filters\AccessRule::allow|allow]]: これが「許可」の規則であるか、「禁止」の規則であるかを指定します。
* [[yii\filters\AccessRule::actions|actions]]: どのアクションにこの規則が適用されるかを指定します。
これはアクション ID の配列でなければなりません。
比較は大文字と小文字を区別します。
このオプションが空であるか指定されていない場合は、規則が全てのアクションに適用されることを意味します。
* [[yii\filters\AccessRule::controllers|controllers]]: どのコントローラにこの規則が適用されるかを指定します。
これはコントローラ ID の配列でなければなりません。
比較は大文字と小文字を区別します。
このオプションが空であるか指定されていない場合は、規則が全てのコントローラに適用されることを意味します。
* [[yii\filters\AccessRule::roles|roles]]: どのユーザロールにこの規則が適用されるかを指定します。
二つの特別なロールが認識されます。
これらは、[[yii\web\User::isGuest]] によって判断されます。
- `?`: ゲストユーザ (まだ認証されていないユーザ) を意味します。
- `@`: 認証されたユーザを意味します。
その他のロール名を使う場合には、RBAC (次の節で説明します) が必要とされ、判断のために [[yii\web\User::can()]] が呼び出されます。
このオプションが空であるか指定されていない場合は、規則が全てのロールに適用されることを意味します。
* [[yii\filters\AccessRule::ips|ips]]: どの [[yii\web\Request::userIP|クライアントの IP アドレス]] にこの規則が適用されるかを指定します。
IP アドレスは、最後にワイルドカード `*` を含むことが出来て、同じプレフィクスを持つ IP アドレスに合致させることが出来ます。
例えば、'192.168.*' は、'192.168.' のセグメントに属する全ての IP アドレスに合致します。
このオプションが空であるか指定されていない場合は、規則が全ての IP アドレスに適用されることを意味します。
* [[yii\filters\AccessRule::verbs|verbs]]: どのリクエストメソッド (例えば、`GET` や `POST`) にこの規則が適用されるかを指定します。
比較は大文字と小文字を区別しません。
* [[yii\filters\AccessRule::matchCallback|matchCallback]]: この規則が適用されるべきか否かを決定するために呼び出されるべき PHP コーラブルを指定します。
* [[yii\filters\AccessRule::denyCallback|denyCallback]]: この規則がアクセスを禁止する場合に呼び出されるべき PHP コーラブルを指定します。
下記は、`matchCallback` オプションを利用する方法を示す例です。
このオプションによって、任意のアクセス制御ロジックを書くことが可能になります。
```php
use yii\filters\AccessControl;
class SiteController extends Controller
{
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['special-callback'],
'rules' => [
[
'actions' => ['special-callback'],
'allow' => true,
'matchCallback' => function ($rule, $action) {
return date('d-m') === '31-10';
}
],
],
],
];
}
// matchCallback が呼ばれる。このページは毎年10月31日だけアクセス出来ます。
public function actionSpecialCallback()
{
return $this->render('happy-halloween');
}
}
```
ロールベースアクセス制御 (RBAC)
---------------------------------------
ロールベースアクセス制御 (RBAC) は、単純でありながら強力な集中型のアクセス制御を提供します。
RBAC と他のもっと伝統的なアクセス制御スキーマとの比較に関する詳細については、[Wiki 記事](http://ja.wikipedia.org/wiki/%E3%83%AD%E3%83%BC%E3%83%AB%E3%83%99%E3%83%BC%E3%82%B9%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E5%88%B6%E5%BE%A1) を参照してください。
Yii は、[NIST RBAC モデル](http://csrc.nist.gov/rbac/sandhu-ferraiolo-kuhn-00.pdf) に従って、一般的階層型 RBAC を実装しています。
RBAC の機能は、[[yii\rbac\ManagerInterface|authManager]] [アプリケーションコンポーネント](structure-application-components.md) を通じて提供されます。
RBAC を使用することには、二つの作業が含まれます。
最初の作業は、RBAC 権限付与データを作り上げることであり、第二の作業は、権限付与データを使って必要とされる場所でアクセスチェックを実行することです。
説明を容易にするために、まず、いくつかの基本的な RBAC の概念を導入します。
### 基本的な概念
ロール (役割) は、*許可* (例えば、記事を作成する、記事を更新するなど) のコレクションです。
一つのロールを一人または複数のユーザに割り当てることが出来ます。
ユーザが特定の許可を有しているか否かをチェックするためには、その許可を含むロールがユーザに割り当てられているか否かをチェックすればよいのです。
各ロールまたは許可に関連付けられた *規則* が存在することがあり得ます。
規則とは、アクセスチェックの際に、対応するロールや許可が現在のユーザに適用されるか否かを決定するために実行されるコード断片のことです。
例えば、「記事更新」の許可は、現在のユーザが記事の作成者であるかどうかをチェックする規則を持つことが出来ます。
そして、アクセスチェックのときに、ユーザが記事の作成者でない場合は、彼/彼女は「記事更新」の許可を持っていないと見なすことが出来ます。
ロールおよび許可は、ともに、階層的に構成することが出来ます。
具体的に言えば、一つのロールは他のロールと許可を含むことが出来、許可は他の許可を含むことが出来ます。
Yii は、一般的な *半順序* 階層を実装していますが、これはその特殊形として *木* 階層を含むものです。
ロールは許可を含むことが出来ますが、許可はロールを含むことが出来ません。
### RBAC マネージャを構成する
権限付与データを定義してアクセスチェックを実行する前に、[[yii\base\Application::authManager|authManager]] アプリケーションコンポーネントを構成する必要があります。
Yii は二種類の権限付与マネージャを提供しています。すなわち、[[yii\rbac\PhpManager]] と [[yii\rbac\DbManager]] です。
前者は権限付与データを保存するのに PHP スクリプトファイルを使いますが、後者は権限付与データをデータベースに保存します。
あなたのアプリケーションが非常に動的なロールと許可の管理を必要とするのでなければ、前者を使うことを考慮するのが良いでしょう。
次のコードは、アプリケーションの構成情報で `authManager` を構成する方法を示すものです。
```php
return [
// ...
'components' => [
'authManager' => [
'class' => 'yii\rbac\PhpManager',
],
// ...
],
];
```
`authManager``\Yii::$app->authManager` によってアクセスすることが出来ます。
> Tip|ヒント: デフォルトでは、[[yii\rbac\PhpManager]] は RBAC データを `@app/rbac/` ディレクトリの下のファイルに保存します。
権限の階層をオンラインで変更する必要がある場合は、必ず、ウェブサーバのプロセスがこのディレクトリとその中の全てのファイルに対する書き込み権限を有するようにしてください。
### 権限付与データを構築する
権限付与データを構築する作業は、つまるところ、以下のタスクに他なりません。
- ロールと許可を定義する
- ロールと許可の関係を定義する
- 規則を定義する
- 規則をロールと許可に結び付ける
- ロールをユーザに割り当てる
権限付与に要求される柔軟性の程度によって、上記のタスクのやりかたも異なってきます。
権限の階層が全く変化せず、決った数のユーザしか存在しない場合は、`authManager` が提供する API によって権限付与データを一回だけ初期設定する [コンソールコマンド](tutorial-console.md#create-command) を作ることが出来ます。
```php
<?php
namespace app\commands;
use Yii;
use yii\console\Controller;
class RbacController extends Controller
{
public function actionInit()
{
$auth = Yii::$app->authManager;
// "createPost" という許可を追加
$createPost = $auth->createPermission('createPost');
$createPost->description = '記事を投稿';
$auth->add($createPost);
// "updatePost" という許可を追加
$updatePost = $auth->createPermission('updatePost');
$updatePost->description = '記事を更新';
$auth->add($updatePost);
// "author" というロールを追加し、このロールに "createPost" 許可を与える
$author = $auth->createRole('author');
$auth->add($author);
$auth->addChild($author, $createPost);
// "admin" というロールを追加し、このロールに "updatePost" 許可を与える
// 同時に、"author" ロールの持つ許可も与える
$admin = $auth->createRole('admin');
$auth->add($admin);
$auth->addChild($admin, $updatePost);
$auth->addChild($admin, $author);
// ロールをユーザに割り当てる。1 と 2 は IdentityInterface::getId() によって返される ID
// 通常はユーザモデルの中で実装する
$auth->assign($author, 2);
$auth->assign($admin, 1);
}
}
```
`yii rbac/init` によってコマンドを実行した後には、次の権限階層が得られます。
![単純な RBAC 階層](images/rbac-hierarchy-1.png "単純な RBAC 階層")
投稿者 (author) は記事を投稿することが出来、管理者 (admin) は記事を更新することに加えて投稿者が出来る全てのことが出来ます。
あなたのアプリケーションがユーザ登録を許している場合は、新しく登録されたユーザに一度ロールを割り当てる必要があります。
例えば、アドバンストアプリケーションテンプレートにおいては、登録したユーザの全てを「投稿者」にするために、`frontend\models\SignupForm::signup()` を次のように修正しなければなりません。
```php
public function signup()
{
if ($this->validate()) {
$user = new User();
$user->username = $this->username;
$user->email = $this->email;
$user->setPassword($this->password);
$user->generateAuthKey();
$user->save(false);
// 次の三行が追加されたものです
$auth = Yii::$app->authManager;
$authorRole = $auth->getRole('author');
$auth->assign($authorRole, $user->getId());
return $user;
}
return null;
}
```
動的に更新される権限付与データを持つ複雑なアクセス制御を必要とするアプリケーションについては、`authManager` が提供する API を使って、特別なユーザインタフェイス (つまり、管理パネル) を開発する必要があるでしょう。
### 規則を使う
既に述べたように、規則がロールと許可に制約を追加します。
規則は [[yii\rbac\Rule]] を拡張したクラスであり、[[yii\rbac\Rule::execute()|execute()]] メソッドを実装しなければなりません。
前に作った権限階層においては、投稿者は自分自身の記事を編集することが出来ないものでした。これを修正しましょう。
最初に、ユーザが記事の投稿者であることを確認する規則が必要です。
```php
namespace app\rbac;
use yii\rbac\Rule;
/**
* authorID がパラメータで渡されたユーザと一致するかチェックする
*/
class AuthorRule extends Rule
{
public $name = 'isAuthor';
/**
* @param string|integer $user ユーザ ID
* @param Item $item この規則が関連付けられているロールまたは許可
* @param array $params ManagerInterface::checkAccess() に渡されたパラメータ
* @return boolean 関連付けられたロールまたは許可を認めるか否かを示す値
*/
public function execute($user, $item, $params)
{
return isset($params['post']) ? $params['post']->createdBy == $user : false;
}
}
```
上の規則は、`post` が `$user` によって作成されたかどうかをチェックします。
次に、前に使ったコマンドの中で、`updateOwnPost` という特別な許可を作成します。
```php
$auth = Yii::$app->authManager;
// 規則を追加する
$rule = new \app\rbac\AuthorRule;
$auth->add($rule);
// "updateOwnPost" という許可を作成し、それに規則を関連付ける
$updateOwnPost = $auth->createPermission('updateOwnPost');
$updateOwnPost->description = '自分の記事を更新';
$updateOwnPost->ruleName = $rule->name;
$auth->add($updateOwnPost);
// "updateOwnPost" は "updatePost" から使われる
$auth->addChild($updateOwnPost, $updatePost);
// "author" に自分の記事を更新することを許可する
$auth->addChild($author, $updateOwnPost);
```
これで、次のような権限階層になります。
![規則を持つ RBAC 階層](images/rbac-hierarchy-2.png "規則を持つ RBAC 階層")
### アクセスチェック
権限付与データが準備できてしまえば、アクセスチェックは [[yii\rbac\ManagerInterface::checkAccess()]] メソッドを呼ぶだけの簡単な仕事です。
たいていのアクセスチェックは現在のユーザに関するものですから、Yii は、便利なように、[[yii\web\User::can()]] というショートカットメソッドを提供しています。
これは、次のようにして使うことが出来ます。
```php
if (\Yii::$app->user->can('createPost')) {
// 記事を作成する
}
```
現在のユーザが ID=1 である Jane であるとすると、`createPost` からスタートして `Jane` まで到達しようと試みます。
![アクセスチェック](images/rbac-access-check-1.png "アクセスチェック")
ユーザが記事を更新することが出来るかどうかをチェックするためには、前に説明した `AuthorRule` によって要求される追加のパラメータを渡す必要があります。
```php
if (\Yii::$app->user->can('updatePost', ['post' => $post])) {
// 記事を更新する
}
```
現在のユーザが John であるとすると、次の経路をたどります。
![アクセスチェック](images/rbac-access-check-2.png "アクセスチェック")
`updatePost` からスタートして、`updateOwnPost` を通過します。
通過するためには、`AuthorRule` が `execute` メソッドで `true` を返さなければなりません。
`execute` メソッドは `can` メソッドの呼び出しから `$params` を受け取りますので、その値は `['post' => $post]` です。
すべて OK であれば、John に割り当てられている `author` に到達します。
Jane の場合は、彼女が管理者であるため、少し簡単になります。
![アクセスチェック](images/rbac-access-check-3.png "アクセスチェック")
### デフォルトロールを使う
デフォルトロールというのは、*全て* のユーザに *黙示的* に割り当てられるロールです。
[[yii\rbac\ManagerInterface::assign()]] を呼び出す必要はなく、権限付与データはその割り当て情報を含みません。
デフォルトロールは、通常、そのロールが当該ユーザに適用されるかどうかを決定する規則と関連付けられます。
デフォルトロールは、たいていは、何らかのロールの割り当てを既に持っているアプリケーションにおいて使われます。
例えば、アプリケーションによっては、ユーザのテーブルに "group" というカラムを持って、個々のユーザが属する特権グループを表している場合があります。
それぞれの特権グループを RBAC ロールに対応付けることが出来るのであれば、デフォルトロールの機能を使って、それぞれのユーザに RBAC ロールを自動的に割り当てることが出来ます。
どのようにすればこれが出来るのか、例を使って説明しましょう。
ユーザのテーブルに `group` というカラムがあって、1 は管理者グループ、2 は投稿者グループを示していると仮定しましょう。
これら二つのグループの権限を表すために、それぞれ、`admin` と `author` という RBAC ロールを作ることにします。
このとき、次のように RBAC データをセットアップすることが出来ます。
```php
namespace app\rbac;
use Yii;
use yii\rbac\Rule;
/**
* ユーザのグループが合致するかどうかをチェックする
*/
class UserGroupRule extends Rule
{
public $name = 'userGroup';
public function execute($user, $item, $params)
{
if (!Yii::$app->user->isGuest) {
$group = Yii::$app->user->identity->group;
if ($item->name === 'admin') {
return $group == 1;
} elseif ($item->name === 'author') {
return $group == 1 || $group == 2;
}
}
return false;
}
}
$auth = Yii::$app->authManager;
$rule = new \app\rbac\UserGroupRule;
$auth->add($rule);
$author = $auth->createRole('author');
$author->ruleName = $rule->name;
$auth->add($author);
// ... $author の子として許可を追加 ...
$admin = $auth->createRole('admin');
$admin->ruleName = $rule->name;
$auth->add($admin);
$auth->addChild($admin, $author);
// ... $admin の子として許可を追加 ...
```
上記において、"author" が "admin" の子として追加されているため、規則クラスの `execute()` メソッドを実装する時には、この階層関係にも配慮しなければならないことに注意してください。
このために、ロール名が "author" である場合には、`execute()` メソッドは、ユーザのグループが 1 または 2 である (ユーザが "admin" グループまたは "author" グループに属している) ときに true を返しています。
次に、`authManager` の構成情報で、この二つのロールを [[yii\rbac\BaseManager::$defaultRoles]] としてリストします。
```php
return [
// ...
'components' => [
'authManager' => [
'class' => 'yii\rbac\PhpManager',
'defaultRoles' => ['admin', 'author'],
],
// ...
],
];
```
このようにすると、アクセスチェックを実行すると、`admin` と `author` の両方のロールは、それらと関連付けられた規則を評価することによってチェックされるようになります。
規則が true を返せば、そのロールが現在のユーザに適用されることになります。
上述の規則の実装に基づいて言えば、ユーザの `group` の値が 1 であれば、`admin` ロールがユーザに適用され、`group` の値が 2 であれば `author` ロールが適用されるということを意味します。

163
docs/guide-ja/security-best-practices.md

@ -0,0 +1,163 @@
セキュリティのベストプラクティス
================================
下記において、一般的なセキュリティの指針を復習し、Yii を使ってアプリケーションを開発するときに脅威を回避する方法を説明します。
基本的な指針
------------
どのようなアプリケーションが開発されているかに関わらず、セキュリティに関しては二つの大きな指針が存在します。
1. 入力をフィルタする。
2. 出力をエスケープする。
### 入力をフィルタする
入力をフィルタするとは、入力値は決して安全なものであると見なさず、取得した値が実際に許可さていれる値に含まれるか否かを常にチェックしなければならない、ということを意味します。
つまり、並べ替えが三つのフィールド `title`、`created_at` および `status` によって実行され、フィールドの値がインプットによって提供されるものであることを知っている場合、取得した値を受信するその場でチェックする方が良い、ということです。
基本的な PHP の形式では、次のようなコードになります。
```php
$sortBy = $_GET['sort'];
if (!in_array($sortBy, ['title', 'created_at', 'status'])) {
throw new Exception('Invalid sort value.');
}
```
Yii においては、たいていの場合、同様のチェックを行うために [フォームのバリデーション](input-validation.md) を使うことになるでしょう。
### 出力をエスケープする
データを使用するコンテキストに応じて、出力をエスケープしなければなりません。
つまり、HTML のコンテキストでは、`<` や `>` などの特殊な文字をエスケープしなければなりません。
JavaScript や SQL のコンテキストでは、対象となる文字は別のセットになります。
全てを手動でエスケープするのは間違いを生じやすいことですから、Yii は異なるコンテキストに応じたエスケープを実行するためのさまざまなツールを提供しています。
SQL インジェクションを回避する
------------------------------
SQL インジェクションは、次のように、エスケープされていない文字列を連結してクエリテキストを構築する場合に発生します。
```php
$username = $_GET['username'];
$sql = "SELECT * FROM user WHERE username = '$username'";
```
正しいユーザ名を提供する代りに、攻撃者は `'; DROP TABLE user; --` のような文字列をあなたのアプリケーションに与えることが出来ます。
結果として構築される SQL は次のようになります。
```sql
SELECT * FROM user WHERE username = ''; DROP TABLE user; --'
```
これは有効なクエリで、空のユーザ名を持つユーザを探してから、`user` テーブルを削除します。
おそらく、ウェブサイトは破壊されて、データは失われることになります (定期的なバックアップは設定済みですよね、ね? )。
Yii においては、ほとんどのデータベースクエリは、PDO のプリペアドステートメントを適切に使用する [アクティブレコード](db-active-record.md) を経由して実行されます。
プリペアドステートメントの場合は、上で説明したようなクエリの改竄は不可能です。
それでも、[生のクエリ](db-dao.md) や [クエリビルダ](db-query-builder.md) を必要とする場合はあります。
その場合には、データを渡すための安全な方法を使わなければなりません。
データをカラムの値として使う場合は、プリペアドステートメントを使うことが望まれます。
```php
// query builder
$userIDs = (new Query())
->select('id')
->from('user')
->where('status=:status', [':status' => $status])
->all();
// DAO
$userIDs = $connection
->createCommand('SELECT id FROM user where status=:status')
->bindValues([':status' => $status])
->queryColumn();
```
データがカラム名やテーブル名を指定するために使われる場合は、事前定義された一連の値だけを許可するのが最善の方法です。
```php
function actionList($orderBy = null)
{
if (!in_array($orderBy, ['name', 'status'])) {
throw new BadRequestHttpException('名前とステータスだけを並べ替えに使うことが出来ます。')
}
// ...
}
```
それが不可能な場合は、テーブル名とカラム名をエスケープしなければなりません。
Yii はそういうエスケープのための特別な文法を持っており、それを使うと、サポートされている全てのデータベースに対して同じ方法でエスケープすることが出来ます。
```php
$sql = "SELECT COUNT([[$column]]) FROM {{table}}";
$rowCount = $connection->createCommand($sql)->queryScalar();
```
この文法の詳細は、[テーブルとカラムの名前を引用符で囲む](db-dao.md#quoting-table-and-column-names) で読むことが出来ます。
XSS を回避する
--------------
XSS すなわちクロスサイトスクリプティングは、ブラウザに HTML を出力する際に、出力が適切にエスケープされていないと発生します。
例えば、ユーザ名を入力できるフォームで `Alexander` の代りに `<script>alert('Hello!');</script>` と入力した場合、ユーザ名をエスケープせずに出力している全てのページでは、JavaScript `alert('Hello!');` が実行されて、ブラウザにアラートボックスがポップアップ表示されます。
ウェブサイト次第では、そのようなスクリプトを使って、無害なアラートではなく、あなたの名前を使ってメッセージを送信したり、さらには銀行取引を実行したりすることが可能です。
XSS の回避は、Yii においてはとても簡単です。一般に、二つのケースがあります。
1. データを平文テキストとして出力したい。
2. データを HTML として出力したい。
平文テキストしか必要でない場合は、エスケープは次のようにとても簡単です。
```php
<?= \yii\helpers\Html::encode($username) ?>
```
HTML である場合は、HtmlPurifier から助けを得ることが出来ます。
```php
<?= \yii\helpers\HtmlPurifier::process($description) ?>
```
HtmlPurifier の処理は非常に重いので、キャッシュを追加することを検討してください。
CSRF を回避する
---------------
TBD: what's CSRF, how it works, intro
1. HTTP の規格に従うこと、すなわち、GET はアプリケーションの状態を変更すべきではない。
2. Yii の CSRF 保護を有効にしておくこと。
TBD: how CSRF protection works
ファイルの曝露を回避する
------------------------
デフォルトでは、サーバのウェブルートは、`index.php` がある `web` ディレクトリを指すように意図されています。
共有ホスティング環境の場合、それをすることが出来ずに、全てのコード、構成情報、ログをサーバのウェブルートの下に置かなくてはならないことがあり得ます。
そういう場合には、`web` 以外の全てに対してアクセスを拒否することを忘れないでください。
それも出来ない場合は、アプリケーションを別の場所でホストすることを検討してください。
実運用環境ではデバッグ情報とデバッグツールを無効にする
------------------------------------------------------
デバッグモードでは、Yii は極めて多くのエラー情報を出力します。これは確かに開発には役立つものです。
しかし、実際の所、これらの饒舌なエラー情報は、攻撃者にとっても、データベース構造、構成情報の値、コードの断片などを曝露してくれる重宝なものです。
実運用のアプリケーションにおいては、決して `index.php``YII_DEBUG``true` にして走らせてはいけません。
実運用環境では Gii を決して有効にしてはいけません。
Gii を使うと、データベース構造とコードに関する情報を得ることが出来るだけでなく、コードを Gii によって生成したもので書き換えることすら出来てしまいます。
デバッグツールバーは本当に必要でない限り実運用環境では使用を避けるべきです。
これはアプリケーションと構成情報の全ての詳細を曝露することが出来ます。
どうしても必要な場合は、あなたの IP だけに適切にアクセス制限されていることを再度チェックしてください。

152
docs/guide-ja/security-passwords.md

@ -0,0 +1,152 @@
セキュリティ
============
> Note|注意: この節はまだ執筆中です。
十分なセキュリティは、どのようなアプリケーションであっても、健全さを保って成功するためには欠くことが出来ないものです。
不幸なことに、理解が不足しているためか、実装の難易度が高すぎるためか、セキュリティのことになると手を抜く開発者がたくさんいます。
Yii によって駆動されるアプリケーションを可能な限り安全にするために、Yii はいくつかの優秀な使いやすいセキュリティ機能を内蔵しています。
ハッシュとパスワードの検証
--------------------------
ほとんどの開発者はパスワードを平文テキストでは保存できないということを知っていますが、パスワードを `md5``sha1` でハッシュしてもまだ安全だと思っている開発者がたくさんいます。
かつては、前述のハッシュアルゴリズムを使えば十分であった時もありましたが、現代のハードウェアをもってすれば、そのようなハッシュはブルートフォースアタックを使って非常に簡単に復元することが可能です。
最悪のシナリオ (アプリケーションに侵入された場合) であっても、ユーザのパスワードについて強化されたセキュリティを提供することが出来るように、ブルートフォースアタックに対する耐性が強いハッシュアルゴリズムを使う必要があります。
現在、最善の選択は `bcrypt` です。
PHP では、[crypt 関数](http://php.net/manual/ja/function.crypt.php) を使って `bcrypt` ハッシュを生成することが出来ます。
Yii は `crypt` を使ってハッシュを安全に生成し検証することを容易にする二つのヘルパ関数を提供します。
ユーザが初めてパスワードを提供するとき (例えば、ユーザ登録の時) には、パスワードをハッシュする必要があります。
```php
$hash = Yii::$app->getSecurity()->generatePasswordHash($password);
```
そして、ハッシュを対応するモデル属性と関連付けて、後で使用するためにデータベースに保存します。
ユーザがログインを試みたときは、送信されたパスワードは、前にハッシュされて保存されたパスワードと照合して検証されます。
```php
if (Yii::$app->getSecurity()->validatePassword($password, $hash)) {
// よろしい、ユーザをログインさせる
} else {
// パスワードが違う
}
```
擬似乱数データを生成する
------------------------
擬似乱数データはさまざまな状況で役に立ちます。
例えば、メール経由でパスワードをリセットするときは、トークンを生成してデータベースに保存し、それをユーザにメールで送信します。
そして、ユーザはこのトークンを自分がアカウントの所有者であることの証拠として使用します。
このトークンがユニークかつ推測困難なものであることは非常に重要なことです。
さもなくば、攻撃者がトークンの値を推測してユーザのパスワードをリセットする可能性があります。
Yii のセキュリティヘルパは擬似乱数データの生成を単純な作業にしてくれます。
```php
$key = Yii::$app->getSecurity()->generateRandomString();
```
暗号論的に安全な乱数データを生成するためには、`openssl` 拡張をインストールしている必要があることに注意してください。
暗号化と復号化
--------------
Yii は秘密鍵を使ってデータを暗号化/復号化することを可能にする便利なヘルパ関数を提供しています。
データを暗号化関数に渡して、秘密鍵を持つ者だけが復号化することが出来るようにすることが出来ます。
例えば、何らかの情報をデータベースに保存する必要があるけれども、(たとえアプリケーションのデータベースが第三者に漏洩した場合でも) 秘密鍵を持つユーザだけがそれを見ることが出来るようにする必要がある、という場合には次のようにします。
```php
// $data と $secretKey はフォームから取得する
$encryptedData = Yii::$app->getSecurity()->encryptByPassword($data, $secretKey);
// $encryptedData をデータベースに保存する
```
そして、後でユーザがデータを読みたいときは、次のようにします。
```php
// $secretKey はユーザ入力から取得、$encryptedData はデータベースから取得
$data = Yii::$app->getSecurity()->decryptByPassword($encryptedData, $secretKey);
```
データの完全性を確認する
------------------------
データが第三者によって改竄されたり、更には何らかの形で毀損されたりしていないことを確認する必要がある、という場合があります。
Yii は二つのヘルパ関数の形で、データの完全性を確認するための簡単な方法を提供しています。
秘密鍵とデータから生成されたハッシュをデータにプレフィクスします。
```php
// $secretKey はアプリケーションまたはユーザの秘密、$genuineData は信頼できるソースから取得
$data = Yii::$app->getSecurity()->hashData($genuineData, $secretKey);
```
データの完全性が毀損されていないかチェックします。
```php
// $secretKey はアプリケーションまたはユーザの秘密、$data は信頼できないソースから取得
$data = Yii::$app->getSecurity()->validateData($data, $secretKey);
```
todo: XSS prevention, CSRF prevention, cookie protection, refer to 1.1 guide
プロパティを設定することによって、CSRF バリデーションをコントローラ および/または アクション単位で無効にすることも出来ます。
```php
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
public $enableCsrfValidation = false;
public function actionIndex()
{
// CSRF バリデーションはこのアクションおよびその他のアクションに適用されない
}
}
```
特定のアクションに対して CSRF バリデーションを無効にするためには、次のようにします。
```php
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
public function beforeAction($action)
{
// ... ここで、何らかの条件に基づいて `$this->enableCsrfValidation` をセットする ...
// 親のメソッドを呼ぶ。プロパティが true なら、その中で CSRF がチェックされる。
return parent::beforeAction($action);
}
}
```
クッキーを安全にする
--------------------
- validation
- httpOnly is default
参照
----
以下も参照してください。
- [ビューのセキュリティ](structure-views.md#security)

1
docs/guide-ja/start-looking-ahead.md

@ -33,3 +33,4 @@ Gii をコード生成に使うと、ウェブ開発のプロセスの大部分
- 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>

2
docs/guide-ja/structure-applications.md

@ -305,7 +305,7 @@ if (YII_ENV_DEV) {
#### [[yii\base\Application::params|params]] <a name="params"></a>
このプロパティは、グローバルにアクセス可能なアプリケーションパラメータの配列を規定します。
コードの中のいたる処でハードコードされた数値や文字列を使う代りに、それらをアプリケーションパラメータとして一ヶ所で定義し、必要な場所ではそのパラメータを使うというのが良い慣行です。
コードの中のいたる処でハードコードされた数値や文字列を使う代りに、それらをアプリケーションパラメータとして一ヶ所で定義し、必要な場所ではそのパラメータを使うというのが良いプラクティスです。
例えば、次のように、サムネール画像のサイズをパラメータとして定義することが出来ます。
```php

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

@ -418,7 +418,7 @@ class SiteController extends Controller
6. アプリケーションはアクションの結果を受け取り、それを [レスポンス](runtime-responses.md) に割り当てる。
## 最善の慣行<a name="best-practices"></a>
## ベストプラクティス<a name="best-practices"></a>
良く設計されたアプリケーションでは、コントローラはたいてい非常に軽いものになり、それぞれのアクションは数行のコードしか含まないものになります。
あなたのコントローラが少々複雑になっている場合、そのことは、通常、コントローラをリファクタして、コードの一部を他のクラスに移動すべきことを示すものです。

6
docs/guide-ja/structure-extensions.md

@ -229,10 +229,10 @@ Composer が Bower または NPM のパッケージをインストールする
例えば、上記の `autoload` の宣言は、`@yii/imagine` という名前のエイリアスに対応することになります。
### 推奨される慣行 <a name="recommended-practices"></a>
### 推奨されるプラクティス <a name="recommended-practices"></a>
エクステンションは他の人々によって使われることを意図したものですから、多くの場合、追加の開発努力が必要になります。
以下に、高品質のエクステンションを作成するときによく用いられ、また推奨される慣行のいくつかを紹介します。
以下に、高品質のエクステンションを作成するときによく用いられ、また推奨されるプラクティスのいくつかを紹介します。
#### 名前空間 <a name="namespaces"></a>
@ -345,7 +345,7 @@ Yii はテストのサポートを提供しており、それよって、ユニ
#### バージョン管理 <a name="versioning"></a>
エクステンションのリリースごとにバージョン番号 (例えば `1.0.1`) を付けるべきです。
どのようなバージョン番号を付けるべきかを決定するときは、[セマンティックバージョニング](http://semver.org) の慣行に従うことを推奨します。
どのようなバージョン番号を付けるべきかを決定するときは、[セマンティックバージョニング](http://semver.org) のプラクティスに従うことを推奨します。
#### リリース(公開) <a name="releasing"></a>

2
docs/guide-ja/structure-models.md

@ -460,7 +460,7 @@ public function fields()
> および `password_reset_token` を選んで除去しています。
## 最善の慣行<a name="best-practices"></a>
## ベストプラクティス<a name="best-practices"></a>
モデルは、業務のデータ、規則、ロジックを表わす中心的なオブジェクトです。
モデルは、さまざまな場所で再利用される必要がよくあります。

2
docs/guide-ja/structure-modules.md

@ -236,7 +236,7 @@ class Module extends \yii\base\Module
このリストには、直接の子と孫以下の両方のモジュールが含まれ、クラス名によってインデックスされています。
## 最善の慣行 <a name="best-practices"></a>
## ベストプラクティス <a name="best-practices"></a>
モジュールは、それぞれ密接に関係する一連の機能を含む数個のグループに分割できるような、規模の大きなアプリケーションに最も適しています。
そのような機能グループをそれぞれモジュールとして、特定の個人やチームによって開発することが出来ます。

2
docs/guide-ja/structure-views.md

@ -680,7 +680,7 @@ http://localhost/index.php?r=site/page&view=about
[[yii\web\ViewAction::viewPrefix]] を構成して、ビューを探すディレクトリを変更することが出来ます。
## 最善の慣行 <a name="best-practices"></a>
## ベストプラクティス <a name="best-practices"></a>
ビューはエンドユーザが望む形式でモデルを表現することに対して責任を持ちます。一般的に、ビューは

2
docs/guide-ja/structure-widgets.md

@ -172,7 +172,7 @@ public function run()
[[yii\base\Widget::getViewPath()]] メソッドをオーバーライドして、ウィジェットのビューファイルを含むディレクトリをカスタマイズすることが出来ます。
## 最善の慣行 <a name="best-practices"></a>
## ベストプラクティス <a name="best-practices"></a>
ウィジェットはビューのコードを再利用するためのオブジェクト指向の方法です。

26
docs/guide-pt-BR/README.md

@ -74,14 +74,14 @@ Conceitos Chave
Trabalhando com Banco de Dados
------------------------------
* [Data Access Objects (DAO, Objeto de Acesso a Dados)](db-dao.md) - Estabelecendo uma conexão com o Banco de Dados, consultas básicas, transações e manipulação do esquema
* [Query Builder (Construtor de Consulta)](db-query-builder.md) - Consultando o banco de dados usando uma camada de abstração simples
* [Active Record](db-active-record.md) - Sobre o Active Record ORM, recuperando e manipulando registros e definindo relacionamentos
* [Migrations (Migrações)](db-migrations.md) - Aplica controle de versão para seus banco de dados em um ambiente de desenvolvimento em equipe
* [Data Access Objects (DAO, Objeto de Acesso a Dados)](db-dao.md)? Estabelecendo uma conexão com o Banco de Dados, consultas básicas, transações e manipulação do esquema
* [Query Builder (Construtor de Consulta)](db-query-builder.md)? Consultando o banco de dados usando uma camada de abstração simples
* [Active Record](db-active-record.md): Sobre o Active Record ORM, recuperando e manipulando registros e definindo relacionamentos
* [Migrations (Migrações)](db-migrations.md): Aplica controle de versão para seus banco de dados em um ambiente de desenvolvimento em equipe
* **TBD** [Sphinx](db-sphinx.md)
* **TBD** [Redis](db-redis.md)
* **TBD** [MongoDB](db-mongodb.md)
* **TBD** [ElasticSearch](db-elastic-search.md)
* **TBD** [ElasticSearch](db-elasticsearch.md)
Coletando Dados de Usuários
@ -96,7 +96,7 @@ Coletando Dados de Usuários
Exibindo Dados
---------------
* [Formatando Dados](output-formatting.md)
* [Formatando Dados](output-formatter.md)
* **TBD** [Paginação](output-pagination.md)
* **TBD** [Ordenação](output-sorting.md)
* [Data Providers (Provedores de Dados)](output-data-providers.md)
@ -125,7 +125,7 @@ Cache
* [Cache HTTP](caching-http.md)
Web Services com RESTful
Web Services RESTful
------------------------
* [Introdução](rest-quick-start.md)
@ -151,7 +151,7 @@ Testes
------
* [Visão Geral](test-overview.md)
* [Configuração do ambiente de testes](test-endvironment-setup.md)
* [Configuração do ambiente de testes](test-environment-setup.md)
* [Testes Unitários](test-unit.md)
* [Testes Funcionais](test-functional.md)
* [Testes de Aceitação](test-acceptance.md)
@ -184,16 +184,16 @@ Widgets
* Menu: **TBD** link para a página de demonstração
* LinkPager: **TBD** link para a página de demonstração
* LinkSorter: **TBD** link para a página de demonstração
* [Widgets do Bootstrap](bootstrap-widgets.md)
* [Widgets do Jquery UI](jui-widgets.md)
* [Widgets do Bootstrap](widget-bootstrap.md)
* [Widgets do Jquery UI](widget-jui.md)
Helpers
-------
* [Visão Geral](helper-overview.md)
* **TBD** [ArrayHelper](helper-array.md)
* **TBD** [Html](helper-html.md)
* **TBD** [Url](helper-url.md)
* [ArrayHelper](helper-array.md)
* [Html](helper-html.md)
* [Url](helper-url.md)
* **TBD** [Segurança](helper-security.md)

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

@ -6,8 +6,24 @@ ou baixando um arquivo compactado. O primeiro modo é o preferido, já que permi
que você instale novas [extensões](structure-extensions.md) ou atualize o
Yii simplesmente executando um único comando.
> Note: Ao contrário do Yii 1, as instalações padrão do Yii 2 resultam em
tanto o framework quanto um esqueleto de aplicação sendo baixados e instalados.
A instalação do Yii padrão resulta no download e instalação tanto do framework
quanto de um template de aplicação.
Um template de aplicação é uma aplicação do Yii implementando algumas recursos básicos,
como a autenticação, o formulário de contato, etc.
Este código é organizado de uma forma recomendada. No entanto, ele pode servir
como ponto de partida para seus projetos.
Nesta e nas próximas seções, iremos descrever como instalar o *Template Básico de
Aplicação* do Yii e como implementar novas funcionalidades em cima deste template.
O Yii também fornece um outro template chamado de [Template Avançado de Aplicação](tutorial-advanced-app.md) que é melhor usado em uma equipe de desenvolvimento que desenvolvem
aplicações de multiplas camadas.
> Informação: O Template Básico de Aplicação é adequado para o desenvolvimento de
cerca de 90% das aplicações Web. Este template difere do Template Avançado de
Aplicação principalmente na forma de como o seu código é organizado. Se você é
novo no Yii, recomendamos fortemente em escolher o Template Básico de Aplicação
pela sua simplicidade além de ter funcionalidades o suficiente.
If you are new to Yii, we strongly recommend you stick to the Basic Application Template for its simplicity yet sufficient functionalities.
Instalando via Composer <a name="installing-via-composer"></a>
@ -39,15 +55,12 @@ o que permite gerenciar dependências via bower e npm package por meio do Compos
Você apenas precisa rodar este comando uma vez. O segundo comando instala o Yii
em um diretório chamado `basic`. Você pode escolher um diretório diferente se quiser.
> Nota: Durante a instalação do Yii pode acontecer que o Composer peça suas
> credenciais de login do Github por ultrapassar taxa limite (rate-limit) da API do Github.
> Isso é normal pois o Composer necessita obter muitas informações de todos os
> pacotes no Github.
> Logando no Github incrementa a taxa limite (rate-limit) da API para que o Composer
> possa continuar o seu trabalho. Para mais detalhes, por favor consulte a
> [documentação do Composer](https://getcomposer.org/doc/articles/troubleshooting.md#api-rate-limit-and-oauth-tokens).
> Observação: Durante a instalação, o Composer pode pedir suas credenciais de login
> do Github. Isto é normal, pelo fato do Composer precisar obter a taxa limite
> (rate-limit) da API para recuperar as informações de dependência de pacotes do
> Github. Para mais detalhes, consulte a [documentação do Composer](https://getcomposer.org/doc/articles/troubleshooting.md#api-rate-limit-and-oauth-tokens).
> Tip: Se você quiser instalar a última versão de desenvolvimento do Yii, você
> Dica: Se você quiser instalar a última versão de desenvolvimento do Yii, você
> pode usar o seguinte comando, que adiciona uma [opção de estabilidade](https://getcomposer.org/doc/04-schema.md#minimum-stability):
>
> composer create-project --prefer-dist --stability=dev yiisoft/yii2-app-basic basic
@ -78,8 +91,9 @@ Outras Opções de Instalação <a name="other-installation-options"></a>
As instruções de instalação acima mostram como instalar o Yii, que também cria
uma aplicação Web básica que funciona imediatamente sem qualquer configuração ou
modificação (*out of the box*). Este método é um bom ponto de início para projetos
pequenos ou para quando você começar a aprender o Yii.
modificação (*out of the box*).
Esta abordagem é um bom ponto de partida para a maioria dos projetos, seja ele
pequeno ou grande. É especialmente adequado se você acabou de começar a aprender Yii.
No entanto, existem outras opções de instalação disponíveis:

483
docs/guide-pt-BR/structure-controllers.md

@ -0,0 +1,483 @@
Controllers (Controladores)
===========
Os controllers (controladores) fazem parte da arquitetura [MVC](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller).
São objetos de classes que estendem de [[yii\base\Controller]] e são responsáveis
pelo processamento das requisições e por gerar respostas. Em particular, após
assumir o controle de [applications](structure-applications.md), controllers
analisarão os dados de entradas obtidos pela requisição, passarão estes dados
para os [models](structure-models.md) (modelos), incluirão os resultados dos models
(modelos) nas [views](structure-views.md) (visões) e finalmente gerarão as respostas
de saída.
## Actions (Ações) <a name="actions"></a>
Os controllers são compostos por unidades básicas chamadas *ações* que podem ser
tratados pelos usuários finais a fim de realizar a sua execução.
No exemplo a seguir mostra um controller `post` com duas ações: `view` e `create`:
```php
namespace app\controllers;
use Yii;
use app\models\Post;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
class PostController extends Controller
{
public function actionView($id)
{
$model = Post::findOne($id);
if ($model === null) {
throw new NotFoundHttpException;
}
return $this->render('view', [
'model' => $model,
]);
}
public function actionCreate()
{
$model = new Post;
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('create', [
'model' => $model,
]);
}
}
}
```
Na ação `view` (definido pelo método `actionView()`), o primeiro código carrega o
[model](structure-models.md) conforme o ID solicitado; Se o model for devidamente
carregado, a ação irá exibi-lo utilizado a [view](structure-views.md) chamada de `view`.
Caso contrário, a ação lançará uma exceção.
Na ação `create` (definido pelo método `actionCreate()`), o código é parecido.
Primeiro ele tenta popular o [model](structure-models.md) usando os dados da requisição
em seguida os salva. Se ambos forem bem sucedidos, a ação redirecionará o navegador
para a ação `view` com o novo ID criado pelo model. Caso contrário, a ação exibirá
a view `create` na qual os usuário poderão fornecer os dados necessários.
## Routes (Rotas) <a name="routes"></a>
Os usuários finais abordarão as ações por meio de *rotas*. Uma rota é uma string composta
pelas seguintes partes:
* um ID do módulo: serve apenas se o controller pertencer a um [módulo](structure-modules.md) que não seja da aplicação;
* um ID do controller: uma string que identifica exclusivamente o controller dentre todos os controllers da mesma aplicação (ou do mesmo módulo, caso o controller pertença a um módulo);
* um ID da ação: uma string que identifica exclusivamente uma ação dentre todas as ações de um mesmo controller.
As rotas seguem o seguinte formato:
```
IDdoController/IDdoAction
```
ou o seguinte formato se o controller estiver em um módulo:
```php
IDdoModule/IDdoController/IDdoAction
```
Portanto, se um usuário fizer uma requisição com a URL `http://hostname/index.php?r=site/index`,
a ação `index` do controller `site` será executada. Para mais detalhes sobre como
as ações são resolvidas pelas rotas, por favor consulte a seção [Roteamento e Criação de URL](runtime-routing.md).
## Criando Controllers <a name="creating-controllers"></a>
Em [[yii\web\Application|aplicações Web]], os controllers devem estender de [[yii\web\Controller]]
ou de suas classes filhas. De forma semelhante, em [[yii\console\Application|aplicaçoes console]],
os controllers devem estender de [[yii\console\Controller]] ou de suas classes filhos. O código a seguir define um controller `site`:
```php
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
}
```
### IDs dos Controllers <a name="controller-ids"></a>
Normalmente, um controller é projetado para tratar as requisições relativos a
um determinado tipo de recurso. Por esta razão, os IDs dos controllers geralmente
são substantivos que referenciam-se ao tipo de recurso que será tratado.
Por exemplo, você pode usar o `article` como o ID do um controller para tratar
dados de artigos.
Por padrão, os IDs dos controllers devem conter apenas esses caracteres:
letras inglesas em caixa baixa, números, underscores (underline), traços e barras.
Por exemplo, `article` e `post-comment` são ambos IDs de controllers válidos,
enquanto `article?`, `PostComment`, `admin\post` não são.
Um ID de controller também pode conter um prefixo para o subdiretório. Por exemplo,
`admin/article` representa um controller `article` em um subdiretório `admin` sob
o [[yii\base\Application::controllerNamespace|namespace do controller]]
Os caracteres válidos para os prefixos de subdiretórios incluem: letras inglesas
em caixa alto ou caixa baixa, números, underscores (underline) e barras, onde as
barras são usadas para separar os níveis dos subdiretórios (por exemplo, `panels/admin`).
### Nomenclatura da Classe do Controller <a name="controller-class-naming"></a>
Os nomes da classes dos controllers podem ser derivadas dos IDs dos controllers
de acordo com as seguintes regras:
* Colocar em caixa alta a primeira letra de cada palavra separadas por traço.
Observe que se o ID do controller possuir barras, a regra é aplicada apenas na
parte após a última barra no ID.
* Remover os traços e substituir todas as barras por barras invertidas.
* Adicionar `Controller` como sufixo.
* E preceder ao [[yii\base\Application::controllerNamespace|namespace controller]].
Segue alguns exemplos, assumindo que o [[yii\base\Application::controllerNamespace|namespace do controller]]
tenha por padrão o valor `app\controllers`:
* `article` deriva-se de `app\controllers\ArticleController`;
* `post-comment` deriva-se de `app\controllers\PostCommentController`;
* `admin/post-comment` deriva-se de `app\controllers\admin\PostCommentController`;
* `adminPanels/post-comment` deriva-se de `app\controllers\adminPanels\PostCommentController`.
As classes dos controllers devem ser [autoloadable](concept-autoloading.md).
Por esta razão, nos exemplos anteriores, o controller `article` deve ser salvo
no arquivo cuja [alias](concept-aliases.md) é `@app/controllers/ArticleController.php`;
enquanto o controller `admin/post2-comment` deve ser salvo no `@app/controllers/admin/Post2CommentController.php`.
> Informação: No último exemplo `admin/post2-comment`, mostra como você pode colocar
um controller em um subdiretório do [[yii\base\Application::controllerNamespace|namespace controller]]. Isto é útil quando você quiser organizar seus controllers em diversas
categorias e não quiser usar [módulos](structure-modules.md).
### Mapeando Controllers <a name="controller-map"></a>
Você pode configurar um [[yii\base\Application::controllerMap|mapeamento de controllers]] para superar as barreiras impostas pelos IDs de controllers e pelos nomes de classes
descritos acima. Isto é útil principalmente quando quiser esconder alguns controllers
de terceiros na qual você não tem controle sobre seus nomes de classes.
Você pode configurar o [[yii\base\Application::controllerMap|mapeamento de controllers]]
na [configuração da aplicação](structure-applications.md#application-configurations) como o seguinte exemplo:
```php
[
'controllerMap' => [
// declara o controller "account" usando um nome de classe
'account' => 'app\controllers\UserController',
// declara o controller "article" usando uma configuração em array
'article' => [
'class' => 'app\controllers\PostController',
'enableCsrfValidation' => false,
],
],
]
```
### Controller Padrão <a name="default-controller"></a>
Cada aplicação tem um controller padrão que é especificado pela propriedade [[yii\base\Application::defaultRoute]].
Quando uma requisição não especificar uma [rota](#id-da-rota), será utilizada a
rota especificada pela propriedade.
Para as [[yii\web\Application|aplicações Web]], este valor é `'site'`, enquanto
para as [[yii\console\Application|aplicações console]] é `help`. Portanto, se uma
URL `http://hostname/index.php` for usada, significa que o controller `site` será
usado nesta requisição.
Você pode alterar o controller padrão como a seguinte [configuração da aplicação](structure-applications.md#application-configurations):
```php
[
'defaultRoute' => 'main',
]
```
## Criando Ações <a name="creating-actions"></a>
Criar ações pode ser tão simples como a definição dos chamados *métodos de ação*
em uma classe controller. Um método de ação é um método *público* cujo nome inicia
com a palavra `action`. O valor de retorno representa os dados de resposta a serem
enviados aos usuário finais. O código a seguir define duas ações, `index` e `hello-world`:
```php
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
public function actionIndex()
{
return $this->render('index');
}
public function actionHelloWorld()
{
return 'Hello World';
}
}
```
### IDs das Ações <a name="action-ids"></a>
Uma ação muitas vezes é projetada para realizar uma manipulação em particular sobre
um recurso. Por esta razão, os IDs das ações geralmente são verbos, tais como `view`, `update`, etc.
Por padrão, os IDs das ações devem conter apenas esses caracteres: letras inglesas
em caixa baixa, números, underscores (underline) e traços. Os traços em um ID da
ação são usados para separar palavras. Por exemplo, `view`, `update2`, `comment-post`
todos são IDs válidos, enquanto `view?`, `Update` não são.
Você pode criar ações de duas maneiras: ações inline (em sequência) e
ações standalone (autônomas). Uma ação inline é definida pelo método
de uma classe controller, enquanto uma ação standalone é uma classe que estende de
[[yii\base\Action]] ou de suas classes filhas. As ações inline exigem menos esforço
para serem criadas e muitas vezes as preferidas quando não se tem a intenção de
reutilizar estas ações. Ações standalone, por outro lado, são criados principalmente
para serem utilizados em diferentes controllers ou para serem distribuídos como
[extensions](structure-extensions.md).
### Ações Inline <a name="inline-actions"></a>
As ações inline referem-se a os chamados métodos de ação, que foram descritos anteriormente.
Os nomes dos métodos de ações são derivadas dos IDs das ações de acordo com os
seguintes critérios:
* Colocar em caixa alta a primeira letra de cada palavra do ID da ação;
* Remover os traços;
* Adicionar o prefixo `action`.
Por exemplo, `index` torna-se `actionIndex` e `hello-world` torna-se `actionHelloWorld`.
> Observação: Os nomes dos métodos de ações são *case-sensitive*. Se você tiver
um método chamado `ActionIndex`, não será considerado como um método de ação e
como resultado, o pedido para a ação `index` lançará uma exceção. Observe também
que os métodos de ações devem ser públicas. Um método privado ou protegido NÃO
será definido como ação inline.
As ações inline normalmente são as mais utilizadas pois demandam pouco esforço
para serem criadas. No entanto, se você deseja reutilizar algumas ações em diferentes
lugares ou se deseja distribuir uma ação, deve considerar defini-la como uma *ação standalone*.
### Ações Standalone <a name="standalone-actions"></a>
Ações standalone são definidas por classes de ações que estendem de [[yii\base\Action]]
ou de suas classes filhas.
Por example, nas versões do Yii, existe a [[yii\web\ViewAction]] e a [[yii\web\ErrorAction]], ambas são ações standalone.
Para usar uma ação standalone, você deve *mapear as ações* sobrescrevendo o método
[[yii\base\Controller::actions()]] em suas classes controllers como o seguinte:
```php
public function actions()
{
return [
// declara a ação "error" usando um nome de classe
'error' => 'yii\web\ErrorAction',
// declara a ação "view" usando uma configuração em array
'view' => [
'class' => 'yii\web\ViewAction',
'viewPrefix' => '',
],
];
}
```
Como pode ver, o método `actions()` deve retornar um array cujas chaves são os IDs
das ações e os valores correspondentes ao nome da classe da ação ou [configurações](concept-configurations.md). Ao contrário das ações inline, os IDs das ações standalone
podem conter caracteres arbitrários desde que sejam mapeados no método `actions()`.
Para criar uma classe de ação standalone, você deve estender de [[yii\base\Action]] ou de duas classes filhas e implementar um método público chamado `run()`. A regra para o método `run()`
é semelhante ao de um método de ação. Por exemplo,
```php
<?php
namespace app\components;
use yii\base\Action;
class HelloWorldAction extends Action
{
public function run()
{
return "Hello World";
}
}
```
### Resultados da Ação <a name="action-results"></a>
O valor de retorno do método de ação ou do método `run()` de uma ação standalone
são importantes. Eles representam o resultado da ação correspondente.
O valor de retorno pode ser um objeto de [resposta](runtime-responses.md) que
que enviará como resposta aos usuários finais.
* Para [[yii\web\Application|aplicações Web]], o valor de retorno também poder
ser algum dado arbitrário que será atribuído à propriedade [[yii\web\Response::data]]
e ainda ser convertido em uma string para representar o corpo da resposta.
* Para [[yii\console\Application|aplicações console]], o valor de retorno também
poder ser um inteiro representando o [[yii\console\Response::exitStatus|exit status]]
(status de saída) da execução do comando.
Nos exemplos acima, todos os resultados são strings que serão tratados como o
corpo das respostas para serem enviados aos usuários finais. No exemplo a seguir,
mostra como uma ação pode redirecionar o navegador do usuário para uma nova URL
retornando um objeto de resposta (o método [[yii\web\Controller::redirect()|redirect()]]
retorna um objeto de resposta):
```php
public function actionForward()
{
// redireciona o navegador do usuário para http://example.com
return $this->redirect('http://example.com');
}
```
### Parâmetros da Ação <a name="action-parameters"></a>
Os métodos de ações para as ações inline e os métodos `run()` para as ações
standalone podem receber parâmetros, chamados *parâmetros da ação*.
Seus valores são obtidos a partir das requisições. Para
[[yii\web\Application|aplicações Web]], o valor de cada parâmetro da ação são
obtidos pelo `$_GET` usando o nome do parâmetro como chave; para
[[yii\console\Application|aplicações console]], eles correspondem aos argumentos
da linha de comando.
No exemplo a seguir, a ação `view` (uma ação inline) possui dois parâmetros declarados:
`$id` e `$version`.
```php
namespace app\controllers;
use yii\web\Controller;
class PostController extends Controller
{
public function actionView($id, $version = null)
{
// ...
}
}
```
A seguir, os parâmetros da ação serão populados em diferentes requisições:
* `http://hostname/index.php?r=post/view&id=123`: o parâmetro `$id` receberá
o valor `'123'`, enquanto o `$version` continuará com o valor nulo porque não
existe o parâmetro `version` na URL.
* `http://hostname/index.php?r=post/view&id=123&version=2`: os parâmetros `$id`
e `$version` serão receberão os valores `'123'` e `'2'`, respectivamente.
* `http://hostname/index.php?r=post/view`: uma exceção [[yii\web\BadRequestHttpException]]
será lançada porque o parâmetro obrigatório `$id` não foi informado na requisição.
* `http://hostname/index.php?r=post/view&id[]=123`: uma exceção [[yii\web\BadRequestHttpException]]
será lançada porque o parâmetro `$id` foi informado com um valor array `['123']`
na qual não era esperado.
Se você quiser que um parâmetro da ação aceite valores arrays, deverá declara-lo
explicitamente com `array`, como mostro a seguir:
```php
public function actionView(array $id, $version = null)
{
// ...
}
```
Agora, se a requisição for `http://hostname/index.php?r=post/view&id[]=123`, o
parâmetro `$id` receberá o valor `['123']`. Se a requisição for
`http://hostname/index.php?r=post/view&id=123`, o parâmetro `$id` ainda receberá
um array como valor pois o valor escalar `'123'` será convertido automaticamente
em um array.
Os exemplo acima mostram, principalmente, como os parâmetros da ação trabalham em
aplicações Web. Para aplicações console, por favor, consulte a seção
[Comandos de Console](tutorial-console.md) para mais detalhes.
### Default Action <a name="default-action"></a>
Cada controller tem uma ação padrão especificado pela propriedade
[[yii\base\Controller::defaultAction]].
Quando uma [rota](#id-da-rota) contém apenas o ID do controller, implica que a
ação padrão do controller seja solicitada.
Por padrão, a ação padrão é definida como `index`. Se quiser alterar o valor padrão,
simplesmente sobrescreva esta propriedade na classe controller, como o seguinte:
```php
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
public $defaultAction = 'home';
public function actionHome()
{
return $this->render('home');
}
}
```
## Ciclo de Vida do Controller <a name="controller-lifecycle"></a>
Ao processar uma requisição, a [aplicação](structure-applications.md) criará
um controller baseada na [rota](#routes) solicitada. O controller, então, se submeterá
ao seguinte ciclo de vida para concluir a requisição:
1. O método [[yii\base\Controller::init()]] é chamado após o controller ser criado e configurado.
2. O controller cria um objeto da ação baseada no ID da ação solicitada:
* Se o ID da ação não for especificado, o [[yii\base\Controller::defaultAction|ID da ação padrão]] será utilizada.
* Se o ID da ação for encontrada no [[yii\base\Controller::actions()|mapeamento das ações]], uma ação standalone será criada;
* Se o ID da ação for encontrada para corresponder a um método de ação, uma ação inline será criada;
* Caso contrário, uma exceção [[yii\base\InvalidRouteException]] será lançada.
3. De forma sequencial, o controller chama o método `beforeAction()` da aplicação, o módulo (se o controller pertencer a um módulo) e o controller.
* Se uma das chamadas retornar false, o restante dos métodos `beforeAction()` serão ignoradas e a execução da ação será cancelada.
* Por padrão, cada método `beforeAction()` desencadeia a execução de um evento chamado `beforeAction` na qual você pode associar a uma função (handler).
4. O controller executa a ação:
* Os parâmetros da ação serão analizados e populados a partir dos dados obtidos pela requisição;
5. De forma sequencial, o controller chama o método `afterAction()` do controller, o módulo (se o controller pertencer a um módulo) e a aplicação.
* Por padrão, cada método `afterAction()` desencadeia a execução de um evento chamado `afterAction` na qual você pode associar a uma função (handler).
6. A aplicação obterá o resultado da ação e irá associá-lo na [resposta](runtime-responses.md).
## Best Practices <a name="best-practices"></a>
Em uma aplicação bem projetada, frequentemente os controllers são bem pequenos na
qual cada ação possui poucas linhas de códigos.
Se o controller for um pouco complicado, geralmente indica que terá que refaze-lo
e passar algum código para outro classe.
Em resumo, os controllers:
* podem acessar os dados de uma [requisição](runtime-requests.md);
* podem chamar os métodos dos [models](structure-models.md) e outros componentes
de serviço com dados da requisição;
* podem usar as [views](structure-views.md) para compor as respostas;
* NÃO devem processar os dados da requisição - isto deve ser feito pelos [models](structure-models.md);
* devem evitar inserir códigos HTML ou outro código de apresentação - é melhor
que sejam feitos nas [views](structure-views.md).

578
docs/guide-pt-BR/structure-models.md

@ -0,0 +1,578 @@
Models (Modelos)
================
Os models (modelos) fazem parte da arquitetura [MVC](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller).
Eles representam os dados, as regras e a lógica de negócio.
Você pode criar uma classe model estendendo de [[yii\base\Model]] ou de seus filhos.
A classe base [[yii\base\Model]] suporta muitos recursos úteis:
* [Atributos](#attributes): representa os dados de negócio e podem ser acessados
normalmente como uma propriedade de objeto ou como um elemento de array;
* [Labels dos atributos](#attribute-labels): especifica os labels de exibição dos
atributos;
* [Atribuição em massa](#massive-assignment): suporta popular vários atributos em
uma única etapa;
* [Regras de validação](#validation-rules): garante que os dados de entrada sejam
baseadas nas regras de validação que foram declaradas;
* [Data Exporting](#data-exporting): permite que os dados de model a serem exportados
em array possuam formatos personalizados.
A classe `Model` também é a classe base para models mais avançados, como o [Active Record](db-active-record.md).
Por favor, consulte a documentação relevante para mais detalhes sobre estes models mais avançados.
> Informação: Você não é obrigado basear suas classe model em [[yii\base\Model]].
> No entanto, por existir muitos componentes do Yii construídos para suportar o
> [[yii\base\Model]], normalmente é a classe base preferível para um model.
## Atributos <a name="attributes"></a>
Os models representam dados de negócio por meio de *atributos*. Cada atributo é
uma propriedade publicamente acessível de um model. O método [[yii\base\Model::attributes()]]
especifica quais atributos de uma classe model possuirá.
Você pode acessar um atributo como fosse uma propriedade normal de um objeto:
```php
$model = new \app\models\ContactForm;
// "name" é um atributo de ContactForm
$model->name = 'example';
echo $model->name;
```
Você também pode acessar os atributos como elementos de um array, graças ao suporte
de [ArrayAccess](http://php.net/manual/en/class.arrayaccess.php) e
[ArrayIterator](http://php.net/manual/en/class.arrayiterator.php) pelo
[[yii\base\Model]]:
```php
$model = new \app\models\ContactForm;
// acessando atributos como elementos de array
$model['name'] = 'example';
echo $model['name'];
// iterando sobre os atributos
foreach ($model as $name => $value) {
echo "$name: $value\n";
}
```
### Definindo Atributos <a name="defining-attributes"></a>
Por padrão, se a classe model estender diretamente de [[yii\base\Model]], todas
as suas variáveis públicas e não estáticas serão atributos. Por exemplo, a classe
model `ContactForm` a seguir possui quatro atributos: `name`, `email`, `subject`
e `body`. O model `ContactForm` é usado para representar os dados de entrada obtidos
a partir de um formulário HTML.
```php
namespace app\models;
use yii\base\Model;
class ContactForm extends Model
{
public $name;
public $email;
public $subject;
public $body;
}
```
Você pode sobrescrever o método [[yii\base\Model::attributes()]] para definir
atributos de uma forma diferente. Este método deve retornar os nomes dos atributos
em um model. Por exemplo, o [[yii\db\ActiveRecord]] faz com que o método retorne
os nomes das colunas da tabela do banco de dados como nomes de atributos.
Observe que também poderá sobrescrever os métodos mágicos tais como `__get()` e
`__set()`, para que os atributos poderem ser acessados como propriedades normais
de objetos.
### Labels dos Atributos <a name="attribute-labels"></a>
Ao exibir valores ou obter dados de entrada dos atributos, muitas vezes é necessário
exibir alguns labels associados aos atributos. Por exemplo, dado um atributo chamado
`firstName`, você pode querer exibir um label `First Name` que é mais amigável
quando exibido aos usuários finais como em formulários e mensagens de erro.
Você pode obter o label de um atributo chamando o método [[yii\base\Model::getAttributeLabel()]].
Por exemplo,
```php
$model = new \app\models\ContactForm;
// displays "Name"
echo $model->getAttributeLabel('name');
```
Por padrão, os labels dos atributos automaticamente serão gerados com os nomes dos
atributos. Isto é feito pelo método [[yii\base\Model::generateAttributeLabel()]].
Ele transforma os nomes camel-case das variáveis em várias palavras, colocando em
caixa alta a primeira letra de cada palavra. Por exemplo, `username` torna-se
`Username`, enquanto `firstName` torna-se `First Name`.
Se você não quiser usar esta geração automática do labels, poderá sobrescrever o
método [[yii\base\Model::attributeLabels()]] declarando explicitamente os labels
dos atributos. Por exemplo,
```php
namespace app\models;
use yii\base\Model;
class ContactForm extends Model
{
public $name;
public $email;
public $subject;
public $body;
public function attributeLabels()
{
return [
'name' => 'Your name',
'email' => 'Your email address',
'subject' => 'Subject',
'body' => 'Content',
];
}
}
```
Para aplicações que suportam vários idiomas, você pode querer traduzir os labels
dos atributos. Isto também é feito no método [[yii\base\Model::attributeLabels()|attributeLabels()]],
conforme o exemplo a seguir:
```php
public function attributeLabels()
{
return [
'name' => \Yii::t('app', 'Your name'),
'email' => \Yii::t('app', 'Your email address'),
'subject' => \Yii::t('app', 'Subject'),
'body' => \Yii::t('app', 'Content'),
];
}
```
Você pode até definir condicionalmente os labels dos atributos. Por exemplo, baseado
no [cenário](#scenarios) que o model estiver utilizando, você pode retornar diferentes
labels para o mesmo atributo.
> Informação: Estritamente falando, os labels dos atributos fazem parte das
[views](structure-views.md) (visões). Mas ao declarar os labels em models (modelos),
frequentemente tornam-se mais convenientes e podem resultar um código mais limpo
e reutilizável.
## Cenários <a name="scenarios"></a>
Um model (modelo) pode ser usado em diferentes *cenários*. Por exemplo, um model
`User` pode ser usado para obter dados de entrada de login, mas também pode ser
usado com a finalidade de registrar o usuário. Em diferentes cenários, um model
pode usar diferentes regras e lógicas de negócio. Por exemplo, um atributo `email`
pode ser obrigatório durante o cadastro do usuário, mas não durante ao login.
Um model (modelo) usa a propriedade [[yii\base\Model::scenario]] para identificar
o cenário que está sendo usado.
Por padrão, um model (modelo) suporta apenas um único cenário chamado `default`.
O código a seguir mostra duas formas de definir o cenário de um model (modelo):
```php
// o cenário é definido pela propriedade
$model = new User;
$model->scenario = 'login';
// o cenário é definido por meio de configuração
$model = new User(['scenario' => 'login']);
```
Por padrão, os cenários suportados por um model (modelo) são determinados pelas
[regras de validação](#validation-rules) declaradas no próprio model (modelo).
No entanto, você pode personalizar este comportamento sobrescrevendo o método
[[yii\base\Model::scenarios()]], conforme o exemplo a seguir:
```php
namespace app\models;
use yii\db\ActiveRecord;
class User extends ActiveRecord
{
public function scenarios()
{
return [
'login' => ['username', 'password'],
'register' => ['username', 'email', 'password'],
];
}
}
```
> Informação: Nos exemplos anteriores, as classes model (model) são estendidas de
[[yii\db\ActiveRecord]] por usarem diversos cenários para auxiliarem as classes
[Active Record](db-active-record.md) classes.
O método `scenarios()` retorna um array cujas chaves são os nomes dos cenários e
os valores que correspondem aos *active attributes* (atributo ativo). Um atributo
ativo podem ser [atribuídos em massa](#massive-assignment) e é sujeito a
[validação](#validation-rules). No exemplo anterior, os atributos `username` e
`password` são ativos no cenário `login`; enquanto no cenário `register`, além
dos atribitos `username` e `password`, o atributo `email` passará a ser ativo.
A implementação padrão do método `scenarios()` retornará todos os cenários encontrados
nas regras de validação declaradas no método [[yii\base\Model::rules()]]. Ao
sobrescrever o método `scenarios()`, se quiser introduzir novos cenários, além
dos cenários padrão, poderá escrever um código conforme o exemplo a seguir:
```php
namespace app\models;
use yii\db\ActiveRecord;
class User extends ActiveRecord
{
public function scenarios()
{
$scenarios = parent::scenarios();
$scenarios['login'] = ['username', 'password'];
$scenarios['register'] = ['username', 'email', 'password'];
return $scenarios;
}
}
```
O recurso de cenários são usados principalmente para [validação](#validation-rules)
e para [atribuição em massa](#massive-assignment).
Você pode, no entanto, usá-lo para outros fins. Por exemplo, você pode declarar
diferentes [labels para os atributos](#attribute-labels) baseados no cenário atual.
## Regras de Validação <a name="validation-rules"></a>
Quando os dados para um model (modelo) são recebidos de usuários finais, devem ser
validados para garantir que satisfazem as regras (*regras de validação*, também
conhecidos como *regras de negócio*). Por exemplo, considerando um model (modelo)
`ContactForm`, você pode querer garantir que todos os atributos não sejam vazios e
que o atributo `email` contenha um e-mail válido.
Se o valor de algum atributo não satisfizer a regra de negócio correspondente,
mensagens apropriadas de erros serão exibidas para ajudar o usuário a corrigi-los.
Você pode chamar o método [[yii\base\Model::validate()]] para validar os dados
recebidos. O método usará as regras de validação declaradas em [[yii\base\Model::rules()]]
para validar todos os atributos relevantes. Se nenhum erro for encontrado, o método
retornará true. Caso contrário, o método irá manter os erros na propriedade
[[yii\base\Model::errors]] e retornará false. Por exemplo,
```php
$model = new \app\models\ContactForm;
// os atributos do model serão populados pelos dados fornecidos pelo usuário
$model->attributes = \Yii::$app->request->post('ContactForm');
if ($model->validate()) {
// todos os dados estão válidos
} else {
// a validação falhou: $errors é um array contendo as mensagens de erro
$errors = $model->errors;
}
```
Para declarar as regras de validação em um model (modelo), sobrescreva o método
[[yii\base\Model::rules()]] retornando as regras que os atributos do model (modelo)
devem satisfazer. O exemplo a seguir mostra as regras de validação sendo declaradas
no model (modelo) `ContactForm`:
```php
public function rules()
{
return [
// os atributos name, email, subject e body são obrigatórios
[['name', 'email', 'subject', 'body'], 'required'],
// o atributo email deve ter um e-mail válido
['email', 'email'],
];
}
```
Uma regra pode ser usada para validar um ou vários atributos e, um atributo pode
ser validado por uma ou várias regras.
Por favor, consulte a seção [Validação de Dados](input-validation.md) para mais
detalhes sobre como declarar regras de validação.
Às vezes, você pode querer que uma regra se aplique apenas em determinados
[cenários](#scenarios). Para fazer isso, você pode especificar a propriedade
`on` de uma regra, como o seguinte:
```php
public function rules()
{
return [
// os atributos username, email e password são obrigatórios no cenario "register"
[['username', 'email', 'password'], 'required', 'on' => 'register'],
// os atributos username e password são obrigatórios no cenario "login"
[['username', 'password'], 'required', 'on' => 'login'],
];
}
```
Se você não especificar a propriedade `on`, a regra será aplicada em todos os
cenários. Uma regra é chamada de *active rule* (regra ativa), se ela puder ser
aplicada no [[yii\base\Model::scenario|cenário]] atual.
Um atributo será validado, se e somente se, for um atributo ativo declarado no
método `scenarios()` e estiver associado a uma ou várias regras declaradas no método `rules()`.
## Atribuição em Massa <a name="massive-assignment"></a>
Atribuição em massa é a forma conveniente para popular um model (modelo) com os
dados de entrada do usuário usando uma única linha de código.
Ele popula os atributos de um model (modelo) atribuindo os dados de entrada diretamente
na propriedade [[yii\base\Model::$attributes]]. Os dois códigos a seguir são
equivalentes, ambos tentam atribuir os dados do formulário enviados pelos usuários
finais para os atributos do model (modelo) `ContactForm`. Evidentemente, a
primeira forma, que utiliza a atribuição em massa, é a mais limpa e o menos
propenso a erros do que a segunda forma:
```php
$model = new \app\models\ContactForm;
$model->attributes = \Yii::$app->request->post('ContactForm');
```
```php
$model = new \app\models\ContactForm;
$data = \Yii::$app->request->post('ContactForm', []);
$model->name = isset($data['name']) ? $data['name'] : null;
$model->email = isset($data['email']) ? $data['email'] : null;
$model->subject = isset($data['subject']) ? $data['subject'] : null;
$model->body = isset($data['body']) ? $data['body'] : null;
```
### Atributos Seguros <a name="safe-attributes"></a>
A atribuição em massa só se aplica aos chamados *safe attributes* (atributos seguros),
que são os atributos listados no [[yii\base\Model::scenarios()]] para o
[[yii\base\Model::scenario|cenário]] atual de um model (modelo).
Por exemplo, se o model (modelo) `User` declarar o cenário como o código a seguir,
quando o cenário atual for `login`, apenas os atributos `username` e `password`
podem ser atribuídos em massa. Todos os outros atributos permanecerão inalterados.
```php
public function scenarios()
{
return [
'login' => ['username', 'password'],
'register' => ['username', 'email', 'password'],
];
}
```
> Informação: A razão da atribuição em massa só se aplicar para os atributos seguros
é para que você tenha o controle de quais atributos podem ser modificados pelos
dados dos usuário finais. Por exemplo, se o model (modelo) tiver um atributo
`permission` que determina a permissão atribuída ao usuário, você gostará que
apenas os administradores possam modificar este atributo através de uma interface backend.
Como a implementação do método [[yii\base\Model::scenarios()]] retornará todos os
cenários e atributos encontrados em [[yii\base\Model::rules()]], se não quiser
sobrescrever este método, isto significa que um atributo é seguro desde que esteja
mencionado em uma regra de validação ativa.
Por esta razão, uma alias especial de validação chamada `safe`, será fornecida
para que você possa declarar um atributo seguro, sem ser validado. Por exemplo,
a declaração da regra a seguir faz com que tanto o atributo `title` quanto o
`description` sejam seguros.
```php
public function rules()
{
return [
[['title', 'description'], 'safe'],
];
}
```
### Atributos não Seguros <a name="unsafe-attributes"></a>
Como descrito anteriormente, o método [[yii\base\Model::scenarios()]] serve para
dois propósitos: determinar quais atributos devem ser validados e quais atributos
são seguros. Em alguns casos raros, você pode quer validar um atributo sem marca-lo
como seguro. Para fazer isto, acrescente um ponto de exclamação `!` como prefixo
do nome do atributo ao declarar no método `scenarios()`, como o que foi feito no
atributo `secret` no exemplo a seguir:
```php
public function scenarios()
{
return [
'login' => ['username', 'password', '!secret'],
];
}
```
Quando o model (modelo) estiver no cenário `login`, todos os três atributos serão
validados. No entanto, apenas os atributos `username` e `password` poderão ser
atribuídos em massa. Para atribuir um valor de entrada no atributo `secret`, terá
que fazer isto explicitamente da seguinte forma:
```php
$model->secret = $secret;
```
## Exportação de Dados <a name="data-exporting"></a>
Muitas vezes os models (modelos) precisam ser exportados em diferentes tipos de
formatos. Por exemplo, você pode querer converter um conjunto de models (modelos)
no formato JSON ou Excel. O processo de exportação pode ser divido em duas etapas independentes.
Na primeira etapa, os models (modelos) serão convertidos em arrays; na segunda
etapa, os arrays serão convertidos em um determinado formato. Se concentre apenas
na primeira etapa, uma vez que a segunda etapa pode ser alcançada por formatadores
de dados genéricos, tais como o [[yii\web\JsonResponseFormatter]].
A maneira mais simples de converter um model (modelo) em um array consiste no uso
da propriedade [[yii\base\Model::$attributes]].
Por exemplo,
```php
$post = \app\models\Post::findOne(100);
$array = $post->attributes;
```
Por padrão, a propriedade [[yii\base\Model::$attributes]] retornará os valores de
todos os atributos declarados no método [[yii\base\Model::attributes()]].
Uma maneira mais flexível e poderosa de converter um model (modelo) em um array é
através do método [[yii\base\Model::toArray()]]. O seu comportamento padrão é o
mesmo do [[yii\base\Model::$attributes]]. No entanto, ele permite que você escolha
quais itens de dados, chamados de *fields* (campos), devem ser mostrados no array
resultante e como eles devem vir formatados.
Na verdade, é a maneira padrão de exportação de models (modelos) no desenvolvimento
de Web services RESTful, como descrito na seção [Formatando Respostas](rest-response-formatting.md).
### Campos <a name="fields"></a>
Um campo é simplesmente um elemento nomeado no array obtido pela chamada do método
[[yii\base\Model::toArray()]] de um model (modelo).
Por padrão, os nomes dos campos são iguais aos nomes dos atributos. No entanto,
você pode alterar este comportamento sobrescrevendo os métodos
[[yii\base\Model::fields()|fields()]] e/ou [[yii\base\Model::extraFields()|extraFields()]].
Ambos os métodos devem retornar uma lista dos campos definidos. Os campos definidos
pelo método `fields()` são os campos padrão, o que significa que o `toArray()`
retornará estes campos por padrão. O método `extraFields()` define, de forma adicional,
os campos disponíveis que também podem ser retornados pelo `toArray()`, contanto
que sejam especificados através do parâmetro `$expand`. Por exemplo, o código a
seguir retornará todos os campos definidos em `fields()` incluindo os campos
`prettyName` e `fullAddress`, a menos que estejam definidos no `extraFields()`.
```php
$array = $model->toArray([], ['prettyName', 'fullAddress']);
```
Você poderá sobrescrever o método `fields()` para adicionar, remover, renomear ou
redefinir os campos. O valor de retorno do `fields()` deve ser um array. As chaves
do array não os nomes dos campos e os valores correspondem ao nome do atributo
definido, na qual, podem ser tanto os nomes de propriedades/atributos quanto funções
anônimas que retornam o valor dos campos correspondentes. Em um caso especial,
quando o nome do campo for igual ao nome do atributo definido, você poderá omitir
a chave do array. Por exemplo,
```php
// usar uma lista explicita de todos os campos lhe garante que qualquer mudança
// em sua tabela do banco de dados ou atributos do model (modelo) não altere os
// nomes de seus campos (para manter compatibilidade com versões anterior da API).
public function fields()
{
return [
// o nome do campos é igual ao nome do atributo
'id',
// o nome do campo é "email", o nome do atributo correspondente é "email_address"
'email' => 'email_address',
// o nome do campo é "name", o seu valor é definido por uma função call-back do PHP
'name' => function () {
return $this->first_name . ' ' . $this->last_name;
},
];
}
// filtra alguns campos, é bem usado quando você quiser herdar a implementação
// da classe pai e remover alguns campos delicados.
public function fields()
{
$fields = parent::fields();
// remove os campos que contém informações delicadas
unset($fields['auth_key'], $fields['password_hash'], $fields['password_reset_token']);
return $fields;
}
```
> Atenção: Como, por padrão, todos os atributos de um model (modelo) serão
>incluídos no array exportado, você deve examinar seus dados para ter certeza
>que não possuem informações delicadas. Se existir, deverá sobrescrever o método
>`fields()` para remove-los. No exemplo anterior, nós decidimos remover os
>campos `auth_key`, `password_hash` e `password_reset_token`.
## Boas Práticas <a name="best-practices"></a>
A representação dos dados, regras e lógicas de negócios estão centralizados nos
models (modelos). Muitas vezes precisam ser reutilizadas em lugares diferentes.
Em um aplicativo bem projetado, models (modelos) geralmente são muitos maiores
que os [controllers](structure-controllers.md)
Em resumo, os models (modelos):
* podem conter atributos para representar os dados de negócio;
* podem conter regras de validação para garantir a validade e integridade dos dados;
* podem conter métodos para implementar lógicas de negócio;
* NÃO devem acessar diretamente as requisições, sessões ou quaisquer dados do
ambiente do usuário. Os models (modelos) devem receber estes dados a partir dos
[controllers (controladores)](structure-controllers.md);
* devem evitar inserir HTML ou outros códigos de apresentação – isto deve ser
feito nas [views (visões)](structure-views.md);
* devem evitar ter muitos [cenários](#scenarios) em um único model (modelo).
Você deve considerar em utilizar com mais frequência a última recomendação acima
quando desenvolver sistemas grandes e complexos.
Nestes sistemas, os models (modelos) podem ser bem grandes, pois são usados em
muitos lugares e podendo, assim, conter muitas regras e lógicas de negócio.
Nestes casos, a manutenção do código de um model (modelo) pode se transformar
em um pesadelo, na qual uma simples mudança no código pode afetar vários lugares
diferentes. Para desenvolver um model (modelo) manutenível, você pode seguir a
seguinte estratégia:
* Definir um conjunto de classes model (modelo) base que são compartilhados por
diferentes [aplicações](structure-applications.md) ou [módulos](structure-modules.md).
Estas classes model (modelo) base deve contem um conjunto mínimo de regras e lógicas
de negocio que são comuns entre os locais que as utilizem.
* Em cada [aplicação](structure-applications.md) ou [módulo](structure-modules.md)
que usa um model (modelo), deve definir uma classe model (modelo) concreta que
estenderá a classe model (modelo) base que a corresponde. A classe model (modelo)
concreta irá conter apenas as regras e lógicas que são específicas de uma aplicação
ou módulo.
Por exemplo, no [Modelo de Aplicação Avançada](tutorial-advanced-app.md), você
pode definir uma classe model (modelo) base `common\models\Post`. Em seguida,
para a aplicação front-end, você define uma classe model (modelo) concreta
`frontend\models\Post` que estende de `common\models\Post`. E de forma similar
para a aplicação back-end, você define a `backend\models\Post`. Com essa estratégia,
você garantirá que o `frontend\models\Post` terá apenas códigos específicos da
aplicação front-end e, se você fizer qualquer mudança nele, não precisará se
preocupar se esta mudança causará erros na aplicação back-end.

4
docs/guide-ru/tutorial-advanced-app.md

@ -39,7 +39,7 @@
php /path/to/yii-application/init
```
Для производственных сервером удобно выполнять данную команду в неинтерактивном режиме.
Для производственных серверов удобно выполнять данную команду в неинтерактивном режиме.
```
php /path/to/yii-application/init --env=Production overwrite=All
@ -139,7 +139,7 @@
- `frontend/config/main.php`
- `frontend/config/main-local.php`
Парамтры считываются в следующем порядке:
Параметры считываются в следующем порядке:
- `common/config/params.php`
- `common/config/params-local.php`

8
docs/guide-uk/README.md

@ -49,7 +49,7 @@ All Rights Reserved.
* [Огляд](runtime-overview.md)
* [Bootstrapping](runtime-bootstrapping.md)
* [Роутінг та створення URL](runtime-routing.md)
* [Маршрутизація та створення URL](runtime-routing.md)
* [Запити](runtime-requests.md)
* [Відповіді](runtime-responses.md)
* [Сесії та кукі](runtime-sessions-cookies.md)
@ -112,7 +112,7 @@ All Rights Reserved.
* [Авторизація](security-authorization.md)
* [Робота з паролями](security-passwords.md)
* **TBD** [Клієнти авторизації](security-auth-clients.md)
* **TBD** [Кращі практики](security-best-practices.md)
* [Кращі практики](security-best-practices.md)
Кешування
@ -131,7 +131,7 @@ RESTful веб-сервіси
* [Швидкий старт](rest-quick-start.md)
* [Ресурси](rest-resources.md)
* [Контролери](rest-controllers.md)
* [Роутінг](rest-routing.md)
* [Маршрутизація](rest-routing.md)
* [Форматування відповіді](rest-response-formatting.md)
* [Аутентифікація](rest-authentication.md)
* [Обмеження частоти запитів](rest-rate-limiting.md)
@ -193,7 +193,7 @@ RESTful веб-сервіси
* [Огляд](helper-overview.md)
* [ArrayHelper](helper-array.md)
* **TBD** [Html](helper-html.md)
* [Html](helper-html.md)
* [Url](helper-url.md)
* **TBD** [Security](helper-security.md)

512
docs/guide-uk/images/application-lifecycle.graphml

@ -0,0 +1,512 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
<!--Created by yEd 3.13-->
<key for="graphml" id="d0" yfiles.type="resources"/>
<key for="port" id="d1" yfiles.type="portgraphics"/>
<key for="port" id="d2" yfiles.type="portgeometry"/>
<key for="port" id="d3" yfiles.type="portuserdata"/>
<key attr.name="url" attr.type="string" for="node" id="d4"/>
<key attr.name="description" attr.type="string" for="node" id="d5"/>
<key for="node" id="d6" yfiles.type="nodegraphics"/>
<key attr.name="Description" attr.type="string" for="graph" id="d7"/>
<key attr.name="url" attr.type="string" for="edge" id="d8"/>
<key attr.name="description" attr.type="string" for="edge" id="d9"/>
<key for="edge" id="d10" yfiles.type="edgegraphics"/>
<graph edgedefault="directed" id="G">
<data key="d7"/>
<node id="n0" yfiles.foldertype="group">
<data key="d4"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="570.7368214925131" width="763.2772213171534" x="-1269.9373595143054" y="-206.46394602457679"/>
<y:Fill color="#FFCC0024" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="node_width" backgroundColor="#FFCC00" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="763.2772213171534" x="0.0" y="0.0">Вхідний скрипт (index.php або yii)</y:NodeLabel>
<y:Shape type="rectangle"/>
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
<y:GroupNode>
<y:Geometry height="50.0" width="50.0" x="313.2978515625" y="225.33495140075684"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="63.75830078125" x="-6.879150390625" y="0.0">Folder 4</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
</y:Realizers>
</y:ProxyAutoBoundsNode>
</data>
<graph edgedefault="directed" id="n0:">
<node id="n0::n0">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="324.9258883570935" x="-1249.511914911339" y="-169.79793039957679"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="219.583984375" x="52.67095199104665" y="5.93359375">Завантаження конфігурації додатка<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n1" yfiles.foldertype="group">
<data key="d4"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="308.66601562499994" width="330.35133296005984" x="-1254.9373595143054" y="35.983324686686274"/>
<y:Fill color="#FFEFD6" transparent="false"/>
<y:BorderStyle hasColor="false" type="dashed" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="node_width" backgroundColor="#FF9900" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="330.35133296005984" x="0.0" y="0.0">Створення екземпляру додатка</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
<y:BorderInsets bottom="19" bottomF="19.15489692687993" left="5" leftF="5.425444602966309" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
<y:GroupNode>
<y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="63.75830078125" x="-6.879150390625" y="0.0">Folder 5</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
</y:Realizers>
</y:ProxyAutoBoundsNode>
</data>
<graph edgedefault="directed" id="n0::n1:">
<node id="n0::n1::n0">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="294.92588835709347" x="-1234.511914911339" y="72.64934031168627"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="49.814453125" x="122.55571761604665" y="5.93359375">preInit()<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n1::n1">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="294.92588835709347" x="-1234.511914911339" y="122.64524027506516"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="192.185546875" x="51.37017074104665" y="5.93359375">Реєстрація обробника помилок<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n1::n2">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="294.92588835709347" x="-1234.511914911339" y="174.96110788981125"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="226.3515625" x="34.28716292854665" y="5.93359375">Налаштування властивостей додатка<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n1::n3">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="294.92588835709347" x="-1234.511914911339" y="226.56779181162517"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="30.677734375" x="132.12407699104665" y="5.93359375">init()<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n1::n4">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="294.9258883570935" x="-1234.511914911339" y="280.4944433848063"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="68.283203125" x="113.32134261604665" y="5.93359375">bootstrap()<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
</graph>
</node>
<node id="n0::n2" yfiles.foldertype="group">
<data key="d4"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="410.9838918050131" width="324.9258883570935" x="-846.5860265542456" y="-169.08748118082679"/>
<y:Fill color="#FFEFD6" transparent="false"/>
<y:BorderStyle hasColor="false" type="dashed" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="node_width" backgroundColor="#FF9900" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="324.9258883570935" x="0.0" y="0.0">Виконання додатка</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="1.1368683772161603E-13"/>
</y:GroupNode>
<y:GroupNode>
<y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="63.75830078125" x="-6.879150390625" y="0.0">Folder 3</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
</y:Realizers>
</y:ProxyAutoBoundsNode>
</data>
<graph edgedefault="directed" id="n0::n2:">
<node id="n0::n2::n0">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="294.9258883570935" x="-831.5860265542456" y="-132.42146555582667"/>
<y:Fill color="#99CC00" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="148.84375" x="73.04106917854676" y="5.93359375">EVENT_BEFORE_REQUEST<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n2::n1" yfiles.foldertype="group">
<data key="d4"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="203.666015625" width="294.9258883570935" x="-831.5860265542456" y="-78.08748118082679"/>
<y:Fill color="#99336635" transparent="false"/>
<y:BorderStyle hasColor="false" type="dashed" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="node_width" backgroundColor="#993366" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" modelName="internal" modelPosition="t" textColor="#FFFFFF" visible="true" width="294.9258883570935" x="0.0" y="0.0">Обробка запиту</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
<y:BorderInsets bottom="8" bottomF="7.929194132486941" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
<y:GroupNode>
<y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="63.75830078125" x="-6.879150390625" y="0.0">Folder 4</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
</y:Realizers>
</y:ProxyAutoBoundsNode>
</data>
<graph edgedefault="directed" id="n0::n2::n1:">
<node id="n0::n2::n1::n0">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="264.9258883570935" x="-816.5860265542456" y="-41.421465555826785"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="199.9375" x="32.49419417854676" y="5.93359375">Запит -&gt; маршрут та параметри<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n2::n1::n1">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="264.9258883570935" x="-816.5860265542456" y="18.578534444173215"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="228.267578125" x="18.329155116046763" y="5.93359375">Створення модуля, контролера та дії<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n2::n1::n2">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="264.9258883570935" x="-816.5860265542456" y="72.64934031168627"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="86.78125" x="89.07231917854676" y="5.93359375">Виконання дії<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
</graph>
</node>
<node id="n0::n2::n2">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="294.9258883570935" x="-831.5860265542456" y="149.20206960042316"/>
<y:Fill color="#99CC00" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="141.982421875" x="76.47173324104676" y="5.93359375">EVENT_AFTER_REQUEST<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n2::n3">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="294.92588835709347" x="-831.5860265542456" y="196.89641062418633"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="263.611328125" x="15.657280116046763" y="5.93359375">Відправка відповіді кінцевому користувачу<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
</graph>
</node>
<node id="n0::n3">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="324.9258883570935" x="-846.5860265542456" y="319.2728754679363"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="173.9921875" x="75.46685042854676" y="5.93359375">Завершення обробки запиту<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
</graph>
</node>
<edge id="e0" source="n0" target="n0::n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="-179.83580569315376" sy="-180.3944529152355" tx="-13.869777491410105" ty="-154.8008369539754"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e0" source="n0::n0" target="n0::n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:EdgeLabel alignment="center" backgroundColor="#99CCFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="120.455078125" x="-137.9645704847153" y="78.82421875000006">Масив конфігурації<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="77.04379339868619" distanceToCenter="true" position="right" ratio="0.5" segment="0"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::n1::e0" source="n0::n1::n0" target="n0::n1::n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::n1::e1" source="n0::n1::n1" target="n0::n1::n2">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::n1::e2" source="n0::n1::n2" target="n0::n1::n3">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::n1::e3" source="n0::n1::n3" target="n0::n1::n4">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e1" source="n0::n1" target="n0::n2">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="2.8060680342755404" sy="-48.37646484374994" tx="-162.49660512430125" ty="105.53540293375653"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::n2::e0" source="n0::n2::n0" target="n0::n2::n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::n2::n1::e0" source="n0::n2::n1::n0" target="n0::n2::n1::n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::n2::n1::e1" source="n0::n2::n1::n1" target="n0::n2::n1::n2">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::n2::e1" source="n0::n2::n1" target="n0::n2::n2">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::n2::e2" source="n0::n2::n2" target="n0::n2::n3">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e2" source="n0::n2" target="n0::n3">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:EdgeLabel alignment="center" backgroundColor="#99CCFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="64.90234375" x="-96.45114634054266" y="28.626707953545406">Exit status<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="63.99999999999999" distanceToCenter="true" position="right" ratio="0.47945569632951074" segment="-1"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
</graph>
<data key="d0">
<y:Resources/>
</data>
</graphml>

BIN
docs/guide-uk/images/application-lifecycle.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
docs/guide-uk/images/start-app-installed.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

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

@ -2,120 +2,149 @@
================
Ви можете встановити Yii двома шляхами: використовуючи [Composer](http://getcomposer.org/) або завантаживши архів.
Перший варіант бажаніший тому, що дозволить встановити всі нові [розширення](structure-extensions.md)
Перший варіант э бажанішим, тому що дозволить встановити всі нові [розширення](structure-extensions.md)
або оновити Yii однією командою.
> Примітка: На відміну від Yii 1, після стандартного встановлення Yii 2 ми отримуємо як фреймворк, так і шаблон додатка.
Встановлення за допомогою Composer <a name="installing-via-composer"></a>
----------------------------------
Якщо Composer все ще не встановлено, то це можна зробити за допомогою інструкції на [getcomposer.org](https://getcomposer.org/download/), або одним із перерахованих способів:
Якщо у вас все ще не вставновлено Composer, то це можна зробити за допомогою інструкції на [getcomposer.org](https://getcomposer.org/download/).
Користувачам Linux та Mac OS X потрібно виконати наступні команди:
* на Linux або Mac, використовуйте наступну команду:
curl -s http://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer
```
curl -s http://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer
```
* на Windows, завантажте і запустіть [Composer-Setup.exe](https://getcomposer.org/Composer-Setup.exe).
При роботі з Windows, необхідно завантажити та запустити [Composer-Setup.exe](https://getcomposer.org/Composer-Setup.exe).
В разі наявності проблем або якщо вам необхідна додаткова інформація, зверніться до [документації Composer](https://getcomposer.org/doc/) .
В разі наявності проблем або якщо вам необхідна додаткова інформація, зверніться до [документації Composer](https://getcomposer.org/doc/).
Після встановлення Composer встановити Yii можна виконавши наступну команду з директорії, яка доступна через Web:
Якщо ж Composer вже було встановлено раніше, переконайтесь, що використовуюєте його останню версію.
Ви можете оновити Composer простою командою `composer self-update`.
```
composer create-project --prefer-dist yiisoft/yii2-app-basic basic
```
Після встановлення Composer, встановити Yii можна виконавши наступну команду з директорії, яка доступна через Web:
Composer встановить Yii (базовий додаток basic) в директорію `basic`.
composer global require "fxp/composer-asset-plugin:1.0.0-beta4"
composer create-project --prefer-dist yiisoft/yii2-app-basic basic
> **Підказка**: Якщо хочете встановити останню нестабільну версію Yii, ви можете добавити ключ `stability`:
```
composer create-project --prefer-dist --stability=dev yiisoft/yii2-app-basic basic
```
Варто замітити, що нестабільну версію Yii неможна використовувати на робочому сервері.
Перша команда встановить [плагін ресурсів composer (composer-asset-plugin)](https://github.com/francoispluchino/composer-asset-plugin/),
що дозволить керувати залежностями пакетів Bower та NPM за допомогою Composer. Цю команду потрібно виконати лише один раз.
Друга команда встановить Yii у директорію під назвою `basic`. За бажанням, ви можете обрати іншу директорію.
> Примітка: Під час встановлення може статися так, що Composer запитає облікові дані від вашого профілю на Github,
> через встановлені обмеження запитів Github API. Це є нормальним, оскільки Composer повинен отримати багато інформації
> для всіх пакетів із Github. Надання облікових даних профіля Github збільшить кількість запитів до API, потрібних для
> подальшої роботи Composer. Для більш детальної інформації, будь ласка, зверніться до
> [документації Composer](https://getcomposer.org/doc/articles/troubleshooting.md#api-rate-limit-and-oauth-tokens).
> Підказка: Якщо ви хочете встановити останню нестабільну версію Yii, ви можете виконати наступну команду,
> яка додає опцію [stability](https://getcomposer.org/doc/04-schema.md#minimum-stability):
>
> composer create-project --prefer-dist --stability=dev yiisoft/yii2-app-basic basic
>
> Варто зауважити, що нестабільну версію Yii не можна використовувати на робочому сервері, оскільки вона може порушити
> виконання робочого коду.
Встановлення з архіву <a name="installing-from-archive-file"></a>
-------------------------------
---------------------
Встановлення Yii з архіву складається з двох кроків:
Встановлення Yii з архіву складається з трьох кроків:
1. Завантажте архів за адресою [yiiframework.com](http://www.yiiframework.com/download/yii2-basic);
1. Завантажте архів за адресою [yiiframework.com](http://www.yiiframework.com/download/);
2. Розпакуйте архів в директорію, доступну через Web.
3. Відредагуйте файл конфігурації `config/web.php` - необхідно заповнити секретний ключ до пункту `cookieValidationKey`
(це виконуєтся автоматично при вставленні Yii через Composer):
```php
// !!! встановити секретний ключ до наступного пункту (якщо порожній) - це необхідно для валідації кукі
'cookieValidationKey' => 'enter your secret key here',
```
Інші параметри встановлення <a name="other-installation-options"></a>
--------------------------
---------------------------
Вище наведені інструкції по встановленню Yii у вигляді базового додатку готового до роботи.
Вище наведені інструкції по встановленню Yii, які також створюють базовий веб-додаток, готового до роботи.
Це відмінний варіант для невеликих проектів або для тих, хто тільки розпочинає вивчати Yii.
Є два основних варіанта данного встановлення:
Але є ще й інші варіанти встановлення:
* Якщо вам потрібен тільки один фреймворк і ви хотіли б створити додаток з нуля, використовуйте інструкцію, яка описана у розділі «[Створення додатка з нуля](tutorial-start-from-scratch.md)».
* Якщо вам потрібен тільки один фреймворк і ви хотіли б створити додаток з нуля, використовуйте інструкцію,
що описана у розділі [Створення додатка з нуля](tutorial-start-from-scratch.md).
* Якщо хочете розпочати з більш насиченого додатка, який добре підходить для роботи в команді, використовуйте
[шаблон додатка advanced](tutorial-advanced-app.md).
[разширений шаблон додатка](tutorial-advanced-app.md).
Перевірка встановлення <a name="verifying-installation"></a>
----------------------
Якщо ви встановили додаток в теку `basic` базової директорії вашого веб сервера і ім’я сервера `hostname`,
запустити додаток можна відкривши наступний URL через браузер:
Після встановлення, ви можете перевірити за допомогою браузера свій встановлений додаток Yii за наступним URL:
```
http://hostname/basic/web/index.php
http://localhost/basic/web/index.php
```
![Успішно встановленний Yii](../guide/images/start-app-installed.png)
Даний URL передбачає встановлення додатка в директорію `basic` базової директорії вашого локального веб-сервера (`localhost`).
Можливо вам знадобиться підкорегувати налаштування свого сервера.
![Успішно встановленний Yii](images/start-app-installed.png)
Ви повинні побачити сторінку привітання «Congratulations!». Якщо ні — провірте вимоги Yii одним із способів:
Ви повинні побачити сторінку браузера із привітанням "Congratulations!". Якщо ні — провірте, чи задовільняють
налаштування PHP вимогам Yii одним із способів:
* Браузером перейдіть на адресу `http://hostname/basic/requirements.php`
* Або виконайте команду в консолі:
* Браузером перейдіть на URL `http://localhost/basic/requirements.php`
* Або виконайте наступні команди в консолі:
```
cd basic
php requirements.php
```
Для коректної роботи фреймворка вам необхідно мати PHP, який відповідає його мінімальним вимогам. Основна вимога — PHP версії 5.4 и вище. Якщо ваш додаток працює з базою даних, необхідно встановити
[розширення PHP PDO](http://www.php.net/manual/ru/pdo.installation.php) і відповідний драйвер
Для коректної роботи фреймворка вам необхідно мати PHP, який відповідає його мінімальним вимогам.
Основна вимога — PHP версії 5.4 або вище. Якщо ваш додаток працює з базою даних, необхідно встановити
[розширення PHP PDO](http://www.php.net/manual/en/pdo.installation.php) та відповідний драйвер
(наприклад, `pdo_mysql` для MySQL).
Налаштування веб сервера <a name="configuring-web-servers"></a>
-----------------------
Налаштування веб серверів <a name="configuring-web-servers"></a>
-------------------------
> Інформація: можете пропустити даний підрозділ, якщо ви тільки розпочали знайомитися з фреймворком і не розгортаєте його на робочому сервері.
> Інформація: можете пропустити даний підрозділ, якщо ви тільки розпочали знайомитися з фреймворком
і не розгортаєте його на робочому сервері.
Додаток, встановлений за інструкціями, наведеними вище, буде працювати зразу як з [Apache](http://httpd.apache.org/),
так і з [Nginx](http://nginx.org/) під Windows і Linux.
Додаток, встановлений за інструкціями, наведеними вище, буде працювати одразу як з [Apache HTTP server](http://httpd.apache.org/),
так і з [Nginx HTTP server](http://nginx.org/) під Windows, Mac OS X чи Linux із встановленим PHP 5.4 або вище.
Yii 2.0 також сумісний із віртуальною машиною [HHVM](http://hhvm.com/) фейсбука, однак є деякі крайні випадки,
де HHVM поводиться інакше, ніж рідний PHP, тому ви повинні бути дуже уважними при використанні HHVM.
На рабочому сервері вам напевно захочеться змінити URL додатку з `http://hostname/basic/web/index.php`
на `http://hostname/index.php`. Для цього необхідно змінити кореневу директорію в налаштуваннях веб сервера так, щоб ті
вказували на `basic/web`. Додатково можно сховати `index.php` відповідно описанню в розділі «[Розбір і генерація URL](runtime-url-handling.md)».
Далі буде показано як налаштувати Apache і Nginx.
На рабочому сервері вам напевно захочеться змінити URL додатку з `http://www.example.com/basic/web/index.php`
на `http://www.example.com/index.php`. Для цього необхідно змінити кореневу директорію в налаштуваннях веб сервера на `basic/web`.
Додатково можно сховати `index.php` із URL, як це описано у розділі [Маршрутизація та створення URL](runtime-routing.md).
Далі буде показано як налаштувати Apache і Nginx для цих цілей.
> Інформація: Встанновлюючи `basic/web` кореневою директорією веб сервера ви захищаете від небажаного доступа код і дані, які знаходяться на одному рівні з `basic/web`. Це робить додаток більш захищенним.
> Інформація: Встанновлюючи `basic/web` кореневою директорією веб-сервера, ви забороняєте кінцевим користувачам доступ
до приватного коду додатка та важливим даним, які знаходяться на одному рівні з `basic/web`. Це робить додаток більш захищенним.
> Інформація: Якщо додаток працює на хостингу, де немає доступу до налаштувань сервера, то можна змінити структуру додатка, як описано в розділі «[Робота на Shared хостингу](tutorial-shared-hosting.md)».
> Інформація: Якщо додаток працює на хостингу, де немає доступу до налаштувань сервера, ви всеодно можете змінити структуру
додатка для покращення безпеки, як описано в розділі [Робота на shared хостингу](tutorial-shared-hosting.md).
### Рекомендовані налаштування Apache <a name="recommended-apache-configuration"></a>
Добавте наступне в `httpd.conf` Apache або в конфігураційний файл віртуального хоста. Не забудьте замінити
`path/to/basic/web` на коректний шлях до `basic/web`.
Додайте наступний код до файлу конфігурации Apache `httpd.conf` або в конфігураційний файл віртуального хоста.
Не забудьте замінити `path/to/basic/web` на коректний шлях до `basic/web`.
```
# Встановлюємо кореневою директорією "basic/web"
DocumentRoot "path/to/basic/web"
<Directory "path/to/basic/web">
# використаємо mod_rewrite для підтримки гарних URL
RewriteEngine on
# Якщо запитувана в URL директорія або файл відсутні звертаємось до них напряму
# Якщо запитуваний файл або директорія існують - звертаємось до них напряму
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Якщо ні - перенаправляємо запит на index.php
@ -128,8 +157,9 @@ DocumentRoot "path/to/basic/web"
### Рекомендовані налаштування Nginx <a name="recommended-nginx-configuration"></a>
PHP повинен бути встановлений як [FPM SAPI](http://php.net/manual/ru/install.fpm.php) для [Nginx](http://wiki.nginx.org/).
Використовуйте наступні параметри Nginx і не забудьте замінити `path/to/basic/web` на коректний шлях до `basic/web`.
Для використання [Nginx](http://wiki.nginx.org/) вам потрібно встановити PHP як [FPM SAPI](http://php.net/install.fpm).
Використовуйте наступні параметри Nginx, замінивши `path/to/basic/web` на коректний шлях до `basic/web`,
а `mysite.local` на бажаний домен.
```
server {
@ -137,21 +167,21 @@ server {
client_max_body_size 128M;
listen 80; ## listen for ipv4
#listen [::]:80 default_server ipv6only=on; ## слухаєм ipv6
#listen [::]:80 default_server ipv6only=on; ## слухаємо ipv6
server_name mysite.local;
root /path/to/basic/web;
index index.php;
access_log /path/to/project/log/access.log main;
error_log /path/to/project/log/error.log;
access_log /path/to/basic/log/access.log main;
error_log /path/to/basic/log/error.log;
location / {
# Перенаправляємо всі запити до неіснуючих директорій або файлів на index.php
# Перенаправляємо всі запити від неіснуючих директорій або файлів на index.php
try_files $uri $uri/ /index.php?$args;
}
# розкоментуйте строки нище для запобігання обробки Yii звернень до неіснуючих статичних файлів
# розкоментуйте строки нижче для запобігання обробки звернень Yii до неіснуючих статичних файлів
#location ~ \.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar)$ {
# try_files $uri =404;
#}
@ -161,6 +191,7 @@ server {
include fastcgi.conf;
fastcgi_pass 127.0.0.1:9000;
#fastcgi_pass unix:/var/run/php5-fpm.sock;
try_files $uri =404;
}
location ~ /\.(ht|svn|git) {
@ -169,7 +200,7 @@ server {
}
```
Використовуючи дану конфігурацію встановіть `cgi.fix_pathinfo=0` в `php.ini` щоб запобігти зайвим системним визовам `stat()`.
Використовуючи дану конфігурацію встановіть `cgi.fix_pathinfo=0` в `php.ini`, щоб запобігти зайвим системним викликам `stat()`.
Врахуйте також, що при використанні HTTPS необхідно задавати `fastcgi_param HTTPS on;` щоб Yii міг корректно оприділяти захищене
з’єднання.
Врахуйте також, що при використанні HTTPS необхідно задавати `fastcgi_param HTTPS on;` щоб Yii міг корректно
визначати захищене з’єднання.

110
docs/guide-uk/structure-application-components.md

@ -1,30 +1,35 @@
Компоненти додатка
=====================
==================
Додатки є [сервіс локаторами](concept-service-locators.md). Вони зберігають багато так званих
*компонентів додатку*, які надають різноманітні інструменти для опрацювання запитів. Наприклад,
компоненти `urlManager` відповідає за маршрутизацію веб запитів до потрібного контролера; компонент `db` надає інструменти для работи з базою даних; і т. д.
*компонентів додатку*, які надають різноманітні інструменти для обробки запитів. Наприклад,
компонент `urlManager` відповідає за маршрутизацію веб запитів до потрібного контролера;
компонент `db` надає інструменти для работи з базою даних; і т. д.
Кожний компонент додатка має свій унікальний ID, який дозволяє ідентифікувати його серед інших різноманітних компонентів
в одному і тому ж додатку. Ви можете отримати доступ до компонента наступним чином:
```php
\Yii::$app->ComponentID
\Yii::$app->componentID
```
Наприклад, ви можете використовувати `\Yii::$app->db` для отримання [[yii\db\Connection|з’єднання з БД]],
і `\Yii::$app->cache` для отримання доступу до основного компонента [[yii\caching\Cache|кеша]], зареєстрованого в додатку.
Компонентами додатку можуть бути любі об’єкти. Ви можете зареєструвати їх з допомогою властивості [[yii\base\Application::components]] в [конфігурації](structure-applications.md#application-configurations) додатка.
Компонент додатка створюється при першому звертанні через попередній вираз.
Будь-які подальші звертання будуть повертати той же примірник компонента.
Компонентами додатку можуть бути будь-які об’єкти. Ви можете зареєструвати їх за допомогою властивості
[[yii\base\Application::components]] в [конфігурації](structure-applications.md#application-configurations) додатка.
Наприклад,
```php
[
'components' => [
// реєстрація "cache" компонента з допомогою назви класу
// реєстрація "cache" компонента за допомогою назви класу
'cache' => 'yii\caching\ApcCache',
// реєстрація "db" компонента з допомогою масива конфігурації
// реєстрація "db" компонента за допомогою масива конфігурації
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=demo',
@ -32,7 +37,7 @@
'password' => '',
],
// реєстрація "search" компонента з допомогою анонімної функції
// реєстрація "search" компонента за допомогою анонімної функції
'search' => function () {
return new app\components\SolrService;
},
@ -41,47 +46,74 @@
```
> Інформація: Хоча ви можете зареєструвати стільки компонентів в додатку скільки вам потрібно,
все ж таки варто робити це осмислено. Компоненти додатку схожі на глобальні змінні. Використання дуже великої кількості компонетів додатку може потенційно зробити ваш код складним для розробки і тестування.
В більшості випадків ви можете просто створити локальний компонент і використовувати його при необхідності.
все ж таки варто робити це осмислено. Компоненти додатку схожі на глобальні змінні.
Використання дуже великої кількості компонетів додатку може потенційно зробити ваш код складним для розробки і тестування.
У більшості випадків ви можете просто створити локальний компонент і використовувати його при необхідності.
## Попереднє завантаження компонентів <a name="bootstrapping-components"></a>
Як згадувалося вище, компонент додатка буде створено при першому звертанні.
Якщо до нього не буде зроблено звертань під час запиту - його взагалі не буде створено.
Однак іноді, ви можете створити екземпляр компонента додатка для кожного запиту, навіть якщо до нього не зверталися явно.
Щоб зробити це, ви можете додати ідентифікатор до властивості [[yii\base\Application::bootstrap|bootstrap]] додатка.
Наприклад, наступна конфігурація додатка завжди гарантує створення компонента `log`:
```php
[
'bootstrap' => [
'log',
],
'components' => [
'log' => [
// конфігурація для компонента "log"
],
],
]
```
## Вбудовані компоненти додатку <a name="core-application-components"></a>
В Yii є декілька *вбудованих* компонентів додатку, з фіксованими ID і конфігураціями за замовчуванням. Наприклад,
компонент [[yii\web\Application::request|request]] використовується для отримання інформації про запит користувача і розбору його в
певний [маршрут](runtime-routing.md); компонент [[yii\base\Application::db|db]] являє собою з’єднання з базою даних,
через яке ви можете виконувати запити. Саме з допомогою цих вбудованих компонентів Yii додатки можуть обрабляти
запит користувача.
В Yii є декілька *вбудованих* компонентів додатку із фіксованими ID та конфігураціями за замовчуванням.
Наприклад, компонент [[yii\web\Application::request|request]] використовується для збору інформації про запит
користувача і розбору його у певний [маршрут](runtime-routing.md); компонент [[yii\base\Application::db|db]]
являє собою з’єднання з базою даних, через яке ви можете виконувати запити.
Саме з допомогою цих вбудованих компонентів Yii додатки можуть обрабляти запит користувача.
Нижче наведений перелік вбудованих компонентів додатку. Ви можете конфігурувати їх так само як і інші компоненти додатку.
Коли ви конфігуруєте вбудований компонент додатку і не вказуєте клас цього компонента, то буде використовуватись значення за замовчуванням.
Нижче наведено перелік вбудованих компонентів додатку. Ви можете конфігурувати їх так само, як і інші компоненти додатку.
Коли ви конфігуруєте вбудований компонент додатку і не вказуєте клас цього компонента, то буде використовуватись
значення за замовчуванням.
* [[yii\web\AssetManager|assetManager]]: використовується для керування і відображенням ресурсів додатку.
Більш детальна інформація представлена в розділі [Ресурси](output-assets.md);
Більш детальна інформація наведена у розділі [Ресурси](output-assets.md).
* [[yii\db\Connection|db]]: являє собою з’єднання з базою даних, через яке ви можете виконувати запити.
Зверніть увагу, що коли конфігуруєте даний компонент, ви маєте вказати клас компонента так як і решту необхідних параметрів, а саме такі як [[yii\db\Connection::dsn]].
Більш детальна інформація представлена в розділі [Об’єкти доступу до даних (DAO)](db-dao.md);
* [[yii\base\Application::errorHandler|errorHandler]]: здійснює опрацювання PHP помилок і виключень.
Більш детальна інформація представлена в розділі [Обробка помилок](runtime-handling-errors.md);
* [[yii\base\Formatter|formatter]]: форматує дані для відображення їх кінцевому користувачу. Наприклад, число може
бути зображене з різноманітними розділителями, дата може бути зображена в форматі `long`.
Більш детальна інформація представлена в розділі [Форматування даних](output-formatting.md);
Зверніть увагу, що, коли конфігуруєте даний компонент, ви маєте вказати клас компонента, разом із рештою
необхідних параметрів, наприклад [[yii\db\Connection::dsn]].
Більш детальна інформація наведена у розділі [Об’єкти доступу до даних (DAO)](db-dao.md).
* [[yii\base\Application::errorHandler|errorHandler]]: здійснює обработку PHP помилок і виключень.
Більш детальна інформація наведена у розділі [Обробка помилок](runtime-handling-errors.md).
* [[yii\i18n\Formatter|formatter]]: форматує дані для відображення їх кінцевому користувачу. Наприклад, число може
бути відображене із різноманітними роздільниками, дата може бути зображена у розширеному форматі.
Більш детальна інформація наведена у розділі [Форматування даних](output-formatter.md).
* [[yii\i18n\I18N|i18n]]: використовується для перекладу повідомлень і форматування.
Більш детальна інформація представлена в розділі [Інтернаціоналізація](tutorial-i18n.md);
Більш детальна інформація наведена у розділі [Інтернаціоналізація](tutorial-i18n.md).
* [[yii\log\Dispatcher|log]]: обробка і маршрутизація логів.
Більш детальна інформація представлена в розділі [Логування](runtime-logging.md);
* [[yii\swiftmailer\Mailer|mail]]: надає можливості для побудови і розсилки поштових повідомлень.
Більш детальна інформація представлена в розділі [Відправлення пошти](tutorial-mailing.md);
* [[yii\base\Application::response|response]]: являє собою дані від серверу, які будуть направлені користувачу.
Більш детальна інформація представлена в розділі [Відповіді](runtime-responses.md);
* [[yii\base\Application::request|request]]: являє собою запит, отриманий від кінцевого користувача.
Більш детальна інформація представлена в розділі [Запити](runtime-requests.md);
* [[yii\web\Session|session]]: інформація про сесії. Даний компонент доступний тільки в [[yii\web\Application|веб додатках]].
Більш детальна інформація представлена в розділі [Сесії і куки](runtime-sessions-cookies.md);
Більш детальна інформація наведена у розділі [Логування](runtime-logging.md).
* [[yii\swiftmailer\Mailer|mail]]: надає можливості для побудови і відправки поштових повідомлень.
Більш детальна інформація наведена у розділі [Відправлення пошти](tutorial-mailing.md).
* [[yii\base\Application::response|response]]: являє собою об’єкт відповіді сервера кінцевим користувачам.
Більш детальна інформація наведена у розділі [Відповіді](runtime-responses.md).
* [[yii\base\Application::request|request]]: являє собою об’єкт запиту, який сервер отримує від кінцевих користувачів.
Більш детальна інформація наведена у розділі [Запити](runtime-requests.md).
* [[yii\web\Session|session]]: надає інформація про сесії.
Даний компонент доступний тільки у [[yii\web\Application|веб додатках]].
Більш детальна інформація наведена у розділі [Сесії і куки](runtime-sessions-cookies.md).
* [[yii\web\UrlManager|urlManager]]: використовується для розбору і побудови URL.
Більш детальна інформація представлена в розділі [Розбір і генерація URL](runtime-url-handling.md);
Більш детальна інформація наведена у розділі [Маршрутизація та створення URL](runtime-routing.md).
* [[yii\web\User|user]]: являє собою інформацію авторизованого користувача.
Даний компонент доступний тільки в [[yii\web\Application|веб додатках]].
Більш детальна інформація представлена в розділі [Аутентифікація](security-authentication.md);
Даний компонент доступний тільки у [[yii\web\Application|веб додатках]].
Більш детальна інформація наведена у розділі [Аутентифікація](security-authentication.md).
* [[yii\web\View|view]]: використовується для відображення представлень.
Більш детальна інформація представлена в розділі [Представлення](structure-views.md).
Більш детальна інформація наведена у розділі [Представлення](structure-views.md).

364
docs/guide-uk/structure-applications.md

@ -1,20 +1,21 @@
Додатки
==========
=======
Додатки це об’єкти, які керують всією структурою і життєвим циклом прикладної системи Yii.
Кожна Yii прикладна система містить у собі один об’єкт додатка, який створбється у [вхідному скрипті](structure-entry-scripts.md)
і глобально доступний через `\Yii::$app`.
Кожна Yii прикладна система містить у собі один об’єкт додатка, який створюється у
[вхідному скрипті](structure-entry-scripts.md) і глобально доступний через `\Yii::$app`.
> Інформація: В залежності від контексту, коли ми говорим "додаток", це може означати як об’єкт додатка, так і прикладну систему додатка вцілому.
> Інформація: В залежності від контексту, коли ми говорим "додаток", це може означати як об’єкт додатка,
так і прикладну систему додатка вцілому.
Існує два вида додатків: [[yii\web\Application|веб додатки]] і [[yii\console\Application|консольні додатки]].
Як можна здогадатись із назви, перший тип в основному займається обробкою веб запитів, в той час як останній - консольних команд.
Існує два типи додатків: [[yii\web\Application|веб додатки]] та [[yii\console\Application|консольні додатки]].
Як можна здогадатися із назв, перший тип, в основному, займається обробкою веб запитів, а другий - консольними командами.
## Конфігурації додатка <a name="application-configurations"></a>
Коли [вхідний скрипт](structure-entry-scripts.md) створює додаток, він завантажить [конфігурацію](concept-configurations.md)
і примінить її до додатка, наприклад:
Коли [вхідний скрипт](structure-entry-scripts.md) створює додаток, він завантажить
[конфігурацію](concept-configurations.md) та застосує її до додатка, наприклад:
```php
require(__DIR__ . '/../vendor/autoload.php');
@ -27,45 +28,57 @@ $config = require(__DIR__ . '/../config/web.php');
(new yii\web\Application($config))->run();
```
Так як і звичайні [конфігурації](concept-configurations.md), конфігурації додатка вказують як слід ініціювати властивості об’єктів додатка. Через те, що конфігурації додатків часто є складними, вони розбиваються на декілька
[конфігураційних файлів](concept-configurations.md#configuration-files), наприклад, `web.php` файл в наведеному вище прикладі.
Як і звичайні [конфігурації](concept-configurations.md), конфігурації додатка вказують як саме слід ініціювати
властивості об’єктів додатка. Через те, що конфігурації додатків часто є складними, вони розбиваються на декілька
[конфігураційних файлів](concept-configurations.md#configuration-files), наприклад, файл `web.php` у наведеному вище прикладі.
## Властивості додатків <a name="application-properties"></a>
## Властивості додатка <a name="application-properties"></a>
Існує багато важливих властивостей додатка, які ви налаштовуєте в конфігураціях додатка. Ці властивості зазвичай описують середовище, в якому працює додаток. Наприклад, додаток мусить знати яким чином завантажувати [контролери](structure-controllers.md), де зберігати тимчасові файли, і т.п. Нижче ми розглянемо дані властивості.
Існує багато важливих властивостей додатка, які ви налаштовуєте в конфігураціях додатка.
Ці властивості, зазвичай, описують середовище, у якому працює додаток. Наприклад,
додаток мусить знати яким чином завантажувати [контролери](structure-controllers.md),
де зберігати тимчасові файли, і т.п. Нижче ми розглянемо дані властивості.
### Об’язкові властивості <a name="required-properties"></a>
В кодному додатку, ви маєте налаштувати мінімум дві властивості: [[yii\base\Application::id|id]]
і [[yii\base\Application::basePath|basePath]].
В кожному додатку, ви маєте налаштувати мінімум дві властивості: [[yii\base\Application::id|id]]
та [[yii\base\Application::basePath|basePath]].
#### [[yii\base\Application::id|id]] <a name="id"></a>
Властивість [[yii\base\Application::id|id]] це унікальний індекс додатка, який відрізняє його від решти інших додатків.
В основному це використовується всередені системи. Хоч і не є обов’язковим, але для кращої сумістності рекомендується використовувати буквено-цифрові символи при налаштуванні індекса додатка.
Властивість [[yii\base\Application::id|id]] є унікальним ID додатка, який відрізняє його від решти інших додатків.
Здебільшого, це використовується всередені системи. Хоч і не є обов’язковим, але для кращої сумістності рекомендується
використовувати буквено-цифрові символи при налаштуванні ID додатка.
#### [[yii\base\Application::basePath|basePath]] <a name="basePath"></a>
Властивість [[yii\base\Application::basePath|basePath]] вказує на кореневу директорію додатка. Ця директорія, яка містить весь код прикладної системи додатка. В цій директорії зазвичай можуть знаходитись теки `models`, `views`, `controllers`, які містять код, що відповідає шаблону проектування MVC.
Властивість [[yii\base\Application::basePath|basePath]] вказує на кореневу директорію додатка. Ця директорія,
яка містить весь код прикладної системи додатка. В цій директорії, зазвичай, можуть знаходитись підкаталоги `models`,
`views`, `controllers`, які містять код, що відповідає шаблону проектування MVC.
Ви можете налаштувати властивість [[yii\base\Application::basePath|basePath]] вказавши прямий шлях до директорії через [псевдоніми шляху](concept-aliases.md). В обох випадках, вказана директорія має існувати, інакше буде отримано виняток. Шлях буде нормалізований за допомогою виклику функції `realpath()`.
Ви можете налаштувати властивість [[yii\base\Application::basePath|basePath]], вказавши прямий шлях до директорії
через [псевдонім шляху](concept-aliases.md). В обох випадках, вказана директорія має існувати, інакше буде отримано
виняток. Шлях буде нормалізовано за допомогою виклику функції `realpath()`.
Властивість [[yii\base\Application::basePath|basePath]] часто використовується для важливих шляхів, наприклад, шлях до runtime директорії, котра використовується в процесі робити додатка. Саме по цій причині, псевдонім шляху `@app` є зумовленим і вказує на дану директорію. Інші шляхи можуть бути визначеними шляхом використання псевдоніму шляху, наприклад,
`@app/runtime`.
Властивість [[yii\base\Application::basePath|basePath]] часто використовується для важливих шляхів (наприклад, шлях до
runtime директорії). Саме з цієї причини, псевдонім шляху `@app` є зумовлений вказувати на дану директорію.
Похідні шляхи потім можуть бути сформовані за допомогою цього псевдоніму шляху (наприклад, `@app/runtime` для
звертання до runtime директорії).
### Важливі властивості <a name="important-properties"></a>
Властивості, перелічені в даному підрозділі, частіш за все повинні бути налаштовані так як вони можуть відрізнятися в різних додатках.
Властивості, перелічені в даному підрозділі, частіш за все повинні бути визначені, тому що вони можуть
відрізнятися у різних додатках.
#### [[yii\base\Application::aliases|aliases]] <a name="aliases"></a>
Дана властивість дозволяє налаштувати вам безліч [псевдонімів](concept-aliases.md) в рамках масива.
Дана властивість дозволяє налаштувати вам безліч [псевдонімів](concept-aliases.md) у рамках масиву.
Ключами масива є імена псевдонімів, а значеннами - відповідні значення шляхів. Наприклад,
```php
@ -77,20 +90,24 @@ $config = require(__DIR__ . '/../config/web.php');
]
```
Ця властивість доступна таким чином, аби ви змогли вказувати псевдоніми в рамках конфігурації додатка, а не викликаючи метод [[Yii::setAlias()]].
Ця властивість доступна таким чином, аби ви змогли вказувати псевдоніми в рамках конфігурації додатка,
а не викликаючи метод [[Yii::setAlias()]].
#### [[yii\base\Application::bootstrap|bootstrap]] <a name="bootstrap"></a>
Дана властивість є дуже зручною, вона дозволяє вказувати масив компонентів, котрі мусять бути завантажені
у процесі [[yii\base\Application::bootstrap()|початкового завантаження]] додатка. Наприклад, якщо ви хочете,
щоб [модуль](structure-modules.md) виконував тонке налаштування [URL правил](runtime-routing.md),
ви можете вказати його ID в якості елемента даної властивості.
Дана властивість є дуже зручною, вона дозволяє вказувати масив компонентів, котрі мусять бути завантажені в процесі [[yii\base\Application::bootstrap()|початкового завантаження]] додатка. Наприклад, якщо ви хочете, щоб [модуль](structure-modules.md) виконував тонке налаштування [URL правил](runtime-url-handling.md), ви можете вказати його ID в якості елемента даної властивості.
Кожен із елементів даної властивості може вказуватись в одному із наступних форматів:
Кожний з елементів даної властивості може вказуватись в одному з наступних форматів:
- ID, вказаний в [компонентах](#components);
- ID модуля, вказаний в [модулях](#modules);
- назва класа;
- ID компонента додатка, що вказаний у [компонентах](#components).
- ID модуля, що вказаний у [модулях](#modules).
- назва класа.
- масив конфігурації.
- анонімна функциія, яка створює та повертає об’єкт компонента.
Наприклад,
@ -101,20 +118,39 @@ $config = require(__DIR__ . '/../config/web.php');
'demo',
// назва класа
'app\components\TrafficMonitor',
'app\components\Profiler',
// масив конфігурації
[
'class' => 'app\components\Profiler',
'level' => 3,
]
],
// анонімна функція
function () {
return new app\components\Profiler();
}
],
]
```
В процесі початкового завантаження, буде створено кожний компонент. Якщо клас компонента містить інтерфейс [[yii\base\BootstrapInterface]], то також буде викликаний метод [[yii\base\BootstrapInterface::bootstrap()|bootstrap()]].
> Інформація: Якщо ID модуля співпадає з ID компонента додатка, перевага буде віддана ініціалізації компонента додатка
під час початкового завантаження. Якщо ж ви хочете використати модуль, вам потрібно використати анонімну функцію,
як показано нижче:
> ```php
[
function () {
return Yii::$app->getModule('user');
},
]
```
Ще одним практичним прикладом є конфігурація [базового шаблону додатка](start-installation.md), в якій модулі `debug` і `gii` вказані як `bootstrap` компоненти, коли додаток знаходиться у відлагоджувальному режимі.
Під час початкового завантаження, буде створено кожний компонент. Якщо клас компонента реалізує інтерфейс
[[yii\base\BootstrapInterface]], то буде викликаний його метод [[yii\base\BootstrapInterface::bootstrap()|bootstrap()]].
Ще одним практичним прикладом є конфігурація [базового шаблону додатка](start-installation.md), у якій модулі
`debug` і `gii` визначені як компоненти початкового завантаження, коли додаток знаходиться режимі розробки.
```php
if (YII_ENV_DEV) {
@ -127,14 +163,19 @@ if (YII_ENV_DEV) {
}
```
> Примітка: Якщо вказувати велику кількість компонентів у `bootstrap`, то це приведе до зниження продуктивності додатка, тому що для кожного запиту буде завантажуватись однакова кількість компонентів. Таким чином ви мусите розумно використовувати початкове завантаження.
> Примітка: Якщо вказувати велику кількість компонентів у `bootstrap` - це негативно позначиться на продуктивності
додатка, оскільки для кожного запиту буде виконуватись один й той самий набір компонентів. Таким чином, потрібно
розсудливо використовувати компоненти початкового завантаження.
#### [[yii\web\Application::catchAll|catchAll]] <a name="catchAll"></a>
Дана властивість підтримується тільки [[yii\web\Application|веб додатками]].Вона вказує на [події контролера](structure-controllers.md), які мусять опрацьовувати всі вхідні запити від користувача. В основному це використовується коли додаток знаходиться в режимі обслуговування і мусить опрацьовувати всі запити через одну подію.
Дана властивість підтримується тільки [[yii\web\Application|веб додатками]]. Вона вказує на
[дії контролера](structure-controllers.md), які мусять обробляти всі вхідні запити від користувача. Переважно,
це використовується, коли додаток знаходиться в режимі обслуговування і повинен обробити всі запити через одну дію.
Конфігурація це масив, перший елемент якого вказує на маршрут події. Решта елементів в форматі ключ-значення вказують на додаткові параметри, які мають бути передані події. Наприклад,
Конфігурація є масивом, перший елемент якого вказує на маршрут події. Решта елементів масиву у форматі ключ-значення
вказують на додаткові параметри, які мають бути передані події. Наприклад,
```php
[
@ -149,7 +190,8 @@ if (YII_ENV_DEV) {
#### [[yii\base\Application::components|components]] <a name="components"></a>
Дана властивість є найважливішою. Вона дозволяє вам вказати перелік компонентів під назвою [компоненти додатку](#structure-application-components.md), які ви можете використовувати в інших місцях. Наприклад,
Дана властивість є найважливішою. Вона дозволяє вам зареєструвати іменні компоненти у
[компонентах додатку](structure-application-components.md), які ви можете використовувати в інших місцях. Наприклад,
```php
[
@ -165,17 +207,22 @@ if (YII_ENV_DEV) {
]
```
Кожний компонент додатка вказаний масивом в форматі ключ-значення. Ключ являє собою ID компонента додатка, в той час як значення являє собою назву класа або [конфігурацію](concept-configurations.md).
Кожен компонент додатка вказаний масивом у форматі ключ-значення. Ключ являє собою ID компонента додатка,
у той час як значення являє собою назву класа або [конфігурацію](concept-configurations.md).
Ви можете зареєструвати будь-який компонент в додатку, пізніше цей компонент буде доступний глобально через вираз `\Yii::$app->ComponentID`.
Ви можете зареєструвати будь-який компонент у додатку, який потім буде доступний глобально
за допомогою виразу `\Yii::$app->componentID`.
Більш детальна інформація наведена в розділі [Компоненти додатка](structure-application-components.md).
#### [[yii\base\Application::controllerMap|controllerMap]] <a name="controllerMap"></a>
Дана властивість дозволяє вам встановлювати залежності між ID контролера і його класом. За замовчуванням, Yii встановлює відповідність між ID контролера і його класом згідно даної [домовленості](#controllerNamespace) (таким чином,
ID `post` буде відповідати `app\controllers\PostController` ). За допомогою налаштування даної властивості ви можете змінити домовленість для потрібних контролерів. В наведеному прикладі, `account` буде відповідати `app\controllers\UserController`, в той час як `article` буде відповідати `app\controllers\PostController`.
Дана властивість дозволяє вам встановлювати відповідність між ID контролера та його класом. За замовчуванням,
Yii встановлює відповідність між ID контролера та його класом згідно [домовленості](#controllerNamespace)
(таким чином, ID `post` буде відповідати `app\controllers\PostController`). За допомогою налаштування даної властивості
ви можете змінити домовленість для необхідних контролерів. У наведеному прикладі, `account` буде
відповідати `app\controllers\UserController`, в той час, як `article` буде відповідати `app\controllers\PostController`.
```php
[
@ -191,49 +238,59 @@ ID `post` буде відповідати `app\controllers\PostController` ). З
]
```
Ключами даної властивості є ID контролерів, а значеннями є назва класа контролера або [конфігурація](concept-configurations.md).
Ключами масиву даної властивості є ID контролерів, а значеннями є назви класів контролерів або
[конфігурації](concept-configurations.md).
#### [[yii\base\Application::controllerNamespace|controllerNamespace]] <a name="controllerNamespace"></a>
Дана властивість вказує на простір імен, де за замовчуванням мусять міститись назви класів контролерів.
За замовчуванням значення рівне `app\controllers`. Якщо ID контролера `post`, то згідно домовленості, відповідний клас контролера (без простору імен) буде рівним `PostController`, а повна назва класа буде `app\controllers\PostController`.
Дана властивість вказує на простір імен за замовчуванням, під яким повинні знаходитись класи контролерів.
За замовчуванням, це значення рівне `app\controllers`. Якщо ID контролера є `post`, то, згідно домовленості,
відповідна назва класу контролера (без простору імен) буде `PostController`, а повна назва класу буде
`app\controllers\PostController`.
Клас контролера також може знаходитись в підпапці теки, що відповідає цьому простору імен. Наприклад, даному ID контролера `admin/post`, відповідає повне ім’я класа контролера `app\controllers\admin\PostController`.
Класи контролерів можуть також знаходитись у підкаталогах директорії, що відповідає її простору імені.
Наприклад, ID контролера `admin/post` відповідає повне ім’я класа контролера `app\controllers\admin\PostController`.
Дуже важливо, щоб ім’я класа контролера могло бути використане [автозавантаженням](concept-autoloading.md) і відповідний простір імен вашого контролера відповідав даній властивості. Інакше, ви отримаєте помилку "Сторінка не знайдена", коли спробуєте отримати доступ до додатка.
Дуже важливо, щоб повне ім’я класа контролера могло бути використане [автозавантаженням](concept-autoloading.md)
і фактичний простір імен вашого контролера відповідав цій властивості. В іншому випадку, ви отримаєте помилку
із заголовком "Сторінка не знайдена", коли спробуєте отримати доступ до додатка.
У випадку, якщо ви хочете змінити домовленість яку розглянуто вище, ви можете використовувати властивість [controllerMap](#controllerMap).
У випадку, якщо ви хочете змінити домовленість, яку розглянуто вище, ви можете використовувати властивість
[controllerMap](#controllerMap).
#### [[yii\base\Application::language|language]] <a name="language"></a>
Дана властивість вказує на мову додатка, на якій вміст сторінки мусить бути зображений кінцевому користувачу.
За замовчуванням, значення даної властивості рівне `en`, що значить "Англійський". Якщо ваш додаток підтримує декілька мов, ви мусите налаштувати дану властивість.
Дана властивість вказує на мову додатка, на якій додаток повинен відображати зміст кінцевому користувачу.
За замовчуванням, значення даної властивості рівне `en`, означаючи англійську мову.
Якщо ваш додаток підтримує декілька мов, ви необхідно налаштувати дану властивість.
Значення даної властивості визначається декількома різними аспектами [інтернаціоналізації](tutorial-i18n.md), в тому числі
перекладом повідомлень, форматуванням дат, форматуванням чисел, і т. п. Наприклад, віджет [[yii\jui\DatePicker]] використовує дану властивість для визначення мови за замовчуванням, на якій має бути зображений календар і формат даних для календаря.
Значення даної властивості визначає кілька різних аспектів [інтернаціоналізації](tutorial-i18n.md), в тому числі
переклади повідомлень, форматування дат, форматування чисел, і т. п. Наприклад, віджет [[yii\jui\DatePicker]]
використовує дану властивість для визначення мови за замовчуванням, на якій має бути зображений календар і
формат даних для календаря.
Рекомендується, щоб ви вказували мову в рамках стандатра [IETF](http://en.wikipedia.org/wiki/IETF_language_tag).
Рекомендується вказувати мову у рамках стандатру [IETF](http://en.wikipedia.org/wiki/IETF_language_tag).
Наприклад, для англійської мови використовується `en`, в той час як для англійської в США - `en-US`.
Більш детальна інформація наведена в розділі [Інтернаціоналізація](tutorial-i18n.md).
Більш детальна інформація наведена у розділі [Інтернаціоналізація](tutorial-i18n.md).
#### [[yii\base\Application::modules|modules]] <a name="modules"></a>
Дана властивість вказує на [модулі](structure-modules.md), які містяться в додатку.
Дана властивість визначає [модулі](structure-modules.md), які містить додаток.
Значеннями властивості можуть бути масиви імен класів модулів або [конфігурацій](concept-configurations.md), а ключами -
ID модулів. Наприклад,
Значенням властивості є масив імен класів модулів або [конфігурацій](concept-configurations.md), а ключами цього масиву
виступають ID модулів. Наприклад,
```php
[
'modules' => [
// a "booking" module specified with the module class
// модуль "booking" визначено класом модуля
'booking' => 'app\modules\booking\BookingModule',
// a "comment" module specified with a configuration array
// модуль "comment" визначено масивом конфігурації
'comment' => [
'class' => 'app\modules\comment\CommentModule',
'db' => 'db',
@ -242,19 +299,23 @@ ID модулів. Наприклад,
]
```
Більш детальна інформація наведена в розділі [Модулі](structure-modules.md).
Більш детальна інформація наведена у розділі [Модулі](structure-modules.md).
#### [[yii\base\Application::name|name]] <a name="name"></a>
Властивість вказує на ім’я додатка, яке може бути зображене кінцевому користувачу. На відміну від властивості [[yii\base\Application::id|id]], яка має бути унікальною, значення даної властивості потрібне в основному для відображення і не є обов’язково унікальною.
Дана властивість вказує на ім’я додатка, яке може бути відображене кінцевому користувачу. На відміну від властивості
[[yii\base\Application::id|id]], яка має бути унікальною, значення даної властивості потрібне в основному для
відображення і не є обов’язково є унікальною.
Якщо ваш код не використовує дану властивість, то ви можете не налаштовувати її.
#### [[yii\base\Application::params|params]] <a name="params"></a>
Дана властивість описує масив глобально доступних параметрів додатка. Замість того, щоб використовувати жорстко фіксовані числа і строки у вашому коді, краще оголосити їх параметрами додатка в єдиному місці і використовувати в необхідних місцях кода. Наприклад, ви можете визначити розмір прев’ю для зображеннь наступним чином:
Дана властивість описує масив глобально доступних параметрів додатка. Замість того, щоб використовувати жорстко
фіксовані числа і строки у вашому коді, краще оголосити їх параметрами додатка в одному місці і використовувати
в необхідних місцях коду. Наприклад, ви можете визначити розмір прев’ю-зображень для зображеннь наступним чином:
```php
[
@ -264,68 +325,88 @@ ID модулів. Наприклад,
]
```
Потім, коли вам потрібно використати дані значення у вашому коді, ви робите так як показано нижче:
Потім, коли вам потрібно використати дані значення у вашому коді, ви можете зробити це наступним чином:
```php
$size = \Yii::$app->params['thumbnail.size'];
$width = \Yii::$app->params['thumbnail.size'][0];
```
Якщо пізніше вам знадобиться змінити розмір прев’ю зображення, то потрібно буде змінити лише це значення в налаштуваннях додатка не торкаючись залежного коду.
Якщо пізніше вам знадобиться змінити розмір прев’ю зображення, то вам потрібно буде змінити це значення лише у
конфігураційному файлі додатка, не змінюючи будь-який залежний код.
#### [[yii\base\Application::sourceLanguage|sourceLanguage]] <a name="sourceLanguage"></a>
Дана властивість вказує мову на якій написаний код додатка. За замовчуванням значення рівне `'en-US'`, що значить "Англійський" (США). Ви мусите налаштувати дану властивість відповідним чином, якщо зміст у вашому коді вказаний не англійською.
Дана властивість вказує мову, на якій написаний код додатка. За замовчуванням значення рівне `'en-US'`,
що означає англійську мову (США). Ви повинні змінити дану властивість, якщо мовою змісту у вашому коді
є не англійська мова.
Аналогічно властивості [language](#language), ви мусите вказати дану властивість в рамках стандарту [IETF](http://en.wikipedia.org/wiki/IETF_language_tag).
Наприклад, для англійської мови використовується `en`, в той час як для англійської в США - `en-US`.
Аналогічно властивості [language](#language), ви повинні вказати дану властивість у рамках стандарту
[IETF](http://en.wikipedia.org/wiki/IETF_language_tag). Наприклад, для англійської мови
використовується `en`, в той час як для англійської в США - `en-US`.
Більш детальна інформація наведена в розділі [Інтернаціоналізація](tutorial-i18n.md).
Більш детальна інформація наведена у розділі [Інтернаціоналізація](tutorial-i18n.md).
#### [[yii\base\Application::timeZone|timeZone]] <a name="timeZone"></a>
Дана властивість надає альтернативний спосіб встановлення часової зони в процесі роботи додатка. Таким чином, вказуючи дану властивість, ви викликаєте PHP функцію [date_default_timezone_set()](http://www.php.net/manual/ru/function.date-default-timezone-set.php). Наприклад,
Дана властивість надає альтернативний спосіб встановлення часової зони за замовчуванням у процесі роботи додатка.
Таким чином, вказуючи дану властивість, ви, по суті, викликаєте PHP функцію
[date_default_timezone_set()](http://php.net/manual/en/function.date-default-timezone-set.php). Наприклад,
```php
[
// Europe/Kiev для України
// 'Europe/Kiev' для України
'timeZone' => 'America/Los_Angeles',
]
```
#### [[yii\base\Application::version|version]] <a name="version"></a>
Дана властивість вказує на версію додатка. За замовчуванням значення рівне `'1.0'`. Ви можете не використовувати дану властивість, якщо ваш код не використовує її.
Дана властивість вказує на версію додатка. За замовчуванням значення рівне `'1.0'`. Ви можете не змінювати
дану властивість, якщо ваш код не використовує її.
### Корисні властивості <a name="useful-properties"></a>
Властивості, які перераховані в даному розділі не є часто конфігуруємими, так як їх значення за замовчуванням відповідають загальноприйнятим домовленостям. Однак, ви можете їх налаштувати, якщо вам потрібно використовувати інші значення.
Властивості, які перераховані в даному розділі, не є часто змінюваними, так як їх значення за замовчуванням
відповідають загальноприйнятим домовленостям. Однак, ви можете їх налаштувати, якщо вам потрібно використовувати
інші значення.
#### [[yii\base\Application::charset|charset]] <a name="charset"></a>
Властивість вказує кодування, яке використовує додаток. За замовчуванням значення рівне `'UTF-8'`, яке мусить бути залишеним для більшості додатків, тільки якщо ви не працюєте з устарівшим кодом, який використовує більшу кількість даних не юнікода.
Властивість вказує кодування, яке використовує додаток. За замовчуванням значення рівне `'UTF-8'`,
яке має бути незмінним для більшості додатків, тільки якщо ви не працюєте із застарілим кодом, який використовує
значний об’єм не юнікод даних.
#### [[yii\base\Application::defaultRoute|defaultRoute]] <a name="defaultRoute"></a>
Властивість вказує [маршрут](runtime-routing.md), який мусить використовувати додаток, коли він не вказаний у вхідному запиті. Маршрут може складатись із ID модуля, ID контролера і/або ID події. Наприклад, `help`,
`post/create`, `admin/post/create`. Якщо подію не вказано, то буде використано значення за замовчуванням вказане в [[yii\base\Controller::defaultAction]].
Властивість вказує [маршрут](runtime-routing.md), який повинен використовувати додаток, коли його не вказано у
вхідному запиті. Маршрут може складатись із ID модуля, ID контролера і/або ID дії. Наприклад, `help`,
`post/create`, `admin/post/create`. Якщо дію не вказано, то буде використано значення за замовчуванням,
що вказане у [[yii\base\Controller::defaultAction]].
Для [yii\web\Application|веб додатків], значення за замовчуванням даної властивості рівне `'site'`, що значить контролер `SiteController` і його подія за замовчуванням. Таким чином, якщо ви спробуєте отримати доступ до додатка не вказавши маршрут, то вам буде зображено результат події `app\controllers\SiteController::actionIndex()`.
Для [yii\web\Application|веб додатків] значення за замовчуванням даної властивості рівне `'site'`, що означає
контролер `SiteController` і його дія за замовчуванням. Таким чином, якщо ви спробуєте отримати доступ
до додатка, не вказавши маршрут - буде відображено результат дії `app\controllers\SiteController::actionIndex()`.
Для [yii\console\Application|консольних додатків], значення за замовчуванням рівне `'help'`, яке означає, що мусить використовуватись вбудована команда [[yii\console\controllers\HelpController::actionIndex()]]. Таким чином, якщо ви виконаєте команду `yii` без аргументів, вам будет зображена довідкова інформація.
Для [yii\console\Application|консольних додатків] значення за замовчуванням рівне `'help'`, яке означає,
що повинна використовуватись вбудована команда [[yii\console\controllers\HelpController::actionIndex()]].
Таким чином, якщо ви виконаєте команду `yii` без аргументів, вам будет зображена довідкова інформація.
#### [[yii\base\Application::extensions|extensions]] <a name="extensions"></a>
Дана властивість описує перелік [розширень](structure-extensions.md), які встановлені і використовуються додатком. За замовчуванням, значення даної властивості буде масив, отриманий з файла `@vendor/yiisoft/extensions.php`. Файл `extensions.php` генерується і використовується автоматично, коли ви використовуєте [Composer](http://getcomposer.org) для встановлення розширень.
Таким чином, в більшості випадків вам не потрібно налаштовувати дану властивість.
Дана властивість описує перелік [розширень](structure-extensions.md), які встановлені і використовуються додатком.
За замовчуванням, значенням даної властивості буде масив, отриманий із файла `@vendor/yiisoft/extensions.php`.
Файл `extensions.php` генерується і підтримується автоматично, коли ви використовуєте
[Composer](http://getcomposer.org) для встановлення розширень.
Таким чином, у більшості випадків, вам не потрібно налаштовувати дану властивість.
В особливих випадках, коли ви хочете опрацьовувати розширення в ручному режимі, ви можете вказати дану властивість наступним чином:
В особливих випадках, коли ви хочете керувати розширеннями власноруч, ви можете вказати дану властивість наступним чином:
```php
[
@ -346,57 +427,72 @@ $width = \Yii::$app->params['thumbnail.size'][0];
]
```
Властивість є масивом специфікацій розширень. Кожне розширення вказано масивом, який складається з елементів `name` і `version`. Якщо розширення має бути виконано в процесі [початкового завантаження](runtime-bootstrapping.md), то слід вказати `bootstrap` елемент, який може бути іменем класа або [конфігурацією](concept-configurations.md).
Як бачите, властивість є масивом специфікацій розширень. Кожне розширення вказано масивом, який складається з елементів
`name` і `version`. Якщо розширення має бути виконано в процесі [початкового завантаження](runtime-bootstrapping.md),
то слід вказати елемент у `bootstrap` властивості, який може бути іменем класа або масивом [конфігурації](concept-configurations.md).
Розширення також може визначати декілька [псевдонімів](concept-aliases.md).
#### [[yii\base\Application::layout|layout]] <a name="layout"></a>
Дана властивість вказує ім’я шаблону за замовчуванням, який мусить бути використаний при формувані [представлення](structure-views.md).
Значення за замовчуванням рівне `'main'`, яке означає, що має бути використаний шаблон `main.php` в [директорії шаблонів](#layoutPath).
Якщо обидві властивості [директорія шаблонів](#layoutPath) і [директорія представлень](#viewPath) мають значення за замовчуванням, то файл шаблону за замовчуванням може бути представлений псевдонімом шляху як `@app/views/layouts/main.php`.
Дана властивість визначає ім’я шаблону за замовчуванням, який мусить бути використаний при формувані
[представлення](structure-views.md). Значення за замовчуванням рівне `'main'`, яке означає, що має бути використаний
шаблон `main.php` в [директорії шаблонів](#layoutPath). Якщо обидві властивості, [директорія шаблонів](#layoutPath)
та [директорія представлень](#viewPath), приймають значення за замовчуванням, то файл шаблону за замовчуванням може
бути представлений псевдонімом шляху як `@app/views/layouts/main.php`.
Для відключення використання шаблону, ви можете вказати дану властивість як `false`, хоча це використовується дуже рідко.
Для відключення використання шаблону, ви можете вказати дану властивість як `false`, однак це є дуже рідкісним випадком.
#### [[yii\base\Application::layoutPath|layoutPath]] <a name="layoutPath"></a>
Властивість вказує шлях по якому слід шукати шаблони. Значення за замовчуванням рівне `layouts`, що означає підпапку в [директорії представлень](#viewPath). Якщо значення [директорії представлень](#viewPath) є значенням за замовчуванням, то директорія шаблонів за замовчуванням може бути представлена псевдонімом шляху як `@app/views/layouts`.
Дана властивість визначає шлях, по якому слід шукати шаблони. Значення за замовчуванням рівне `layouts`,
що означає підпапку у [директорії представлень](#viewPath). Якщо значення [директорії представлень](#viewPath)
є значенням за замовчуванням, то директорія шаблонів за замовчуванням може бути представлена псевдонімом шляху як `@app/views/layouts`.
Ви можете налаштувати дану властивість як теку так і як [псевдонім](concept-aliases.md).
Ви можете налаштувати дану властивість як директорію, так і як [псевдонім шляху](concept-aliases.md).
#### [[yii\base\Application::runtimePath|runtimePath]] <a name="runtimePath"></a>
Властивість вказує шлях, по якому зберігаються тимчасові файли, такі як: лог файли, кеш файли. За замовчуванням значення рівне директорії, яка преставлена псевдонімом шляху `@app/runtime`.
Дана властивість визначає шлях, по якому зберігаються тимчасові файли, такі як: лог файли, кеш файли.
За замовчуванням це значення рівне директорії, яка преставлена псевдонімом шляху `@app/runtime`.
Ви можете налаштувати дану властивість як директорію або як [псевдонім](concept-aliases.md) шляху. Зверніть увагу, що дана директорія має бути доступна для запису процесом, який запускає додаток. Також директорія має бути захищена від доступу кінцевим користувачам, файли які зберігаються в ній можуть містити важливу інформацію.
Ви можете налаштувати дану властивість як директорію або як [псевдонім](concept-aliases.md) шляху. Зверніть увагу,
що дана директорія має бути доступна для запису процесом, який виконує додаток. Також директорія має
бути захищена від доступу кінцевим користувачам, оскільки файли, які зберігаються в ній,, можуть містити важливу інформацію.
Для спрощення роботи з даною директорією, Yii надає зумовлений псевдонім шляху `@runtime`.
#### [[yii\base\Application::viewPath|viewPath]] <a name="viewPath"></a>
Дана властивість вказує на базову директорію, де містяться всі файли представлень. Значення за замовчуванням являє собою псевдонім `@app/views`. Ви можете налаштувати дану властивість як директорію так і [псевдонімом](concept-aliases.md).
Дана властивість визначає базову директорію, де містяться всі файли представлень. Значення за замовчуванням являє
собою псевдонім `@app/views`. Ви можете налаштувати дану властивість як директорі або [псевдонім шляху](concept-aliases.md).
#### [[yii\base\Application::vendorPath|vendorPath]] <a name="vendorPath"></a>
Властивість визначає директорію сторонніх бібліотек, які використовуються і керуються [Composer](http://getcomposer.org). Вона містить всі сторонні бібліотеки, які використовуються додатком, включаючи Yii фреймворк. Значеня за замовчуванням являє собою псевдонім `@app/vendor`.
Дана властивість визначає директорію сторонніх бібліотек, які використовуються і керуються за допомогою
[Composer](http://getcomposer.org). Вона містить всі сторонні бібліотеки, які використовуються додатком,
включаючи сам Yii фреймворк. Значеня за замовчуванням являє собою псевдонім `@app/vendor`.
Ви можете налаштувати дану властивість як директорію так і [псевдонімом](concept-aliases.md). При зміні даної властивості, переконайтесь що ви також змінили відповідним чином налаштування Composer.
Ви можете налаштувати дану властивість як директорію або [псевдонім шляху](concept-aliases.md).
При зміні даної властивості, переконайтесь, що ви також змінили відповідним чином налаштування Composer.
Для спрощення роботи з даною директорією, Yii надає зумовлений псевдонім шляху `@vendor`.
#### [[yii\console\Application::enableCoreCommands|enableCoreCommands]] <a name="enableCoreCommands"></a>
Дана властивість підтримується тільки [[yii\console\Application|консольними додатками]]. Вона вказує чи потрібно використовувати вбудовані в Yii консольні команди. Значення за замовчуванням рівне `true`.
Дана властивість підтримується тільки [[yii\console\Application|консольними додатками]]. Вона вказує чи потрібно
використовувати вбудовані в Yii консольні команди. Значення за замовчуванням рівне `true`.
## Події додатка <a name="application-events"></a>
Протягом життєвого циклу додатка, виникає декілька подій. Ви можете призначати обробники подій в конфігурації додатка наступним чином:
Додаток викликає декілька подій під час свого життєвого циклу обробки запиту.
Ви можете приєднати обробники подій в конфігурації додатка наступним чином:
```php
[
@ -406,10 +502,11 @@ $width = \Yii::$app->params['thumbnail.size'][0];
]
```
Використання синтаксису `on eventName` детально описано в розділі [Конфігурації](concept-configurations.md#configuration-format).
Використання синтаксису `on eventName` детально описано у розділі
[Конфігурації](concept-configurations.md#configuration-format).
Також ви можете призначити обробників подій в процесі початкового [завантаження додатку](runtime-bootstrapping.md), зразу після того
як буде створено додаток. Наприклад,
Іншим методом приэднання обробників подій у процесі [початкового завантаження додатку](runtime-bootstrapping.md),
одразу після того, як буде створено додаток, є описаний нижче приклад:
```php
\Yii::$app->on(\yii\base\Application::EVENT_BEFORE_REQUEST, function ($event) {
@ -419,27 +516,33 @@ $width = \Yii::$app->params['thumbnail.size'][0];
### [[yii\base\Application::EVENT_BEFORE_REQUEST|EVENT_BEFORE_REQUEST]] <a name="beforeRequest"></a>
Дана подія виникає *до* того як додаток починає обробляти вхідний запит.
Справжнє ім’я події - `beforeRequest`.
Дана подія виникає *до* того, як додаток починає обробляти вхідний запит. Справжнє ім’я події - `beforeRequest`.
На момент виникнення даної події, об’єкт додатка вже створений і проініційований. Таким чином, це є добрим місцем для добавляння вашого коду з допомогою подій, для перехвату управління обробкою запиту.
Наприклад, обробник події, може динамічно підставляти мову додатка [[yii\base\Application::language]] в залежності від деяких параметрів.
Коли виникає ця подія, об’єкт додатка вже створений і проініційований. Таким чином, це є
коректним місцем для додавання вашого коду за допомогою подій для перехвату управління обробки запиту.
Наприклад,в обробник події ви може динамічно призначати мову додатка [[yii\base\Application::language]]
в залежності від деяких параметрів.
### [[yii\base\Application::EVENT_BEFORE_REQUEST|EVENT_AFTER_REQUEST]] <a name="afterRequest"></a>
### [[yii\base\Application::EVENT_AFTER_REQUEST|EVENT_AFTER_REQUEST]] <a name="afterRequest"></a>
Дана подія виникає *після* того як додаток закінчує обробку запиту, але *до* того як виникне відправка відповіді. Справжнє ім’я події - `afterRequest`.
Дана подія виникає *після* закінчення обробки запиту додатком, але *до* відправки відповіді.
Справжнє ім’я події - `afterRequest`.
На момент виникнення даної події, обробка запиту завершена і ви можете використати це для побудови постобробки запиту, з метою налаштування відповіді.
На момент виникнення даної події, обробка запиту завершена і ви можете використати це для побудови постобробки запиту,
з метою налаштування відповіді.
Зверніть увагу, що в компоненті [[yii\web\Response|response]] також виникають події в процесі відправки даних кінцевому користувачу. Ці події виникають *після* поточної події.
Зверніть увагу, що у компоненті [[yii\web\Response|response]] також виникають події в процесі відправки даних кінцевому
користувачу. Ці події виникають *після* поточної події.
### [[yii\base\Application::EVENT_BEFORE_REQUEST|EVENT_BEFORE_ACTION]] <a name="beforeAction"></a>
### [[yii\base\Application::EVENT_BEFORE_ACTION|EVENT_BEFORE_ACTION]] <a name="beforeAction"></a>
Подія виникає *до* того як буде виконано [подію контролера](structure-controllers.md). Справжнє ім’я події - `beforeAction`.
Подія виникає *до* виконання кожної [дії контролера](structure-controllers.md).
Справжнє ім’я події - `beforeAction`.
Подія є об’єктом [[yii\base\ActionEvent]]. Обробник події може встановлювати властивість [[yii\base\ActionEvent::isValid]] рівним `false` для попередження виконання події.
Параметр події є об’єктом [[yii\base\ActionEvent]]. Обробник події може встановлювати властивість
[[yii\base\ActionEvent::isValid]] рівним `false` для зупинки виконання дії.
Наприклад,
@ -454,17 +557,18 @@ $width = \Yii::$app->params['thumbnail.size'][0];
]
```
Зверніть увагу на те, що та сама подія `beforeAction` виникає в [модулях](structure-modules.md) і [контролерах](structure-controllers.md). Об’єкти додатку є першими, хто ініціює дані події, вслід за модулями (якщо такі мають місце) і в кінці контролерами. Якщо обробник події встановлює властивість [[yii\base\ActionEvent::isValid]] рівним `false`, то всі наступні події не виникнуть.
Зверніть увагу на те, що така ж подія `beforeAction` виникає також у [модулях](structure-modules.md) та
[контролерах](structure-controllers.md). Об’єкти додатку є першими, хто ініціює дані події,
за якими ініціюють модулі (якщо такі є), і в кінці - контролери. Якщо обробник події встановлює властивість
[[yii\base\ActionEvent::isValid]] рівним `false`, то всі наступні події не будуть викликані.
### [[yii\base\Application::EVENT_BEFORE_REQUEST|EVENT_AFTER_ACTION]] <a name="afterAction"></a>
### [[yii\base\Application::EVENT_AFTER_ACTION|EVENT_AFTER_ACTION]] <a name="afterAction"></a>
Подія виникає *після* виконання [події контролера](structure-controllers.md).
Справжнє ім’я події - `afterAction`.
Ця подія виникає *після* виконання [дії контролера](structure-controllers.md). Справжнє ім’я події - `afterAction`.
Подія є об’єктом [[yii\base\ActionEvent]]. Через властивість [[yii\base\ActionEvent::result]] обробник події може отримати доступ і змінити значення виконання події контролера.
Наприклад,
Параметр події є об’єктом [[yii\base\ActionEvent]]. Через властивість [[yii\base\ActionEvent::result]]
обробник події може отримати доступ або змінити результат дії контролера. Наприклад,
```php
[
@ -477,24 +581,30 @@ $width = \Yii::$app->params['thumbnail.size'][0];
]
```
Зверніть увагу, що ті ж самі події `afterAction` виникають в [модулях](structure-modules.md) і [контролерах](structure-controllers.md). Ці об’єкти ініціюють події у зворотньому порядку, якщо зрівнювати з `beforeAction`.
Таким чином, контролери є першими, де виникає дана подія, потім в модулях (якщо такі мають місце), і врешті в додатках.
Зверніть увагу на те, що така ж подія `afterAction` виникає також у [модулях](structure-modules.md) та
[контролерах](structure-controllers.md). Ці об’єкти ініціюють події у зворотньому порядку, порівнюючи із `beforeAction`.
Таким чином, контролери є першими, хто ініціює дану подію, далі йдуть модулі (якщо такі є), і врешті - у додатках.
## Життєвий цикл додатка <a name="application-lifecycle"></a>
Коли [вхідний скрипт](structure-entry-scripts.md) виконується для обробки запиту, додаток буде розвиватись згідно наступного життєвого циклу:
![Життєвий цикл додатка](images/application-lifecycle.png)
Коли [вхідний скрипт](structure-entry-scripts.md) виконується для обробки запиту, додаток пройде наступний
життєвий цикл:
1. Вхідний скрипт завантажує конфігурацію додатка в якості масива;
1. Вхідний скрипт завантажує конфігурацію додатка у якості масива.
2. Вхідний скрипт створює новий об’єкт додатка:
* Викликається метод [[yii\base\Application::preInit()|preInit()]], який налаштовує деякі життєво важливі властивості додатка, такі як [[yii\base\Application::basePath|basePath]];
* Реєструється [[yii\base\Application::errorHandler|обробник помилок]];
* Налаштовуються властивості додатку;
* Викликається метод [[yii\base\Application::init()|init()]], котрий потім викликає метод [[yii\base\Application::bootstrap()|bootstrap()]] для початкового завантаження компонентів.
* Викликається метод [[yii\base\Application::preInit()|preInit()]], який налаштовує деякі життєво важливі властивості
додатка, як наприклад [[yii\base\Application::basePath|basePath]].
* Реєструється [[yii\base\Application::errorHandler|обробник помилок]].
* Налаштовуються властивості додатку.
* Викликається метод [[yii\base\Application::init()|init()]], який далі викликає метод
[[yii\base\Application::bootstrap()|bootstrap()]] для початкового завантаження компонентів.
3. Вхідний скрипт викликає метод [[yii\base\Application::run()]] для запуску додатка:
* Виникає подія [[yii\base\Application::EVENT_BEFORE_REQUEST|EVENT_BEFORE_REQUEST]];
* Обробка запиту: розбір інформації запиту в [маршруті](runtime-routing.md) з відповідними параметрами;
створення об’єктів модуля, контролера і події згідно вказаного маршруту; запуск подій;
* Виникає подія [[yii\base\Application::EVENT_AFTER_REQUEST|EVENT_AFTER_REQUEST]];
* Ініціюється подія [[yii\base\Application::EVENT_BEFORE_REQUEST|EVENT_BEFORE_REQUEST]].
* Обробка запиту: розбір інформації запиту на [маршрут](runtime-routing.md) та відповідні параметри;
створення об’єктів модуля, контролера та дії, згідно вказаного маршруту; ініціювання подій.
* Ініціюється подія [[yii\base\Application::EVENT_AFTER_REQUEST|EVENT_AFTER_REQUEST]].
* Відповідь надсилається кінцевому користувачу.
4. Вхідний скрипт отримує значення статусу виходу з додатка і завершує обробку запиту.
4. Вхідний скрипт отримує значення статусу виходу із додатка та завершує обробку запиту.

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

@ -1,17 +1,19 @@
Контролери
===========
==========
Контролери є частиною [MVC](https://ru.wikipedia.org/wiki/Model-View-Controller) архітектури. Це об’єкти класів, успадкованих
від [[yii\base\Controller]] і відповідають за опрацювання запиту і генерації відповіді. По суті, після опрацювання запиту [додатками](structure-applications.md),
контролери проаналізують вхідні дані, передадуть їх в [моделі](structure-models.md), додадуть результати моделі в [представлення](structure-views.md),
і в кінцевому підсумку згенерують вихідні відповіді.
Контролери є частиною [MVC](http://uk.wikipedia.org/wiki/Модель-вид-контролер) архітектури. Це об’єкти класів,
успадкованих від [[yii\base\Controller]] та відповідають за обработку запитів і генерацію відповідей.
Зокрема, після отримання контролю від [додатків](structure-applications.md), контролери проаналізують
вхідні дані, передадуть їх у [моделі](structure-models.md), додадуть результати моделі у
[представлення](structure-views.md), і в кінцевому підсумку згенерують вихідні відповіді.
## Події <a name="actions"></a>
## Дії <a name="actions"></a>
Контролери складаються з *подій*, які є основними блоками, до яких може звертатись кінцевий користувач і запитувати виконання того або іншого функціоналу. В контролері може бути одна або декілька подій.
Контролери складаються з *дій*, які є основними блоками, до яких може звертатись кінцевий користувач і запитувати
виконання того або іншого функціоналу. В контролері може бути одна або декілька дій.
Наступний приклад показує `post` контролер з двома подіями: `view` і `create`:
Наступний приклад показує `post` контролер з двома діями: `view` та `create`:
```php
namespace app\controllers;
@ -50,21 +52,25 @@ class PostController extends Controller
}
```
В події `view` (визначено методом `actionView()`), код спочатку завантажує [модель](structure-models.md)
згідно запитуваної ID моделі; Якщо модель успішно завантажена, то код відобразить її за допомогою [представлення](structure-views.md)
під назвою `view`. В іншому випадку буде визване виключення.
У дії `view` (визначеній методом `actionView()`) код спочатку завантажує [модель](structure-models.md),
відповідно запитуваної ID моделі; Якщо модель успішно завантажена, то код відобразить її за допомогою
[представлення](structure-views.md), під назвою `view`. В іншому випадку - буде визване виключення.
В події `create` (визначено методом `actionCreate()`), код аналогічний. Він спочатку намагається завантажити [модель](structure-models.md) за допомогою даних із запиту і зберегти модель. Якщо все пройшло успішно, то код перенаправить браузер на подію `view` з ID щойно створеної моделі. В іншому випадку він відобразить предаставлення `create`, через яке користувач зможе вказати необхідні дані.
У дії `create` (визначеній методом `actionCreate()`), код аналогічний. Він спочатку намагається завантажити
[модель](structure-models.md) за допомогою даних із запиту і зберегти модель. Якщо все пройшло успішно,
то код перенаправить браузер на дію `view` із ID щойно створеної моделі. В іншому випадку - він відобразить
предаставлення `create`, через яке користувач зможе вказати необхідні дані.
## Маршрути <a name="routes"></a>
Кінцеві користувачі звертаються до подій з допомогою так названих *маршрутів*. Маршрут це рядок, який складається з наступних частин:
Кінцеві користувачі звертаються до дій з допомогою так названих *маршрутів*. Маршрут це рядок,
який складається з наступних частин:
* ID модуля: він існує, тільки якщо контролер належить не додатку, а [модулю](structure-modules.md);
* ID контролера: рядок, який унікально ідентифікує контролер серед всіх інших контролерів одного і того ж додатка
(або одного й того ж модуля, якщо контролер належить модулю);
* ID події: рядок, який унікально идентифікує подію серед всіх інших подій одного й того ж конторолера.
* ID дії: рядок, який унікально ідентифікує дію серед всіх інших дій одного й того ж конторолера.
Маршрути можуть мати наступний формат:
@ -78,14 +84,16 @@ ControllerID/ActionID
ModuleID/ControllerID/ActionID
```
Таким чином, якщо користувач звертається до URL `http://hostname/index.php?r=site/index`, то `index` подія в `site` контролері яку буде викликано.
Секція [Маршрутизація](runtime-routing.md) містить більш детальну інформацію про те як маршрути співставляються з подіями.
Таким чином, якщо користувач звертається до URL `http://hostname/index.php?r=site/index`, то буде викликано дію `index`
у контролері `site`. Розділ [Маршрутизація та створення URL](runtime-routing.md) містить більш детальну інформацію
про те, як маршрути співставляються із діями.
## Створення контролерів <a name="creating-controllers"></a>
В [[yii\web\Application|Веб додатках]], контролери мусять бути успадковані від [[yii\web\Controller]] або його потомків.
Аналогічно для [[yii\console\Application|консольних додатків]], контролери мусять бути успадковані від [[yii\console\Controller]] або його потомків. Наступний код визначає `site` контролер:
У [[yii\web\Application|веб додатках]] контролери повинні бути успадкованими від класу [[yii\web\Controller]]
або його нащадків. Аналогічно для [[yii\console\Application|консольних додатків]], контролери повинні бути
успадкованими від класу [[yii\console\Controller]] або його нащадків. Наступний код визначає контролер `site`:
```php
namespace app\controllers;
@ -100,66 +108,68 @@ class SiteController extends Controller
### ID контролерів <a name="controller-ids"></a>
За звичай контролер зроблений таким чином, що він мусить опрацьовувати запити, які пов’язані з певним ресурсом.
Саме через дані причини, ID контролерів за завичай є іменниками, які посилаються на ресурс, який вони опрацьовують.
Наприклад, ви можете використовувати `article` в якості ID контролера, який відповідає за опрацювання даних публікацій.
За звичай контролер зроблений таким чином, що він повинен обробляти запити, які пов’язані з певним ресурсом.
Саме з цієї причини, ID контролерів за завичай є іменниками, які посилаються на ресурс, який вони обробляють.
Наприклад, ви можете використовувати `article` в якості ID контролера, який відповідає за обробку даних публікацій.
За замовчуванням, ID контролерів мають містити тільки наступні символи: Англійські букви в нижньому регістрі, цифри, підкреслення,
тире и слеш. Наприклад, обидва `article` і `post-comment` є прийнятними ID контролерів, в той час як `article?`, `PostComment`,
`admin\post` не являються такими.
За замовчуванням, ID контролерів мають містити тільки наступні символи: англійські букви в нижньому регістрі, цифри,
підкреслення, тире і слеш. Наприклад, обидва `article` та `post-comment` є прийнятними ID контролерів, в той час,
як `article?`, `PostComment`, `admin\post` не є такими.
ID контролерів також можуть містити префікс субдиректорії. Наприклад, в `admin/article` частина `article` є контролером в
субдиректорії `admin` в [[yii\base\Application::controllerNamespace|порсторі імен]].
Допустимими символами для префіксів субдиректорій є: Англійські букви в нижньому і верхньому регістрі, символи підкреслення і слеш, де слеш використовується в якості розділителя для багатовкладених субдиректорій (наприклад `panels/admin`).
ID контролера також може містити префікс субдиректорії. Наприклад, у `admin/article` - частина `article` відповідає
контролеру в субдиректорії `admin` [[yii\base\Application::controllerNamespace|простору імен контролера]].
Допустимими символами для префіксів субдиректорій є: англійські букви в нижньому і верхньому регістрах, цифри,
символи підкреслення і слеш, де слеш - використовується в якості роздільника для багаторівневих субдиректорій
(наприклад `panels/admin`).
### Іменування класів контролерів <a name="controller-class-naming"></a>
### Правила найменування класів контролерів <a name="controller-class-naming"></a>
Назви класів контролерів можуть бути отримані із ID контролерів наступними правилами:
Назви класів контролерів можуть бути отримані з ID контролерів наступними способами:
* Привести у верхній регістр перший символ в кожному слові, розділеному дефісами. Зверніть увагу, що, якщо
ID контролера містить слеш, то дане правило поширюється тільки на частину після останнього слеша в ID контролера.
* Прибрати дефіси і замінити будь-який прямий слеш на зворотний.
* Додати суфікс `Controller`.
* Додати на початок [[yii\base\Application::controllerNamespace|простір імен контролера]].
* Привести в верхній регістр перший символ в кожному слові, розділеному дефісами. Зверніть увагу що, якщо ID контролера
містить слеш, то дане правило поширюється тільки на частину після останнього слеша в ID контролера;
* Прибрати дефіси і замінити будь-який прямий слеш на зворотний;
* Додати суфікс `Controller`;
* Додати в початок [[yii\base\Application::controllerNamespace|простір імен контролерів]].
Нижче наведено декілька прикладів, з урахуванням того, що [[yii\base\Application::controllerNamespace|простір імен контролерів]] має значення за замовчуванням `app\controllers`:
Нижче наведено декілька прикладів, з урахуванням того, що
[[yii\base\Application::controllerNamespace|простір імен контролера]] має значення за замовчуванням `app\controllers`:
* `article` відповідає `app\controllers\ArticleController`;
* `post-comment` відповідає `app\controllers\PostCommentController`;
* `admin/post-comment` відповідає `app\controllers\admin\PostCommentController`;
* `adminPanels/post-comment` відповідає `app\controllers\adminPanels\PostCommentController`.
Класи контролерів мають бути [автозавантаженими](concept-autoloading.md). Саме по цій причині, у вищенаведених прикладах,
контролер `article` має бути збереженим у файл, [псевдонім](concept-aliases.md) якого `@app/controllers/ArticleController.php`;
в той час як контролер `admin/post2-comment` має знаходитись у файлі `@app/controllers/admin/Post2CommentController.php`.
Класи контролерів мають бути [автозавантаженими](concept-autoloading.md). Саме з цієї причини у вищенаведених прикладах
контролер `article` має бути збереженим у файл, [псевдонім шляху](concept-aliases.md) якого є
`@app/controllers/ArticleController.php`; в той час, як контролер `admin/post2-comment` має знаходитись у файлі
`@app/controllers/admin/Post2CommentController.php`.
> Інформація: Останній приклад `admin/post2-comment` показує яким чином ви можете розташувати контролер в директорії
[[yii\base\Application::controllerNamespace|простору імен контролерів]]. Це дуже зручно, коли ви хочете організувати свої контролери в декілька категорій і не хочете використовувати [модулі](structure-modules.md).
[[yii\base\Application::controllerNamespace|простору імен контролера]]. Це дуже зручно, коли ви хочете організувати
свої контролери у декілька категорій і не хочете використовувати [модулі](structure-modules.md).
### Мапа контролерів <a name="controller-map"></a>
Ви можете налаштувати [[yii\base\Application::controllerMap|Мапу контролерів]] для того, щоб подолати
описані вище обмеження іменування ID контролерів і назв класів. В основному це дуже зручно, коли ви використовуєте
Ви можете налаштувати [[yii\base\Application::controllerMap|мапу контролерів]] для того, щоб подолати
описані вище обмеження іменування ID контролерів і назв класів. В основному, це дуже зручно, коли ви використовуєте
сторонні контролери, іменування яких ви не можете контролювати.
Ви можете налаштувати [[yii\base\Application::controllerMap|мапу контролерів]] в [налаштуваннях додатка](structure-applications.md#application-configurations)
наступним чином:
Ви можете налаштувати [[yii\base\Application::controllerMap|мапу контролерів]] в
[налаштуваннях додатка](structure-applications.md#application-configurations) наступним чином:
```php
[
'controllerMap' => [
[
// оголошує "account" контролер, використовуючи назву класу
'account' => 'app\controllers\UserController',
// оголошує "article" контролер, використовуючи масив конфігурації
'article' => [
'class' => 'app\controllers\PostController',
'enableCsrfValidation' => false,
],
// оголошує контролер "account", використовуючи назву класу
'account' => 'app\controllers\UserController',
// оголошує контролер "article", використовуючи масив конфігурації
'article' => [
'class' => 'app\controllers\PostController',
'enableCsrfValidation' => false,
],
],
]
@ -168,11 +178,13 @@ ID контролерів також можуть містити префікс
### Контролер за замовчуванням <a name="default-controller"></a>
Кожний додаток має контролер за замовчуванням, вказаний через властивість [[yii\base\Application::defaultRoute]].
Коли в запиті не вказаний [маршрут](#ids-routes), тоді буде використаний маршрут вказаний в даній властивості.
Для [[yii\web\Application|Веб додатків]], це значення `'site'`, в той час як для [[yii\console\Application|консольних додатків]],
це `'help'`. Таким чином, якщо вказаний URL `http://hostname/index.php`, це значить, що контролер `site` виконає обробку запиту.
Коли в запиті не вказано [маршрут](#ids-routes), то буде використано маршрут із даної властивості.
Для [[yii\web\Application|веб додатків]], це значення рівне `'site'`, у той час, як для
[[yii\console\Application|консольних додатків]], це `'help'`. Таким чином, якщо вказаний URL
`http://hostname/index.php`, це значить, що контролер `site` виконає обробку запиту.
Ви можете змінити контролер за замовчуванням наступним чином в [налаштуваннях додатку](structure-applications.md#application-configurations):
Ви можете змінити контролер за замовчуванням наступним чином в
[налаштуваннях додатку](structure-applications.md#application-configurations):
```php
[
@ -181,9 +193,11 @@ ID контролерів також можуть містити префікс
```
## Створення подій <a name="creating-actions"></a>
## Створення дій <a name="creating-actions"></a>
Створення подій не містить складнощів також як і оголошення так званих *методов подій* в класі контролера. Метод події це *public* метод, ім’я якого починається за слова `action`. Значення, що повертаються методу події являють собою відповідні дані, які будуть вислані кінцевому користувачу. Наведений нижче код визначає дві події `index` і `hello-world`:
Створення дій може бути таким же простим, як і оголошення так званих *методов дій* у класі контролера.
Метод дії це *public* метод, ім’я якого починається зі слова `action`. Значення методі дії, що повертається, є даними
відповіді, які будуть вислані кінцевому користувачу. Наведений нижче код визначає дві дії - `index` і `hello-world`:
```php
namespace app\controllers;
@ -205,54 +219,60 @@ class SiteController extends Controller
```
### ID подій <a name="action-ids"></a>
### ID дій <a name="action-ids"></a>
В основному події розробляються для певної конкретної обробки ресурса. По цій причині, ID подій в основному
є дієсловами, такими як `view`, `update`, і т. д.
Частіше за все, дія розробляється для певної конкретної обробки ресурса. З цієї причини ID дій, в основному,
є дієсловами, такими як `view`, `update`, і т.д.
За замовчуванням, ID події повинен містити тільки такі символи: Англійські букви в нижньому регістрі, цифри,
підкреслення і дефіси. Дефіси в ID подій використовуються для поділу слів. Наприклад, `view`, `update2`, `comment-post` є допустимими ID подій, в той час як `view?`, `Update` не являються такими.
За замовчуванням, ID дій повинні містити тільки такі символи: англійські букви в нижньому регістрі, цифри,
підкреслення і дефіси. Дефіси в ID дій використовуються для поділу слів. Наприклад, `view`, `update2`,
`comment-post` є допустимими ID дій, в той час, як `view?`, `Update` не є такими.
Ви можете створювати події двома способами: вбудовані події і окремі події. Вбудована подія є методом, визначеним
в класі контролера, тоді як окрема подія є екземпляром класу, успадкованого від [[yii\base\Action]] або його потомків.
Вбудовані події вимагають менше зусиль для створення і в основному використовуються якщо у вас немає потреби в повторному використанні подій.
Окремі події, з іншого боку, в основному створюються для використання в різних контролерах або при використанні в [розширеннях](structure-extensions.md).
Ви можете створювати дії двома способами: вбудовані дії і окремі дії. Вбудована дія є методом, визначеним
в класі контролера, тоді як окрема дія є екземпляром класу, успадкованого від [[yii\base\Action]] або його нащадків.
Вбудовані дії вимагають менше зусиль для створення і, в основному, використовуються якщо у вас немає потреби
у повторному використанні цих дій. Окремі дії, з іншого боку, в основному створюються для використання в різних
контролерах або при використанні у [розширеннях](structure-extensions.md).
### Вбудовані події <a name="inline-actions"></a>
### Вбудовані дії <a name="inline-actions"></a>
Вбудовані події це ті події, які визначені в рамках методів контролера, як ми це вже обговорили.
Вбудовані дії це ті дії, які визначені у рамках методів контролера, як ми це вже обговорили.
Назви методів подій можуть бути отримані з ID подій наступним чином:
Назви методів дій можуть бути отримані із ID дій наступним чином:
* Привести перший символ кожного слова в ID події у верхній регістр;
* Привести перший символ кожного слова в ID дії у верхній регістр;
* Прибрати дефіси;
* Додати префікс `action`.
Наприклад, `index` відповідає `actionIndex`, а `hello-world` відповідає `actionHelloWorld`.
> Примітка: Назви імен подій є *регістрозалежними*. Якщо у вас є метод `ActionIndex`, він не буде врахований як метод події, таким чином, запит до події `index` призведе до зображення виключення. Також слід врахувати, що методи подій повинні мати область видимості public. Методи, що мають область видимості private або protected НЕ визначають методи вбудованих подій.
Наприклад, `index` перетвориться у `actionIndex`, а `hello-world` перетвориться у `actionHelloWorld`.
> Примітка: Назви імен дій є *регістрозалежними*. Якщо у вас є метод `ActionIndex`, то його не буде враховано
як метод дії, і в результаті, запит до дії `index` призведе до отримання виключення. Також слід врахувати,
що методи дій повинні бути публічними ("public"). Приватні ("private") або захищені ("protected") методи
НЕ визначають вбудованих дій.
Вбудовані події в основному використовуються, тому що для їх створення не потрібного багато зусиль. Тим не менше, якщо ви плануєте повторно використовувати деякі події в різних місцях, або якщо ви хочете перерозподілити події, ви повинні визначити їх як *окремі події*.
В основному використовуються вбудовані дії, оскільки для їх створення не потрібного багато зусиль.
Тим не менше, якщо ви плануєте повторно використовувати деякі дії у різних місцях або якщо ви хочете
перерозподілити дії, ви повинні визначити їх як *окремими діями*.
### Окремі події <a name="standalone-actions"></a>
### Окремі дії <a name="standalone-actions"></a>
Окремі події визначаються в якості класів, успадкованих від [[yii\base\Action]] або його потомків.
Наприклад, в Yii релізах, присутні [[yii\web\ViewAction]] і [[yii\web\ErrorAction]], обидва з яких є окремими подіями.
Окремі дії визначаються в якості класів, успадкованих від [[yii\base\Action]] або його нащадків.
Наприклад, в релізах Yii присутні [[yii\web\ViewAction]] та [[yii\web\ErrorAction]], обидва класи є окремими діями.
Для використання окремої події, ви маєте вказати її в *мапі подій*, з допомогою перевизначення метода
Для використання окремої дії, ви маєте вказати її у *мапі дій* за допомогою перевизначення методу
[[yii\base\Controller::actions()]] у вашому класі контролера, наступним чином:
```php
public function actions()
{
return [
// оголошує "error" подію з допомогою назви класу
// оголошує дію "error" за допомогою назви класу
'error' => 'yii\web\ErrorAction',
// оголошує "view" подію з допомогою конфігураційного масиву
// оголошує дію "view" за допомогою конфігураційного масиву
'view' => [
'class' => 'yii\web\ViewAction',
'viewPrefix' => '',
@ -261,10 +281,12 @@ public function actions()
}
```
Як ви можете бачити, метод `actions()` мусить повернути масив, ключами якого є ID подій, а значенями - відповідні назви класу події або [конфігурація](concept-configurations.md). На відміну від вбудованих подій, ID окремих подій можуть містити довільні символи, до тих пір поки вони визначені в методі `actions()`.
Як ви можете бачити, метод `actions()` повинен повернути масив, ключами якого є ID дій, а значеннями - відповідні
назви класів дій або [конфігурацій](concept-configurations.md). На відміну від вбудованих дій, ID окремих дій
можуть містити довільні символи, доки вони визначені у методі `actions()`.
Для створення окремої події, ви мусите успадкуватись від класу [[yii\base\Action]] або його потомків, і реалізувати
метод `run()` з областю видимості public. Роль метода `run()` аналогічна іншим методам подій. Наприклад,
Для створення окремої дії, ви повинні успадкуватись від класу [[yii\base\Action]] або його нащадків, і реалізувати
публічний ("public") метод `run()`. Роль метода `run()` аналогічна іншим методам дій. Наприклад,
```php
<?php
@ -282,21 +304,22 @@ class HelloWorldAction extends Action
```
### Результати подій <a name="action-results"></a>
### Результати дій <a name="action-results"></a>
Значення, що повертається методами подій або методом `run()` окремої події дуже важливе. Воно є результатом
виконання відповідної події.
Значення, що повертається від метода дії або метода `run()` окремої дії дуже важливе.
Воно є результатом виконання відповідної дії.
Значення, що повертається може бути об’єктом [response](runtime-responses.md), який буде направлений кінцевому користувачу в якості відповіді.
Значення, що повертається, може бути об’єктом [відповіді](runtime-responses.md), яке буде відправлено
кінцевому користувачу.
* Для [[yii\web\Application|Веб додатків]], значення, що повертається також може бути довільними даними, яким будуть
назначені [[yii\web\Response::data]], а потім конвертовані в рядок, що представляє тіло відповіді.
* Для [[yii\console\Application|Консольних додатків]], значення, що повертається також може бути числом, що представляє
[[yii\console\Response::exitStatus|статус виходу]] виконання команди.
* Для [[yii\web\Application|веб додатків]], значення, що повертається, також може бути довільними даними,
яке буде призначене до [[yii\web\Response::data]], а потім конвертоване у рядок, що представляє тіло відповіді.
* Для [[yii\console\Application|консольних додатків]], значення, що повертається, також може бути числом, що
представляє [[yii\console\Response::exitStatus|статус виходу]] виконання команди.
В вищенаведених прикладах, всі результати подій є рядками, які будуть використані в якості тіла відповіді,
висланого користувачеві. Наступний приклад, показує подію, що може перенаправити браузер користувача на новий URL, за допомогою
повернення response об'єкта ([[yii\web\Controller::redirect()|redirect()]] метод повертає response об’єкт):
В вищенаведених прикладах всі результати дій є рядками, які будуть використані у якості тіла відповіді користувачу.
Наступний приклад показує як дія може перенаправити браузер користувача на новий URL за допомогою
повернення об’єкта відповіді (оскільки метод [[yii\web\Controller::redirect()|redirect()]] повертає об’єкт response):
```php
public function actionForward()
@ -307,12 +330,14 @@ public function actionForward()
```
### Параметри подій <a name="action-parameters"></a>
### Параметри дій <a name="action-parameters"></a>
Методи подій для вбудованих подій і методи `run()` для окремих подій можуть приймати параметри, які називають *параметри подій*. Їх значення беруться із запитів. Для [[yii\web\Application|Веб додатків]], значення кожного з параметрів події береться з `$_GET`, використовуючи назву параметра в якості ключа;
для [[yii\console\Application|консольних додатків]], вони відповідають аргументам командної строки.
Методи дій для вбудованих дій і методи `run()` для окремих дій можуть приймати, так звані, *параметри дії*.
Їх значення беруться із запитів. Для [[yii\web\Application|веб додатків]], значення кожного з параметрів дії
береться із `$_GET`, використовуючи назву параметра у якості ключа;
для [[yii\console\Application|консольних додатків]] - вони відповідають аргументам командної строки.
В наведеному нижче прикладі, подія `view` (вбудовона подія) визначає два параметра: `$id` і `$version`.
В наступному прикладі, дія `view` (вбудовона дія) визначає два параметри: `$id` і `$version`.
```php
namespace app\controllers;
@ -328,17 +353,19 @@ class PostController extends Controller
}
```
Для різних запитів параметри події будуть визначені наступним чином:
Параметри дії будуть заповнені для різних запитів наступним чином:
* `http://hostname/index.php?r=post/view&id=123`: параметр `$id` буде присвоєне значення `'123'`, в той час як `$version` буде мати значення null, так як рядок запиту не містить параметра `version`;
* `http://hostname/index.php?r=post/view&id=123`: параметру `$id` буде присвоєне значення `'123'`, у той час,
як `$version` буде мати значення null, так як рядок запиту не містить параметра `version`.
* `http://hostname/index.php?r=post/view&id=123&version=2`: параметрам `$id` і `$version` будуть присвоєні
значення `'123'` і `'2'` відповідно;
* `http://hostname/index.php?r=post/view`: буде вкинуте виключення [[yii\web\BadRequestHttpException]], так як
обов’язковий параметр `$id` не був вказаний в запиті;
* `http://hostname/index.php?r=post/view&id[]=123`: буде вкинуте виключення [[yii\web\BadRequestHttpException]], так як
параметр `$id` отримав невірне значення `['123']`.
значення `'123'` і `'2'` відповідно.
* `http://hostname/index.php?r=post/view`: буде отримане виключення [[yii\web\BadRequestHttpException]], оскільки
обов’язковий параметр `$id` не було вказано у запиті.
* `http://hostname/index.php?r=post/view&id[]=123`: буде отримане виключення [[yii\web\BadRequestHttpException]],
оскільки параметр `$id` отримав невірне значення `['123']`.
Якщо ви хочите, щою параметр події приймав масив значеннь, ви мусите використовувати type-hint значення `array`, як зображено нажче:
Якщо ви хочете, щоб параметр дії приймав масив значень, ви повинні використати type-hint `array` параметра метода,
як зображено нажче:
```php
public function actionView(array $id, $version = null)
@ -347,19 +374,22 @@ public function actionView(array $id, $version = null)
}
```
Тепер, якщо запит буде містити URL `http://hostname/index.php?r=post/view&id[]=123`, то параметр `$id` отримає значення
`['123']`. Якщо запит буде містити URL `http://hostname/index.php?r=post/view&id=123`, то параметр `$id` все рівно буде містити масив, так як скалярне значення `'123'` буде автоматично сконвертовано в масив.
Тепер, якщо запит буде містити URL `http://hostname/index.php?r=post/view&id[]=123`, то параметр `$id` отримає
значення `['123']`. Якщо запит буде містити URL `http://hostname/index.php?r=post/view&id=123`, то параметр
`$id` все рівно отримає масив, оскільки скалярне значення `'123'` буде автоматично сконвертовано у масив.
Вищенаведені приклади в основному показують як параметри подій працюють для Веб додатків. Більше інформації
Вищенаведені приклади в основному показують як параметри дій працюють для веб додатків. Більше інформації
про параметри консольних додатків наведено в секції [Консольні команди](tutorial-console.md).
### Події за замовчуванням <a name="default-action"></a>
### Дія за замовчуванням <a name="default-action"></a>
Кожний контролер містить події, визначені через властивість [[yii\base\Controller::defaultAction]].
Коли [маршрут](#ids-routes) містить тільки ID контролера, то розуміється, що було запрошено подію контролера за замовчуванням.
Кожний контролер містить дію за замовчуванням, визначену через властивість [[yii\base\Controller::defaultAction]].
Коли [маршрут](#ids-routes) містить тільки ID контролера, то розуміється, що було запитана дія контролера
за замовчуванням.
За замовчуванням, ця подія має значення `index`. Якщо ви хочите змінити це значення, просто перевизначте дану властивість в класі контролера наступним чином:
За замовчуванням, ця дія має значення `index`. Якщо ви хочете змінити це значення - просто перевизначте дану
властивість у класі контролера наступним чином:
```php
namespace app\controllers;
@ -380,35 +410,39 @@ class SiteController extends Controller
## Життєвий цикл контролера <a name="controller-lifecycle"></a>
При опрацюванні запиту, [додаток](structure-applications.md) створить контролер, базуючись на
запрошеному [маршруті](#routes). Для виконання запиту, контролер пройде через наступні етапи життєвого циклу:
При обробці запиту, [додаток](structure-applications.md) створить контролер, базуючись на [маршруті](#routes),
який було запитано. Для виконання запиту, контролер пройде через наступні етапи життєвого циклу:
1. Метод [[yii\base\Controller::init()]] буде викликаний після того як контролер буде створений і сконфігурований;
2. Контролер створить об’єкт події, базуючись на запрошеному ID події:
* Якщо ID події не вказано, то буде використано [[yii\base\Controller::defaultAction|ID події за замовчуванням]];
* Якщо ID події знайдено в [[yii\base\Controller::actions()|мапі подій]], то буде створено окрему подію;
* Якщо ID події відповідає методу події, то буде створено вбудовану подію;
* В іншому випадку, буде вкинуте виключення [[yii\base\InvalidRouteException]].
1. Метод [[yii\base\Controller::init()]] буде викликаний після того, як контролер був створений і сконфігурований.
2. Контролер створить об’єкт дії, базуючись на ID дії, яку було запитано:
* Якщо ID дії не вказано, то буде використано [[yii\base\Controller::defaultAction|ID дії за замовчуванням]];
* Якщо ID дії знайдено у [[yii\base\Controller::actions()|мапі дій]], то буде створено окрему дію;
* Якщо ID дії відповідає методу дії, то буде створено вбудовану дію;
* В іншому випадку, буде отримане виключення [[yii\base\InvalidRouteException]].
3. Контролер послідовно викликає метод `beforeAction()` додатка, модуля (якщо контролер належить модулю) і
самого контролера.
* Якщо один із методів повернув `false`, то решта, невикликані методи `beforeAction` будуть пропущені, а виконання події буде відмінено;
* За замовчуванням, кожний виклик метода `beforeAction()` викликає подію `beforeAction`, на яку ви можете призначити обробників.
4. Контролер запускає подію:
* Параметри події будуть проаналізовані і заповнені з даних запиту.
* Якщо один із методів повернув `false`, то решта невикликаних методів `beforeAction` будуть пропущені,
а виконання дії буде відмінено;
* За замовчуванням, кожний виклик метода `beforeAction()` викликає подію `beforeAction`, на яку ви можете
призначити обробники.
4. Контролер виконує дію:
* Параметри дії будуть проаналізовані і заповнені із даних запиту.
5. Контролер послідовно викликає методи `afterAction` контролера, модуля (якщо контролер належить модулю) і додатка.
* За замовчуванням, кожний виклик метода `afterAction()` викликає подію `afterAction`, на яку ви можете призначити обробників.
6. Додаток, отримавши результат виконання події, присвоює його об’єкту [response](runtime-responses.md).
* За замовчуванням, кожний виклик метода `afterAction()` викликає подію `afterAction`, на яку ви можете
призначити обробники.
6. Додаток, отримавши результат виконання дії, привласнює його об’єкту [response](runtime-responses.md).
## Кращі практики <a name="best-practices"></a>
В добре організованих додатках, контролери за звичай дуже тонкі, і містять лише декілька рядків коду.
Якщо ваш контролер дуже складний, це за звичай означає, що вам потрібно провести рефакторинг його і перенести будь-який код в інші місце.
Якщо ваш контролер дуже складний, це за звичай означає, що вам потрібно провести його рефакторинг і
перенести деякий код в інші класи.
В цілому, контролери
* можуть мати доступ до даних [запиту](runtime-requests.md);
* можуть викликати методи [моделей](structure-models.md) і інших компонентів системи з даними запиту;
* можуть викликати методи [моделей](structure-models.md) та інших компонентів системи із даними запиту;
* можуть використовувати [представлення](structure-views.md) для формування відповіді;
* не повинні займатись опрацюванням даних, це має відбуватись в [моделях](structure-models.md);
* мають уникати використання HTML або іншої розмітки, краще це робити в [представленнях](structure-views.md).
* не повинні займатись обробкою даних - це має відбуватися у [моделях](structure-models.md);
* мають уникати використання HTML або іншої розмітки - краще це робити у [представленнях](structure-views.md).

49
docs/guide-uk/structure-entry-scripts.md

@ -1,22 +1,26 @@
Вхідні скрипти
===============
==============
Вхідні скрипти це перша ланка в процесі початкового завантаження додатку. Додаток (веб додаток або консольний додаток)
включає єдиний вхідний скрипт. Кінцеві користувачі роблять запити до вхідного скрипта, який створює об’єкти додатка і перенаправляє запит до них.
має єдиний вхідний скрипт. Кінцеві користувачі роблять запити до вхідного скрипта, який створює об’єкти додатка та
перенаправляє запит до них.
Вхідні скрипти для веб додатків повинні бути збережені в теках доступних з веб, таким чином вони можуть бути доступними кінцевому користувачу. Такі скрипти за звичай називаються `index.php`, але також можут використовуватись і інші імена, які можуть бути розпізнані використовуваними веб-серверами.
Вхідні скрипти для веб додатків повинні бути збережені в директоріях, доступних із веб, таким чином, вони можуть бути
доступними кінцевим користувачам. Зазвичай вони називаються `index.php`, але також можут використовуватись і інші
імена, які можуть бути розпізнані веб-серверами.
Вхідні скрипти для консольних додатків за звичай розміщенні в [кореневій директорії](structure-applications.md) додатку і мають назву
`yii` (з суфіксом `.php`). Вони мають права на виконання, таким чином користувачі зможуть запускати консольні додатки через команду `./yii <маршрут> [аргументи] [опції]`.
Вхідні скрипти для консольних додатків зазвичай розміщенні у [кореневій директорії](structure-applications.md)
додатку і мають назву `yii` (з суфіксом `.php`). Вони повинні мати права на виконання, щоб користувачі мали змогу
запускати консольні додатки через команду `./yii <маршрут> [аргументи] [опції]`.
Вхідні скрипти в основному виконують наступну роботу:
* Оголошують глобальні константи;
* Реєструють завантажувач класів [Composer](http://getcomposer.org/doc/01-basic-usage.md#autoloading);
* Підключають файл класа [[Yii]];
* Реєструють автозавантажувач класів [Composer](http://getcomposer.org/doc/01-basic-usage.md#autoloading);
* Підключають файл класу [[Yii]];
* Завантажують конфігурацію додатка;
* Створюють і конфігурують об’єкт [додатка](structure-applications.md);
* Викликають метод [[yii\base\Application::run()]] додатка для опрацювання вхідного запиту.
* Викликають метод [[yii\base\Application::run()]] додатка для обробки вхідного запиту.
## Веб додатки <a name="web-applications"></a>
@ -29,16 +33,16 @@
defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');
// реєстрація завантажувача класів Composer
// реєстрація автозавантажувача класів Composer
require(__DIR__ . '/../vendor/autoload.php');
// підключення файла класа Yii
// підключення файла класу Yii
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
// завантаження конфігурації додатка
$config = require(__DIR__ . '/../config/web.php');
// створення і конфігурація додатка, а також виклик метода для опрацювання вхідного запиту
// створення, конфігурація та виконання додатка
(new yii\web\Application($config))->run();
```
@ -60,14 +64,14 @@ $config = require(__DIR__ . '/../config/web.php');
defined('YII_DEBUG') or define('YII_DEBUG', true);
// fcgi не має констант STDIN и STDOUT, вони визначаються за замовчуванням
// fcgi не має констант STDIN та STDOUT за замовчуванням
defined('STDIN') or define('STDIN', fopen('php://stdin', 'r'));
defined('STDOUT') or define('STDOUT', fopen('php://stdout', 'w'));
// реєстрація завантажувача класів Composer
// реєстрація автозавантажувача класів Composer
require(__DIR__ . '/vendor/autoload.php');
// підключення файла класа Yii
// підключення файла класу Yii
require(__DIR__ . '/vendor/yiisoft/yii2/Yii.php');
// завантаження конфігурації додатка
@ -83,11 +87,15 @@ exit($exitCode);
Вхідні скрипти є найкращим місцем для оголошення глобальних констант. Yii підтримує наступні три константи:
* `YII_DEBUG`: вказує чи працює додаткок у відлагоджувальному режимі. Перебуваючи у відлагоджувальному режимі, додаток буде збирати більше інформації у логи і покаже більш детальний стек викликів, якщо виникне виняток. По цій причині, відлагоджувальний режим повинен бути використаний тільки в процесі розробки. За замовчуванням значення `YII_DEBUG` дорівнює false;
* `YII_ENV`: вказує в якому середовищі працює додаток. Дана тема детально розглянута в розділі [Конфігурації](concept-configurations.md#environment-constants).
За замовчуванням значення `YII_ENV` дорівнює `'prod'`, що значить, що додаток працює у виробничому режимі;
* `YII_ENABLE_ERROR_HANDLER`: вказує чи потрібно включати наявний у Yii обробник помилок. За замовчуванням значення даної константи
дорівнює true.
* `YII_DEBUG`: вказує чи працює додаткок у режимі відлагодження ("debug mode"), перебуваючи у якому,
додаток буде збирати більше інформації у логи та покаже більш детальний стек викликів при отриманні виключення.
З цієї причини, режим відлагодження повинен бути використаний тільки в процесі розробки.
За замовчуванням значення `YII_DEBUG` дорівнює `false`.
* `YII_ENV`: вказує в якому середовищі працює додаток. Дана тема детально розглянута у розділі
[Конфігурації](concept-configurations.md#environment-constants). За замовчуванням значення `YII_ENV` дорівнює
`'prod'`, яке означає, що додаток працює у робочому ("production") режимі.
* `YII_ENABLE_ERROR_HANDLER`: вказує чи потрібно увімкнути наявний у Yii обробник помилок.
За замовчуванням значення даної константи дорівнює `true`.
При визначенні константи, ми зазвичай використовуєм наступний код:
@ -105,4 +113,5 @@ if (!defined('YII_DEBUG')) {
Перший варіант є більш коротким і зрозумілим.
Константи мають бути визначені якомога раніше, в самому початку вхідного скрипта, таким чином вони зможуть вплинути на решту PHP файлів які будуть підключатись.
Константи мають бути визначені якомога раніше, на самому початку вхідного скрипта, щоб вони могли вплинути на решту
PHP файлів, які будуть підключатись.

28
docs/guide-uk/structure-overview.md

@ -1,25 +1,27 @@
Огляд
=====
Yii додаток організований згідно шаблону проектування [модель-представлення-подія (MVC)](http://ru.wikipedia.org/wiki/Model-View-Controller).
[Моделі](structure-models.md) являють собою дані, бізнес логіку і бізнес правила; [представлення](structure-views.md)
відповідають за відображення інформації, в тому числі і на основі даних, отриманих з моделей; [контролери](structure-controllers.md)
приймають вхідні дані від користувача і перетворюють їх в зрозумілий для [моделей](structure-models.md) формат і команди, а також відповідають за відображення потрібного представлення.
Додатки Yii організовані згідно шаблону проектування
[модель-представлення-подія (MVC)](http://uk.wikipedia.org/wiki/Модель-вид-контролер).
[Моделі](structure-models.md) являють собою дані, бізнес логіку та бізнес правила;
[представлення](structure-views.md) відповідають за відображення даних моделей;
[контролери](structure-controllers.md) приймають вхідні дані від користувача і перетворюють їх у команди для
[моделей](structure-models.md) та [представлень](structure-views.md).
Окрім MVC, Yii додаток також має наступні сутності:
* [вхідні скрипти](structure-entry-scripts.md): це PHP скрипти, які доступні напряму кінцевому користувачу додатка.
Вони відповідають за запуск та опрацювання вхідного запиту;
Вони відповідають за запуск циклу обробки запиту.
* [додатки](structure-applications.md): це глобально доступні об’єкти, які відповідають за коректну роботу різних
компонентів додатка і їх координацію для обробки запиту;
компонентів додатка і їх координацію для обробки запиту.
* [компоненти додатку](structure-application-components.md): це об’єкти, зареєстровані в додатку і які надають
різноманітні можливості для обробки поточного запиту;
різноманітні можливості для обробки запитів.
* [модулі](structure-modules.md): це самодостатні пакети, що включають в себе повністю всі ресурси для MVC.
Додаток може бути організовано з допомогою декількох модулів;
* [фільтри](structure-filters.md): це код, який повинен бути виконаний до і після оброки запиту контролерами;
* [віджети](structure-widgets.md): це об’єкти, які можуть включати в себе [представлення](structure-views.md).
Вони можуть містити різноманітну логіку і використовуватись в різноманітних представленнях.
Додаток може бути організовано за допомогою декількох модулів.
* [фільтри](structure-filters.md): це код, який повинен бути виконаний до і після обробки запиту контролерами.
* [віджети](structure-widgets.md): це об’єкти, які можуть бути вбудованими у [представлення](structure-views.md).
Вони можуть містити різноманітну логіку і можуть бути повто використаними у різних представленнях.
Нижче на діаграмі наведена структурна схема додатку:
На наступній діаграмі наведена структурна схема додатку:
![Стандартна структура додатку](../guide/images/application-structure.png)
![Статична структура додатку](images/application-structure.png)

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

@ -1,18 +1,22 @@
数据库基础
数据库访问 (DAO)
========
Yii 基于 PHP's PDO建立了一个成熟的数据库访问层。它提供统一的 API 并解决了一些不同 DBMS 产生的使用不利。 Yii 默认支持以下 DBMS :
Yii 包含了一个建立在 PHP PDO 之上的数据访问层 (DAO). DAO为不同的数据库提供了一套统一的API. 其中```ActiveRecord``` 提供了数据库与模型(MVC 中的 M,Model) 的交互,```QueryBuilder``` 用于创建动态的查询语句. DAO提供了简单高效的SQL查询,可以用在与数据库交互的各个地方.
MySQL
MariaDB
SQLite
PostgreSQL
CUBRID: version 9.1.0 or higher.
Oracle
MSSQL: version 2012 或更高版本,如需使用 LIMIT/OFFSET。
配置
Yii 默认支持以下数据库 (DBMS):
- [MySQL](http://www.mysql.com/)
- [MariaDB](https://mariadb.com/)
- [SQLite](http://sqlite.org/)
- [PostgreSQL](http://www.postgresql.org/)
- [CUBRID](http://www.cubrid.org/): 版本 >= 9.3 . (由于PHP PDO 扩展的一个[bug](http://jira.cubrid.org/browse/APIS-658) 引用值会无效,所以你需要在 CUBRID的客户端和服务端都使用 9.3 )
- [Oracle](http://www.oracle.com/us/products/database/overview/index.html)
- [MSSQL](https://www.microsoft.com/en-us/sqlserver/default.aspx): 版本>=2005.
开始使用数据库首先需要配置数据库连接组件,通过添加 db 组件到应用配置实现("基础的" Web 应用是 config/web.php),如下所示:
##配置
开始使用数据库首先需要配置数据库连接组件,通过添加 db 组件到应用配置实现("基础的" Web 应用是 config/web.php),DSN( Data Source Name )是数据源名称,用于指定数据库信息.如下所示:
```php
return [
// ...
'components' => [
@ -34,25 +38,69 @@ return [
],
// ...
];
请参考PHP manual获取更多有关 DSN 格式信息。
```
请参考PHP manual获取更多有关 DSN 格式信息。
配置连接组件后可以使用以下语法访问:
$connection = \Yii::$app->db;
请参考[[yii\db\Connection]]获取可配置的属性列表。也请注意如果需要同时使用多个数据库可以定义 多个 连接组件:
```$connection = \Yii::$app->db;```
请参考```[[yii\db\Connection]]```获取可配置的属性列表。
如果你想通过ODBC连接数据库,则需要配置[[yii\db\Connection::driverName]] 属性,例如:
```
'db' => [
'class' => 'yii\db\Connection',
'driverName' => 'mysql',
'dsn' => 'odbc:Driver={MySQL};Server=localhost;Database=test',
'username' => 'root',
'password' => '',
],
```
注意:如果需要同时使用多个数据库可以定义 多个 连接组件:
```php
return [
// ...
'components' => [
// ...
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=mydatabase',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
],
'secondDb' => [
'class' => 'yii\db\Connection',
'dsn' => 'sqlite:/path/to/database/file',
],
],
// ...
];
```
在代码中通过以下方式使用:
```
$primaryConnection = \Yii::$app->db;
$secondaryConnection = \Yii::$app->secondDb;
如果不想定义数据库连接为应用组件,可以直接初始化使用:
```
如果不想定义数据库连接为全局[应用](structure-application-components.md)组件,可以在代码中直接初始化使用:
```
$connection = new \yii\db\Connection([
'dsn' => $dsn,
'username' => $username,
'password' => $password,
]);
$connection->open();
小提示:如果在创建了连接后需要执行额外的 SQL 查询,可以添加以下代码到应用配置文件:
```
>小提示:如果在创建了连接后需要执行额外的 SQL 查询,可以添加以下代码到应用配置文件:
```
return [
// ...
'components' => [
@ -67,36 +115,48 @@ return [
],
// ...
];
SQL 基础查询
```
一旦有了连接实例就可以通过[[yii\db\Command]]执行 SQL 查询。
##SQL 基础查询
SELECT 查询
一旦有了连接实例就可以通过[[yii\db\Command]]执行 SQL 查询。
###SELECT 查询
查询返回多行:
```
$command = $connection->createCommand('SELECT * FROM post');
$posts = $command->queryAll();
```
返回单行:
```
$command = $connection->createCommand('SELECT * FROM post WHERE id=1');
$post = $command->queryOne();
查询多列值:
```
查询多行单值:
```
$command = $connection->createCommand('SELECT title FROM post');
$titles = $command->queryColumn();
```
查询标量值/计算值:
```
$command = $connection->createCommand('SELECT COUNT(*) FROM post');
$postCount = $command->queryScalar();
UPDATE, INSERT, DELETE 更新、插入和删除等
```
###UPDATE, INSERT, DELETE 更新、插入和删除等
如果执行 SQL 不返回任何数据可使用命令中的 execute 方法:
```
$command = $connection->createCommand('UPDATE post SET status=1 WHERE id=1');
$command->execute();
选择以下考虑到引用了恰当表名和列名的语法是可能的:
```
你可以使用`insert`,`update`,`delete` 方法,这些方法会根据参数生成合适的SQL并执行.
```php
// INSERT
$connection->createCommand()->insert('user', [
'name' => 'Sam',
@ -115,20 +175,27 @@ $connection->createCommand()->update('user', ['status' => 1], 'age > 30')->execu
// DELETE
$connection->createCommand()->delete('user', 'status = 0')->execute();
引用的表名和列名
```
大多数时间都使用以下语法来引用表名和列名:
###引用的表名和列名
$sql = "SELECT COUNT([[$column]]) FROM {{$table}}";
$rowCount = $connection->createCommand($sql)->queryScalar();
In the code above [[X]] will be converted to properly quoted column name while {{Y}} will be converted to properly 以上代码[[X]] 会转变为引用恰当的列名,而{{Y}} 就转变为引用恰当的表名。
大多数时间都使用以下语法来安全地引用表名和列名:
表名有个专用的变体 {{%Y}} ,如果设置了表前缀使用该变体可以自动在表名前添加前缀:
```php
$sql = "SELECT COUNT([[$column]]) FROM {{table}}";
$rowCount = $connection->createCommand($sql)->queryScalar();
```
以上代码`[[$column]]` 会转变为引用恰当的列名,而`{{table}}` 就转变为引用恰当的表名。
表名有个特殊的变量 {{%Y}} ,如果设置了表前缀使用该变体可以自动在表名前添加前缀:
```php
$sql = "SELECT COUNT([[$column]]) FROM {{%$table}}";
$rowCount = $connection->createCommand($sql)->queryScalar();
```
如果在配置文件如下设置了表前缀,以上代码将在 tbl_table 这个表查询结果:
```php
return [
// ...
'components' => [
@ -139,21 +206,30 @@ return [
],
],
];
```
手工引用表名和列名的另一个选择是使用[[yii\db\Connection::quoteTableName()]] 和 [[yii\db\Connection::quoteColumnName()]]:
```php
$column = $connection->quoteColumnName($column);
$table = $connection->quoteTableName($table);
$sql = "SELECT COUNT($column) FROM $table";
$rowCount = $connection->createCommand($sql)->queryScalar();
预处理语句
```
为安全传递查询参数可以使用预处理语句:
###预处理语句
为安全传递查询参数可以使用预处理语句,首先应当使用`:placeholder`占位,再将变量绑定到对应占位符:
```php
$command = $connection->createCommand('SELECT * FROM post WHERE id=:id');
$command->bindValue(':id', $_GET['id']);
$post = $command->query();
```
另一种用法是准备一次预处理语句而执行多次查询:
```php
$command = $connection->createCommand('DELETE FROM post WHERE id=:id');
$command->bindParam(':id', $id);
@ -162,10 +238,15 @@ $command->execute();
$id = 2;
$command->execute();
事务
```
>提示,在执行前绑定变量,然后在每个执行中改变变量的值(一般用在循环中)比较高效.
##事务
当你需要顺序执行多个相关的的`query`时,你可以把他们封装到一个事务中去保护数据一致性.Yii提供了一个简单的接口来实现事务操作.
如下执行 SQL 事务查询语句:
```php
$transaction = $connection->beginTransaction();
try {
$connection->createCommand($sql1)->execute();
@ -175,8 +256,12 @@ try {
} catch(Exception $e) {
$transaction->rollBack();
}
```
我们通过[[yii\db\Connection::beginTransaction()|beginTransaction()]]开始一个事务,通过`try catch` 捕获异常.当执行成功,通过[[yii\db\Transaction::commit()|commit()]]提交事务并结束,当发生异常失败通过[[yii\db\Transaction::rollBack()|rollBack()]]进行事务回滚.
如需要也可以嵌套多个事务:
```php
// 外部事务
$transaction1 = $connection->beginTransaction();
try {
@ -195,33 +280,192 @@ try {
} catch (Exception $e) {
$transaction1->rollBack();
}
操作数据库模式
```
>注意你使用的数据库必须支持`Savepoints`才能正确地执行,以上代码在所有关系数据中都可以执行,但是只有支持`Savepoints`才能保证安全性。
Yii 也支持为事务设置隔离级别`isolation levels`,当执行事务时会使用数据库默认的隔离级别,你也可以为事物指定隔离级别.
Yii 提供了以下常量作为常用的隔离级别
- [[\yii\db\Transaction::READ_UNCOMMITTED]] - 允许读取改变了的还未提交的数据,可能导致脏读、不可重复读和幻读
- [[\yii\db\Transaction::READ_COMMITTED]] - 允许并发事务提交之后读取,可以避免脏读,可能导致重复读和幻读。
- [[\yii\db\Transaction::REPEATABLE_READ]] - 对相同字段的多次读取结果一致,可导致幻读。
- [[\yii\db\Transaction::SERIALIZABLE]] - 完全服从ACID的原则,确保不发生脏读、不可重复读和幻读。
你可以使用以上常量或者使用一个string字符串命令,在对应数据库中执行该命令用以设置隔离级别,比如对于`postgres`有效的命令为`SERIALIZABLE READ ONLY DEFERRABLE`.
>注意:某些数据库只能针对连接来设置事务隔离级别,所以你必须要为连接明确制定隔离级别.目前受影响的数据库:`MSSQL SQLite`
>注意:SQLite 只支持两种事务隔离级别,所以你只能设置`READ UNCOMMITTED` 和 `SERIALIZABLE`.使用其他隔离级别会抛出异常.
>注意:PostgreSQL 不允许在事务开始前设置隔离级别,所以你不能在事务开始时指定隔离级别.你可以在事务开始之后调用[[yii\db\Transaction::setIsolationLevel()]] 来设置.
关于隔离级别[isolation levels]: http://en.wikipedia.org/wiki/Isolation_%28database_systems%29#Isolation_levels
##数据库复制和读写分离
很多数据库支持数据库复制 [database replication](http://en.wikipedia.org/wiki/Replication_(computing)#Database_replication)来提高可用性和响应速度. 在数据库复制中,数据总是从*主服务器* 到 *从服务器*. 所有的插入和更新等写操作在主服务器执行,而读操作在从服务器执行.
通过配置[[yii\db\Connection]]可以实现数据库复制和读写分离.
```php
[
'class' => 'yii\db\Connection',
// 配置主服务器
'dsn' => 'dsn for master server',
'username' => 'master',
'password' => '',
// 配置从服务器
'slaveConfig' => [
'username' => 'slave',
'password' => '',
'attributes' => [
// use a smaller connection timeout
PDO::ATTR_TIMEOUT => 10,
],
],
// 配置从服务器组
'slaves' => [
['dsn' => 'dsn for slave server 1'],
['dsn' => 'dsn for slave server 2'],
['dsn' => 'dsn for slave server 3'],
['dsn' => 'dsn for slave server 4'],
],
]
```
以上的配置实现了一主多从的结构,从服务器用以执行读查询,主服务器执行写入查询,读写分离的功能由后台代码自动完成.调用者无须关心.例如:
```php
// 使用以上配置创建数据库连接对象
$db = Yii::createObject($config);
// 通过从服务器执行查询操作
$rows = $db->createCommand('SELECT * FROM user LIMIT 10')->queryAll();
// 通过主服务器执行更新操作
$db->createCommand("UPDATE user SET username='demo' WHERE id=1")->execute();
```
>注意:通过[[yii\db\Command::execute()]] 执行的查询被认为是写操作,所有使用[[yii\db\Command]]来执行的其他查询方法被认为是读操作.你可以通过`$db->slave`得到当前正在使用能够的从服务器.
`Connection`组件支持从服务器的负载均衡和故障转移,当第一次执行读查询时,会随即选择一个从服务器进行连接,如果连接失败则又选择另一个,如果所有从服务器都不可用,则会连接主服务器。你可以配置[[yii\db\Connection::serverStatusCache|server status cache]]来记住那些不能连接的从服务器,使Yii 在一段时间[[yii\db\Connection::serverRetryInterval].内不会重复尝试连接那些根本不可用的从服务器.
>注意:在上述配置中,每个从服务器连接超时时间被指定为10s. 如果在10s内不能连接,则被认为该服务器已经挂掉.你也可以自定义超时参数.
你也可以配置多主多从的结构,例如:
```php
[
'class' => 'yii\db\Connection',
// 配置主服务器
'masterConfig' => [
'username' => 'master',
'password' => '',
'attributes' => [
// use a smaller connection timeout
PDO::ATTR_TIMEOUT => 10,
],
],
// 配置主服务器组
'masters' => [
['dsn' => 'dsn for master server 1'],
['dsn' => 'dsn for master server 2'],
],
// 配置从服务器
'slaveConfig' => [
'username' => 'slave',
'password' => '',
'attributes' => [
// use a smaller connection timeout
PDO::ATTR_TIMEOUT => 10,
],
],
// 配置从服务器组
'slaves' => [
['dsn' => 'dsn for slave server 1'],
['dsn' => 'dsn for slave server 2'],
['dsn' => 'dsn for slave server 3'],
['dsn' => 'dsn for slave server 4'],
],
]
```
上述配置制定了2个主服务器和4个从服务器.`Connection`组件也支持主服务器的负载均衡和故障转移,与从服务器不同的是,如果所有主服务器都不可用,则会抛出异常.
>注意:当你使用[[yii\db\Connection::masters|masters]]来配置一个或多个主服务器时,`Connection`中关于数据库连接的其他属性(例如:`dsn`, `username`, `password`)都会被忽略.
事务默认使用主服务器的连接,并且在事务执行中的所有操作都会使用主服务器的连接,例如:
```php
// 在主服务器连接上开始事务
$transaction = $db->beginTransaction();
try {
// 所有的查询都在主服务器上执行
$rows = $db->createCommand('SELECT * FROM user LIMIT 10')->queryAll();
$db->createCommand("UPDATE user SET username='demo' WHERE id=1")->execute();
$transaction->commit();
} catch(\Exception $e) {
$transaction->rollBack();
throw $e;
}
```
如果你想在从服务器上执行事务操作则必须要明确地指定,比如:
```php
$transaction = $db->slave->beginTransaction();
```
获得模式信息
有时你想强制使用主服务器来执行读查询,你可以调用`seMaster()`方法.
如下获得[[yii\db\Schema]]实例:
```php
$rows = $db->useMaster(function ($db) {
return $db->createCommand('SELECT * FROM user LIMIT 10')->queryAll();
});
```
你也可以设置`$db->enableSlaves` 为`false`来使所有查询都在主服务器上执行.
##操作数据库模式
###获得模式信息
你可以通过 [[yii\db\Schema]]实例来获取Schema信息:
```php
$schema = $connection->getSchema();
```
该实例包括一系列方法来检索数据库多方面的信息:
```php
$tables = $schema->getTableNames();
完整参考请核对[[yii\db\Schema]]。
```
更多信息请参考[[yii\db\Schema]]
修改模式
###修改模式
除了基础的 SQL 查询,[[yii\db\Command]]还包括一系列方法来修改数据库模式:
createTable, renameTable, dropTable, truncateTable
addColumn, renameColumn, dropColumn, alterColumn
addPrimaryKey, dropPrimaryKey
addForeignKey, dropForeignKey
createIndex, dropIndex
如下使用它们:
- 创建/重命名/删除/清空表
- 增加/重命名/删除/修改字段
- 增加/删除主键
- 增加/删除外键
- 创建/删除索引
使用示例:
// 新建表
```php
// 创建表
$connection->createCommand()->createTable('post', [
'id' => 'pk',
'title' => 'string',
'text' => 'text',
]);
完整参考请核对 [[yii\db\Command]].
```
完整参考请查看[[yii\db\Command]].

2
docs/guide/README.md

@ -112,7 +112,7 @@ Security
* [Authorization](security-authorization.md)
* [Working with Passwords](security-passwords.md)
* **TBD** [Auth Clients](security-auth-clients.md)
* **TBD** [Best Practices](security-best-practices.md)
* [Best Practices](security-best-practices.md)
Caching

12
docs/guide/db-active-record.md

@ -9,7 +9,7 @@ an Active Record instance corresponds to a row of that table, and an attribute o
instance represents the value of a column in that row. Instead of writing raw SQL statements,
you can work with Active Record in an object-oriented fashion to manipulate the data in database tables.
For example, assume `Customer` is an Active Record class is associated with the `customer` table
For example, assume `Customer` is an Active Record class which is associated with the `customer` table
and `name` is a column of the `customer` table. You can write the following code to insert a new
row into the `customer` table:
@ -33,7 +33,7 @@ Below is the list of databases that are currently supported by Yii Active Record
* MySQL 4.1 or later: via [[yii\db\ActiveRecord]]
* PostgreSQL 7.3 or later: via [[yii\db\ActiveRecord]]
* SQLite 2 and 3: via [[yii\db\ActiveRecord]]
* Microsoft SQL Server 2010 or later: via [[yii\db\ActiveRecord]]
* Microsoft SQL Server 2008 or later: via [[yii\db\ActiveRecord]]
* Oracle: via [[yii\db\ActiveRecord]]
* CUBRID 9.3 or later: via [[yii\db\ActiveRecord]] (Note that due to a [bug](http://jira.cubrid.org/browse/APIS-658) in
the cubrid PDO extension, quoting of values will not work, so you need CUBRID 9.3 as the client as well as the server)
@ -346,7 +346,7 @@ of the active record class and set the values there. For example to set the defa
public function init()
{
parent::init();
$this->status = 'active';
$this->status = self::STATUS_ACTIVE;
}
```
@ -700,7 +700,7 @@ if ($customers[0]->orders[0]->customer === $customers[0]) {
> you cannot call [[yii\db\ActiveQuery::inverseOf()]] further.
Joining with Relations
Joining with Relations <a name="joining-with-relations"></a>
----------------------
When working with relational databases, a common task is to join multiple tables and apply various
@ -1020,9 +1020,9 @@ To use Optimistic locking:
1. Create a column to store the version number of each row. The column type should be `BIGINT DEFAULT 0`.
Override the `optimisticLock()` method to return the name of this column.
2. In the Web form that collects the user input, add a hidden field that stores
the lock version of the recording being updated.
the lock version of the record being updated.
3. In the controller action that does the data updating, try to catch the [[\yii\db\StaleObjectException]]
and implement necessary business logic (e.g. merging the changes, prompting stated data)
and implement necessary business logic (e.g. merging the changes, prompting staled data)
to resolve the conflict.
Dirty Attributes

4
docs/guide/db-dao.md

@ -15,7 +15,7 @@ By default, Yii supports the following DBMS:
- [CUBRID](http://www.cubrid.org/): version 9.3 or higher. (Note that due to a [bug](http://jira.cubrid.org/browse/APIS-658) in
the cubrid PDO extension, quoting of values will not work, so you need CUBRID 9.3 as the client as well as the server)
- [Oracle](http://www.oracle.com/us/products/database/overview/index.html)
- [MSSQL](https://www.microsoft.com/en-us/sqlserver/default.aspx): version 2005 or higher.
- [MSSQL](https://www.microsoft.com/en-us/sqlserver/default.aspx): version 2008 or higher.
Configuration
@ -194,7 +194,7 @@ $connection->createCommand()->update('user', ['status' => 1], 'age > 30')->execu
$connection->createCommand()->delete('user', 'status = 0')->execute();
```
Quoting Table and Column Names
Quoting Table and Column Names <a name="quoting-table-and-column-names"></a>
------------------------------
To make column and table names safe to use in queries, you can have Yii properly quote them for you:

53
docs/guide/helper-html.md

@ -9,6 +9,7 @@ of Html helper which provides a set of static methods for handling commonly used
> Note: If your markup is nearly static it's better to use HTML directly. There's no need to wrap absolutely everything
with Html helper calls.
Basics <a name="basics"></a>
----------------------------
@ -39,7 +40,7 @@ In case you need just start tag or just closing tag you can use `Html::beginTag(
Options are used in many methods of Html helper and various widgets. In all these cases there is some extra handling to
know about:
- If a value is null, the corresponding attribute will not be rendered.
- Attributes whose values are of boolean type will be treated as
[boolean attributes](http://www.w3.org/TR/html5/infrastructure.html#boolean-attributes).
@ -49,13 +50,12 @@ know about:
- The "data" attribute could receive JSON. It is handled the same way as array i.e.
`'data' => ['params' => ['id' => 1, 'name' => 'yii'], 'status' => 'ok']` becomes
`data-params='{"id":1,"name":"yii"}' data-status="ok"`.
### Forming class and style dynamically
When building options for HTML tag we're often starting with defaults which we need to modify. In order to add or
remove CSS class you can use the following:
```php
$options = ['class' => 'btn btn-default'];
@ -88,7 +88,7 @@ could be converted there and forth by using [[yii\helpers\Html::cssStyleFromArra
[[yii\helpers\Html::cssStyleToArray()|cssStyleToArray()]]. The [[yii\helpers\Html::removeCssStyle()|removeCssStyle()]]
method accepts an array of properties to remove. If it's going to be a single property it could be specified as string.
Encoding and decoding content <a name="encoding-and-decoding-content"></a>
--------------------------------------------------------------------------
@ -104,7 +104,7 @@ $userName = Html::encode($user->name);
echo $userName;
$decodedUserName = Html::decode($userName);
```
```
Forms
@ -115,6 +115,7 @@ dealing with them.
> Note: consider using [[yii\widgets\ActiveForm|ActiveForm]] in case you deal with models and need validation.
### Open and close a form
Form could be opened with [[yii\helpers\Html::beginForm()|beginForm()]] method like the following:
@ -134,6 +135,7 @@ Closing form tag is simple:
<?= Html::endForm() ?>
```
### Buttons
In order to generate buttons you can use the following code:
@ -154,7 +156,6 @@ There are two groups on input methods. The ones starting with `active` and calle
with it. Active inputs are taking data from model and attribute specified while in case of regular input data is specified
directly.
The most generic methods are:
```php
@ -198,7 +199,7 @@ Dropdown list and list box could be rendered like the following:
First argument is the name of the input, second is the value that's currently selected and third is key-value pairs where
array key is list value and array value is list label.
If you want multiple choices to be selectable, checkbox list is a good match:
```php
@ -213,9 +214,8 @@ If not, use radio list:
<?= Html::activeRadioList($user, 'role', ArrayHelper::map($roleModels, 'id', 'name')) ?>
```
### Labels and errors
### Labels and errors
Same as inputs there are two methods for generating form labels. Active that's taking data from the model and non-active
that accepts data directly:
@ -224,8 +224,8 @@ that accepts data directly:
<?= Html::label('User name', 'username', ['class' => 'label username']) ?>
<?= Html::activeLabel($user, 'username', ['class' => 'label username'])
```
In order to display form errors from a model or models as a summart you could use:
In order to display form errors from a model or models as a summary you could use:
```php
<?= Html::errorSummary($posts, ['class' => 'errors']) ?>
@ -236,11 +236,11 @@ To display individual error:
```php
<?= Html::error($post, 'title', ['class' => 'error']) ?>
```
### Names and values
There are methods to get names, ids and values for input fields based on the model. These are mailly used internally
There are methods to get names, ids and values for input fields based on the model. These are mainly used internally
but could be handy sometimes:
```php
@ -257,7 +257,7 @@ echo Html::getAttributeValue($post, 'title');
echo Html::getAttributeValue($post, '[0]authors[0]');
```
In the above first argument is the model while the second one is attribute expression. In its simplest for it's
In the above first argument is the model while the second one is attribute expression. In its simplest form it's
attribute name but it could be an attribute name prefixed and/or suffixed with array indexes which are mainly used
for tabular input:
@ -271,14 +271,13 @@ In order to get attribute name without suffixes or prefixes one can use the foll
// dates
echo Html::getAttributeName('dates[0]');
```
Styles and scripts
------------------
There two methods to generate tags wrapping embedded styles and scripts:
```php
<?= Html::style('.danger { color: #f00; }') ?>
@ -321,12 +320,13 @@ To link JavaScript file:
Same as with CSS first argument specifies link to the file to be included. Options could be passed as the second argument.
In options you can specify `condition` in the same way as in options for `cssFile`.
Links
-----
There's a method to generate hyperlink conveniently:
```php
<?= Html::a('Profile', ['user/view', 'id' => $id], ['class' => 'profile-link']) ?>
```
@ -336,17 +336,17 @@ The first argument is the title. It's not encoded so if you're using data got fr
what values it accepts. Third argument is array of tag properties.
In you need to generate `mailto` link you can use the following code:
```php
<?= Html::mailto('Contact us', 'admin@example.com') ?>
```
Images
------
In order to generate image tag use the following:
```php
<?= Html::img('@web/images/logo.png', ['alt' => 'My logo']) ?>
@ -357,10 +357,11 @@ generates
Aside [aliases](concept-aliases.md) the first argument can accept routes, parameters and URLs. Same way as
[Url::to()](helper-url.md) does.
Lists
-----
Unordered list could be generated like the following:
```php

89
docs/guide/input-file-upload.md

@ -1,13 +1,12 @@
Uploading Files
===============
> Note: This section is under development.
Uploading files in Yii is done via a form model, its validation rules and some controller code. Let's review what's
required to handle uploads properly.
Uploading files in Yii is done via the a form model, its validation rules and some controller code. Let's review what's needed
to handle uploads properly.
Form model
----------
Uploading single file
---------------------
First of all, you need to create a model that will handle file uploads. Create `models/UploadForm.php` with the following
content:
@ -24,7 +23,7 @@ use yii\web\UploadedFile;
class UploadForm extends Model
{
/**
* @var UploadedFile|Null file attribute
* @var UploadedFile file attribute
*/
public $file;
@ -40,11 +39,10 @@ class UploadForm extends Model
}
```
In the code above, we created a model `UploadForm` with an attribute `$file` that will become `<input type="file">` in
In the code above, we've created a model `UploadForm` with an attribute `file` that will become `<input type="file">` in
the HTML form. The attribute has the validation rule named `file` that uses [[yii\validators\FileValidator|FileValidator]].
Form view
---------
### Form view
Next, create a view that will render the form:
@ -65,10 +63,9 @@ use yii\widgets\ActiveForm;
The `'enctype' => 'multipart/form-data'` is necessary because it allows file uploads. `fileInput()` represents a form
input field.
Controller
----------
### Controller
Now create the controller that connects the form and model together:
Now create the controller that connects the form and the model together:
```php
namespace app\controllers;
@ -98,13 +95,16 @@ class SiteController extends Controller
```
Instead of `model->load(...)`, we are using `UploadedFile::getInstance(...)`. [[\yii\web\UploadedFile|UploadedFile]]
does not run the model validation, rather it only provides information about the uploaded file. Therefore, you need to run the validation manually via `$model->validate()` to trigger the [[yii\validators\FileValidator|FileValidator]] that expects a file:
does not run the model validation, rather it only provides information about the uploaded file. Therefore, you need to run the validation manually via `$model->validate()` to trigger the [[yii\validators\FileValidator|FileValidator]]. The validator expects that
the attribute is an uploaded file, as you see in the core framework code:
```php
$file instanceof UploadedFile || $file->error == UPLOAD_ERR_NO_FILE //in the code framework
if (!$file instanceof UploadedFile || $file->error == UPLOAD_ERR_NO_FILE) {
return [$this->uploadRequired, []];
}
```
If validation is successful, then we're saving the file:
If the validation is successful, then we're saving the file:
```php
$model->file->saveAs('uploads/' . $model->file->baseName . '.' . $model->file->extension);
@ -114,10 +114,13 @@ If you're using the "basic" application template, then folder `uploads` should b
That's it. Load the page and try uploading. Uploads should end up in `basic/web/uploads`.
Additional information
----------------------
Validation
----------
It's often required to adjust validation rules to accept certain files only or require uploading. Below we'll review
some common rule configurations.
### Required rule
### Required
If you need to make the file upload mandatory, use `skipOnEmpty` like the following:
@ -156,14 +159,15 @@ public function rules()
[List of common media types](http://en.wikipedia.org/wiki/Internet_media_type#List_of_common_media_types)
### Validating uploaded image
### Image properties
If you upload an image, [[yii\validators\ImageValidator|ImageValidator]] may come in handy. It verifies if an attribute
received a valid image that can be then either saved or processed using the [Imagine Extension](https://github.com/yiisoft/yii2/tree/master/extensions/imagine).
### Uploading multiple files
Uploading multiple files
------------------------
If you need to download multiple files at once, some adjustments are required.
If you need to upload multiple files at once, some adjustments are required.
Model:
@ -194,15 +198,9 @@ View:
use yii\widgets\ActiveForm;
$form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]);
if ($model->hasErrors()) { //it is necessary to see all the errors for all the files.
echo '<pre>';
print_r($model->getErrors());
echo '</pre>';
}
?>
<?= $form->field($model, 'file[]')->fileInput(['multiple' => '']) ?>
<?= $form->field($model, 'file[]')->fileInput(['multiple' => true]) ?>
<button>Submit</button>
@ -212,7 +210,7 @@ if ($model->hasErrors()) { //it is necessary to see all the errors for all the f
The difference is the following line:
```php
<?= $form->field($model, 'file[]')->fileInput(['multiple' => '']) ?>
<?= $form->field($model, 'file[]')->fileInput(['multiple' => true]) ?>
```
Controller:
@ -232,31 +230,13 @@ class SiteController extends Controller
$model = new UploadForm();
if (Yii::$app->request->isPost) {
$files = UploadedFile::getInstances($model, 'file');
foreach ($files as $file) {
$_model = new UploadForm();
$_model->file = $file;
if ($_model->validate()) {
$_model->file->saveAs('uploads/' . $_model->file->baseName . '.' . $_model->file->extension);
} else {
foreach ($_model->getErrors('file') as $error) {
$model->addError('file', $error);
}
$model->file = UploadedFile::getInstances($model, 'file');
if ($model->file && $model->validate()) {
foreach ($model->file as $file) {
$file->saveAs('uploads/' . $file->baseName . '.' . $file->extension);
}
}
if ($model->hasErrors('file')){
$model->addError(
'file',
count($model->getErrors('file')) . ' of ' . count($files) . ' files not uploaded'
);
}
}
return $this->render('upload', ['model' => $model]);
@ -264,5 +244,6 @@ class SiteController extends Controller
}
```
The difference is using `UploadedFile::getInstances($model, 'file');` instead of `UploadedFile::getInstance($model, 'file');`.
The former returns instances for **all** uploaded files while the latter gives you only a single instance.
There are two differences from single file upload. First is that `UploadedFile::getInstances($model, 'file');` is used
instead of `UploadedFile::getInstance($model, 'file');`. The former returns instances for **all** uploaded files while
the latter gives you only a single instance. The second difference is that we're doing `foreach` and saving each file.

2
docs/guide/input-forms.md

@ -86,7 +86,7 @@ All of the content placed between [[yii\widgets\ActiveForm::begin()|ActiveForm::
As with any widget, you can specify some options as to how the widget should be configured by passing an array to
the `begin` method. In this case, an extra CSS class and identifying ID are passed to be used in the opening `<form>` tag.
In order to create a form element in the form, along with the element's label, and any application JavaScript validation,
In order to create a form element in the form, along with the element's label, and any applicable JavaScript validation,
the [[yii\widgets\ActiveForm::field()|ActiveForm::field()]] method of the Active Form widget is called.
When the invocation of this method is echoed directly, the result is a regular (text) input.
To customize the output, you can chain additional methods to this call:

21
docs/guide/input-validation.md

@ -22,15 +22,6 @@ if ($model->validate()) {
}
```
Behind the scenes, the `validate()` method does the following steps to perform validation:
1. Determine which attributes should be validated by getting the attribute list from [[yii\base\Model::scenarios()]]
using the current [[yii\base\Model::scenario|scenario]]. These attributes are called *active attributes*.
2. Determine which validation rules should be used by getting the rule list from [[yii\base\Model::rules()]]
using the current [[yii\base\Model::scenario|scenario]]. These rules are called *active rules*.
3. Use each active rule to validate each active attribute associated with that rule. If the rule fails,
keep an error message for the attribute in the model.
## Declaring Rules <a name="declaring-rules"></a>
@ -58,7 +49,7 @@ of the following format:
[
// required, specifies which attributes should be validated by this rule.
// For a single attribute, you can use the attribute name directly
// without having it in an array instead of an array
// without having it in an array
['attribute1', 'attribute2', ...],
// required, specifies the type of this rule.
@ -92,13 +83,13 @@ If you do not specify an `on` option, it means the rule will be applied to all s
When the `validate()` method is called, it does the following steps to perform validation:
1. Determine which attributes should be validated by checking the current [[yii\base\Model::scenario|scenario]]
against the scenarios declared in [[yii\base\Model::scenarios()]]. These attributes are the active attributes.
2. Determine which rules should be applied by checking the current [[yii\base\Model::scenario|scenario]]
against the rules declared in [[yii\base\Model::rules()]]. These rules are the active rules.
1. Determine which attributes should be validated by getting the attribute list from [[yii\base\Model::scenarios()]]
using the current [[yii\base\Model::scenario|scenario]]. These attributes are called *active attributes*.
2. Determine which validation rules should be used by getting the rule list from [[yii\base\Model::rules()]]
using the current [[yii\base\Model::scenario|scenario]]. These rules are called *active rules*.
3. Use each active rule to validate each active attribute which is associated with the rule.
The validation rules are evaluated in the order they are listed.
According to the above validation steps, an attribute will be validated if and only if it is
an active attribute declared in `scenarios()` and is associated with one or multiple active rules
declared in `rules()`.

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

@ -73,29 +73,29 @@ the data provider. The displayed table is equipped with sorting and pagination f
Yii grid consists of a number of columns. Depending on column type and settings these are able to present data differently.
These are defined in the columns part of GridView configuration like the following:
These are defined in the `columns` part of GridView configuration like the following:
```php
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
// A simple column defined by the data contained in $dataProvider.
// Data from the model's column1 will be used.
// Simple columns defined by the data contained in $dataProvider.
// Data from the model's column will be used.
'id',
'username',
// More complex one.
[
'class' => 'yii\grid\DataColumn', // can be omitted, default
'class' => 'yii\grid\DataColumn', // can be omitted, as it is the default
'value' => function ($data) {
return $data->name; //$data['name'] for array data, e.g. using SqlDataProvider.
return $data->name; // $data['name'] for array data, e.g. using SqlDataProvider.
},
],
],
]);
```
Note that if the columns part of the configuration isn't specified, Yii tries to show all possible data provider model columns.
Note that if the `columns` part of the configuration isn't specified, Yii tries to show all possible columns of the data provider's model.
### Column classes
@ -111,9 +111,9 @@ echo GridView::widget([
],
```
In addition to column classes provided by Yii that we'll review below you can create your own column classes.
In addition to column classes provided by Yii that we'll review below, you can create your own column classes.
Each column class extends from [[\yii\grid\Column]] so there are some common options you can set while configuring
Each column class extends from [[\yii\grid\Column]] so that there are some common options you can set while configuring
grid columns.
- `header` allows to set content for header row.
@ -151,7 +151,7 @@ echo GridView::widget([
],
[
'attribute' => 'birthday',
'format' => ['date', 'Y-m-d']
'format' => ['date', 'php:Y-m-d']
],
],
]);
@ -159,7 +159,7 @@ echo GridView::widget([
In the above, `text` corresponds to [[\yii\i18n\Formatter::asText()]]. The value of the column is passed as the first
argument. In the second column definition, `date` corresponds to [[\yii\i18n\Formatter::asDate()]]. The value of the
column is, again, passed as the first argument while 'Y-m-d' is used as the second argument value.
column is, again, passed as the first argument while 'php:Y-m-d' is used as the second argument value.
For a list of available formatters see the [section about Data Formatting](output-formatter.md).
@ -256,7 +256,7 @@ A common practice when using [active records](db-active-record.md) is to create
that provides needed functionality (it can be generated for you by Gii). This class defines the validation
rules for the search and provides a `search()` method that will return the data provider.
To add the search capability for the `Post` model, we can create `PostSearch` like in the following example:
To add the search capability for the `Post` model, we can create `PostSearch` like the following example:
```php
<?php
@ -419,14 +419,14 @@ $query->andFilterWhere(['LIKE', 'author.name', $this->getAttribute('author.name'
> ```
> Info: For more information on `joinWith` and the queries performed in the background, check the
> [active record docs on eager and lazy loading](db-active-record.md#lazy-and-eager-loading).
> [active record docs on joining with relations](db-active-record.md#joining-with-relations).
#### Using sql views for filtering, sorting and displaying data
There is also another approach that can be faster and more useful - sql views. For example, if we need to show the gridview
with users and their profiles, we can do so in this way:
```php
```sql
CREATE OR REPLACE VIEW vw_user_info AS
SELECT user.*, user_profile.lastname, user_profile.firstname
FROM user, user_profile
@ -485,7 +485,7 @@ After that you can use this UserView active record with search models, without a
All attributes will be working out of the box. Note that this approach has several pros and cons:
- you don't need to specify different sorting and filtering conditions. Everything works out of the box;
- it can be much faster because of the data size, count of sql queries performed (for each relation you will need an additional query);
- it can be much faster because of the data size, count of sql queries performed (for each relation you will not need any additional query);
- since this is just a simple mapping UI on the sql view it lacks some domain logic that is in your entities, so if you have some methods like `isActive`,
`isDeleted` or others that will influence the UI, you will need to duplicate them in this class too.

6
docs/guide/output-formatter.md

@ -154,10 +154,10 @@ The format for number formatting can be adjusted using the [[yii\i18n\Formatter:
For more advanced configuration, [[yii\i18n\Formatter::numberFormatterOptions]] and [[yii\i18n\Formatter::numberFormatterTextOptions]]
can be used to configure the internally used [NumberFormatter class](http://php.net/manual/en/class.numberformatter.php)
For example to adjust the maximum and minimum value of fraction digits you can configure this property like the following:
For example, to adjust the maximum and minimum value of fraction digits, you can configure [[yii\i18n\Formatter::numberFormatterOptions]] property like the following:
```php
[
'numberFormatterOptions' => [
NumberFormatter::MIN_FRACTION_DIGITS => 0,
NumberFormatter::MAX_FRACTION_DIGITS => 2,
]
@ -191,4 +191,4 @@ In addition to date, time and number formatting, Yii provides a set of other use
For values that are `null` in PHP, the formatter class will print a placeholder instead of an empty string which
defaults to `(not set)` translated to the current application language. You can configure the
[[yii\i18n\Formatter::nullDisplay|nullDisplay]] property to set a custom placeholder.
If you do not you want special handling for `null` values, you can set [[yii\i18n\Formatter::nullDisplay|nullDisplay]] to `null`.
If you do not want special handling for `null` values, you can set [[yii\i18n\Formatter::nullDisplay|nullDisplay]] to `null`.

11
docs/guide/output-theming.md

@ -38,6 +38,17 @@ For example, with a configuration above a themed version of a view file `@app/vi
`@app/themes/basic/site/index.php`. It basically replaces `@app/views` in `@app/views/site/index.php` with
`@app/themes/basic`.
In order to configure theme runtime you can use the following code before rendering a view. Typically it will be
placed in controller:
```php
$this->getView()->theme = Yii::createObject([
'class' => '\yii\base\Theme',
'pathMap' => ['@app/views' => '@app/themes/basic'],
'baseUrl' => '@web/themes/basic',
]);
```
### Theming modules
In order to theme modules, `pathMap` may look like the following:

24
docs/guide/security-authorization.md

@ -90,11 +90,13 @@ matches. This should be an array of controller IDs. The comparison is case-sensi
empty or not set, it means the rule applies to all controllers.
* [[yii\filters\AccessRule::roles|roles]]: specifies which user roles that this rule matches.
Two special roles are recognized, and they are checked via [[yii\web\User::isGuest]]:
Two special roles are recognized, and they are checked via [[yii\web\User::isGuest]]:
- `?`: matches a guest user (not authenticated yet)
- `@`: matches an authenticated user
Using other role names requires RBAC (to be described in the next section), and [[yii\web\User::can()]] will be called.
If this option is empty or not set, it means this rule applies to all roles.
Using other role names requires RBAC (to be described in the next section), and [[yii\web\User::can()]] will be called.
If this option is empty or not set, it means this rule applies to all roles.
* [[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.
@ -202,9 +204,8 @@ return [
The `authManager` can now be accessed via `\Yii::$app->authManager`.
> Tip: By default, [[yii\rbac\PhpManager]] stores RBAC data in three files: `@app/rbac/items.php`, `@app/rbac/assignments.php` and `@app/rbac/rules.php`.
Make sure these files are writable by the Web server process if the authorization needs to be changed online.
Sometimes you will need to create these files manually.
> Tip: By default, [[yii\rbac\PhpManager]] stores RBAC data in files under `@app/rbac/` directory. Make sure the directory
and all the files in it are writable by the Web server process if permissions hierarchy needs to be changed online.
### Building Authorization Data
@ -220,7 +221,7 @@ Building authorization data is all about the following tasks:
Depending on authorization flexibility requirements the tasks above could be done in different ways.
If your permissions hierarchy doesn't change at all and you have a fixed number of users you can create a
[console command](tutorial-console.md#create-command) command that will initialize authorization data once via APIs offered by `authManager`:
[console command](tutorial-console.md#create-command) that will initialize authorization data once via APIs offered by `authManager`:
```php
<?php
@ -272,7 +273,7 @@ After executing the command with `yii rbac/init` we'll get the following hierarc
Author can create post, admin can update post and do everything author can.
If your application allows user signup you need to assign roles to these new users once. For example, in order for all
signed up users to become authors you in advanced application template you need to modify `frontend\models\SignupForm::signup()`
signed up users to become authors in your advanced application template you need to modify `frontend\models\SignupForm::signup()`
as follows:
```php
@ -302,11 +303,6 @@ For applications that require complex access control with dynamically updated au
(i.e. admin panel) may need to be developed using APIs offered by `authManager`.
> Tip: By default, [[yii\rbac\PhpManager]] stores RBAC data in three files: `@app/rbac/items.php`, `@app/rbac/assignments.php` and `@app/rbac/rules.php`.
Make sure these files are writable by the Web server process if the authorization needs to be changed online.
Sometimes you will need to create these files manually.
### Using Rules
As aforementioned, rules add additional constraint to roles and permissions. A rule is a class extending
@ -416,7 +412,7 @@ assign each user to a RBAC role. Let's use an example to show how this can be do
Assume in the user table, you have a `group` column which uses 1 to represent the administrator group and 2 the author group.
You plan to have two RBAC roles `admin` and `author` to represent the permissions for these two groups, respectively.
You can create set up the RBAC data as follows,
You can set up the RBAC data as follows,
```php

168
docs/guide/security-best-practices.md

@ -1,6 +1,164 @@
Security best practice
======================
Security best practices
=======================
> Note: This section is under development.
>
> It has no content yet.
Below we'll review common security principles and describe how to avoid threats when developing applications using Yii.
Basic principles
----------------
There are two main principles when it comes to security no matter which application is being developed:
1. Filter input.
2. Escape output.
### Filter input
Filter input means that input should never be considered safe and you should always check if the value you've got is
actually among allowed ones i.e. if we know that sorting could be done by three fields `title`, `created_at` and `status`
and the field could be supplied via used input it's better to check the value we've got right where we're receiving it.
In terms of basic PHP that would look like the following:
```php
$sortBy = $_GET['sort'];
if (!in_array($sortBy, ['title', 'created_at', 'status'])) {
throw new Exception('Invalid sort value.');
}
```
In Yii, most probably you'll use [form validation](input-validation.md) to do alike checks.
### Escape output
Escape output means that depending on context where we're using data it should be escaped i.e. in context of HTML you
should escape `<`, `>` and alike special characters. In context of JavaScript or SQL it will be different set of characters.
Since it's error-prone to escape everything manually Yii provides various tools to perform escaping for different
contexts.
Avoiding SQL injections
-----------------------
SQL injection happens when query text is formed by concatenating unescaped strings such as the following:
```php
$username = $_GET['username'];
$sql = "SELECT * FROM user WHERE username = '$username'";
```
Instead of supplying correct username attacker could give your applications something like `'; DROP TABLE user; --`.
Resulting SQL will be the following:
```sql
SELECT * FROM user WHERE username = ''; DROP TABLE user; --'
```
This is valid query that will search for users with empty username and then will drop `user` table most probably
resulting in broken website and data loss (you've set up regular backups, right?).
In Yii most of database querying happens via [Active Record](db-active-record.md) which properly uses PDO prepared
statements internally. In case of prepared statements it's not possible to manipulate query as was demonstrated above.
Still, sometimes you need [raw queries](db-dao.md) or [query builder](db-query-builder.md). In this case you should use
safe ways of passing data. If data is used for column values it's preferred to use prepared statements:
```php
// query builder
$userIDs = (new Query())
->select('id')
->from('user')
->where('status=:status', [':status' => $status])
->all();
// DAO
$userIDs = $connection
->createCommand('SELECT id FROM user where status=:status')
->bindValues([':status' => $status])
->queryColumn();
```
If data is used to specify column names or table names the best thing to do is to allow only predefined set of values:
```php
function actionList($orderBy = null)
{
if (!in_array($orderBy, ['name', 'status'])) {
throw new BadRequestHttpException('Only name and status are allowed to order by.')
}
// ...
}
```
In case it's not possible, table and column names should be escaped. Yii has special syntax for such escaping
which allows doing it the same way for all databases it supports:
```php
$sql = "SELECT COUNT([[$column]]) FROM {{table}}";
$rowCount = $connection->createCommand($sql)->queryScalar();
```
You can get details about the syntax in [Quoting Table and Column Names](db-dao.md#quoting-table-and-column-names).
Avoiding XSS
------------
XSS or cross-site scripting happens when output isn't escaped properly when outputting HTML to the browser. For example,
if user can enter his name and instead of `Alexander` he enters `<script>alert('Hello!');</script>`, every page that
outputs user name without escaping it will execute JavaScript `alert('Hello!');` resulting in alert box popping up
in a browser. Depending on website instead of innocent alert such script could send messages using your name or even
perform bank transactions.
Avoiding XSS is quite easy in Yii. There are generally two cases:
1. You want data to be outputted as plain text.
2. You want data to be outputted as HTML.
If all you need is plain text then escaping is as easy as the following:
```php
<?= \yii\helpers\Html::encode($username) ?>
```
If it should be HTML we could get some help from HtmlPurifier:
```php
<?= \yii\helpers\HtmlPurifier::process($description) ?>
```
Note that HtmlPurifier processing is quite heavy so consider adding caching.
Avoiding CSRF
-------------
TBD: what's CSRF, how it works, intro
1. Follow HTTP specification i.e. GET should not change application state.
2. Keep Yii CSRF protection enabled.
TBD: how CSRF protection works
Avoiding file exposure
----------------------
By default server webroot is meant to be pointed to `web` directory where `index.php` is. In case of shared hosting
environments it could be impossible to achieve so we'll end up with all the code, configs and logs in server webroot.
If it's the case don't forget to deny access to everything except `web`. If it can't be done consider hosting your
application elsewhere.
Avoiding debug info and tools at production
-------------------------------------------
In debug mode Yii shows quite verbose errors which are certainly helpful for development. The thing is that these
verbose errors are handy for attacker as well since these could reveal database structure, configuration values and
parts of your code. Never run production applications with `YII_DEBUG` set to `true` in your `index.php`.
You should never enalble Gii at production. It could be used to get information about database structure, code and to
simply rewrite code with what's generated by Gii.
Debug toolbar should be avoided at production unless really necessary. It exposes all the application and config
details possible. If you absolutely need it check twice that access is proerly restricted to your IP only.

1
docs/guide/start-looking-ahead.md

@ -31,3 +31,4 @@ This section will summarize the Yii resources available to help you be more prod
- 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>

12
docs/guide/tutorial-core-validators.md

@ -290,7 +290,17 @@ back to the attribute being validated.
Note that if the filter cannot handle array input, you should set this property to be true. Otherwise some
PHP error might occur.
> Tip: If you want to trim input values, you may directly use [trim](#trim) validator.
> Tip: If you want to trim input values, you may directly use the [trim](#trim) validator.
> Tip: There are many PHP functions that have the signature expected for the `filter` callback.
> For example to apply type casting (using e.g. [intval](http://php.net/manual/en/function.intval.php),
> [boolval](http://php.net/manual/en/function.boolval.php), ...) to ensure a specific type for an attribute,
> you can simply specify the function names of the filter without the need to wrap them in a closure:
>
> ```php
> ['property', 'filter', 'filter' => 'boolval'],
> ['property', 'filter', 'filter' => 'intval'],
> ```
## [[yii\validators\ImageValidator|image]] <a name="image"></a>

4
docs/guide/widget-jui.md

@ -3,7 +3,7 @@ Jquery UI Widgets
> Note: This section is under development.
Yii includes support for the [jQuery UI](http://api.jqueryui.com/) library in an officail extension. jQuery UI is
Yii includes support for the [jQuery UI](http://api.jqueryui.com/) library in an official extension. jQuery UI is
a curated set of user interface interactions, effects, widgets, and themes built on top of the jQuery JavaScript Library.
Installation
@ -45,4 +45,4 @@ framework features. All widgets belong to `\yii\jui` namespace:
- [[yii\jui\SliderInput|SliderInput]]
- [[yii\jui\Sortable|Sortable]]
- [[yii\jui\Spinner|Spinner]]
- [[yii\jui\Tabs|Tabs]]
- [[yii\jui\Tabs|Tabs]]

16
docs/internals-pt-BR/translation-workflow.md

@ -54,7 +54,7 @@ build translation "../docs/guide" "../docs/guide-pt-BR" > report-guide-pt-BR.htm
Antes de iniciar seus trabalhos de tradução certifique-se que o arquivo em qual
irá trabalhar esteja disponível para ser traduzido. Para isso, acesse a
[planilha no Google Docs](https://docs.google.com/spreadsheets/d/17JOpAjkJz2YZCjD6gWaUx32wskGRB-2CdFbed111iys/edit?usp=sharing).
[planilha no Google Docs](https://docs.google.com/spreadsheets/d/1pAMe-qsKK0poEsQwGI2HLFmj4afKSkEUd_1qegU5YqQ).
Regras e Observações
@ -74,19 +74,27 @@ Regras e Observações
- action — ação
- application system - sistema
- application template — template de aplicação
- controller — controller (controlador)
- eager loading — eager loading (carregamento na inicialização)
- lazy loading — lazy loading (carregamento retardado)
- model — model (modelo)
- query builder — query builder (construtor de consulta)
- view — view (visão)
- note — observação
- info — informação
- tip — dica
- warning - atenção
- attribute label - label do atributo
- inline action — ação inline
- standalone action — ação standalone
### Termos Sem Tradução
- active record
- alias
- cache
- CamelCase
- CamelCase, camel-case
- core
- framework
- hash
@ -94,4 +102,6 @@ Regras e Observações
- id
- runtime
- widget
- backend
- frontend
- web service

1
docs/internals/translation-teams.md

@ -39,6 +39,7 @@ Japanese
- Nobuo Kihara 木原伸夫, [@softark](https://github.com/softark), softark@gmail.com
- Tomoki Morita, [@jamband](https://github.com/jamband), tmsongbooks215@gmail.com
- Hisateru Tanaka, [@tanakahisateru](https://github.com/tanakahisateru), tanakahisateru@gmail.com
Russian
-------

8
extensions/apidoc/CHANGELOG.md

@ -1,7 +1,13 @@
Yii Framework 2 apidoc extension Change Log
===========================================
2.0.1 under development
2.0.2 under development
-----------------------
- no changes in this release.
2.0.1 December 07, 2014
-----------------------
- Bug #5623: Fixed crash when a class contains a setter that has no arguments e.g. `setXyz()` (cebe)

3
extensions/apidoc/models/PropertyDoc.php

@ -13,6 +13,9 @@ use yii\apidoc\helpers\PrettyPrinter;
/**
* Represents API documentation information for a `property`.
*
* @property bool $isReadOnly If property is read only. This property is read-only.
* @property bool $isWriteOnly If property is write only. This property is read-only.
*
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/

3
extensions/apidoc/templates/bootstrap/assets/JsSearchAsset.php vendored

@ -7,7 +7,6 @@
namespace yii\apidoc\templates\bootstrap\assets;
use yii\web\AssetBundle;
use yii\web\View;
/**
@ -16,7 +15,7 @@ use yii\web\View;
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
class JsSearchAsset extends AssetBundle
class JsSearchAsset extends \yii\web\AssetBundle
{
public $sourcePath = '@vendor/cebe/js-search';
public $js = [

8
extensions/authclient/CHANGELOG.md

@ -1,7 +1,13 @@
Yii Framework 2 authclient extension Change Log
===============================================
2.0.1 under development
2.0.2 under development
-----------------------
- no changes in this release.
2.0.1 December 07, 2014
-----------------------
- Bug #6000: Fixed CCS for `yii\authclient\widgets\AuthChoice` does not loaded if `popupMode` disabled (klimov-paul)

9
extensions/bootstrap/CHANGELOG.md

@ -1,7 +1,13 @@
Yii Framework 2 bootstrap extension Change Log
==============================================
2.0.1 under development
2.0.2 under development
-----------------------
- no changes in this release.
2.0.1 December 07, 2014
-----------------------
- Bug #5570: `yii\bootstrap\Tabs` would throw an exception if `content` is not set for one of its `items` (RomeroMsk)
@ -9,6 +15,7 @@ Yii Framework 2 bootstrap extension Change Log
- Enh #4146: Added `yii\bootstrap\ButtonDropdown::$containerOptions` (samdark)
- Enh #4181: Added `yii\bootstrap\Modal::$headerOptions` and `yii\bootstrap\Modal::$footerOptions` (tuxoff, samdark)
- Enh #4450: Added `yii\bootstrap\Nav::renderDropdown()` (qiangxue)
- Enh #5494: Added support for specifying a menu header as a configuration array in `yii\bootstrap\Dropdown` (hiltonjanfield, qiangxue)
- Enh #5735: Added `yii\bootstrap\Tabs::renderTabContent` to support manually rendering tab contents (RomeroMsk)
- Enh #5799: `yii\bootstrap\ButtonGroup::buttons` can take all options that are supported by `yii\bootstrap\Button` (aleksanderd)
- Chg #5874: Upgraded Twitter Bootstrap to 3.3.x (samdark)

41
extensions/bootstrap/Dropdown.php

@ -10,6 +10,7 @@ namespace yii\bootstrap;
use yii\base\InvalidConfigException;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;
use yii\helpers\Url;
/**
* Dropdown renders a Bootstrap dropdown menu component.
@ -25,7 +26,8 @@ class Dropdown extends Widget
* or an array representing a single menu with the following structure:
*
* - label: string, required, the label of the item link
* - url: string, optional, the url of the item link. Defaults to "#".
* - url: string|array, optional, the url of the item link. This will be processed by [[Url::to()]].
* If not set, the item will be treated as a menu header when the item has no sub-menu.
* - visible: boolean, optional, whether this menu item is visible. Defaults to true.
* - linkOptions: array, optional, the HTML attributes of the item link.
* - options: array, optional, the HTML attributes of the item.
@ -40,11 +42,6 @@ class Dropdown extends Widget
*/
public $encodeLabels = true;
/**
* @var array the HTML attributes for the widget container tag.
* @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
*/
protected $_containerOptions = [];
/**
* Initializes the widget.
@ -54,7 +51,6 @@ class Dropdown extends Widget
{
parent::init();
Html::addCssClass($this->options, 'dropdown-menu');
$this->_containerOptions = $this->options;
}
/**
@ -62,17 +58,18 @@ class Dropdown extends Widget
*/
public function run()
{
echo $this->renderItems($this->items);
echo $this->renderItems($this->items, $this->options);
BootstrapPluginAsset::register($this->getView());
}
/**
* Renders menu items.
* @param array $items the menu items to be rendered
* @param array $options the container HTML attributes
* @return string the rendering result.
* @throws InvalidConfigException if the label option is not specified in one of the items.
*/
protected function renderItems($items)
protected function renderItems($items, $options = [])
{
$lines = [];
foreach ($items as $i => $item) {
@ -89,18 +86,28 @@ class Dropdown extends Widget
}
$encodeLabel = isset($item['encode']) ? $item['encode'] : $this->encodeLabels;
$label = $encodeLabel ? Html::encode($item['label']) : $item['label'];
$options = ArrayHelper::getValue($item, 'options', []);
$itemOptions = ArrayHelper::getValue($item, 'options', []);
$linkOptions = ArrayHelper::getValue($item, 'linkOptions', []);
$linkOptions['tabindex'] = '-1';
$content = Html::a($label, ArrayHelper::getValue($item, 'url', '#'), $linkOptions);
if (!empty($item['items'])) {
unset($this->_containerOptions['id']);
$content .= $this->renderItems($item['items']);
Html::addCssClass($options, 'dropdown-submenu');
$url = array_key_exists('url', $item) ? $item['url'] : null;
if (empty($item['items'])) {
if ($url === null) {
$content = $label;
Html::addCssClass($itemOptions, 'dropdown-header');
} else {
$content = Html::a($label, $url, $linkOptions);
}
} else {
$submenuOptions = $options;
unset($submenuOptions['id']);
$content = Html::a($label, $url === null ? '#' : $url, $linkOptions)
. $this->renderItems($item['items'], $submenuOptions);
Html::addCssClass($itemOptions, 'dropdown-submenu');
}
$lines[] = Html::tag('li', $content, $options);
$lines[] = Html::tag('li', $content, $itemOptions);
}
return Html::tag('ul', implode("\n", $lines), $this->_containerOptions);
return Html::tag('ul', implode("\n", $lines), $options);
}
}

8
extensions/codeception/CHANGELOG.md

@ -1,7 +1,13 @@
Yii Framework 2 Codeception extension Change Log
================================================
2.0.1 under development
2.0.2 under development
-----------------------
- no changes in this release.
2.0.1 December 07, 2014
-----------------------
- no changes in this release.

8
extensions/composer/CHANGELOG.md

@ -1,7 +1,13 @@
Yii Framework 2 composer extension Change Log
=============================================
2.0.1 under development
2.0.2 under development
-----------------------
- no changes in this release.
2.0.1 December 07, 2014
-----------------------
- no changes in this release.

3
extensions/composer/Installer.php

@ -176,6 +176,9 @@ class Installer extends LibraryInstaller
protected function saveExtensions(array $extensions)
{
$file = $this->vendorDir . '/' . self::EXTENSION_FILE;
if (!file_exists(dirname($file))) {
mkdir(dirname($file), 0777, true);
}
$array = str_replace("'<vendor-dir>", '$vendorDir . \'', var_export($extensions, true));
file_put_contents($file, "<?php\n\n\$vendorDir = dirname(__DIR__);\n\nreturn $array;\n");
// invalidate opcache of extensions.php if exists

9
extensions/debug/CHANGELOG.md

@ -1,7 +1,14 @@
Yii Framework 2 debug extension Change Log
==========================================
2.0.1 under development
2.0.2 under development
-----------------------
- Bug #4820: Fixed reading incomplete debug index data in case of high request concurrency (martingeorg, samdark)
- Chg #6572: Allow panels to stay even if they do not receive any debug data (qiangxue)
2.0.1 December 07, 2014
-----------------------
- Bug #5402: Debugger was not loading when there were closures in asset classes (samdark)

15
extensions/debug/controllers/DefaultController.php

@ -118,7 +118,17 @@ class DefaultController extends Controller
clearstatcache();
}
$indexFile = $this->module->dataPath . '/index.data';
if (is_file($indexFile) && is_readable($indexFile) && ($content = file_get_contents($indexFile)) !== false) {
$content = '';
$fp = @fopen($indexFile, 'r');
if ($fp !== false) {
@flock($fp, LOCK_SH);
$content = fread($fp, filesize($indexFile));
@flock($fp, LOCK_UN);
fclose($fp);
}
if ($content !== '') {
$this->_manifest = array_reverse(unserialize($content), true);
} else {
$this->_manifest = [];
@ -142,9 +152,6 @@ class DefaultController extends Controller
if (isset($data[$id])) {
$panel->tag = $tag;
$panel->load($data[$id]);
} else {
// remove the panel since it has not received any data
unset($this->module->panels[$id]);
}
}
$this->summary = $data['summary'];

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

Loading…
Cancel
Save