Browse Source

Merge branch 'master' into 2.1

# Conflicts:
#	framework/UPGRADE.md
#	framework/behaviors/SluggableBehavior.php
tags/3.0.0-alpha1
Alexander Makarov 8 years ago
parent
commit
a10365a3db
  1. 27
      docs/guide-es/concept-aliases.md
  2. 939
      docs/guide-es/db-migrations.md
  3. 67
      docs/guide-es/glossary.md
  4. 142
      docs/guide-es/helper-array.md
  5. 71
      docs/guide-es/helper-url.md
  6. 527
      docs/guide-es/images/application-lifecycle.graphml
  7. BIN
      docs/guide-es/images/application-lifecycle.png
  8. 368
      docs/guide-es/images/rbac-access-check-1.graphml
  9. BIN
      docs/guide-es/images/rbac-access-check-1.png
  10. 368
      docs/guide-es/images/rbac-access-check-2.graphml
  11. BIN
      docs/guide-es/images/rbac-access-check-2.png
  12. 368
      docs/guide-es/images/rbac-access-check-3.graphml
  13. BIN
      docs/guide-es/images/rbac-access-check-3.png
  14. 312
      docs/guide-es/images/rbac-hierarchy-1.graphml
  15. BIN
      docs/guide-es/images/rbac-hierarchy-1.png
  16. 368
      docs/guide-es/images/rbac-hierarchy-2.graphml
  17. BIN
      docs/guide-es/images/rbac-hierarchy-2.png
  18. BIN
      docs/guide-es/images/tutorial-console-help.png
  19. 208
      docs/guide-es/input-file-upload.md
  20. 714
      docs/guide-es/input-validation.md
  21. 44
      docs/guide-es/intro-upgrade-from-v1.md
  22. 98
      docs/guide-es/output-client-scripts.md
  23. 72
      docs/guide-es/output-pagination.md
  24. 44
      docs/guide-es/rest-authentication.md
  25. 19
      docs/guide-es/rest-error-handling.md
  26. 5
      docs/guide-es/rest-response-formatting.md
  27. 55
      docs/guide-es/runtime-handling-errors.md
  28. 527
      docs/guide-es/security-authorization.md
  29. 31
      docs/guide-es/security-passwords.md
  30. 89
      docs/guide-es/start-databases.md
  31. 2
      docs/guide-es/start-hello.md
  32. 155
      docs/guide-es/start-installation.md
  33. 53
      docs/guide-es/start-looking-ahead.md
  34. 18
      docs/guide-es/start-workflow.md
  35. 383
      docs/guide-es/structure-views.md
  36. 49
      docs/guide-es/test-environment-setup.md
  37. 379
      docs/guide-es/test-fixtures.md
  38. 11
      docs/guide-es/test-functional.md
  39. 25
      docs/guide-es/test-unit.md
  40. 6
      docs/guide-es/tutorial-core-validators.md
  41. 231
      docs/guide-es/tutorial-mailing.md
  42. 55
      docs/guide-es/tutorial-start-from-scratch.md
  43. 49
      docs/guide-es/tutorial-template-engines.md
  44. 118
      docs/guide-es/tutorial-yii-integration.md
  45. 143
      docs/guide-id/start-hello.md
  46. 238
      docs/guide-id/start-installation.md
  47. 102
      docs/guide-id/start-workflow.md
  48. 3
      docs/guide-ja/README.md
  49. 4
      docs/guide-ja/concept-di-container.md
  50. 7
      docs/guide-ja/db-migrations.md
  51. 21
      docs/guide-ja/db-query-builder.md
  52. 4
      docs/guide-ja/input-forms.md
  53. 24
      docs/guide-ja/input-validation.md
  54. 15
      docs/guide-ja/output-data-widgets.md
  55. 2
      docs/guide-ja/runtime-sessions-cookies.md
  56. 52
      docs/guide-ja/security-best-practices.md
  57. 68
      docs/guide-ja/security-cryptography.md
  58. 14
      docs/guide-ja/security-overview.md
  59. 122
      docs/guide-ja/security-passwords.md
  60. 4
      docs/guide-ja/start-installation.md
  61. 2
      docs/guide-ru/db-migrations.md
  62. 2
      docs/guide-ru/start-workflow.md
  63. 2
      docs/guide-ru/structure-application-components.md
  64. 3
      docs/guide/README.md
  65. 2
      docs/guide/concept-di-container.md
  66. 2
      docs/guide/db-active-record.md
  67. 6
      docs/guide/db-migrations.md
  68. 20
      docs/guide/db-query-builder.md
  69. 25
      docs/guide/input-validation.md
  70. 16
      docs/guide/output-data-widgets.md
  71. 2
      docs/guide/runtime-sessions-cookies.md
  72. 51
      docs/guide/security-best-practices.md
  73. 66
      docs/guide/security-cryptography.md
  74. 14
      docs/guide/security-overview.md
  75. 125
      docs/guide/security-passwords.md
  76. 4
      docs/guide/start-installation.md
  77. 4
      docs/guide/test-environment-setup.md
  78. 6
      docs/internals-ja/core-code-style.md
  79. 2
      docs/internals-ja/git-workflow.md
  80. 3
      docs/internals/core-code-style.md
  81. 19
      framework/CHANGELOG.md
  82. 5
      framework/UPGRADE.md
  83. 2
      framework/assets/yii.gridView.js
  84. 28
      framework/base/ActionFilter.php
  85. 1
      framework/base/Configurable.php
  86. 2
      framework/base/Controller.php
  87. 3
      framework/behaviors/AttributeBehavior.php
  88. 9
      framework/behaviors/BlameableBehavior.php
  89. 8
      framework/behaviors/SluggableBehavior.php
  90. 3
      framework/behaviors/TimestampBehavior.php
  91. 2
      framework/caching/migrations/schema-pgsql.sql
  92. 2
      framework/captcha/Captcha.php
  93. 2
      framework/console/ErrorHandler.php
  94. 4
      framework/console/controllers/CacheController.php
  95. 2
      framework/console/controllers/FixtureController.php
  96. 34
      framework/console/controllers/MessageController.php
  97. 4
      framework/console/controllers/MigrateController.php
  98. 2
      framework/console/controllers/ServeController.php
  99. 7
      framework/data/ArrayDataProvider.php
  100. 2
      framework/db/ActiveQuery.php
  101. Some files were not shown because too many files have changed in this diff Show More

27
docs/guide-es/concept-aliases.md

@ -1,15 +1,17 @@
Alias
=====
Los alias son utilizados para representar las rutas de archivos o URLs para evitar su [hard-coding](http://es.wikipedia.org/wiki/Hard_code)
en tu código. Un alias debe comenzar con un cáracter `@` para que así pueda ser diferenciado de las rutas de archivos y URLs.
Por ejemplo, el alias `@yii` representa la ruta de instalación de la librería Yii, mientras que `@web` representa la
URL base la aplicación que actualmente se está ejecutando.
Loa alias son utilizados para representar rutas o URLs de manera que no tengas que escribir explícitamente rutas absolutas o URLs en tu
proyecto. Un alias debe comenzar con el signo `@` para ser diferenciado de una ruta normal de archivo y de URLs. Los alias definidos
sin el `@` del principio, serán prefijados con el signo `@`.
Definiendo Alias <span id="defining-aliases"></span>
----------------
Yii trae disponibles varios alias predefinidos. Por ejemplo, el alias `@yii` representa la ruta de instalación del
framework Yii; `@web` representa la URL base para la aplicación Web ejecutándose.
Puedes llamar a [[Yii::setAlias()]] para definir un alias para una determinada ruta de archivo o URL. Por ejemplo,
Definir Alias <span id="defining-aliases"></span>
-------------
Para definir un alias puedes llamar a [[Yii::setAlias()]] para una determinada ruta de archivo o URL. Por ejemplo,
```php
// un alias de una ruta de archivos
@ -83,9 +85,10 @@ Si `@foo/bar` no está definido como un alias de raíz, la última declaración
Usando Alias <span id="using-aliases"></span>
------------
Los alias son utilizados en muchos lugares en Yii sin necesidad de llamar [[Yii::getAlias()]] para convertirlos en rutas/URLs.
Por ejemplo, [[yii\caching\FileCache::cachePath]] puede aceptar tanto una ruta de archivo como un alias que represente
la ruta de archivo, gracias al prefijo `@` el cual permite diferenciar una ruta de archivo de un alias.
Los alias son utilizados en muchos lugares en Yii sin necesidad de llamar [[Yii::getAlias()]] para convertirlos
en rutas/URLs. Por ejemplo, [[yii\caching\FileCache::cachePath]] puede aceptar tanto una ruta de archivo como un alias
que represente la ruta de archivo, gracias al prefijo `@` el cual permite diferenciar una ruta de archivo
de un alias.
```php
use yii\caching\FileCache;
@ -121,10 +124,10 @@ mientras que el resto de los alias están definidos en el constructor de la apli
Alias en Extensiones <span id="extension-aliases"></span>
--------------------
Un alias se define automaticamente por cada [extensión](structure-extensions.md) que ha sido instalada a través de Composer.
Un alias se define automáticamente por cada [extensión](structure-extensions.md) que ha sido instalada a través de Composer.
El alias es nombrado tras el `namespace` de raíz de la extensión instalada tal y como está declarada en su archivo `composer.json`,
y representa el directorio raíz de la extensión. Por ejemplo, si instalas la extensión `yiisoft/yii2-jui`, tendrás
automaticamente definido el alias `@yii/jui` durante la etapa [bootstrapping](runtime-bootstrapping.md) de la aplicación:
automáticamente definido el alias `@yii/jui` durante la etapa [bootstrapping](runtime-bootstrapping.md) de la aplicación:
```php
Yii::setAlias('@yii/jui', 'VendorPath/yiisoft/yii2-jui');

939
docs/guide-es/db-migrations.md

@ -0,0 +1,939 @@
Migración de Base de Datos
==========================
Durante el curso de desarrollo y mantenimiento de una aplicación con base de datos, la estructura de dicha base de datos
evoluciona tanto como el código fuente. Por ejemplo, durante el desarrollo de una aplicación,
una nueva tabla podría ser necesaria; una vez que la aplicación se encuentra en producción, podría descrubrirse
que debería crearse un índice para mejorar el tiempo de ejecución de una consulta; y así sucesivamente. Debido a los cambios en la estructura de la base de datos
a menudo se requieren cambios en el código, Yii soporta la característica llamada *migración de base de datos*, la cual permite
tener un seguimiento de esos cambios en término de *migración de base de datos*, cuyo versionado es controlado
junto al del código fuente.
Los siguientes pasos muestran cómo una migración puede ser utilizada por un equipo durante el desarrollo:
1. Tim crea una nueva migración (por ej. crea una nueva table, cambia la definición de una columna, etc.).
2. Tim hace un commit con la nueva migración al sistema de control de versiones (por ej. Git, Mercurial).
3. Doug actualiza su repositorio desde el sistema de control de versiones y recibe la nueva migración.
4. Doug aplica dicha migración a su base de datos local de desarrollo, de ese modo sincronizando su base de datos
y reflejando los cambios que hizo Tim.
Los siguientes pasos muestran cómo hacer una puesta en producción con una migración de base de datos:
1. Scott crea un tag de lanzamiento en el repositorio del proyecto que contiene algunas migraciones de base de datos.
2. Scott actualiza el código fuente en el servidor de producción con el tag de lanzamiento.
3. Scott aplica cualquier migración de base de datos acumulada a la base de datos de producción.
Yii provee un grupo de herramientas de línea de comandos que te permite:
* crear nuevas migraciones;
* aplicar migraciones;
* revertir migraciones;
* re-aplicar migraciones;
* mostrar el historial y estado de migraciones.
Todas esas herramientas son accesibles a través del comando `yii migrate`. En esta sección describiremos en detalle
cómo lograr varias tareas utilizando dichas herramientas. Puedes a su vez ver el uso de cada herramienta a través del comando
de ayuda `yii help migrate`.
> Tip: las migraciones pueden no sólo afectar un esquema de base de datos sino también ajustar datos existentes para que encajen en el nuevo esquema, crear herencia RBAC
o también limpiar el cache.
## Creando Migraciones <span id="creating-migrations"></span>
Para crear una nueva migración, ejecuta el siguiente comando:
```
yii migrate/create <name>
```
El argumento requerido `name` da una pequeña descripción de la nueva migración. Por ejemplo, si
la migración se trata acerca de crear una nueva tabla llamada *news*, podrías utilizar el nombre `create_news_table`
y ejecutar el siguiente comando:
```
yii migrate/create create_news_table
```
> Note: Debido a que el argumento `name` será utilizado como parte del nombre de clase de la migración generada,
sólo debería contener letras, dígitos, y/o guines bajos.
El comando anterior un nuevo archivo de clase PHP llamado `m150101_185401_create_news_table.php`
en el directorio `@app/migrations`. El archivo contendrá el siguiente código, que principalmente declara
una clase de tipo migración `m150101_185401_create_news_table` con el siguiente esqueleto de código:
```php
<?php
use yii\db\Migration;
class m150101_185401_create_news_table extends Migration
{
public function up()
{
}
public function down()
{
echo "m101129_185401_create_news_table cannot be reverted.\n";
return false;
}
/*
// Use safeUp/safeDown to run migration code within a transaction
public function safeUp()
{
}
public function safeDown()
{
}
*/
}
```
Cada migración de base de datos es definida como una clase PHP que extiende de [[yii\db\Migration]]. La nombre de clase
de la migración es generado automáticamente en el formato `m<YYMMDD_HHMMSS>_<Name>`, donde
* `<YYMMDD_HHMMSS>` se refiere a la marca de tiempo UTC en la cual el comando de migración fue ejecutado.
* `<Name>` es el mismo valor del argumento `name` provisto al ejecutar el comando.
En la clase de la migración, se espera que tu escribas código en el método `up()`, que realiza los cambios en la base de datos.
Podrías también querer introducir código en el método `down()`, que debería revertir los cambios realizados por `up()`. El método `up()` es llamado
cuando actualizas la base de datos con esta migración, mientras que el método `down()` es llamado cuando reviertes dicha migración.
El siguiente código muestra cómo podrías implementar la clase de migración para crear la tabla `news`:
```php
<?php
use yii\db\Schema;
use yii\db\Migration;
class m150101_185401_create_news_table extends Migration
{
public function up()
{
$this->createTable('news', [
'id' => Schema::TYPE_PK,
'title' => Schema::TYPE_STRING . ' NOT NULL',
'content' => Schema::TYPE_TEXT,
]);
}
public function down()
{
$this->dropTable('news');
}
}
```
> Info: No todas las migraciones son reversibles. Por ejemplo, si el método `up()` elimina un registro en una tabla, podrías
no ser capáz de recuperarla en el método `down()`. A veces, podrías ser simplemente demasiado perezoso para implementar
el método `down()`, debido a que no es muy común revertir migraciones de base de datos. En este caso, deberías devolver
`false` en el método `down()` para indicar que dicha migración no es reversible.
La clase de migración de base de datos [[yii\db\Migration]] expone una conexión a la base de datos mediante la propiedad [[yii\db\Migration::db|db]].
Puedes utilizar esto para manipular el esquema de la base de datos utilizando métodos como se describen en
[Trabajando con Esquemas de Base de Datos](db-dao.md#working-with-database-schema-).
En vez de utilizar tipos físicos, al crear tablas o columnas deberías utilizar los *tipos abstractos*
así las migraciones son independientes de algún DBMS específico. La clase [[yii\db\Schema]] define
un grupo de constantes que representan los tipos abstractos soportados. Dichas constantes son llamadas utilizando el formato
de `TYPE_<Name>`. Por ejemplo, `TYPE_PK` se refiere al tipo clave primaria auto-incremental; `TYPE_STRING`
se refiere al tipo string. Cuando se aplica una migración a una base de datos en particular, los tipos abstractos
serán traducidos a los tipos físicos correspondientes. En el caso de MySQL, `TYPE_PK` será transformado
en `int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY`, mientras `TYPE_STRING` se vuelve `varchar(255)`.
Puedes agregar restricciones adicionales al utilizar tipos abstractos. En el ejemplo anterior, ` NOT NULL` es agregado
a `Schema::TYPE_STRING` para especificar que la columna no puede ser null.
> Info: El mapeo entre tipos abstractos y tipos físicos es especificado en
la propiedad [[yii\db\QueryBuilder::$typeMap|$typeMap]] en cada clase concreta `QueryBuilder`.
Desde la versión 2.0.6, puedes hacer uso del recientemente introducido generador de esquemas, el cual provee una forma más conveniente de definir las columnas.
De esta manera, la migración anterior podría ser escrita así:
```php
<?php
use yii\db\Migration;
class m150101_185401_create_news_table extends Migration
{
public function up()
{
$this->createTable('news', [
'id' => $this->primaryKey(),
'title' => $this->string()->notNull(),
'content' => $this->text(),
]);
}
public function down()
{
$this->dropTable('news');
}
}
```
Existe una lista de todos los métodos disponibles para la definición de tipos de columna en la API de la documentación de [[yii\db\SchemaBuilderTrait]].
## Generar Migraciones <span id="generating-migrations"></span>
Desde la versión 2.0.7 la consola provee una manera muy conveniente de generar migraciones.
Si el nombre de la migración tiene una forma especial, por ejemplo `create_xxx` o `drop_xxx` entonces el archivo de la migración generada
contendrá código extra, en este caso para crear/eliminar tablas.
A continuación se describen todas estas variantes.
### Crear Tabla
```php
yii migrate/create create_post
```
esto genera
```php
/**
* Handles the creation for table `post`.
*/
class m150811_220037_create_post extends Migration
{
/**
* @inheritdoc
*/
public function up()
{
$this->createTable('post', [
'id' => $this->primaryKey()
]);
}
/**
* @inheritdoc
*/
public function down()
{
$this->dropTable('post');
}
}
```
Para crear las columnas en ese momento, las puedes especificar vía la opción `--fields`.
```php
yii migrate/create create_post --fields="title:string,body:text"
```
genera
```php
/**
* Handles the creation for table `post`.
*/
class m150811_220037_create_post extends Migration
{
/**
* @inheritdoc
*/
public function up()
{
$this->createTable('post', [
'id' => $this->primaryKey(),
'title' => $this->string(),
'body' => $this->text(),
]);
}
/**
* @inheritdoc
*/
public function down()
{
$this->dropTable('post');
}
}
```
Puedes especificar más parámetros para las columnas.
```php
yii migrate/create create_post --fields="title:string(12):notNull:unique,body:text"
```
genera
```php
/**
* Handles the creation for table `post`.
*/
class m150811_220037_create_post extends Migration
{
/**
* @inheritdoc
*/
public function up()
{
$this->createTable('post', [
'id' => $this->primaryKey(),
'title' => $this->string(12)->notNull()->unique(),
'body' => $this->text()
]);
}
/**
* @inheritdoc
*/
public function down()
{
$this->dropTable('post');
}
}
```
> Note: la clave primaria es automáticamente agragada y llamada `id` por defecto. Si quieres utilizar otro nombre puedes
> especificarlo así `--fields="name:primaryKey"`.
#### Claves Foráneas
Desde 2.0.8 el generador soporta claves foráneas utilizando la palabra clave `foreignKey`.
```php
yii migrate/create create_post --fields="author_id:integer:notNull:foreignKey(user),category_id:integer:defaultValue(1):foreignKey,title:string,body:text"
```
genera
```php
/**
* Handles the creation for table `post`.
* Has foreign keys to the tables:
*
* - `user`
* - `category`
*/
class m160328_040430_create_post extends Migration
{
/**
* @inheritdoc
*/
public function up()
{
$this->createTable('post', [
'id' => $this->primaryKey(),
'author_id' => $this->integer()->notNull(),
'category_id' => $this->integer()->defaultValue(1),
'title' => $this->string(),
'body' => $this->text(),
]);
// creates index for column `author_id`
$this->createIndex(
'idx-post-author_id',
'post',
'author_id'
);
// add foreign key for table `user`
$this->addForeignKey(
'fk-post-author_id',
'post',
'author_id',
'user',
'id',
'CASCADE'
);
// creates index for column `category_id`
$this->createIndex(
'idx-post-category_id',
'post',
'category_id'
);
// add foreign key for table `category`
$this->addForeignKey(
'fk-post-category_id',
'post',
'category_id',
'category',
'id',
'CASCADE'
);
}
/**
* @inheritdoc
*/
public function down()
{
// drops foreign key for table `user`
$this->dropForeignKey(
'fk-post-author_id',
'post'
);
// drops index for column `author_id`
$this->dropIndex(
'idx-post-author_id',
'post'
);
// drops foreign key for table `category`
$this->dropForeignKey(
'fk-post-category_id',
'post'
);
// drops index for column `category_id`
$this->dropIndex(
'idx-post-category_id',
'post'
);
$this->dropTable('post');
}
}
```
La posición de la palabra clave `foreignKey` en la descripción de la columna
no cambia el código generado. Esto significa:
- `author_id:integer:notNull:foreignKey(user)`
- `author_id:integer:foreignKey(user):notNull`
- `author_id:foreignKey(user):integer:notNull`
Todas generan el mismo código.
La palabra clave `foreignKey` puede tomar un parámetro entre paréntesis el cual
será el nombre de la tabla relacionada por la clave foránea generada. Si no se pasa ningún parámetro
el nombre de la tabla será deducido en base al nombre de la columna.
En el ejemplo anterior `author_id:integer:notNull:foreignKey(user)` generará
una columna llamada `author_id` con una clave foránea a la tabla `user` mientras
`category_id:integer:defaultValue(1):foreignKey` generará
`category_id` con una clave foránea a la tabla `category`.
### Eliminar Tabla
```php
yii migrate/create drop_post --fields="title:string(12):notNull:unique,body:text"
```
genera
```php
class m150811_220037_drop_post extends Migration
{
public function up()
{
$this->dropTable('post');
}
public function down()
{
$this->createTable('post', [
'id' => $this->primaryKey(),
'title' => $this->string(12)->notNull()->unique(),
'body' => $this->text()
]);
}
}
```
### Agregar Columna
Si el nombre de la migración está en la forma `add_xxx_to_yyy` entonces el archivo generado contendrá
las declaraciones `addColumn` y `dropColumn` necesarias.
Para agregar una columna:
```php
yii migrate/create add_position_to_post --fields="position:integer"
```
genera
```php
class m150811_220037_add_position_to_post extends Migration
{
public function up()
{
$this->addColumn('post', 'position', $this->integer());
}
public function down()
{
$this->dropColumn('post', 'position');
}
}
```
### Eliminar Columna
Si el nombre de la migración está en la forma `drop_xxx_from_yyy` entonces el archivo generado contendrá
las declaraciones `addColumn` y `dropColumn` necesarias.
```php
yii migrate/create drop_position_from_post --fields="position:integer"
```
genera
```php
class m150811_220037_drop_position_from_post extends Migration
{
public function up()
{
$this->dropColumn('post', 'position');
}
public function down()
{
$this->addColumn('post', 'position', $this->integer());
}
}
```
### Agregar Tabla de Unión
Si el nombre de la migración está en la forma `create_junction_xxx_and_yyy` entonces se generará el código necesario
para una tabla de unión.
```php
yii migrate/create create_junction_post_and_tag --fields="created_at:dateTime"
```
genera
```php
/**
* Handles the creation for table `post_tag`.
* Has foreign keys to the tables:
*
* - `post`
* - `tag`
*/
class m160328_041642_create_junction_post_and_tag extends Migration
{
/**
* @inheritdoc
*/
public function up()
{
$this->createTable('post_tag', [
'post_id' => $this->integer(),
'tag_id' => $this->integer(),
'created_at' => $this->dateTime(),
'PRIMARY KEY(post_id, tag_id)',
]);
// creates index for column `post_id`
$this->createIndex(
'idx-post_tag-post_id',
'post_tag',
'post_id'
);
// add foreign key for table `post`
$this->addForeignKey(
'fk-post_tag-post_id',
'post_tag',
'post_id',
'post',
'id',
'CASCADE'
);
// creates index for column `tag_id`
$this->createIndex(
'idx-post_tag-tag_id',
'post_tag',
'tag_id'
);
// add foreign key for table `tag`
$this->addForeignKey(
'fk-post_tag-tag_id',
'post_tag',
'tag_id',
'tag',
'id',
'CASCADE'
);
}
/**
* @inheritdoc
*/
public function down()
{
// drops foreign key for table `post`
$this->dropForeignKey(
'fk-post_tag-post_id',
'post_tag'
);
// drops index for column `post_id`
$this->dropIndex(
'idx-post_tag-post_id',
'post_tag'
);
// drops foreign key for table `tag`
$this->dropForeignKey(
'fk-post_tag-tag_id',
'post_tag'
);
// drops index for column `tag_id`
$this->dropIndex(
'idx-post_tag-tag_id',
'post_tag'
);
$this->dropTable('post_tag');
}
}
```
### Migraciones Transaccionales <span id="transactional-migrations"></span>
Al ejecutar migraciones complejas de BD, es importante asegurarse que todas las migraciones funcionen o fallen como una unidad
así la base de datos puede mantener integridad y consistencia. Para alcanzar este objetivo, se recomienda que
encierres las operación de la BD de cada migración en una [transacción](db-dao.md#performing-transactions).
Una manera simple de implementar migraciones transaccionales es poniendo el código de las migraciones en los métodos `safeUp()` y `safeDown()`.
Estos métodos se diferencias con `up()` y `down()` en que son encerrados implícitamente en una transacción.
Como resultado, si alguna de las operaciones dentro de estos métodos falla, todas las operaciones previas son automáticamente revertidas.
En el siguiente ejemplo, además de crear la tabla `news` también insertamos un registro inicial dentro de la dicha tabla.
```php
<?php
use yii\db\Migration;
class m150101_185401_create_news_table extends Migration
{
public function safeUp()
{
$this->createTable('news', [
'id' => $this->primaryKey(),
'title' => $this->string()->notNull(),
'content' => $this->text(),
]);
$this->insert('news', [
'title' => 'test 1',
'content' => 'content 1',
]);
}
public function safeDown()
{
$this->delete('news', ['id' => 1]);
$this->dropTable('news');
}
}
```
Ten en cuenta que usualmente cuando ejecutas múltiples operaciones en la BD en `safeUp()`, deberías revertir su orden de ejecución
en `safeDown()`. En el ejemplo anterior primero creamos la tabla y luego insertamos la finla en `safeUp()`; mientras
que en `safeDown()` primero eliminamos el registro y posteriormente eliminamos la tabla.
> Note: No todos los DBMS soportan transacciones. Y algunas consultas a la BD no pueden ser puestas en transacciones. Para algunos ejemplos,
por favor lee acerca de [commits implícitos](http://dev.mysql.com/doc/refman/5.7/en/implicit-commit.html). En estos casos,
deberías igualmente implementar `up()` y `down()`.
### Métodos de Acceso a la Base de Datos <span id="db-accessing-methods"></span>
La clase base [[yii\db\Migration]] provee un grupo de métodos que te permiten acceder y manipular bases de datos.
Podrías encontrar que estos métodos son nombrados de forma similar a los [métodos DAO](db-dao.md) provistos por la clase [[yii\db\Command]].
Por ejemplo, el método [[yii\db\Migration::createTable()]] te permite crear una nueva tabla,
tal como lo hace [[yii\db\Command::createTable()]].
El beneficio de utilizar lo métodos provistos por [[yii\db\Migration]] es que no necesitas explícitamente
crear instancias de [[yii\db\Command]], y la ejecución de cada método mostrará automáticamente mensajes útiles
diciéndote qué operaciones de la base de datos se realizaron y cuánto tiempo tomaron.
Debajo hay una lista de todos los métodos de acceso a la base de datos:
* [[yii\db\Migration::execute()|execute()]]: ejecuta una declaración SQL
* [[yii\db\Migration::insert()|insert()]]: inserta un único registro
* [[yii\db\Migration::batchInsert()|batchInsert()]]: inserta múltiples registros
* [[yii\db\Migration::update()|update()]]: actualiza registros
* [[yii\db\Migration::delete()|delete()]]: elimina registros
* [[yii\db\Migration::createTable()|createTable()]]: crea una nueva tabla
* [[yii\db\Migration::renameTable()|renameTable()]]: renombra una tabla
* [[yii\db\Migration::dropTable()|dropTable()]]: elimina una tabla
* [[yii\db\Migration::truncateTable()|truncateTable()]]: elimina todos los registros de una tabla
* [[yii\db\Migration::addColumn()|addColumn()]]: agrega una columna
* [[yii\db\Migration::renameColumn()|renameColumn()]]: renombra una columna
* [[yii\db\Migration::dropColumn()|dropColumn()]]: elimina una columna
* [[yii\db\Migration::alterColumn()|alterColumn()]]: modifica una columna
* [[yii\db\Migration::addPrimaryKey()|addPrimaryKey()]]: agrega una clave primaria
* [[yii\db\Migration::dropPrimaryKey()|dropPrimaryKey()]]: elimina una clave primaria
* [[yii\db\Migration::addForeignKey()|addForeignKey()]]: agrega una clave foránea
* [[yii\db\Migration::dropForeignKey()|dropForeignKey()]]: elimina una clave foránea
* [[yii\db\Migration::createIndex()|createIndex()]]: crea un índice
* [[yii\db\Migration::dropIndex()|dropIndex()]]: elimina un índice
* [[yii\db\Migration::addCommentOnColumn()|addCommentOnColumn()]: agrega un comentario a una columna
* [[yii\db\Migration::dropCommentFromColumn()|dropCommentFromColumn()]: elimina un comentario de una columna
* [[yii\db\Migration::addCommentOnTable()|addCommentOnTable()]: agrega un comentario a una tabla
* [[yii\db\Migration::dropCommentFromTable()|dropCommentFromTable()]: elimina un comentario de una tabla
> Info: [[yii\db\Migration]] no provee un método de consulta a la base de datos. Esto es porque normalmente no necesitas
mostrar mensajes detallados al traer datos de una base de datos. También se debe a que puedes utilizar el poderoso
[Query Builder](db-query-builder.md) para generar y ejecutar consultas complejas.
> Note: Al manipular datos utilizando una migración podrías encontrar que utilizando tus clases [Active Record](db-active-record.md)
> para esto podría ser útil ya que algo de la lógica ya está implementada ahí. Ten en cuenta de todos modos, que en contraste con
> el código escrito en las migraciones, cuya naturaleza es permanecer constante por siempre, la lógica de la aplicación está sujeta a cambios.
> Entonces al utilizar Active Record en migraciones, los cambios en la lógica en la capa Active Record podrían accidentalmente romper
> migraciones existentes. Por esta razón, el código de las migraciones debería permanecer independiente de determinada lógica de la aplicación
> tal como clases Active Record.
## Aplicar Migraciones <span id="applying-migrations"></span>
To upgrade a database to its latest structure, you should apply all available new migrations using the following command:
Para actualizar una base de datos a su última estructura, deberías aplicar todas las nuevas migraciones utilizando el siguiente comando:
```
yii migrate
```
Este comando listará todas las migraciones que no han sido aplicadas hasta el momento. Si confirmas que quieres aplicar
dichas migraciones, se correrá el método `up()` o `safeUp()` en cada clase de migración nueva, una tras otra,
en el orden de su valor de marca temporal. Si alguna de las migraciones falla, el comando terminará su ejecución sin aplicar
el resto de las migraciones.
> Tip: En caso de no disponer de la línea de comandos en el servidor, podrías intentar utilizar
> la extensión [web shell](https://github.com/samdark/yii2-webshell).
Por cada migración aplicada correctamente, el comando insertará un registro en la base de datos, en la tabla llamada
`migration` para registrar la correcta aplicación de la migración. Esto permitirá a la herramienta de migración identificar
cuáles migraciones han sido aplicadas y cuáles no.
> Info: La herramienta de migración creará automáticamente la tabla `migration` en la base de datos especificada
en la opción [[yii\console\controllers\MigrateController::db|db]] del comando. Por defecto, la base de datos
es especificada en el [componente de aplicación](structure-application-components.md) `db`.
A veces, podrías sólo querer aplicar una o algunas pocas migraciones, en vez de todas las migraciones disponibles.
Puedes hacer esto el número de migraciones que quieres aplicar al ejecutar el comando.
Por ejemplo, el siguiente comando intentará aplicar las tres siguientes migraciones disponibles:
```
yii migrate 3
```
Puedes además explícitamente especificar una migración en particular a la cual la base de datos debería migrar
utilizando el comando `migrate/to` de acuerdo a uno de los siguientes formatos:
```
yii migrate/to 150101_185401 # utiliza la marca temporal para especificar la migración
yii migrate/to "2015-01-01 18:54:01" # utiliza un string que puede ser analizado por strtotime()
yii migrate/to m150101_185401_create_news_table # utiliza el nombre completo
yii migrate/to 1392853618 # utiliza el tiempo UNIX
```
Si hubiera migraciones previas a la especificada sin aplicar, estas serán aplicadas antes de que la migración especificada
sea aplicada.
Si la migración especificada ha sido aplicada previamente, cualquier migración aplicada posteriormente será revertida.
## Revertir Migraciones <span id="reverting-migrations"></span>
Para revertir (deshacer) una o varias migraciones ya aplicadas, puedes ejecutar el siguiente comando:
```
yii migrate/down # revierte la más reciente migración aplicada
yii migrate/down 3 # revierte las 3 últimas migraciones aplicadas
```
> Note: No todas las migraciones son reversibles. Intentar revertir tales migraciones producirá un error y detendrá
completamente el proceso de reversión.
## Rehacer Migraciones <span id="redoing-migrations"></span>
Rehacer (re-ejecutar) migraciones significa primero revertir las migraciones especificadas y luego aplicarlas nuevamente. Esto puede hacerse
de esta manera:
```
yii migrate/redo # rehace la más reciente migración aplicada
yii migrate/redo 3 # rehace las 3 últimas migraciones aplicadas
```
> Note: Si una migración no es reversible, no tendrás posibilidades de rehacerla.
## Listar Migraciones <span id="listing-migrations"></span>
Para listar cuáles migraciones han sido aplicadas y cuáles no, puedes utilizar los siguientes comandos:
```
yii migrate/history # muestra las últimas 10 migraciones aplicadas
yii migrate/history 5 # muestra las últimas 5 migraciones aplicadas
yii migrate/history all # muestra todas las migraciones aplicadas
yii migrate/new # muestra las primeras 10 nuevas migraciones
yii migrate/new 5 # muestra las primeras 5 nuevas migraciones
yii migrate/new all # muestra todas las nuevas migraciones
```
## Modificar el Historial de Migraciones <span id="modifying-migration-history"></span>
En vez de aplicar o revertir migraciones, a veces simplemente quieres marcar que tu base de datos
ha sido actualizada a una migración en particular. Esto sucede normalmente cuando cambias manualmente la base de datos
a un estado particular y no quieres que la/s migración/es de ese cambio sean re-aplicadas posteriormente. Puedes alcanzar este objetivo
con el siguiente comando:
```
yii migrate/mark 150101_185401 # utiliza la marca temporal para especificar la migración
yii migrate/mark "2015-01-01 18:54:01" # utiliza un string que puede ser analizado por strtotime()
yii migrate/mark m150101_185401_create_news_table # utiliza el nombre completo
yii migrate/mark 1392853618 # utiliza el tiempo UNIX
```
El comando modificará la tabla `migration` agregando o eliminado ciertos registros para indicar que en la base de datos
han sido aplicadas las migraciones hasta la especificada. Ninguna migración será aplicada ni revertida por este comando.
## Personalizar Migraciones <span id="customizing-migrations"></span>
Hay varias maneras de personalizar el comando de migración.
### Utilizar Opciones de la Línea de Comandos <span id="using-command-line-options"></span>
El comando de migración trae algunas opciones de línea de comandos que pueden ser utilizadas para personalizar su comportamiento:
* `interactive`: boolean (por defecto true), especificar si se debe ejecutar la migración en modo interactivo.
Cuando se indica true, se le pedirá confirmación al usuario antes de ejecutar ciertas acciones.
Puedes querer definirlo como false si el comando está siendo utilizado como un proceso de fondo.
* `migrationPath`: string (por defecto `@app/migrations`), especifica el directorio que contiene todos los archivos
de clase de las migraciones. Este puede ser especificado tanto como una ruta a un directorio un [alias](concept-aliases.md) de ruta.
Ten en cuenta que el directorio debe existir, o el comando disparará un error.
* `migrationTable`: string (por defecto `migration`), especifica el nombre de la tabla de la base de datos que almacena
información del historial de migraciones. Dicha tabla será creada por el comando en caso de que no exista.
Puedes también crearla manualmente utilizando la estructura `version varchar(255) primary key, apply_time integer`.
* `db`: string (por defecto `db`), especifica el ID del [componente de aplicación](structure-application-components.md) de la base de datos.
Esto representa la base de datos que será migrada en este comando.
* `templateFile`: string (por defecto `@yii/views/migration.php`), especifica la ruta al template
utilizado para generar el esqueleto de los archivos de clases de migración. Puede ser especificado tanto como una ruta a un archivo
como una [alias](concept-aliases.md) de una ruta. El template es un archivo PHP en el cual puedes utilizar una variable predefinida
llamada `$className` para obtener el nombre de clase de la migración.
* `generatorTemplateFiles`: array (por defecto `[
'create_table' => '@yii/views/createTableMigration.php',
'drop_table' => '@yii/views/dropTableMigration.php',
'add_column' => '@yii/views/addColumnMigration.php',
'drop_column' => '@yii/views/dropColumnMigration.php',
'create_junction' => '@yii/views/createJunctionMigration.php'
]`), especifica los templates utilizados para generar las migraciones. Ver "[Generar Migraciones](#generating-migrations)"
para más detalles.
* `fields`: array de strings de definiciones de columna utilizado por el código de migración. Por defecto `[]`. El formato de cada
definición es `COLUMN_NAME:COLUMN_TYPE:COLUMN_DECORATOR`. Por ejemplo, `--fields=name:string(12):notNull` produce
una columna string de tamaño 12 que es not null.
El siguiente ejemplo muestra cómo se pueden utilizar estas opciones.
Por ejemplo, si queremos migrar un módulo `forum` cuyos arhivos de migración
están ubicados dentro del directorio `migrations` del módulo, podemos utilizar el siguientedocs/guide-es/db-migrations.md
comando:
```
# realiza las migraciones de un módulo forum sin interacción del usuario
yii migrate --migrationPath=@app/modules/forum/migrations --interactive=0
```
### Configurar el Comando Globalmente <span id="configuring-command-globally"></span>
En vez de introducir los valores de las opciones cada vez que ejecutas un comandod e migración, podrías configurarlos
de una vez por todas en la configuración de la aplicación como se muestra a continuación:
```php
return [
'controllerMap' => [
'migrate' => [
'class' => 'yii\console\controllers\MigrateController',
'migrationTable' => 'backend_migration',
],
],
];
```
Con esta configuración, cada vez que ejecutes un comando de migración, la tabla `backend_migration`
será utilizada para registrar el historial de migraciones. No necesitarás volver a especificarla con la opción `migrationTable`
de la línea de comandos.
## Migrar Múltiples Bases de Datos <span id="migrating-multiple-databases"></span>
Por defecto, las migraciones son aplicadas en la misma base de datos especificada en el [componente de aplicación](structure-application-components.md) `db`.
Si quieres que sean aplicadas en una base de datos diferente, puedes especificar la opción `db` como se muestra a continuación,
```
yii migrate --db=db2
```
El comando anterior aplicará las migraciones en la base de datos `db2`.
A veces puede suceder que quieras aplicar *algunas* de las migraciones a una base de datos, mientras algunas otras
a una base de datos distinta. Para lograr esto, al implementar una clase de migración debes especificar explícitamente el ID del componente DB
que la migración debe utilizar, como a continuación:
```php
<?php
use yii\db\Migration;
class m150101_185401_create_news_table extends Migration
{
public function init()
{
$this->db = 'db2';
parent::init();
}
}
```
La migración anterior se aplicará a `db2`, incluso si especificas una base de datos diferente en la opción `db` de la
línea de comandos. Ten en cuenta que el historial aún será registrado in la base de datos especificada en la opción `db` de la línea de comandos.
Si tienes múltiples migraciones que utilizan la misma base de datos, es recomandable que crees una clase base de migración
con el código `init()` mostrado. Entonces cada clase de migración puede extender de esa clase base.
> Tip: Aparte de definir la propiedad [[yii\db\Migration::db|db]], puedes también operar en diferentes bases de datos
creando nuevas conexiones de base de datos en tus clases de migración. También puedes utilizar [métodos DAO](db-dao.md)
con esas conexiones para manipular diferentes bases de datos.
Another strategy that you can take to migrate multiple databases is to keep migrations for different databases in
different migration paths. Then you can migrate these databases in separate commands like the following:
Otra estrategia que puedes seguir para migrar múltiples bases de datos es mantener las migraciones para diferentes bases de datos en
distintas rutas de migración. Entonces podrías migrar esas bases de datos en comandos separados como a continuación:
```
yii migrate --migrationPath=@app/migrations/db1 --db=db1
yii migrate --migrationPath=@app/migrations/db2 --db=db2
...
```
El primer comando aplicará las migraciones que se encuentran en `@app/migrations/db1` en la base de datos `db1`, el segundo comando
aplicará las migraciones que se encuentran en `@app/migrations/db2` en `db2`, y así sucesivamente.

67
docs/guide-es/glossary.md

@ -0,0 +1,67 @@
# A
## alias
Alias es un string utilizado por Yii para referirse a una clase o directorio tal como `@app/vendor`.
## aplicación
La aplicación es el objeto central durante la solicitud HTTP. Contiene un número de componentes con los que toma información de la solicitud y la envía al controlador apropiado para posterior procesamiento.
El objeto de la aplicación es instanciado como un singleton por el script de entrada. El singleton de la aplicación puede ser accedido desde cualquier lugar a través de `\Yii::$app`.
## assets
Asset se refiere a un archivo de recurso. Típicamente contiene JavaScript o CSS pero puede ser cualquier otra cosa que sea accesible vía HTTP.
## atributo
Un atributo es una propiedad de un modelo (una variable miembro de clase o una propiedad mágica definida vía `__get()`/`__set()`) que almacena **datos de negocio**.
# B
## bundle
Bundle, conocido como paquete en Yii 1.1, se refiere a un número de recursos y un archivo de configuración que describe dependencias y lista recursos.
# C
## configuración
Configuración puede referirse tanto al proceso de establecer propiedades de un objeto como a un archivo de configuración que almacena la definición de propiedades para un objeto o clase de objetos.
# E
## extensión
Extensión es un grupo de clases, paquete de recursos y configuraciones que agrega más características a la aplicación.
# I
## instalación
Instalación es el proceso de preparar algo para trabajar, desde seguir un archivo léame hasta ejecutar un script preparado especialmente para tal fin. En el caso de Yii, define permisos y chequea los requerimientos para el funcionamiento del software.
# M
## módulo
Módulo es una sub-aplicación que contiene elementos MVC en sí mismo, como modelos, vistas, controladores, etc. y puede ser utilizado dentro de la aplicación principal. Típicamente remitiendo las solicitudes al módulo en vez de manejándolo desde controladores.
# N
## namespace
Namespace (espacio de nombres) se refiere a una [característica de PHP](http://php.net/manual/es/language.namespaces.php) activamente utilizada en Yii 2.
# P
## paquete
[Ver bundle](#bundle).
# V
## vendor
Vendor (proveedor) es una organización o un desarrollador individual que provee código en forma de extensiones, módulos o librerías.

142
docs/guide-es/helper-array.md

@ -1,7 +1,7 @@
ArrayHelper
===========
Adicionalmente al [rico conjunto de funciones para arrays de PHP](http://php.net/manual/es/book.array.php) Yii array helper proporciona
Adicionalmente al [rico conjunto de funciones para arrays de PHP](http://php.net/manual/es/book.array.php), el array helper de Yii proporciona
métodos estáticos adicionales permitiendo trabajar con arrays de manera más eficiente.
@ -109,30 +109,94 @@ $result = ArrayHelper::getColumn($array, function ($element) {
## Re-indexar Arrays <span id="reindexing-arrays"></span>
Con el fin de indexar un array según una clave especificada, se puede usar el método `index`. La entrada del array debe ser
multidimensional o un array de objetos. La clave puede ser un nombre clave del sub-array, un nombre de una propiedad del objeto, o
una función anónima que retorne el valor de la clave dado el elemento del array.
Con el fin de indexar un array según una clave especificada, se puede usar el método `index`. La entrada debería ser
un array multidimensional o un array de objetos. `$key` puede ser tanto una clave del sub-array, un nombre de una propiedad
del objeto, o una función anónima que debe devolver el valor que será utilizado como clave.
Si el valor de la clave es null, el correspondiente elemento del array será desechado y no se pondrá en el resultado. Por ejemplo,
El atributo `$groups` es un array de claves, que será utilizado para agrupar el array de entrada en uno o más sub-arrays
basado en la clave especificada.
Si el atributo `$key` o su valor por el elemento en particular es null y `$groups` no está definido, dicho elemento del array
será descartado. De otro modo, si `$groups` es especificado, el elemento del array será agregado al array resultante
sin una clave.
Por ejemplo:
```php
$array = [
['id' => '123', 'data' => 'abc'],
['id' => '345', 'data' => 'def'],
['id' => '123', 'data' => 'abc', 'device' => 'laptop'],
['id' => '345', 'data' => 'def', 'device' => 'tablet'],
['id' => '345', 'data' => 'hgi', 'device' => 'smartphone'],
];
$result = ArrayHelper::index($array, 'id');
// el resultado es:
// [
// '123' => ['id' => '123', 'data' => 'abc'],
// '345' => ['id' => '345', 'data' => 'def'],
// ]
$result = ArrayHelper::index($array, 'id');');
```
El resultado será un array asociativo, donde la clave es el valor del atributo `id`
```php
[
'123' => ['id' => '123', 'data' => 'abc', 'device' => 'laptop'],
'345' => ['id' => '345', 'data' => 'hgi', 'device' => 'smartphone']
// El segundo elemento del array original es sobrescrito por el último elemento debido a que tiene el mismo id
]
```
Pasando una función anónima en `$key`, da el mismo resultado.
// usando función anónima
```php
$result = ArrayHelper::index($array, function ($element) {
return $element['id'];
});
```
Pasando `id` como tercer argumento, agrupará `$array` mediante `id`:
```php
$result = ArrayHelper::index($array, null, 'id');
```
El resultado será un array multidimensional agrupado por `id` en su primer nivel y no indexado en su segundo nivel:
```php
[
'123' => [
['id' => '123', 'data' => 'abc', 'device' => 'laptop']
],
'345' => [ // todos los elementos con este índice están presentes en el array resultante
['id' => '345', 'data' => 'def', 'device' => 'tablet'],
['id' => '345', 'data' => 'hgi', 'device' => 'smartphone'],
]
]
```
Una función anónima puede ser usada también en el array agrupador:
```php
$result = ArrayHelper::index($array, 'data', [function ($element) {
return $element['id'];
}, 'device']);
```
El resultado será un array multidimensional agrupado por `id` en su primer nivel, por `device` en su segundo nivel e
indexado por `data` en su tercer nivel:
```php
[
'123' => [
'laptop' => [
'abc' => ['id' => '123', 'data' => 'abc', 'device' => 'laptop']
]
],
'345' => [
'tablet' => [
'def' => ['id' => '345', 'data' => 'def', 'device' => 'tablet']
],
'smartphone' => [
'hgi' => ['id' => '345', 'data' => 'hgi', 'device' => 'smartphone']
]
]
]
```
## Construyendo Mapas (Maps) <span id="building-maps"></span>
@ -241,31 +305,30 @@ La codificación utilizará el charset de la aplicación y podría ser cambiado
```php
/**
* Merges two or more arrays into one recursively.
* If each array has an element with the same string key value, the latter
* will overwrite the former (different from array_merge_recursive).
* Recursive merging will be conducted if both arrays have an element of array
* type and are having the same key.
* For integer-keyed elements, the elements from the latter array will
* be appended to the former array.
* @param array $a array to be merged to
* @param array $b array to be merged from. You can specify additional
* arrays via third argument, fourth argument etc.
* @return array the merged array (the original arrays are not changed.)
*/
* Fusiona recursivamente dos o más arrays en uno.
* Si cada array tiene un elemento con el mismo valor string de clave, el último
* sobrescribirá el anterior (difiere de array_merge_recursive).
* Se llegará a una fusión recursiva si ambos arrays tienen un elemento tipo array
* y comparten la misma clave.
* Para elementos cuyas claves son enteros, los elementos del array final
* serán agregados al array anterior.
* @param array $a array al que se va a fusionar
* @param array $b array desde el cual fusionar. Puedes especificar
* arrays adicionales mediante el tercer argumento, cuarto argumento, etc.
* @return array el array fusionado (los arrays originales no sufren cambios)
*/
public static function merge($a, $b)
```
## Convirtiendo Objetos a Arrays <span id="converting-objects-to-arrays"></span>
A menudo necesitas convertir un objeto o un array de objetos a un array. El caso más común es convertir los modelos de
active record con el fin de servir los arrays de datos vía API REST o utilizarlos de otra manera. El siguiente código
se podría utilizar para hacerlo:
A menudo necesitas convertir un objeto o un array de objetos a un array. El caso más común es convertir los modelos de active record
con el fin de servir los arrays de datos vía API REST o utilizarlos de otra manera. El siguiente código se podría utilizar para hacerlo:
```php
$posts = Post::find()->limit(10)->all();
$data = ArrayHelper::toArray($post, [
$data = ArrayHelper::toArray($posts, [
'app\models\Post' => [
'id',
'title',
@ -302,3 +365,22 @@ El resultado de la conversión anterior será:
Es posible proporcionar una manera predeterminada de convertir un objeto a un array para una clase especifica
mediante la implementación de la interfaz [[yii\base\Arrayable|Arrayable]] en esa clase.
## Haciendo pruebas con Arrays <span id="testing-arrays"></span>
A menudo necesitarás comprobar está en un array o un grupo de elementos es un sub-grupo de otro.
A pesar de que PHP ofrece `in_array()`, este no soporta sub-grupos u objetos de tipo `\Traversable`.
Para ayudar en este tipo de pruebas, [[yii\base\ArrayHelper]] provee [[yii\base\ArrayHelper::isIn()|isIn()]]
y [[yii\base\ArrayHelper::isSubset()|isSubset()]] con la misma firma del método [[in_array()]].
```php
// true
ArrayHelper::isIn('a', ['a']);
// true
ArrayHelper::isIn('a', new(ArrayObject['a']));
// true
ArrayHelper::isSubset(new(ArrayObject['a', 'c']), new(ArrayObject['a', 'b', 'c'])
```

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

@ -3,8 +3,8 @@ Clase Auxiliar URL (URL Helper)
La clase auxiliar URL proporciona un conjunto de métodos estáticos para gestionar URLs.
Obtener URLs Comunes
--------------------
## Obtener URLs comúnes <span id="getting-common-urls"></span>
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:
@ -15,7 +15,7 @@ $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
Si no se pasan parámetros, la URL generada es relativa. 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:
@ -28,11 +28,11 @@ $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:
## Creación de URLs <span id="creating-urls"></span>
Para crear una URL para una ruta determinada se puede usar `Url::toRoute()`. El método utiliza [[\yii\web\UrlManager]]
para crear la URL:
```php
$url = Url::toRoute(['product/view', 'id' => 42]);
@ -42,7 +42,7 @@ Se puede especificar la ruta como una cadena de texto, ej. `site/index`. Tambié
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
// genera: /index.php?r=site%2Findex&param1=value1&param2=value2
['site/index', 'param1' => 'value1', 'param2' => 'value2']
```
@ -53,9 +53,8 @@ Si se quiere crear una URL con un enlace, se puede usar el formato de array con
['site/index', 'param1' => 'value1', '#' => 'name']
```
Una ruta puede ser absoluta o relativa. Una ruta absoluta tiene una barra al principio (ej. `/site/index`),
mientras que una ruta relativa no la tiene (ej. `site/index` o `index`). Una ruta relativa se convertirá en una
ruta absoluta siguiendo las siguientes normas:
Una ruta puede ser absoluta o relativa. Una ruta absoluta tiene una barra al principio (ej. `/site/index`), mientras que una ruta relativa
no la tiene (ej. `site/index` o `index`). Una ruta relativa se convertirá en una ruta absoluta siguiendo las siguientes reglas:
- Si la ruta es una cadena vacía, se usará la [[\yii\web\Controller::route|route]] actual;
- Si la ruta no contiene barras (ej. `index`), se considerará que es el ID de una acción del controlador actual y
@ -63,19 +62,26 @@ ruta absoluta siguiendo las siguientes normas:
- Si la ruta no tiene barra inicial (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.
Desde la versión 2.0.2, puedes especificar una ruta en términos de [alias](concept-aliases.md). Si este es el caso,
el alias será convertido primero en la ruta real, la cual será entonces transformada en una ruta absoluta de acuerdo
a las reglas mostradas arriba.
A continuación se muestran varios ejemplos del uso de este método:
```php
// /index?r=site/index
// /index.php?r=site%2Findex
echo Url::toRoute('site/index');
// /index?r=site/index&src=ref1#name
// /index.php?r=site%2Findex&src=ref1#name
echo Url::toRoute(['site/index', 'src' => 'ref1', '#' => 'name']);
// http://www.example.com/index.php?r=site/index
// /index.php?r=post%2Fedit&id=100 asume que el alias "@postEdit" se definió como "post/edit"
echo Url::toRoute(['@postEdit', 'id' => 100]);
// http://www.example.com/index.php?r=site%2Findex
echo Url::toRoute('site/index', true);
// https://www.example.com/index.php?r=site/index
// https://www.example.com/index.php?r=site%2Findex
echo Url::toRoute('site/index', 'https');
```
@ -99,13 +105,16 @@ el especificado.
A continuación se muestran algunos ejemplos de uso:
```php
// /index?r=site/index
// /index.php?r=site%2Findex
echo Url::to(['site/index']);
// /index?r=site/index&src=ref1#name
// /index.php?r=site%2Findex&src=ref1#name
echo Url::to(['site/index', 'src' => 'ref1', '#' => 'name']);
// la URL solicitada actualmente
// /index.php?r=post%2Fedit&id=100 asume que el alias "@postEdit" se definió como "post/edit"
echo Url::to(['@postEdit', 'id' => 100]);
// the currently requested URL
echo Url::to();
// /images/logo.gif
@ -121,8 +130,24 @@ echo Url::to('@web/images/logo.gif', true);
echo Url::to('@web/images/logo.gif', 'https');
```
Recordar la URL para utilizarla más adelante
--------------------------------------------
Desde la versión 2.0.3, puedes utilizar [[yii\helpers\Url::current()]] para crear una URL a partir de la ruta
solicitada y los parámetros GET. Puedes modificar o eliminar algunos de los parámetros GET, o también agregar nuevos
pasando un parámetro `$params` al método. Por ejemplo,
```php
// asume que $_GET = ['id' => 123, 'src' => 'google'], la ruta actual es "post/view"
// /index.php?r=post%2Fview&id=123&src=google
echo Url::current();
// /index.php?r=post%2Fview&id=123
echo Url::current(['src' => null]);
// /index.php?r=post%2Fview&id=100&src=google
echo Url::current(['id' => 100]);
```
## Recordar URLs <span id="remember-urls"></span>
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:
@ -145,11 +170,9 @@ $url = Url::previous();
$productUrl = Url::previous('product');
```
Reconocer la relatividad de URLs
--------------------------------
## Chequear URLs relativas <span id="checking-relative-urls"></span>
Para descubrir si una URL es relativa, es decir, que no contenga información del host, se puede utilizar el siguiente
código:
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');

527
docs/guide-es/images/application-lifecycle.graphml

@ -0,0 +1,527 @@
<?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 attr.name="Description" attr.type="string" for="graph" id="d0"/>
<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 for="graphml" id="d7" yfiles.type="resources"/>
<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="d0"/>
<node id="n0" yfiles.foldertype="group">
<data key="d4"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="571.4472707112631" width="763.2772213171534" x="-1269.9373595143054" y="-207.17439524332679"/>
<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="22.37646484375" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="763.2772213171534" x="0.0" y="0.0">Entry script (index.php or 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="22.37646484375" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="59.02685546875" x="-4.513427734375" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="126.759765625" x="99.08306136604676" y="5.6494140625">Load application config<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="d5"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="309.37646484374994" width="330.35133296005984" x="-1254.9373595143054" y="35.272875467936274"/>
<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="22.37646484375" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="330.35133296005984" x="0.0" y="0.0">Create application instance</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="22.37646484375" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="59.02685546875" x="-4.513427734375" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="45.34375" x="124.79106917854676" y="5.6494140625">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.701171875" modelName="custom" textColor="#000000" visible="true" width="120.71875" x="87.10356917854676" y="5.6494140625">Register error handler<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.701171875" modelName="custom" textColor="#000000" visible="true" width="173.435546875" x="60.74517074104676" y="5.6494140625">Configure application properties<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.701171875" modelName="custom" textColor="#000000" visible="true" width="27.33203125" x="133.79692855354676" y="5.6494140625">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.701171875" modelName="custom" textColor="#000000" visible="true" width="62.025390625" x="116.45024886604676" y="5.6494140625">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="d5"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="411.6943410237631" width="324.9258883570935" x="-846.5860265542456" y="-169.79793039957679"/>
<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="22.37646484375" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="324.9258883570935" x="0.0" y="0.0">Run application</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="22.37646484375" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="59.02685546875" x="-4.513427734375" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="164.705078125" x="65.11040511604676" y="5.6494140625">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="d5"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="204.37646484375" width="294.9258883570935" x="-831.5860265542456" y="-78.79793039957679"/>
<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="22.37646484375" modelName="internal" modelPosition="t" textColor="#FFFFFF" visible="true" width="294.9258883570935" x="0.0" y="0.0">Handle request</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="22.37646484375" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="59.02685546875" x="-4.513427734375" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="231.4609375" x="16.732475428546763" y="5.6494140625">Resolve request into route and parameters<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.701171875" modelName="custom" textColor="#000000" visible="true" width="197.44140625" x="33.74224105354676" y="5.6494140625">Create module, controller and action<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.701171875" modelName="custom" textColor="#000000" visible="true" width="61.369140625" x="101.77837386604676" y="5.649414062500057">Run action<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.701171875" modelName="custom" textColor="#000000" visible="true" width="154.697265625" x="70.11431136604676" y="5.6494140625">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.701171875" modelName="custom" textColor="#000000" visible="true" width="148.099609375" x="73.41313949104676" y="5.6494140625">Send response to end user<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.701171875" modelName="custom" textColor="#000000" visible="true" width="160.08203125" x="82.42192855354676" y="5.6494140625">Complete request processing<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="d9"/>
<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.701171875" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="106.052734375" x="-130.76131968438426" y="78.18481445312506">Configuration array<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="d9"/>
<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="d9"/>
<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="d9"/>
<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="d9"/>
<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="d9"/>
<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="d9"/>
<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="d9"/>
<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="d9"/>
<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="d9"/>
<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="d9"/>
<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="d9"/>
<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.701171875" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="59.353515625" x="-93.67673227804266" y="28.318773905436274">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="d7">
<y:Resources/>
</data>
</graphml>

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

368
docs/guide-es/images/rbac-access-check-1.graphml

@ -0,0 +1,368 @@
<?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.12.2-->
<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">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="69.0" width="103.0" x="34.0" y="-11.5"/>
<y:Fill color="#ADF4A6" transparent="false"/>
<y:BorderStyle color="#FF0000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="36.68359375" x="33.158203125" y="25.1494140625">admin<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="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n1">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="69.0" width="103.0" x="193.0" y="-11.5"/>
<y:Fill color="#ADF4A6" transparent="false"/>
<y:BorderStyle color="#FF0000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="38.025390625" x="32.4873046875" y="25.1494140625">author<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="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n2">
<data key="d6">
<y:SVGNode>
<y:Geometry height="64.53585815429688" width="56.560157775878906" x="216.21992111206055" y="-132.03585815429688"/>
<y:Fill color="#CCCCFF" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="62.37109375" x="-2.905467987060547" y="-27.814727783203125">John, ID=2<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.5" nodeRatioX="0.0" nodeRatioY="-0.5" offsetX="0.0" offsetY="-9.113555908203125" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:SVGNodeProperties usingVisualBounds="true"/>
<y:SVGModel svgBoundsPolicy="0">
<y:SVGContent refid="1"/>
</y:SVGModel>
</y:SVGNode>
</data>
</node>
<node id="n3">
<data key="d6">
<y:SVGNode>
<y:Geometry height="66.76200103759766" width="56.554100036621094" x="57.22294998168945" y="-133.14892959594727"/>
<y:Fill color="#CCCCFF" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="62.37109375" x="-2.908496856689453" y="-27.701656341552734">Jane, ID=1<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.5" nodeRatioX="0.0" nodeRatioY="-0.5" offsetX="0.0" offsetY="-9.000484466552734" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:SVGNodeProperties usingVisualBounds="true"/>
<y:SVGModel svgBoundsPolicy="0">
<y:SVGContent refid="2"/>
</y:SVGModel>
</y:SVGNode>
</data>
</node>
<node id="n4">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="69.0" width="103.0" x="34.0" y="197.5"/>
<y:Fill color="#99CCFF" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="64.71484375" x="19.142578125" y="25.1494140625">updatePost<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="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n5">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="69.0" width="103.0" x="193.0" y="197.5"/>
<y:Fill color="#99CCFF" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="89.388671875" x="6.8056640625" y="25.1494140625">updateOwnPost<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="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n6">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="69.0" width="103.0" x="352.0" y="197.5"/>
<y:Fill color="#99CCFF" transparent="false"/>
<y:BorderStyle color="#FF0000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="61.36328125" x="20.818359375" y="25.1494140625">createPost<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="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n7">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="29.535858154296875" width="103.0" x="193.0" y="167.96414184570312"/>
<y:Fill color="#FFCC00" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="64.03515625" x="19.482421875" y="5.4173431396484375">AuthorRule<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="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<edge id="e0" source="n4" target="n0">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e1" source="n4" target="n5">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e2" source="n1" target="n0">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FF0000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e3" source="n6" target="n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
<y:Point x="403.5" y="23.0"/>
</y:Path>
<y:LineStyle color="#FF0000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e4" source="n1" target="n2">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e5" source="n0" target="n3">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FF0000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e6" source="n7" target="n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
</graph>
<data key="d0">
<y:Resources>
<y:Resource id="1">&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="57px" height="65px" viewBox="0 0 57 65" enable-background="new 0 0 57 65" xml:space="preserve"&gt;
&lt;g&gt;
&lt;linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="26.3398" y1="3115.7266" x2="27.5807" y2="3145.5239" gradientTransform="matrix(1 0 0 1 0.3203 -3091.7656)"&gt;
&lt;stop offset="0.2711" style="stop-color:#FFAB4F"/&gt;
&lt;stop offset="1" style="stop-color:#FFD28F"/&gt;
&lt;/linearGradient&gt;
&lt;path fill="url(#SVGID_1_)" stroke="#ED9135" stroke-miterlimit="10" d="M49.529,51.225c-4.396-4.396-10.951-5.884-12.063-6.109
V37.8H19.278c0,0,0.038,6.903,0,6.868c0,0-6.874,0.997-12.308,6.432C1.378,56.691,0.5,62.77,0.5,62.77
c0,1.938,1.575,3.492,3.523,3.492h48.51c1.947,0,3.521-1.558,3.521-3.492C56.055,62.768,54.211,55.906,49.529,51.225z"/&gt;
&lt;path id="body_18_" fill="#ECECEC" stroke="#9B9B9B" stroke-miterlimit="10" d="M0.5,62.768c0,1.938,1.575,3.494,3.523,3.494h48.51
c1.947,0,3.521-1.559,3.521-3.494c0,0-1.844-6.861-6.525-11.543c-4.815-4.813-11.244-6.146-11.244-6.146
c-1.771,1.655-5.61,3.802-10.063,3.802c-4.453,0-8.292-2.146-10.063-3.802c0,0-5.755,0.586-11.189,6.021
C1.378,56.689,0.5,62.768,0.5,62.768z"/&gt;
&lt;radialGradient id="SVGID_2_" cx="22.6621" cy="21.707" r="17.7954" gradientTransform="matrix(1 0 0 -1 0.04 64.1543)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_2_)" stroke="#E55E03" d="M28.106,33.486c-8.112,0-12.688,4.313-12.688,10.438
c0,7.422,12.688,10.438,12.688,10.438s14.688-3.016,14.688-10.438C42.793,38.75,36.215,33.486,28.106,33.486z M26.288,53.051
c0,0-7.135-2.093-8.805-7.201c-0.222-0.682,0.147-1.156,0.795-1.521V37.8h20.188v6.663c0.235,0.352,1.109,0.737,1.229,1.387
C40.445,49.917,26.288,53.051,26.288,53.051z"/&gt;
&lt;radialGradient id="SVGID_3_" cx="15.2056" cy="831.1875" r="32.3071" gradientTransform="matrix(1 0 0 1 0.0801 -773.6914)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_3_)" stroke="#E55E03" d="M49.529,51.225c-2.239-2.24-5.041-3.724-7.396-4.67
c-2.854,5.51-14.021,7.807-14.021,7.807s-10.472-2.483-12.387-8.514c-2.439,0.771-5.787,2.287-8.749,5.25
c-5.592,5.592-6.47,11.67-6.47,11.67c0,1.938,1.575,3.492,3.523,3.492h48.51c1.946,0,3.521-1.558,3.521-3.492
C56.055,62.768,54.211,55.906,49.529,51.225z"/&gt;
&lt;radialGradient id="SVGID_4_" cx="17.0723" cy="18.4907" r="11.8931" gradientTransform="matrix(1 0 0 -1 0.04 64.1543)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_4_)" stroke="#E55E03" d="M13.404,44.173c1.15-1.81,2.039-3.832,3.332-5.397
c-0.514,1.027-1.669,4.084-1.669,5.148c0,5.186,10.366,9.079,14.688,10.438c-3.472,1.627-9.134-1.498-11.334-2.359
c-3.601-1.419-4.071-3.063-5.89-4.854C12.523,47.135,12.878,45,13.404,44.173z"/&gt;
&lt;radialGradient id="SVGID_5_" cx="31.8184" cy="19.3525" r="14.63" gradientTransform="matrix(1 0 0 -1 0.04 64.1543)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_5_)" stroke="#E55E03" d="M45.777,43.924c-1.317-1.568-5.11-9.424-6.604-6.617
c0.516,1.025,3.617,3.693,3.617,6.617c0,5.186-10.271,8.576-16.699,9.145c1.429,4.938,11.373,1.293,13.805-0.313
c3.563-2.354,4.563-5.133,7.854-3.705C47.754,49.045,48.006,46.574,45.777,43.924z"/&gt;
&lt;radialGradient id="SVGID_6_" cx="30.4893" cy="4.8721" r="5.2028" gradientTransform="matrix(1 0 0 -1 0.04 64.1543)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_6_)" stroke="#E55E03" d="M30.777,54.167c0.357,0.836-0.153,1.983-0.352,2.813
c-0.256,1.084-0.072,2.104,0.102,3.186c0.164,1.02,0.156,2.107,0.25,3.167c0.082,0.916,0.482,1.849,0.357,2.75"/&gt;
&lt;radialGradient id="SVGID_7_" cx="23.2871" cy="5.3008" r="5.5143" gradientTransform="matrix(1 0 0 -1 0.04 64.1543)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_7_)" stroke="#E55E03" d="M23.695,53.417c-0.508,0.584-0.476,2.209-0.398,3
c0.116,1.183,0.456,2.099,0.333,3.333c-0.192,1.943,0.154,4.479-0.436,6.333"/&gt;
&lt;radialGradient id="face_x5F_white_1_" cx="27.5835" cy="3117.4922" r="23.425" fx="23.0139" fy="3115.0024" gradientTransform="matrix(1 0 0 1 0.3203 -3091.7656)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FFD28F"/&gt;
&lt;stop offset="1" style="stop-color:#FFAB4F"/&gt;
&lt;/radialGradient&gt;
&lt;path id="face_x5F_white_3_" fill="url(#face_x5F_white_1_)" stroke="#ED9135" stroke-miterlimit="10" d="M43.676,23.357
c0.086,10.2-6.738,18.52-15.25,18.586c-8.5,0.068-15.464-8.146-15.55-18.344C12.794,13.4,19.618,5.079,28.123,5.012
C36.627,4.945,43.59,13.158,43.676,23.357z"/&gt;
&lt;linearGradient id="face_highlight_1_" gradientUnits="userSpaceOnUse" x1="6468.501" y1="-12291.5195" x2="6492.1304" y2="-12384.9688" gradientTransform="matrix(0.275 0 0 -0.2733 -1752.8849 -3351.7349)"&gt;
&lt;stop offset="0" style="stop-color:#FFFFFF;stop-opacity:0.24"/&gt;
&lt;stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.16"/&gt;
&lt;/linearGradient&gt;
&lt;path id="face_highlight_3_" fill="url(#face_highlight_1_)" d="M28.415,5.625c-6.035,0.047-10.747,4.493-12.787,10.386
c-0.664,1.919-0.294,4.043,0.98,5.629c2.73,3.398,5.729,6.283,9.461,8.088c3.137,1.518,7.535,2.385,11.893,1.247
c2.274-0.592,3.988-2.459,4.375-4.766c0.187-1.094,0.293-2.289,0.283-3.553C42.54,13.244,36.729,5.56,28.415,5.625z"/&gt;
&lt;path id="Hair_Young_Black_1_" fill="#5C5C5C" stroke="#353535" stroke-linecap="round" stroke-linejoin="round" d="M20.278,13.25
c3.417,4.333,9.333,6.917,9.333,6.917l-1.417-3.5c0,0,7.094,4.691,8.083,4.333c0.968-0.2-1.082-3.807-1.082-3.807
s3.138,1.795,4.854,3.969c1.803,2.28,4.285,3.504,4.285,3.504S47.027,2.719,27.289,2.744C8.278,2.709,12.058,27.678,12.058,27.678
L14.695,17c0,0,0.914,5.757,1.399,4.875C17.861,15.211,18.861,11.5,20.278,13.25z"/&gt;
&lt;/g&gt;
&lt;/svg&gt;
</y:Resource>
<y:Resource id="2">&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="57px" height="67px" viewBox="0 0 57 67" enable-background="new 0 0 57 67" xml:space="preserve"&gt;
&lt;g&gt;
&lt;linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="26.3398" y1="3115.7266" x2="27.5807" y2="3145.5239" gradientTransform="matrix(1 0 0 1 0.3203 -3091.7656)"&gt;
&lt;stop offset="0.2711" style="stop-color:#FFAB4F"/&gt;
&lt;stop offset="1" style="stop-color:#FFD28F"/&gt;
&lt;/linearGradient&gt;
&lt;path fill="url(#SVGID_1_)" stroke="#ED9135" stroke-miterlimit="10" d="M49.529,51.225c-4.396-4.396-10.951-5.884-12.063-6.109
V37.8H19.278c0,0,0.038,6.903,0,6.868c0,0-6.874,0.997-12.308,6.432C1.378,56.691,0.5,62.77,0.5,62.77
c0,1.938,1.575,3.492,3.523,3.492h48.51c1.947,0,3.521-1.558,3.521-3.492C56.055,62.768,54.211,55.906,49.529,51.225z"/&gt;
&lt;radialGradient id="face_x5F_white_1_" cx="27.5835" cy="3117.4922" r="23.425" fx="23.0139" fy="3115.0024" gradientTransform="matrix(1 0 0 1 0.3203 -3091.7656)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FFD28F"/&gt;
&lt;stop offset="1" style="stop-color:#FFAB4F"/&gt;
&lt;/radialGradient&gt;
&lt;path id="face_x5F_white_3_" fill="url(#face_x5F_white_1_)" stroke="#ED9135" stroke-miterlimit="10" d="M43.676,23.357
c0.086,10.199-6.738,18.52-15.25,18.586c-8.5,0.068-15.464-8.146-15.55-18.344C12.794,13.4,19.618,5.079,28.123,5.012
C36.627,4.945,43.59,13.158,43.676,23.357z"/&gt;
&lt;linearGradient id="face_highlight_1_" gradientUnits="userSpaceOnUse" x1="6468.5" y1="-12286.8594" x2="6492.1294" y2="-12380.3086" gradientTransform="matrix(0.275 0 0 -0.2733 -1752.8849 -3350.4617)"&gt;
&lt;stop offset="0" style="stop-color:#FFFFFF;stop-opacity:0.24"/&gt;
&lt;stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.16"/&gt;
&lt;/linearGradient&gt;
&lt;path id="face_highlight_3_" fill="url(#face_highlight_1_)" d="M28.415,5.625c-6.035,0.047-10.747,4.493-12.787,10.386
c-0.664,1.919-0.294,4.043,0.98,5.629c2.73,3.398,5.729,6.283,9.461,8.088c3.137,1.518,7.535,2.385,11.893,1.247
c2.274-0.592,3.988-2.459,4.375-4.766c0.187-1.094,0.293-2.289,0.283-3.553C42.54,13.244,36.729,5.56,28.415,5.625z"/&gt;
&lt;path id="Hair_Female_1_Red_1_" fill="#FAE1AA" stroke="#E2B354" stroke-linecap="round" stroke-linejoin="round" d="M28.372,0.5
C17.537,0.5,8.269,7.748,9.153,26.125c0.563,6.563,5.862,12.042,9.366,13.531c-2.929-10.968-0.304-25.021-0.585-25.526
c-0.281-0.505,3.536,6.728,3.536,6.728l3.183-8.312c5.541,4.28,0.393,11.309,1.049,11.058c4.26-1.631,5.34-9.228,5.34-9.228
s2.729,3.657,2.701,5.504c-0.054,3.562,2.194-6.067,2.194-6.067l1.027,2.031c6.727,9.822,3.684,16.208,1.648,22.781
c15.666-0.703,12.291-10.48,9.66-18.407C43.59,6.092,39.206,0.5,28.372,0.5z"/&gt;
&lt;linearGradient id="body_1_" gradientUnits="userSpaceOnUse" x1="95.9063" y1="-3134.2153" x2="31.5133" y2="-3134.2153" gradientTransform="matrix(0.9852 0 0 -0.9852 -34.4844 -3031.9851)"&gt;
&lt;stop offset="0" style="stop-color:#49AD33"/&gt;
&lt;stop offset="1" style="stop-color:#C2DA92"/&gt;
&lt;/linearGradient&gt;
&lt;path id="body_8_" fill="url(#body_1_)" stroke="#008D33" d="M0.5,62.768c0,1.938,1.575,3.494,3.523,3.494h48.51
c1.947,0,3.521-1.559,3.521-3.494c0,0-1.844-6.861-6.525-11.543c-4.815-4.813-8.244-5.146-8.244-5.146
c-1.444,6.983-8.555,8.786-13.007,8.786s-11.322-2.643-11.941-9.439c0,0-4.559,1.199-9.367,5.674
C1.378,56.689,0.5,62.768,0.5,62.768z"/&gt;
&lt;/g&gt;
&lt;/svg&gt;
</y:Resource>
</y:Resources>
</data>
</graphml>

BIN
docs/guide-es/images/rbac-access-check-1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

368
docs/guide-es/images/rbac-access-check-2.graphml

@ -0,0 +1,368 @@
<?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.12.2-->
<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">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="69.0" width="103.0" x="34.0" y="-11.5"/>
<y:Fill color="#ADF4A6" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="36.68359375" x="33.158203125" y="25.1494140625">admin<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="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n1">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="69.0" width="103.0" x="193.0" y="-11.5"/>
<y:Fill color="#ADF4A6" transparent="false"/>
<y:BorderStyle color="#FF0000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="38.025390625" x="32.4873046875" y="25.1494140625">author<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="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n2">
<data key="d6">
<y:SVGNode>
<y:Geometry height="64.53585815429688" width="56.560157775878906" x="216.21992111206055" y="-132.03585815429688"/>
<y:Fill color="#CCCCFF" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="62.37109375" x="-2.905467987060547" y="-27.814727783203125">John, ID=2<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.5" nodeRatioX="0.0" nodeRatioY="-0.5" offsetX="0.0" offsetY="-9.113555908203125" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:SVGNodeProperties usingVisualBounds="true"/>
<y:SVGModel svgBoundsPolicy="0">
<y:SVGContent refid="1"/>
</y:SVGModel>
</y:SVGNode>
</data>
</node>
<node id="n3">
<data key="d6">
<y:SVGNode>
<y:Geometry height="66.76200103759766" width="56.554100036621094" x="57.22294998168945" y="-133.14892959594727"/>
<y:Fill color="#CCCCFF" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="62.37109375" x="-2.908496856689453" y="-27.701656341552734">Jane, ID=1<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.5" nodeRatioX="0.0" nodeRatioY="-0.5" offsetX="0.0" offsetY="-9.000484466552734" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:SVGNodeProperties usingVisualBounds="true"/>
<y:SVGModel svgBoundsPolicy="0">
<y:SVGContent refid="2"/>
</y:SVGModel>
</y:SVGNode>
</data>
</node>
<node id="n4">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="69.0" width="103.0" x="34.0" y="197.5"/>
<y:Fill color="#99CCFF" transparent="false"/>
<y:BorderStyle color="#FF0000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="64.71484375" x="19.142578125" y="25.1494140625">updatePost<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="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n5">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="69.0" width="103.0" x="193.0" y="197.5"/>
<y:Fill color="#99CCFF" transparent="false"/>
<y:BorderStyle color="#FF0000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="89.388671875" x="6.8056640625" y="25.1494140625">updateOwnPost<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="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n6">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="69.0" width="103.0" x="352.0" y="197.5"/>
<y:Fill color="#99CCFF" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="61.36328125" x="20.818359375" y="25.1494140625">createPost<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="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n7">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="29.535858154296875" width="103.0" x="193.0" y="167.96414184570312"/>
<y:Fill color="#FFCC00" transparent="false"/>
<y:BorderStyle color="#FF0000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="64.03515625" x="19.482421875" y="5.4173431396484375">AuthorRule<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="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<edge id="e0" source="n4" target="n0">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e1" source="n4" target="n5">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FF0000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e2" source="n1" target="n0">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e3" source="n6" target="n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
<y:Point x="403.5" y="23.0"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e4" source="n1" target="n2">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FF0000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e5" source="n0" target="n3">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e6" source="n7" target="n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FF0000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
</graph>
<data key="d0">
<y:Resources>
<y:Resource id="1">&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="57px" height="65px" viewBox="0 0 57 65" enable-background="new 0 0 57 65" xml:space="preserve"&gt;
&lt;g&gt;
&lt;linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="26.3398" y1="3115.7266" x2="27.5807" y2="3145.5239" gradientTransform="matrix(1 0 0 1 0.3203 -3091.7656)"&gt;
&lt;stop offset="0.2711" style="stop-color:#FFAB4F"/&gt;
&lt;stop offset="1" style="stop-color:#FFD28F"/&gt;
&lt;/linearGradient&gt;
&lt;path fill="url(#SVGID_1_)" stroke="#ED9135" stroke-miterlimit="10" d="M49.529,51.225c-4.396-4.396-10.951-5.884-12.063-6.109
V37.8H19.278c0,0,0.038,6.903,0,6.868c0,0-6.874,0.997-12.308,6.432C1.378,56.691,0.5,62.77,0.5,62.77
c0,1.938,1.575,3.492,3.523,3.492h48.51c1.947,0,3.521-1.558,3.521-3.492C56.055,62.768,54.211,55.906,49.529,51.225z"/&gt;
&lt;path id="body_18_" fill="#ECECEC" stroke="#9B9B9B" stroke-miterlimit="10" d="M0.5,62.768c0,1.938,1.575,3.494,3.523,3.494h48.51
c1.947,0,3.521-1.559,3.521-3.494c0,0-1.844-6.861-6.525-11.543c-4.815-4.813-11.244-6.146-11.244-6.146
c-1.771,1.655-5.61,3.802-10.063,3.802c-4.453,0-8.292-2.146-10.063-3.802c0,0-5.755,0.586-11.189,6.021
C1.378,56.689,0.5,62.768,0.5,62.768z"/&gt;
&lt;radialGradient id="SVGID_2_" cx="22.6621" cy="21.707" r="17.7954" gradientTransform="matrix(1 0 0 -1 0.04 64.1543)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_2_)" stroke="#E55E03" d="M28.106,33.486c-8.112,0-12.688,4.313-12.688,10.438
c0,7.422,12.688,10.438,12.688,10.438s14.688-3.016,14.688-10.438C42.793,38.75,36.215,33.486,28.106,33.486z M26.288,53.051
c0,0-7.135-2.093-8.805-7.201c-0.222-0.682,0.147-1.156,0.795-1.521V37.8h20.188v6.663c0.235,0.352,1.109,0.737,1.229,1.387
C40.445,49.917,26.288,53.051,26.288,53.051z"/&gt;
&lt;radialGradient id="SVGID_3_" cx="15.2056" cy="831.1875" r="32.3071" gradientTransform="matrix(1 0 0 1 0.0801 -773.6914)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_3_)" stroke="#E55E03" d="M49.529,51.225c-2.239-2.24-5.041-3.724-7.396-4.67
c-2.854,5.51-14.021,7.807-14.021,7.807s-10.472-2.483-12.387-8.514c-2.439,0.771-5.787,2.287-8.749,5.25
c-5.592,5.592-6.47,11.67-6.47,11.67c0,1.938,1.575,3.492,3.523,3.492h48.51c1.946,0,3.521-1.558,3.521-3.492
C56.055,62.768,54.211,55.906,49.529,51.225z"/&gt;
&lt;radialGradient id="SVGID_4_" cx="17.0723" cy="18.4907" r="11.8931" gradientTransform="matrix(1 0 0 -1 0.04 64.1543)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_4_)" stroke="#E55E03" d="M13.404,44.173c1.15-1.81,2.039-3.832,3.332-5.397
c-0.514,1.027-1.669,4.084-1.669,5.148c0,5.186,10.366,9.079,14.688,10.438c-3.472,1.627-9.134-1.498-11.334-2.359
c-3.601-1.419-4.071-3.063-5.89-4.854C12.523,47.135,12.878,45,13.404,44.173z"/&gt;
&lt;radialGradient id="SVGID_5_" cx="31.8184" cy="19.3525" r="14.63" gradientTransform="matrix(1 0 0 -1 0.04 64.1543)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_5_)" stroke="#E55E03" d="M45.777,43.924c-1.317-1.568-5.11-9.424-6.604-6.617
c0.516,1.025,3.617,3.693,3.617,6.617c0,5.186-10.271,8.576-16.699,9.145c1.429,4.938,11.373,1.293,13.805-0.313
c3.563-2.354,4.563-5.133,7.854-3.705C47.754,49.045,48.006,46.574,45.777,43.924z"/&gt;
&lt;radialGradient id="SVGID_6_" cx="30.4893" cy="4.8721" r="5.2028" gradientTransform="matrix(1 0 0 -1 0.04 64.1543)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_6_)" stroke="#E55E03" d="M30.777,54.167c0.357,0.836-0.153,1.983-0.352,2.813
c-0.256,1.084-0.072,2.104,0.102,3.186c0.164,1.02,0.156,2.107,0.25,3.167c0.082,0.916,0.482,1.849,0.357,2.75"/&gt;
&lt;radialGradient id="SVGID_7_" cx="23.2871" cy="5.3008" r="5.5143" gradientTransform="matrix(1 0 0 -1 0.04 64.1543)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_7_)" stroke="#E55E03" d="M23.695,53.417c-0.508,0.584-0.476,2.209-0.398,3
c0.116,1.183,0.456,2.099,0.333,3.333c-0.192,1.943,0.154,4.479-0.436,6.333"/&gt;
&lt;radialGradient id="face_x5F_white_1_" cx="27.5835" cy="3117.4922" r="23.425" fx="23.0139" fy="3115.0024" gradientTransform="matrix(1 0 0 1 0.3203 -3091.7656)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FFD28F"/&gt;
&lt;stop offset="1" style="stop-color:#FFAB4F"/&gt;
&lt;/radialGradient&gt;
&lt;path id="face_x5F_white_3_" fill="url(#face_x5F_white_1_)" stroke="#ED9135" stroke-miterlimit="10" d="M43.676,23.357
c0.086,10.2-6.738,18.52-15.25,18.586c-8.5,0.068-15.464-8.146-15.55-18.344C12.794,13.4,19.618,5.079,28.123,5.012
C36.627,4.945,43.59,13.158,43.676,23.357z"/&gt;
&lt;linearGradient id="face_highlight_1_" gradientUnits="userSpaceOnUse" x1="6468.501" y1="-12291.5195" x2="6492.1304" y2="-12384.9688" gradientTransform="matrix(0.275 0 0 -0.2733 -1752.8849 -3351.7349)"&gt;
&lt;stop offset="0" style="stop-color:#FFFFFF;stop-opacity:0.24"/&gt;
&lt;stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.16"/&gt;
&lt;/linearGradient&gt;
&lt;path id="face_highlight_3_" fill="url(#face_highlight_1_)" d="M28.415,5.625c-6.035,0.047-10.747,4.493-12.787,10.386
c-0.664,1.919-0.294,4.043,0.98,5.629c2.73,3.398,5.729,6.283,9.461,8.088c3.137,1.518,7.535,2.385,11.893,1.247
c2.274-0.592,3.988-2.459,4.375-4.766c0.187-1.094,0.293-2.289,0.283-3.553C42.54,13.244,36.729,5.56,28.415,5.625z"/&gt;
&lt;path id="Hair_Young_Black_1_" fill="#5C5C5C" stroke="#353535" stroke-linecap="round" stroke-linejoin="round" d="M20.278,13.25
c3.417,4.333,9.333,6.917,9.333,6.917l-1.417-3.5c0,0,7.094,4.691,8.083,4.333c0.968-0.2-1.082-3.807-1.082-3.807
s3.138,1.795,4.854,3.969c1.803,2.28,4.285,3.504,4.285,3.504S47.027,2.719,27.289,2.744C8.278,2.709,12.058,27.678,12.058,27.678
L14.695,17c0,0,0.914,5.757,1.399,4.875C17.861,15.211,18.861,11.5,20.278,13.25z"/&gt;
&lt;/g&gt;
&lt;/svg&gt;
</y:Resource>
<y:Resource id="2">&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="57px" height="67px" viewBox="0 0 57 67" enable-background="new 0 0 57 67" xml:space="preserve"&gt;
&lt;g&gt;
&lt;linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="26.3398" y1="3115.7266" x2="27.5807" y2="3145.5239" gradientTransform="matrix(1 0 0 1 0.3203 -3091.7656)"&gt;
&lt;stop offset="0.2711" style="stop-color:#FFAB4F"/&gt;
&lt;stop offset="1" style="stop-color:#FFD28F"/&gt;
&lt;/linearGradient&gt;
&lt;path fill="url(#SVGID_1_)" stroke="#ED9135" stroke-miterlimit="10" d="M49.529,51.225c-4.396-4.396-10.951-5.884-12.063-6.109
V37.8H19.278c0,0,0.038,6.903,0,6.868c0,0-6.874,0.997-12.308,6.432C1.378,56.691,0.5,62.77,0.5,62.77
c0,1.938,1.575,3.492,3.523,3.492h48.51c1.947,0,3.521-1.558,3.521-3.492C56.055,62.768,54.211,55.906,49.529,51.225z"/&gt;
&lt;radialGradient id="face_x5F_white_1_" cx="27.5835" cy="3117.4922" r="23.425" fx="23.0139" fy="3115.0024" gradientTransform="matrix(1 0 0 1 0.3203 -3091.7656)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FFD28F"/&gt;
&lt;stop offset="1" style="stop-color:#FFAB4F"/&gt;
&lt;/radialGradient&gt;
&lt;path id="face_x5F_white_3_" fill="url(#face_x5F_white_1_)" stroke="#ED9135" stroke-miterlimit="10" d="M43.676,23.357
c0.086,10.199-6.738,18.52-15.25,18.586c-8.5,0.068-15.464-8.146-15.55-18.344C12.794,13.4,19.618,5.079,28.123,5.012
C36.627,4.945,43.59,13.158,43.676,23.357z"/&gt;
&lt;linearGradient id="face_highlight_1_" gradientUnits="userSpaceOnUse" x1="6468.5" y1="-12286.8594" x2="6492.1294" y2="-12380.3086" gradientTransform="matrix(0.275 0 0 -0.2733 -1752.8849 -3350.4617)"&gt;
&lt;stop offset="0" style="stop-color:#FFFFFF;stop-opacity:0.24"/&gt;
&lt;stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.16"/&gt;
&lt;/linearGradient&gt;
&lt;path id="face_highlight_3_" fill="url(#face_highlight_1_)" d="M28.415,5.625c-6.035,0.047-10.747,4.493-12.787,10.386
c-0.664,1.919-0.294,4.043,0.98,5.629c2.73,3.398,5.729,6.283,9.461,8.088c3.137,1.518,7.535,2.385,11.893,1.247
c2.274-0.592,3.988-2.459,4.375-4.766c0.187-1.094,0.293-2.289,0.283-3.553C42.54,13.244,36.729,5.56,28.415,5.625z"/&gt;
&lt;path id="Hair_Female_1_Red_1_" fill="#FAE1AA" stroke="#E2B354" stroke-linecap="round" stroke-linejoin="round" d="M28.372,0.5
C17.537,0.5,8.269,7.748,9.153,26.125c0.563,6.563,5.862,12.042,9.366,13.531c-2.929-10.968-0.304-25.021-0.585-25.526
c-0.281-0.505,3.536,6.728,3.536,6.728l3.183-8.312c5.541,4.28,0.393,11.309,1.049,11.058c4.26-1.631,5.34-9.228,5.34-9.228
s2.729,3.657,2.701,5.504c-0.054,3.562,2.194-6.067,2.194-6.067l1.027,2.031c6.727,9.822,3.684,16.208,1.648,22.781
c15.666-0.703,12.291-10.48,9.66-18.407C43.59,6.092,39.206,0.5,28.372,0.5z"/&gt;
&lt;linearGradient id="body_1_" gradientUnits="userSpaceOnUse" x1="95.9063" y1="-3134.2153" x2="31.5133" y2="-3134.2153" gradientTransform="matrix(0.9852 0 0 -0.9852 -34.4844 -3031.9851)"&gt;
&lt;stop offset="0" style="stop-color:#49AD33"/&gt;
&lt;stop offset="1" style="stop-color:#C2DA92"/&gt;
&lt;/linearGradient&gt;
&lt;path id="body_8_" fill="url(#body_1_)" stroke="#008D33" d="M0.5,62.768c0,1.938,1.575,3.494,3.523,3.494h48.51
c1.947,0,3.521-1.559,3.521-3.494c0,0-1.844-6.861-6.525-11.543c-4.815-4.813-8.244-5.146-8.244-5.146
c-1.444,6.983-8.555,8.786-13.007,8.786s-11.322-2.643-11.941-9.439c0,0-4.559,1.199-9.367,5.674
C1.378,56.689,0.5,62.768,0.5,62.768z"/&gt;
&lt;/g&gt;
&lt;/svg&gt;
</y:Resource>
</y:Resources>
</data>
</graphml>

BIN
docs/guide-es/images/rbac-access-check-2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

368
docs/guide-es/images/rbac-access-check-3.graphml

@ -0,0 +1,368 @@
<?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.12.2-->
<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">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="69.0" width="103.0" x="34.0" y="-11.5"/>
<y:Fill color="#ADF4A6" transparent="false"/>
<y:BorderStyle color="#FF0000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="36.68359375" x="33.158203125" y="25.1494140625">admin<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="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n1">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="69.0" width="103.0" x="193.0" y="-11.5"/>
<y:Fill color="#ADF4A6" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="38.025390625" x="32.4873046875" y="25.1494140625">author<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="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n2">
<data key="d6">
<y:SVGNode>
<y:Geometry height="64.53585815429688" width="56.560157775878906" x="216.21992111206055" y="-132.03585815429688"/>
<y:Fill color="#CCCCFF" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="62.37109375" x="-2.905467987060547" y="-27.814727783203125">John, ID=2<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.5" nodeRatioX="0.0" nodeRatioY="-0.5" offsetX="0.0" offsetY="-9.113555908203125" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:SVGNodeProperties usingVisualBounds="true"/>
<y:SVGModel svgBoundsPolicy="0">
<y:SVGContent refid="1"/>
</y:SVGModel>
</y:SVGNode>
</data>
</node>
<node id="n3">
<data key="d6">
<y:SVGNode>
<y:Geometry height="66.76200103759766" width="56.554100036621094" x="57.22294998168945" y="-133.14892959594727"/>
<y:Fill color="#CCCCFF" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="62.37109375" x="-2.908496856689453" y="-27.701656341552734">Jane, ID=1<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.5" nodeRatioX="0.0" nodeRatioY="-0.5" offsetX="0.0" offsetY="-9.000484466552734" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:SVGNodeProperties usingVisualBounds="true"/>
<y:SVGModel svgBoundsPolicy="0">
<y:SVGContent refid="2"/>
</y:SVGModel>
</y:SVGNode>
</data>
</node>
<node id="n4">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="69.0" width="103.0" x="34.0" y="197.5"/>
<y:Fill color="#99CCFF" transparent="false"/>
<y:BorderStyle color="#FF0000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="64.71484375" x="19.142578125" y="25.1494140625">updatePost<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="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n5">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="69.0" width="103.0" x="193.0" y="197.5"/>
<y:Fill color="#99CCFF" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="89.388671875" x="6.8056640625" y="25.1494140625">updateOwnPost<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="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n6">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="69.0" width="103.0" x="352.0" y="197.5"/>
<y:Fill color="#99CCFF" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="61.36328125" x="20.818359375" y="25.1494140625">createPost<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="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n7">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="29.535858154296875" width="103.0" x="193.0" y="167.96414184570312"/>
<y:Fill color="#FFCC00" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="64.03515625" x="19.482421875" y="5.4173431396484375">AuthorRule<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="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<edge id="e0" source="n4" target="n0">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FF0000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e1" source="n4" target="n5">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e2" source="n1" target="n0">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e3" source="n6" target="n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
<y:Point x="403.5" y="23.0"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e4" source="n1" target="n2">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e5" source="n0" target="n3">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FF0000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e6" source="n7" target="n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
</graph>
<data key="d0">
<y:Resources>
<y:Resource id="1">&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="57px" height="65px" viewBox="0 0 57 65" enable-background="new 0 0 57 65" xml:space="preserve"&gt;
&lt;g&gt;
&lt;linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="26.3398" y1="3115.7266" x2="27.5807" y2="3145.5239" gradientTransform="matrix(1 0 0 1 0.3203 -3091.7656)"&gt;
&lt;stop offset="0.2711" style="stop-color:#FFAB4F"/&gt;
&lt;stop offset="1" style="stop-color:#FFD28F"/&gt;
&lt;/linearGradient&gt;
&lt;path fill="url(#SVGID_1_)" stroke="#ED9135" stroke-miterlimit="10" d="M49.529,51.225c-4.396-4.396-10.951-5.884-12.063-6.109
V37.8H19.278c0,0,0.038,6.903,0,6.868c0,0-6.874,0.997-12.308,6.432C1.378,56.691,0.5,62.77,0.5,62.77
c0,1.938,1.575,3.492,3.523,3.492h48.51c1.947,0,3.521-1.558,3.521-3.492C56.055,62.768,54.211,55.906,49.529,51.225z"/&gt;
&lt;path id="body_18_" fill="#ECECEC" stroke="#9B9B9B" stroke-miterlimit="10" d="M0.5,62.768c0,1.938,1.575,3.494,3.523,3.494h48.51
c1.947,0,3.521-1.559,3.521-3.494c0,0-1.844-6.861-6.525-11.543c-4.815-4.813-11.244-6.146-11.244-6.146
c-1.771,1.655-5.61,3.802-10.063,3.802c-4.453,0-8.292-2.146-10.063-3.802c0,0-5.755,0.586-11.189,6.021
C1.378,56.689,0.5,62.768,0.5,62.768z"/&gt;
&lt;radialGradient id="SVGID_2_" cx="22.6621" cy="21.707" r="17.7954" gradientTransform="matrix(1 0 0 -1 0.04 64.1543)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_2_)" stroke="#E55E03" d="M28.106,33.486c-8.112,0-12.688,4.313-12.688,10.438
c0,7.422,12.688,10.438,12.688,10.438s14.688-3.016,14.688-10.438C42.793,38.75,36.215,33.486,28.106,33.486z M26.288,53.051
c0,0-7.135-2.093-8.805-7.201c-0.222-0.682,0.147-1.156,0.795-1.521V37.8h20.188v6.663c0.235,0.352,1.109,0.737,1.229,1.387
C40.445,49.917,26.288,53.051,26.288,53.051z"/&gt;
&lt;radialGradient id="SVGID_3_" cx="15.2056" cy="831.1875" r="32.3071" gradientTransform="matrix(1 0 0 1 0.0801 -773.6914)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_3_)" stroke="#E55E03" d="M49.529,51.225c-2.239-2.24-5.041-3.724-7.396-4.67
c-2.854,5.51-14.021,7.807-14.021,7.807s-10.472-2.483-12.387-8.514c-2.439,0.771-5.787,2.287-8.749,5.25
c-5.592,5.592-6.47,11.67-6.47,11.67c0,1.938,1.575,3.492,3.523,3.492h48.51c1.946,0,3.521-1.558,3.521-3.492
C56.055,62.768,54.211,55.906,49.529,51.225z"/&gt;
&lt;radialGradient id="SVGID_4_" cx="17.0723" cy="18.4907" r="11.8931" gradientTransform="matrix(1 0 0 -1 0.04 64.1543)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_4_)" stroke="#E55E03" d="M13.404,44.173c1.15-1.81,2.039-3.832,3.332-5.397
c-0.514,1.027-1.669,4.084-1.669,5.148c0,5.186,10.366,9.079,14.688,10.438c-3.472,1.627-9.134-1.498-11.334-2.359
c-3.601-1.419-4.071-3.063-5.89-4.854C12.523,47.135,12.878,45,13.404,44.173z"/&gt;
&lt;radialGradient id="SVGID_5_" cx="31.8184" cy="19.3525" r="14.63" gradientTransform="matrix(1 0 0 -1 0.04 64.1543)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_5_)" stroke="#E55E03" d="M45.777,43.924c-1.317-1.568-5.11-9.424-6.604-6.617
c0.516,1.025,3.617,3.693,3.617,6.617c0,5.186-10.271,8.576-16.699,9.145c1.429,4.938,11.373,1.293,13.805-0.313
c3.563-2.354,4.563-5.133,7.854-3.705C47.754,49.045,48.006,46.574,45.777,43.924z"/&gt;
&lt;radialGradient id="SVGID_6_" cx="30.4893" cy="4.8721" r="5.2028" gradientTransform="matrix(1 0 0 -1 0.04 64.1543)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_6_)" stroke="#E55E03" d="M30.777,54.167c0.357,0.836-0.153,1.983-0.352,2.813
c-0.256,1.084-0.072,2.104,0.102,3.186c0.164,1.02,0.156,2.107,0.25,3.167c0.082,0.916,0.482,1.849,0.357,2.75"/&gt;
&lt;radialGradient id="SVGID_7_" cx="23.2871" cy="5.3008" r="5.5143" gradientTransform="matrix(1 0 0 -1 0.04 64.1543)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_7_)" stroke="#E55E03" d="M23.695,53.417c-0.508,0.584-0.476,2.209-0.398,3
c0.116,1.183,0.456,2.099,0.333,3.333c-0.192,1.943,0.154,4.479-0.436,6.333"/&gt;
&lt;radialGradient id="face_x5F_white_1_" cx="27.5835" cy="3117.4922" r="23.425" fx="23.0139" fy="3115.0024" gradientTransform="matrix(1 0 0 1 0.3203 -3091.7656)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FFD28F"/&gt;
&lt;stop offset="1" style="stop-color:#FFAB4F"/&gt;
&lt;/radialGradient&gt;
&lt;path id="face_x5F_white_3_" fill="url(#face_x5F_white_1_)" stroke="#ED9135" stroke-miterlimit="10" d="M43.676,23.357
c0.086,10.2-6.738,18.52-15.25,18.586c-8.5,0.068-15.464-8.146-15.55-18.344C12.794,13.4,19.618,5.079,28.123,5.012
C36.627,4.945,43.59,13.158,43.676,23.357z"/&gt;
&lt;linearGradient id="face_highlight_1_" gradientUnits="userSpaceOnUse" x1="6468.501" y1="-12291.5195" x2="6492.1304" y2="-12384.9688" gradientTransform="matrix(0.275 0 0 -0.2733 -1752.8849 -3351.7349)"&gt;
&lt;stop offset="0" style="stop-color:#FFFFFF;stop-opacity:0.24"/&gt;
&lt;stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.16"/&gt;
&lt;/linearGradient&gt;
&lt;path id="face_highlight_3_" fill="url(#face_highlight_1_)" d="M28.415,5.625c-6.035,0.047-10.747,4.493-12.787,10.386
c-0.664,1.919-0.294,4.043,0.98,5.629c2.73,3.398,5.729,6.283,9.461,8.088c3.137,1.518,7.535,2.385,11.893,1.247
c2.274-0.592,3.988-2.459,4.375-4.766c0.187-1.094,0.293-2.289,0.283-3.553C42.54,13.244,36.729,5.56,28.415,5.625z"/&gt;
&lt;path id="Hair_Young_Black_1_" fill="#5C5C5C" stroke="#353535" stroke-linecap="round" stroke-linejoin="round" d="M20.278,13.25
c3.417,4.333,9.333,6.917,9.333,6.917l-1.417-3.5c0,0,7.094,4.691,8.083,4.333c0.968-0.2-1.082-3.807-1.082-3.807
s3.138,1.795,4.854,3.969c1.803,2.28,4.285,3.504,4.285,3.504S47.027,2.719,27.289,2.744C8.278,2.709,12.058,27.678,12.058,27.678
L14.695,17c0,0,0.914,5.757,1.399,4.875C17.861,15.211,18.861,11.5,20.278,13.25z"/&gt;
&lt;/g&gt;
&lt;/svg&gt;
</y:Resource>
<y:Resource id="2">&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="57px" height="67px" viewBox="0 0 57 67" enable-background="new 0 0 57 67" xml:space="preserve"&gt;
&lt;g&gt;
&lt;linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="26.3398" y1="3115.7266" x2="27.5807" y2="3145.5239" gradientTransform="matrix(1 0 0 1 0.3203 -3091.7656)"&gt;
&lt;stop offset="0.2711" style="stop-color:#FFAB4F"/&gt;
&lt;stop offset="1" style="stop-color:#FFD28F"/&gt;
&lt;/linearGradient&gt;
&lt;path fill="url(#SVGID_1_)" stroke="#ED9135" stroke-miterlimit="10" d="M49.529,51.225c-4.396-4.396-10.951-5.884-12.063-6.109
V37.8H19.278c0,0,0.038,6.903,0,6.868c0,0-6.874,0.997-12.308,6.432C1.378,56.691,0.5,62.77,0.5,62.77
c0,1.938,1.575,3.492,3.523,3.492h48.51c1.947,0,3.521-1.558,3.521-3.492C56.055,62.768,54.211,55.906,49.529,51.225z"/&gt;
&lt;radialGradient id="face_x5F_white_1_" cx="27.5835" cy="3117.4922" r="23.425" fx="23.0139" fy="3115.0024" gradientTransform="matrix(1 0 0 1 0.3203 -3091.7656)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FFD28F"/&gt;
&lt;stop offset="1" style="stop-color:#FFAB4F"/&gt;
&lt;/radialGradient&gt;
&lt;path id="face_x5F_white_3_" fill="url(#face_x5F_white_1_)" stroke="#ED9135" stroke-miterlimit="10" d="M43.676,23.357
c0.086,10.199-6.738,18.52-15.25,18.586c-8.5,0.068-15.464-8.146-15.55-18.344C12.794,13.4,19.618,5.079,28.123,5.012
C36.627,4.945,43.59,13.158,43.676,23.357z"/&gt;
&lt;linearGradient id="face_highlight_1_" gradientUnits="userSpaceOnUse" x1="6468.5" y1="-12286.8594" x2="6492.1294" y2="-12380.3086" gradientTransform="matrix(0.275 0 0 -0.2733 -1752.8849 -3350.4617)"&gt;
&lt;stop offset="0" style="stop-color:#FFFFFF;stop-opacity:0.24"/&gt;
&lt;stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.16"/&gt;
&lt;/linearGradient&gt;
&lt;path id="face_highlight_3_" fill="url(#face_highlight_1_)" d="M28.415,5.625c-6.035,0.047-10.747,4.493-12.787,10.386
c-0.664,1.919-0.294,4.043,0.98,5.629c2.73,3.398,5.729,6.283,9.461,8.088c3.137,1.518,7.535,2.385,11.893,1.247
c2.274-0.592,3.988-2.459,4.375-4.766c0.187-1.094,0.293-2.289,0.283-3.553C42.54,13.244,36.729,5.56,28.415,5.625z"/&gt;
&lt;path id="Hair_Female_1_Red_1_" fill="#FAE1AA" stroke="#E2B354" stroke-linecap="round" stroke-linejoin="round" d="M28.372,0.5
C17.537,0.5,8.269,7.748,9.153,26.125c0.563,6.563,5.862,12.042,9.366,13.531c-2.929-10.968-0.304-25.021-0.585-25.526
c-0.281-0.505,3.536,6.728,3.536,6.728l3.183-8.312c5.541,4.28,0.393,11.309,1.049,11.058c4.26-1.631,5.34-9.228,5.34-9.228
s2.729,3.657,2.701,5.504c-0.054,3.562,2.194-6.067,2.194-6.067l1.027,2.031c6.727,9.822,3.684,16.208,1.648,22.781
c15.666-0.703,12.291-10.48,9.66-18.407C43.59,6.092,39.206,0.5,28.372,0.5z"/&gt;
&lt;linearGradient id="body_1_" gradientUnits="userSpaceOnUse" x1="95.9063" y1="-3134.2153" x2="31.5133" y2="-3134.2153" gradientTransform="matrix(0.9852 0 0 -0.9852 -34.4844 -3031.9851)"&gt;
&lt;stop offset="0" style="stop-color:#49AD33"/&gt;
&lt;stop offset="1" style="stop-color:#C2DA92"/&gt;
&lt;/linearGradient&gt;
&lt;path id="body_8_" fill="url(#body_1_)" stroke="#008D33" d="M0.5,62.768c0,1.938,1.575,3.494,3.523,3.494h48.51
c1.947,0,3.521-1.559,3.521-3.494c0,0-1.844-6.861-6.525-11.543c-4.815-4.813-8.244-5.146-8.244-5.146
c-1.444,6.983-8.555,8.786-13.007,8.786s-11.322-2.643-11.941-9.439c0,0-4.559,1.199-9.367,5.674
C1.378,56.689,0.5,62.768,0.5,62.768z"/&gt;
&lt;/g&gt;
&lt;/svg&gt;
</y:Resource>
</y:Resources>
</data>
</graphml>

BIN
docs/guide-es/images/rbac-access-check-3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

312
docs/guide-es/images/rbac-hierarchy-1.graphml

@ -0,0 +1,312 @@
<?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.12.2-->
<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">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="69.0" width="103.0" x="34.0" y="-11.5"/>
<y:Fill color="#ADF4A6" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="36.68359375" x="33.158203125" y="25.1494140625">admin<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="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n1">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="69.0" width="103.0" x="193.0" y="-11.5"/>
<y:Fill color="#ADF4A6" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="38.025390625" x="32.4873046875" y="25.1494140625">author<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="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n2">
<data key="d6">
<y:SVGNode>
<y:Geometry height="64.53585815429688" width="56.560157775878906" x="216.21992111206055" y="-132.03585815429688"/>
<y:Fill color="#CCCCFF" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="62.37109375" x="-2.905467987060547" y="-27.814727783203125">John, ID=2<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.5" nodeRatioX="0.0" nodeRatioY="-0.5" offsetX="0.0" offsetY="-9.113555908203125" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:SVGNodeProperties usingVisualBounds="true"/>
<y:SVGModel svgBoundsPolicy="0">
<y:SVGContent refid="1"/>
</y:SVGModel>
</y:SVGNode>
</data>
</node>
<node id="n3">
<data key="d6">
<y:SVGNode>
<y:Geometry height="66.76200103759766" width="56.554100036621094" x="57.22294998168945" y="-133.14892959594727"/>
<y:Fill color="#CCCCFF" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="62.37109375" x="-2.908496856689453" y="-27.701656341552734">Jane, ID=1<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.5" nodeRatioX="0.0" nodeRatioY="-0.5" offsetX="0.0" offsetY="-9.000484466552734" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:SVGNodeProperties usingVisualBounds="true"/>
<y:SVGModel svgBoundsPolicy="0">
<y:SVGContent refid="2"/>
</y:SVGModel>
</y:SVGNode>
</data>
</node>
<node id="n4">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="69.0" width="103.0" x="34.0" y="197.5"/>
<y:Fill color="#99CCFF" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="64.71484375" x="19.142578125" y="25.1494140625">updatePost<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="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n5">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="69.0" width="103.0" x="193.0" y="197.5"/>
<y:Fill color="#99CCFF" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="61.36328125" x="20.818359375" y="25.1494140625">createPost<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="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<edge id="e0" source="n4" target="n0">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e1" source="n1" target="n0">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e2" source="n1" target="n2">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e3" source="n0" target="n3">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e4" source="n5" target="n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
</graph>
<data key="d0">
<y:Resources>
<y:Resource id="1">&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="57px" height="65px" viewBox="0 0 57 65" enable-background="new 0 0 57 65" xml:space="preserve"&gt;
&lt;g&gt;
&lt;linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="26.3398" y1="3115.7266" x2="27.5807" y2="3145.5239" gradientTransform="matrix(1 0 0 1 0.3203 -3091.7656)"&gt;
&lt;stop offset="0.2711" style="stop-color:#FFAB4F"/&gt;
&lt;stop offset="1" style="stop-color:#FFD28F"/&gt;
&lt;/linearGradient&gt;
&lt;path fill="url(#SVGID_1_)" stroke="#ED9135" stroke-miterlimit="10" d="M49.529,51.225c-4.396-4.396-10.951-5.884-12.063-6.109
V37.8H19.278c0,0,0.038,6.903,0,6.868c0,0-6.874,0.997-12.308,6.432C1.378,56.691,0.5,62.77,0.5,62.77
c0,1.938,1.575,3.492,3.523,3.492h48.51c1.947,0,3.521-1.558,3.521-3.492C56.055,62.768,54.211,55.906,49.529,51.225z"/&gt;
&lt;path id="body_18_" fill="#ECECEC" stroke="#9B9B9B" stroke-miterlimit="10" d="M0.5,62.768c0,1.938,1.575,3.494,3.523,3.494h48.51
c1.947,0,3.521-1.559,3.521-3.494c0,0-1.844-6.861-6.525-11.543c-4.815-4.813-11.244-6.146-11.244-6.146
c-1.771,1.655-5.61,3.802-10.063,3.802c-4.453,0-8.292-2.146-10.063-3.802c0,0-5.755,0.586-11.189,6.021
C1.378,56.689,0.5,62.768,0.5,62.768z"/&gt;
&lt;radialGradient id="SVGID_2_" cx="22.6621" cy="21.707" r="17.7954" gradientTransform="matrix(1 0 0 -1 0.04 64.1543)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_2_)" stroke="#E55E03" d="M28.106,33.486c-8.112,0-12.688,4.313-12.688,10.438
c0,7.422,12.688,10.438,12.688,10.438s14.688-3.016,14.688-10.438C42.793,38.75,36.215,33.486,28.106,33.486z M26.288,53.051
c0,0-7.135-2.093-8.805-7.201c-0.222-0.682,0.147-1.156,0.795-1.521V37.8h20.188v6.663c0.235,0.352,1.109,0.737,1.229,1.387
C40.445,49.917,26.288,53.051,26.288,53.051z"/&gt;
&lt;radialGradient id="SVGID_3_" cx="15.2056" cy="831.1875" r="32.3071" gradientTransform="matrix(1 0 0 1 0.0801 -773.6914)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_3_)" stroke="#E55E03" d="M49.529,51.225c-2.239-2.24-5.041-3.724-7.396-4.67
c-2.854,5.51-14.021,7.807-14.021,7.807s-10.472-2.483-12.387-8.514c-2.439,0.771-5.787,2.287-8.749,5.25
c-5.592,5.592-6.47,11.67-6.47,11.67c0,1.938,1.575,3.492,3.523,3.492h48.51c1.946,0,3.521-1.558,3.521-3.492
C56.055,62.768,54.211,55.906,49.529,51.225z"/&gt;
&lt;radialGradient id="SVGID_4_" cx="17.0723" cy="18.4907" r="11.8931" gradientTransform="matrix(1 0 0 -1 0.04 64.1543)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_4_)" stroke="#E55E03" d="M13.404,44.173c1.15-1.81,2.039-3.832,3.332-5.397
c-0.514,1.027-1.669,4.084-1.669,5.148c0,5.186,10.366,9.079,14.688,10.438c-3.472,1.627-9.134-1.498-11.334-2.359
c-3.601-1.419-4.071-3.063-5.89-4.854C12.523,47.135,12.878,45,13.404,44.173z"/&gt;
&lt;radialGradient id="SVGID_5_" cx="31.8184" cy="19.3525" r="14.63" gradientTransform="matrix(1 0 0 -1 0.04 64.1543)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_5_)" stroke="#E55E03" d="M45.777,43.924c-1.317-1.568-5.11-9.424-6.604-6.617
c0.516,1.025,3.617,3.693,3.617,6.617c0,5.186-10.271,8.576-16.699,9.145c1.429,4.938,11.373,1.293,13.805-0.313
c3.563-2.354,4.563-5.133,7.854-3.705C47.754,49.045,48.006,46.574,45.777,43.924z"/&gt;
&lt;radialGradient id="SVGID_6_" cx="30.4893" cy="4.8721" r="5.2028" gradientTransform="matrix(1 0 0 -1 0.04 64.1543)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_6_)" stroke="#E55E03" d="M30.777,54.167c0.357,0.836-0.153,1.983-0.352,2.813
c-0.256,1.084-0.072,2.104,0.102,3.186c0.164,1.02,0.156,2.107,0.25,3.167c0.082,0.916,0.482,1.849,0.357,2.75"/&gt;
&lt;radialGradient id="SVGID_7_" cx="23.2871" cy="5.3008" r="5.5143" gradientTransform="matrix(1 0 0 -1 0.04 64.1543)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_7_)" stroke="#E55E03" d="M23.695,53.417c-0.508,0.584-0.476,2.209-0.398,3
c0.116,1.183,0.456,2.099,0.333,3.333c-0.192,1.943,0.154,4.479-0.436,6.333"/&gt;
&lt;radialGradient id="face_x5F_white_1_" cx="27.5835" cy="3117.4922" r="23.425" fx="23.0139" fy="3115.0024" gradientTransform="matrix(1 0 0 1 0.3203 -3091.7656)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FFD28F"/&gt;
&lt;stop offset="1" style="stop-color:#FFAB4F"/&gt;
&lt;/radialGradient&gt;
&lt;path id="face_x5F_white_3_" fill="url(#face_x5F_white_1_)" stroke="#ED9135" stroke-miterlimit="10" d="M43.676,23.357
c0.086,10.2-6.738,18.52-15.25,18.586c-8.5,0.068-15.464-8.146-15.55-18.344C12.794,13.4,19.618,5.079,28.123,5.012
C36.627,4.945,43.59,13.158,43.676,23.357z"/&gt;
&lt;linearGradient id="face_highlight_1_" gradientUnits="userSpaceOnUse" x1="6468.501" y1="-12291.5195" x2="6492.1304" y2="-12384.9688" gradientTransform="matrix(0.275 0 0 -0.2733 -1752.8849 -3351.7349)"&gt;
&lt;stop offset="0" style="stop-color:#FFFFFF;stop-opacity:0.24"/&gt;
&lt;stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.16"/&gt;
&lt;/linearGradient&gt;
&lt;path id="face_highlight_3_" fill="url(#face_highlight_1_)" d="M28.415,5.625c-6.035,0.047-10.747,4.493-12.787,10.386
c-0.664,1.919-0.294,4.043,0.98,5.629c2.73,3.398,5.729,6.283,9.461,8.088c3.137,1.518,7.535,2.385,11.893,1.247
c2.274-0.592,3.988-2.459,4.375-4.766c0.187-1.094,0.293-2.289,0.283-3.553C42.54,13.244,36.729,5.56,28.415,5.625z"/&gt;
&lt;path id="Hair_Young_Black_1_" fill="#5C5C5C" stroke="#353535" stroke-linecap="round" stroke-linejoin="round" d="M20.278,13.25
c3.417,4.333,9.333,6.917,9.333,6.917l-1.417-3.5c0,0,7.094,4.691,8.083,4.333c0.968-0.2-1.082-3.807-1.082-3.807
s3.138,1.795,4.854,3.969c1.803,2.28,4.285,3.504,4.285,3.504S47.027,2.719,27.289,2.744C8.278,2.709,12.058,27.678,12.058,27.678
L14.695,17c0,0,0.914,5.757,1.399,4.875C17.861,15.211,18.861,11.5,20.278,13.25z"/&gt;
&lt;/g&gt;
&lt;/svg&gt;
</y:Resource>
<y:Resource id="2">&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="57px" height="67px" viewBox="0 0 57 67" enable-background="new 0 0 57 67" xml:space="preserve"&gt;
&lt;g&gt;
&lt;linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="26.3398" y1="3115.7266" x2="27.5807" y2="3145.5239" gradientTransform="matrix(1 0 0 1 0.3203 -3091.7656)"&gt;
&lt;stop offset="0.2711" style="stop-color:#FFAB4F"/&gt;
&lt;stop offset="1" style="stop-color:#FFD28F"/&gt;
&lt;/linearGradient&gt;
&lt;path fill="url(#SVGID_1_)" stroke="#ED9135" stroke-miterlimit="10" d="M49.529,51.225c-4.396-4.396-10.951-5.884-12.063-6.109
V37.8H19.278c0,0,0.038,6.903,0,6.868c0,0-6.874,0.997-12.308,6.432C1.378,56.691,0.5,62.77,0.5,62.77
c0,1.938,1.575,3.492,3.523,3.492h48.51c1.947,0,3.521-1.558,3.521-3.492C56.055,62.768,54.211,55.906,49.529,51.225z"/&gt;
&lt;radialGradient id="face_x5F_white_1_" cx="27.5835" cy="3117.4922" r="23.425" fx="23.0139" fy="3115.0024" gradientTransform="matrix(1 0 0 1 0.3203 -3091.7656)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FFD28F"/&gt;
&lt;stop offset="1" style="stop-color:#FFAB4F"/&gt;
&lt;/radialGradient&gt;
&lt;path id="face_x5F_white_3_" fill="url(#face_x5F_white_1_)" stroke="#ED9135" stroke-miterlimit="10" d="M43.676,23.357
c0.086,10.199-6.738,18.52-15.25,18.586c-8.5,0.068-15.464-8.146-15.55-18.344C12.794,13.4,19.618,5.079,28.123,5.012
C36.627,4.945,43.59,13.158,43.676,23.357z"/&gt;
&lt;linearGradient id="face_highlight_1_" gradientUnits="userSpaceOnUse" x1="6468.5" y1="-12286.8594" x2="6492.1294" y2="-12380.3086" gradientTransform="matrix(0.275 0 0 -0.2733 -1752.8849 -3350.4617)"&gt;
&lt;stop offset="0" style="stop-color:#FFFFFF;stop-opacity:0.24"/&gt;
&lt;stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.16"/&gt;
&lt;/linearGradient&gt;
&lt;path id="face_highlight_3_" fill="url(#face_highlight_1_)" d="M28.415,5.625c-6.035,0.047-10.747,4.493-12.787,10.386
c-0.664,1.919-0.294,4.043,0.98,5.629c2.73,3.398,5.729,6.283,9.461,8.088c3.137,1.518,7.535,2.385,11.893,1.247
c2.274-0.592,3.988-2.459,4.375-4.766c0.187-1.094,0.293-2.289,0.283-3.553C42.54,13.244,36.729,5.56,28.415,5.625z"/&gt;
&lt;path id="Hair_Female_1_Red_1_" fill="#FAE1AA" stroke="#E2B354" stroke-linecap="round" stroke-linejoin="round" d="M28.372,0.5
C17.537,0.5,8.269,7.748,9.153,26.125c0.563,6.563,5.862,12.042,9.366,13.531c-2.929-10.968-0.304-25.021-0.585-25.526
c-0.281-0.505,3.536,6.728,3.536,6.728l3.183-8.312c5.541,4.28,0.393,11.309,1.049,11.058c4.26-1.631,5.34-9.228,5.34-9.228
s2.729,3.657,2.701,5.504c-0.054,3.562,2.194-6.067,2.194-6.067l1.027,2.031c6.727,9.822,3.684,16.208,1.648,22.781
c15.666-0.703,12.291-10.48,9.66-18.407C43.59,6.092,39.206,0.5,28.372,0.5z"/&gt;
&lt;linearGradient id="body_1_" gradientUnits="userSpaceOnUse" x1="95.9063" y1="-3134.2153" x2="31.5133" y2="-3134.2153" gradientTransform="matrix(0.9852 0 0 -0.9852 -34.4844 -3031.9851)"&gt;
&lt;stop offset="0" style="stop-color:#49AD33"/&gt;
&lt;stop offset="1" style="stop-color:#C2DA92"/&gt;
&lt;/linearGradient&gt;
&lt;path id="body_8_" fill="url(#body_1_)" stroke="#008D33" d="M0.5,62.768c0,1.938,1.575,3.494,3.523,3.494h48.51
c1.947,0,3.521-1.559,3.521-3.494c0,0-1.844-6.861-6.525-11.543c-4.815-4.813-8.244-5.146-8.244-5.146
c-1.444,6.983-8.555,8.786-13.007,8.786s-11.322-2.643-11.941-9.439c0,0-4.559,1.199-9.367,5.674
C1.378,56.689,0.5,62.768,0.5,62.768z"/&gt;
&lt;/g&gt;
&lt;/svg&gt;
</y:Resource>
</y:Resources>
</data>
</graphml>

BIN
docs/guide-es/images/rbac-hierarchy-1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

368
docs/guide-es/images/rbac-hierarchy-2.graphml

@ -0,0 +1,368 @@
<?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.12.2-->
<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">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="69.0" width="103.0" x="34.0" y="-11.5"/>
<y:Fill color="#ADF4A6" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="36.68359375" x="33.158203125" y="25.1494140625">admin<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="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n1">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="69.0" width="103.0" x="193.0" y="-11.5"/>
<y:Fill color="#ADF4A6" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="38.025390625" x="32.4873046875" y="25.1494140625">author<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="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n2">
<data key="d6">
<y:SVGNode>
<y:Geometry height="64.53585815429688" width="56.560157775878906" x="216.21992111206055" y="-132.03585815429688"/>
<y:Fill color="#CCCCFF" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="62.37109375" x="-2.905467987060547" y="-27.814727783203125">John, ID=2<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.5" nodeRatioX="0.0" nodeRatioY="-0.5" offsetX="0.0" offsetY="-9.113555908203125" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:SVGNodeProperties usingVisualBounds="true"/>
<y:SVGModel svgBoundsPolicy="0">
<y:SVGContent refid="1"/>
</y:SVGModel>
</y:SVGNode>
</data>
</node>
<node id="n3">
<data key="d6">
<y:SVGNode>
<y:Geometry height="66.76200103759766" width="56.554100036621094" x="57.22294998168945" y="-133.14892959594727"/>
<y:Fill color="#CCCCFF" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="62.37109375" x="-2.908496856689453" y="-27.701656341552734">Jane, ID=1<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.5" nodeRatioX="0.0" nodeRatioY="-0.5" offsetX="0.0" offsetY="-9.000484466552734" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:SVGNodeProperties usingVisualBounds="true"/>
<y:SVGModel svgBoundsPolicy="0">
<y:SVGContent refid="2"/>
</y:SVGModel>
</y:SVGNode>
</data>
</node>
<node id="n4">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="69.0" width="103.0" x="34.0" y="197.5"/>
<y:Fill color="#99CCFF" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="64.71484375" x="19.142578125" y="25.1494140625">updatePost<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="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n5">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="69.0" width="103.0" x="193.0" y="197.5"/>
<y:Fill color="#99CCFF" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="89.388671875" x="6.8056640625" y="25.1494140625">updateOwnPost<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="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n6">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="69.0" width="103.0" x="352.0" y="197.5"/>
<y:Fill color="#99CCFF" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="61.36328125" x="20.818359375" y="25.1494140625">createPost<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="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n7">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="29.535858154296875" width="103.0" x="193.0" y="167.96414184570312"/>
<y:Fill color="#FFCC00" 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.701171875" modelName="custom" textColor="#000000" visible="true" width="64.03515625" x="19.482421875" y="5.4173431396484375">AuthorRule<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="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<edge id="e0" source="n4" target="n0">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e1" source="n4" target="n5">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e2" source="n1" target="n0">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e3" source="n6" target="n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
<y:Point x="403.5" y="23.0"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e4" source="n1" target="n2">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e5" source="n0" target="n3">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e6" source="n7" target="n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
</graph>
<data key="d0">
<y:Resources>
<y:Resource id="1">&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="57px" height="65px" viewBox="0 0 57 65" enable-background="new 0 0 57 65" xml:space="preserve"&gt;
&lt;g&gt;
&lt;linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="26.3398" y1="3115.7266" x2="27.5807" y2="3145.5239" gradientTransform="matrix(1 0 0 1 0.3203 -3091.7656)"&gt;
&lt;stop offset="0.2711" style="stop-color:#FFAB4F"/&gt;
&lt;stop offset="1" style="stop-color:#FFD28F"/&gt;
&lt;/linearGradient&gt;
&lt;path fill="url(#SVGID_1_)" stroke="#ED9135" stroke-miterlimit="10" d="M49.529,51.225c-4.396-4.396-10.951-5.884-12.063-6.109
V37.8H19.278c0,0,0.038,6.903,0,6.868c0,0-6.874,0.997-12.308,6.432C1.378,56.691,0.5,62.77,0.5,62.77
c0,1.938,1.575,3.492,3.523,3.492h48.51c1.947,0,3.521-1.558,3.521-3.492C56.055,62.768,54.211,55.906,49.529,51.225z"/&gt;
&lt;path id="body_18_" fill="#ECECEC" stroke="#9B9B9B" stroke-miterlimit="10" d="M0.5,62.768c0,1.938,1.575,3.494,3.523,3.494h48.51
c1.947,0,3.521-1.559,3.521-3.494c0,0-1.844-6.861-6.525-11.543c-4.815-4.813-11.244-6.146-11.244-6.146
c-1.771,1.655-5.61,3.802-10.063,3.802c-4.453,0-8.292-2.146-10.063-3.802c0,0-5.755,0.586-11.189,6.021
C1.378,56.689,0.5,62.768,0.5,62.768z"/&gt;
&lt;radialGradient id="SVGID_2_" cx="22.6621" cy="21.707" r="17.7954" gradientTransform="matrix(1 0 0 -1 0.04 64.1543)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_2_)" stroke="#E55E03" d="M28.106,33.486c-8.112,0-12.688,4.313-12.688,10.438
c0,7.422,12.688,10.438,12.688,10.438s14.688-3.016,14.688-10.438C42.793,38.75,36.215,33.486,28.106,33.486z M26.288,53.051
c0,0-7.135-2.093-8.805-7.201c-0.222-0.682,0.147-1.156,0.795-1.521V37.8h20.188v6.663c0.235,0.352,1.109,0.737,1.229,1.387
C40.445,49.917,26.288,53.051,26.288,53.051z"/&gt;
&lt;radialGradient id="SVGID_3_" cx="15.2056" cy="831.1875" r="32.3071" gradientTransform="matrix(1 0 0 1 0.0801 -773.6914)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_3_)" stroke="#E55E03" d="M49.529,51.225c-2.239-2.24-5.041-3.724-7.396-4.67
c-2.854,5.51-14.021,7.807-14.021,7.807s-10.472-2.483-12.387-8.514c-2.439,0.771-5.787,2.287-8.749,5.25
c-5.592,5.592-6.47,11.67-6.47,11.67c0,1.938,1.575,3.492,3.523,3.492h48.51c1.946,0,3.521-1.558,3.521-3.492
C56.055,62.768,54.211,55.906,49.529,51.225z"/&gt;
&lt;radialGradient id="SVGID_4_" cx="17.0723" cy="18.4907" r="11.8931" gradientTransform="matrix(1 0 0 -1 0.04 64.1543)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_4_)" stroke="#E55E03" d="M13.404,44.173c1.15-1.81,2.039-3.832,3.332-5.397
c-0.514,1.027-1.669,4.084-1.669,5.148c0,5.186,10.366,9.079,14.688,10.438c-3.472,1.627-9.134-1.498-11.334-2.359
c-3.601-1.419-4.071-3.063-5.89-4.854C12.523,47.135,12.878,45,13.404,44.173z"/&gt;
&lt;radialGradient id="SVGID_5_" cx="31.8184" cy="19.3525" r="14.63" gradientTransform="matrix(1 0 0 -1 0.04 64.1543)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_5_)" stroke="#E55E03" d="M45.777,43.924c-1.317-1.568-5.11-9.424-6.604-6.617
c0.516,1.025,3.617,3.693,3.617,6.617c0,5.186-10.271,8.576-16.699,9.145c1.429,4.938,11.373,1.293,13.805-0.313
c3.563-2.354,4.563-5.133,7.854-3.705C47.754,49.045,48.006,46.574,45.777,43.924z"/&gt;
&lt;radialGradient id="SVGID_6_" cx="30.4893" cy="4.8721" r="5.2028" gradientTransform="matrix(1 0 0 -1 0.04 64.1543)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_6_)" stroke="#E55E03" d="M30.777,54.167c0.357,0.836-0.153,1.983-0.352,2.813
c-0.256,1.084-0.072,2.104,0.102,3.186c0.164,1.02,0.156,2.107,0.25,3.167c0.082,0.916,0.482,1.849,0.357,2.75"/&gt;
&lt;radialGradient id="SVGID_7_" cx="23.2871" cy="5.3008" r="5.5143" gradientTransform="matrix(1 0 0 -1 0.04 64.1543)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FCB57A"/&gt;
&lt;stop offset="1" style="stop-color:#FF8C36"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_7_)" stroke="#E55E03" d="M23.695,53.417c-0.508,0.584-0.476,2.209-0.398,3
c0.116,1.183,0.456,2.099,0.333,3.333c-0.192,1.943,0.154,4.479-0.436,6.333"/&gt;
&lt;radialGradient id="face_x5F_white_1_" cx="27.5835" cy="3117.4922" r="23.425" fx="23.0139" fy="3115.0024" gradientTransform="matrix(1 0 0 1 0.3203 -3091.7656)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FFD28F"/&gt;
&lt;stop offset="1" style="stop-color:#FFAB4F"/&gt;
&lt;/radialGradient&gt;
&lt;path id="face_x5F_white_3_" fill="url(#face_x5F_white_1_)" stroke="#ED9135" stroke-miterlimit="10" d="M43.676,23.357
c0.086,10.2-6.738,18.52-15.25,18.586c-8.5,0.068-15.464-8.146-15.55-18.344C12.794,13.4,19.618,5.079,28.123,5.012
C36.627,4.945,43.59,13.158,43.676,23.357z"/&gt;
&lt;linearGradient id="face_highlight_1_" gradientUnits="userSpaceOnUse" x1="6468.501" y1="-12291.5195" x2="6492.1304" y2="-12384.9688" gradientTransform="matrix(0.275 0 0 -0.2733 -1752.8849 -3351.7349)"&gt;
&lt;stop offset="0" style="stop-color:#FFFFFF;stop-opacity:0.24"/&gt;
&lt;stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.16"/&gt;
&lt;/linearGradient&gt;
&lt;path id="face_highlight_3_" fill="url(#face_highlight_1_)" d="M28.415,5.625c-6.035,0.047-10.747,4.493-12.787,10.386
c-0.664,1.919-0.294,4.043,0.98,5.629c2.73,3.398,5.729,6.283,9.461,8.088c3.137,1.518,7.535,2.385,11.893,1.247
c2.274-0.592,3.988-2.459,4.375-4.766c0.187-1.094,0.293-2.289,0.283-3.553C42.54,13.244,36.729,5.56,28.415,5.625z"/&gt;
&lt;path id="Hair_Young_Black_1_" fill="#5C5C5C" stroke="#353535" stroke-linecap="round" stroke-linejoin="round" d="M20.278,13.25
c3.417,4.333,9.333,6.917,9.333,6.917l-1.417-3.5c0,0,7.094,4.691,8.083,4.333c0.968-0.2-1.082-3.807-1.082-3.807
s3.138,1.795,4.854,3.969c1.803,2.28,4.285,3.504,4.285,3.504S47.027,2.719,27.289,2.744C8.278,2.709,12.058,27.678,12.058,27.678
L14.695,17c0,0,0.914,5.757,1.399,4.875C17.861,15.211,18.861,11.5,20.278,13.25z"/&gt;
&lt;/g&gt;
&lt;/svg&gt;
</y:Resource>
<y:Resource id="2">&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="57px" height="67px" viewBox="0 0 57 67" enable-background="new 0 0 57 67" xml:space="preserve"&gt;
&lt;g&gt;
&lt;linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="26.3398" y1="3115.7266" x2="27.5807" y2="3145.5239" gradientTransform="matrix(1 0 0 1 0.3203 -3091.7656)"&gt;
&lt;stop offset="0.2711" style="stop-color:#FFAB4F"/&gt;
&lt;stop offset="1" style="stop-color:#FFD28F"/&gt;
&lt;/linearGradient&gt;
&lt;path fill="url(#SVGID_1_)" stroke="#ED9135" stroke-miterlimit="10" d="M49.529,51.225c-4.396-4.396-10.951-5.884-12.063-6.109
V37.8H19.278c0,0,0.038,6.903,0,6.868c0,0-6.874,0.997-12.308,6.432C1.378,56.691,0.5,62.77,0.5,62.77
c0,1.938,1.575,3.492,3.523,3.492h48.51c1.947,0,3.521-1.558,3.521-3.492C56.055,62.768,54.211,55.906,49.529,51.225z"/&gt;
&lt;radialGradient id="face_x5F_white_1_" cx="27.5835" cy="3117.4922" r="23.425" fx="23.0139" fy="3115.0024" gradientTransform="matrix(1 0 0 1 0.3203 -3091.7656)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FFD28F"/&gt;
&lt;stop offset="1" style="stop-color:#FFAB4F"/&gt;
&lt;/radialGradient&gt;
&lt;path id="face_x5F_white_3_" fill="url(#face_x5F_white_1_)" stroke="#ED9135" stroke-miterlimit="10" d="M43.676,23.357
c0.086,10.199-6.738,18.52-15.25,18.586c-8.5,0.068-15.464-8.146-15.55-18.344C12.794,13.4,19.618,5.079,28.123,5.012
C36.627,4.945,43.59,13.158,43.676,23.357z"/&gt;
&lt;linearGradient id="face_highlight_1_" gradientUnits="userSpaceOnUse" x1="6468.5" y1="-12286.8594" x2="6492.1294" y2="-12380.3086" gradientTransform="matrix(0.275 0 0 -0.2733 -1752.8849 -3350.4617)"&gt;
&lt;stop offset="0" style="stop-color:#FFFFFF;stop-opacity:0.24"/&gt;
&lt;stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.16"/&gt;
&lt;/linearGradient&gt;
&lt;path id="face_highlight_3_" fill="url(#face_highlight_1_)" d="M28.415,5.625c-6.035,0.047-10.747,4.493-12.787,10.386
c-0.664,1.919-0.294,4.043,0.98,5.629c2.73,3.398,5.729,6.283,9.461,8.088c3.137,1.518,7.535,2.385,11.893,1.247
c2.274-0.592,3.988-2.459,4.375-4.766c0.187-1.094,0.293-2.289,0.283-3.553C42.54,13.244,36.729,5.56,28.415,5.625z"/&gt;
&lt;path id="Hair_Female_1_Red_1_" fill="#FAE1AA" stroke="#E2B354" stroke-linecap="round" stroke-linejoin="round" d="M28.372,0.5
C17.537,0.5,8.269,7.748,9.153,26.125c0.563,6.563,5.862,12.042,9.366,13.531c-2.929-10.968-0.304-25.021-0.585-25.526
c-0.281-0.505,3.536,6.728,3.536,6.728l3.183-8.312c5.541,4.28,0.393,11.309,1.049,11.058c4.26-1.631,5.34-9.228,5.34-9.228
s2.729,3.657,2.701,5.504c-0.054,3.562,2.194-6.067,2.194-6.067l1.027,2.031c6.727,9.822,3.684,16.208,1.648,22.781
c15.666-0.703,12.291-10.48,9.66-18.407C43.59,6.092,39.206,0.5,28.372,0.5z"/&gt;
&lt;linearGradient id="body_1_" gradientUnits="userSpaceOnUse" x1="95.9063" y1="-3134.2153" x2="31.5133" y2="-3134.2153" gradientTransform="matrix(0.9852 0 0 -0.9852 -34.4844 -3031.9851)"&gt;
&lt;stop offset="0" style="stop-color:#49AD33"/&gt;
&lt;stop offset="1" style="stop-color:#C2DA92"/&gt;
&lt;/linearGradient&gt;
&lt;path id="body_8_" fill="url(#body_1_)" stroke="#008D33" d="M0.5,62.768c0,1.938,1.575,3.494,3.523,3.494h48.51
c1.947,0,3.521-1.559,3.521-3.494c0,0-1.844-6.861-6.525-11.543c-4.815-4.813-8.244-5.146-8.244-5.146
c-1.444,6.983-8.555,8.786-13.007,8.786s-11.322-2.643-11.941-9.439c0,0-4.559,1.199-9.367,5.674
C1.378,56.689,0.5,62.768,0.5,62.768z"/&gt;
&lt;/g&gt;
&lt;/svg&gt;
</y:Resource>
</y:Resources>
</data>
</graphml>

BIN
docs/guide-es/images/rbac-hierarchy-2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
docs/guide-es/images/tutorial-console-help.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

208
docs/guide-es/input-file-upload.md

@ -0,0 +1,208 @@
Subir Archivos
==============
Subir archivos en Yii es normalmente realizado con la ayuda de [[yii\web\UploadedFile]], que encapsula cada archivo subido
en un objeto `UploadedFile`. Combinado con [[yii\widgets\ActiveForm]] y [modelos](structure-models.md),
puedes fácilmente implementar un mecanismo seguro de subida de archivos.
## Crear Modelos <span id="creating-models"></span>
Al igual que al trabajar con entradas de texto plano, para subir un archivo debes crear una clase de modelo y utilizar un atributo
de dicho modelo para mantener la instancia del archivo subido. Debes también declarar una regla para validar la subida del archivo.
Por ejemplo,
```php
namespace app\models;
use yii\base\Model;
use yii\web\UploadedFile;
class UploadForm extends Model
{
/**
* @var UploadedFile
*/
public $imageFile;
public function rules()
{
return [
[['imageFile'], 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg'],
];
}
public function upload()
{
if ($this->validate()) {
$this->imageFile->saveAs('uploads/' . $this->imageFile->baseName . '.' . $this->imageFile->extension);
return true;
} else {
return false;
}
}
}
```
En el código anterior, el atributo `imageFile` es utilizado para mantener una instancia del archivo subido. Este está asociado con
una regla de validación `file`, que utiliza [[yii\validators\FileValidator]] para asegurarse que el archivo a subir tenga extensión `png` o `jpg`.
El método `upload()` realizará la validación y guardará el archivo subido en el servidor.
El validador `file` te permite chequear las extensiones, el tamaño, el tipo MIME, etc. Por favor consulta
la sección [Validadores del Framework](tutorial-core-validators.md#file) para más detalles.
> Tip: Si estás subiendo una imagen, podrías considerar el utilizar el validador `image`. El validador `image` es
implementado a través de [[yii\validators\ImageValidator]], que verifica que un atributo haya recibido una imagen válida
que pueda ser tanto guardada como procesada utilizando la [Extensión Imagine](https://github.com/yiisoft/yii2-imagine).
## Renderizar Campos de Subida de Archivos <span id="rendering-file-input"></span>
A continuación, crea un campo de subida de archivo en la vista:
```php
<?php
use yii\widgets\ActiveForm;
?>
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]) ?>
<?= $form->field($model, 'imageFile')->fileInput() ?>
<button>Enviar</button>
<?php ActiveForm::end() ?>
```
Es importante recordad que agregues la opción `enctype` al formulario para que el archivo pueda ser subido apropiadamente.
La llamada a `fileInput()` renderizará un tag `<input type="file">` que le permitirá al usuario seleccionar el archivo a subir.
> Tip: desde la versión 2.0.8, [[yii\web\widgets\ActiveField::fileInput|fileInput]] agrega la opción `enctype` al formulario
automáticamente cuando se utiliza una campo de subida de archivo.
## Uniendo Todo <span id="wiring-up"></span>
Ahora, en una acción del controlador, escribe el código que una el modelo y la vista para implementar la subida de archivos:
```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->imageFile = UploadedFile::getInstance($model, 'imageFile');
if ($model->upload()) {
// el archivo se subió exitosamente
return;
}
}
return $this->render('upload', ['model' => $model]);
}
}
```
En el código anterior, cuando se envía el formulario, el método [[yii\web\UploadedFile::getInstance()]] es llamado
para representar el archivo subido como una instancia de `UploadedFile`. Entonces dependemos de la validación del modelo
para asegurarnos que el archivo subido es válido y entonces subirlo al servidor.
## Uploading Multiple Files <span id="uploading-multiple-files"></span>
También puedes subir varios archivos a la vez, con algunos ajustes en el código de las subsecciones previas.
Primero debes ajustar la clase del modelo, agregando la opción `maxFiles` en la regla de validación `file` para limitar
el número máximo de archivos a subir. Definir `maxFiles` como `0` significa que no hay límite en el número de archivos
a subir simultáneamente. El número máximo de archivos permitidos para subir simultáneamente está también limitado
por la directiva PHP [`max_file_uploads`](http://php.net/manual/en/ini.core.php#ini.max-file-uploads),
cuyo valor por defecto es 20. El método `upload()` debería también ser modificado para guardar los archivos uno a uno.
```php
namespace app\models;
use yii\base\Model;
use yii\web\UploadedFile;
class UploadForm extends Model
{
/**
* @var UploadedFile[]
*/
public $imageFiles;
public function rules()
{
return [
[['imageFiles'], 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg', 'maxFiles' => 4],
];
}
public function upload()
{
if ($this->validate()) {
foreach ($this->imageFiles as $file) {
$file->saveAs('uploads/' . $file->baseName . '.' . $file->extension);
}
return true;
} else {
return false;
}
}
}
```
En el archivo de la vista, debes agregar la opción `multiple` en la llamada a `fileInput()` de manera que el campo
pueda recibir varios archivos:
```php
<?php
use yii\widgets\ActiveForm;
?>
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]) ?>
<?= $form->field($model, 'imageFiles[]')->fileInput(['multiple' => true, 'accept' => 'image/*']) ?>
<button>Enviar</button>
<?php ActiveForm::end() ?>
```
Y finalmente en la acción del controlador, debes llamar `UploadedFile::getInstances()` en vez de
`UploadedFile::getInstance()` para asignar un array de instancias `UploadedFile` a `UploadForm::imageFiles`.
```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->imageFiles = UploadedFile::getInstances($model, 'imageFiles');
if ($model->upload()) {
// el archivo fue subido exitosamente
return;
}
}
return $this->render('upload', ['model' => $model]);
}
}
```

714
docs/guide-es/input-validation.md

@ -0,0 +1,714 @@
Validación de Entrada
=====================
Como regla básica, nunca debes confiar en los datos recibidos de un usuario final y deberías validarlo siempre
antes de ponerlo en uso.
Dado un [modelo](structure-models.md) poblado con entradas de usuarios, puedes validar esas entradas llamando al
método [[yii\base\Model::validate()]]. Dicho método devolverá un valor booleano indicando si la validación
tuvo éxito o no. En caso de que no, puedes obtener los mensajes de error de la propiedad [[yii\base\Model::errors]]. Por ejemplo,
```php
$model = new \app\models\ContactForm();
// poblar los atributos del modelo desde la entrada del usuario
$model->load(\Yii::$app->request->post());
// lo que es equivalente a:
// $model->attributes = \Yii::$app->request->post('ContactForm');
if ($model->validate()) {
// toda la entrada es válida
} else {
// la validación falló: $errors es un array que contienen los mensajes de error
$errors = $model->errors;
}
```
## Declarar Reglas <span id="declaring-rules"></span>
Para hacer que `validate()` realmente funcione, debes declarar reglas de validación para los atributos que planeas validar.
Esto debería hacerse sobrescribiendo el método [[yii\base\Model::rules()]]. El siguiente ejemplo muestra cómo
son declaradas las reglas de validación para el modelo `ContactForm`:
```php
public function rules()
{
return [
// los atributos name, email, subject y body son obligatorios
[['name', 'email', 'subject', 'body'], 'required'],
// el atributo email debe ser una dirección de email válida
['email', 'email'],
];
}
```
El método [[yii\base\Model::rules()|rules()]] debe devolver un array de reglas, la cual cada una
tiene el siguiente formato:
```php
[
// requerido, especifica qué atributos deben ser validados por esta regla.
// Para un sólo atributo, puedes utilizar su nombre directamente
// sin tenerlo dentro de un array
['attribute1', 'attribute2', ...],
// requerido, especifica de qué tipo es la regla.
// Puede ser un nombre de clase, un alias de validador, o el nombre de un método de validación
'validator',
// opcional, especifica en qué escenario/s esta regla debe aplicarse
// si no se especifica, significa que la regla se aplica en todos los escenarios
// Puedes también configurar la opción "except" en caso de que quieras aplicar la regla
// en todos los escenarios salvo los listados
'on' => ['scenario1', 'scenario2', ...],
// opcional, especifica atributos adicionales para el objeto validador
'property1' => 'value1', 'property2' => 'value2', ...
]
```
Por cada regla debes especificar al menos a cuáles atributos aplica la regla y cuál es el tipo de la regla.
Puedes especificar el tipo de regla de las siguientes maneras:
* el alias de un validador propio del framework, tal como `required`, `in`, `date`, etc. Por favor consulta
[Validadores del núcleo](tutorial-core-validators.md) para la lista completa de todos los validadores incluidos.
* el nombre de un método de validación en la clase del modelo, o una función anónima. Consulta la
subsección [Validadores en Línea](#inline-validators) para más detalles.
* el nombre completo de una clase de validador. Por favor consulta la subsección [Validadores Independientes](#standalone-validators)
para más detalles.
Una regla puede ser utilizada para validar uno o varios atributos, y un atributo puede ser validado por una o varias reglas.
Una regla puede ser aplicada en ciertos [escenarios](structure-models.md#scenarios) con tan sólo especificando la opción `on`.
Si no especificas una opción `on`, significa que la regla se aplicará en todos los escenarios.
Cuando el método `validate()` es llamado, este sigue los siguientes pasos para realiza la validación:
1. Determina cuáles atributos deberían ser validados obteniendo la lista de atributos de [[yii\base\Model::scenarios()]]
utilizando el [[yii\base\Model::scenario|scenario]] actual. Estos atributos son llamados *atributos activos*.
2. Determina cuáles reglas de validación deberían ser validados obteniendo la lista de reglas de [[yii\base\Model::rules()]]
utilizando el [[yii\base\Model::scenario|scenario]] actual. Estas reglas son llamadas *reglas activas*.
3. Utiliza cada regla activa para validar cada atributo activo que esté asociado a la regla.
Las reglas de validación son evaluadas en el orden en que están listadas.
De acuerdo a los pasos de validación mostrados arriba, un atributo será validado si y sólo si
es un atributo activo declarado en `scenarios()` y está asociado a una o varias reglas activas
declaradas en `rules()`.
> Note: Es práctico darle nombre a las reglas, por ej:
> ```php
> public function rules()
> {
> return [
> // ...
> 'password' => [['password'], 'string', 'max' => 60],
> ];
> }
> ```
>
> Puedes utilizarlas en una subclase del modelo:
>
> ```php
> public function rules()
> {
> $rules = parent::rules();
> unset($rules['password']);
> return $rules;
> }
### Personalizar Mensajes de Error <span id="customizing-error-messages"></span>
La mayoría de los validadores tienen mensajes de error por defecto que serán agregados al modelo siendo validado cuando sus atributos
fallan la validación. Por ejemplo, el validador [[yii\validators\RequiredValidator|required]] agregará
el mensaje "Username no puede estar vacío." a un modelo cuando falla la validación del atributo `username` al utilizar esta regla.
Puedes especificar el mensaje de error de una regla especificado la propiedad `message` al declarar la regla,
como a continuación,
```php
public function rules()
{
return [
['username', 'required', 'message' => 'Por favor escoge un nombre de usuario.'],
];
}
```
Algunos validadores pueden soportar mensajes de error adicionales para describir más precisamente las causas
del fallo de validación. Por ejemplo, el validador [[yii\validators\NumberValidator|number]] soporta
[[yii\validators\NumberValidator::tooBig|tooBig]] y [[yii\validators\NumberValidator::tooSmall|tooSmall]]
para describir si el fallo de validación es porque el valor siendo validado es demasiado grande o demasiado pequeño, respectivamente.
Puedes configurar estos mensajes de error tal como cualquier otroa propiedad del validador en una regla de validación.
### Eventos de Validación <span id="validation-events"></span>
Cuando el método [[yii\base\Model::validate()]] es llamado, este llamará a dos métodos que puedes sobrescribir para personalizar
el proceso de validación:
* [[yii\base\Model::beforeValidate()]]: la implementación por defecto lanzará un evento [[yii\base\Model::EVENT_BEFORE_VALIDATE]].
Puedes tanto sobrescribir este método o responder a este evento para realizar algún trabajo de pre procesamiento
(por ej. normalizar datos de entrada) antes de que ocurra la validación en sí. El método debe devolver un booleano que indique
si la validación debe continuar o no.
* [[yii\base\Model::afterValidate()]]: la implementación por defecto lanzará un evento [[yii\base\Model::EVENT_AFTER_VALIDATE]].
uedes tanto sobrescribir este método o responder a este evento para realizar algún trabajo de post procesamiento después
de completada la validación.
### Validación Condicional <span id="conditional-validation"></span>
Para validar atributos sólo en determinadas condiciones, por ej. la validación de un atributo depende
del valor de otro atributo puedes utilizar la propiedad [[yii\validators\Validator::when|when]]
para definir la condición. Por ejemplo,
```php
['state', 'required', 'when' => function($model) {
return $model->country == 'USA';
}]
```
La propiedad [[yii\validators\Validator::when|when]] toma un método invocable PHP con la siguiente firma:
```php
/**
* @param Model $model el modelo siendo validado
* @param string $attribute al atributo siendo validado
* @return boolean si la regla debe ser aplicada o no
*/
function ($model, $attribute)
```
Si también necesitas soportar validación condicional del lado del cliente, debes configurar
la propiedad [[yii\validators\Validator::whenClient|whenClient]], que toma un string que representa una función JavaScript
cuyo valor de retorno determina si debe aplicarse la regla o no. Por ejemplo,
```php
['state', 'required', 'when' => function ($model) {
return $model->country == 'USA';
}, 'whenClient' => "function (attribute, value) {
return $('#country').val() == 'USA';
}"]
```
### Filtro de Datos <span id="data-filtering"></span>
La entrada del usuario a menudo debe ser filtrada o pre procesada. Por ejemplo, podrías querer eliminar los espacions alrededor
de la entrada `username`. Puedes utilizar reglas de validación para lograrlo.
Los siguientes ejemplos muestran cómo eliminar esos espacios en la entrada y cómo transformar entradas vacías en null utilizando
los validadores del framework [trim](tutorial-core-validators.md#trim) y [default](tutorial-core-validators.md#default):
```php
return [
[['username', 'email'], 'trim'],
[['username', 'email'], 'default'],
];
```
También puedes utilizar el validador más general [filter](tutorial-core-validators.md#filter) para realizar filtros
de datos más complejos.
Como puedes ver, estas reglas de validación no validan la entrada realmente. En cambio, procesan los valores
y los guardan en el atributo siendo validado.
### Manejando Entradas Vacías <span id="handling-empty-inputs"></span>
Cuando los datos de entrada son enviados desde formularios HTML, a menudo necesitas asignar algunos valores por defecto a las entradas
si estas están vacías. Puedes hacerlo utilizando el validador [default](tutorial-core-validators.md#default). Por ejemplo,
```php
return [
// convierte "username" y "email" en null si estos están vacíos
[['username', 'email'], 'default'],
// convierte "level" a 1 si está vacío
['level', 'default', 'value' => 1],
];
```
Por defecto, una entrada se considera vacía si su valor es un string vacío, un array vacío o null.
Puedes personalizar la lógica de detección de valores vacíos configurando la propiedad [[yii\validators\Validator::isEmpty]]
con una función PHP invocable. Por ejemplo,
```php
['agree', 'required', 'isEmpty' => function ($value) {
return empty($value);
}]
```
> Note: La mayoría de los validadores no manejan entradas vacías si su propiedad [[yii\validators\Validator::skipOnEmpty]] toma
el valor por defecto true. Estas serán simplemente salteadas durante la validación si sus atributos asociados reciben una entrada vacía.
Entre los [validadores del framework](tutorial-core-validators.md), sólo `captcha`, `default`, `filter`,
`required`, y `trim` manejarán entradas vacías.
## Validación Ad Hoc <span id="ad-hoc-validation"></span>
A veces necesitas realizar *validación ad hoc* para valores que no están ligados a ningún modelo.
Si sólo necesitas realizar un tipo de validación (por ej: validar direcciones de email), podrías llamar
al método [[yii\validators\Validator::validate()|validate()]] de los validadores deseados, como a continuación:
```php
$email = 'test@example.com';
$validator = new yii\validators\EmailValidator();
if ($validator->validate($email, $error)) {
echo 'Email válido.';
} else {
echo $error;
}
```
> Note: No todos los validadores soportan este tipo de validación. Un ejemplo es el validador del framework [unique](tutorial-core-validators.md#unique),
que está diseñado para trabajar sólo con un modelo.
Si necesitas realizar varias validaciones contro varios valores, puedes utilizar [[yii\base\DynamicModel]],
que soporta declarar tanto los atributos como las reglas sobre la marcha. Su uso es como a continuación:
```php
public function actionSearch($name, $email)
{
$model = DynamicModel::validateData(compact('name', 'email'), [
[['name', 'email'], 'string', 'max' => 128],
['email', 'email'],
]);
if ($model->hasErrors()) {
// validación fallida
} else {
// validación exitosa
}
}
```
El método [[yii\base\DynamicModel::validateData()]] crea una instancia de `DynamicModel`, define los atributos
utilizando los datos provistos (`name` e `email` en este ejemplo), y entonces llama a [[yii\base\Model::validate()]]
con las reglas provistas.
Alternativamente, puedes utilizar la sintaxis más "clásica" para realizar la validación ad hoc:
```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()) {
// validación fallida
} else {
// validación exitosa
}
}
```
Después de la validación, puedes verificar si la validación tuvo éxito o no llamando al
método [[yii\base\DynamicModel::hasErrors()|hasErrors()]], obteniendo así los errores de validación de la
propiedad [[yii\base\DynamicModel::errors|errors]], como haces con un modelo normal.
Puedes también acceder a los atributos dinámicos definidos a través de la instancia del modelo, por ej.,
`$model->name` y `$model->email`.
## Crear Validadores <span id="creating-validators"></span>
Además de los [validadores del framework](tutorial-core-validators.md) incluidos en los lanzamientos de Yii, puedes también
crear tus propios validadores. Puedes crear validadores en línea o validadores independientes.
### Validadores en Línea <span id="inline-validators"></span>
Un validador en línea es uno definido en términos del método de un modelo o una función anónima. La firma
del método/función es:
```php
/**
* @param string $attribute el atributo siendo validado actualmente
* @param mixed $params el valor de los "parámetros" dados en la regla
*/
function ($attribute, $params)
```
Si falla la validación de un atributo, el método/función debería llamar a [[yii\base\Model::addError()]] para guardar
el mensaje de error en el modelo de manera que pueda ser recuperado más tarde y presentado a los usuarios finales.
Debajo hay algunos ejemplos:
```php
use yii\base\Model;
class MyForm extends Model
{
public $country;
public $token;
public function rules()
{
return [
// un validador en línea definido como el método del modelo validateCountry()
['country', 'validateCountry'],
// un validador en línea definido como una función anónima
['token', function ($attribute, $params) {
if (!ctype_alnum($this->$attribute)) {
$this->addError($attribute, 'El token debe contener letras y dígitos.');
}
}],
];
}
public function validateCountry($attribute, $params)
{
if (!in_array($this->$attribute, ['USA', 'Web'])) {
$this->addError($attribute, 'El país debe ser "USA" o "Web".');
}
}
}
```
> Note: Por defecto, los validadores en línea no serán aplicados si sus atributos asociados reciben entradas vacías
o si alguna de sus reglas de validación ya falló. Si quieres asegurarte de que una regla siempre sea aplicada,
puedes configurar las reglas [[yii\validators\Validator::skipOnEmpty|skipOnEmpty]] y/o [[yii\validators\Validator::skipOnError|skipOnError]]
como false en las declaraciones de las reglas. Por ejemplo:
>
> ```php
> [
> ['country', 'validateCountry', 'skipOnEmpty' => false, 'skipOnError' => false],
> ]
> ```
### Validadores Independientes <span id="standalone-validators"></span>
Un validador independiente es una clase que extiende de [[yii\validators\Validator]] o sus sub clases. Puedes implementar
su lógica de validación sobrescribiendo el método [[yii\validators\Validator::validateAttribute()]]. Si falla la validación
de un atributo, llama a [[yii\base\Model::addError()]] para guardar el mensaje de error en el modelo, tal como haces
con los [validadores en línea](#inline-validators).
Por ejemplo, el validador en línea de arriba podría ser movida a una nueva clase [[components/validators/CountryValidator]].
```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, 'El país debe ser "USA" o "Web".');
}
}
}
```
Si quieres que tu validador soporte la validación de un valor sin modelo, deberías también sobrescribir
el método[[yii\validators\Validator::validate()]]. Puedes también sobrescribir [[yii\validators\Validator::validateValue()]]
en vez de `validateAttribute()` y `validate()` porque por defecto los últimos dos métodos son implementados
llamando a `validateValue()`.
Debajo hay un ejemplo de cómo podrías utilizar la clase del validador de arriba dentro de tu modelo.
```php
namespace app\models;
use Yii;
use yii\base\Model;
use app\components\validators\CountryValidator;
class EntryForm extends Model
{
public $name;
public $email;
public $country;
public function rules()
{
return [
[['name', 'email'], 'required'],
['country', CountryValidator::className()],
['email', 'email'],
];
}
}
```
## Validación del Lado del Cliente <span id="client-side-validation"></span>
La validación del lado del cliente basada en JavaScript es deseable cuando la entrada del usuario proviene de formularios HTML, dado que
permite a los usuarios encontrar errores más rápido y por lo tanto provee una mejor experiencia. Puedes utilizar o implementar
un validador que soporte validación del lado del cliente *en adición a* validación del lado del servidor.
> Info: Si bien la validación del lado del cliente es deseable, no es una necesidad. Su principal propósito es proveer al usuario una mejor
experiencia. Al igual que datos de entrada que vienen del los usuarios finales, nunca deberías confiar en la validación del lado del cliente. Por esta razón,
deberías realizar siempre la validación del lado del servidor llamando a [[yii\base\Model::validate()]], como
se describió en las subsecciones previas.
### Utilizar Validación del Lado del Cliente <span id="using-client-side-validation"></span>
Varios [validadores del framework](tutorial-core-validators.md) incluyen validación del lado del cliente. Todo lo que necesitas hacer
es solamente utilizar [[yii\widgets\ActiveForm]] para construir tus formularios HTML. Por ejemplo, `LoginForm` mostrado abajo declara dos
reglas: una utiliza el validador del framework [required](tutorial-core-validators.md#required), el cual es soportado tanto en
lado del cliente como del servidor; y el otro usa el validador en línea `validatePassword`, que es sólo soportado de lado
del servidor.
```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 y password son ambos requeridos
[['username', 'password'], 'required'],
// password es validado por validatePassword()
['password', 'validatePassword'],
];
}
public function validatePassword()
{
$user = User::findByUsername($this->username);
if (!$user || !$user->validatePassword($this->password)) {
$this->addError('password', 'Username o password incorrecto.');
}
}
}
```
El formulario HTML creado en el siguiente código contiene dos campos de entrada: `username` y `password`.
Si envias el formulario sin escribir nada, encontrarás que los mensajes de error requiriendo que
escribas algo aparecen sin que haya comunicación alguna con el servidor.
```php
<?php $form = yii\widgets\ActiveForm::begin(); ?>
<?= $form->field($model, 'username') ?>
<?= $form->field($model, 'password')->passwordInput() ?>
<?= Html::submitButton('Login') ?>
<?php yii\widgets\ActiveForm::end(); ?>
```
Detrás de escena, [[yii\widgets\ActiveForm]] leerá las reglas de validación declaradas en el modelo
y generará el código JavaScript apropiado para los validadores que soportan validación del lado del cliente. Cuando un usuario
cambia el valor de un campo o envia el formulario, se lanzará la validación JavaScript del lado del cliente.
Si quieres deshabilitar la validación del lado del cliente completamente, puedes configurar
la propiedad [[yii\widgets\ActiveForm::enableClientValidation]] como false. También puedes deshabilitar la validación
del lado del cliente de campos individuales configurando su propiedad [[yii\widgets\ActiveField::enableClientValidation]]
como false. Cuando `enableClientValidation` es configurado tanto a nivel de campo como a nivel de formulario,
tendrá prioridad la primera.
### Implementar Validación del Lado del Cliente <span id="implementing-client-side-validation"></span>
Para crear validadores que soportan validación del lado del cliente, debes implementar
el método [[yii\validators\Validator::clientValidateAttribute()]], que devuelve una pieza de código JavaScript
que realiza dicha validación. Dentro del código JavaScript, puedes utilizar las siguientes
variables predefinidas:
- `attribute`: el nombre del atributo siendo validado.
- `value`: el valor siendo validado.
- `messages`: un array utilizado para contener los mensajes de error de validación para el atributo.
- `deferred`: un array con objetos diferidos puede ser insertado (explicado en la subsección siguiente).
En el siguiente ejemplo, creamos un `StatusValidator` que valida si la entrada es un status válido
contra datos de status existentes. El validador soporta tato tanto validación del lado del servidor como del lado del cliente.
```php
namespace app\components;
use yii\validators\Validator;
use app\models\Status;
class StatusValidator extends Validator
{
public function init()
{
parent::init();
$this->message = 'Entrada de Status Inválida.';
}
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) === -1) {
messages.push($message);
}
JS;
}
}
```
> Tip: El código de arriba muestra principalmente cómo soportar validación del lado del cliente. En la práctica,
> puedes utilizar el validador del framework [in](tutorial-core-validators.md#in) para alcanzar el mismo objetivo. Puedes
> escribir la regla de validación como a como a continuación:
>
> ```php
> [
> ['status', 'in', 'range' => Status::find()->select('id')->asArray()->column()],
> ]
> ```
> Tip: Si necesitas trabajar con validación del lado del cliente manualmente, por ejemplo, agregar campos dinámicamente o realizar alguna lógica de UI,
> consulta [Trabajar con ActiveForm vía JavaScript](https://github.com/samdark/yii2-cookbook/blob/master/book/forms-activeform-js.md)
> en el Yii 2.0 Cookbook.
### Validación Diferida <span id="deferred-validation"></span>
Si necesitas realizar validación del lado del cliente asincrónica, puedes crear [Objetos Diferidos](http://api.jquery.com/category/deferred-object/).
Por ejemplo, para realizar validación AJAX personalizada, puedes utilizar el siguiente código:
```php
public function clientValidateAttribute($model, $attribute, $view)
{
return <<<JS
deferred.push($.get("/check", {value: value}).done(function(data) {
if ('' !== data) {
messages.push(data);
}
}));
JS;
}
```
Arriba, la variable `deferred` es provista por Yii, y es un array de Objetos Diferidos. El método `$.get()`
de jQuery crea un Objeto Diferido, el cual es insertado en el array `deferred`.
Puedes también crear un Objeto Diferito explícitamente y llamar a su método `resolve()` cuando la llamada asincrónica
tiene lugar. El siguiente ejemplo muestra cómo validar las dimensiones de un archivo de imagen del lado del cliente.
```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('Imagen demasiado ancha!!');
}
def.resolve();
}
var reader = new FileReader();
reader.onloadend = function() {
img.src = reader.result;
}
reader.readAsDataURL(file);
deferred.push(def);
JS;
}
```
> Note: El método `resolve()` debe ser llamado después de que el atributo ha sido validado. De otra manera la validación
principal del formulario no será completada.
Por simplicidad, el array `deferred` está equipado con un método de atajo, `add()`, que automáticamente crea un
Objeto Diferido y lo agrega al array `deferred`. Utilizando este método, puedes simplificar el ejemplo de arriba de esta manera,
```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('Imagen demasiado ancha!!');
}
def.resolve();
}
var reader = new FileReader();
reader.onloadend = function() {
img.src = reader.result;
}
reader.readAsDataURL(file);
});
JS;
}
```
### Validación AJAX <span id="ajax-validation"></span>
Algunas validaciones sólo pueden realizarse del lado del servidor, debido a que sólo el servidor tiene la información necesaria.
Por ejemplo, para validar si un nombre de usuario es único o no, es necesario revisar la tabla de usuarios del lado del servidor.
Puedes utilizar validación basada en AJAX en este caso. Esta lanzará una petición AJAX de fondo para validar
la entrada mientras se mantiene la misma experiencia de usuario como en una validación del lado del cliente regular.
Para habilitar la validación AJAX individualmente un campo de entrada, configura la propiedad [[yii\widgets\ActiveField::enableAjaxValidation|enableAjaxValidation]]
de ese campo como true y especifica un único `id` de formulario:
```php
use yii\widgets\ActiveForm;
$form = ActiveForm::begin([
'id' => 'registration-form',
]);
echo $form->field($model, 'username', ['enableAjaxValidation' => true]);
// ...
ActiveForm::end();
```
Para habiliar la validación AJAX en el formulario entero, configura [[yii\widgets\ActiveForm::enableAjaxValidation|enableAjaxValidation]]
como true a nivel del formulario:
```php
$form = ActiveForm::begin([
'id' => 'contact-form',
'enableAjaxValidation' => true,
]);
```
> Note: Cuando la propiedad `enableAjaxValidation` es configurada tanto a nivel de campo como a nivel de formulario,
la primera tendrá prioridad.
Necesitas también preparar el servidor para que pueda manejar las peticiones AJAX.
Esto puede alcanzarse con una porción de código como la siguiente en las acciones del controlador:
```php
if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
Yii::$app->response->format = Response::FORMAT_JSON;
return ActiveForm::validate($model);
}
```
El código de arriba chequeará si la petición actual es AJAX o no. Si lo es, responderá
esta petición ejecutando la validación y devolviendo los errores en formato JSON.
> Info: Puedes también utilizar [Validación Diferida](#deferred-validation) para realizar validación AJAX.
De todos modos, la característica de validación AJAX descrita aquí es más sistemática y requiere menos esfuerzo de escritura de código.
Cuando tanto `enableClientValidation` como `enableAjaxValidation` son definidas como true, la petición de validación AJAX será lanzada
sólo después de una validación del lado del cliente exitosa.

44
docs/guide-es/intro-upgrade-from-v1.md

@ -1,5 +1,5 @@
Actualizando desde Yii 1.1
==========================
Actualizar desde Yii 1.1
========================
Existen muchas diferencias entre las versiones 1.1 y 2.0 de Yii ya que el framework fue completamente reescrito
en su segunda versión.
@ -18,7 +18,8 @@ Instalación
Yii 2.0 adopta íntegramente [Composer](https://getcomposer.org/), el administrador de paquetes de facto de PHP.
Tanto la instalación del núcleo del framework como las extensiones se manejan a través de Composer. Por favor consulta
la sección [Comenzando con la Aplicación Básica](start-installation.md) para aprender a instalar Yii 2.0. Si quieres crear extensiones
o transformar extensiones de Yii 1.1 para que sean compatibles con Yii 2.0, consulta la sección [Creando Extensiones](structure-extensions.md#creating-extensions) de la guía.
o transformar extensiones de Yii 1.1 para que sean compatibles con Yii 2.0, consulta
la sección [Creando Extensiones](structure-extensions.md#creating-extensions) de la guía.
Requerimientos de PHP
@ -107,7 +108,7 @@ $object = Yii::createObject([
], [$param1, $param2]);
```
Se puede encontrar más detalles acerca del tema en la sección [Configuración de objetos](concept-configurations.md).
Se puede encontrar más detalles acerca del tema en la sección [Configuración](concept-configurations.md).
Eventos
@ -142,7 +143,7 @@ están soportados en la mayor parte del núcleo. Por ejemplo, [[yii\caching\File
una ruta de directorios normal como un alias.
Un alias está estrechamente relacionado con un namespace de la clase. Se recomienda definir un alias
por cada namespace raíz, y así poder utilizar el autolader de Yii sin otra configuración.
por cada namespace raíz, y así poder utilizar el autoloader de Yii sin otra configuración.
Por ejemplo, debido a que `@yii` se refiere al directorio de instalación, una clase
como `yii\web\Request` puede ser auto-cargada. Si estás utilizando una librería de terceros,
como Zend Framework, puedes definir un alias `@Zend` que se refiera al directorio de instalación
@ -155,15 +156,12 @@ Vistas
------
El cambio más significativo con respecto a las vistas en Yii 2 es que la variable especial `$this` dentro de una vista
ya no se refiere al controlador o widget actual.
En vez de eso, `$this` ahora se refiere al objeto de la *vista*, un concepto nuevo introducido en Yii 2.0.
El objeto *vista* es del tipo [[yii\web\View]], que representa la parte de las vistas en el patrón MVC. Si
quieres acceder al controlador o al widget correspondiente desde la propia vista,
puedes utilizar `$this->context`.
ya no se refiere al controlador o widget actual. En vez de eso, `$this` ahora se refiere al objeto de la *vista*, un concepto nuevo
introducido en Yii 2.0. El objeto *vista* es del tipo [[yii\web\View]], que representa la parte de las vistas
en el patrón MVC. Si quieres acceder al controlador o al widget correspondiente desde la propia vista, puedes utilizar `$this->context`.
Para renderizar una vista parcial (partial) dentro de otra vista, se utiliza `$this->render()`, no `$this->renderPartial()`.
La llamada a `render` además tiene que ser mostrada explícitamente a través de `echo`, ya que el método `render()`
devuelve el resultado de la renderización en vez de mostrarlo directamente. Por ejemplo:
Para renderizar una vista parcial (partial) dentro de otra vista, se utiliza `$this->render()`, no `$this->renderPartial()`. La llamada a `render` además tiene que ser mostrada explícitamente a través de `echo`,
ya que el método `render()` devuelve el resultado de la renderización en vez de mostrarlo directamente. Por ejemplo:
```php
echo $this->render('_item', ['item' => $item]);
@ -172,7 +170,8 @@ echo $this->render('_item', ['item' => $item]);
Además de utilizar PHP como el lenguaje principal de plantillas (templates), Yii 2.0 está también equipado con soporte
oficial de otros dos motores de plantillas populares: Smarty y Twig. El motor de plantillas de Prado ya no está soportado.
Para utilizar esos motores, necesitas configurar el componente `view` de la aplicación, definiendo la propiedad [[yii\base\View::$renderers|View::$renderers]].
Por favor consulta la sección [Motores de Plantillas](tutorial-template-engines.md) para más detalles.
Por favor consulta la sección [Motores de Plantillas](tutorial-template-engines.md)
para más detalles.
Modelos
@ -431,7 +430,7 @@ class Customer extends \yii\db\ActiveRecord
```
Ahora puedes utilizar `$customer->orders` para acceder a las órdenes de la tabla relacionada. También puedes utilizar el siguiente
código para realizar una consulta relacional 'al-vuelo' con una condición personalizada:
código para realizar una consulta relacional 'sobre la marcha' con una condición personalizada:
```php
$orders = $customer->getOrders()->andWhere('status=1')->all();
@ -504,9 +503,10 @@ User e IdentityInterface
La clase `CWebUser` de 1.1 es reemplazada por [[yii\web\User]], y la clase `CUserIdentity` ha dejado de existir.
En cambio, ahora debes implementar [[yii\web\IdentityInterface]] el cual es mucho más directo de usar.
La plantilla de Aplicación Avanzada provee un ejemplo así.
El template de proyecto avanzado provee un ejemplo así.
Consulta las secciones [Autenticación](security-authentication.md), [Autorización](security-authorization.md), y [Template de Proyecto Avanzado](https://github.com/yiisoft/yii2-app-advanced/blob/master/docs/guide-es/README.md) para más detalles.
Consulta las secciones [Autenticación](security-authentication.md), [Autorización](security-authorization.md), y [Plantilla de Aplicación Avanzada](tutorial-advanced-app.md) para más detalles.
Manejo de URLs
@ -526,8 +526,14 @@ En 1.1, tendrías que haber creado dos reglas diferentes para obtener el mismo r
Por favor, consulta la sección [Documentación del Manejo de URLs](runtime-routing.md) para más detalles.
Utilizando Yii 1.1 y 2.x juntos
-------------------------------
Un cambio importante en la convención de nombres para rutas es que los nombres en CamelCase de controladores
y acciones ahora son convertidos a minúsculas y cada palabra separada por un guión, por ejemplo el id del controlador
`CamelCaseController` será `camel-case`.
Consulta la sección acerca de [IDs de controladores](structure-controllers.md#controller-ids) y [IDs de acciones](structure-controllers.md#action-ids) para más detalles.
Utilizar Yii 1.1 y 2.x juntos
-----------------------------
Si tienes código en Yii 1.1 que quisieras utilizar junto con Yii 2.0, por favor consulta
la sección [Utilizando Yii 1.1 y 2.0 juntos](tutorial-yii-integration.md).

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

@ -0,0 +1,98 @@
Trabajar con Scripts del Cliente
================================
> Note: Esta sección se encuentra en desarrollo.
### Registrar scripts
Con el objeto [[yii\web\View]] puedes registrar scripts. Hay dos métodos dedicados a esto:
[[yii\web\View::registerJs()|registerJs()]] para scripts en línea
[[yii\web\View::registerJsFile()|registerJsFile()]] para scripts externos.
Los scripts en línea son útiles para configuración y código generado dinámicamente.
El método para agregarlos puede ser utilizado así:
```php
$this->registerJs("var options = ".json_encode($options).";", View::POS_END, 'my-options');
```
El primer argumento es el código JS real que queremos insertar en la página. El segundo argumento
determina en qué parte de la página debería ser insertado el script. Los valores posibles son:
- [[yii\web\View::POS_HEAD|View::POS_HEAD]] para la sección head.
- [[yii\web\View::POS_BEGIN|View::POS_BEGIN]] justo después de la etiqueta `<body>`.
- [[yii\web\View::POS_END|View::POS_END]] justo antes de cerrar la etiqueta `</body>`.
- [[yii\web\View::POS_READY|View::POS_READY]] para ejecutar código en el evento `ready` del documento. Esto registrará [[yii\web\JqueryAsset|jQuery]] automáticamente.
- [[yii\web\View::POS_LOAD|View::POS_LOAD]] para ejecutar código en el evento `load` del documento. Esto registrará [[yii\web\JqueryAsset|jQuery]] automáticamente.
El último argumento es un ID único del script, utilizado para identificar el bloque de código y reemplazar otro con el mismo ID
en vez de agregar uno nuevo. En caso de no proveerlo, el código JS en sí será utilizado como ID.
Un script externo puede ser agregado de esta manera:
```php
$this->registerJsFile('http://example.com/js/main.js', ['depends' => [\yii\web\JqueryAsset::className()]]);
```
Los argumentos para [[yii\web\View::registerJsFile()|registerJsFile()]] son similares a los de
[[yii\web\View::registerCssFile()|registerCssFile()]]. En el ejemplo anterior,
registramos el archivo `main.js` con dependencia de `JqueryAsset`. Esto quiere decir que el archivo `main.js`
será agregado DESPUÉS de `jquery.js`. Si esta especificación de dependencia, el orden relativo entre
`main.js` y `jquery.js` sería indefinido.
Como para [[yii\web\View::registerCssFile()|registerCssFile()]], es altamente recomendable que utilices
[asset bundles](structure-assets.md) para registrar archivos JS externos más que utilizar [[yii\web\View::registerJsFile()|registerJsFile()]].
### Registrar asset bundles
Como mencionamos anteriormente, es preferible utilizar asset bundles en vez de usar CSS y JavaScript directamente. Puedes obtener detalles
de cómo definir asset bundles en la sección [gestor de assets](structure-assets.md) de esta guía. Utilizar asset bundles
ya definidos es muy sencillo:
```php
\frontend\assets\AppAsset::register($this);
```
### Registrar CSS
Puedes registrar CSS utilizando [[yii\web\View::registerCss()|registerCss()]] o [[yii\web\View::registerCssFile()|registerCssFile()]].
El primero registra un bloque de código CSS mientras que el segundo registra un archivo CSS externo. Por ejemplo,
```php
$this->registerCss("body { background: #f00; }");
```
El código anterior dará como resultado que se agregue lo siguiente a la sección head de la página:
```html
<style>
body { background: #f00; }
</style>
```
Si quieres especificar propiedades adicionales a la etiqueta style, pasa un array de claves-valores como tercer argumento.
Si necesitas asegurarte que haya sólo una etiqueta style utiliza el cuarto argumento como fue mencionado en las descripciones de meta etiquetas.
```php
$this->registerCssFile("http://example.com/css/themes/black-and-white.css", [
'depends' => [BootstrapAsset::className()],
'media' => 'print',
], 'css-print-theme');
```
El código de arriba agregará un link al archivo CSS en la sección head de la página.
* El primer argumento especifica el archivo CSS a ser registrado.
* El segundo argumento especifica los atributos HTML de la etiqueta `<link>` resultante. La opción `depends`
es especialmente tratada. Esta especifica de qué asset bundles depende este archivo CSS. En este caso, depende
del asset bundle [[yii\bootstrap\BootstrapAsset|BootstrapAsset]]. Esto significa que el archivo CSS será agregado
*después* de los archivos CSS de [[yii\bootstrap\BootstrapAsset|BootstrapAsset]].
* El último argumento especifica un ID que identifica al archivo CSS. Si no es provisto, se utilizará la URL
del archivo.
Es altamente recomendable que ustilices [asset bundles](structure-assets.md) para registrar archivos CSS en vez de
utilizar [[yii\web\View::registerCssFile()|registerCssFile()]]. Utilizar asset bundles te permite combinar y comprimir
varios archivos CSS, deseable en sitios web de tráfico alto.

72
docs/guide-es/output-pagination.md

@ -0,0 +1,72 @@
Paginación
==========
Cuando hay muchos datos a mostrar en una sola página, una estrategia común es mostrarlos en varias
páginas y en cada una de ellas mostrar sólo una pequeña porción de datos. Esta estrategia es conocida como *paginación*.
Yii utiliza el objeto [[yii\data\Pagination]] para representar la información acerca del esquema de paginación. En particular,
* [[yii\data\Pagination::$totalCount|cuenta total]] especifica el número total de ítems de datos. Ten en cuenta que
este es normalmente un número mucho mayor que el número de ítems necesarios a mostrar en una simple página.
* [[yii\data\Pagination::$pageSize|tamaño de página]] especifica cuántos ítems de datos contiene cada página. El valor
por defecto es 20.
* [[yii\data\Pagination::$page|página actual]] da el número de la página actual (comenzando desde 0). El valor
por defecto es 0, lo que sería la primera página.
Con un objeto [[yii\data\Pagination]] totalmente especificado, puedes obtener y mostrar datos en partes. Por ejemplo,
si estás recuperando datos de una base de datos, puedes especificar las cláusulas `OFFSET` y `LIMIT` de la consulta a la BD
correspondientes a los valores provistos por la paginación. A continuación hay un ejemplo,
```php
use yii\data\Pagination;
// construye una consulta a la BD para obtener todos los artículos con status = 1
$query = Article::find()->where(['status' => 1]);
// obtiene el número total de artículos (pero no recupera los datos de los artículos todavía)
$count = $query->count();
// crea un objeto paginación con dicho total
$pagination = new Pagination(['totalCount' => $count]);
// limita la consulta utilizando la paginación y recupera los artículos
$articles = $query->offset($pagination->offset)
->limit($pagination->limit)
->all();
```
¿Qué página de artículos devolverá el ejemplo de arriba? Depende de si se le es pasado un parámetro llamado `page`.
Por defecto, la paginación intentará definir la [[yii\data\Pagination::$page|página actual]] con
el valor del parámetro `page`. Si el parámetro no es provisto, entonces tomará por defecto el valor 0.
Para facilitar la construcción de elementos UI que soporten paginación, Yii provee el widget [[yii\widgets\LinkPager]],
que muestra una lista de botones de navegación que el usuario puede presionar para indicar qué página de datos debería mostrarse.
El widget toma un objeto de paginación y tal manera conoce cuál es la página actual y cuántos botones
debe mostrar. Por ejemplo,
```php
use yii\widgets\LinkPager;
echo LinkPager::widget([
'pagination' => $pagination,
]);
```
Si quieres construir los elementos de UI manualmente, puedes utilizar [[yii\data\Pagination::createUrl()]] para generar URLs que
dirigirán a las distintas páginas. El método requiere un parámetro de página y generará una URL apropiadamente formada
contieniendo el parámetro de página. Por ejemplo,
```php
// especifica la ruta que la URL generada debería utilizar
// Si no lo especificas, se utilizará la ruta de la petición actual
$pagination->route = 'article/index';
// muestra: /index.php?r=article%2Findex&page=100
echo $pagination->createUrl(100);
// muestra: /index.php?r=article%2Findex&page=101
echo $pagination->createUrl(101);
```
> Tip: puedes personalizar el parámetro `page` de la consulta configurando
la propiedad [[yii\data\Pagination::pageParam|pageParam]] al crear el objeto de la paginación.

44
docs/guide-es/rest-authentication.md

@ -1,22 +1,25 @@
Autenticación
=============
A diferencia de las aplicaciones Web, las API RESTful son usualmente sin estado (stateless), lo que permite que las sesiones o las cookies no sean usadas.
Por lo tanto, cada petición debe llevar alguna suerte de credenciales de autenticación, porque la autenticación del usuario no puede ser mantenida por las sesiones o las cookies.
Una práctica común es enviar una pieza (token) secreta de acceso con cada petición para autenticar al usuario. Dado que una pieza de autenticación
puede ser usada para identificar y autenticar solamente a un usuario, **el API de peticiones tiene que ser siempre enviado vía HTTPS para prevenir ataques que intervengan en la transmisión "man-in-the-middle" (MitM) **.
A diferencia de las aplicaciones Web, las API RESTful son usualmente sin estado (stateless), lo que permite que las sesiones o las cookies
no sean usadas. Por lo tanto, cada petición debe llevar alguna suerte de credenciales de autenticación,
porque la autenticación del usuario no puede ser mantenida por las sesiones o las cookies. Una práctica común
es enviar una pieza (token) secreta de acceso con cada petición para autenticar al usuario. Dado que una pieza de autenticación
puede ser usada para identificar y autenticar solamente a un usuario, **la API de peticiones tiene que ser siempre enviado
vía HTTPS para prevenir ataques tipo "man-in-the-middle" (MitM) **.
Hay muchas maneras de enviar una token (pieza) de acceso:
* [Autorización Básica HTTP](http://en.wikipedia.org/wiki/Basic_access_authentication): la pieza de acceso
* [Autenticación Básica HTTP](https://es.wikipedia.org/wiki/Autenticaci%C3%B3n_de_acceso_b%C3%A1sica): la pieza de acceso
es enviada como nombre de usuario. Esto sólo debe de ser usado cuando la pieza de acceso puede ser guardada
de forma segura en la parte del API del consumidor. Por ejemplo, el API del consumidor es un programa ejecutándose en un servidor.
* Parámetro de la consulta: la pieza de acceso es enviada como un parámetro de la consulta en la URL de la API, p.e.,
`https://example.com/users?access-token=xxxxxxxx`. Debido que muchos servidores dejan los parámetros de consulta en los logs del servidor,
esta aproximación suele ser usada principalmente para servir peticiones `JSONP`
esta aproximación suele ser usada principalmente para servir peticiones `JSONP`
que no usen las cabeceras HTTP para enviar piezas de acceso.
* [OAuth 2](http://oauth.net/2/): la pieza de acceso es obtenida por el consumidor por medio de una autorización del servidor
y enviada al API del servidor según el protocolo OAuth 2 [tokens HTTP del portador] (http://tools.ietf.org/html/rfc6750).
y enviada al API del servidor según el protocolo
OAuth 2 [tokens HTTP del portador](http://tools.ietf.org/html/rfc6750).
Yii soporta todos los métodos anteriores de autenticación. Puedes crear nuevos métodos de autenticación de una forma fácil.
@ -34,17 +37,18 @@ Cuando [[yii\web\User::enableSession|enableSession]] es false, el estado de aute
Si embargo, la autenticación será realizada para cada petición, lo que se consigue en los pasos 2 y 3.
> Tip:Puedes configurar [[yii\web\User::enableSession|enableSession]] del componente de la aplicación `user` en la configuración
de las aplicaciones si estás desarrollando APIs RESTful en términos de un aplicación. Si desarrollas un módulo de las APIs RESTful,
puedes poner la siguiente línea en el método del módulo `init()`, tal y como sigue:
> de las aplicaciones si estás desarrollando APIs RESTful en términos de un aplicación. Si desarrollas un módulo de las APIs RESTful,
> puedes poner la siguiente línea en el método del módulo `init()`, tal y como sigue:
>
> ```php
public function init()
{
parent::init();
\Yii::$app->user->enableSession = false;
}
```
> public function init()
> {
> parent::init();
> \Yii::$app->user->enableSession = false;
> }
> ```
Por ejemplo, para usar HTTP Basic Auth, puedes configurar el comportamiento `authenticator` como sigue,
Por ejemplo, para usar HTTP Basic Auth, puedes configurar el comportamiento (behavior) `authenticator` como sigue,
```php
use yii\filters\auth\HttpBasicAuth;
@ -108,14 +112,16 @@ puede intentar autenticar al usuario en su evento `beforeAction()`.
Si la autenticación tiene éxito, el controlador realizará otras comprobaciones (como son límite del ratio, autorización)
y entonces ejecutar la acción. La identidad del usuario autenticado puede ser recuperada via `Yii::$app->user->identity`.
Si la autenticación falla, una respuesta con estado HTTP 401 será devuelta junto con otras cabeceras apropiadas (tal como la cabecera para autenticación básica HTTP `WWW-Authenticate`).
Si la autenticación falla, una respuesta con estado HTTP 401 será devuelta junto con otras cabeceras apropiadas
(tal como la cabecera para autenticación básica HTTP `WWW-Authenticate`).
## Autorización <span id="authorization"></span>
Después de que un usuario se ha autenticado, probablementer querrás comprobar si él o ella tiene los permisos para realizar
la acción solicitada. Este proceso es llamado *autorización (authorization)* y está cubierto en detalle en la [Sección de Autorización](security-authorization.md).
la acción solicitada. Este proceso es llamado *autorización (authorization)* y está cubierto en detalle
en la [Sección de Autorización](security-authorization.md).
Si tus controladores extienden de [[yii\rest\ActiveController]], puedes sobreescribir
el método [[yii\rest\Controller::checkAccess()|checkAccess()]] para realizar la comprobación de la autorización.
el método [[yii\rest\ActiveController::checkAccess()|checkAccess()]] para realizar la comprobación de la autorización.
El método será llamado por las acciones contenidas en [[yii\rest\ActiveController]].

19
docs/guide-es/rest-error-handling.md

@ -6,7 +6,8 @@ ocurre en el servidor, simplemente puedes lanzar una excepción para notificar a
Si puedes identificar la causa del error (p.e., el recurso solicitado no existe), debes considerar lanzar una excepción
con el código HTTP de estado apropiado (p.e., [[yii\web\NotFoundHttpException]] representa un código de estado 404).
Yii enviará la respuesta a continuación con el correspondiente código de estado HTTP y el texto. Yii puede incluir también
la representación serializada de la excepción en el cuerpo de la respuesta. Por ejemplo:
la representación serializada de la excepción en el cuerpo de la respuesta.
Por ejemplo:
```
HTTP/1.1 404 Not Found
@ -17,7 +18,7 @@ Content-Type: application/json; charset=UTF-8
{
"name": "Not Found Exception",
"message": "El recurso solicitado no ha sido encontrado.",
"message": "The requested resource was not found.",
"code": 0,
"status": 404
}
@ -26,21 +27,23 @@ Content-Type: application/json; charset=UTF-8
La siguiente lista sumariza los códigos de estado HTTP que son usados por el framework REST:
* `200`: OK. Todo ha funcionado como se esperaba.
* `201`: El recurso ha creado con éxito en respuesta a la petición `POST`. La cabecera de situación `Location` contiene la URL apuntando al nuevo recurso creado.
* `201`: El recurso ha creado con éxito en respuesta a la petición `POST`. La cabecera de situación `Location`
contiene la URL apuntando al nuevo recurso creado.
* `204`: La petición ha sido manejada con éxito y el cuerpo de la respuesta no tiene contenido (como una petición `DELETE`).
* `304`: El recurso no ha sido modificado. Puede usar la versión en caché.
* `400`: Petición errónea. Esto puede estar causado por varias acciones de el usuario, como proveer un JSON no válido en el cuerpo de la petición, proveyendo parámetros de acción no válidos, etc.
* `400`: Petición errónea. Esto puede estar causado por varias acciones de el usuario, como proveer un JSON no válido
en el cuerpo de la petición, proveyendo parámetros de acción no válidos, etc.
* `401`: Autenticación fallida.
* `403`: El usuario autenticado no tiene permitido acceder a la API final.
* `404`: El recurso pedido no existe.
* `405`: Método no permitido. Por favor comprueba la cabecera `Allow` por los métodos HTTP permitidos.
* `415`: Tipo de medio no soportado. El tipo de contenido pedido o el número de versión no es válido.
* `422`: La validación de datos ha fallado (en respuesta a una petición `POST` , por ejemplo). Por favor, comprobad en el cuerpo de la respuesta el mensaje detallado.
* `422`: La validación de datos ha fallado (en respuesta a una petición `POST` , por ejemplo). Por favor, comprueba en el cuerpo de la respuesta el mensaje detallado.
* `429`: Demasiadas peticiones. La petición ha sido rechazada debido a un limitación de rango.
* `500`: Error interno del servidor. Esto puede estar causado por errores internos del programa.
## Personalizando la Respuesta al Error <span id="customizing-error-response"></span>
## Personalizar la Respuesta al Error <span id="customizing-error-response"></span>
A veces puedes querer personalizar el formato de la respuesta del error por defecto . Por ejemplo, en lugar de depender
del uso de diferentes estados HTTP para indicar los diferentes errores, puedes querer usar siempre el estado HTTP 200
@ -64,7 +67,7 @@ Content-Type: application/json; charset=UTF-8
}
```
Para lograr este objetivo, puedes responder al evento `beforeSend` del componente `response` en la configuración de la aplicación:
Para lograrlo, puedes responder al evento `beforeSend` del componente `response` en la configuración de la aplicación:
```php
return [
@ -74,7 +77,7 @@ return [
'class' => 'yii\web\Response',
'on beforeSend' => function ($event) {
$response = $event->sender;
if ($response->data !== null && !empty(Yii::$app->request->get['suppress_response_code'])) {
if ($response->data !== null && Yii::$app->request->get('suppress_response_code')) {
$response->data = [
'success' => $response->isSuccessful,
'data' => $response->data,

5
docs/guide-es/rest-response-formatting.md

@ -9,8 +9,9 @@ con el formato de la respuesta:
2. La conversión de objetos recurso en arrays, como está descrito en la sección [Recursos (Resources)](rest-resources.md).
Esto es realizado por la clase [[yii\rest\Serializer]].
3. La conversión de arrays en cadenas con el formato determinado por el paso de negociación de contenido. Esto es
realizado por los [[yii\web\ResponseFormatterInterface|response formatters]] registrados con el
componente de la aplicación [[yii\web\Response::formatters|response]].
realizado por los [[yii\web\ResponseFormatterInterface|formatos de respuesta]] registrados
con la propiedad [[yii\web\Response::formatters|formatters]] del
[componente de la aplicación](structure-application-components.md) `response`.
## Negociación de contenido (Content Negotiation) <span id="content-negotiation"></span>

55
docs/guide-es/runtime-handling-errors.md

@ -4,22 +4,20 @@ Gestión de Errores
Yii incluye un [[yii\web\ErrorHandler|error handler]] que permite una gestión de errores mucho más práctica que
anteriormente. En particular, el gestor de errores de Yii hace lo siguiente para mejorar la gestión de errores:
* Todos los errores no fatales (ej. advertencias (warning), avisos (notices)) se convierten en excepciones
capturables.
* Todos los errores no fatales (ej. advertencias (warning), avisos (notices)) se convierten en excepciones capturables.
* Las excepciones y los errores fatales de PHP se muestran con una pila de llamadas (call stack) de información
detallada y lineas de código fuente.
* Soporta el uso de [acciones de controlador](structure-controllers.md#actions) dedicadas para mostrar errores.
* Soporta diferentes formatos de respuesta (response) de errores.
El [[yii\web\ErrorHandler|error handler]] esta habilitado de forma predeterminada. Se puede deshabilitar definiendo la
constante `YII_ENABLE_ERROR_HANDLER` con valor false en el
[script de entrada (entry script)](structure-entry-scripts.md) de la aplicación.
constante `YII_ENABLE_ERROR_HANDLER` con valor false en el [script de entrada (entry script)](structure-entry-scripts.md) de la aplicación.
## Uso del Gestor de Errores <span id="using-error-handler"></span>
El [[yii\web\ErrorHandler|error handler]] se registra como un
[componente de aplicación](structure-application-components.md) llamado `errorHandler`. Se puede configurar en la
configuración de la aplicación como en el siguiente ejemplo:
El [[yii\web\ErrorHandler|error handler]] se registra como un [componente de aplicación](structure-application-components.md) llamado `errorHandler`.
Se puede configurar en la configuración de la aplicación como en el siguiente ejemplo:
```php
return [
@ -31,8 +29,7 @@ return [
];
```
Con la anterior configuración, el numero del lineas de código fuente que se mostrará en las páginas de excepciones
será como máximo de 20.
Con la anterior configuración, el numero del lineas de código fuente que se mostrará en las páginas de excepciones será como máximo de 20.
Como se ha mencionado, el gestor de errores convierte todos los errores de PHP no fatales en excepciones capturables.
Esto significa que se puede usar el siguiente código para tratar los errores PHP:
@ -61,29 +58,27 @@ use yii\web\NotFoundHttpException;
throw new NotFoundHttpException();
```
## Personalizar la Visualización de Errores <span id="customizing-error-display"></span>
El [[yii\web\ErrorHandler|error handler]] ajusta la visualización del error conforme al valor de la constante
`YII_DEBUG`. Cuando `YII_DEBUG` es `true` (es decir, en modo depuración (debug)), el gestor de errores mostrara las
excepciones con una pila detallada de información y con lineas de código fuente para ayudar a depurar. Y cuando la
variable `YII_DEBUG` es `false`, solo se mostrará el mensaje de error para prevenir la revelación de información
sensible de la aplicación.
El [[yii\web\ErrorHandler|error handler]] ajusta la visualización del error conforme al valor de la constante `YII_DEBUG`.
Cuando `YII_DEBUG` es `true` (es decir, en modo depuración (debug)), el gestor de errores mostrara las
excepciones con una pila detallada de información y con lineas de código fuente para ayudar a depurar. Y cuando la variable `YII_DEBUG` es `false`,
solo se mostrará el mensaje de error para prevenir la revelación de información sensible de la aplicación.
> Info: Si una excepción es descendiente de [[yii\base\UserException]], no se mostrará la pila de llamadas
independientemente del valor de `YII_DEBUG`. Esto es debido a que se considera que estas excepciones se deben a
errores cometidos por los usuarios y los desarrolladores no necesitan corregirlas.
independientemente del valor de `YII_DEBUG`. Esto es debido a que se considera que estas excepciones se deben a
errores cometidos por los usuarios y los desarrolladores no necesitan corregirlas.
De forma predeterminada, el [[yii\web\ErrorHandler|error handler]] muestra los errores usando dos
[vistas](structure-views.md):
De forma predeterminada, el [[yii\web\ErrorHandler|error handler]] muestra los errores usando dos [vistas](structure-views.md):
* `@yii/views/errorHandler/error.php`: se usa cuando deben mostrarse los errores SIN la información de la pila de
llamadas. Cuando `YII_DEBUG` es falos, este es el único error que se mostrara.
* `@yii/views/errorHandler/exception.php`: se usa cuando los errores deben mostrarse CON la información de la pila de
llamadas.
* `@yii/views/errorHandler/exception.php`: se usa cuando los errores deben mostrarse CON la información de la pila de llamadas.
Se pueden configurar las propiedades [[yii\web\ErrorHandler::errorView|errorView]] y [[yii\web\ErrorHandler::exceptionView|exceptionView]]
el gestor de errores para usar nuestros propias vistas para personalizar la visualización de los errores.
Se pueden configurar las propiedades [[yii\web\ErrorHandler::errorView|errorView]] y
[[yii\web\ErrorHandler::exceptionView|exceptionView]] el gestor de errores para usar nuestros propias vistas para
personalizar la visualización de los errores.
### Uso de Acciones de Error <span id="using-error-actions"></span>
@ -129,8 +124,7 @@ class SiteController extends Controller
El código anterior define la acción `error` usando la clase [[yii\web\ErrorAction]] que renderiza un error usando la
vista llamada `error`.
Además, usando [[yii\web\ErrorAction]], también se puede definir la acción `error` usando un método de acción como en
el siguiente ejemplo,
Además, usando [[yii\web\ErrorAction]], también se puede definir la acción `error` usando un método de acción como en el siguiente ejemplo,
```php
public function actionError()
@ -150,8 +144,15 @@ a las siguientes variables si se define el error como un [[yii\web\ErrorAction]]
* `exception`: el objeto de excepción a través del cual se puede obtener más información útil, tal como el código de
estado HTTP, el código de error, la pila de llamadas del error, etc.
> Info: Tanto la [plantilla de aplicación básica](start-installation.md) como la
[plantilla de aplicación avanzada](tutorial-advanced-app.md), ya incorporan la acción de error y la vista de error.
> Info: Tanto la [plantilla de aplicación básica](start-installation.md) como la [plantilla de aplicación avanzada](tutorial-advanced-app.md),
ya incorporan la acción de error y la vista de error.
> Note: Si necesitas redireccionar en un gestor de error, hazlo de la siguiente manera:
> ```php
> Yii::$app->getResponse()->redirect($url)->send();
> return;
> ```
### Personalizar el Formato de Respuesta de Error <span id="error-format"></span>

527
docs/guide-es/security-authorization.md

@ -0,0 +1,527 @@
Autorización
============
Autorización esl el proceso de verificación de que un usuario tenga sugifientes permisos para realizar algo. Yii provee
dos métodos de autorización: Filtro de Control de Acceso y Control Basado en Roles (ACF y RBAC por sus siglas en inglés).
## Filtro de Control de Acceso <span id="access-control-filter"></span>
Filtro de Control de Acceso (ACF) es un único método de autorización implementado como [[yii\filters\AccessControl]], el cual
es mejor utilizado por aplicaciones que sólo requieran un control de acceso simple. Como su nombre lo indica, ACF es
un [filtro](structure-filters.md) de acción que puede ser utilizado en un controlador o en un módulo. Cuando un usuario solicita
la ejecución de una acción, ACF comprobará una lista de [[yii\filters\AccessControl::rules|reglas de acceso]]
para determinar si el usuario tiene permitido acceder a dicha acción.
El siguiente código muestra cómo utilizar ACF en el controlador `site`:
```php
use yii\web\Controller;
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' => ['@'],
],
],
],
];
}
// ...
}
```
En el código anterior, ACF es adjuntado al controlador `site` en forma de behavior (comportamiento). Esta es la forma típica de utilizar
un filtro de acción. La opción `only` especifica que el ACF debe ser aplicado solamente a las acciones `login`, `logout` y `signup`.
Las acciones restantes en el controlador `site` no están sujetas al control de acceso. La opción `rules` lista
las [[yii\filters\AccessRule|reglas de acceso]], y se lee como a continuación:
- Permite a todos los usuarios invitados (sin autenticar) acceder a las acciones `login` y `signup`. La opción `roles`
contiene el signo de interrogación `?`, que es un código especial para representar a los "invitados".
- Permite a los usuarios autenticados acceder a la acción `logout`. El signo `@` es otro código especial que representa
a los "usuarios autenticados".
ACF ejecuta la comprobación de autorización examinando las reglas de acceso una a una desde arriba hacia abajo hasta que encuentra
una regla que aplique al contexto de ejecución actual. El valor `allow` de la regla que coincida será entonces utilizado
para juzgar si el usuario está autorizado o no. Si ninguna de las reglas coincide, significa que el usuario NO está autorizado,
y el ACF detendrá la ejecución de la acción.
Cuando el ACF determina que un usuario no está autorizado a acceder a la acción actual, toma las siguientes medidas por defecto:
* Si el usuario es un invitado, llamará a [[yii\web\User::loginRequired()]] para redireccionar el navegador a la pantalla de login.
* Si el usuario está autenticado, lanzará una excepeción [[yii\web\ForbiddenHttpException]].
Puedes personalizar este comportamiento configurando la propiedad [[yii\filters\AccessControl::denyCallback]] como a continuación:
```php
[
'class' => AccessControl::className(),
...
'denyCallback' => function ($rule, $action) {
throw new \Exception('No tienes los suficientes permisos para acceder a esta página');
}
]
```
Las [[yii\filters\AccessRule|Reglas de Acceso]] soportan varias opciones. Abajo hay un resumen de las mismas.
También puedes extender de [[yii\filters\AccessRule]] para crear tus propias clases de reglas de acceso personalizadas.
* [[yii\filters\AccessRule::allow|allow]]: especifica si la regla es de tipo "allow" (permitir) o "deny" (denegar).
* [[yii\filters\AccessRule::actions|actions]]: especifica con qué acciones coinciden con esta regla. Esta debería ser
un array de IDs de acciones. La comparación es sensible a mayúsculas. Si la opción está vacía o no definida,
significa que la regla se aplica a todas las acciones.
* [[yii\filters\AccessRule::controllers|controllers]]: especifica con qué controladores coincide
esta regla. Esta debería ser un array de IDs de controladores. Cada ID de controlador es prefijado con el ID del módulo (si existe).
La comparación es sensible a mayúsculas. Si la opción está vacía o no definida, significa que la regla se aplica a todos los controladores.
* [[yii\filters\AccessRule::roles|roles]]: especifica con qué roles de usuarios coincide esta regla.
Son reconocidos dos roles especiales, y son comprobados vía [[yii\web\User::isGuest]]:
- `?`: coincide con el usuario invitado (sin autenticar)
- `@`: coincide con el usuario autenticado
El utilizar otro nombre de rol invocará una llamada a [[yii\web\User::can()]], que requiere habilitar RBAC
(a ser descrito en la próxima subsección). Si la opción está vacía o no definida, significa que la regla se aplica a todos los roles.
* [[yii\filters\AccessRule::ips|ips]]: especifica con qué [[yii\web\Request::userIP|dirección IP del cliente]] coincide esta regla.
Una dirección IP puede contener el caracter especial `*` al final de manera que coincidan todas las IPs que comiencen igual.
Por ejemplo, '192.168.*' coincide con las direcciones IP en el segmento '192.168.'. Si la opción está vacía o no definida,
significa que la regla se aplica a todas las direcciones IP.
* [[yii\filters\AccessRule::verbs|verbs]]: especifica con qué método de la solicitud (por ej. `GET`, `POST`) coincide esta regla.
La comparación no distingue minúsculas de mayúsculas.
* [[yii\filters\AccessRule::matchCallback|matchCallback]]: especifica una función PHP invocable que debe ser llamada para determinar
si la regla debe ser aplicada.
* [[yii\filters\AccessRule::denyCallback|denyCallback]]: especifica una función PHP invocable que debe ser llamada cuando esta regla
deniegue el acceso.
Debajo hay un ejemplo que muestra cómo utilizar la opción `matchCallback`, que te permite escribir lógica de comprabación de acceso
arbitraria:
```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';
}
],
],
],
];
}
// Callback coincidente llamado! Esta página sólo puede ser accedida cada 31 de Octubre
public function actionSpecialCallback()
{
return $this->render('happy-halloween');
}
}
```
## Control de Acceso Basado en Roles (RBAC) <span id="rbac"></span>
El Control de Acceso Basado en Roles (RBAC) provee una simple pero poderosa manera centralizada de control de acceso. Por favos consulta
la [Wikipedia](http://en.wikipedia.org/wiki/Role-based_access_control) para más detalles sobre comparar RBAC
con otros mecanismos de control de acceso más tradicionales.
Yii implementa una Jerarquía General RBAC, siguiendo el [modelo NIST RBAC](http://csrc.nist.gov/rbac/sandhu-ferraiolo-kuhn-00.pdf).
Esto provee la funcionalidad RBAC a través de [componente de la aplicación](structure-application-components.md) [[yii\rbac\ManagerInterface|authManager]].
Utilizar RBAC envuelve dos cosas. La primera es construir los datos de autorización RBAC, y la segunda
es utilizar esos datos de autorización para comprobar el acceso en los lugares donde se necesite.
Para facilitar la próxima descripción, necesitamos primero instroducir algunos conceptos RBAC básicos.
### Conceptos Básicos <span id="basic-concepts"></span>
Un rol representa una colección de *permisos* (por ej. crear posts, actualizar posts). Un rol puede ser asignado
a uno o varios usuarios. Para comprobar que un usuario cuenta con determinado permiso, podemos comprobar si el usuario tiene asignado
un rol que cuente con dicho permiso.
Asociado a cada rol o permiso, puede puede haber una *regla*. Una regla representa una porción de código que será
ejecutada durante la comprobación de acceso para determinar si el rol o permiso correspondiente aplica al usuario actual.
Por ejemplo, el permiso "actualizar post" puede tener una regla que compruebe que el usuario actual es el autor del post.
Durante la comprobación de acceso, si el usuario NO es el autor del post, se considerará que el/ella no cuenta con el permiso "actualizar post".
Tanto los roles como los permisos pueden ser organizados en una jerarquía. En particular, un rol puede consistir en otros roles o permisos;
y un permiso puede consistir en otros permisos. Yii implementa una jerarquía de *orden parcial*, que incluye
una jerarquía de *árbol* especial. Mientras que un rol puede contener un permiso, esto no sucede al revés.
### Configurar RBAC <span id="configuring-rbac"></span>
Antes de definir todos los datos de autorización y ejecutar la comprobación de acceso, necesitamos configurar el
componente de la aplicación [[yii\base\Application::authManager|authManager]]. Yii provee dos tipos de administradores de autorización:
[[yii\rbac\PhpManager]] y [[yii\rbac\DbManager]]. El primero utiliza un archivo PHP para almacenar los datos
de autorización, mientras que el segundo almacena dichos datos en una base de datos. Puedes considerar utilizar el primero si tu aplicación
no requiere una administración de permisos y roles muy dinámica.
#### Utilizar `PhpManager` <span id="using-php-manager"></span>
El siguiente código muestra cómo configurar `authManager` en la configuración de nuestra aplicación utilizando la clase [[yii\rbac\PhpManager]]:
```php
return [
// ...
'components' => [
'authManager' => [
'class' => 'yii\rbac\PhpManager',
],
// ...
],
];
```
El `authManager` ahora puede ser accedido vía `\Yii::$app->authManager`.
Por defecto, [[yii\rbac\PhpManager]] almacena datos RBAC en archivos bajo el directorio `@app/rbac`. Asegúrate de que el directorio
y todos sus archivos son tienen permiso de escritura para el proceso del servidor Web si la jerarquía de permisos necesita ser modoficada en línea.
#### Utilizar `DbManager` <span id="using-db-manager"></span>
El sigiente código muestra cómo configurar `authManager` en la configuración de la aplicación utilizando la clase [[yii\rbac\DbManager]]:
```php
return [
// ...
'components' => [
'authManager' => [
'class' => 'yii\rbac\DbManager',
],
// ...
],
];
```
> Note: si estás utilizando el template yii2-basic-app, existe el archivo de configuración `config/console.php` donde
necesita declararse `authManager` adicionalmente a `config/web.php`.
> En el caso de yii2-advanced-app, `authManager` sólo debe declararse en `common/config/main.php`.
`DbManager` utiliza cuatro tablas de la BD para almacenar los datos:
- [[yii\rbac\DbManager::$itemTable|itemTable]]: la tabla para almacenar los ítems de autorización. Por defecto "auth_item".
- [[yii\rbac\DbManager::$itemChildTable|itemChildTable]]: la tabla para almacentar la jerarquía de los ítems de autorización. Por defecto "auth_item_child".
- [[yii\rbac\DbManager::$assignmentTable|assignmentTable]]: la tabla para almacenar las asignaciones de los ítems de autorización. Por defecto "auth_assignment".
- [[yii\rbac\DbManager::$ruleTable|ruleTable]]: la tabla para almacenar las reglas. Por defecto "auth_rule".
Antes de continuar, necesitas crear las tablas respectivas en la base de datos. Para hacerlo, puedes utilizar las migraciones contenidas en `@yii/rbac/migrations`:
`yii migrate --migrationPath=@yii/rbac/migrations`
El `authManager` puede ahora ser accedido vía `\Yii::$app->authManager`.
### Construir los Datos de Autorización <span id="generating-rbac-data"></span>
Construir los datos de autorización implica las siguientes tareas:
- definir roles y permisos;
- establecer relaciones entre roles y permisos;
- definir reglas;
- asociar reglas con roles y permisos;
- asignar roles a usuarios.
Dependiendo de los requerimientos de flexibilidad en la autorización, las tareas se pueden lograr de diferentes maneras.
Si la jerarquía de permisos no cambia en absoluto y tienes un número fijo de usuarios puede crear un
[comando de consola](tutorial-console.md#create-command) que va a inicializar los datos de autorización una vez a través de las API que ofrece por `authManager`:
```php
<?php
namespace app\commands;
use Yii;
use yii\console\Controller;
class RbacController extends Controller
{
public function actionInit()
{
$auth = Yii::$app->authManager;
// agrega el permiso "createPost"
$createPost = $auth->createPermission('createPost');
$createPost->description = 'Create a post';
$auth->add($createPost);
// agrega el permiso "updatePost"
$updatePost = $auth->createPermission('updatePost');
$updatePost->description = 'Update post';
$auth->add($updatePost);
// agrega el rol "author" y le asigna el permiso "createPost"
$author = $auth->createRole('author');
$auth->add($author);
$auth->addChild($author, $createPost);
// agrega el rol "admin" y le asigna el permiso "updatePost"
// más los permisos del rol "author"
$admin = $auth->createRole('admin');
$auth->add($admin);
$auth->addChild($admin, $updatePost);
$auth->addChild($admin, $author);
// asigna roles a usuarios. 1 y 2 son IDs devueltos por IdentityInterface::getId()
// usualmente implementado en tu modelo User.
$auth->assign($author, 2);
$auth->assign($admin, 1);
}
}
```
> Note: Si estas utilizando el template avanzado, necesitas poner tu `RbacController` dentro del directorio `console/controllers`
y cambiar el espacio de nombres a `console/controllers`.
Después de ejecutar el comando `yii rbac/init`, obtendremos la siguiente jerarquía:
![Simple RBAC hierarchy](../guide/images/rbac-hierarchy-1.png "Simple RBAC hierarchy")
"Author" puede crear un post, "admin" puede actualizar posts y hacer todo lo que puede hacer "author".
Si tu aplicación permite el registro de usuarios, necesitas asignar los roles necesarios para cada usuario nuevo. Por ejemplo, para que todos
los usuarios registrados tengan el rol "author", en el template de aplicación avanzada debes modificar `frontend\models\SignupForm::signup()`
como a continuación:
```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);
// las siguientes tres líneas fueron agregadas
$auth = Yii::$app->authManager;
$authorRole = $auth->getRole('author');
$auth->assign($authorRole, $user->getId());
return $user;
}
return null;
}
```
Para aplicaciones que requieren un control de acceso complejo con una actualización constante en los datos de autorización, puede ser necesario
desarrollar una interfaz especial (por ej. un panel de administración) utilizando las APIs ofrecidas por `authManager`.
### Utilizar Reglas <span id="using-rules"></span>
Como se había mencionado, las reglas agregan restricciones adicionales a los roles y permisos. Una regla es una clase extendida
de [[yii\rbac\Rule]]. Debe implementar al método [[yii\rbac\Rule::execute()|execute()]]. En la jerarquía que creamos
previamente, "author" no puede editar su propio post. Vamos a arreglarlo. Primero necesitamos una regla para comprobar que el usuario actual es el autor del post:
```php
namespace app\rbac;
use yii\rbac\Rule;
/**
* Comprueba si authorID coincide con el usuario pasado como parámetro
*/
class AuthorRule extends Rule
{
public $name = 'isAuthor';
/**
* @param string|integer $user el ID de usuario.
* @param Item $item el rol o permiso asociado a la regla
* @param array $params parámetros pasados a ManagerInterface::checkAccess().
* @return boolean un valor indicando si la regla permite al rol o permiso con el que está asociado.
*/
public function execute($user, $item, $params)
{
return isset($params['post']) ? $params['post']->createdBy == $user : false;
}
}
```
La regla anterior comprueba si el `post` fue creado por `$user`. Crearemos un permiso especial, `updateOwnPost`, en el comando que hemos utilizado
anteriormente:
```php
$auth = Yii::$app->authManager;
// agrega la regla
$rule = new \app\rbac\AuthorRule;
$auth->add($rule);
// agrega el permiso "updateOwnPost" y le asocia la regla.
$updateOwnPost = $auth->createPermission('updateOwnPost');
$updateOwnPost->description = 'Update own post';
$updateOwnPost->ruleName = $rule->name;
$auth->add($updateOwnPost);
// "updateOwnPost" será utilizado desde "updatePost"
$auth->addChild($updateOwnPost, $updatePost);
// permite a "author" editar sus propios posts
$auth->addChild($author, $updateOwnPost);
```
Ahora tenemos la siguiente jerarquía:
![RBAC hierarchy with a rule](../guide/images/rbac-hierarchy-2.png "RBAC hierarchy with a rule")
### Comprobación de Acceso <span id="access-check"></span>
Con los datos de autorización listos, la comprobación de acceso se hace con una simple llamada al método [[yii\rbac\ManagerInterface::checkAccess()]].
Dado que la mayoría de la comprobación de acceso se hace sobre el usuario actual, para mayor comodidad Yii proporciona el atajo
[[yii\web\User::can()]], que puede ser utilizado como a continuación:
```php
if (\Yii::$app->user->can('createPost')) {
// crear el post
}
```
Si el usuario actual es Jane con `ID=1`, comenzamos desde `createPost` y tratamos de alcanzar a `Jane`:
![Access check](../guide/images/rbac-access-check-1.png "Access check")
Con el fin de comprobar si un usuario puede actualizar un post, necesitamos pasarle un parámetro adicional requerido por `AuthorRule`, descrito antes:
```php
if (\Yii::$app->user->can('updatePost', ['post' => $post])) {
// actualizar post
}
```
Aquí es lo que sucede si el usuario actual es John:
![Access check](../guide/images/rbac-access-check-2.png "Access check")
Comenzamos desde `updatePost` y pasamos por `updateOwnPost`. Con el fin de pasar la comprobación de acceso, `AuthorRule`
debe devolver `true` desde su método `execute()`. El método recive `$params` desde la llamada al método `can()`, cuyo valor es
`['post' => $post]`. Si todo está bien, vamos a obtener `author`, el cual es asignado a John.
En caso de Jane es un poco más simple, ya que ella es un "admin":
![Access check](../guide/images/rbac-access-check-3.png "Access check")
### Utilizar Roles por Defecto <span id="using-default-roles"></span>
Un rol por defecto es un rol que esta asignado *implícitamente* a *todos* los usuarios. La llamada a [[yii\rbac\ManagerInterface::assign()]]
no es necesaria, y los datos de autorización no contienen su información de asignación.
Un rol por defecto es usualmente asociado con una regla que determina si el rol aplica al usuario siendo verificado.
Los roles por defecto se utilizan a menudo en aplicaciones que ya tienen algún tipo de asignación de roles. Por ejemplo, una aplicación
puede tener una columna "grupo" en su tabla de usuario para representar a qué grupo de privilegio pertenece cada usuario.
Si cada grupo privilegio puede ser conectado a un rol de RBAC, se puede utilizar la función de rol por defecto para asignar
cada usuario a un rol RBAC automáticamente. Usemos un ejemplo para mostrar cómo se puede hacer esto.
Suponga que en la tabla de usuario, usted tiene una columna `group` que utiliza 1 para representar el grupo administrador y 2 al grupo autor.
Planeas tener dos roles RBAC, `admin` y `author`, para representar los permisos de estos dos grupos, respectivamente.
Puede configurar los datos RBAC de la siguiente manera,
```php
namespace app\rbac;
use Yii;
use yii\rbac\Rule;
/**
* Comprueba si el grupo coincide
*/
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);
// ... agrega permisos hijos a $author ...
$admin = $auth->createRole('admin');
$admin->ruleName = $rule->name;
$auth->add($admin);
$auth->addChild($admin, $author);
// ... agrega permisos hijos a $admin ...
```
Tenga en cuenta que en el ejemplo anterior, dado que "author" es agregado como hijo de "admin", cuando implementes el método `execute()`
de la clase de la regla, necesitas respetar esta jerarquía. Esto se debe a que cuando el nombre del rol es "author",
el método `execute()` devolverá true si el grupo de usuario es tanto 1 como 2 (lo que significa que el usuario se encuentra en
cualquiera de los dos grupos, "admin" o "author").
Luego, configura `authManager` enumerando los dos roles en [[yii\rbac\BaseManager::$defaultRoles]]:
```php
return [
// ...
'components' => [
'authManager' => [
'class' => 'yii\rbac\PhpManager',
'defaultRoles' => ['admin', 'author'],
],
// ...
],
];
```
Ahora si realizas una comprobación de acceso, tanto el rol `admin` y como el rol `author` serán comprobados evaluando
las reglas asociadas con ellos. Si la regla devuelve true, significa que la regla aplica al usuario actual.
Basado en la implementación de la regla anterior, esto significa que si el valor `group` en un usuario es 1, el rol `admin`
se aplicaría al usuario; y si el valor de `group` es 2, se le aplicaría el rol `author`.

31
docs/guide-es/security-passwords.md

@ -0,0 +1,31 @@
Trabajar con Passwords
======================
La mayoría de los desarrolladores saben que los passwords no deben ser guardados en texto plano, pero muchos desarrolladores aún creen
que es seguro aplicar a los passowrds hash `md5` o `sha1`. Hubo un tiempo cuando utilizar esos algoritmos de hash mencionados era suficiente,
pero el hardware moderno hace posible que ese tipo de hash e incluso más fuertes, puedan revertirse rápidamente utilizando ataques de fuerza bruta.
Para poder proveer de una seguridad mayor para los passwords de los usuarios, incluso en el peor de los escenarios (tu aplicación sufre una brecha de seguridad),
necesitas utilizar un algoritmo que resista los ataques de fuerza bruta. La mejor elección actualmente es `bcrypt`.
En PHP, puedes generar un hash `bcrypt` utilizando la [función crypt](http://php.net/manual/en/function.crypt.php). Yii provee
dos funciones auxiliares que hacen que `crypt` genere y verifique los hash más fácilmente.
Cuando un usuario provee un password por primera vez (por ej., en la registración), dicho password necesita ser pasado por un hash:
```php
$hash = Yii::$app->getSecurity()->generatePasswordHash($password);
```
El hash puede estar asociado con el atributo del model correspondiente, de manera que pueda ser almacenado en la base de datos para uso posterior.
Cuando un usuario intenta ingresar al sistema, el password enviado debe ser verificado con el password con hash almacenado previamente:
```php
if (Yii::$app->getSecurity()->validatePassword($password, $hash)) {
// todo en orden, dejar ingresar al usuario
} else {
// password erróneo
}
```

89
docs/guide-es/start-databases.md

@ -1,37 +1,35 @@
Trabajando con Bases de Datos
=============================
Trabajar con Bases de Datos
===========================
En esta sección, explicaremos cómo crear una nueva página para mostrar datos de países traídos de una tabla de la
base de datos llamada `country`. Para lograr este objetivo, configurarás una conexión a la base de datos,
crearás una clase [Active Record](db-active-record.md), una [acción](structure-controllers.md)
y una [vista](structure-views.md).
A lo largo de este tutorial, aprenderás
A lo largo de este tutorial, aprenderás a
* Cómo configurar una conexión a la base de datos;
* Cómo definir una clase Active Record;
* Cómo realizar consultas a la base de datos utilizando la clase Active Record;
* Cómo mostrar datos en una vista con paginación incluida.
* configurar una conexión a la base de datos;
* definir una clase Active Record;
* realizar consultas a la base de datos utilizando la clase Active Record;
* mostrar datos en una vista con paginación incluida.
Ten en cuenta que para finalizar esta sección, deberás tener al menos conocimientos básicos y experiencia con bases de datos.
En particular, deberás ser capaz de crear una base de datos y saber ejecutar consultas SQL usando alguna herramienta de cliente de
base de datos.
En particular, deberás ser capaz de crear una base de datos y saber ejecutar consultas SQL usando alguna herramienta de cliente de base de datos.
Preparando una Base de Datos <span id="preparing-database"></span>
----------------------------
Preparar una Base de Datos <span id="preparing-database"></span>
--------------------------
Para empezar, crea una base de datos llamada `yii2basic` de la cual tomarás los datos en la aplicación.
Puedes elegir entre una base de datos SQLite, MySQL, PostgreSQL, MSSQL u Oracle. Por simplicidad, usaremos MySQL
en la siguiente descripción.
Puedes elegir entre una base de datos SQLite, MySQL, PostgreSQL, MSSQL u Oracle, dado que Yii incluye soporte para varios motores. Por simplicidad, usaremos MySQL en la siguiente descripción.
Crea una tabla llamada `country` e inserta algunos datos de ejemplo. Puedes utilizar las siguientes declaraciones SQL.
A continuación, crea una tabla llamada `country` e inserta algunos datos de ejemplo. Puedes utilizar las siguientes declaraciones SQL.
```sql
CREATE TABLE `country` (
`code` char(2) NOT NULL PRIMARY KEY,
`name` char(52) NOT NULL,
`population` int(11) NOT NULL DEFAULT '0'
`code` CHAR(2) NOT NULL PRIMARY KEY,
`name` CHAR(52) NOT NULL,
`population` INT(11) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `country` VALUES ('AU','Australia',24016400);
@ -46,12 +44,10 @@ INSERT INTO `country` VALUES ('RU','Russia',146519759);
INSERT INTO `country` VALUES ('US','United States',322976000);
```
Al final, tendrás una base de datos llamada `yii2basic`, y dentro de esta, una tabla llamada `country` con diez
registros en ella.
Al final, tendrás una base de datos llamada `yii2basic`, y dentro de esta, una tabla llamada `country` con diez registros en ella.
Configurando una conexión a la Base de Datos <span id="configuring-db-connection"></span>
--------------------------------------------
Configurar una conexión a la Base de Datos <span id="configuring-db-connection"></span>
------------------------------------------
Asegúrate de tener instalado la extensión de PHP [PDO](http://www.php.net/manual/es/book.pdo.php) y el driver
de PDO para el motor que estés utilizando (ej. `pdo_mysql` para MySQL). Este es un requisito básico si tu aplicación
@ -72,8 +68,8 @@ return [
];
```
Esta es una típica [configuración](concept-configurations.md) basada en archivos. Especifica los parámetros
necesarios para crear e inicializar una instancia de [[yii\db\Connection]] a través de la cual puedes realizar
El archivo `config/db.php` representa la típica [configuración](concept-configurations.md) basada en archivos. Este archivo de configuración en particular
especifica los parámetros necesarios para crear e inicializar una instancia de [[yii\db\Connection]] a través de la cual puedes realizar
consultas SQL contra la base de datos subyacente.
La conexión a la base de datos realizada anteriormente puede ser accedida mediante `Yii::$app->db`.
@ -82,9 +78,15 @@ La conexión a la base de datos realizada anteriormente puede ser accedida media
el cual especifica cómo la instancia de la [aplicación](structure-applications.md) debe ser inicializada.
Para más información, consulta la sección [Configuraciones](concept-configurations.md).
Si necesitas trabajar con bases de datos cuyo soporte no está incluído en Yii, revisa las siguientes extensiones:
- [Informix](https://github.com/edgardmessias/yii2-informix)
- [IBM DB2](https://github.com/edgardmessias/yii2-ibm-db2)
- [Firebird](https://github.com/edgardmessias/yii2-firebird)
Creando un Active Record <span id="creating-active-record"></span>
------------------------
Crear un Active Record <span id="creating-active-record"></span>
----------------------
Para representar y extraer datos de la tabla `country`, crea una clase [Active Record](db-active-record.md)
llamada `Country` y guárdala en el archivo `models/Country.php`.
@ -101,12 +103,13 @@ class Country extends ActiveRecord
}
```
La clase `Country` extiende de [[yii\db\ActiveRecord]]. No necesitas escribir ningún código dentro de ella.
Yii adivinará la tabla correspondiente a la clase desde su nombre. En caso de que esto no funcione, puedes
sobrescribir el método [[yii\db\ActiveRecord::tableName()]] para especificar la tabla asociada a la clase.
La clase `Country` extiende de [[yii\db\ActiveRecord]]. No necesitas escribir ningún código dentro de ella! Con tan sólo el código de arriba,
Yii adivinará la tabla correspondiente a la clase desde su nombre.
> Info: Si no se puede realizar un emparejamiento entre el nombre de la clase y la tabla, puedes
sobrescribir el método [[yii\db\ActiveRecord::tableName()]] para especificar explícitamente el nombre de la tabla asiciada.
Utilizando la clase `Country`, puedes manipular los datos de la tabla `country` fácilmente. Debajo hay sencillos
ejemplos de código que muestran cómo utilizar la clase `Country`.
Utilizando la clase `Country`, puedes manipular los datos de la tabla `country` fácilmente, como se muestra en los siguiente ejemplos:
```php
use app\models\Country;
@ -125,14 +128,12 @@ $country->name = 'U.S.A.';
$country->save();
```
> Info: Active Record es una potente forma de acceder y manipular datos de una base de datos de una manera
orientada a objetos.
Puedes encontrar información más detallada acerca de [Active Record](db-active-record.md). Además de Active Record,
puedes utilizar un método de acceso de bajo nivel llamado [Data Access Objects](db-dao.md).
> Info: Active Record es una potente forma de acceder y manipular datos de una base de datos de una manera orientada a objetos.
Puedes encontrar información más detallada acerca de [Active Record](db-active-record.md). Además de Active Record, puedes utilizar un método de acceso de bajo nivel llamado [Data Access Objects](db-dao.md).
Creando una Acción <span id="creating-action"></span>
------------------
Crear una Acción <span id="creating-action"></span>
----------------
Para mostrar el país a los usuarios, necesitas crear una acción. En vez de hacerlo en el controlador `site`
como lo hiciste en las secciones previas, tiene más sentido crear un nuevo controlador que englobe todas las
@ -174,8 +175,7 @@ class CountryController extends Controller
Guarda el código anterior en el archivo `controllers/CountryController.php`.
La acción `index` llama a `Country::find()` para generar una consulta a la base de datos y traer todos los datos
de la tabla `country`.
La acción `index` llama a `Country::find()` para generar una consulta a la base de datos y traer todos los datos de la tabla `country`.
Para limitar la cantidad de registros traídos en cada petición, la consulta es paginada con la ayuda de un objeto
[[yii\data\Pagination]]. El objeto `Pagination` sirve para dos propósitos:
@ -188,8 +188,8 @@ Al final, la acción `index` renderiza una vista llamada `index` y le pasa los d
de paginación relacionada.
Creando una Vista <span id="creating-view"></span>
-----------------
Crear una Vista <span id="creating-view"></span>
---------------
Bajo el directorio `views`, crea primero un sub-directorio llamado `country`. Este será usado para contener
todas las vistas renderizadas por el controlador `country`.
@ -214,8 +214,7 @@ use yii\widgets\LinkPager;
```
La vista consiste en dos partes. En la primera, los datos de países son recorridos y renderizados como una lista HTML.
En la segunda parte, un widget [[yii\widgets\LinkPager]] es renderizado usando la información de paginación
pasada desde la acción.
En la segunda parte, un widget [[yii\widgets\LinkPager]] es renderizado usando la información de paginación pasada desde la acción.
El widget `LinkPager` muestra una lista de botones que representan las páginas disponibles. Haciendo click en cualquiera
de ellas mostrará los datos de países de la página correspondiente.
@ -226,7 +225,7 @@ Probándolo <span id="trying-it-out"></span>
Para ver cómo funciona, utiliza a la siguiente URL en tu navegador:
```
http://hostname/index.php?r=country/index
http://hostname/index.php?r=country%2Findex
```
![Lista de Países](images/start-country-list.png)
@ -236,7 +235,7 @@ Si haces click en el botón "2", verás que la página muestra otros cinco país
Observa más cuidadosamente y verás que la URL en el navegador cambia a
```
http://hostname/index.php?r=country/index&page=2
http://hostname/index.php?r=country%2Findex&page=2
```
Entre bastidores, [[yii\data\Pagination|Pagination]] está realizando su magia.

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

@ -101,7 +101,7 @@ Probándolo <span id="trying-it-out"></span>
Después de crear la acción y la vista, puedes acceder a la nueva página abriendo el siguiente URL:
```
http://hostname/index.php?r=site/say&message=Hello+World
http://hostname/index.php?r=site%2Fsay&message=Hello+World
```
![Hello World](images/start-hello-world.png)

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

@ -1,58 +1,89 @@
Instalando Yii
==============
Instalar Yii
============
Yii puede ser instalado de dos maneras, usando [Composer](https://getcomposer.org/) o descargando un archivo comprimido.
Es preferible usar la primera forma, ya que te permite instalar [extensiones](structure-extensions.md) o actualizar Yii ejecutando un simple comando.
Puedes instalar Yii de dos maneras, utilizando el administrador de paquetes [Composer](https://getcomposer.org/) o descargando un archivo comprimido.
La forma recomendada es la primera, ya que te permite instalar nuevas [extensions](structure-extensions.md) o actualizar Yii con sólo ejecutar un comando.
> Note: A diferencia de Yii 1, la instalación estándar de Yii 2 resulta en la descarga e instalación tanto del framework como del esqueleto de la aplicación.
La instalación estándar de Yii cuenta tanto con el framework como un template de proyecto instalados.
Un template de proyecto es un proyecto Yii funcional que implementa algunas características básicas como: login, formulario de contacto, etc.
El código está organizado de una forma recomendada. Por lo tanto, puede servir como un buen punto de partida para tus proyectos.
En esta y en las próximas secciones, describiremos cómo instalar Yii con el llamado *Template de Proyecto Básico*
y cómo implementar nuevas características por encima del template. Yii también provee otro template llamado
[Template de Proyecto Avanzado](https://github.com/yiisoft/yii2-app-advanced/blob/master/docs/guide/README.md) qué es mejor para desarrollar aplicaciones con varios niveles
en el entorno de un equipo de desarrollo.
> Info: El Template de Proyecto Básico es adecuado para desarrollar el 90 porciento de las aplicaciones Web. Difiere del
Template de Proyecto Avanzado principalmente en cómo está organizado el código. Si eres nuevo en Yii, te recomendamos
utilizar el Template de Proyecto Básico por su simplicidad pero funcionalidad suficiente.
Instalando a través de Composer <span id="installing-via-composer"></span>
Installing via Composer <span id="installing-via-composer"></span>
-------------------------------
Si aún no tienes Composer instalado, puedes hacerlo siguiendo las instrucciones que se encuentran en
[getcomposer.org](https://getcomposer.org/download/). En Linux y Mac OS X, se ejecutan los siguientes comandos:
curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer
```bash
curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer
```
En Windows, tendrás que descargar y ejecutar [Composer-Setup.exe](https://getcomposer.org/Composer-Setup.exe).
Por favor, consulta la [Documentación de Composer](https://getcomposer.org/doc/) si encuentras algún problema
o deseas obtener un conocimiento más profundo sobre su utilización.
Si ya tienes composer instalado asegurate que esté actualizado ejecutando `composer self-update`
Si ya tienes composer instalado, asegúrate de tener una versión actualizada. Puedes actualizar Composer
ejecutando el comando `composer self-update`
Teniendo Composer instalado, puedes instalar Yii ejecutando los siguientes comandos en un directorio accesible vía Web:
Nota: es posible que en al ejecutar el primer comando te pida tu username
composer global require "fxp/composer-asset-plugin:~1.1.1"
composer create-project --prefer-dist yiisoft/yii2-app-basic basic
```bash
composer global require "fxp/composer-asset-plugin:~1.1.1"
composer create-project --prefer-dist yiisoft/yii2-app-basic basic
```
El primer comando instala [composer asset plugin](https://github.com/francoispluchino/composer-asset-plugin/),
que permite administrar dependencias de paquetes bower y npm a través de Composer. Sólo necesitas ejecutar este comando
una vez. El segundo comando instala Yii en un directorio llamado `basic`. Puedes elegir un nombre de directorio diferente si así lo deseas.
El comando anterior instala Yii dentro del directorio `basic`.
> Note: Durante la instalación, Composer puede preguntar por tus credenciales de acceso de Github. Esto es normal ya que Composer
> necesita obtener suficiente límite de acceso de la API para traer la información de dependencias de Github. Para más detalles,
> consulta la [documentación de Composer](https://getcomposer.org/doc/articles/troubleshooting.md#api-rate-limit-and-oauth-tokens).
> Tip: Si quieres instalar la última versión de desarrollo de Yii, puedes utilizar el siguiente comando,
> que añade una [opción de estabilidad mínima](https://getcomposer.org/doc/04-schema.md#minimum-stability):
> Tip: Si quieres instalar la última versión de desarrollo de Yii, puedes utilizar uno de los siguientes comandos,
> que agregan una [opción de estabilidad](https://getcomposer.org/doc/04-schema.md#minimum-stability):
>
> composer create-project --prefer-dist --stability=dev yiisoft/yii2-app-basic basic
> ```bash
> composer create-project --prefer-dist --stability=dev yiisoft/yii2-app-basic basic
> ```
>
> Ten en cuenta que la versión de desarrollo de Yii no debería ser usada para producción ya que podría romper el funcionamiento actual de la aplicación.
> Ten en cuenta que la versión de desarrollo de Yii no debería ser utilizada en producción ya que podría romper tu código actual.
Instalando desde un Archivo Comprimido <span id="installing-from-archive-file"></span>
--------------------------------------
Instalar desde un Archivo Comprimido <span id="installing-from-archive-file"></span>
------------------------------------
Instalar Yii desde un archivo comprimido involucra dos pasos:
Instalar Yii desde un archivo comprimido involucra tres pasos:
1. Descargar el archivo desde [yiiframework.com](http://www.yiiframework.com/download/yii2-basic).
2. Descomprimirlo en un directorio accesible vía Web.
3. Modificar el archivo `config/web.php` introduciendo una clave secreta para el ítem de configuración `cookieValidationKey`
(esto se realiza automáticamente si estás instalando Yii a través de Composer):
```php
// !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
'cookieValidationKey' => 'enter your secret key here',
```
Otras Opciones de Instalación <span id="other-installation-options"></span>
-----------------------------
Las instrucciones anteriores muestran cómo instalar Yii, lo que también crea una aplicación Web lista para ser usada.
Este es un buen punto de partida para pequeñas aplicaciones, o cuando apenas estás aprendiendo a utilizar Yii.
Este es un buen punto de partida para la mayoría de proyectos, tanto grandes como pequeños. Es especialmente adecuado si recién
estás aprendiendo a utilizar Yii.
Pero también hay otras opciones de instalación disponibles:
@ -65,45 +96,61 @@ Pero también hay otras opciones de instalación disponibles:
Verificando las Instalación <span id="verifying-installation"></span>
---------------------------
Después de la instalación, puedes acceder a la aplicación instalada a través de la siguiente URL:
Una vez finalizada la instalación, o bien configura tu servidor web (mira la sección siguiente) o utiliza
el [servidor web incluido en PHP](https://secure.php.net/manual/en/features.commandline.webserver.php) ejecutando el siguiente
comando de consola estando parado en el directorio `web` de la aplicación:
```bash
php yii serve
```
> Note: Por defecto el servidor HTTP escuchará en el puerto 8080. De cualquier modo, si el puerto está en uso o deseas
servir varias aplicaciones de esta manera, podrías querer especificar qué puerto utilizar. Sólo agrega el argumento --port:
```bash
php yii serve --port=8888
```
http://localhost/basic/web/index.php
Puedes utilizar tu navegador para acceder a la aplicación instalada de Yii en la siguiente URL:
```
http://localhost:8080/.
Esta URL da por hecho que Yii se instaló en un directorio llamado `basic`, directamente bajo el directorio del Servidor Web,
y que el Servidor Web está corriendo en tu máquina local (`localhost`). Sino, podrías necesitar ajustarlo de acuerdo a tu entorno de instalación.
![Instalación Correcta de Yii](images/start-app-installed.png)
Deberías ver la página mostrando "Congratulations!" en tu navegador. Si no ocurriera, por favor chequea que la instalación
de PHP satisface los requerimientos de Yii. Esto puedes hacerlo usando cualquiera de los siguientes procedimientos:
de PHP satisfaga los requerimientos de Yii. Esto puedes hacerlo usando cualquiera de los siguientes procedimientos:
* Visitando la URL `http://localhost/basic/requirements.php` en tu navegador
* Copiando `/requirements.php` a `/web/requirements.php` y visitando la URL `http://localhost/basic/requirements.php` en tu navegador
* Corriendo los siguientes comandos:
```
```bash
cd basic
php requirements.php
```
Deberías configurar tu instalación de PHP para que satisfaga los requisitos mínimos de Yii. Lo que es más importante,
debes tener PHP 5.4 o mayor. También deberías instalar la [Extensión de PHP PDO](http://www.php.net/manual/es/pdo.installation.php)
y el correspondiente driver de base de datos (como `pdo_mysql` para bases de datos MySQL), si tu aplicación lo necesitara.
Deberías configurar tu instalación de PHP para que satisfaga los requisitos mínimos de Yii. Lo que es más importante, debes tener PHP 5.4 o mayor.
También deberías instalar la [Extensión de PHP PDO](http://www.php.net/manual/es/pdo.installation.php) y el correspondiente driver de base de datos
(como `pdo_mysql` para bases de datos MySQL), si tu aplicación lo necesitara.
Configurar Servidores Web <span id="configuring-web-servers"></span>
-------------------------
Configurando Servidores Web <span id="configuring-web-servers"></span>
---------------------------
> Info: Puedes saltear esta sección por ahora si sólo estás probando Yii sin intención
de poner la aplicación en un servidor de producción.
> Info: Puedes saltear esta sección por ahora si sólo estás probando Yii sin intención de poner la aplicación en un servidor de producción.
La aplicación instalada siguiendo las instrucciones mencionadas debería estar lista para usar tanto
con un [servidor HTTP Apache](http://httpd.apache.org/) como con un [servidor HTTP Nginx](http://nginx.org/),
en Windows, Mac OS X, o Linux utilizando PHP 5.4 o mayor. Yii 2.0 también es compatible con [HHVM](http://hhvm.com/)
de Facebook. De todos modos, hay algunos casos donde HHVM se comporta diferente del
PHP oficial, por lo que tendrás que tener cuidados extra al utilizarlo.
La aplicación instalada debería estar lista para usar tanto con un [servidor HTTP Apache](http://httpd.apache.org/) como con un [servidor HTTP Nginx](http://nginx.org/),
en Windows, Mac OS X, o Linux.
En un servidor de producción, podrías querer configurar el servidor Web para que la aplicación sea accedida a través de la
URL `http://www.example.com/index.php` en vez de `http://www.example.com/basic/web/index.php`. Tal configuración
require apuntar el document root de tu servidor Web al directorio `basic/web`. También podrías querer ocultar `index.php`
de la URL, como se describe en la sección [Parseo y Generación de URLs](runtime-url-handling.md).
En un servidor de producción, podrías querer configurar el servidor Web para que la aplicación sea accedida
a través de la URL `http://www.example.com/index.php` en vez de `http://www.example.com/basic/web/index.php`. Tal configuración
require apuntar el document root de tu servidor Web a la carpeta `basic/web`. También podrías
querer ocultar `index.php` de la URL, como se describe en la sección [Parseo y Generación de URLs](runtime-url-handling.md).
En esta sub-sección, aprenderás a configurar tu servidor Apache o Nginx para alcanzar estos objetivos.
> Info: Al definir `basic/web` como document root, también previenes que los usuarios finales accedan
@ -120,29 +167,29 @@ la sección [Entorno de Hosting Compartido](tutorial-shared-hosting.md) para má
Utiliza la siguiente configuración del archivo `httpd.conf` de Apache dentro de la configuración del virtual host. Ten en cuenta
que deberás reemplazar `path/to/basic/web` con la ruta real a `basic/web`.
```
# Definir el document root de "basic/web"
```apache
# Definir el document root como "basic/web"
DocumentRoot "path/to/basic/web"
<Directory "path/to/basic/web">
# utiliza mod_rewrite para soporte de URLs amigables
RewriteEngine on
# Si el directorio o archivo existe, utiliza el request directamente
# Si el directorio o archivo existe, utiliza la petición directamente
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Sino envía el request a index.php
# Sino, redirige la petición a index.php
RewriteRule . index.php
# ...s configuraciones...
# ...otras configuraciones...
</Directory>
```
### Configuración Recomendada de Nginx <span id="recommended-nginx-configuration"></span>
Deberías haber instalado PHP como un [FPM SAPI](http://php.net/install.fpm) para utilizar [Nginx](http://wiki.nginx.org/).
Utiliza la siguiente configuración de Nginx, reemplazando `path/to/basic/web` con la ruta real a `basic/web` y `mysite.local` con el
hostname real del servidor.
Para utilizar [Nginx](http://wiki.nginx.org/), debes instalar PHP como un [FPM SAPI](http://php.net/install.fpm).
Utiliza la siguiente configuración de Nginx, reemplazando `path/to/basic/web` con la ruta real a
`basic/web` y `mysite.local` con el hostname real a servir.
```
server {
@ -156,12 +203,12 @@ server {
root /path/to/basic/web;
index index.php;
access_log /path/to/basic/log/access.log main;
access_log /path/to/basic/log/access.log;
error_log /path/to/basic/log/error.log;
location / {
# Redireccionar a index.php todo lo que no sea un archivo real
try_files $uri $uri/ /index.php?$args;
try_files $uri $uri/ /index.php$is_args$args;
}
# descomentar para evitar el procesamiento de llamadas de Yii a archivos estáticos no existente
@ -171,9 +218,11 @@ server {
#error_page 404 /404.html;
location ~ \.php$ {
include fastcgi.conf;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass 127.0.0.1:9000;
#fastcgi_pass unix:/var/run/php5-fpm.sock;
try_files $uri =404;
}
location ~ /\.(ht|svn|git) {

53
docs/guide-es/start-looking-ahead.md

@ -1,32 +1,35 @@
Mirando Hacia Adelante
======================
Hasta ahora, has creado una aplicación completa en Yii, y has aprendido cómo implementar algunas de las características más típicas y necesarias, como la de obtener datos de los usuarios a través de un formulario HTML, y traer datos de la base de datos
para mostrarlos en forma paginada. También has aprendido cómo utilizar la herramienta [Gii](tool-gii.md) para generar
código automáticamente, lo que transforma el hecho de programar en una tarea tan simple como la de completar algunos formularios.
En esta sección, resumiremos los recursos acerca de Yii que ayudan a ser más productivos al utilizar la librería.
Si has leído el capítulo "Comenzando con Yii" completo, has creado una aplicación completa en Yii. En el proceso, has aprendido cómo implementar algunas
características comúnmente necesitadas, tales como obtener datos del usuario a través de formularios HTML, traer datos desde la base de datos,
y mostrar datos utilizando paginación. También has aprendido a utilizar [Gii](https://github.com/yiisoft/yii2-gii/blob/master/docs/guide/README.md) para generar
código automáticamente. Utilizar Gii para la generación de código transforma la carga en el proceso de tu desarrollo Web en una tarea tan simple como solamente completar unos formularios.
Esta sección resumirá los recursos disponibles de Yii que te ayudarán a ser más productivo al utilizar el framework.
* Documentación
- La Guía Definitiva:
Como el nombre indica, la guía precisamente define cómo Yii debería trabajar y te da una guía general
acerca de cómo usar la librería. Este es el tutorial simple más importante de Yii que deberías leer
antes de empezar a escribir código.
- La Referencia de Clases:
Este especifica el uso de cada clase provista por Yii. Debería ser utilizado mayormente cuando estés escribiendo
código y quieras entender el funcionamiento de alguna clase, método o propiedad en particular.
- Artículos de la Wiki:
Estos artículos son escritos por usuarios de Yii basado en experiencias propias. En su mayoría son escritos
como recetas que muestran cómo resolver problemas particulares en Yii. Aunque la calidad de estos artículos
puede ser tan buena como la Guía Definitiva, son particularmente útiles al cubrir aspectos más amplios
y puede a menudo ofrecer soluciones listas para usar.
- Libros
- [La Guía Definitiva](http://www.yiiframework.com/doc-2.0/guide-README.html):
Como su nombre lo indica, la guía define precisamente cómo debería trabajar Yii y provee guías generales
acerca de su utilización. Es el tutorial más importante de Yii, y el que deberías leer
antes de escribir cualquier código en Yii.
- [La Referencia de Clases](http://www.yiiframework.com/doc-2.0/index.html):
Esta especifica el uso de cada clase provista por Yii. Debería ser utilizada principalmente cuando estás escribiendo
código y deseas entender el uso de una clase, método o propiedad en particular. El uso de la referencia de clases es mejor luego de un entendimiento contextual del framework.
- [Los Artículos de la Wiki](http://www.yiiframework.com/wiki/?tag=yii2):
Los artículos de la wiki son escritos por usuarios de Yii basados en sus propias experiencias. La mayoría de ellos están escritos
como recetas de cocina, y muestran cómo resolver problemas particulares utilizando Yii. Si bien la calidad de estos
puede no ser tan buena como la de la Guía Definitiva, son útiles ya que cubren un espectro muy amplio
de temas y puede proveer a menudo soluciones listas para usar.
- [Libros](http://www.yiiframework.com/doc/)
* [Extensiones](http://www.yiiframework.com/extensions/):
Yii cuenta con una librería de cientos de extensiones que han sido provistas por la comunidad de usuarios que pueden ser fácilmente integradas
en tu aplicación y lograr que sea más simple y rápido desarrollarla.
Yii puede hacer alarde de una librería de miles de extensiones contribuidas por usuarios, que pueden fácilmente conectadas a tu aplicación, haciendo que el desarrollo de la misma sea todavía más fácil y rápido.
* Comunidad
- [Foro](http://www.yiiframework.com/forum/)
- [GitHub](https://github.com/yiisoft/yii2)
- [Facebook](https://www.facebook.com/groups/yiitalk/)
- [Twitter](https://twitter.com/yiiframework)
- [LinkedIn](https://www.linkedin.com/groups/yii-framework-1483367)
- Foro: <http://www.yiiframework.com/forum/>
- Chat IRC: El canal #yii en la red freenode (<irc://irc.freenode.net/yii>)
- Chat Gitter: <https://gitter.im/yiisoft/yii2>
- GitHub: <https://github.com/yiisoft/yii2>
- Facebook: <https://www.facebook.com/groups/yiitalk/>
- Twitter: <https://twitter.com/yiiframework>
- LinkedIn: <https://www.linkedin.com/groups/yii-framework-1483367>
- Stackoverflow: <http://stackoverflow.com/questions/tagged/yii2>

18
docs/guide-es/start-workflow.md

@ -10,6 +10,9 @@ y cómo la aplicación maneja los requests en general.
como el document root de tu servidor Web, y configurado la URL de acceso a tu aplicación para que sea `http://hostname/index.php`
o similar.
Dependiendo de tus necesidades, por favor ajusta dichas URLs.
Ten en cuenta que a diferencia del framework en sí, después de que el template de proyecto es instalado, este es todo tuyo. Eres libre de agregar o eliminar
código modificar todo según tu necesidad.
Funcionalidad <span id="functionality"></span>
@ -17,10 +20,9 @@ Funcionalidad <span id="functionality"></span>
La aplicación básica contiene 4 páginas:
* Página principal, mostrada cuando se accede a la URL `http://hostname/index.php`,
* página principal, mostrada cuando se accede a la URL `http://hostname/index.php`,
* página "Acerca de (About)",
* la página "Contacto (Contact)", que muestra un formulario de contacto que permite a los usuarios
finales contactarse vía email,
* la página "Contacto (Contact)", que muestra un formulario de contacto que permite a los usuarios finales contactarse vía email,
* y la página "Login", que muestra un formulario para loguearse que puede usarse para autenticar usuarios.
Intenta loguearte con "admin/admin", y verás que el elemento "Login" del menú principal cambiará a "Logout".
@ -28,10 +30,13 @@ Estas páginas comparten un encabezado y un pie. El encabezado contiene una barr
la navegación entre las diferentes páginas.
También deberías ver una barra en la parte inferior de la ventana del navegador.
Esta es la útil [herramienta de depuración](tool-debugger.md) provista por Yii para registrar y mostrar mucha información de depuración,
tal como los mensajes de log, response status, las consultas ejecutadas a la base de datos, y más.
Esta es la útil [herramienta de depuración](tool-debugger.md) provista por Yii para registrar y mostrar mucha información de depuración, tal como los mensajes de log, response status, las consultas ejecutadas a la base de datos, y más.
Adicionalmente a la aplicación web, hay un script de consola llamado `yii`, localizado en el directorio base de la aplicación.
El script puede ser utilizado para ejecutar tareas de fondo y tareas de mantenimiento de la aplicación, las cuales son descritas
en la [Sección de Aplicación de Consola](tutorial-console.md).
Estructura de la aplicación <span id="application-structure"></span>
---------------------------
@ -71,7 +76,7 @@ Cada aplicación tiene un script de entrada `web/index.php` que es el único scr
El script de entrada toma una petición (request) entrante y crea una instancia de una [aplicación](structure-applications.md) para manejarlo.
La [aplicación](structure-applications.md) resuelve la petición (request) con la ayuda de sus [componentes](concept-components.md),
y la envía al resto de los elementos MVC. Los [widgets](structure-widgets.md) son usados en las [vistas](structure-views.md)
para ayudar a construir elementos de interfáz complejos y dinámicos.
para ayudar a construir elementos de interfaz complejos y dinámicos.
Ciclo de Vida de una Petición (Request) <span id="request-lifecycle"></span>
@ -94,3 +99,4 @@ El siguiente diagrama muestra cómo una aplicación maneja una petición.
9. La acción renderiza una vista, pasándole los datos del modelo cargado.
10. El resultado de la renderización es pasado al componente [response](runtime-responses.md) de la aplicación.
11. El componente response envía el resultado de la renderización al navegador del usuario.

383
docs/guide-es/structure-views.md

@ -2,13 +2,18 @@ Vistas
======
Las Vistas (views) son una parte de la arquitectura [MVC](http://es.wikipedia.org/wiki/Modelo%E2%80%93vista%E2%80%93controlador).
Estas son el código responsable de presentar los datos al usuario final. En una aplicación Web, las vistas son usualmente creadas en términos de *templates* que son archivos PHP que contienen principalmente HTML y PHP.
Son manejadas por el componente de la aplicación [[yii\web\View|view]], el cual provee métodos comúnmente utilizados para facilitar la composición y el renderizado de las mismas. Por simplicidad, a menudo las llamamos *templates* o *archivos de templates*.
Estas son el código responsable de presentar los datos al usuario final. En una aplicación Web, las vistas son usualmente creadas
en términos de *templates* que son archivos PHP que contienen principalmente HTML y PHP.
Estas son manejadas por el [componente de la aplicación](structure-application-components.md) [[yii\web\View|view]], el cual provee los métodos comúnmente utilizados
para facilitar la composición y renderizado. Por simplicidad, a menudo nos referimos a los templates de vistas o archivos de templates
como vistas.
## Creando Vistas <span id="creating-views"></span>
## Crear Vistas <span id="creating-views"></span>
Como fue mencionado, una vista es simplemente un archivo PHP que mezcla código PHP y HTML. La siguiente es una vista que muestra un formulario de login. Como puedes ver, el código PHP utilizado es para generar contenido dinámico, como el título de la página y el formulario mismo, mientras que el código HTML organiza estos elementos en una página HTML mostrable.
Como fue mencionado, una vista es simplemente un archivo PHP que mezcla código PHP y HTML. La siguiente es una vista
que muestra un formulario de login. Como puedes ver, el código PHP utilizado es para generar contenido dinámico, como el
título de la página y el formulario mismo, mientras que el código HTML organiza estos elementos en una página HTML mostrable.
```php
<?php
@ -32,18 +37,25 @@ $this->title = 'Login';
<?php ActiveForm::end(); ?>
```
Dentro de una vista, puedes acceder a la variable `$this` referida al [[yii\web\View|componente view]] que maneja y renderiza la vista actual.
Dentro de una vista, puedes acceder a la variable `$this` referida al [[yii\web\View|componente view]]
que maneja y renderiza la vista actual.
Además de `$this`, puede haber otras variables predefinidas en una vista, como `$form` y `$model` en el ejemplo anterior. Estas variables representan los datos que son *inyectados* a la vista desde el [controlador](structure-controllers.md) o algún otro objeto que dispara la [renderización de la vista](#rendering-views).
Además de `$this`, puede haber otras variables predefinidas en una vista, como `$form` y `$model` en el
ejemplo anterior. Estas variables representan los datos que son *inyectados* a la vista desde el [controlador](structure-controllers.md)
o algún otro objeto que dispara la [renderización de la vista](#rendering-views).
> Tip: La lista de variables predefinidas están listadas en un bloque de comentario al principio de la vista así pueden ser reconocidas por las IDEs. Esto es también una buena manera de documentar tus propias vistas.
> Tip: La lista de variables predefinidas están listadas en un bloque de comentario al principio de la vista así
pueden ser reconocidas por las IDEs. Esto es también una buena manera de documentar tus propias vistas.
### Seguridad <span id="security"></span>
Al crear vistas que generan páginas HTML, es importante que codifiques (encode) y/o filtres los datos provenientes de los usuarios antes de mostrarlos. De otro modo, tu aplicación puede estar expuesta a ataques tipo [cross-site scripting](http://es.wikipedia.org/wiki/Cross-site_scripting).
Al crear vistas que generan páginas HTML, es importante que codifiques (encode) y/o filtres los datos
provenientes de los usuarios antes de mostrarlos. De otro modo, tu aplicación puede estar expuesta
a ataques tipo [cross-site scripting](http://es.wikipedia.org/wiki/Cross-site_scripting).
Para mostrar un texto plano, codifícalos previamente utilizando [[yii\helpers\Html::encode()]]. Por ejemplo, el siguiente código aplica una codificación del nombre de usuario antes de mostrarlo:
Para mostrar un texto plano, codifícalos previamente utilizando [[yii\helpers\Html::encode()]]. Por ejemplo, el siguiente código aplica
una codificación del nombre de usuario antes de mostrarlo:
```php
<?php
@ -55,7 +67,8 @@ use yii\helpers\Html;
</div>
```
Para mostrar contenido HTML, utiliza [[yii\helpers\HtmlPurifier]] para filtrarlo antes. Por ejemplo, el siguiente código filtra el contenido del post antes de mostrarlo en pantalla:
Para mostrar contenido HTML, utiliza [[yii\helpers\HtmlPurifier]] para filtrarlo antes. Por ejemplo, el siguiente código
filtra el contenido del post antes de mostrarlo en pantalla:
```php
<?php
@ -67,23 +80,31 @@ use yii\helpers\HtmlPurifier;
</div>
```
> Tip: Aunque HTMLPurifier hace un excelente trabajo al hacer la salida más segura, no es rápido. Deberías considerar utilizar [caching](caching-overview.md) al resultado de aplicar el filtro si tu aplicación requiere un gran desempeño (performance).
> Tip: Aunque HTMLPurifier hace un excelente trabajo al hacer la salida más segura, no es rápido. Deberías considerar
el aplicar un [caching](caching-overview.md) al resultado de aplicar el filtro si tu aplicación requiere un gran desempeño (performance).
### Organizando Vistas <span id="organizing-views"></span>
### Organizar las Vistas <span id="organizing-views"></span>
Así como en [controladores](structure-controllers.md) y [modelos](structure-models.md), existen convenciones para organizar las vistas.
* Para vistas renderizadas por controladores, deberían colocarse en un directorio tipo `@app/views/ControllerID` por defecto, donde `ControllerID` se refiere al [ID del controlador](structure-controllers.md#routes). Por ejemplo, si la clase del controlador es `PostController`, el directorio sería `@app/views/post`; Si fuera `PostCommentController`, el directorio sería `@app/views/post-comment`. En caso de que el controlador pertenezca a un módulo, el directorio sería `views/ControllerID` bajo el [[yii\base\Module::basePath|directorio del módulo]].
* Para vistas renderizadas por un [widget](structure-widgets.md), deberían ser puestas en un directorio tipo `WidgetPath/views` por defecto, donde `WidgetPath` se refiere al directorio que contiene a la clase del widget.
* Para vistas renderizadas por controladores, deberían colocarse en un directorio tipo `@app/views/ControllerID` por defecto,
donde `ControllerID` se refiere al [ID del controlador](structure-controllers.md#routes). Por ejemplo,
si la clase del controlador es `PostController`, el directorio sería `@app/views/post`; Si fuera `PostCommentController`,
el directorio sería `@app/views/post-comment`. En caso de que el controlador pertenezca a un módulo,
el directorio sería `views/ControllerID` bajo el [[yii\base\Module::basePath|directorio del módulo]].
* Para vistas renderizadas por un [widget](structure-widgets.md), deberían ser puestas en un directorio
tipo `WidgetPath/views` por defecto, donde `WidgetPath` se refiere al directorio que contiene a la clase del widget.
* Para vistas renderizadas por otros objetos, se recomienda seguir una convención similar a la utilizada con los widgets.
Puedes personalizar estos directorios por defecto sobrescribiendo el método [[yii\base\ViewContextInterface::getViewPath()]] en el controlador o widget necesario.
Puedes personalizar estos directorios por defecto sobrescribiendo el método [[yii\base\ViewContextInterface::getViewPath()]]
en el controlador o widget necesario.
## Renderizando Vistas <span id="rendering-views"></span>
Puedes renderizar vistas desde [controllers](structure-controllers.md), [widgets](structure-widgets.md), o cualquier otro lugar llamando a los métodos de renderización de vistas. Estos métodos comparten una firma similar, como se muestra a continuación:
Puedes renderizar vistas desde [controllers](structure-controllers.md), [widgets](structure-widgets.md), o cualquier otro lugar
llamando a los métodos de renderización de vistas. Estos métodos comparten una firma similar, como se muestra a continuación:
```
/**
@ -99,10 +120,15 @@ methodName($view, $params = [])
Dentro de los [controladores](structure-controllers.md), puedes llamar al siguiente método del controlador para renderizar una vista:
* [[yii\base\Controller::render()|render()]]: renderiza la [vista nombrada](#named-views) y aplica un [layout](#layouts) al resultado de la renderización.
* [[yii\base\Controller::render()|render()]]: renderiza la [vista nombrada](#named-views) y aplica un [layout](#layouts)
al resultado de la renderización.
* [[yii\base\Controller::renderPartial()|renderPartial()]]: renderiza la [vista nombrada](#named-views) sin ningún layout aplicado.
* [[yii\web\Controller::renderAjax()|renderAjax()]]: renderiza la [vista nombrada](#named-views) sin layout, e inyecta todos los scripts y archivos JS/CSS registrados. Esto sucede usualmente en respuestas a llamadas a AJAX `requests`.
* [[yii\base\Controller::renderFile()|renderFile()]]: renderiza la vista especificada en términos de la ruta al archivo o [alias](concept-aliases.md).
* [[yii\web\Controller::renderAjax()|renderAjax()]]: renderiza la [vista nombrada](#named-views) sin layout,
e inyecta todos los scripts y archivos JS/CSS registrados. Esto sucede usualmente en respuestas a peticiones AJAX.
* [[yii\base\Controller::renderFile()|renderFile()]]: renderiza la vista especificada en términos de la ruta al archivo o
[alias](concept-aliases.md).
* [[yii\base\Controller::renderContent()|renderContent()]]: renderiza un string fijo, inscrustándolo en
el [layout](#layouts) actualmente aplicable. Este método está disponible desde la versión 2.0.1.
Por ejemplo:
@ -137,7 +163,8 @@ class PostController extends Controller
Dentro de [widgets](structure-widgets.md), puedes llamar a cualquier de los siguientes métodos de widget para renderizar una vista.
* [[yii\base\Widget::render()|render()]]: renderiza la [vista nombrada](#named-views).
* [[yii\base\Widget::renderFile()|renderFile()]]: renderiza la vista especificada en términos de ruta al archivo o [alias](concept-aliases.md).
* [[yii\base\Widget::renderFile()|renderFile()]]: renderiza la vista especificada en términos de ruta al archivo
o [alias](concept-aliases.md).
Por ejemplo:
@ -162,22 +189,25 @@ class ListWidget extends Widget
```
### Renderizando en Vistas <span id="rendering-in-views"></span>
### Renderizar en Vistas <span id="rendering-in-views"></span>
Puedes renderizar una vista dentro de otra vista llamando a algunos de los siguientes métodos provistos por el [[yii\base\View|componente view]]:
* [[yii\base\View::render()|render()]]: renderiza la [vista nombrada](#named-views).
* [[yii\web\View::renderAjax()|renderAjax()]]: renderiza la [vista nombrada](#named-views) e inyecta todos los archivos y scripts JS/CSS. Esto sucede usualmente en respuestas a llamadas a AJAX `requests`.
* [[yii\base\View::renderFile()|renderFile()]]: renderiza la vista especificada en términos de ruta al archivo o [alias](concept-aliases.md).
* [[yii\web\View::renderAjax()|renderAjax()]]: renderiza la [vista nombrada](#named-views) e inyecta
todos los archivos y scripts JS/CSS. Esto sucede usualmente en respuestas a las peticiones AJAX.
* [[yii\base\View::renderFile()|renderFile()]]: renderiza la vista especificada en términos de ruta al archivo
o [alias](concept-aliases.md).
Por ejemplo, el siguiente código en una vista renderiza el template `_overview.php` encontrado en el mismo directorio de la vista renderizada actualmente. Recuerda que la variable `$this` en una vista se refiere al componente [[yii\base\View|view]]:
Por ejemplo, el siguiente código en una vista renderiza el template `_overview.php` encontrado en el mismo directorio
de la vista renderizada actualmente. Recuerda que la variable `$this` en una vista se refiere al componente [[yii\base\View|view]]:
```php
<?= $this->render('_overview') ?>
```
### Renderizando en Otros Lugares <span id="rendering-in-other-places"></span>
### Renderizar en Otros Lugares <span id="rendering-in-other-places"></span>
En cualquier lugar, puedes tener acceso al componente [[yii\base\View|view]] utilizando la expresión
`Yii::$app->view` y entonces llamar a los métodos previamente mencionados para renderizar una vista. Por ejemplo:
@ -190,25 +220,43 @@ echo \Yii::$app->view->renderFile('@app/views/site/license.php');
### Vistas Nombradas <span id="named-views"></span>
Cuando renderizas una vista, puedes especificar el template utilizando tanto el nombre de la vista o la ruta/alias al archivo. En la mayoría de los casos, utilizarías la primera porque es más concisa y flexible. *Vistas nombradas* son vistas especificadas mediante un nombre en vez de una ruta al archivo o alias.
Cuando renderizas una vista, puedes especificar el template utilizando tanto el nombre de la vista o la ruta/alias al archivo. En la mayoría de los casos,
utilizarías la primera porque es más concisa y flexible. Las *vistas nombradas* son vistas especificadas mediante un nombre en vez de una ruta al archivo o alias.
Un nombre de vista es resuelto a su correspondiente ruta de archivo siguiendo las siguientes reglas:
* Un nombre de vista puede omitir la extensión del archivo. En estos casos se utilizará `.php` como extensión del archivo. Por ejemplo, el nombre de vista `about` corresponde al archivo `about.php`.
* Un nombre de vista puede omitir la extensión del archivo. En estos casos se utilizará `.php` como extensión del archivo. Por ejemplo,
el nombre de vista `about` corresponde al archivo `about.php`.
* Si el nombre de la vista comienza con doble barra (`//`), la ruta al archivo correspondiente será `@app/views/ViewName`.
Esto quiere decir que la vista es buscada bajo el [[yii\base\Application::viewPath|view path de la aplicación]].
Por ejemplo, `//site/about` será resuelto como `@app/views/site/about.php`.
* Si el nombre de la vista comienza con una barra simple `/`, la ruta al archivo de la vista utilizará como prefijo el nombre de la vista con el [[yii\base\Module::viewPath|view path]] del [módulo](structure-modules.md) utilizado actualmente. Si no hubiera módulo activo se utilizará `@app/views/ViewName`. Por ejemplo, `/user/create` será resuelto a `@app/modules/user/views/user/create.php` si el módulo activo es `user`. Si no hubiera módulo activo, la ruta al archivo será `@app/views/user/create.php`.
* Si la vista es renderizada con un [[yii\base\View::context|context]] y dicho contexto implementa [[yii\base\ViewContextInterface]], la ruta al archivo se forma utilizando como prefijo el [[yii\base\ViewContextInterface::getViewPath()|view path]] del contexto de la vista. Esto principalmente aplica a vistas renderizadas en controladores y widgets. Por ejemplo, `site/about` será resuelto a `@app/views/site/about.php` si el contexto es el controlador `SiteController`.
* Si la vista es renderizada dentro de otra vista, el directorio que contiene la otra vista será prefijado al nuevo nombre de la vista para formar la ruta a la vista. Por ejemplo, `item` sera resuelto a `@app/views/post/item` si está siendo renderizado desde la vista `@app/views/post/index.php`.
De acuerdo a las reglas mencionadas, al llamar a `$this->render('view')` en el controlador `app\controllers\PostController` se renderizará el template `@app/views/post/view.php`, mientras que llamando a `$this->render('_overview')` en la vista renderizará el template `@app/views/post/_overview.php`.
### Accediendo a Datos en la Vista <span id="accessing-data-in-views"></span>
Esto quiere decir que la vista es buscada bajo el [[yii\base\Application::viewPath|ruta de vistas de la aplicación]].
Por ejemplo, `//site/about` será resuelto como `@app/views/site/about.php`.
* Si el nombre de la vista comienza con una barra simple `/`, la ruta al archivo de la vista utilizará como prefijo el nombre de la vista
con el [[yii\base\Module::viewPath|view path]] del [módulo](structure-modules.md) utilizado actualmente.
Si no hubiera módulo activo se utilizará `@app/views/ViewName`. Por ejemplo, `/user/create` será resuelto como
`@app/modules/user/views/user/create.php` si el módulo activo es `user`. Si no hubiera módulo activo,
la ruta al archivo será `@app/views/user/create.php`.
* Si la vista es renderizada con un [[yii\base\View::context|context]] y dicho contexto implementa [[yii\base\ViewContextInterface]],
la ruta al archivo se forma utilizando como prefijo la [[yii\base\ViewContextInterface::getViewPath()|ruta de vistas]] del contexto
de la vista. Esto principalmente aplica a vistas renderizadas en controladores y widgets. Por ejemplo,
`about` será resuelto como `@app/views/site/about.php` si el contexto es el controlador `SiteController`.
* Si la vista es renderizada dentro de otra vista, el directorio que contiene la otra vista será prefijado
al nuevo nombre de la vista para formar la ruta a la vista. Por ejemplo, `item` sera resuelto como `@app/views/post/item`
si está siendo renderizado desde la vista `@app/views/post/index.php`.
De acuerdo a las reglas mencionadas, al llamar a `$this->render('view')` en el controlador `app\controllers\PostController`
se renderizará el template `@app/views/post/view.php`, mientras que llamando a `$this->render('_overview')` en la vista
renderizará el template `@app/views/post/_overview.php`.
### Acceder a Datos en la Vista <span id="accessing-data-in-views"></span>
Hay dos modos posibles de acceder a los datos en la vista: push (inyectar) y pull (traer).
Al pasar los datos como segundo parámetro en algún método de renderización, estás utilizando el modo push. Los datos deberían ser representados como un array de pares clave-valor. Cuando la vista está siendo renderizada, la función PHP `extract()` será llamada sobre este array así se extraen las variables que contiene a la vista actual. Por ejemplo, el siguiente código de renderización en un controlador inyectará dos variables a la vista `report`: `$foo = 1` and `$bar = 2`.
Al pasar los datos como segundo parámetro en algún método de renderización, estás utilizando el modo push.
Los datos deberían ser representados como un array de pares clave-valor. Cuando la vista está siendo renderizada, la función PHP `extract()`
será llamada sobre este array así se extraen las variables que contiene a la vista actual.
Por ejemplo, el siguiente código de renderización en un controlador inyectará dos variables a la vista `report`:
`$foo = 1` y `$bar = 2`.
```php
echo $this->render('report', [
@ -217,26 +265,34 @@ echo $this->render('report', [
]);
```
El modo pull obtiene los datos del [[yii\base\View|componente view]] u otros objetos accesibles en las vistas (ej. `Yii::$app`). Utilizando el código anterior como ejemplo, dentro de una vista puedes acceder al objeto del controlador a través de la expresión `$this->context`. Como resultado, te es posible acceder a cualquier propiedad o método del controlador en la vista `report`, tal como el ID del controlador como se muestra a continuación:
El modo pull obtiene los datos del [[yii\base\View|componente view]] u otros objetos accesibles
en las vistas (ej. `Yii::$app`). Utilizando el código anterior como ejemplo, dentro de una vista puedes acceder al objeto del controlador
a través de la expresión `$this->context`. Como resultado, te es posible acceder a cualquier propiedad o método
del controlador en la vista `report`, tal como el ID del controlador como se muestra a continuación:
```php
El ID del controlador es: <?= $this->context->id ?>
?>
```
Para acceder a datos en la vista, normalmente se prefiere el modo push, ya que hace a la vista menos dependiente de los objetos del contexto. La contra es que tienes que construir el array manualmente cada vez, lo que podría volverse tedioso y propenso al error si la misma vista es compartida y renderizada desde diferentes lugares.
Para acceder a datos en la vista, normalmente se prefiere el modo push, ya que hace a la vista menos dependiente
de los objetos del contexto. La contra es que tienes que construir el array manualmente cada vez, lo que podría
volverse tedioso y propenso al error si la misma vista es compartida y renderizada desde diferentes lugares.
### Compartiendo Datos Entre las Vistas <span id="sharing-data-among-views"></span>
### Compartir Datos Entre las Vistas <span id="sharing-data-among-views"></span>
El [[yii\base\View|componente view]] provee la propiedad [[yii\base\View::params|params]] para que puedas compartir datos entre diferentes vistas.
El [[yii\base\View|componente view]] provee la propiedad [[yii\base\View::params|params]] para que puedas compartir datos
entre diferentes vistas.
Por ejemplo, en una vista `about`, podrías tener el siguiente código que especifica el segmento actual del breadcrumbs (migas de pan).
Por ejemplo, en una vista `about`, podrías tener el siguiente código que especifica el segmento actual
del breadcrumbs (migas de pan).
```php
$this->params['breadcrumbs'][] = 'Acerca de Nosotros';
```
Entonces, en el archivo del [layout](#layouts), que es también una vista, puedes mostrar el breadcrumbs utilizando los datos pasados a través de [[yii\base\View::params|params]]:
Entonces, en el archivo del [layout](#layouts), que es también una vista, puedes mostrar el breadcrumbs utilizando los datos
pasados a través de [[yii\base\View::params|params]]:
```php
<?= yii\widgets\Breadcrumbs::widget([
@ -247,14 +303,22 @@ Entonces, en el archivo del [layout](#layouts), que es también una vista, puede
## Layouts <span id="layouts"></span>
Los layouts son un tipo especial de vista que representan partes comunes de otras múltiples vistas. Por ejemplo, las páginas de la mayoría de las aplicaciones Web comparten el mismo encabezado y pie de página. Aunque puedes repetirlos en todas y cada una de las vistas, una mejor forma es hacerlo sólo en el layout e incrustar el resultado de la renderización de la vista en un lugar apropiado del mismo.
Los layouts son un tipo especial de vista que representan partes comunes de otras múltiples vistas. Por ejemplo, las páginas
de la mayoría de las aplicaciones Web comparten el mismo encabezado y pie de página. Aunque puedes repetirlos en todas y cada una de las vistas,
una mejor forma es hacerlo sólo en el layout e incrustar el resultado de la renderización de la vista
en un lugar apropiado del mismo.
### Creando Layouts <span id="creating-layouts"></span>
### Crear Layouts <span id="creating-layouts"></span>
Dado que los layouts son también vistas, pueden ser creados de manera similar a las vistas comunes. Por defecto, los layouts son guardados en el directorio `@app/views/layouts`. Para layouts utilizados dentro de un [módulo](structure-modules.md), deberían ser guardados en el directorio `views/layouts` bajo el [[yii\base\Module::basePath|directorio del módulo]]. Puedes personalizar el directorio de layouts por defecto configurando la propiedad [[yii\base\Module::layoutPath]] de la aplicación o módulos.
Dado que los layouts son también vistas, pueden ser creados de manera similar a las vistas comunes. Por defecto, los layouts
son guardados en el directorio `@app/views/layouts`. Para layouts utilizados dentro de un [módulo](structure-modules.md), deberían ser guardados
en el directorio `views/layouts` bajo el [[yii\base\Module::basePath|directorio del módulo]].
Puedes personalizar el directorio de layouts por defecto configurando la propiedad [[yii\base\Module::layoutPath]]
de la aplicación o módulos.
El siguiente ejemplo muestra cómo debe verse un layout. Ten en cuenta que por motivos ilustrativos, hemos simplificado bastante el código del layout. En la práctica, probablemente le agregues más contenido, como tags en el `head`, un menú principal, etc.
El siguiente ejemplo muestra cómo debe verse un layout. Ten en cuenta que por motivos ilustrativos, hemos simplificado
bastante el código del layout. En la práctica, probablemente le agregues más contenido, como tags en el `head`, un menú principal, etc.
```php
<?php
@ -283,29 +347,51 @@ use yii\helpers\Html;
<?php $this->endPage() ?>
```
Como puedes ver, el layout genera los tags HTML comunes a todas las páginas. Dentro de la sección `<body>`,el layout imprime la variable `$content`, que representa el resultado de la renderización del contenido de cada vista y es incrustado dentro del layout cuando se llama al método [[yii\base\Controller::render()]].
Como puedes ver, el layout genera los tags HTML comunes a todas las páginas. Dentro de la sección `<body>`,
el layout imprime la variable `$content`, que representa el resultado de la renderización del contenido de cada vista
y es incrustado dentro del layout cuando se llama al método [[yii\base\Controller::render()]].
La mayoría de layouts deberían llamar a los siguientes métodos (como fue mostrado recién). Estos métodos principalmente disparan eventos acerca del proceso de renderizado así los scripts y tags registrados en otros lugares pueden ser propiamente inyectados en los lugares donde los métodos son llamados.
La mayoría de layouts deberían llamar a los siguientes métodos (como fue mostrado recién). Estos métodos principalmente disparan eventos
acerca del proceso de renderizado así los scripts y tags registrados en otros lugares pueden ser propiamente inyectados
en los lugares donde los métodos son llamados.
- [[yii\base\View::beginPage()|beginPage()]]: Este método debería ser llamado bien al principio del layout. Esto dispara el evento [[yii\base\View::EVENT_BEGIN_PAGE|EVENT_BEGIN_PAGE]], el cual indica el comienzo de la página.
- [[yii\base\View::endPage()|endPage()]]: Este método debería ser llamado al final del layout. Esto dispara el evento [[yii\base\View::EVENT_END_PAGE|EVENT_END_PAGE]], indicando el final de la página.
- [[yii\web\View::head()|head()]]: Este método debería llamarse dentro de la sección `<head>` de una página HTML. Esto genera un espacio vacío que será reemplazado con el código del head HTML registrado (ej. link tags, meta tags) cuando una página finaliza el renderizado.
- [[yii\base\View::beginBody()|beginBody()]]: Este método debería llamarse al principio de la sección `<body>`. Esto dispara el evento [[yii\web\View::EVENT_BEGIN_BODY|EVENT_BEGIN_BODY]] y genera un espacio vacío que será reemplazado con el código HTML registrado (ej. JavaScript) que apunta al principio del body.
- [[yii\base\View::endBody()|endBody()]]: Este método debería llamarse al final de la sección `<body>`. Esto dispara el evento [[yii\web\View::EVENT_END_BODY|EVENT_END_BODY]], que genera un espacio vacío a ser reemplazado por el código HTML registrado (ej. JavaScript) que apunta al final del body.
- [[yii\base\View::beginPage()|beginPage()]]: Este método debería ser llamado bien al principio del layout.
Esto dispara el evento [[yii\base\View::EVENT_BEGIN_PAGE|EVENT_BEGIN_PAGE]], el cual indica el comienzo de la página.
- [[yii\base\View::endPage()|endPage()]]: Este método debería ser llamado al final del layout.
Esto dispara el evento [[yii\base\View::EVENT_END_PAGE|EVENT_END_PAGE]], indicando el final de la página.
- [[yii\web\View::head()|head()]]: Este método debería llamarse dentro de la sección `<head>` de una página HTML.
Esto genera un espacio vacío que será reemplazado con el código del head HTML registrado (ej. link tags, meta tags)
cuando una página finaliza el renderizado.
- [[yii\base\View::beginBody()|beginBody()]]: Este método debería llamarse al principio de la sección `<body>`.
Esto dispara el evento [[yii\web\View::EVENT_BEGIN_BODY|EVENT_BEGIN_BODY]] y genera un espacio vacío que será reemplazado
con el código HTML registrado (ej. JavaScript) que apunta al principio del body.
- [[yii\base\View::endBody()|endBody()]]: Este método debería llamarse al final de la sección `<body>`.
Esto dispara el evento [[yii\web\View::EVENT_END_BODY|EVENT_END_BODY]], que genera un espacio vacío a ser reemplazado
por el código HTML registrado (ej. JavaScript) que apunta al final del body.
### Accediendo a Datos en Layouts <span id="accessing-data-in-layouts"></span>
### Acceder a Datos en Layouts <span id="accessing-data-in-layouts"></span>
Dentro de un layout, tienes acceso a dos variables predefinidas: `$this` y `$content`. La primera se refiere al componente [[yii\base\View|view]], como en cualquier vista, mientras que la última contiene el resultado de la renderización del contenido de la vista que está siendo renderizada all llamar al método [[yii\base\Controller::render()|render()]] en los controladores.
Dentro de un layout, tienes acceso a dos variables predefinidas: `$this` y `$content`. La primera se refiere al componente [[yii\base\View|view]],
como en cualquier vista, mientras que la última contiene el resultado de la renderización del contenido de la vista que está siendo renderizada
al llamar al método [[yii\base\Controller::render()|render()]] en los controladores.
Si quieres acceder a otros datos en los layouts, debes utilizar el modo pull que fue descrito en la sub-sección [Accediendo a Datos en la Vista](#accessing-data-in-views). Si quieres pasar datos desde al contenido de la vista a un layout, puedes utilizar el método descrito en la sub-sección [Compartiendo Datos Entre las Vistas](#sharing-data-among-views).
Si quieres acceder a otros datos en los layouts, debes utilizar el modo pull que fue descrito en la sub-sección [Accediendo a Datos en la Vista](#accessing-data-in-views).
Si quieres pasar datos desde al contenido de la vista a un layout, puedes utilizar el método descrito en la
sub-sección [Compartiendo Datos Entre las Vistas](#sharing-data-among-views).
### Utilizando Layouts <span id="using-layouts"></span>
### Utilizar Layouts <span id="using-layouts"></span>
Como se describe en la sub-sección [Renderizando en Controllers](#rendering-in-controllers), cuando renderizas una vista llamando al método [[yii\base\Controller::render()|render()]] en un controlador, al resultado de dicha renderización le será aplicado un layout. Por defecto, el layout `@app/views/layouts/main.php` será el utilizado.
Como se describe en la sub-sección [Renderizando en Controllers](#rendering-in-controllers), cuando renderizas una vista
llamando al método [[yii\base\Controller::render()|render()]] en un controlador, al resultado de dicha renderización le será aplicado un layout.
Por defecto, el layout `@app/views/layouts/main.php` será el utilizado.
Puedes utilizar un layout diferente configurando la propiedad [[yii\base\Application::layout]] o [[yii\base\Controller::layout]]. El primero se refiere al layout utilizado por todos los controladores, mientras que el último sobrescribe el layout en controladores individuales. Por ejemplo, el siguiente código hace que el controlador `post` utilice `@app/views/layouts/post.php` como layout al renderizar sus vistas. Otros controladores, asumiendo que su propiedad `layout` no fue modificada, utilizarán `@app/views/layouts/main.php` como layout.
Puedes utilizar un layout diferente configurando la propiedad [[yii\base\Application::layout]] o [[yii\base\Controller::layout]]. El primero
se refiere al layout utilizado por todos los controladores, mientras que el último sobrescribe el layout en controladores individuales.
Por ejemplo, el siguiente código hace que el controlador `post` utilice `@app/views/layouts/post.php` como layout al renderizar sus vistas.
Otros controladores, asumiendo que su propiedad `layout` no fue modificada,
utilizarán `@app/views/layouts/main.php` como layout.
```php
namespace app\controllers;
@ -320,20 +406,31 @@ class PostController extends Controller
}
```
Para controladores que pertencen a un módulo, puedes también configurar la propiedad [[yii\base\Module::layout|layout]] y así utilizar un layout en particular para esos controladores.
Para controladores que pertencen a un módulo, puedes también configurar la propiedad [[yii\base\Module::layout|layout]] y así utilizar un layout
en particular para esos controladores.
Dado que la propiedad `layout` puede ser configurada en diferentes niveles (controladores, módulos, aplicación), detrás de escena Yii realiza dos pasos para determinar cuál es el archivo de layout siendo utilizado para un controlador en particular.
Dado que la propiedad `layout` puede ser configurada en diferentes niveles (controladores, módulos, aplicación), detrás de escena
Yii realiza dos pasos para determinar cuál es el archivo de layout siendo utilizado para un controlador en particular.
En el primer paso, determina el valor del layout y el módulo de contexto:
- Si la propiedad [[yii\base\Controller::layout]] no es `null`, la utiliza como valor del layout y el [[yii\base\Controller::module|módulo]] del controlador como el módulo de contexto.
- Si [[yii\base\Controller::layout|layout]] es `null`, busca a través de todos los módulos ancestros del controlador y encuentra el primer módulo cuya propiedad [[yii\base\Module::layout|layout]] no es `null`. Utiliza ese módulo y su valor de [[yii\base\Module::layout|layout]] como módulo de contexto y como layout seleccionado. Si tal módulo no puede ser encontrado, significa que no se aplicará ningún layout.
- Si la propiedad [[yii\base\Controller::layout]] no es `null`, la utiliza como valor del layout y el [[yii\base\Controller::module|módulo]]
del controlador como el módulo de contexto.
- Si [[yii\base\Controller::layout|layout]] es `null`, busca a través de todos los módulos ancestros del controlador
y encuentra el primer módulo cuya propiedad [[yii\base\Module::layout|layout]] no es `null`.
Utiliza ese módulo y su valor de [[yii\base\Module::layout|layout]] como módulo de contexto y como layout seleccionado.
Si tal módulo no puede ser encontrado, significa que no se aplicará ningún layout.
En el segundo paso, se determina el archivo de layout actual de acuerdo al valor de layout y el módulo de contexto determinado en el primer paso. El valor de layout puede ser:
En el segundo paso, se determina el archivo de layout actual de acuerdo al valor de layout y el módulo de contexto determinado en el primer paso.
El valor de layout puede ser:
- un alias de ruta (ej. `@app/views/layouts/main`).
- una ruta absoluta (ej. `/main`): el valor del layout comienza con una barra. El archivo de layout actual será buscado bajo el [[yii\base\Application::layoutPath|layout path]] de la aplicación, que es por defecto `@app/views/layouts`.
- una ruta relativa (ej. `main`): El archivo de layout actual será buscado bajo el [[yii\base\Module::layoutPath|layout path]] del módulo de contexto, que es por defecto el directorio `views/layouts` bajo el [[yii\base\Module::basePath|directorio del módulo]].
- una ruta absoluta (ej. `/main`): el valor del layout comienza con una barra. El archivo de layout actual será buscado
bajo el [[yii\base\Application::layoutPath|layout path]] de la aplicación,
que es por defecto `@app/views/layouts`.
- una ruta relativa (ej. `main`): El archivo de layout actual será buscado bajo el [[yii\base\Module::layoutPath|layout path]]
del módulo de contexto, que es por defecto el directorio `views/layouts`
bajo el [[yii\base\Module::basePath|directorio del módulo]].
- el valor booleano `false`: no se aplicará ningún layout.
Si el valor de layout no contiene una extensión de tipo de archivo, utilizará por defecto `.php`.
@ -341,7 +438,10 @@ Si el valor de layout no contiene una extensión de tipo de archivo, utilizará
### Layouts Anidados <span id="nested-layouts"></span>
A veces podrías querer anidar un layout dentro de otro. Por ejemplo, en diferentes secciones de un sitio Web, podrías querer utilizar layouts diferentes, mientras que todos esos layouts comparten el mismo layout básico que genera la estructura general de la página en HTML5. Esto es posible llamando a los métodos [[yii\base\View::beginContent()|beginContent()]] y [[yii\base\View::endContent()|endContent()]] en los layouts hijos como se muestra a continuación:
A veces podrías querer anidar un layout dentro de otro. Por ejemplo, en diferentes secciones de un sitio Web,
podrías querer utilizar layouts diferentes, mientras que todos esos layouts comparten el mismo layout básico que genera
la estructura general de la página en HTML5. Esto es posible llamando a los métodos
[[yii\base\View::beginContent()|beginContent()]] y [[yii\base\View::endContent()|endContent()]] en los layouts hijos como se muestra a continuación:
```php
<?php $this->beginContent('@app/views/layouts/base.php'); ?>
@ -351,14 +451,80 @@ A veces podrías querer anidar un layout dentro de otro. Por ejemplo, en diferen
<?php $this->endContent(); ?>
```
Como se acaba de mostrar, el contenido del layout hijo debe ser encerrado dentro de [[yii\base\View::beginContent()|beginContent()]] y [[yii\base\View::endContent()|endContent()]]. El parámetro pasado a [[yii\base\View::beginContent()|beginContent()]] especifica cuál es el módulo padre. Este puede ser tanto un archivo layout como un alias.
Como se acaba de mostrar, el contenido del layout hijo debe ser encerrado dentro de [[yii\base\View::beginContent()|beginContent()]]
y [[yii\base\View::endContent()|endContent()]]. El parámetro pasado a [[yii\base\View::beginContent()|beginContent()]]
especifica cuál es el módulo padre. Este puede ser tanto un archivo layout como un alias.
Utilizando la forma recién mencionada, puedes anidar layouts en más de un nivel.
## Utilizando Componentes de Vista <span id="using-view-components"></span>
### Utilizar Blocks <span id="using-blocks"></span>
Los bloques te permiten especificar el contenido de la vista en un lugar y mostrarlo en otro. Estos son a menudo utilizados junto a
los layouts. Por ejemplo, puedes definir un bloque un una vista de contenido y mostrarla en el layout.
Para definir un bloque, llamas a [[yii\base\View::beginBlock()|beginBlock()]] y [[yii\base\View::endBlock()|endBlock()]].
El bloque puede ser accedido vía `$view->blocks[$blockID]`, donde `$blockID` se refiere al ID único que le asignas
al bloque cuando lo defines.
El siguiente ejemplo muestra cómo utilizar bloques para personalizar partes especificas del layout in una vista.
Los [[yii\base\View|componentes de vista]] proveen características relacionadas a las vistas. Aunque puedes obtener componentes de vista creando instancias individuales de [[yii\base\View]] o sus clases hijas, en la mayoría de los casos utilizarías el componente `view` del a aplicación. Puedes configurar este componente en la [configuración de la aplicación](structure-applications.md#application-configurations) como a continuación:
Primero, en una vista, define uno o varios bloques:
```php
...
<?php $this->beginBlock('block1'); ?>
...contenido de block1...
<?php $this->endBlock(); ?>
...
<?php $this->beginBlock('block3'); ?>
...contenido de block3...
<?php $this->endBlock(); ?>
```
Entonces, en la vista del layout, renderiza los bloques si están disponibles, o muestra un contenido por defecto si el bloque
no está definido.
```php
...
<?php if (isset($this->blocks['block1'])): ?>
<?= $this->blocks['block1'] ?>
<?php else: ?>
... contenido por defecto de block1 ...
<?php endif; ?>
...
<?php if (isset($this->blocks['block2'])): ?>
<?= $this->blocks['block2'] ?>
<?php else: ?>
... contenido por defecto de block2 ...
<?php endif; ?>
...
<?php if (isset($this->blocks['block3'])): ?>
<?= $this->blocks['block3'] ?>
<?php else: ?>
... contenido por defecto de block3 ...
<?php endif; ?>
...
```
## Utilizar Componentes de Vista <span id="using-view-components"></span>
Los [[yii\base\View|componentes de vista]] proveen características relacionadas a las vistas. Aunque puedes obtener componentes de vista
creando instancias individuales de [[yii\base\View]] o sus clases hijas, en la mayoría de los casos utilizarías el componente `view` del a aplicación.
Puedes configurar este componente en la [configuración de la aplicación](structure-applications.md#application-configurations)
como a continuación:
```php
[
@ -386,13 +552,15 @@ Puedes también utilizar frecuentemente el siguiente menor pero útil grupo de c
### Definiendo Títulos de Página <span id="setting-page-titles"></span>
Toda página Web debería tener un título. Normalmente el tag de título es generado en [layout](#layouts). De todos modos, en la práctica el título es determinado en el contenido de las vistas más que en layouts. Para resolver este problema, [[yii\web\View]] provee la propiedad [[yii\web\View::title|title]] para que puedas pasar información del título desde el contenido de la vista a los layouts.
Toda página Web debería tener un título. Normalmente el tag de título es generado en [layout](#layouts). De todos modos, en la práctica
el título es determinado en el contenido de las vistas más que en layouts. Para resolver este problema, [[yii\web\View]] provee
la propiedad [[yii\web\View::title|title]] para que puedas pasar información del título desde el contenido de la vista a los layouts.
Para utilizar esta característica, en cada contenido de la vista, puedes definir el título de la siguiente manera:
```php
<?php
$this->title = 'Mi título de página';
$this->title = 'Título de mi página';
?>
```
@ -403,11 +571,13 @@ Entonces en el layout, asegúrate de tener el siguiente código en la sección `
```
### Registrando Meta Tags <span id="registering-meta-tags"></span>
### Registrar Meta Tags <span id="registering-meta-tags"></span>
Las páginas Web usualmente necesitan generar varios meta tags necesarios por diferentes grupos (ej. Facebook, motores de búsqueda, etc). Cómo los títulos de página, los meta tags aparecen en la sección `<head>` y son usualmente generado en los layouts.
Las páginas Web usualmente necesitan generar varios meta tags necesarios para diferentes grupos. Cómo los títulos de página, los meta tags
aparecen en la sección `<head>` y son usualmente generado en los layouts.
Si quieres especificar cuáles meta tags generar en las vistas, puedes llamar a [[yii\web\View::registerMetaTag()]] dentro de una de ellas, como se muestra a continuación:
Si quieres especificar cuáles meta tags generar en las vistas, puedes llamar a [[yii\web\View::registerMetaTag()]]
dentro de una de ellas, como se muestra a continuación:
```php
<?php
@ -415,25 +585,31 @@ $this->registerMetaTag(['name' => 'keywords', 'content' => 'yii, framework, php'
?>
```
El código anterior registrará el meta tag "keywords" a través del componente view. El meta tag registrado no se renderiza hasta que finaliza el renderizado del layout. Para entonces, el siguiente código HTML será insertado en el lugar donde llamas a [[yii\web\View::head()]] en el layout, generando el siguiente HTML:
El código anterior registrará el meta tag "keywords" a través del componente view. El meta tag registrado
no se renderiza hasta que finaliza el renderizado del layout. Para entonces, el siguiente código HTML será insertado
en el lugar donde llamas a [[yii\web\View::head()]] en el layout, generando el siguiente HTML:
```php
<meta name="keywords" content="yii, framework, php">
```
Ten en cuenta que si llamas a [[yii\web\View::registerMetaTag()]] varias veces, esto registrará varios meta tags, sin tener en cuenta si los meta tags son los mismo o no.
Ten en cuenta que si llamas a [[yii\web\View::registerMetaTag()]] varias veces, esto registrará varios meta tags,
sin tener en cuenta si los meta tags son los mismo o no.
Para asegurarte de que sólo haya una instancia de cierto tipo de meta tag, puedes especificar una clave al llamar al método. Por ejemplo, el siguiente código registra dos meta tags "description", aunque sólo el segundo será renderizado.
Para asegurarte de que sólo haya una instancia de cierto tipo de meta tag, puedes especificar una clave al llamar al método.
Por ejemplo, el siguiente código registra dos meta tags "description", aunque sólo el segundo será renderizado.
```html
```php
$this->registerMetaTag(['name' => 'description', 'content' => 'Este es mi sitio Web cool hecho con Yii!'], 'description');
$this->registerMetaTag(['name' => 'description', 'content' => 'Este sitio Web es sobre mapaches graciosos.'], 'description');
```
### Registrando Link Tags <span id="registering-link-tags"></span>
### Registrar Link Tags <span id="registering-link-tags"></span>
Tal como los [meta tags](#adding-meta-tags), los link tags son útiles en muchos casos, como personalizar el ícono (favicon) del sitio, apuntar a una fuente de RSS o delegar OpenID a otro servidor. Puedes trabajar con link tags, al igual que con meta tags, utilizando [[yii\web\View::registerLinkTag()]]. Por ejemplo, en el contenido de una vista, puedes registrar un link tag como se muestra a continuación:
Tal como los [meta tags](#adding-meta-tags), los link tags son útiles en muchos casos, como personalizar el ícono (favicon) del sitio,
apuntar a una fuente de RSS o delegar OpenID a otro servidor. Puedes trabajar con link tags, al igual que con meta tags,
utilizando [[yii\web\View::registerLinkTag()]]. Por ejemplo, en el contenido de una vista, puedes registrar un link tag como se muestra a continuación:
```php
$this->registerLinkTag([
@ -450,16 +626,20 @@ El resultado del código es el siguiente:
<link title="Noticias en Vivo de Yii" rel="alternate" type="application/rss+xml" href="http://www.yiiframework.com/rss.xml/">
```
Al igual que con [[yii\web\View::registerMetaTag()|registerMetaTags()]], puedes especificar una clave al llamar a [[yii\web\View::registerLinkTag()|registerLinkTag()]] para evitar registrar link tags repetidos.
Al igual que con [[yii\web\View::registerMetaTag()|registerMetaTags()]], puedes especificar una clave al llamar
a [[yii\web\View::registerLinkTag()|registerLinkTag()]] para evitar registrar link tags repetidos.
## Eventos de Vistas <span id="view-events"></span>
Los [[yii\base\View|componentes de vistas]] disparan varios eventos durante el proceso de renderizado de la vista. Puedes responder a estos eventos para inyectar contenido a la vista o procesar el resultado de la renderización antes de que sea enviada al usuario final.
Los [[yii\base\View|componentes de vistas]] disparan varios eventos durante el proceso de renderizado de la vista. Puedes responder
a estos eventos para inyectar contenido a la vista o procesar el resultado de la renderización antes de que sea enviada al usuario final.
- [[yii\base\View::EVENT_BEFORE_RENDER|EVENT_BEFORE_RENDER]]: disparado al principio del renderizado de un archivo en un controlador. Los manejadores de este evento pueden definir [[yii\base\ViewEvent::isValid]] como `false` para cancelar el proceso de renderizado.
- [[yii\base\View::EVENT_AFTER_RENDER|EVENT_AFTER_RENDER]]: disparado por la llamada a [[yii\base\View::beginPage()]] en layouts.
Los manejadores de este evento pueden obtener el resultado de la renderización a través de [[yii\base\ViewEvent::output]] y entonces modificar esta propiedad para así cambiar el mismo.
- [[yii\base\View::EVENT_BEFORE_RENDER|EVENT_BEFORE_RENDER]]: disparado al principio del renderizado de un archivo
en un controlador. Los manejadores de este evento pueden definir [[yii\base\ViewEvent::isValid]] como `false` para cancelar el proceso de renderizado.
- [[yii\base\View::EVENT_AFTER_RENDER|EVENT_AFTER_RENDER]]: disparado luego de renderizar un archivo con la llamada de [[yii\base\View::afterRender()]].
Los manejadores de este evento pueden obtener el resultado del renderizado a través de [[yii\base\ViewEvent::output]] y modificar
esta propiedad para cambiar dicho resultado.
- [[yii\base\View::EVENT_BEGIN_PAGE|EVENT_BEGIN_PAGE]]: disparado por la llamada a [[yii\base\View::beginPage()]] en layouts.
- [[yii\base\View::EVENT_END_PAGE|EVENT_END_PAGE]]: disparado por la llamada a [[yii\base\View::endPage()]] en layouts.
- [[yii\web\View::EVENT_BEGIN_BODY|EVENT_BEGIN_BODY]]: disparado por la llamada a [[yii\web\View::beginBody()]] en layouts.
@ -474,9 +654,10 @@ Por ejemplo, el siguiente código inyecta la fecha actual al final del body de l
```
## Renderizando Páginas Estáticas <span id="rendering-static-pages"></span>
## Renderizar Páginas Estáticas <span id="rendering-static-pages"></span>
Con páginas estáticas nos referimos a esas páginas cuyo contenido es mayormente estático y sin necesidad de acceso a datos dinámicos enviados desde los controladores.
Con páginas estáticas nos referimos a esas páginas cuyo contenido es mayormente estático y sin necesidad de acceso
a datos dinámicos enviados desde los controladores.
Puedes generar páginas estáticas utilizando un código como el que sigue dentro de un controlador:
@ -487,7 +668,9 @@ public function actionAbout()
}
```
Si un sitio Web contiene muchas páginas estáticas, resultaría tedioso repetir el mismo código en muchos lados. Para resolver este problema, puedes introducir una [acción independiente](structure-controllers.md#standalone-actions) llamada [[yii\web\ViewAction]] en el controlador. Por ejemplo,
Si un sitio Web contiene muchas páginas estáticas, resultaría tedioso repetir el mismo código en muchos lados.
Para resolver este problema, puedes introducir una [acción independiente](structure-controllers.md#standalone-actions)
llamada [[yii\web\ViewAction]] en el controlador. Por ejemplo,
```php
namespace app\controllers;
@ -507,13 +690,16 @@ class SiteController extends Controller
}
```
Ahora, si creamos una vista llamada `about` bajo el directorio `@app/views/site/pages`, serás capáz de mostrarla en la siguiente URL:
Ahora, si creamos una vista llamada `about` bajo el directorio `@app/views/site/pages`, serás capáz de mostrarla
en la siguiente URL:
```
http://localhost/index.php?r=site/page&view=about
http://localhost/index.php?r=site%2Fpage&view=about
```
El parámetro `GET` `view` le comunica a [[yii\web\ViewAction]] cuál es la vista solicitada. La acción entonces buscará esta vista dentro de `@app/views/site/pages`. Puedes configurar la propiedad [[yii\web\ViewAction::viewPrefix]] para cambiar el directorio en el que se buscarán dichas páginas.
El parámetro `GET` `view` le comunica a [[yii\web\ViewAction]] cuál es la vista solicitada. La acción entonces buscará
esta vista dentro de `@app/views/site/pages`. Puedes configurar la propiedad [[yii\web\ViewAction::viewPrefix]]
para cambiar el directorio en el que se buscarán dichas páginas.
## Buenas Prácticas <span id="best-practices"></span>
@ -523,12 +709,15 @@ Las vistas son responsables de la presentación de modelos en el formato que el
* deberían contener principalmente sólo código de presentación, como HTML, y PHP simple para recorrer, dar formato y renderizar datos.
* no deberían contener código que realiza consultas a la base de datos. Ese tipo de código debe ir en los modelos.
* deberían evitar el acceso directo a datos del `request`, como `$_GET` y/o `$_POST`. Esto es una responsabilidad de los controladores.
Si se necesitan datos del `request`, deben ser inyectados a la vista desde el controlador.
Si se necesitan datos del `request`, deben ser inyectados a la vista desde el controlador.
* pueden leer propiedades del modelo, pero no debería modificarlas.
Para hacer las vistas más manejables, evita crear vistas que son demasiado complejas o que contengan código redundante. Puedes utilizar estas técnicas para alcanzar dicha meta:
Para hacer las vistas más manejables, evita crear vistas que son demasiado complejas o que contengan código redundante.
Puedes utilizar estas técnicas para alcanzar dicha meta:
* utiliza [layouts](#layouts) para representar secciones comunes (ej. encabezado y footer de la página).
* divide una vista compleja en varias más simples. Las vistas pequeñas pueden ser renderizadas y unidas una mayor utilizando los métodos de renderización antes descritos.
* divide una vista compleja en varias más simples. Las vistas pequeñas pueden ser renderizadas y unidas una mayor
utilizando los métodos de renderización antes descritos.
* crea y utiliza [widgets](structure-widgets.md) como bloques de construcción de la vista.
* crea y utilizar helpers para transformar y dar formato a los datos en la vista.

49
docs/guide-es/test-environment-setup.md

@ -0,0 +1,49 @@
Preparación del entorno de test
===============================
> Note: Esta sección se encuentra en desarrollo.
Yii 2 ha mantenido integración oficial con el framework de testing [`Codeception`](https://github.com/Codeception/Codeception),
que te permite crear los siguientes tipos de tests:
- [Test de unidad](test-unit.md) - verifica que una unidad simple de código funciona como se espera;
- [Test funcional](test-functional.md) - verifica escenarios desde la perspectiva de un usuario a través de la emulación de un navegador;
- [Test de aceptación](test-acceptance.md) - verifica escenarios desde la perspectiva de un usuario en un navegador.
Yii provee grupos de pruebas listos para utilizar en ambos
[`yii2-basic`](https://github.com/yiisoft/yii2-app-basic) y
[`yii2-advanced`](https://github.com/yiisoft/yii2-app-advanced) templates de proyectos.
Para poder ejecutar estos tests es necesario instalar [Codeception](https://github.com/Codeception/Codeception).
Puedes instalarlo tanto localmente - únicamente para un proyecto en particular, o globalmente - para tu máquina de desarrollo.
Para la instalación local utiliza los siguientes comandos:
```
composer require "codeception/codeception=2.1.*"
composer require "codeception/specify=*"
composer require "codeception/verify=*"
```
Para la instalación global necesitarás la directiva `global`:
```
composer global require "codeception/codeception=2.1.*"
composer global require "codeception/specify=*"
composer global require "codeception/verify=*"
```
En caso de que nunca hayas utilizado Composer para paquetes globales, ejecuta `composer global status`. Esto debería mostrar la salida:
```
Changed current directory to <directory>
```
Entonces agrega `<directory>/vendor/bin` a tu variable de entorno `PATH`. Ahora podrás utilizar el `codecept` en la línea
de comandos a nivel global.
> Note: la instalación global te permite usar Codeception para todos los proyectos en los que trabajes en tu máquina de desarrollo y
te permite ejecutar el comando `codecept` globalmente sin especificar su ruta. De todos modos, ese acercamiento podría ser inapropiado,
por ejemplo, si 2 proyectos diferentes requieren diferentes versiones de Codeception instaladas.
Por simplicidad, todos los comandos relacionados a tests en esta guía están escritos asumiendo que Codeception
ha sido instalado en forma global.

379
docs/guide-es/test-fixtures.md

@ -0,0 +1,379 @@
Fixtures
========
Los fixtures son una parte importante de los tests. Su propósito principal es el de preparar el entorno en una estado fijado/conocido
de manera que los tests sean repetibles y corran de la manera esperada. Yii provee un framework de fixtures que te permite
dichos fixtures de manera precisa y usarlo de forma simple.
Un concepto clave en el framework de fixtures de Yii es el llamado *objeto fixture*. Un objeto fixture representa
un aspecto particular de un entorno de pruebas y es una instancia de [[yii\test\Fixture]] o heredada de esta. Por ejemplo,
puedes utilizar `UserFixture` para asegurarte de que la tabla de usuarios de la BD contiene un grupo de datos fijos. Entonces cargas uno o varios
objetos fixture antes de correr un test y lo descargas cuando el test ha concluido.
Un fixture puede depender de otros fixtures, especificándolo en su propiedad [[yii\test\Fixture::depends]].
Cuando un fixture está siendo cargado, los fixtures de los que depende serán cargados automáticamente ANTES que él;
y cuando el fixture está siendo descargado, los fixtures dependientes serán descargados DESPUÉS de él.
Definir un Fixture
------------------
Para definir un fixture, crea una nueva clase que extienda de [[yii\test\Fixture]] o [[yii\test\ActiveFixture]].
El primero es más adecuado para fixtures de propósito general, mientras que el último tiene características mejoradas específicamente
diseñadas para trabajar con base de datos y ActiveRecord.
El siguiente código define un fixture acerca del ActiveRecord `User` y su correspondiente tabla user.
```php
<?php
namespace app\tests\fixtures;
use yii\test\ActiveFixture;
class UserFixture extends ActiveFixture
{
public $modelClass = 'app\models\User';
}
```
> Tip: Cada `ActiveFixture` se encarga de preparar la tabla de la DB para los tests. Puedes especificar la tabla
> definiendo tanto la propiedad [[yii\test\ActiveFixture::tableName]] o la propiedad [[yii\test\ActiveFixture::modelClass]].
> Haciéndolo como el último, el nombre de la tabla será tomado de la clase `ActiveRecord` especificada en `modelClass`.
> Note: [[yii\test\ActiveFixture]] es sólo adecualdo para bases de datos SQL. Para bases de datos NoSQL, Yii provee
> las siguientes clases `ActiveFixture`:
>
> - Mongo DB: [[yii\mongodb\ActiveFixture]]
> - Elasticsearch: [[yii\elasticsearch\ActiveFixture]] (desde la versión 2.0.2)
Los datos para un fixture `ActiveFixture` son usualmente provistos en un archivo ubicado en `FixturePath/data/TableName.php`,
donde `FixturePath` corresponde al directorio conteniendo el archivo de clase del fixture, y `TableName`
es el nombre de la tabla asociada al fixture. En el ejemplo anterior, el archivo debería ser
`@app/tests/fixtures/data/user.php`. El archivo de datos debe devolver un array de registros
a ser insertados en la tabla user. Por ejemplo,
```php
<?php
return [
'user1' => [
'username' => 'lmayert',
'email' => 'strosin.vernice@jerde.com',
'auth_key' => 'K3nF70it7tzNsHddEiq0BZ0i-OU8S3xV',
'password' => '$2y$13$WSyE5hHsG1rWN2jV8LRHzubilrCLI5Ev/iK0r3jRuwQEs2ldRu.a2',
],
'user2' => [
'username' => 'napoleon69',
'email' => 'aileen.barton@heaneyschumm.com',
'auth_key' => 'dZlXsVnIDgIzFgX4EduAqkEPuphhOh9q',
'password' => '$2y$13$kkgpvJ8lnjKo8RuoR30ay.RjDf15bMcHIF7Vz1zz/6viYG5xJExU6',
],
];
```
Puedes dar un alias al registro tal que más tarde en tu test, puedas referirte a ese registra a través de dicho alias. En el ejemplo anterior,
los dos registros tienen como alias `user1` y `user2`, respectivamente.
Además, no necesitas especificar los datos de columnas auto-incrementales. Yii automáticamente llenará esos valores
dentro de los registros cuando el fixture está siendo cargado.
> Tip: Puedes personalizar la ubicación del archivo de datos definiendo la propiedad [[yii\test\ActiveFixture::dataFile]].
> Puedes también sobrescribir [[yii\test\ActiveFixture::getData()]] para obtener los datos.
Como se describió anteriormente, un fixture puede depender de otros fixtures. Por ejemplo, un `UserProfileFixture` puede necesitar depender de `UserFixture`
porque la table de perfiles de usuarios contiene una clave foránea a la tabla user.
La dependencia es especificada vía la propiedad [[yii\test\Fixture::depends]], como a continuación,
```php
namespace app\tests\fixtures;
use yii\test\ActiveFixture;
class UserProfileFixture extends ActiveFixture
{
public $modelClass = 'app\models\UserProfile';
public $depends = ['app\tests\fixtures\UserFixture'];
}
```
La dependencia también asegura que los fixtures son cargados y descargados en un orden bien definido. En el ejemplo `UserFixture`
será siempre cargado antes de `UserProfileFixture` para asegurar que todas las referencias de las claves foráneas existan y será siempre descargado después de `UserProfileFixture`
por la misma razón.
Arriba te mostramos cómo definir un fixture de BD. Para definir un fixture no relacionado a BD
(por ej. un fixture acerca de archivos y directorios), puedes extender de la clase base más general
[[yii\test\Fixture]] y sobrescribir los métodos [[yii\test\Fixture::load()|load()]] y [[yii\test\Fixture::unload()|unload()]].
Utilizar Fixtures
-----------------
Si estás utilizando [Codeception](http://codeception.com/) para hacer tests de tu código, deberías considerar el utilizar
la extensión `yii2-codeception`, que tiene soporte incorporado para la carga y acceso a fixtures.
En caso de que utilices otros frameworks de testing, puedes usar [[yii\test\FixtureTrait]] en tus casos de tests
para alcanzar el mismo objetivo.
A continuación describiremos cómo escribir una clase de test de unidad `UserProfile` utilizando `yii2-codeception`.
En tu clase de test de unidad que extiende de [[yii\codeception\DbTestCase]] o [[yii\codeception\TestCase]],
indica cuáles fixtures quieres utilizar en el método [[yii\test\FixtureTrait::fixtures()|fixtures()]]. Por ejemplo,
```php
namespace app\tests\unit\models;
use yii\codeception\DbTestCase;
use app\tests\fixtures\UserProfileFixture;
class UserProfileTest extends DbTestCase
{
public function fixtures()
{
return [
'profiles' => UserProfileFixture::className(),
];
}
// ...métodos de test...
}
```
Los fixtures listados en el método `fixtures()` serán automáticamente cargados antes de correr cada método de test
en el caso de test y descargado al finalizar cada uno. También, como describimos antes, cuando un fixture está
siendo cargado, todos sus fixtures dependientes serán cargados primero. En el ejemplo de arriba, debido a que
`UserProfileFixture` depende de `UserFixture`, cuando ejecutas cualquier método de test en la clase,
dos fixtures serán cargados secuencialmente: `UserFixture` y `UserProfileFixture`.
Al especificar fixtures en `fixtures()`, puedes utilizar tanto un nombre de clase o un array de configuración para referirte a
un fixture. El array de configuración te permitirá personalizar las propiedades del fixture cuando este es cargado.
Puedes también asignarles alias a los fixtures. En el ejemplo anterior, el `UserProfileFixture` tiene como alias `profiles`.
En los métodos de test, puedes acceder a un objeto fixture utilizando su alias. Por ejemplo, `$this->profiles`
devolverá el objeto `UserProfileFixture`.
Dado que `UserProfileFixture` extiende de `ActiveFixture`, puedes por lo tanto usar la siguiente sintáxis para acceder
a los datos provistos por el fixture:
```php
// devuelve el registro del fixture cuyo alias es 'user1'
$row = $this->profiles['user1'];
// devuelve el modelo UserProfile correspondiente al registro cuyo alias es 'user1'
$profile = $this->profiles('user1');
// recorre cada registro en el fixture
foreach ($this->profiles as $row) ...
```
> Info: `$this->profiles` es todavía del tipo `UserProfileFixture`. Las características de acceso mostradas arriba son implementadas
> a través de métodos mágicos de PHP.
Definir y Utilizar Fixtures Globales
------------------------------------
Los fixtures descritos arriba son principalmente utilizados para casos de tests individuales. En la mayoría de los casos, puedes necesitar algunos
fixtures globales que sean aplicados a TODOS o muchos casos de test. Un ejemplo sería [[yii\test\InitDbFixture]], que hace
dos cosas:
* Realiza alguna tarea de inicialización común al ejectutar un script ubicado en `@app/tests/fixtures/initdb.php`;
* Deshabilita la comprobación de integridad antes de cargar otros fixtures de BD, y la rehabilita después de que todos los fixtures son descargados.
Utilizar fixtures globales es similar a utilizar los no-globales. La única diferencia es que declaras estos fixtures
en [[yii\codeception\TestCase::globalFixtures()]] en vez de en `fixtures()`. Cuando un caso de test carga fixtures,
primero carga los globales y luego los no-globales.
Por defecto, [[yii\codeception\DbTestCase]] ya declara `InitDbFixture` en su método `globalFixtures()`.
Esto significa que sólo necesitas trabajar con `@app/tests/fixtures/initdb.php` si quieres realizar algún trabajo de inicialización
antes de cada test. Sino puedes simplemente enfocarte en desarrollar cada caso de test individual y sus fixtures correspondientes.
Organizar Clases de Fixtures y Archivos de Datos
------------------------------------------------
Por defecto, las clases de fixtures busca los archivos de datos correspondientes dentro de la carpeta `data`, que es una subcarpeta
de la carpeta conteniendo los archivos de clases de fixtures. Puedes seguir esta convención al trabajar en proyectos simples.
Para proyectos más grandes, es probable que a menudo necesites intercambiar entre diferentes archivos de datos para la misma clase de fixture
en diferentes tests. Recomendamos que organices los archivos de datos en forma jerárquica similar
a tus espacios de nombre de clases. Por ejemplo,
```
# bajo la carpeta tests\unit\fixtures
data\
components\
fixture_data_file1.php
fixture_data_file2.php
...
fixture_data_fileN.php
models\
fixture_data_file1.php
fixture_data_file2.php
...
fixture_data_fileN.php
# y así sucesivamente
```
De esta manera evitarás la colisión de archivos de datos de fixtures entre tests y podrás utlilizarlos como necesites.
> Note: En el ejemplo de arriba los archivos de fixtures son nombrados así sólo como ejemplo. En la vida real deberías nombrarlos
> de acuerdo a qué clase de fixture extienden tus clases de fixtures. Por ejemplo, si estás extendiendo
> de [[yii\test\ActiveFixture]] para fixtures de BD, deberías utilizar nombres de tabla de la BD como nombres de los archivos de fixtures;
> Si estás extendiendo de [[yii\mongodb\ActiveFixture]] para fixtures de MongoDB, deberías utilizar nombres de colecciones para los nombres de archivo.
Se puede utilizar una jerarquía similar para organizar archivos de clases de fixtures. En vez de utilizar `data` como directorio raíz, podrías
querer utilizar `fixtures` como directorio raíz para evitar conflictos con los archivos de datos.
Resumen
-------
> Note: Esta sección se encuentra en desarrollo.
Arriba, definimos cómo definir y utilizar fixtures. Abajo resumiremos el típico flujo de trabajo
de correr tests de unidad relacionados a BD:
1. Usa la herramienta `yii migrate` para actualizar tu base de datos de prueba a la última versión;
2. Corre el caso de test:
- Carga los fixtures: limpia las tablas de la BD relevantes y cargala con los datos de los fixtures;
- Realiza el test en sí;
- Descarga los fixtures.
3. Repite el Paso 2 hasta que todos los tests terminen.
**Lo siguiente, a ser limpiado**
Administrar Fixtures
====================
> Note: Esta sección está en desarrollo.
>
> todo: este tutorial podría ser unificado con la parte de arriba en test-fixtures.md
Los fixtures son una parte importante del testing. Su principal propósito es el de poblarte con datos necesarios para el test
de diferentes casos. Con estos datos. utilizar tests se vuelve más eficiente y útil.
Yii soporta fixtures a través de la herramienta de línea de comandos `yii fixture`. Esta herramienta soporta:
* Cargar fixtures a diferentes almacenamientos: RDBMS, NoSQL, etc;
* Descargar fixtures de diferentes maneras (usualmente limpiando el almacenamiento);
* Auto-generar fixtures y poblarlos con datos al azar.
Formato de Fixtures
-------------------
Los fixtures son objetos con diferentes métodos y configuraciones, inspecciónalos en la [documentación oficial](https://github.com/yiisoft/yii2/blob/master/docs/guide-es/test-fixtures.md).
Asumamos que tenemos datos de fixtures a cargar:
```
#archivo users.php bajo la ruta de los fixtures, por defecto @tests\unit\fixtures\data
return [
[
'name' => 'Chase',
'login' => 'lmayert',
'email' => 'strosin.vernice@jerde.com',
'auth_key' => 'K3nF70it7tzNsHddEiq0BZ0i-OU8S3xV',
'password' => '$2y$13$WSyE5hHsG1rWN2jV8LRHzubilrCLI5Ev/iK0r3jRuwQEs2ldRu.a2',
],
[
'name' => 'Celestine',
'login' => 'napoleon69',
'email' => 'aileen.barton@heaneyschumm.com',
'auth_key' => 'dZlXsVnIDgIzFgX4EduAqkEPuphhOh9q',
'password' => '$2y$13$kkgpvJ8lnjKo8RuoR30ay.RjDf15bMcHIF7Vz1zz/6viYG5xJExU6',
],
];
```
Si estamos utilizando un fixture que carga datos en la base de datos, entonces esos registros serán insertados en la tabla `users`. Si estamos utilizando fixtures no sql, por ejemplo de `mongodb`,
entonces estos datos serán aplicados a la colección mongodb `users`. Para aprender cómo implementar varias estrategias de carga y más, visita la [documentación oficial](https://github.com/yiisoft/yii2/blob/master/docs/guide-es/test-fixtures.md).
El fixture de ejemplo de arriba fue autogenerado por la extensión `yii2-faker`, lee más acerca de esto en su [sección](#auto-generating-fixtures).
Los nombres de clase de fixtures no deberían ser en plural.
Cargar fixtures
----------------
Las clases de fixture deberían tener el prefijo `Fixture`. Por defecto los fixtures serán buscados bajo el espacio de nombre `tests\unit\fixtures`, puedes
modificar este comportamiento con opciones de comando o configuración. Puedes excluir algunos fixtures para carga o descarga especificando `-` antes de su nombre, por ejemplo `-User`.
Para cargar un fixture, ejecuta el siguiente comando:
```
yii fixture/load <fixture_name>
```
El parámetro requerido `fixture_name` especifica un nombre de fixture cuyos datos serán cargados. Puedes cargar varios fixtures de una sola vez.
Abajo se muestran formatos correctos de este comando:
```
// carga el fixture `User`
yii fixture/load User
// lo mismo que arriba, dado que la acción por defecto del comando "fixture" es "load"
yii fixture User
// carga varios fixtures
yii fixture User UserProfile
// carga todos los fixtures
yii fixture/load "*"
// lo mismo que arriba
yii fixture "*"
// carga todos los fixtures excepto uno
yii fixture "*" -DoNotLoadThisOne
// carga fixtures, pero los busca en diferente espacio de nombre. El espacio de nombre por defecto es: tests\unit\fixtures.
yii fixture User --namespace='alias\my\custom\namespace'
// carga el fixture global `some\name\space\CustomFixture` antes de que otros fixtures sean cargados.
// Por defecto está opción se define como `InitDbFixture` para habilitar/deshabilitar la comprobación de integridad. Puedes especificar varios
// fixtures globales separados por coma.
yii fixture User --globalFixtures='some\name\space\Custom'
```
Descargar fixtures
------------------
Para descargar un fixture, ejecuta el siguiente comando:
```
// descarga el fixture Users, por defecto limpiará el almacenamiento del fixture (por ejemplo la tabla "users", o la colección "users" si es un fixture mongodb).
yii fixture/unload User
// descarga varios fixtures
yii fixture/unload User,UserProfile
// descarga todos los fixtures
yii fixture/unload "*"
// descarga todos los fixtures excepto uno
yii fixture/unload "*" -DoNotUnloadThisOne
```
Opciones de comando similares como: `namespace`, `globalFixtures` también pueden ser aplicadas a este comando.
Configurar el Comando Globalmente
---------------------------------
Mientras que las opciones de línea de comandos nos permiten configurar el comando de migración
en el momento, a veces queremos configurar el comando de una vez y para siempre. Por ejemplo puedes configurar
diferentes rutas de migración como a continuación:
```
'controllerMap' => [
'fixture' => [
'class' => 'yii\console\controllers\FixtureController',
'namespace' => 'myalias\some\custom\namespace',
'globalFixtures' => [
'some\name\space\Foo',
'other\name\space\Bar'
],
],
]
```
Autogenerando fixtures
----------------------
Yii puede también autogenerar fixtures por tí basándose en algún template. Puedes generar tus fixtures con distintos datos en diferentes lenguajes y formatos.
Esta característica es realizada por la librería [Faker](https://github.com/fzaninotto/Faker) y la extensión `yii2-faker`.
Visita la [guía de la extensión](https://github.com/yiisoft/yii2-faker) para mayor documentación.

11
docs/guide-es/test-functional.md

@ -0,0 +1,11 @@
Tests Funcionales
=================
> Note: Esta sección se encuentra en desarrollo.
- [Tests Funcionales de Codeception](http://codeception.com/docs/04-FunctionalTests)
Ejecutar test funcionales de templates básicos y avanzados
----------------------------------------------------------
Por favor consulta las instrucciones provistas en `apps/advanced/tests/README.md` y `apps/basic/tests/README.md`.

25
docs/guide-es/test-unit.md

@ -0,0 +1,25 @@
Tests de Unidad
===============
> Note: Esta sección se encuentra en desarrollo.
Un test de unidad se encarga de verificar que una unidad simple de código funcione como se espera. En la programación orientada a objetos,
la unidad de código más básica es una clase. Por lo tanto, un test de unidad necesita verificar que cada método de la interfaz de la clase funciona apropiadamente.
Esto quiere decir que, dando diferentes parámetros de entrada, el test verifica que el método devuelve el resultado esperado.
Los tests de unidad son normalmente desarrollados por la persona que escribe las clases siendo testeadas.
Los tests de unidad en Yii están construidos en base a PHPUnit y opcionalmente, Codeception, por lo que se recomineda consultar su respectiva documentación:
- [Documentación de PHPUnit comienza en el capítulo 2](http://phpunit.de/manual/current/en/writing-tests-for-phpunit.html).
- [Tests de Unidad con Codeception](http://codeception.com/docs/05-UnitTests).
Ejecutar test de unidad de templates básicos y avanzados
--------------------------------------------------------
Por favor consulta las instrucciones provistas en `apps/advanced/tests/README.md` y `apps/basic/tests/README.md`.
Test de unidad del Framework
----------------------------
Si quieres ejecutar tests de unidad para Yii en sí, consulta
"[Comenzando a desarrollar con Yii 2](https://github.com/yiisoft/yii2/blob/master/docs/internals/getting-started.md)".

6
docs/guide-es/tutorial-core-validators.md

@ -1,7 +1,7 @@
Validadores del núcleo
======================
Validadores del framework
=========================
Yii provee en el núcleo un conjunto de validadores de uso común, que se pueden encontrar principalmente bajo el espacio de nombres (namespace) `yii\validators`.
Yii provee en su núcleo un conjunto de validadores de uso común, que se pueden encontrar principalmente bajo el espacio de nombres (namespace) `yii\validators`.
En vez de utilizar interminables nombres de clases para los validadores, puedes usar *alias* para especificar el uso de esos validadores del núcleo. Por ejemplo, puedes usar el alias `required` para referirte a la clase [[yii\validators\RequiredValidator]] :
```php

231
docs/guide-es/tutorial-mailing.md

@ -0,0 +1,231 @@
Envío de Emails
===============
> Note: Esta sección se encuentra en desarrollo.
Yii soporta composición y envío de emails. De cualquier modo, el núcleo del framework provee
sólo la funcionalidad de composición y una interfaz básica. En mecanismo de envío en sí debería
ser provisto por la extensión, dado que diferentes proyectos pueden requerir diferente implementación y esto
usualmente depende de servicios y librerías externas.
Para la mayoría de los casos, puedes utilizar la extensión oficial [yii2-swiftmailer](https://github.com/yiisoft/yii2-swiftmailer).
Configuración
-------------
La configuración del componente Mail depende de la extensión que hayas elegido.
En general, la configuración de tu aplicación debería verse así:
```php
return [
//....
'components' => [
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
],
],
];
```
Uso Básico
----------
Una vez configurado el componente 'mailer', puedes utilizar el siguiente código para enviar un correo electrónico:
```php
Yii::$app->mailer->compose()
->setFrom('from@domain.com')
->setTo('to@domain.com')
->setSubject('Asunto del mensaje')
->setTextBody('Contenido en texto plano')
->setHtmlBody('<b>Contenido HTML</b>')
->send();
```
En el ejemplo anterior, el método `compose()` crea una instancia del mensaje de correo, el cual puede ser llenado y enviado.
En caso de ser necesario, puedes agregar una lógica más compleja en el proceso:
```php
$message = Yii::$app->mailer->compose();
if (Yii::$app->user->isGuest) {
$message->setFrom('from@domain.com')
} else {
$message->setFrom(Yii::$app->user->identity->email)
}
$message->setTo(Yii::$app->params['adminEmail'])
->setSubject('Asunto del mensaje')
->setTextBody('Contenido en texto plano')
->send();
```
> Note: cada extensión 'mailer' viene en dos grandes clases: 'Mailer' y 'Message'. 'Mailer' siempre conoce
el nombre de clase especifico de 'Message'. No intentes instanciar el objeto 'Message' directamente -
siempre utiliza el método `compose()` para ello.
Puedes también enviar varios mensajes al mismo tiempo:
```php
$messages = [];
foreach ($users as $user) {
$messages[] = Yii::$app->mailer->compose()
// ...
->setTo($user->email);
}
Yii::$app->mailer->sendMultiple($messages);
```
Algunas extensiones en particular pueden beneficiarse de este enfoque, utilizando mensaje simple de red, etc.
Componer el contenido del mensaje
---------------------------------
Yii permite componer el contenido de los mensajes de correo a través de archivos de vista especiales.
Por defecto, estos archivos deben estar ubicados en la ruta '@app/mail'.
Ejemplo de archivo de contenido de correo:
```php
<?php
use yii\helpers\Html;
use yii\helpers\Url;
/* @var $this \yii\web\View instancia del componente view */
/* @var $message \yii\mail\BaseMessage instancia del mensaje de correo recién creado */
?>
<h2>Este mensaje te permite visitar nuestro sitio con un sólo click</h2>
<?= Html::a('Ve a la página principal', Url::home('http')) ?>
```
Para componer el contenido del mensaje utilizando un archivo, simplemente pasa el nombre de la vista al método `compose()`:
```php
Yii::$app->mailer->compose('home-link') // el resultado del renderizado de la vista se transforma en el cuerpo del mensaje aquí
->setFrom('from@domain.com')
->setTo('to@domain.com')
->setSubject('Asunto del mensaje')
->send();
```
Puedes pasarle parámetros adicionales a la vista en el método `compose()`, los cuales estarán disponibles dentro de las vistas:
```php
Yii::$app->mailer->compose('greetings', [
'user' => Yii::$app->user->identity,
'advertisement' => $adContent,
]);
```
Puedes especificar diferentes archivos de vista para el contenido del mensaje en HTML y texto plano:
```php
Yii::$app->mailer->compose([
'html' => 'contact-html',
'text' => 'contact-text',
]);
```
Si especificas el nombre de la vista como un string, el resultado de su renderización será utilizado como cuerpo HTML, mientras
que el cuerpo en texto plano será compuesto removiendo todas las entidades HTML del anterior.
El resultado de la renderización de la vista puede ser envuelta en el layout, que puede ser definido utiliazando [[yii\mail\BaseMailer::htmlLayout]]
y [[yii\mail\BaseMailer::textLayout]]. Esto funciona igual a como funcionan los layouts en una aplicación web normal.
El layout puede utilizar estilos CSS u otros contenidos compartidos:
```php
<?php
use yii\helpers\Html;
/* @var $this \yii\web\View instancia del componente view */
/* @var $message \yii\mail\MessageInterface el mensaje siendo compuesto */
/* @var $content string el resultado de la renderización de la vista principal */
?>
<?php $this->beginPage() ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=<?= Yii::$app->charset ?>" />
<style type="text/css">
.heading {...}
.list {...}
.footer {...}
</style>
<?php $this->head() ?>
</head>
<body>
<?php $this->beginBody() ?>
<?= $content ?>
<div class="footer">Saludos cordiales, el equipo de<?= Yii::$app->name ?></div>
<?php $this->endBody() ?>
</body>
</html>
<?php $this->endPage() ?>
```
Adjuntar archivos
-----------------
Puedes adjuntar archivos al mensaje utilizando los métodos `attach()` y `attachContent()`:
```php
$message = Yii::$app->mailer->compose();
// Adjunta un archivo del sistema local de archivos:
$message->attach('/path/to/file.pdf');
// Crear adjuntos sobre la marcha
$message->attachContent('Contenido adjunto', ['fileName' => 'attach.txt', 'contentType' => 'text/plain']);
```
Incrustar imágenes
------------------
Puedes incrustar imágenes en el mensaje utilizando el método `embed()`. Este método devuelve el id del adjunto,
que debería ser utilizado como tag 'img'.
Este método es fácil de utilizar al componer mensajes a través de un archivo de vista:
```php
Yii::$app->mailer->compose('embed-email', ['imageFileName' => '/path/to/image.jpg'])
// ...
->send();
```
Entonces, dentro de tu archivo de vista, puedes utilizar el siguiente código:
```php
<img src="<?= $message->embed($imageFileName); ?>">
```
Testear y depurar
-----------------
Un desarrollador a menudo necesita comprobar qué emails están siendo enviados por la aplicación, cuál es su contenido y otras cosas.
Yii concede dicha habilidad vía `yii\mail\BaseMailer::useFileTransport`. Si se habilita, esta opción hace que
los datos del mensaje sean guardados en archivos locales en vez de enviados. Esos archivos serán guardados bajo
`yii\mail\BaseMailer::fileTransportPath`, que por defecto es '@runtime/mail'.
> Note: puedes o bien guardar los mensajes en archivos, o enviarlos a sus receptores correspondientes, pero no puedes hacer las dos cosas al mismo tiempo.
Un archivo de mensaje puede ser abierto por un editor de texto común, de modo que puedas ver sus cabeceras, su contenido y demás.
Este mecanismo en sí puede comprobarse al depurar la aplicación o al ejecutar un test de unidad.
> Note: el archivo de contenido de mensaje es compuesto vía `\yii\mail\MessageInterface::toString()`, por lo que depende de la extensión
actual de correo utilizada en tu aplicación.
Crear tu solución personalizada de correo
-----------------------------------------
Para crear tu propia solución de correo, necesitas crear 2 clases: una para 'Mailer' y
otra para 'Message'.
Puedes utilizar `yii\mail\BaseMailer` y `yii\mail\BaseMessage` como clases base de tu solución. Estas clases
ya contienen un lógica básica, la cual se describe en esta guía. De cualquier modo, su utilización no es obligatoria, es suficiente
con implementar las interfaces `yii\mail\MailerInterface` y `yii\mail\MessageInterface`.
Luego necesitas implementar todos los métodos abstractos para construir tu solución.

55
docs/guide-es/tutorial-start-from-scratch.md

@ -0,0 +1,55 @@
Crear tu propia estructura de Aplicación
========================================
> Note: Esta sección se encuentra en desarrollo.
Mientras que los templates de proyectos [basic](https://github.com/yiisoft/yii2-app-basic) y [advanced](https://github.com/yiisoft/yii2-app-advanced)
son grandiosos para la mayoría de tus necesidades, podrías querer crear tu propio template de proyecto del cual
partir todos tus proyectos.
Los templates de proyectos en Yii son simplemente repositorios conteniendo un archivo `composer.json`, y registrado como un paquete de Composer.
Cualquier repositorio puede ser identificado como paquete Composer, haciéndolo instalable a través del comando de Composer `create-project`.
Dado que es un poco demasiado comenzar tu template de proyecto desde cero, es mejor utilizar uno de los
templates incorporados como una base. Utilicemos el template básico aquí.
Clonar el Template Básico
-------------------------
El primer paso es clonar el template básico de Yii desde su repositorio Git:
```bash
git clone git@github.com:yiisoft/yii2-app-basic.git
```
Entonces espera que el repositorio sea descargado a tu computadora. Dado que los cambios realizados al template no serán enviados al repositorio, puedes eliminar el directorio `.git`
y todo su contenido de la descarga.
Modificar los Archivos
----------------------
A continuación, querrás modificar el archivo `composer.json` para que refleje tu template. Cambia los valores de `name`, `description`, `keywords`, `homepage`, `license`, y `support`
de forma que describa tu nuevo template. También ajusta las opciones `require`, `require-dev`, `suggest`, y demás para que encajen con los requerimientos de tu template.
> Note: En el archivo `composer.json`, utiliza el parámetro `writable` (bajo `extra`) para especificar
> permisos-por-archivo a ser definidos después de que la aplicación es creada a partir del template.
Luego, pasa a modificar la estructura y contenido de la aplicación como te gustaría que sea por defecto. Finalmente, actualiza el archivo README para que sea aplicable a tu template.
Hacer un Paquete
----------------
Con el template definido, crea un repositorio Git a partir de él, y sube tus archivos ahí. Si tu template va a ser de código abierto, [Github](http://github.com) es el mejor lugar para alojarlo. Si tu intención es que el template no sea colaborativo, cualquier sitio de repositorios Git servirá.
Ahora, necesitas registrar tu paquete para Composer. Para templates públicos, el paquete debe ser registrado en [Packagist](https://packagist.org/).
Para templates privados, es un poco más complicado registrarlo. Puedes ver instrucciones para hacerlo en la [documentación de Composer](https://getcomposer.org/doc/05-repositories.md#hosting-your-own).
Utilizar el Template
--------------------
Eso es todo lo que se necesita para crear un nuevo template de proyecto Yii. Ahora puedes crear tus propios proyectos a partir de este template:
```
composer global require "fxp/composer-asset-plugin:~1.1.1"
composer create-project --prefer-dist --stability=dev mysoft/yii2-app-coolone new-project
```

49
docs/guide-es/tutorial-template-engines.md

@ -0,0 +1,49 @@
Usar motores de plantillas
==========================
Por defecto, Yii utiliza PHP como su lenguaje de plantilla, pero puedes configurar Yii para que soporte otros motores de renderizado, tal como
[Twig](http://twig.sensiolabs.org/) o [Smarty](http://www.smarty.net/), disponibles como extensiones.
El componente `view` es el responsable de renderizar las vistas. Puedes agregar un motor de plantillas personalizado reconfigurando
el comportamiento (behavior) de este componente:
```php
[
'components' => [
'view' => [
'class' => 'yii\web\View',
'renderers' => [
'tpl' => [
'class' => 'yii\smarty\ViewRenderer',
//'cachePath' => '@runtime/Smarty/cache',
],
'twig' => [
'class' => 'yii\twig\ViewRenderer',
'cachePath' => '@runtime/Twig/cache',
// Array de opciones de Twig:
'options' => [
'auto_reload' => true,
],
'globals' => ['html' => '\yii\helpers\Html'],
'uses' => ['yii\bootstrap'],
],
// ...
],
],
],
]
```
En el código de arriba, tanto Smarty como Twig son configurados para ser utilizables por los archivos de vista. Pero para tener ambas extensiones en tu proyecto, también necesitas modificar
tu archivo `composer.json` para incluirlos:
```
"yiisoft/yii2-smarty": "*",
"yiisoft/yii2-twig": "*",
```
Ese código será agregado a la sección `require` de `composer.json`. Después de realizar ese cambio y guardar el archivo, puedes instalar estas extensiones ejecutando `composer update --prefer-dist` en la línea de comandos.
Para más detalles acerca del uso concreto de cada motor de plantillas, visita su documentación:
- [Guía de Twig](https://github.com/yiisoft/yii2-twig/tree/master/docs/guide)
- [Guía de Smarty](https://github.com/yiisoft/yii2-smarty/tree/master/docs/guide)

118
docs/guide-es/tutorial-yii-integration.md

@ -1,23 +1,27 @@
Trabajando con código de terceros
=================================
Trabajar con código de terceros
===============================
De tiempo en tiempo, puede necesitar usar algún código de terceros en sus aplicaciones Yii. O puedes querer usar Yii como una librería en otros sistemas de terceros. En esta sección, te enseñaremos cómo conseguir estos objetivos.
De tiempo en tiempo, puede necesitar usar algún código de terceros en sus aplicaciones Yii. O puedes querer
utilizar Yii como una librería en otros sistemas de terceros. En esta sección, te enseñaremos cómo conseguir estos objetivos.
## Usando librerías de terceros en Yii <span id="using-libs-in-yii"></span>
Para usar una librería en una aplicación Yii, primeramente debes de asegurarte que las clases een la librería son incluidas adecuadamente o pueden ser cargadas de forma automática.
Utilizar librerías de terceros en Yii <span id="using-libs-in-yii"></span>
-------------------------------------
Para usar una librería en una aplicación Yii, primeramente debes de asegurarte que las clases en la librería
son incluidas adecuadamente o pueden ser cargadas de forma automática.
### Usando Paquetes de Composer <span id="using-composer-packages"></span>
Muchas librerías de terceros son liberadas en términos de paquetes [Composer](https://getcomposer.org/).
Puedes instalar este tipo de librerias siguiendo dos sencillos pasos:
Puedes instalar este tipo de librerías siguiendo dos sencillos pasos:
1. modificar el fichero `composer.json` de tu aplicación y especificar que paquetes Composer quieres instalar.
2. ejecuta `composer install` para instalar los paquetes específicados.
2. ejecuta `composer install` para instalar los paquetes especificados.
Las clases en los paquetes Composer instalados pueden ser autocargados usando el cargador automatizado de Composer autoloader. Asegúrate que el fichero [script de entrada](structure-entry-scripts.md) de tu aplicación contiene las siguientes líneas para instalar el cargador automático de Composer:
Las clases en los paquetes Composer instalados pueden ser autocargados usando el cargador automatizado de Composer autoloader.
Asegúrate que el fichero [script de entrada](structure-entry-scripts.md) de tu aplicación contiene las siguientes líneas
para instalar el cargador automático de Composer:
```php
// instalar el cargador automático de Composer
@ -27,15 +31,21 @@ require(__DIR__ . '/../vendor/autoload.php');
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
```
### Usando librerías Descargadas <span id="using-downloaded-libs"></span>
Si la librería no es liberada como un paquete de Composer, debes de seguir sus instrucciones de instalación para instalarla.
En muchos casos, puedes necesitar descargar manualmente el fichero de la versión y desempaquetarlo en el directorio `BasePath/vendor` , donde `BasePath` representa el [camino base (base path)](structure-applications.md#basePath) de tu aplicación.
En muchos casos, puedes necesitar descargar manualmente el fichero de la versión y desempaquetarlo en el directorio `BasePath/vendor`,
donde `BasePath` representa el [camino base (base path)](structure-applications.md#basePath) de tu aplicación.
Si la librería lleva su propio cargador automático (autoloader), puedes instalarlo en [script de entrada](structure-entry-scripts.md) de tu aplicación. Es recomendable que la instalación se termine antes de incluir el fichero `Yii.php` de forma que el cargador automático tenga precedencia al cargar de forma automática las clases.
Si la librería lleva su propio cargador automático (autoloader), puedes instalarlo en [script de entrada](structure-entry-scripts.md) de tu aplicación.
Es recomendable que la instalación se termine antes de incluir el fichero `Yii.php` de forma que el cargador automático tenga precedencia al cargar
de forma automática las clases.
Si la librería no provee un cargador automático de clases, pero la denominación de sus clases sigue el [PSR-4](http://www.php-fig.org/psr/psr-4/), puedes usar el cargador automático de Yii para cargar de forma automática las clases. Todo lo que necesitas es declarar un [alias raiz](concept-aliases.md#defining-aliases) para cada espacio de nombres (namespace) raiz usado en sus clases. Por ejemplo, asume que has instalado una librería en el directorio `vendor/foo/bar`, y que las clases de la librería están bajo el espacio de nombres raiz `xyz`. Puedes incluir el siguiente código en la configuración de tu aplicación:
Si la librería no provee un cargador automático de clases, pero la denominación de sus clases sigue el [PSR-4](http://www.php-fig.org/psr/psr-4/),
puedes usar el cargador automático de Yii para cargar de forma automática las clases. Todo lo que necesitas
es declarar un [alias raíz](concept-aliases.md#defining-aliases) para cada espacio de nombres (namespace) raiz usado en sus clases. Por ejemplo,
asume que has instalado una librería en el directorio `vendor/foo/bar`, y que las clases de la librería están bajo el espacio de nombres raiz `xyz`.
Puedes incluir el siguiente código en la configuración de tu aplicación:
```php
[
@ -45,30 +55,61 @@ Si la librería no provee un cargador automático de clases, pero la denominaci
]
```
Si ninguno de lo anterior es el caso, estaría bien que la librería dependa del camino de inclusión (include path) de configuración de PHP para localizar correctamente e incluir los ficheros de las clases. Simplemente siguiendo estas instrucciones de cómo configurar el camino de inclusión de PHP.
Si ninguno de lo anterior es el caso, estaría bien que la librería dependa del camino de inclusión (include path) de configuración de PHP
para localizar correctamente e incluir los ficheros de las clases. Simplemente siguiendo estas instrucciones de cómo configurar el camino de inclusión de PHP.
En el caso más grave en el que la librería necesite incluir cada uno de sus ficheros de clases, puedes usar el siguiente método para incluir las clases según se pidan:
En el caso más grave en el que la librería necesite incluir cada uno de sus ficheros de clases, puedes usar el siguiente método
para incluir las clases según se pidan:
* Identificar que clases contiene la librería.
* Listar las clases y el camino a los ficheros correspondientes en `Yii::$classMap` en el script de entrada [script de entrada](structure-entry-scripts.md) de la aplicación. Por ejemplo,
* Listar las clases y el camino a los archivos correspondientes en `Yii::$classMap` en el script de entrada [script de entrada](structure-entry-scripts.md)
de la aplicación. Por ejemplo,
```php
Yii::$classMap['Class1'] = 'path/to/Class1.php';
Yii::$classMap['Class2'] = 'path/to/Class2.php';
```
## Usando Yii en Sistemas de Terceros <span id="using-yii-in-others"></span>
Utilizar Yii en Sistemas de Terceros <span id="using-yii-in-others"></span>
------------------------------------
Debido a que Yii provee muchas posibilidades excelentes, a veces puedes querer usar alguna de sus características para permitir el desarrollo o mejora de sistemas de terceros, como es WordPress, Joomla, o aplicaciones desarrolladas usando otros frameworks de PHP. Por ejemplo, puedes queres usar la clase [[yii\helpers\ArrayHelper]] o usar la característica [Active Record](db-active-record.md) en un sistema de terceros. Para lograr este objetivo, principalmente necesitas realizar dos pasos: instalar Yii , e iniciar Yii.
Debido a que Yii provee muchas posibilidades excelentes, a veces puedes querer usar alguna de sus características para permitir
el desarrollo o mejora de sistemas de terceros, como es WordPress, Joomla, o aplicaciones desarrolladas usando otros frameworks de PHP.
Por ejemplo, puedes querer utilizar la clase [[yii\helpers\ArrayHelper]] o usar la característica [Active Record](db-active-record.md)
en un sistema de terceros. Para lograr este objetivo, principalmente necesitas realizar dos pasos:
instalar Yii , e iniciar Yii.
Si el sistema de terceros usa Composer para manejar sus dependencias, simplemente ejecuta estos comandos para instalar Yii:
Si el sistema de terceros usa Composer para manejar sus dependencias, simplemente ejecuta estos comandos
para instalar Yii:
composer global require "fxp/composer-asset-plugin:~1.1.1"
composer require yiisoft/yii2
composer install
El primer comando instala el [composer asset plugin](https://github.com/francoispluchino/composer-asset-plugin/),
que permite administrar paquetes bower y npm a través de Composer. Incluso si sólo quieres utilizar la capa de base de datos
u otra característica de Yii no relacionada a assets, requiere que instales el paquete composer de Yii.
Si quieres utilizar la [publicación de Assets de Yii](structure-assets.md) deberías agregar también la siguiente configuración
a la sección `extra` de tu `composer.json`:
```json
{
...
"extra": {
"asset-installer-paths": {
"npm-asset-library": "vendor/npm",
"bower-asset-library": "vendor/bower"
}
}
}
```
composer require "yiisoft/yii2:*"
composer install
```
En otro caso, puedes [descargar](http://www.yiiframework.com/download/) el fichero de la edición de Yii y desempaquetarla en el directorio `BasePath/vendor`.
Visita también la [sección de cómo instalar Yii](start-installation.md#installing-via-composer) para más información
sobre Composer y sobre cómo solucionar posibles problemas que surjan durante la instalación.
En otro caso, puedes [descargar](http://www.yiiframework.com/download/) el archivo de la edición de Yii
y desempaquetarla en el directorio `BasePath/vendor`.
Después, debes de modificar el script de entrada de sistema de terceros para incluir el siguiente código al principio:
@ -79,24 +120,32 @@ $yiiConfig = require(__DIR__ . '/../config/yii/web.php');
new yii\web\Application($yiiConfig); // No ejecutes run() aquí
```
Como puedes ver, el código anterior es muy similar al que puedes ver en [script de entrada](structure-entry-scripts.md) de una aplicación típica. La única diferencia es que después de que se crea la instancia de la aplicación, el método `run()` no es llamado. Esto es así porque llamando a `run()`, Yii se haría cargo del control del flujo de trabajo del manejo de las peticiones, lo cual no es necesario en este caso por estar ya es manejado por la aplicación existente.
Como puedes ver, el código anterior es muy similar al que puedes ver en [script de entrada](structure-entry-scripts.md)
de una aplicación típica. La única diferencia es que después de que se crea la instancia de la aplicación, el método `run()` no es llamado.
Esto es así porque llamando a `run()`, Yii se haría cargo del control del flujo de trabajo del manejo de las peticiones,
lo cual no es necesario en este caso por estar ya es manejado por la aplicación existente.
Como en una aplicación Yii, debes configurar la instancia de la aplicación basándose en el entorno que se está ejecutando del sistema de terceros. Por ejemplo, para usar la característica [Active Record](db-active-record.md) , necesitas configurar `db` [componente de la aplicación](structure-application-components.md) con los parámetros de la conexión de base de datos usados por el sistema de terceros.
Como en una aplicación Yii, debes configurar la instancia de la aplicación basándose en el entorno que se está
ejecutando del sistema de terceros. Por ejemplo, para usar la característica [Active Record](db-active-record.md), necesitas configurar
el [componente de la aplicación](structure-application-components.md) `db` con los parámetros de la conexión a la BD del sistema de terceros.
Ahora puedes usar muchas características provistas por Yii. Por ejemplo, puedes crear clases Active Record y usarlas para trabajar con bases de datos.
Ahora puedes usar muchas características provistas por Yii. Por ejemplo, puedes crear clases Active Record y usarlas
para trabajar con bases de datos.
## Usando Yii 2 con Yii 1 <span id="using-both-yii2-yii1"></span>
Si estaba usando Yii 1 previamente, es como si tuvieras una aplicación Yii 1 funcionando. En vez de reescribir toda la aplicación en Yii 2, puedes solamente mejorarla usando alguna de las características sólo disponibles en Yii 2.
Utilizar Yii 2 con Yii 1 <span id="using-both-yii2-yii1"></span>
------------------------
Si estaba usando Yii 1 previamente, es como si tuvieras una aplicación Yii 1 funcionando. En vez de reescribir
toda la aplicación en Yii 2, puedes solamente mejorarla usando alguna de las características sólo disponibles en Yii 2.
Esto se puede lograr tal y como se describe abajo.
> Note: Yii 2 requiere PHP 5.4 o superior. Debes de estar seguro que tanto tu servidor como la aplicación existente lo soportan.
> Note: Yii 2 requiere PHP 5.4 o superior. Debes de estar seguro que tanto tu servidor como la aplicación
> existente lo soportan.
Primero, instala Yii 2 en tu aplicación siguiendo las instrucciones descritas en la [última subsección](#using-yii-in-others).
Segundo,modifica el script de entrada de la aplicación como sigue,
Segundo, modifica el script de entrada de la aplicación como sigue,
```php
// incluir la clase Yii personalizada descrita debajo
@ -112,7 +161,6 @@ Yii::createWebApplication($yii1Config)->run();
```
Debido a que ambos Yii 1 y Yii 2 tiene la clase `Yii` , debes crear una versión personalizada para combinarlas.
El código anterior incluye el fichero con la clase `Yii` personalizada, que tiene que ser creada como sigue.
```php
@ -128,15 +176,17 @@ class Yii extends \yii\BaseYii
}
Yii::$classMap = include($yii2path . '/classes.php');
// registrar el autoloader de Yii2 autoloader via Yii1
// registrar el autoloader de Yii 2 vía Yii 1
Yii::registerAutoloader(['Yii', 'autoload']);
// crear el contenedor de inyección de dependencia
Yii::$container = new yii\di\Container;
```
¡Esto es todo!. Ahora, en cualquier parte de tu código, puedes usar `Yii::$app` para acceder a la instancia de la aplicación de Yii 2, mientras `Yii::app()` proporciona la instancia de la aplicación de Yii 1 :
¡Esto es todo!. Ahora, en cualquier parte de tu código, puedes usar `Yii::$app` para acceder a la instancia de la aplicación de Yii 2,
mientras `Yii::app()` proporciona la instancia de la aplicación de Yii 1 :
```php
echo get_class(Yii::app()); // genera 'CWebApplication'
echo get_class(Yii::$app); // genera 'yii\web\Application'
```

143
docs/guide-id/start-hello.md

@ -0,0 +1,143 @@
Katakan Hello
============
Bagian ini menjelaskan cara membuat halaman "Hello" baru dalam aplikasi Anda.
Untuk mencapai tujuan ini, Anda akan membuat [action](structure-controllers.md#creating-actions) dan
sebuah [view](structure-views.md):
* Aplikasi ini akan mengirimkan permintaan halaman ke `action`.
* Dan `action` pada gilirannya akan membuat tampilan yang menunjukkan kata "Hello" kepada pengguna akhir.
Melalui tutorial ini, Anda akan belajar tiga hal:
1. Cara membuat [action](structure-controllers.md#creating-actions) untuk menanggapi permintaan,
2. Cara membuat [view](structure-views.md) untuk menyusun konten respon, dan
3. bagaimana aplikasi mengirimkan permintaan ke [action](structure-controllers.md#creating-actions).
Membuat Action <span id="creating-action"></span>
---------------
Untuk tugas "Hello", Anda akan membuat [action](structure-controllers.md#creating-actions) `say` yang membaca
parameter `message` dari request dan menampilkan pesan bahwa kembali ke pengguna. Jika request
tidak memberikan parameter `message`, aksi akan menampilkan pesan "Hello".
> Info: [Action](structure-controllers.md#creating-actions) adalah objek yang pengguna akhir dapat langsung merujuk ke
  eksekusi. Action dikelompokkan berdasarkan [controllers](structure-controllers.md). Hasil eksekusi
  action adalah respon yang pengguna akhir akan terima.
Action harus dinyatakan di [controllers](structure-controllers.md). Untuk mempermudah, Anda mungkin
mendeklarasikan action `say` di` SiteController` yang ada. kontroler ini didefinisikan
dalam file kelas `controllers/SiteController.php`. Berikut adalah awal dari action baru:
```php
<?php
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
// ...existing code...
public function actionSay($message = 'Hello')
{
return $this->render('say', ['message' => $message]);
}
}
```
Pada kode di atas, action `say` didefinisikan sebagai metode bernama` actionSay` di kelas `SiteController`.
Yii menggunakan awalan `action` untuk membedakan metode action dari metode non-action dalam kelas controller.
Nama setelah awalan `action` peta untuk ID tindakan ini.
Untuk sampai pada penamaan action, Anda harus memahami bagaimana Yii memperlakukan ID action. ID action selalu
direferensikan dalam huruf kecil. Jika ID tindakan membutuhkan beberapa kata, mereka akan digabungkan dengan `tanda hubung`
(Mis, `create-comment`). nama metode aksi yang dipetakan ke ID tindakan diperoleh dengan menghapus tanda hubung apapun dari ID,
mengkapitalkan huruf pertama di setiap kata, dan awalan string yang dihasilkan dengan `action`. Sebagai contoh,
ID action `create-comment` sesuai dengan nama method action `actionCreateComment`.
Metode action dalam contoh kita mengambil parameter `$message`, yang nilai defaultnya adalah `"Hello"` (persis
dengan cara yang sama Anda menetapkan nilai default untuk fungsi atau metode apapun argumen di PHP). Ketika aplikasi
menerima permintaan dan menentukan bahwa action `say` bertanggung jawab untuk penanganan request, aplikasi akan
mengisi parameter ini dengan parameter bernama sama yang ditemukan dalam request. Dengan kata lain, jika permintaan mencakup
a parameter `message` dengan nilai` "Goodbye" `, maka variabel `$message` dalam aksi akan ditugaskan nilai itu.
Dalam metode action, [[yii\web\Controller::render()|render()]] dipanggil untuk membuat
sebuah [view](structure-views.md) dari file bernama `say`. Parameter `message` juga diteruskan ke view
sehingga dapat digunakan di sana. Hasil render dikembalikan dengan metode tindakan. Hasil yang akan diterima
oleh aplikasi dan ditampilkan kepada pengguna akhir di browser (sebagai bagian dari halaman HTML yang lengkap).
Membuat View <span id="creating-view"></span>
---------------
[View](structure-views.md) adalah skrip yang Anda tulis untuk menghasilkan konten respon.
Untuk "Hello" tugas, Anda akan membuat view `say` yang mencetak parameter `message` yang diterima dari metode aksi:
```php
<?php
use yii\helpers\Html;
?>
<?= Html::encode($message) ?>
```
View `say` harus disimpan dalam file `views/site/say.php`. Ketika metode [[yii\web\Controller::render()|render()]]
disebut dalam tindakan, itu akan mencari file PHP bernama `views/ControllerID/ViewName.php`.
Perhatikan bahwa dalam kode di atas, parameter `message` adalah di-[[yii\helpers\Html::encode()|HTML-encoded]]
sebelum dicetak. Hal ini diperlukan karena sebagai parameter yang berasal dari pengguna akhir, sangat rentan terhadap
[serangan Cross-site scripting (XSS)](http://en.wikipedia.org/wiki/Cross-site_scripting) dengan melekatkan
kode JavaScript berbahaya dalam parameter.
Tentu, Anda dapat menempatkan lebih banyak konten di view `say`. konten dapat terdiri dari tag HTML, teks biasa, dan bahkan pernyataan PHP.
Nyatanya, view `say` hanyalah sebuah script PHP yang dijalankan oleh metode [[yii\web\Controller::render()|render()]].
Isi dicetak oleh skrip view akan dikembalikan ke aplikasi sebagai hasil respon ini. Aplikasi ini pada gilirannya akan mengeluarkan hasil ini kepada pengguna akhir.
Trying it Out <span id="trying-it-out"></span>
-------------
Setelah membuat action dan view, Anda dapat mengakses halaman baru dengan mengakses URL berikut:
```
http://hostname/index.php?r=site%2Fsay&message=Hello+World
```
![Hello World](images/start-hello-world.png)
URL ini akan menghasilkan halaman yang menampilkan "Hello World". Halaman yang berbagi header dan footer yang sama dengan halaman aplikasi lainnya.
Jika Anda menghilangkan parameter `message` dalam URL, Anda akan melihat tampilan halaman "Hello". Hal ini karena `message` dilewatkan sebagai parameter untuk metode `actionSay()`, dan ketika itu dihilangkan,
nilai default `"Hello"` akan digunakan sebagai gantinya.
> Info: Halaman baru berbagi header dan footer yang sama dengan halaman lain karena metode [[yii\web\Controller::render()|render()]]
  otomatis akan menanamkan hasil view `say` kedalam apa yang disebut [layout](structure-views.md#layouts) yang dalam hal ini
  Kasus terletak di `views/layouts/main.php`.
Parameter `r` di URL di atas memerlukan penjelasan lebih lanjut. Ini adalah singkatan dari [route](runtime-routing.md), sebuah ID unik aplikasi
yang mengacu pada action. format rute ini adalah `ControllerID/ActionID`. Ketika aplikasi menerima
permintaan, itu akan memeriksa parameter ini, menggunakan bagian `ControllerID` untuk menentukan kontroler
kelas harus dipakai untuk menangani permintaan. Kemudian, controller akan menggunakan bagian `ActionID`
untuk menentukan action yang harus dipakai untuk melakukan pekerjaan yang sebenarnya. Dalam contoh kasus ini, rute `site/say`
akan diselesaikan dengan kontroler kelas `SiteController` dan action `say`. Sebagai hasilnya,
metode `SiteController::actionSay()` akan dipanggil untuk menangani permintaan.
> Info: Seperti action, kontroler juga memiliki ID yang unik mengidentifikasi mereka dalam sebuah aplikasi.
  ID kontroler menggunakan aturan penamaan yang sama seperti ID tindakan. nama kelas controller yang berasal dari
  kontroler ID dengan menghapus tanda hubung dari ID, memanfaatkan huruf pertama di setiap kata,
  dan suffixing string yang dihasilkan dengan kata `Controller`. Misalnya, controller ID `post-comment` berkorespondensi
  dengan nama kelas controller `PostCommentController`.
Ringkasan <span id="summary"></span>
-------
Pada bagian ini, Anda telah menyentuh controller dan melihat bagian dari pola arsitektur MVC.
Anda menciptakan sebuah action sebagai bagian dari controller untuk menangani permintaan khusus. Dan Anda juga menciptakan view
untuk menulis konten respon ini. Dalam contoh sederhana ini, tidak ada model yang terlibat. Satu-satunya data yang digunakan adalah parameter `message`.
Anda juga telah belajar tentang rute di Yii, yang bertindak sebagai jembatan antara permintaan pengguna dan tindakan controller.
Pada bagian berikutnya, Anda akan belajar cara membuat model, dan menambahkan halaman baru yang berisi bentuk HTML.

238
docs/guide-id/start-installation.md

@ -0,0 +1,238 @@
Instalasi Yii
==============
Anda dapat menginstal Yii dalam dua cara, menggunakan [Composer](https://getcomposer.org/) paket manager atau dengan mengunduh file arsip.
Yang pertama adalah cara yang lebih disukai, karena memungkinkan Anda untuk menginstal [ekstensi](structure-extensions.md) baru atau memperbarui Yii dengan hanya menjalankan *command line*.
Hasil instalasi standar Yii baik framework maupun template proyek keduanya akan terunduh dan terpasang.
Sebuah template proyek adalah proyek Yii yang menerapkan beberapa fitur dasar, seperti login, formulir kontak, dll.
Kode diatur dalam cara yang direkomendasikan. Oleh karena itu, dapat berfungsi sebagai titik awal yang baik untuk proyek-proyek Anda.
    
Dalam hal ini dan beberapa bagian berikutnya, kita akan menjelaskan cara menginstal Yii dengan apa yang disebut *Template Proyek Dasar* dan
bagaimana menerapkan fitur baru di atas template ini. Yii juga menyediakan template lain yang disebut
yang [Template Proyek Lanjutan](https://github.com/yiisoft/yii2-app-advanced/blob/master/docs/guide/README.md) yang lebih baik digunakan dalam lingkungan pengembangan tim
untuk mengembangkan aplikasi dengan beberapa tingkatan.
> Info: Template Proyek Dasar ini cocok untuk mengembangkan 90 persen dari aplikasi Web. Ini berbeda
  dari Template Proyek Lanjutan terutama dalam bagaimana kode mereka diatur. Jika Anda baru untuk Yii, kami sangat
  merekomendasikan Anda tetap pada Template Proyek Dasar untuk kesederhanaan dan fungsi yang cukup.
Menginstal melalui Komposer <span id="installing-via-composer"></span>
-----------------------
Jika Anda belum memiliki Composer terinstal, Anda dapat melakukannya dengan mengikuti petunjuk di
[getcomposer.org] (https://getcomposer.org/download/). Pada Linux dan Mac OS X, Anda akan menjalankan perintah berikut:
```bash
curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer
```
Pada Windows, Anda akan mengunduh dan menjalankan [Composer-Setup.exe](https://getcomposer.org/Composer-Setup.exe).
Silakan merujuk ke [Dokumentasi Composer](https://getcomposer.org/doc/) jika Anda menemukan
masalah atau ingin mempelajari lebih lanjut tentang penggunaan Composer.
Jika Composer sudah terinstal sebelumnya, pastikan Anda menggunakan versi terbaru. Anda dapat memperbarui Komposer
dengan menjalankan `composer self-update`.
Dengan Komposer diinstal, Anda dapat menginstal Yii dengan menjalankan perintah berikut di bawah folder yang terakses web:
```bash
composer global require "fxp/composer-asset-plugin:~1.1.1"
composer create-project --prefer-dist yiisoft/yii2-app-basic basic
```
Perintah pertama menginstal [komposer aset Plugin](https://github.com/francoispluchino/composer-asset-plugin/)
yang memungkinkan mengelola bower dan paket npm melalui Composer. Anda hanya perlu menjalankan perintah ini
sekali untuk semua. Perintah kedua menginstal Yii dalam sebuah direktori bernama `basic`. Anda dapat memilih nama direktori yang berbeda jika Anda ingin.
> Catatan: Selama instalasi, Composer dapat meminta login Github Anda. Ini normal karena Komposer
> Perlu mendapatkan cukup API rate-limit untuk mengambil informasi paket dari Github. Untuk lebih jelasnya,
> Silahkan lihat [Documentation Composer](https://getcomposer.org/doc/articles/troubleshooting.md#api-rate-limit-and-oauth-tokens).
> Tip: Jika Anda ingin menginstal versi pengembangan terbaru dari Yii, Anda dapat menggunakan perintah berikut sebagai gantinya,
> Yang menambahkan [opsi stabilitas](https://getcomposer.org/doc/04-schema.md#minimum-stability):
>
> ```bash
> composer create-project --prefer-dist --stability=dev yiisoft/yii2-app-basic basic
> ```
>
> Perhatikan bahwa versi pengembangan dari Yii tidak boleh digunakan untuk produksi karena kemungkinan dapat *merusak* kode Anda yang sedang berjalan.
Instalasi dari file Arsip <span id="installing-from-archive-file"></span>
-------------------------------
Instalasi Yii dari file arsip melibatkan tiga langkah:
1. Download file arsip dari [yiiframework.com](http://www.yiiframework.com/download/).
2. Uraikan file yang didownload ke folder yang bisa diakses web.
3. Memodifikasi `config/web.php` dengan memasukkan kunci rahasia untuk `cookieValidationKey`.
   (Ini dilakukan secara otomatis jika Anda menginstal Yii menggunakan Composer):
```php
// !!! Isikan nilai key jika kosong - ini diperlukan oleh cookie validation
'cookieValidationKey' => 'enter your secret key here',
```
Pilihan Instalasi lainnya <span id="other-installation-options"></span>
--------------------------
Petunjuk instalasi di atas menunjukkan cara menginstal Yii, yang juga menciptakan aplikasi Web dasar yang bekerja di luar kotak.
Pendekatan ini adalah titik awal yang baik untuk sebagian besar proyek, baik kecil atau besar. Hal ini terutama cocok jika Anda hanya
mulai belajar Yii.
Tetapi ada pilihan instalasi lain yang tersedia:
* Jika Anda hanya ingin menginstal kerangka inti dan ingin membangun seluruh aplikasi dari awal,
  Anda dapat mengikuti petunjuk seperti yang dijelaskan dalam [Membangun Aplikasi dari Scratch](tutorial-start-from-scratch.md).
* Jika Anda ingin memulai dengan aplikasi yang lebih canggih, lebih cocok untuk tim lingkungan pengembangan,
  Anda dapat mempertimbangkan memasang [Template Lanjutan Proyek] (https://github.com/yiisoft/yii2-app-advanced/blob/master/docs/guide/README.md).
Memverifikasi Instalasi <span id="memverifikasi instalasi"></span>
--------------------------
Setelah instalasi selesai, baik mengkonfigurasi web server Anda (lihat bagian berikutnya) atau menggunakan
[Built-in web server PHP] (https://secure.php.net/manual/en/features.commandline.webserver.php) dengan menjalankan berikut
konsol perintah sementara dalam proyek `web` direktori:
```bash
php yii serve
```
> Catatan: Secara default HTTP-server akan mendengarkan port 8080. Namun jika port yang sudah digunakan atau Anda ingin
melayani beberapa aplikasi dengan cara ini, Anda mungkin ingin menentukan port apa yang harus digunakan. Cukup tambahkan argumen --port:
```bash
php yii serve --port = 8888
```
Anda dapat menggunakan browser untuk mengakses aplikasi Yii yang diinstal dengan URL berikut:
```
http://localhost:8080/
```
![Instalasi Sukses dari Yii](images/start-app-installed.png)
Anda seharusnya melihat halaman "Congratulations!" di browser Anda. Jika tidak, periksa apakah instalasi PHP Anda memenuhi
persyaratan Yii. Anda dapat memeriksa apakah persyaratan minimumnya cocok dengan menggunakan salah satu pendekatan berikut:
* Copy `/requirements.php` ke `/web/requirements.php` kemudian gunakan browser untuk mengakses melalui `http://localhost/requirements.php`
* Jalankan perintah berikut:
  ```bash
  cd basic
  php requirements.php
  ```
Anda harus mengkonfigurasi instalasi PHP Anda sehingga memenuhi persyaratan minimal Yii. Yang paling penting, Anda
harus memiliki PHP versi 5.4 atau lebih. Anda juga harus menginstal [PDO PHP Ekstensi](http://www.php.net/manual/en/pdo.installation.php)
dan driver database yang sesuai (seperti `pdo_mysql` untuk database MySQL), jika aplikasi Anda membutuhkan database.
Konfigurasi Web Server <span id="configuring-web-servers"></span>
-----------------------
> Info: Anda dapat melewati seksi ini untuk saat ini jika Anda hanya menguji sebuah Yii dengan niat
  penggelaran itu untuk server produksi.
Aplikasi yang diinstal sesuai dengan petunjuk di atas seharusnya bekerja dengan baik
pada [Apache HTTP server](http://httpd.apache.org/) atau [Nginx HTTP server](http://nginx.org/), pada
Windows, Mac OS X, atau Linux yang menjalankan PHP 5.4 atau lebih tinggi. Yii 2.0 juga kompatibel dengan facebook
[HHVM](http://hhvm.com/). Namun, ada beberapa kasus di mana HHVM berperilaku berbeda dari PHP asli,
sehingga Anda harus mengambil beberapa perlakuan ekstra ketika menggunakan HHVM.
Pada server produksi, Anda mungkin ingin mengkonfigurasi server Web Anda sehingga aplikasi dapat diakses
melalui URL `http://www.example.com/index.php` bukannya `http://www.example.com/dasar/web/index.php`. konfigurasi seperti itu
membutuhkan root dokumen server Web Anda menunjuk ke folder `basic/web`. Anda mungkin juga
ingin menyembunyikan `index.php` dari URL, seperti yang dijelaskan pada bagian [Routing dan Penciptaan URL](runtime-routing.md).
Dalam bagian ini, Anda akan belajar bagaimana untuk mengkonfigurasi Apache atau Nginx server Anda untuk mencapai tujuan tersebut.
> Info: Dengan menetapkan `basic/web` sebagai akar dokumen, Anda juga mencegah pengguna akhir mengakses
kode private aplikasi Anda dan file data sensitif yang disimpan dalam direktori sejajar
dari `basic/web`. Mencegah akses ke folder lainnya adalah sebuah peningkatan keamanan.
> Info: Jika aplikasi Anda akan berjalan di lingkungan shared hosting di mana Anda tidak memiliki izin
untuk memodifikasi konfigurasi server Web-nya, Anda mungkin masih menyesuaikan struktur aplikasi Anda untuk keamanan yang lebih baik. Silakan merujuk ke
yang lebih baik. Lihat bagian [Shared Hosting Lingkungan](tutorial-shared-hosting.md) untuk rincian lebih lanjut.
### Konfigurasi Apache yang Direkomendasikan <span id="recommended-apache-configuration"></span>
Gunakan konfigurasi berikut di file `httpd.conf` Apache atau dalam konfigurasi virtual host. Perhatikan bahwa Anda
harus mengganti `path/to/basic/web` dengan path ` dasar/web` yang sebenarnya.
```apache
# Set document root to be "basic/web"
DocumentRoot "path/to/basic/web"
<Directory "path/to/basic/web">
# use mod_rewrite for pretty URL support
RewriteEngine on
# If a directory or a file exists, use the request directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Otherwise forward the request to index.php
RewriteRule . index.php
# ...other settings...
</Directory>
```
### Konfigurasi Nginx yang Direkomendasikan<span id="recommended-nginx-configuration"></span>
Untuk menggunakan [Nginx](http://wiki.nginx.org/), Anda harus menginstal PHP sebagai [FPM SAPI](http://php.net/install.fpm).
Anda dapat menggunakan konfigurasi Nginx berikut, menggantikan `path/to/basic/web` dengan path yang sebenarnya untuk
`basic/web` dan `mysite.local` dengan hostname yang sebenarnya untuk server.
```nginx
server {
charset utf-8;
client_max_body_size 128M;
listen 80; ## listen for ipv4
#listen [::]:80 default_server ipv6only=on; ## listen for ipv6
server_name mysite.local;
root /path/to/basic/web;
index index.php;
access_log /path/to/basic/log/access.log;
error_log /path/to/basic/log/error.log;
location / {
# Redirect everything that isn't a real file to index.php
try_files $uri $uri/ /index.php$is_args$args;
}
# uncomment to avoid processing of calls to non-existing static files by Yii
#location ~ \.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar)$ {
# try_files $uri =404;
#}
#error_page 404 /404.html;
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass 127.0.0.1:9000;
#fastcgi_pass unix:/var/run/php5-fpm.sock;
try_files $uri =404;
}
location ~ /\.(ht|svn|git) {
deny all;
}
}
```
Bila menggunakan konfigurasi ini, Anda juga harus menetapkan `cgi.fix_pathinfo=0` di file` php.ini`
untuk menghindari banyak panggilan `stat()` sistem yang tidak perlu.
Sekalian catat bahwa ketika menjalankan server HTTPS, Anda perlu menambahkan `fastcgi_param HTTPS on;` sehingga Yii
benar dapat mendeteksi jika sambungan aman.

102
docs/guide-id/start-workflow.md

@ -0,0 +1,102 @@
Menjalankan Aplikasi
====================
Setelah menginstal Yii, Anda memiliki aplikasi Yii yang dapat diakses melalui
URL `http://hostname/basic/web/index.php` atau `http://hostname/index.php`, tergantung
pada konfigurasi Anda. Bagian ini akan memperkenalkan fungsi built-in aplikasi,
bagaimana kode ini disusun, dan bagaimana aplikasi menangani permintaan secara umum.
> Info: Untuk mempermudah, selama tutorial "Mulai", itu diasumsikan bahwa Anda telah menetapkan `basic/web`
  sebagai root dokumen server Web Anda, dan URL dikonfigurasi untuk mengakses
  aplikasi Anda untuk menjadi `http://hostname/index.php` atau sesuatu yang serupa.
  Untuk kebutuhan Anda, silakan menyesuaikan URL sesuai deskripsi kami.
  
Perhatikan bahwa tidak seperti framework itu sendiri, setelah template proyek diinstal, itu semua milikmu. Anda bebas untuk menambah atau menghapus
kode dan memodifikasi keseluruhannya sesuai yang Anda butuhkan.
Fungsi <span id="functionality"></span>
-------------
Aplikasi dasar diinstal berisi empat halaman:
* Homepage, ditampilkan saat Anda mengakses URL `http://hostname/index.php`,
* Halaman "About",
* Halaman "Contact", yang menampilkan formulir kontak yang memungkinkan pengguna akhir untuk menghubungi Anda melalui email,
* Dan halaman "Login", yang menampilkan form login yang dapat digunakan untuk otentikasi pengguna akhir. Cobalah masuk
  dengan "admin/admin", dan Anda akan menemukan item "Login" di menu utama akan berubah menjadi "Logout".
Halaman ini berbagi header umum dan footer. header berisi menu bar utama untuk memungkinkan navigasi
antara halaman yang berbeda.
Anda juga harus melihat toolbar di bagian bawah jendela browser.
Ini adalah [debugger tool](https://github.com/yiisoft/yii2-debug/blob/master/docs/guide/README.md) yang disediakan oleh Yii
untuk merekam dan menampilkan banyak informasi debug, seperti log pesan, status respon, query database berjalan, dan sebagainya.
Selain itu untuk aplikasi web, ada script konsol yang disebut `yii`, yang terletak di direktori aplikasi dasar.
Script ini dapat digunakan untuk menjalankan aplikasi background dan tugas pemeliharaan untuk aplikasi, yang diuraikan
di bagian [Console Application](tutorial-console.md).
Struktur aplikasi <span id="application-structure"></span>
---------------------
Direktori yang paling penting dan file dalam aplikasi Anda (dengan asumsi direktori root aplikasi adalah `basic`):
```
basic/ path aplikasi dasar
composer.json digunakan oleh Composer, package information
config/ berisi konfigurasi aplikasi dan yang lain
console.php konfigurasi aplikasi konsole
web.php konfigurasi aplikasi web
commands/ contains console command classes
controllers/ contains controller classes
models/ contains model classes
runtime/ contains files generated by Yii during runtime, such as logs and cache files
vendor/ contains the installed Composer packages, including the Yii framework itself
views/ contains view files
web/ application Web root, contains Web accessible files
assets/ contains published asset files (javascript and css) by Yii
index.php the entry (or bootstrap) script for the application
yii the Yii console command execution script
```
Secara umum, file dalam aplikasi dapat dibagi menjadi dua jenis: mereka yang di bawah `basic/web` dan mereka yang
di bawah direktori lain. Yang pertama dapat langsung diakses melalui HTTP (yaitu, di browser), sedangkan yang kedua tidak dapat dan tidak seharusnya boleh.
Yii mengimplementasikan pola arsitektur [model-view-controller (MVC)](http://wikipedia.org/wiki/Model-view-controller),
yang tercermin dalam organisasi direktori di atas. Direktori `models` berisi semua [Model kelas](structure-models.md),
direktori `views` berisi semua [view script] structure-views.md), dan direktori `controllers` mengandung
semua [kelas kontroler](structure-controllers.md).
Diagram berikut memperlihatkan struktur statis dari sebuah aplikasi.
![Struktur statis aplikasi](images/application-structure.png)
Setiap aplikasi memiliki naskah entri `web/index.php` yang merupakan satu-satunya PHP skrip dalam aplikasi yang dapat diakses web.
Naskah entri mengambil permintaan masuk dan menciptakan [aplikasi](structure-applications.md) untuk menanganinya.
[Aplikasi](structure-applications.md) menyelesaikan permintaan dengan bantuan [komponen](concept-components.md)nya,
dan mengirimkan permintaan ke elemen MVC. [Widget](structure-widgets.md) digunakan dalam [view](structure-views.md)
untuk membantu membangun elemen antarmuka pengguna yang kompleks dan dinamis.
Daur Hidup Request <span id="request-lifecycle"></span>
-----------------
Diagram berikut menunjukkan bagaimana aplikasi menangani permintaan.
![Request Lifecycle](images/request-lifecycle.png)
1. Pengguna membuat permintaan ke [skrip entri](structure-entry-scripts.md) `web/index.php`.
2. Naskah entri memuat [konfigurasi](concept-configurations.md) aplikasi dan menciptakan
   [aplikasi](structure-applications.md) untuk menangani permintaan.
3. Aplikasi menyelesaikan [route](runtime-routing.md) yang diminta dengan bantuan
   komponen [request](runtime-requests.md) aplikasi.
4. Aplikasi ini menciptakan [kontroler](structure-controllers.md) untuk menangani permintaan.
5. Controller menciptakan [action](structure-controllers.md) dan melakukan filter untuk action.
6. Jika filter gagal, aksi dibatalkan.
7. Jika semua filter lulus, aksi dieksekusi.
8. Action memuat model data, mungkin dari database.
9. Aksi meyiapkan view, menyediakannya dengan model data.
10. Hasilnya diberikan dikembalikan ke komponen aplikasi [respon](runtime-responses.md).
11. Komponen respon mengirimkan hasil yang diberikan ke browser pengguna.

3
docs/guide-ja/README.md

@ -109,9 +109,12 @@ All Rights Reserved.
セキュリティ
------------
* [概要](security-overview.md)
* [認証](security-authentication.md)
* [権限付与](security-authorization.md)
* [パスワードを扱う](security-passwords.md)
* [暗号化](security-cryptography.md)
* [ビューのセキュリティ](structure-views.md#security)
* [認証クライアント](https://github.com/yiisoft/yii2-authclient/blob/master/docs/guide-ja/README.md)
* [ベストプラクティス](security-best-practices.md)

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

@ -287,7 +287,7 @@ Yii は、新しいオブジェクトを作成するさい、そのコアコー
\Yii::$container->set('yii\widgets\LinkPager', ['maxButtonCount' => 5]);
```
次のコードでビューでウィジェットを使用すれば、 `maxButtonCount` プロパティは、
そして、次のコードでビューでウィジェットを使用すれば、`maxButtonCount` プロパティは、
クラスで定義されているデフォルト値 10 の代わりに 5 で初期化されます。
```php
@ -300,6 +300,8 @@ echo \yii\widgets\LinkPager::widget();
echo \yii\widgets\LinkPager::widget(['maxButtonCount' => 20]);
```
> Tip: どのような型の値であろうとも上書きされますので、オプションの配列の指定には気を付けてください。オプションの配列はマージされません。
DI コンテナの自動コンストラクタ・インジェクションの利点を活かす別の例です。
あなたのコントローラクラスが、ホテル予約サービスのような、いくつかの他のオブジェクトに依存するとします。
あなたは、コンストラクタパラメータを通して依存関係を宣言して、DI コンテナにあなたの課題を解決させることができます。

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

@ -668,6 +668,10 @@ class m150101_185401_create_news_table extends Migration
* [[yii\db\Migration::dropForeignKey()|dropForeignKey()]]: 外部キーを削除
* [[yii\db\Migration::createIndex()|createIndex()]]: インデックスを作成
* [[yii\db\Migration::dropIndex()|dropIndex()]]: インデックスを削除
* [[yii\db\Migration::addCommentOnColumn()|addCommentOnColumn()]: カラムにコメントを追加
* [[yii\db\Migration::dropCommentFromColumn()|dropCommentFromColumn()]: カラムからコメントを削除
* [[yii\db\Migration::addCommentOnTable()|addCommentOnTable()]: テーブルにコメントを追加
* [[yii\db\Migration::dropCommentFromTable()|dropCommentFromTable()]: テーブルからコメントを削除
> Info: [[yii\db\Migration]] は、データベースクエリメソッドを提供しません。
これは、通常、データベースからのデータ取得については、メッセージを追加して表示する必要がないからです。
@ -692,6 +696,9 @@ yii migrate
リストされたマイグレーションを適用することをあなたが確認すると、タイムスタンプの値の順に、一つずつ、すべての新しいマイグレーションクラスの `up()` または `safeUp()` メソッドが実行されます。
マイグレーションのどれかが失敗した場合は、コマンドは残りのマイグレーションを適用せずに終了します。
> Tip: あなたのサーバでコマンドラインを使用できない場合は
> [web shell](https://github.com/samdark/yii2-webshell) エクステンションを使ってみてください。
適用が成功したマイグレーションの一つ一つについて、`migration` という名前のデータベーステーブルに行が挿入されて、マイグレーションの成功が記録されます。
この記録によって、マイグレーションツールは、どのマイグレーションが適用され、どのマイグレーションが適用されていないかを特定することが出来ます。

21
docs/guide-ja/db-query-builder.md

@ -332,6 +332,20 @@ $query->filterWhere([
[[yii\db\Query::andWhere()|andWhere()]] または [[yii\db\Query::orWhere()|orWhere()]] と同じように、[[yii\db\Query::andFilterWhere()|andFilterWhere()]] または [[yii\db\Query::orFilterWhere()|orFilterWhere()]] を使って、既存の条件に別のフィルタ条件を追加することも出来ます。
さらに加えて、値の方に含まれている比較演算子を適切に判断してくれる [[yii\db\Query::andFilterCompare()]] があります。
```php
$query->andFilterCompare('name', 'John Doe');
$query->andFilterCompare('rating', '>9');
$query->andFilterCompare('value', '<=100');
```
比較演算子を明示的に指定することも可能です。
```php
$query->andFilterCompare('name', 'Doe', 'like');
```
### [[yii\db\Query::orderBy()|orderBy()]] <span id="order-by"></span>
[[yii\db\Query::orderBy()|orderBy()]] メソッドは SQL クエリの `ORDER BY` 句を指定します。例えば、
@ -580,6 +594,13 @@ $query = (new \yii\db\Query())
この無名関数は、現在の行データを含む `$row` というパラメータを取り、現在の行のインデックス値として使われるスカラ値を返さなくてはなりません。
> Note: [[yii\db\Query::groupBy()|groupBy()]] や [[yii\db\Query::orderBy()|orderBy()]]
> のようなクエリメソッドが SQL に変換されてクエリの一部となるのとは対照的に、
> このメソッドはデータベースからデータが取得された後で動作します。
> このことは、クエリの SELECT に含まれるカラム名だけを使うことが出来る、ということを意味します。
> また、テーブルプレフィックスを付けてカラムを選択した場合、例えば `customer.id` を選択した場合は、
> リザルトセットのカラム名は `id` しか含みませんので、テーブルプレフィックス無しで `->indexBy('id')` と呼ぶ必要があります。
## バッチクエリ <span id="batch-query"></span>

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

@ -76,6 +76,10 @@ $form = ActiveForm::begin([
例えば、上記の例における `username` 属性のインプットフィールドの名前は `LoginForm[username]` となります。
この命名規則の結果として、ログインフォームの全ての属性が配列として、サーバ側においては `$_POST['LoginForm']` に格納されて利用できることになります。
> Tip: 一つのフォームに一つのモデルだけがある場合、インプットの名前を単純化したいときは、
> モデルの [[yii\base\Model::formName()|formName()]] メソッドをオーバーライドして空文字列を返すようにして、配列の部分をスキップすることが出来ます。
> この方法を使えば、[GridView](output-data-widgets.md#grid-view) で使われるフィルターモデルで、もっと見栄えの良い URL を生成させることが出来ます。
モデルの属性を指定するために、もっと洗練された方法を使うことも出来ます。
例えば、複数のファイルをアップロードしたり、複数の項目を選択したりする場合に、属性の名前に `[]` を付けて、属性が配列の値を取り得ることを指定することが出来ます。

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

@ -90,6 +90,27 @@ public function rules()
属性は、上記の検証のステップに従って、`scenarios()` でアクティブな属性であると宣言されており、かつ、`rules()` で宣言された一つまたは複数のアクティブな規則と関連付けられている場合に、また、その場合に限って、検証されます。
> Note: 規則に名前を付けると便利です。すなわち、
> ```php
> public function rules()
> {
> return [
> // ...
> 'password' => [['password'], 'string', 'max' => 60],
> ];
> }
> ```
>
> これを子のモデルで使うことが出来ます。
>
> ```php
> public function rules()
> {
> $rules = parent::rules();
> unset($rules['password']);
> return $rules;
> }
### エラーメッセージをカスタマイズする <span id="customizing-error-messages"></span>
@ -526,6 +547,9 @@ JS;
> ]
> ```
> Tip: クライアント側の検証を手動で操作する必要がある場合、すなわち、動的にフィールドを追加したり、何か特殊な UI ロジックを実装する場合は、
> Yii 2.0 Cookbook の [Working with ActiveForm via JavaScript](https://github.com/samdark/yii2-cookbook/blob/master/book/forms-activeform-js.md) を参照してください。
### Deferred 検証 <span id="deferred-validation"></span>
非同期のクライアント側の検証をサポートする必要がある場合は、[Defered オブジェクト](http://api.jquery.com/category/deferred-object/) を作成することが出来ます。

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

@ -102,7 +102,7 @@ echo ListView::widget([
GridView <a name="grid-view"></a>
--------
データグリッドすなわち [[yii\widgets\GridView|GridView]] は Yii の最も強力なウィジェットの一つです。
データグリッドすなわち [[yii\grid\GridView|GridView]] は Yii の最も強力なウィジェットの一つです。
これは、システムの管理セクションを素速く作らねばならない時に、この上なく便利なものです。
このウィジェットは [データプロバイダ](output-data-providers.md) からデータを受けて、テーブルの形式で、行ごとに一組の [[yii\grid\GridView::columns|カラム]] を使ってデータを表示します。
@ -392,6 +392,9 @@ class PostSearch extends Post
```
> Tip: フィルタのクエリを構築する方法を学ぶためには、[クエリビルダ](db-query-builder.md)、
> 中でも特に [フィルタ条件](db-query-builder.md#filter-conditions) を参照してください。
この `search()` メソッドをコントローラで使用して、GridView のためのデータプロバイダを取得することが出来ます。
```php
@ -688,11 +691,11 @@ echo GridView::widget([
### GridView を Pjax とともに使う
[[yii\widgets\Pjax|Pjax]] ウィジェットを使うと、ページ全体をリロードせずに、ページの一部分だけを更新することが出来ます。
これを使うと、フィルタを使うときに、[[yii\widgets\GridView|GridView]] の中身だけを更新することが出来ます。
これを使うと、フィルタを使うときに、[[yii\grid\GridView|GridView]] の中身だけを更新することが出来ます。
```php
use yii\widgets\Pjax;
use yii\widgets\GridView;
use yii\grid\GridView;
Pjax::begin([
// PJax のオプション
@ -704,8 +707,8 @@ Pjax::end();
```
[[yii\widgets\Pjax|Pjax]] は、[[yii\widgets\Pjax::$linkSelector|Pjax::$linkSelector]] の指定に従って、リンクに対しても動作します。
これは [[yii\data\ActionColumn|ActionColumn]] を使う場合には問題となり得ます。
この問題を防止するためには、[[yii\data\ActionColumn::$buttons|ActionColumn::$buttons]]
これは [[yii\grid\ActionColumn|ActionColumn]] を使う場合には問題となり得ます。
この問題を防止するためには、[[yii\grid\ActionColumn::$buttons|ActionColumn::$buttons]]
プロパティを編集して `data-pjax="0"` という HTML 属性を追加します。
#### Gii における Pjax を伴う GridView
@ -718,7 +721,7 @@ yii gii/crud --controllerClass="backend\\controllers\PostController" \
--enablePjax=1
```
これによって、[[yii\widgets\GridView|GridView]] または [[yii\widgets\ListView|ListView]]
これによって、[[yii\grid\GridView|GridView]] または [[yii\widgets\ListView|ListView]]
を囲む [[yii\widgets\Pjax|Pjax]] ウィジェットが生成されます。

2
docs/guide-ja/runtime-sessions-cookies.md

@ -234,6 +234,8 @@ Yii は個々のクッキーを [[yii\web\Cookie]] のオブジェクトとし
[[yii\web\Request]] と [[yii\web\Response]] は、ともに、`cookies` という名前のプロパティによって、クッキーのコレクションを保持します。
後者のクッキーコレクションはリクエストの中で送信されてきたクッキーを表し、一方、後者のクッキーコレクションは、これからユーザに送信されるクッキーを表します。
アプリケーションで、リクエストとレスポンスを直接に操作する部分は、コントローラです。
従って、クッキーの読み出しと送信はコントローラで実行されるべきです。
### クッキーを読み出す <span id="reading-cookies"></span>

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

@ -152,6 +152,43 @@ CSRF を回避するためには、常に次のことを守らなければなり
1. HTTP の規格、すなわち、GET はアプリケーションの状態を変更すべきではない、という規則に従うこと。
2. Yii の CSRF 保護を有効にしておくこと。
場合によっては、コントローラやアクションの単位で 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);
}
}
```
ファイルの曝露を回避する
------------------------
@ -175,3 +212,18 @@ Gii を使うと、データベース構造とコードに関する情報を得
デバッグツールバーは本当に必要でない限り本番環境では使用を避けるべきです。
これはアプリケーションと構成情報の全ての詳細を曝露することが出来ます。
どうしても必要な場合は、あなたの IP だけに適切にアクセス制限されていることを再度チェックしてください。
TLS によるセキュアな接続を使う
------------------------------
Yii が提供する機能には、クッキーや PHP セッションに依存するものがあります。
これらのものは、接続が侵害された場合には、脆弱性となり得ます。
アプリケーションが TLS によるセキュアな接続を使用している場合は、この危険性を減少させることが出来ます。
その設定の仕方については、あなたのウェブサーバのドキュメントの指示を参照してください。
H5BP プロジェクトが提供する構成例を参考にすることも出来ます。
- [Nginx](https://github.com/h5bp/server-configs-nginx)
- [Apache](https://github.com/h5bp/server-configs-apache).
- [IIS](https://github.com/h5bp/server-configs-iis).
- [Lighttpd](https://github.com/h5bp/server-configs-lighttpd).

68
docs/guide-ja/security-cryptography.md

@ -0,0 +1,68 @@
暗号化
======
個の節では、セキュリティの以下の側面について見ていきます。
- 乱数データの生成
- 暗号化と複合化
- データの完全性の確認
擬似乱数データを生成する
------------------------
擬似乱数データはさまざまな状況で役に立ちます。
例えば、メール経由でパスワードをリセットするときは、トークンを生成してデータベースに保存し、それをユーザにメールで送信します。
そして、ユーザはこのトークンを自分がアカウントの所有者であることの証拠として使用します。
このトークンがユニークかつ推測困難なものであることは非常に重要なことです。
さもなくば、攻撃者がトークンの値を推測してユーザのパスワードをリセットする可能性があります。
Yii のセキュリティヘルパは擬似乱数データの生成を単純な作業にしてくれます。
```php
$key = Yii::$app->getSecurity()->generateRandomString();
```
暗号化と復号化
--------------
Yii は秘密鍵を使ってデータを暗号化/復号化することを可能にする便利なヘルパ関数を提供しています。
データを暗号化関数に渡して、秘密鍵を持つ者だけが復号化することが出来るようにすることが出来ます。
例えば、何らかの情報をデータベースに保存する必要があるけれども、(たとえアプリケーションのデータベースが第三者に漏洩した場合でも) 秘密鍵を持つユーザだけがそれを見ることが出来るようにする必要がある、という場合には次のようにします。
```php
// $data と $secretKey はフォームから取得する
$encryptedData = Yii::$app->getSecurity()->encryptByPassword($data, $secretKey);
// $encryptedData をデータベースに保存する
```
そして、後でユーザがデータを読みたいときは、次のようにします。
```php
// $secretKey はユーザ入力から取得、$encryptedData はデータベースから取得
$data = Yii::$app->getSecurity()->decryptByPassword($encryptedData, $secretKey);
```
[[\yii\base\Security::encryptByKey()]] と [[\yii\base\Security::decryptByKey()]] によって、パスワードの代わりにキーを使うことも可能です。
データの完全性を確認する
------------------------
データが第三者によって改竄されたり、更には何らかの形で毀損されたりしていないことを確認する必要がある、という場合があります。
Yii は二つのヘルパ関数の形で、データの完全性を確認するための簡単な方法を提供しています。
秘密鍵とデータから生成されたハッシュをデータにプレフィクスします。
```php
// $secretKey はアプリケーションまたはユーザの秘密、$genuineData は信頼できるソースから取得
$data = Yii::$app->getSecurity()->hashData($genuineData, $secretKey);
```
データの完全性が毀損されていないかチェックします。
```php
// $secretKey はアプリケーションまたはユーザの秘密、$data は信頼できないソースから取得
$data = Yii::$app->getSecurity()->validateData($data, $secretKey);
```

14
docs/guide-ja/security-overview.md

@ -0,0 +1,14 @@
セキュリティ
============
十分なセキュリティは、すべてのアプリケーションの健全さと成功のために欠くことが出来ないものです。
不幸なことに、理解が不足しているためか、実装の難易度が高すぎるためか、セキュリティのことになると手を抜く開発者がたくさんいます。
Yii によって駆動されるあなたのアプリケーションを可能な限り安全にするために、Yii はいくつかの優秀な使いやすいセキュリティ機能を内蔵しています。
* [認証](security-authentication.md)
* [権限付与](security-authorization.md)
* [パスワードを扱う](security-passwords.md)
* [暗号化](security-cryptography.md)
* [ビューのセキュリティ](structure-views.md#security)
* [認証クライアント](https://github.com/yiisoft/yii2-authclient/blob/master/docs/guide-ja/README.md)
* [ベストプラクティス](security-best-practices.md)

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

@ -1,16 +1,6 @@
パスワードを扱う
================
> Note: この節はまだ執筆中です。
十分なセキュリティは、すべてのアプリケーションの健全さと成功のために欠くことが出来ないものです。
不幸なことに、理解が不足しているためか、実装の難易度が高すぎるためか、セキュリティのことになると手を抜く開発者がたくさんいます。
Yii によって駆動されるあなたのアプリケーションを可能な限り安全にするために、Yii はいくつかの優秀な使いやすいセキュリティ機能を内蔵しています。
ハッシュとパスワードの検証
--------------------------
ほとんどの開発者はパスワードを平文テキストで保存してはいけないということを知っていますが、パスワードを `md5``sha1` でハッシュしてもまだ安全だと思っている開発者がたくさんいます。
かつては、前述のハッシュアルゴリズムを使えば十分であった時もありましたが、現代のハードウェアをもってすれば、そのようなハッシュはブルートフォースアタックを使って非常に簡単に復元することが可能です。
@ -38,115 +28,3 @@ if (Yii::$app->getSecurity()->validatePassword($password, $hash)) {
// パスワードが違う
}
```
擬似乱数データを生成する
------------------------
擬似乱数データはさまざまな状況で役に立ちます。
例えば、メール経由でパスワードをリセットするときは、トークンを生成してデータベースに保存し、それをユーザにメールで送信します。
そして、ユーザはこのトークンを自分がアカウントの所有者であることの証拠として使用します。
このトークンがユニークかつ推測困難なものであることは非常に重要なことです。
さもなくば、攻撃者がトークンの値を推測してユーザのパスワードをリセットする可能性があります。
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)

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

@ -203,7 +203,7 @@ server {
location / {
# 本当のファイルでないものは全て index.php にリダイレクト
try_files $uri $uri/ /index.php?$args;
try_files $uri $uri/ /index.php$is_args$args;
}
# 存在しない静的ファイルの呼び出しを Yii に処理させたくない場合はコメントを外す
@ -214,7 +214,7 @@ server {
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass 127.0.0.1:9000;
#fastcgi_pass unix:/var/run/php5-fpm.sock;
try_files $uri =404;

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

@ -330,7 +330,7 @@ class m150811_220037_drop_position_from_post extends Migration
Если имя миграции задано как `create_junction_xxx_and_yyy`, файл будет содержать код для создания промежуточной таблцы.
```php
yii create/migration create_junction_post_and_tag
yii migrate/create create_junction_post_and_tag
```
сгенерирует

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

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

2
docs/guide-ru/structure-application-components.md

@ -16,6 +16,8 @@
Например, вы можете использовать `\Yii::$app->db` для получения [[yii\db\Connection|соединения с БД]],
и `\Yii::$app->cache` для получения доступа к основному компоненту [[yii\caching\Cache|кэша]], зарегистрированному в приложении.
Компонент приложения будет создан при первом обращении к нему через вышеуказанное выражение. Любые дальнейшие обращения будут возвращать тот же экземпляр компонента.
Компонентами приложения могут быть любые объекты. Вы можете зарегистрировать их с помощью
свойства [[yii\base\Application::components]] в [конфигурации](structure-applications.md#application-configurations) приложения.
Например,

3
docs/guide/README.md

@ -109,9 +109,12 @@ Displaying Data
Security
--------
* [Overview](security-overview.md)
* [Authentication](security-authentication.md)
* [Authorization](security-authorization.md)
* [Working with Passwords](security-passwords.md)
* [Cryptography](security-cryptography.md)
* [Views security](structure-views.md#security)
* [Auth Clients](https://github.com/yiisoft/yii2-authclient/blob/master/docs/guide/README.md)
* [Best Practices](security-best-practices.md)

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

@ -303,6 +303,8 @@ You can still override the value set via DI container, though:
echo \yii\widgets\LinkPager::widget(['maxButtonCount' => 20]);
```
> Tip: no matter which value type it is, it will be overwritten so be careful with option arrays. They won't be merged.
Another example is to take advantage of the automatic constructor injection of the DI container.
Assume your controller class depends on some other objects, such as a hotel booking service. You
can declare the dependency through a constructor parameter and let the DI container to resolve it for you.

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

@ -182,7 +182,7 @@ Both methods can take one of the following parameter formats:
- an associative array: the keys are column names and the values are the corresponding desired column values to
be looked for. Please refer to [Hash Format](db-query-builder.md#hash-format) for more details.
The following code shows how theses methods can be used:
The following code shows how these methods can be used:
```php
// returns a single customer whose ID is 123

6
docs/guide/db-migrations.md

@ -414,8 +414,7 @@ The `foreignKey` keyword can take a parameter between parenthesis which will be
the name of the related table for the generated foreign key. If no parameter
is passed then the table name will be deduced from the column name.
In the
example above `author_id:integer:notNull:foreignKey(user)` will generate a
In the example above `author_id:integer:notNull:foreignKey(user)` will generate a
column named `author_id` with a foreign key to the `user` table while
`category_id:integer:defaultValue(1):foreignKey` will generate a column
`category_id` with a foreign key to the `category` table.
@ -715,6 +714,9 @@ these migrations, it will run the `up()` or `safeUp()` method in every new migra
in the order of their timestamp values. If any of the migrations fails, the command will quit without applying
the rest of the migrations.
> Tip: In case you don't have command line at your server you may try [web shell](https://github.com/samdark/yii2-webshell)
> extension.
For each migration that has been successfully applied, the command will insert a row into a database table named
`migration` to record the successful application of the migration. This will allow the migration tool to identify
which migrations have been applied and which have not.

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

@ -351,6 +351,20 @@ Like [[yii\db\Query::andWhere()|andWhere()]] and [[yii\db\Query::orWhere()|orWhe
[[yii\db\Query::andFilterWhere()|andFilterWhere()]] and [[yii\db\Query::orFilterWhere()|orFilterWhere()]]
to append additional filter conditions to the existing one.
Additionally, there is [[yii\db\Query::andFilterCompare()]] that can intelligently determine operator based on what's
in the value:
```php
$query->andFilterCompare('name', 'John Doe');
$query->andFilterCompare('rating', '>9');
$query->andFilterCompare('value', '<=100');
```
You can also specify operator explicitly:
```php
$query->andFilterCompare('name', 'Doe', 'like');
```
### [[yii\db\Query::orderBy()|orderBy()]] <span id="order-by"></span>
@ -620,6 +634,12 @@ $query = (new \yii\db\Query())
The anonymous function takes a parameter `$row` which contains the current row data and should return a scalar
value which will be used as the index value for the current row.
> Note: In contrast to query methods like [[yii\db\Query::groupBy()|groupBy()]] or [[yii\db\Query::orderBy()|orderBy()]]
> which are converted to SQL and are part of the query, this method works after the data has been fetched from the database.
> That means that only those column names can be used that have been part of SELECT in your query.
> Also if you selected a column with table prefix, e.g. `customer.id`, the result set will only contain `id` so you have to call
> `->indexBy('id')` without table prefix.
### Batch Query <span id="batch-query"></span>

25
docs/guide/input-validation.md

@ -96,6 +96,27 @@ According to the above validation steps, an attribute will be validated if and o
an active attribute declared in `scenarios()` and is associated with one or multiple active rules
declared in `rules()`.
> Note: It is handy to give names to rules i.e.
> ```php
> public function rules()
> {
> return [
> // ...
> 'password' => [['password'], 'string', 'max' => 60],
> ];
> }
> ```
>
> You can use it in a child model:
>
> ```php
> public function rules()
> {
> $rules = parent::rules();
> unset($rules['password']);
> return $rules;
> }
### Customizing Error Messages <span id="customizing-error-messages"></span>
@ -556,6 +577,10 @@ JS;
> ]
> ```
> Tip: If you need to work with client validation manually i.e. dynamically add fields or do some custom UI logic, refer
> to [Working with ActiveForm via JavaScript](https://github.com/samdark/yii2-cookbook/blob/master/book/forms-activeform-js.md)
> in Yii 2.0 Cookbook.
### Deferred Validation <span id="deferred-validation"></span>
If you need to perform asynchronous client-side validation, you can create [Deferred objects](http://api.jquery.com/category/deferred-object/).

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

@ -103,7 +103,7 @@ These are then also available as variables in the view.
GridView <a name="grid-view"></a>
--------
Data grid or [[yii\widgets\GridView|GridView]] is one of the most powerful Yii widgets. It is extremely useful if you need to quickly build the admin
Data grid or [[yii\grid\GridView|GridView]] is one of the most powerful Yii widgets. It is extremely useful if you need to quickly build the admin
section of the system. It takes data from a [data provider](output-data-providers.md) and renders each row using a set of [[yii\grid\GridView::columns|columns]]
presenting data in the form of a table.
@ -395,9 +395,11 @@ class PostSearch extends Post
return $dataProvider;
}
}
```
> Tip: See [Query Builder](db-query-builder.md) and especially [Filter Conditions](db-query-builder.md#filter-conditions)
> to learn how to build filtering query.
You can use this function in the controller to get the dataProvider for the GridView:
```php
@ -699,11 +701,11 @@ echo GridView::widget([
The [[yii\widgets\Pjax|Pjax]] widget allows you to update a certain section of a
page instead of reloading the entire page. You can use it to to update only the
[[yii\widgets\GridView|GridView]] content when using filters.
[[yii\grid\GridView|GridView]] content when using filters.
```php
use yii\widgets\Pjax;
use yii\widgets\GridView;
use yii\grid\GridView;
Pjax::begin([
// PJax options
@ -716,9 +718,9 @@ Pjax::end();
Pjax also works for the links inside the [[yii\widgets\Pjax|Pjax]] widget and
for the links specified by [[yii\widgets\Pjax::$linkSelector|Pjax::$linkSelector]].
But this might be a problem for the links of an [[yii\data\ActionColumn|ActionColumn]].
But this might be a problem for the links of an [[yii\grid\ActionColumn|ActionColumn]].
To prevent this, add the HTML attribute `data-pjax="0"` to the links when you edit
the [[yii\data\ActionColumn::$buttons|ActionColumn::$buttons]] property.
the [[yii\grid\ActionColumn::$buttons|ActionColumn::$buttons]] property.
#### GridView/ListView with Pjax in Gii
@ -732,7 +734,7 @@ yii gii/crud --controllerClass="backend\\controllers\PostController" \
```
Which generates a [[yii\widgets\Pjax|Pjax]] widget wrapping the
[[yii\widgets\GridView|GridView]] or [[yii\widgets\ListView|ListView]] widgets.
[[yii\grid\GridView|GridView]] or [[yii\widgets\ListView|ListView]] widgets.
Further reading
---------------

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

@ -247,6 +247,8 @@ maintain a collection of cookies via the property named `cookies`. The cookie co
the cookies submitted in a request, while the cookie collection in the latter represents the cookies that are to
be sent to the user.
The part of the application dealing with request and response directly is controller. Therefore, cookies should be
read and sent in controller.
### Reading Cookies <span id="reading-cookies"></span>

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

@ -148,6 +148,43 @@ In order to avoid CSRF you should always:
1. Follow HTTP specification i.e. GET should not change application state.
2. Keep Yii CSRF protection enabled.
Sometimes you need to disable CSRF validation per controller and/or action. It could be achieved by setting its property:
```php
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
public $enableCsrfValidation = false;
public function actionIndex()
{
// CSRF validation will not be applied to this and other actions
}
}
```
To disable CSRF validation per custom actions you can do:
```php
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
public function beforeAction($action)
{
// ...set `$this->enableCsrfValidation` here based on some conditions...
// call parent method that will check CSRF if such property is true.
return parent::beforeAction($action);
}
}
```
Avoiding file exposure
----------------------
@ -170,3 +207,17 @@ 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 properly restricted to your IP only.
Using secure connection over TLS
--------------------------------
Yii provides features that rely on cookies and/or PHP sessions. These can be vulnerable in case your connection is
compromised. The risk is reduced if the app uses secure connection via TLS.
Please refer to your webserver documentation for instructions on how to configure it. You may also check example configs
provided by H5BP project:
- [Nginx](https://github.com/h5bp/server-configs-nginx)
- [Apache](https://github.com/h5bp/server-configs-apache).
- [IIS](https://github.com/h5bp/server-configs-iis).
- [Lighttpd](https://github.com/h5bp/server-configs-lighttpd).

66
docs/guide/security-cryptography.md

@ -0,0 +1,66 @@
Cryptography
============
In this section we'll review the following security aspects:
- Generating random data
- Encryption and Decryption
- Confirming Data Integrity
Generating Pseudorandom Data
----------------------------
Pseudorandom data is useful in many situations. For example when resetting a password via email you need to generate a
token, save it to the database, and send it via email to end user which in turn will allow them to prove ownership of
that account. It is very important that this token be unique and hard to guess, else there is a possibility that attacker
can predict the token's value and reset the user's password.
Yii security helper makes generating pseudorandom data simple:
```php
$key = Yii::$app->getSecurity()->generateRandomString();
```
Encryption and Decryption
-------------------------
Yii provides convenient helper functions that allow you to encrypt/decrypt data using a secret key. The data is passed through the encryption function so that only the person which has the secret key will be able to decrypt it.
For example, we need to store some information in our database but we need to make sure only the user who has the secret key can view it (even if the application database is compromised):
```php
// $data and $secretKey are obtained from the form
$encryptedData = Yii::$app->getSecurity()->encryptByPassword($data, $secretKey);
// store $encryptedData to database
```
Subsequently when user wants to read the data:
```php
// $secretKey is obtained from user input, $encryptedData is from the database
$data = Yii::$app->getSecurity()->decryptByPassword($encryptedData, $secretKey);
```
It's also possible to use key instead of password via [[\yii\base\Security::encryptByKey()]] and
[[\yii\base\Security::decryptByKey()]].
Confirming Data Integrity
-------------------------
There are situations in which you need to verify that your data hasn't been tampered with by a third party or even corrupted in some way. Yii provides an easy way to confirm data integrity in the form of two helper functions.
Prefix the data with a hash generated from the secret key and data
```php
// $secretKey our application or user secret, $genuineData obtained from a reliable source
$data = Yii::$app->getSecurity()->hashData($genuineData, $secretKey);
```
Checks if the data integrity has been compromised
```php
// $secretKey our application or user secret, $data obtained from an unreliable source
$data = Yii::$app->getSecurity()->validateData($data, $secretKey);
```

14
docs/guide/security-overview.md

@ -0,0 +1,14 @@
Security
========
Good security is vital to the health and success of any application. Unfortunately, many developers cut corners when it
comes to security, either due to a lack of understanding or because implementation is too much of a hurdle. To make your
Yii powered application as secure as possible, Yii has included several excellent and easy to use security features.
* [Authentication](security-authentication.md)
* [Authorization](security-authorization.md)
* [Working with Passwords](security-passwords.md)
* [Cryptography](security-cryptography.md)
* [Views security](structure-views.md#security)
* [Auth Clients](https://github.com/yiisoft/yii2-authclient/blob/master/docs/guide/README.md)
* [Best Practices](security-best-practices.md)

125
docs/guide/security-passwords.md

@ -1,17 +1,14 @@
Working with Passwords
========
======================
> Note: This section is under development.
Most developers know that passwords cannot be stored in plain text, but many developers believe it's still safe to hash
passwords using `md5` or `sha1`. There was a time when using the aforementioned hashing algorithms was sufficient,
but modern hardware makes it possible to reverse such hashes and even stronger ones very quickly using brute force attacks.
Good security is vital to the health and success of any application. Unfortunately, many developers cut corners when it comes to security, either due to a lack of understanding or because implementation is too much of a hurdle. To make your Yii powered application as secure as possible, Yii has included several excellent and easy to use security features.
Hashing and Verifying Passwords
-------------------------------
Most developers know that passwords cannot be stored in plain text, but many developers believe it's still safe to hash passwords using `md5` or `sha1`. There was a time when using the aforementioned hashing algorithms was sufficient, but modern hardware makes it possible to reverse such hashes very quickly using brute force attacks.
In order to provide increased security for user passwords, even in the worst case scenario (your application is breached), you need to use a hashing algorithm that is resilient against brute force attacks. The best current choice is `bcrypt`. In PHP, you can create a `bcrypt` hash using the [crypt function](http://php.net/manual/en/function.crypt.php). Yii provides two helper functions which make using `crypt` to securely generate and verify hashes easier.
In order to provide increased security for user passwords, even in the worst case scenario (your application is breached),
you need to use a hashing algorithm that is resilient against brute force attacks. The best current choice is `bcrypt`.
In PHP, you can create a `bcrypt` hash using the [crypt function](http://php.net/manual/en/function.crypt.php). Yii provides
two helper functions which make using `crypt` to securely generate and verify hashes easier.
When a user provides a password for the first time (e.g., upon registration), the password needs to be hashed:
@ -32,109 +29,3 @@ if (Yii::$app->getSecurity()->validatePassword($password, $hash)) {
// wrong password
}
```
Generating Pseudorandom Data
-----------
Pseudorandom data is useful in many situations. For example when resetting a password via email you need to generate a token, save it to the database, and send it via email to end user which in turn will allow them to prove ownership of that account. It is very important that this token be unique and hard to guess, else there is a possibility that attacker can predict the token's value and reset the user's password.
Yii security helper makes generating pseudorandom data simple:
```php
$key = Yii::$app->getSecurity()->generateRandomString();
```
Note that you need to have the `openssl` extension installed in order to generate cryptographically secure random data.
Encryption and Decryption
-------------------------
Yii provides convenient helper functions that allow you to encrypt/decrypt data using a secret key. The data is passed through the encryption function so that only the person which has the secret key will be able to decrypt it.
For example, we need to store some information in our database but we need to make sure only the user who has the secret key can view it (even if the application database is compromised):
```php
// $data and $secretKey are obtained from the form
$encryptedData = Yii::$app->getSecurity()->encryptByPassword($data, $secretKey);
// store $encryptedData to database
```
Subsequently when user wants to read the data:
```php
// $secretKey is obtained from user input, $encryptedData is from the database
$data = Yii::$app->getSecurity()->decryptByPassword($encryptedData, $secretKey);
```
Confirming Data Integrity
--------------------------------
There are situations in which you need to verify that your data hasn't been tampered with by a third party or even corrupted in some way. Yii provides an easy way to confirm data integrity in the form of two helper functions.
Prefix the data with a hash generated from the secret key and data
```php
// $secretKey our application or user secret, $genuineData obtained from a reliable source
$data = Yii::$app->getSecurity()->hashData($genuineData, $secretKey);
```
Checks if the data integrity has been compromised
```php
// $secretKey our application or user secret, $data obtained from an unreliable source
$data = Yii::$app->getSecurity()->validateData($data, $secretKey);
```
todo: XSS prevention, CSRF prevention, cookie protection, refer to 1.1 guide
You also can disable CSRF validation per controller and/or action, by setting its property:
```php
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
public $enableCsrfValidation = false;
public function actionIndex()
{
// CSRF validation will not be applied to this and other actions
}
}
```
To disable CSRF validation per custom actions you can do:
```php
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
public function beforeAction($action)
{
// ...set `$this->enableCsrfValidation` here based on some conditions...
// call parent method that will check CSRF if such property is true.
return parent::beforeAction($action);
}
}
```
Securing Cookies
----------------
- validation
- httpOnly is default
See also
--------
- [Views security](structure-views.md#security)

4
docs/guide/start-installation.md

@ -208,7 +208,7 @@ server {
location / {
# Redirect everything that isn't a real file to index.php
try_files $uri $uri/ /index.php?$args;
try_files $uri $uri/ /index.php$is_args$args;
}
# uncomment to avoid processing of calls to non-existing static files by Yii
@ -219,7 +219,7 @@ server {
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass 127.0.0.1:9000;
#fastcgi_pass unix:/var/run/php5-fpm.sock;
try_files $uri =404;

4
docs/guide/test-environment-setup.md

@ -20,7 +20,7 @@ You can install it either locally - for particular project only, or globally - f
For the local installation use following commands:
```
composer require "codeception/codeception=2.0.*"
composer require "codeception/codeception=2.1.*"
composer require "codeception/specify=*"
composer require "codeception/verify=*"
```
@ -28,7 +28,7 @@ composer require "codeception/verify=*"
For the global installation you will need to use `global` directive:
```
composer global require "codeception/codeception=2.0.*"
composer global require "codeception/codeception=2.1.*"
composer global require "codeception/specify=*"
composer global require "codeception/verify=*"
```

6
docs/internals-ja/core-code-style.md

@ -484,5 +484,7 @@ public function getEventHandlers($name)
### ディレクトリ/名前空間の名前
- 小文字を使います。
- オブジェクトを表すものには複数形の名詞を使います (例えば、validators)
- 機能や特徴を表す名前には単数形を使います (例えば、web)
- オブジェクトを表すものには複数形の名詞を使います (例えば、validators)。
- 機能や特徴を表す名前には単数形を使います (例えば、web)。
- 出来れば単一の語の名前空間にします。
- 単一の語が適切でない場合は、camelCase を使います。

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

@ -131,7 +131,7 @@ git checkout -b 999-name-of-your-branch-goes-here
### 5. CHANGELOG を更新する
CHANGELOG ファイルを編集して、あなたの修正を追加します。
新しい行は、ファイル冒頭の "Work in progress" 見出しの下に挿入してください。
新しい行は、ファイル冒頭の最初の見出し (現在開発中のバージョン) の下に挿入してください。
チェンジログの行は、下記のどちらかのように書いてください。
```

3
docs/internals/core-code-style.md

@ -486,3 +486,6 @@ Properties allowing to configure component not to do something should accept val
- use lower case
- use plural form for nouns which represent objects (e.g. validators)
- use singular form for names representing relevant functionality/features (e.g. web)
- prefer single word namespaces
- if single word isn't suitable, use camelCase

19
framework/CHANGELOG.md

@ -12,7 +12,26 @@ Yii Framework 2 Change Log
2.0.9 under development
-----------------------
- Enh #8795: Refactored `yii\web\User::loginByCookie()` in order to make it easier to override (maine-mike, silverfire)
- Enh #9948: `yii\rbac\PhpManager` now invalidates script file cache performed by 'OPCache' or 'APC' on file saving (klimov-paul)
- Enh #11195: Added ability to append custom string to schema builder column definition (df2, samdark)
- Enh #11490: Added `yii\data\ArrayDataProvider::$modelClass` property to specify a model used to provide column labels even when data array is empty (PowerGamer1)
- Enh #11591: Added support for wildcards for `only` and `except` at `yii\base\ActionFilter` (klimov-paul)
- Bug #9950: Updated `yii\grid\DataColumn::getHeaderCellLabel()` to extract attribute label from the `filterModel` of Grid (silverfire)
- Bug #11429: Fixed `yii\i18n\PhpMessageSource::loadFallbackMessages()` not to log error when source and language is same, but locales are different (silverfire)
- Enh #11484: Speed up `yii\db\oci\Schema::loadTableSchema()` for Oracle DBMS (SSiwek)
- Enh #11428: Speedup SQL query in `yii\db\oci\Schema::findColumns()` (SSiwek)
- Enh #11414: Files specified as `null` in `yii\web\AssetBundle` won't be registered (Razzwan)
- Enh #11432: Added HTTP status 421 "Misdirected Request" to list of statuses in `yii\web\Response` (dasmfm)
- Enh #11438: Configurable `yii\helpers\Markdown` default flavor (mdmunir)
- Bug #11459: Fixed flash messages not destroyed when `session.auto_start = 1` set in php.ini (cartmanchen)
- Bug #11498: Fixed inability to save serialized object into PostgreSQL binary column (klimov-paul)
- Bug #11507: Fixed `yii\validators\EachValidator::validateAttribute()` does not respect `skipOnEmpty` rule parameter (webdevsega)
- Bug #11523: Fixed `yii\web\User::checkRedirectAcceptable()` to treat acceptable content type `*/*` as `*` (silverfire)
- Bug #11532: Fixed casting of empty char value to `null` resulting in integrity constraint violation for not null columns (samdark)
- Bug #11571: Fixed `yii\db\ColumnSchemaBuilder` to work with custom column types (andrey-mokhov, silverfire)
- Bug #11662: Fixed `schema-oci.sql` for RBAC (jonny7)
- Bug #11527: Fixed `bigPrimaryKey()` for SQLite (dynasource)
2.0.8 April 28, 2016

5
framework/UPGRADE.md

@ -33,6 +33,11 @@ Upgrade to Yii 2.1.0
`yii\db\QueryBuilderbuild::buildGroupBy($columns)` -> `buildGroupBy($columns, &$params)`
`yii\db\QueryBuilderbuild::buildOrderByAndLimit($sql, $orderBy, $limit, $offset)` -> `buildOrderByAndLimit($sql, $orderBy, $limit, $offset, &$params)`
Upgrade from Yii 2.0.8
----------------------
* Part of code from `yii\web\User::loginByCookie()` method was moved to new `getIdentityAndDurationFromCookie()`
and `removeIdentityCookie()` methods. If you override `loginByCookie()` method, update it in order use new methods.
Upgrade from Yii 2.0.7
----------------------

2
framework/assets/yii.gridView.js

@ -123,7 +123,7 @@
var $form = $('<form/>', {
action: url,
method: 'get',
class: 'gridview-filter-form',
'class': 'gridview-filter-form',
style: 'display:none',
'data-pjax': ''
}).appendTo($grid);

28
framework/base/ActionFilter.php

@ -28,6 +28,8 @@ class ActionFilter extends Behavior
* Note that if the filter is attached to a module, the action IDs should also include child module IDs (if any)
* and controller IDs.
*
* Since version 2.0.9 action IDs can be specified as wildcards, e.g. `site/*`.
*
* @see except
*/
public $only;
@ -116,7 +118,8 @@ class ActionFilter extends Behavior
* @return string
* @since 2.0.7
*/
protected function getActionId($action) {
protected function getActionId($action)
{
if ($this->owner instanceof Module) {
$mid = $this->owner->getUniqueId();
$id = $action->getUniqueId();
@ -138,6 +141,27 @@ class ActionFilter extends Behavior
protected function isActive($action)
{
$id = $this->getActionId($action);
return !in_array($id, $this->except, true) && (empty($this->only) || in_array($id, $this->only, true));
if (empty($this->only)) {
$onlyMatch = true;
} else {
$onlyMatch = false;
foreach ($this->only as $pattern) {
if (fnmatch($pattern, $id)) {
$onlyMatch = true;
break;
}
}
}
$exceptMatch = false;
foreach ($this->except as $pattern) {
if (fnmatch($pattern, $id)) {
$exceptMatch = true;
break;
}
}
return !$exceptMatch && $onlyMatch;
}
}

1
framework/base/Configurable.php

@ -29,4 +29,3 @@ namespace yii\base;
interface Configurable
{
}

2
framework/base/Controller.php

@ -50,7 +50,7 @@ class Controller extends Component implements ViewContextInterface
*/
public $defaultAction = 'index';
/**
* @var null|string|boolean the name of the layout to be applied to this controller's views.
* @var null|string|false the name of the layout to be applied to this controller's views.
* This property mainly affects the behavior of [[render()]].
* Defaults to null, meaning the actual layout value should inherit that from [[module]]'s layout value.
* If false, no layout will be applied.

3
framework/behaviors/AttributeBehavior.php

@ -42,6 +42,9 @@ use yii\db\ActiveRecord;
* }
* ```
*
* Because attribute values will be set automatically, it's a good idea to make sure attribute names aren't
* in `rules()` method of the model.
*
* @author Luciano Baraglia <luciano.baraglia@gmail.com>
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0

9
framework/behaviors/BlameableBehavior.php

@ -28,8 +28,13 @@ use yii\db\BaseActiveRecord;
*
* By default, BlameableBehavior will fill the `created_by` and `updated_by` attributes with the current user ID
* when the associated AR object is being inserted; it will fill the `updated_by` attribute
* with the current user ID when the AR object is being updated. If your attribute names are different, you may configure
* the [[createdByAttribute]] and [[updatedByAttribute]] properties like the following:
* with the current user ID when the AR object is being updated.
*
* Because attribute values will be set automatically, it's a good idea to make sure `created_by` and `updated_by` aren't
* in `rules()` method of the model.
*
* If your attribute names are different, you may configure the [[createdByAttribute]] and [[updatedByAttribute]]
* properties like the following:
*
* ```php
* public function behaviors()

8
framework/behaviors/SluggableBehavior.php

@ -34,8 +34,12 @@ use Yii;
* ```
*
* By default, SluggableBehavior will fill the `slug` attribute with a value that can be used a slug in a URL
* when the associated AR object is being validated. If your attribute name is different, you may configure
* the [[slugAttribute]] property like the following:
* when the associated AR object is being validated.
*
* Because attribute value will be set automatically, it's a good idea to make sure `slug` isn't
* in `rules()` method of the model.
*
* If your attribute name is different, you may configure the [[slugAttribute]] property like the following:
*
* ```php
* public function behaviors()

3
framework/behaviors/TimestampBehavior.php

@ -30,6 +30,9 @@ use yii\db\BaseActiveRecord;
* when the associated AR object is being inserted; it will fill the `updated_at` attribute
* with the timestamp when the AR object is being updated. The timestamp value is obtained by `time()`.
*
* Because attribute values will be set automatically, it's a good idea to make sure `created_at` and `updated_at` aren't
* in `rules()` method of the model.
*
* For the above implementation to work with MySQL database, please declare the columns(`created_at`, `updated_at`) as int(11) for being UNIX timestamp.
*
* If your attribute names are different or you want to use a different way of calculating the timestamp,

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

@ -15,6 +15,6 @@ create table "cache"
(
"id" varchar(128) not null,
"expire" integer,
"data" BLOB,
"data" bytea,
primary key ("id")
);

2
framework/captcha/Captcha.php

@ -150,7 +150,7 @@ class Captcha extends InputWidget
$options = [
'refreshUrl' => Url::toRoute($route),
'hashKey' => 'yiiCaptcha/' . trim($route[0], '/')
'hashKey' => 'yiiCaptcha/' . trim($route[0], '/'),
];
return $options;

2
framework/console/ErrorHandler.php

@ -75,4 +75,4 @@ class ErrorHandler extends \yii\base\ErrorHandler
}
return $message;
}
}
}

4
framework/console/controllers/CacheController.php

@ -93,7 +93,7 @@ class CacheController extends Controller
$cachesInfo[] = [
'name' => $name,
'class' => $class,
'is_flushed' => Yii::$app->get($name)->flush(),
'is_flushed' => Yii::$app->get($name)->flush(),
];
}
@ -117,7 +117,7 @@ class CacheController extends Controller
$cachesInfo[] = [
'name' => $name,
'class' => $class,
'is_flushed' => Yii::$app->get($name)->flush(),
'is_flushed' => Yii::$app->get($name)->flush(),
];
}

2
framework/console/controllers/FixtureController.php

@ -77,7 +77,7 @@ class FixtureController extends Controller
{
return array_merge(parent::optionAliases(), [
'g' => 'globalFixtures',
'n' => 'namespace'
'n' => 'namespace',
]);
}

34
framework/console/controllers/MessageController.php

@ -141,22 +141,22 @@ class MessageController extends Controller
public function options($actionID)
{
return array_merge(parent::options($actionID), [
'sourcePath',
'messagePath',
'languages',
'translator',
'sort',
'overwrite',
'removeUnused',
'markUnused',
'except',
'only',
'format',
'db',
'sourceMessageTable',
'messageTable',
'catalog',
'ignoreCategories'
'sourcePath',
'messagePath',
'languages',
'translator',
'sort',
'overwrite',
'removeUnused',
'markUnused',
'except',
'only',
'format',
'db',
'sourceMessageTable',
'messageTable',
'catalog',
'ignoreCategories',
]);
}
@ -180,7 +180,7 @@ class MessageController extends Controller
't' => 'translator',
'm' => 'sourceMessageTable',
's' => 'sourcePath',
'r' => 'removeUnused'
'r' => 'removeUnused',
]);
}

4
framework/console/controllers/MigrateController.php

@ -80,7 +80,7 @@ class MigrateController extends BaseMigrateController
'drop_table' => '@yii/views/dropTableMigration.php',
'add_column' => '@yii/views/addColumnMigration.php',
'drop_column' => '@yii/views/dropColumnMigration.php',
'create_junction' => '@yii/views/createTableMigration.php'
'create_junction' => '@yii/views/createTableMigration.php',
];
/**
* @var boolean indicates whether the table names generated should consider
@ -295,7 +295,7 @@ class MigrateController extends BaseMigrateController
$foreignKeys[$column] = [
'idx' => $this->generateTableName("idx-$table-$column"),
'fk' => $this->generateTableName("fk-$table-$column"),
'relatedTable' => $this->generateTableName($relatedTable)
'relatedTable' => $this->generateTableName($relatedTable),
];
}

2
framework/console/controllers/ServeController.php

@ -103,7 +103,7 @@ class ServeController extends Controller
return array_merge(parent::optionAliases(), [
't' => 'docroot',
'p' => 'port',
'r' => 'router'
'r' => 'router',
]);
}

7
framework/data/ArrayDataProvider.php

@ -63,7 +63,12 @@ class ArrayDataProvider extends BaseDataProvider
* The array elements must use zero-based integer keys.
*/
public $allModels;
/**
* @var string the name of the [[yii\base\Model|Model]] class that will be represented.
* This property is used to get columns' names.
* @since 2.0.9
*/
public $modelClass;
/**
* @inheritdoc

2
framework/db/ActiveQuery.php

@ -405,7 +405,7 @@ class ActiveQuery extends Query implements ActiveQueryInterface
// relation is defined with an alias, adjust callback to apply alias
list(, $relation, $alias) = $matches;
$name = $relation;
$callback = function($query) use ($callback, $alias) {
$callback = function ($query) use ($callback, $alias) {
/** @var $query ActiveQuery */
$query->alias($alias);
if ($callback !== null) {

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

Loading…
Cancel
Save