Compare commits

..

3 Commits

Author SHA1 Message Date
Carsten Brandt 6d2f0837fc improved memory assertation 9 years ago
Carsten Brandt c73b116ba5 batch query result test for pgsql and sqlite 9 years ago
Carsten Brandt 0a88d4b0b7 [WIP] added batch query test for big table 9 years ago
  1. 41
      .appveyor.yml
  2. 32
      .codeclimate.yml
  3. 3
      .dockerignore
  4. 1
      .eslintignore
  5. 213
      .eslintrc
  6. 11
      .gitattributes
  7. 7
      .github/CONTRIBUTING.md
  8. 5
      .github/FUNDING.yml
  9. 19
      .github/ISSUE_TEMPLATE.md
  10. 6
      .github/PULL_REQUEST_TEMPLATE.md
  11. 6
      .github/SECURITY.md
  12. 113
      .github/workflows/build.yml
  13. 103
      .github/workflows/ci-mssql.yml
  14. 80
      .github/workflows/ci-mysql.yml
  15. 81
      .github/workflows/ci-oracle.yml
  16. 84
      .github/workflows/ci-pgsql.yml
  17. 16
      .gitignore
  18. 113
      .gitlab-ci.yml
  19. 27
      .php_cs
  20. 22
      .scrutinizer.yml
  21. 65
      .travis.yml
  22. 7
      CONTRIBUTING.md
  23. 13
      Dockerfile
  24. 3
      LICENSE.md
  25. 104
      README.md
  26. 27
      ROADMAP.md
  27. 4
      build/build
  28. 2
      build/controllers/ClassmapController.php
  29. 98
      build/controllers/DevController.php
  30. 88
      build/controllers/MimeTypeController.php
  31. 431
      build/controllers/PhpDocController.php
  32. 910
      build/controllers/ReleaseController.php
  33. 13
      build/controllers/TranslationController.php
  34. 126
      build/controllers/Utf8Controller.php
  35. 73
      code-of-conduct.md
  36. 65
      composer.json
  37. 2727
      composer.lock
  38. 60
      contrib/completion/bash/yii
  39. 40
      contrib/completion/zsh/_yii
  40. 1
      cs/TODO.md
  41. 172
      cs/src/YiiConfig.php
  42. 39
      cs/src/YiisoftConfig.php
  43. 39
      docs/documentation_style_guide.md
  44. 205
      docs/guide-ar/README.md
  45. 57
      docs/guide-ar/intro-yii.md
  46. 290
      docs/guide-ar/start-databases.md
  47. 253
      docs/guide-ar/start-forms.md
  48. 161
      docs/guide-ar/start-gii.md
  49. 149
      docs/guide-ar/start-hello.md
  50. 303
      docs/guide-ar/start-installation.md
  51. 36
      docs/guide-ar/start-looking-ahead.md
  52. 25
      docs/guide-ar/start-prerequisites.md
  53. 115
      docs/guide-ar/start-workflow.md
  54. 2
      docs/guide-de/README.md
  55. 3
      docs/guide-de/translators.json
  56. 3
      docs/guide-es/README.md
  57. 22
      docs/guide-es/caching-data.md
  58. 6
      docs/guide-es/caching-http.md
  59. 33
      docs/guide-es/concept-aliases.md
  60. 8
      docs/guide-es/concept-autoloading.md
  61. 30
      docs/guide-es/concept-behaviors.md
  62. 16
      docs/guide-es/concept-components.md
  63. 10
      docs/guide-es/concept-configurations.md
  64. 18
      docs/guide-es/concept-di-container.md
  65. 20
      docs/guide-es/concept-events.md
  66. 10
      docs/guide-es/concept-properties.md
  67. 26
      docs/guide-es/db-dao.md
  68. 939
      docs/guide-es/db-migrations.md
  69. 2
      docs/guide-es/db-query-builder.md
  70. 67
      docs/guide-es/glossary.md
  71. 145
      docs/guide-es/helper-array.md
  72. 8
      docs/guide-es/helper-html.md
  73. 71
      docs/guide-es/helper-url.md
  74. 527
      docs/guide-es/images/application-lifecycle.graphml
  75. BIN
      docs/guide-es/images/application-lifecycle.png
  76. 368
      docs/guide-es/images/rbac-access-check-1.graphml
  77. BIN
      docs/guide-es/images/rbac-access-check-1.png
  78. 368
      docs/guide-es/images/rbac-access-check-2.graphml
  79. BIN
      docs/guide-es/images/rbac-access-check-2.png
  80. 368
      docs/guide-es/images/rbac-access-check-3.graphml
  81. BIN
      docs/guide-es/images/rbac-access-check-3.png
  82. 312
      docs/guide-es/images/rbac-hierarchy-1.graphml
  83. BIN
      docs/guide-es/images/rbac-hierarchy-1.png
  84. 368
      docs/guide-es/images/rbac-hierarchy-2.graphml
  85. BIN
      docs/guide-es/images/rbac-hierarchy-2.png
  86. BIN
      docs/guide-es/images/tutorial-console-help.png
  87. 208
      docs/guide-es/input-file-upload.md
  88. 85
      docs/guide-es/input-multiple-models.md
  89. 715
      docs/guide-es/input-validation.md
  90. 76
      docs/guide-es/intro-upgrade-from-v1.md
  91. 44
      docs/guide-es/intro-yii.md
  92. 98
      docs/guide-es/output-client-scripts.md
  93. 421
      docs/guide-es/output-data-providers.md
  94. 245
      docs/guide-es/output-data-widgets.md
  95. 72
      docs/guide-es/output-pagination.md
  96. 2
      docs/guide-es/output-theming.md
  97. 54
      docs/guide-es/rest-authentication.md
  98. 8
      docs/guide-es/rest-controllers.md
  99. 19
      docs/guide-es/rest-error-handling.md
  100. 2
      docs/guide-es/rest-quick-start.md
  101. Some files were not shown because too many files have changed in this diff Show More

41
.appveyor.yml

@ -1,41 +0,0 @@
build: false
version: dev-{build}
clone_folder: C:\projects\yii2
environment:
matrix:
- php_ver: 7.2.4
cache:
- '%APPDATA%\Composer'
- '%LOCALAPPDATA%\Composer'
- C:\tools\php -> .appveyor.yml
- C:\tools\composer.phar -> .appveyor.yml
init:
- SET PATH=C:\tools\php;%PATH%
install:
- ps: Set-Service wuauserv -StartupType Manual
- IF NOT EXIST C:\tools\php (choco install --yes --allow-empty-checksums php --version %php_ver% --params '/InstallDir:C:\tools\php')
- cd C:\tools\php
- copy php.ini-production php.ini
- echo date.timezone="UTC" >> php.ini
- echo memory_limit=512M >> php.ini
- echo extension_dir=ext >> php.ini
- echo extension=php_curl.dll >> php.ini
- echo extension=php_fileinfo.dll >> php.ini
- echo extension=php_gd2.dll >> php.ini
- echo extension=php_intl.dll >> php.ini
- echo extension=php_mbstring.dll >> php.ini
- echo extension=php_openssl.dll >> php.ini
- echo extension=php_pdo_sqlite.dll >> php.ini
- IF NOT EXIST C:\tools\composer.phar (cd C:\tools && appveyor DownloadFile https://getcomposer.org/download/1.4.1/composer.phar)
before_test:
- cd C:\projects\yii2
- php C:\tools\composer.phar update --no-interaction --no-progress --prefer-stable --no-ansi
test_script:
- cd C:\projects\yii2
- vendor\bin\phpunit --exclude-group mssql,mysql,pgsql,sqlite,db,oci,wincache,xcache,zenddata,cubrid

32
.codeclimate.yml

@ -1,32 +0,0 @@
engines:
duplication:
enabled: true
config:
languages:
- javascript
- php
eslint:
enabled: true
fixme:
enabled: true
phpmd:
enabled: true
config:
rulesets: "codesize,design,unusedcode,tests/data/codeclimate/phpmd_ruleset.xml"
ratings:
paths:
- "**.js"
- "**.php"
exclude_paths:
- tests/
- build/
- docs/
- framework/messages/
checks:
file-lines:
enabled: false
method-count:
enabled: false
method-lines:
enabled: false

3
.dockerignore

@ -1,3 +0,0 @@
.git
vendor
docs

1
.eslintignore

@ -1 +0,0 @@
**/*{.,-}min.js

213
.eslintrc

@ -1,213 +0,0 @@
ecmaFeatures:
modules: true
jsx: true
env:
amd: true
browser: true
es6: true
jquery: true
node: true
# http://eslint.org/docs/rules/
rules:
# Possible Errors
comma-dangle: [2, never]
no-cond-assign: 2
no-console: 0
no-constant-condition: 2
no-control-regex: 2
no-debugger: 2
no-dupe-args: 2
no-dupe-keys: 2
no-duplicate-case: 2
no-empty: 2
no-empty-character-class: 2
no-ex-assign: 2
no-extra-boolean-cast: 2
no-extra-parens: 0
no-extra-semi: 2
no-func-assign: 2
no-inner-declarations: [2, functions]
no-invalid-regexp: 2
no-irregular-whitespace: 2
no-negated-in-lhs: 2
no-obj-calls: 2
no-regex-spaces: 2
no-sparse-arrays: 2
no-unexpected-multiline: 2
no-unreachable: 2
use-isnan: 2
valid-jsdoc: 0
valid-typeof: 2
# Best Practices
accessor-pairs: 2
block-scoped-var: 0
complexity: [2, 6]
consistent-return: 0
curly: 0
default-case: 0
dot-location: 0
dot-notation: 0
eqeqeq: 2
guard-for-in: 2
no-alert: 2
no-caller: 2
no-case-declarations: 2
no-div-regex: 2
no-else-return: 0
no-empty-label: 2
no-empty-pattern: 2
no-eq-null: 2
no-eval: 2
no-extend-native: 2
no-extra-bind: 2
no-fallthrough: 2
no-floating-decimal: 0
no-implicit-coercion: 0
no-implied-eval: 2
no-invalid-this: 0
no-iterator: 2
no-labels: 0
no-lone-blocks: 2
no-loop-func: 2
no-magic-number: 0
no-multi-spaces: 0
no-multi-str: 0
no-native-reassign: 2
no-new-func: 2
no-new-wrappers: 2
no-new: 2
no-octal-escape: 2
no-octal: 2
no-proto: 2
no-redeclare: 2
no-return-assign: 2
no-script-url: 2
no-self-compare: 2
no-sequences: 0
no-throw-literal: 0
no-unused-expressions: 2
no-useless-call: 2
no-useless-concat: 2
no-void: 2
no-warning-comments: 0
no-with: 2
radix: 2
vars-on-top: 0
wrap-iife: 2
yoda: 0
# Strict
strict: 0
# Variables
init-declarations: 0
no-catch-shadow: 2
no-delete-var: 2
no-label-var: 2
no-shadow-restricted-names: 2
no-shadow: 0
no-undef-init: 2
no-undef: 0
no-undefined: 0
no-unused-vars: 0
no-use-before-define: 0
# Node.js and CommonJS
callback-return: 2
global-require: 2
handle-callback-err: 2
no-mixed-requires: 0
no-new-require: 0
no-path-concat: 2
no-process-exit: 2
no-restricted-modules: 0
no-sync: 0
# Stylistic Issues
array-bracket-spacing: 0
block-spacing: 0
brace-style: 0
camelcase: 0
comma-spacing: 0
comma-style: 0
computed-property-spacing: 0
consistent-this: 0
eol-last: 0
func-names: 0
func-style: 0
id-length: 0
id-match: 0
indent: 0
jsx-quotes: 0
key-spacing: 0
linebreak-style: 0
lines-around-comment: 0
max-depth: 0
max-len: 0
max-nested-callbacks: 0
max-params: 0
max-statements: [2, 30]
new-cap: 0
new-parens: 0
newline-after-var: 0
no-array-constructor: 0
no-bitwise: 0
no-continue: 0
no-inline-comments: 0
no-lonely-if: 0
no-mixed-spaces-and-tabs: 0
no-multiple-empty-lines: 0
no-negated-condition: 0
no-nested-ternary: 0
no-new-object: 0
no-plusplus: 0
no-restricted-syntax: 0
no-spaced-func: 0
no-ternary: 0
no-trailing-spaces: 0
no-underscore-dangle: 0
no-unneeded-ternary: 0
object-curly-spacing: 0
one-var: 0
operator-assignment: 0
operator-linebreak: 0
padded-blocks: 0
quote-props: 0
quotes: 0
require-jsdoc: 0
semi-spacing: 0
semi: 0
sort-vars: 0
space-after-keywords: 0
space-before-blocks: 0
space-before-function-paren: 0
space-before-keywords: 0
space-in-parens: 0
space-infix-ops: 0
space-return-throw-case: 0
space-unary-ops: 0
spaced-comment: 0
wrap-regex: 0
# ECMAScript 6
arrow-body-style: 0
arrow-parens: 0
arrow-spacing: 0
constructor-super: 0
generator-star-spacing: 0
no-arrow-condition: 0
no-class-assign: 0
no-const-assign: 0
no-dupe-class-members: 0
no-this-before-super: 0
no-var: 0
object-shorthand: 0
prefer-arrow-callback: 0
prefer-const: 0
prefer-reflect: 0
prefer-spread: 0
prefer-template: 0
require-yield: 0

11
.gitattributes vendored

@ -13,6 +13,7 @@
*.json text
*.bat text
*.sql text
*.xml text
*.yml text
# Ensure those won't be messed up with
@ -21,16 +22,16 @@
*.gif binary
*.ttf binary
# Ignore some meta files when creating an archive of this repository
# We do not ignore any content, because this repo represents the
# `yiisoft/yii2-dev` package, which is expected to ship all tests and docs.
/.appveyor.yml export-ignore
/.github export-ignore
# Ignore all test and documentation for archive
/.editorconfig export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
/.scrutinizer.yml export-ignore
/.travis.yml export-ignore
/phpunit.xml.dist export-ignore
/tests export-ignore
/docs export-ignore
/build export-ignore
# Avoid merge conflicts in CHANGELOG
# https://about.gitlab.com/2015/02/10/gitlab-reduced-merge-conflicts-by-90-percent-with-changelog-placeholders/

7
.github/CONTRIBUTING.md

@ -1,7 +0,0 @@
Contributing to Yii 2
=====================
- [Report an issue](../docs/internals/report-an-issue.md)
- [Translate documentation or messages](../docs/internals/translation-workflow.md)
- [Give us feedback or start a design discussion](http://www.yiiframework.com/forum/index.php/forum/42-general-discussions-for-yii-20/)
- [Contribute to the core code or fix bugs](../docs/internals/git-workflow.md)

5
.github/FUNDING.yml

@ -1,5 +0,0 @@
# These are supported funding model platforms
open_collective: yiisoft
github: [yiisoft]
tidelift: "packagist/yiisoft/yii2"

19
.github/ISSUE_TEMPLATE.md

@ -1,19 +0,0 @@
<!--
Please use this issue tracker for bugs and feature requests only. In case you need support please use one of
Yii communities listed at https://github.com/yiisoft/yii2/wiki/communities
-->
### What steps will reproduce the problem?
### What is the expected result?
### What do you get instead?
### Additional info
| Q | A
| ---------------- | ---
| Yii version | 2.0.?
| PHP version |
| Operating system |

6
.github/PULL_REQUEST_TEMPLATE.md

@ -1,6 +0,0 @@
| Q | A
| ------------- | ---
| Is bugfix? | ✔/❌
| New feature? | ✔/❌
| Breaks BC? | ✔/❌
| Fixed issues | <!-- comma-separated list of tickets # fixed by the PR, if any -->

6
.github/SECURITY.md

@ -1,6 +0,0 @@
# Security Policy
Please use the [security issue form](https://www.yiiframework.com/security) to report to us any security issue you find in Yii.
DO NOT use the issue tracker or discuss it in the public forum as it will cause more damage than help.
Please note that as a non-commercial OpenSource project we are not able to pay bounties at the moment.

113
.github/workflows/build.yml

@ -1,113 +0,0 @@
name: build
on: [push, pull_request]
env:
DEFAULT_COMPOSER_FLAGS: "--prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi"
PHPUNIT_EXCLUDE_GROUP: mssql,oci,wincache,xcache,zenddata,cubrid
XDEBUG_MODE: coverage, develop
jobs:
phpunit:
name: PHP ${{ matrix.php }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
services:
mysql:
image: mysql:5.7
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: yiitest
ports:
- 3306:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
postgres:
image: postgres:9.6
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: yiitest
ports:
- 5432:5432
options: --name=postgres --health-cmd="pg_isready" --health-interval=10s --health-timeout=5s --health-retries=3
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
php: ['5.4', '5.5', '5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1']
steps:
- name: Generate french locale
run: sudo locale-gen fr_FR.UTF-8
- name: Checkout
uses: actions/checkout@v2
- name: Install PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
tools: pecl
extensions: apc, curl, dom, imagick, intl, mbstring, mcrypt, memcached, mysql, pdo, pdo_mysql, pdo_pgsql, pdo_sqlite, pgsql, sqlite
ini-values: date.timezone='UTC', session.save_path="${{ runner.temp }}"
- name: Install Memcached
uses: niden/actions-memcached@v7
- name: Get composer cache directory
id: composer-cache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: Cache composer dependencies
uses: actions/cache@v1
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-
- name: Install dependencies
run: composer update $DEFAULT_COMPOSER_FLAGS
- name: PHP Unit tests for PHP 7.1
run: vendor/bin/phpunit --verbose --coverage-clover=coverage.clover --exclude-group $PHPUNIT_EXCLUDE_GROUP --colors=always
if: matrix.php == '7.1'
- name: PHP Unit tests for PHP >= 7.2
run: vendor/bin/phpunit --verbose --exclude-group $PHPUNIT_EXCLUDE_GROUP --colors=always
env:
PHPUNIT_EXCLUDE_GROUP: mssql,oci,wincache,xcache,zenddata,cubrid
if: matrix.php >= '7.2'
- name: PHP Unit tests for PHP <= 7.0
run: vendor/bin/phpunit --verbose --exclude-group $PHPUNIT_EXCLUDE_GROUP --colors=always
if: matrix.php <= '7.0'
- name: Code coverage
run: |
wget https://scrutinizer-ci.com/ocular.phar
php ocular.phar code-coverage:upload --format=php-clover coverage.clover
if: matrix.php == '7.1'
continue-on-error: true # if is fork
npm:
name: NPM 6 on ubuntu-latest
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Install PHP
uses: shivammathur/setup-php@v2
with:
php-version: 7.2
ini-values: session.save_path=${{ runner.temp }}
- name: Get composer cache directory
id: composer-cache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: Cache composer dependencies
uses: actions/cache@v1
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-
- name: Install dependencies
run: composer update $DEFAULT_COMPOSER_FLAGS
- name: Install node.js
uses: actions/setup-node@v1
with:
node-version: 6
- name: Tests
run: |
npm install
npm test
# env:
# CI: true

103
.github/workflows/ci-mssql.yml

@ -1,103 +0,0 @@
on:
- pull_request
- push
name: ci-mssql
jobs:
tests:
name: PHP ${{ matrix.php }}-mssql-${{ matrix.mssql }}
env:
key: cache
runs-on: ubuntu-latest
strategy:
matrix:
include:
- php: '7.0'
extensions: pdo, pdo_sqlsrv-5.8.1
mssql: 'server:2017-latest'
- php: '7.1'
extensions: pdo, pdo_sqlsrv-5.8.1
mssql: 'server:2017-latest'
- php: '7.2'
extensions: pdo, pdo_sqlsrv-5.8.1
mssql: 'server:2017-latest'
- php: '7.3'
extensions: pdo, pdo_sqlsrv-5.8.1
mssql: 'server:2017-latest'
- php: '7.4'
extensions: pdo, pdo_sqlsrv
mssql: 'server:2017-latest'
- php: '7.4'
extensions: pdo, pdo_sqlsrv
mssql: 'server:2019-latest'
- php: '8.0'
extensions: pdo, pdo_sqlsrv
mssql: 'server:2017-latest'
- php: '8.0'
extensions: pdo, pdo_sqlsrv
mssql: 'server:2019-latest'
services:
mssql:
image: mcr.microsoft.com/mssql/${{ matrix.mssql }}
env:
SA_PASSWORD: YourStrong!Passw0rd
ACCEPT_EULA: Y
MSSQL_PID: Developer
ports:
- 1433:1433
options: --name=mssql --health-cmd="/opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P 'YourStrong!Passw0rd' -Q 'SELECT 1'" --health-interval=10s --health-timeout=5s --health-retries=3
steps:
- name: Checkout
uses: actions/checkout@v2.3.4
- name: Create MS SQL Database
run: docker exec -i mssql /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P 'YourStrong!Passw0rd' -Q 'CREATE DATABASE yiitest'
- name: Install PHP with extensions
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: ${{ matrix.extensions }}
ini-values: date.timezone='UTC'
tools: composer:v2, pecl
- name: Determine composer cache directory on Linux
run: echo "COMPOSER_CACHE_DIR=$(composer config cache-dir)" >> $GITHUB_ENV
- name: Cache dependencies installed with composer
uses: actions/cache@v2
with:
path: ${{ env.COMPOSER_CACHE_DIR }}
key: php${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}
restore-keys: |
php${{ matrix.php }}-composer-
- name: Update composer
run: composer self-update
- name: Install dependencies with composer
run: composer update --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi
- name: Install dependencies with composer php 8.0
if: matrix.php == '8.0'
run: composer update --ignore-platform-reqs --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi
- name: PHP Unit tests for PHP 7.1
run: vendor/bin/phpunit --coverage-clover=coverage.clover --group mssql --colors=always
if: matrix.php == '7.1'
- name: Run tests with phpunit without coverage
run: vendor/bin/phpunit --group mssql --colors=always
- name: Code coverage
run: |
wget https://scrutinizer-ci.com/ocular.phar
php ocular.phar code-coverage:upload --format=php-clover coverage.clover
if: matrix.php == '7.1'
continue-on-error: true # if is fork

80
.github/workflows/ci-mysql.yml

@ -1,80 +0,0 @@
on:
- pull_request
- push
name: ci-mysql
jobs:
tests:
name: PHP ${{ matrix.php-version }}-mysql-${{ matrix.mysql-version }}
env:
extensions: curl, intl, pdo, pdo_mysql
key: cache-v1
runs-on: ${{ matrix.os }}
strategy:
matrix:
os:
- ubuntu-latest
php-version:
- "7.4"
mysql-version:
- "latest"
services:
mysql:
image: mysql:${{ matrix.mysql-version }}
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: yiitest
ports:
- 3306:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup cache environment
id: cache-env
uses: shivammathur/cache-extensions@v1
with:
php-version: ${{ matrix.php-version }}
extensions: ${{ env.extensions }}
key: ${{ env.key }}
- name: Cache extensions
uses: actions/cache@v1
with:
path: ${{ steps.cache-env.outputs.dir }}
key: ${{ steps.cache-env.outputs.key }}
restore-keys: ${{ steps.cache-env.outputs.key }}
- name: Install PHP with extensions
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
extensions: ${{ env.extensions }}
ini-values: date.timezone='UTC'
coverage: pcov
- name: Determine composer cache directory
if: matrix.os == 'ubuntu-latest'
run: echo "COMPOSER_CACHE_DIR=$(composer config cache-dir)" >> $GITHUB_ENV
- name: Cache dependencies installed with composer
uses: actions/cache@v1
with:
path: ${{ env.COMPOSER_CACHE_DIR }}
key: php${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-${{ hashFiles('**/composer.json') }}
restore-keys: |
php${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-
- name: Install dependencies with composer
run: composer update --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi
- name: Run mysql tests with phpunit
run: vendor/bin/phpunit --group mysql --colors=always

81
.github/workflows/ci-oracle.yml

@ -1,81 +0,0 @@
on:
- pull_request
- push
name: ci-oracle
jobs:
tests:
name: PHP ${{ matrix.php }}-${{ matrix.os }}
env:
extensions: oci8, pdo, pdo_oci
key: cache-v1
runs-on: ${{ matrix.os }}
strategy:
matrix:
os:
- ubuntu-latest
php:
- "7.4"
services:
oci:
image: wnameless/oracle-xe-11g-r2:latest
ports:
- 1521:1521
options: --name=oci
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup cache environment
id: cache-env
uses: shivammathur/cache-extensions@v1
with:
php-version: ${{ matrix.php }}
extensions: ${{ env.extensions }}
key: ${{ env.key }}
- name: Cache extensions
uses: actions/cache@v1
with:
path: ${{ steps.cache-env.outputs.dir }}
key: ${{ steps.cache-env.outputs.key }}
restore-keys: ${{ steps.cache-env.outputs.key }}
- name: Install PHP with extensions
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: ${{ env.extensions }}
ini-values: date.timezone='UTC'
coverage: pcov
tools: composer:v2, pecl
- name: Determine composer cache directory
run: echo "COMPOSER_CACHE_DIR=$(composer config cache-dir)" >> $GITHUB_ENV
- name: Cache dependencies installed with composer
uses: actions/cache@v2
with:
path: ${{ env.COMPOSER_CACHE_DIR }}
key: php${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }}
restore-keys: |
php${{ matrix.php }}-composer-
- name: Install dependencies with composer
run: composer update --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi
- name: PHP Unit tests
run: vendor/bin/phpunit --coverage-clover=coverage.clover --group oci --colors=always
- name: Code coverage
run: |
wget https://scrutinizer-ci.com/ocular.phar
php ocular.phar code-coverage:upload --format=php-clover coverage.clover
continue-on-error: true # if is fork

84
.github/workflows/ci-pgsql.yml

@ -1,84 +0,0 @@
on:
- pull_request
- push
name: ci-pgsql
jobs:
tests:
name: PHP ${{ matrix.php-version }}-pgsql-${{ matrix.pgsql-version }}
env:
extensions: curl, intl, pdo, pdo_pgsql
key: cache-v1
runs-on: ${{ matrix.os }}
strategy:
matrix:
os:
- ubuntu-latest
php-version:
- "7.4"
pgsql-version:
- "10"
- "11"
- "12"
- "13"
services:
postgres:
image: postgres:${{ matrix.pgsql-version }}
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: yiitest
ports:
- 5432:5432
options: --name=postgres --health-cmd="pg_isready" --health-interval=10s --health-timeout=5s --health-retries=3
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup cache environment
id: cache-env
uses: shivammathur/cache-extensions@v1
with:
php-version: ${{ matrix.php-version }}
extensions: ${{ env.extensions }}
key: ${{ env.key }}
- name: Cache extensions
uses: actions/cache@v1
with:
path: ${{ steps.cache-env.outputs.dir }}
key: ${{ steps.cache-env.outputs.key }}
restore-keys: ${{ steps.cache-env.outputs.key }}
- name: Install PHP with extensions
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
extensions: ${{ env.extensions }}
ini-values: date.timezone='UTC'
coverage: pcov
- name: Determine composer cache directory
if: matrix.os == 'ubuntu-latest'
run: echo "COMPOSER_CACHE_DIR=$(composer config cache-dir)" >> $GITHUB_ENV
- name: Cache dependencies installed with composer
uses: actions/cache@v1
with:
path: ${{ env.COMPOSER_CACHE_DIR }}
key: php${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-${{ hashFiles('**/composer.json') }}
restore-keys: |
php${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-
- name: Install dependencies with composer
run: composer update --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi
- name: Run pgsql tests with phpunit
run: vendor/bin/phpunit --group pgsql --colors=always

16
.gitignore vendored

@ -1,6 +1,5 @@
# phpstorm project files
.idea
*.iml
# netbeans project files
nbproject
@ -10,13 +9,6 @@ nbproject
.project
.settings
# sublime text project / workspace files
*.sublime-project
*.sublime-workspace
# visual studio code project files
.vscode
# windows thumbnail cache
Thumbs.db
@ -39,12 +31,6 @@ phpunit.phar
# local phpunit config
/phpunit.xml
# ignore dev installed apps and extensions
# ignore sub directory for dev installed apps and extensions
/apps
/extensions
/packages
# NPM packages
/node_modules
.env
package-lock.json

113
.gitlab-ci.yml

@ -1,113 +0,0 @@
image: docker:latest
services:
- docker:dind
variables:
DOCKER_YII2_PHP_IMAGE: yiisoftware/yii2-php:7.4-apache
DOCKER_MYSQL_IMAGE: percona:5.7
DOCKER_POSTGRES_IMAGE: postgres:9.3
before_script:
- apk add --no-cache git curl docker-compose
- docker info
- cd tests
stages:
- travis
- test
- cleanup
test:
stage: test
script:
- docker-compose up --build -d
- docker-compose run --rm php vendor/bin/phpunit -v --exclude caching,db,data --log-junit tests/_junit/test.xml
caching:
stage: test
only:
- tests/caching
- tests/full
script:
- export COMPOSE_FILE=docker-compose.yml:docker-compose.${CI_BUILD_NAME}.yml
- docker-compose up --build -d
- docker-compose run --rm php vendor/bin/phpunit -v --group caching --exclude db
db:
stage: test
only:
- tests/mysql
- tests/full
script:
- docker-compose up --build -d
- docker-compose run --rm php vendor/bin/phpunit -v --group db --exclude caching,mysql,pgsql,mssql,cubrid,oci
mysql:
stage: test
only:
- tests/mysql
- tests/full
script:
- export COMPOSE_FILE=docker-compose.yml:docker-compose.${CI_BUILD_NAME}.yml
- docker-compose up --build -d
# wait for db (retry X times)
- docker-compose run --rm php bash -c "while ! curl mysql:3306; do ((c++)) && ((c==30)) && break; sleep 2; done"
- docker-compose run --rm php vendor/bin/phpunit -v --group mysql
pgsql:
stage: test
only:
- tests/pgsql
- tests/full
script:
- export COMPOSE_FILE=docker-compose.yml:docker-compose.${CI_BUILD_NAME}.yml
- docker-compose up --build -d
# wait for db (retry X times)
- docker-compose run --rm php bash -c 'while [ true ]; do curl postgres:5432; if [ $? == 52 ]; then break; fi; ((c++)) && ((c==25)) && break; sleep 2; done'
- docker-compose run --rm php vendor/bin/phpunit -v --group pgsql
cubrid:
stage: test
only:
- tests/cubrid
- tests/extra
script:
- cd cubrid
- docker-compose up --build -d
# wait for db (retry X times)
- docker-compose run --rm php bash -c 'while [ true ]; do curl cubrid:1523; if [ $? == 56 ]; then break; fi; ((c++)) && ((c==20)) && break; sleep 3; done'
- sleep 5
- docker-compose run --rm php /project/vendor/bin/phpunit -v --group cubrid
mssql:
stage: test
only:
- tests/mssql
- tests/extra
script:
- cd mssql
- docker-compose up --build -d
# wait for db (retry X times)
- docker-compose run --rm php bash -c 'while [ true ]; do curl mssql:1433; if [ $? == 52 ]; then break; fi; ((c++)) && ((c==15)) && break; sleep 5; done'
- sleep 3
# Note: Password has to be the last parameter
- docker-compose run --rm sqlcmd sh -c 'sqlcmd -S mssql -U sa -Q "CREATE DATABASE yii2test" -P Microsoft-12345'
- docker-compose run --rm php vendor/bin/phpunit -v --group mssql
travis:
stage: travis
only:
- travis
script:
- export COMPOSE_FILE=docker-compose.yml:docker-compose.mysql.yml:docker-compose.pgsql.yml
- docker-compose up --build -d
# wait for dbs ...
- sleep 10
- docker-compose run --rm php vendor/bin/phpunit -v --exclude mssql,cubrid,oci,wincache,xcache,zenddata,cubrid

27
.php_cs

@ -1,27 +0,0 @@
<?php
if (!class_exists('yii\cs\YiisoftConfig', true)) {
// TODO: change error message
fwrite(STDERR, "Your php-cs-version is outdated: please upgrade it.\n");
die(16);
}
return yii\cs\YiisoftConfig::create()
->setCacheFile(__DIR__ . '/tests/runtime/php_cs.cache')
->mergeRules([
'braces' => [
'allow_single_line_closure' => true,
],
])
->setFinder(
PhpCsFixer\Finder::create()
->in(__DIR__)
->exclude('docs')
->exclude('apps')
->exclude('extensions')
// requirement checker should work even on PHP 4.3, so it needs special treatment
->exclude('framework/requirements')
->notPath('framework/classes.php')
->notPath('framework/helpers/mimeTypes.php')
->notPath('framework/views/messageConfig.php')
);

22
.scrutinizer.yml

@ -1,20 +1,10 @@
build:
nodes:
analysis:
tests:
override:
- php-scrutinizer-run
filter:
excluded_paths:
- "tests/"
- "build/"
- "docs/"
- "framework/messages/"
dependency_paths:
- "vendor/"
imports:
- php
tools:
external_code_coverage:
runs: 3
timeout: 2100 # Timeout in seconds.
# disable copy paste detector and similarity analyzer as they have no real value
# and a huge bunch of false-positives
php_sim: false
php_cpd: false

65
.travis.yml

@ -0,0 +1,65 @@
language: php
php:
- 5.4
- 5.5
- 5.6
- 7.0
- hhvm
env:
- CUBRID_VERSION=9.3.0/CUBRID-9.3.0.0206 CUBRID_PDO_VERSION=9.3.0.0001
services:
- memcached
# faster builds on new travis setup not using sudo
sudo: false
# cache vendor dirs
cache:
directories:
# - cubrid/9.3.0
- vendor
- $HOME/.composer/cache
# try running against postgres 9.3
addons:
postgresql: "9.3"
install:
- travis_retry composer self-update && composer --version
- travis_retry composer global require "fxp/composer-asset-plugin:~1.1.1"
- export PATH="$HOME/.composer/vendor/bin:$PATH"
# core framework:
- travis_retry composer install --prefer-dist --no-interaction
- tests/data/travis/apc-setup.sh
- tests/data/travis/memcache-setup.sh
# - tests/data/travis/cubrid-setup.sh
before_script:
# show some versions and env information
- php -r "echo INTL_ICU_VERSION . \"\n\";"
- php -r "echo INTL_ICU_DATA_VERSION . \"\n\";"
- mysql --version
- psql --version
# initialize databases
- mysql -e 'CREATE DATABASE yiitest;';
- psql -U postgres -c 'CREATE DATABASE yiitest;';
- |
if [ $TRAVIS_PHP_VERSION = '5.6' ]; then
PHPUNIT_FLAGS="--coverage-clover=coverage.clover"
fi
script:
- vendor/bin/phpunit --verbose $PHPUNIT_FLAGS --exclude-group mssql,oci,wincache,xcache,zenddata,cubrid
after_script:
- |
if [ $TRAVIS_PHP_VERSION = '5.6' ]; then
travis_retry wget https://scrutinizer-ci.com/ocular.phar
php ocular.phar code-coverage:upload --format=php-clover coverage.clover
fi

7
CONTRIBUTING.md

@ -0,0 +1,7 @@
Contributing to Yii2
====================
- [Report an issue](docs/internals/report-an-issue.md)
- [Translate documentation or messages](docs/internals/translation-workflow.md)
- [Give us feedback or start a design discussion](http://www.yiiframework.com/forum/index.php/forum/42-general-discussions-for-yii-20/)
- [Contribute to the core code or fix bugs](docs/internals/git-workflow.md)

13
Dockerfile

@ -1,13 +0,0 @@
ARG DOCKER_YII2_PHP_IMAGE
FROM ${DOCKER_YII2_PHP_IMAGE}
# Project source-code
WORKDIR /project
ADD composer.* /project/
# Apply testing patches
ADD tests/phpunit_mock_objects.patch /project/tests/phpunit_mock_objects.patch
ADD tests/phpunit_getopt.patch /project/tests/phpunit_getopt.patch
# Install packgaes
RUN /usr/local/bin/composer install --prefer-dist
ADD ./ /project
ENV PATH /project/vendor/bin:${PATH}

3
LICENSE.md

@ -1,3 +1,6 @@
The Yii framework is free software. It is released under the terms of
the following BSD License.
Copyright © 2008 by Yii Software LLC (http://www.yiisoft.com)
All rights reserved.

104
README.md

@ -1,83 +1,71 @@
<p align="center">
<a href="https://www.yiiframework.com/" target="_blank">
<img src="https://www.yiiframework.com/image/yii_logo_light.svg" width="400" alt="Yii Framework" />
</a>
</p>
Yii PHP Framework Version 2
===========================
Yii 2 is a modern framework designed to be a solid foundation for your PHP application.
Thank you for choosing Yii 2 - a modern PHP framework designed for professional Web development.
It is fast, secure and efficient and works right out of the box pre-configured with reasonable defaults.
The framework is easy to adjust to meet your needs, because Yii has been designed to be flexible.
Yii 2 is a complete rewrite of its previous version Yii 1.1 which is one of the most popular PHP frameworks.
Yii 2 inherits the main spirit behind Yii for being simple, fast and highly extensible.
Yii 2 requires PHP 5.4 and embraces the best practices and protocols found in modern Web application development.
[![Latest Stable Version](https://img.shields.io/packagist/v/yiisoft/yii2.svg)](https://packagist.org/packages/yiisoft/yii2)
[![Total Downloads](https://img.shields.io/packagist/dt/yiisoft/yii2.svg)](https://packagist.org/packages/yiisoft/yii2)
[![Build Status](https://github.com/yiisoft/yii2/workflows/build/badge.svg)](https://github.com/yiisoft/yii2/actions)
[![Latest Stable Version](https://poser.pugx.org/yiisoft/yii2/v/stable.png)](https://packagist.org/packages/yiisoft/yii2)
[![Total Downloads](https://poser.pugx.org/yiisoft/yii2/downloads.png)](https://packagist.org/packages/yiisoft/yii2)
[![Reference Status](https://www.versioneye.com/php/yiisoft:yii2/reference_badge.svg)](https://www.versioneye.com/php/yiisoft:yii2/references)
[![Build Status](https://img.shields.io/travis/yiisoft/yii2.svg)](http://travis-ci.org/yiisoft/yii2)
[![Dependency Status](https://www.versioneye.com/php/yiisoft:yii2/dev-master/badge.png)](https://www.versioneye.com/php/yiisoft:yii2/dev-master)
[![HHVM Status](https://img.shields.io/hhvm/yiisoft/yii2-dev.svg)](http://hhvm.h4cc.de/package/yiisoft/yii2-dev)
[![Code Coverage](https://scrutinizer-ci.com/g/yiisoft/yii2/badges/coverage.png?s=31d80f1036099e9d6a3e4d7738f6b000b3c3d10e)](https://scrutinizer-ci.com/g/yiisoft/yii2/)
[![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/yiisoft/yii2/badges/quality-score.png?s=b1074a1ff6d0b214d54fa5ab7abbb90fc092471d)](https://scrutinizer-ci.com/g/yiisoft/yii2/)
[![Code Climate](https://img.shields.io/codeclimate/github/yiisoft/yii2.svg)](https://codeclimate.com/github/yiisoft/yii2)
DIRECTORY STRUCTURE
-------------------
```
build/ internally used build tools
docs/ documentation
framework/ core framework code
tests/ tests of the core framework code
```
Installation
REQUIREMENTS
------------
- The minimum required PHP version of Yii is PHP 5.4.
- It works best with PHP 7.
- [Follow the Definitive Guide](https://www.yiiframework.com/doc-2.0/guide-start-installation.html)
in order to get step by step instructions.
The minimum requirement by Yii is that your Web server supports PHP 5.4.
Documentation
DOCUMENTATION
-------------
- A [Definitive Guide](https://www.yiiframework.com/doc/guide/2.0) and
a [Class Reference](https://www.yiiframework.com/doc/api/2.0) cover every detail
of the framework.
- There is a [PDF version](https://www.yiiframework.com/doc/download/yii-guide-2.0-en.pdf) of the Definitive Guide
Yii 2.0 has a [Definitive Guide](http://www.yiiframework.com/doc-2.0/guide-index.html) and
a [Class Reference](http://www.yiiframework.com/doc-2.0/index.html) which cover every detail of Yii.
There is also a [PDF version](http://stuff.cebe.cc/yii2-guide.en.pdf) of the Definitive Guide
and a [Definitive Guide Mirror](http://stuff.cebe.cc/yii2docs/) which is updated every 15 minutes.
- For Yii 1.1 users, there is [Upgrading from Yii 1.1](https://www.yiiframework.com/doc/guide/2.0/en/intro-upgrade-from-v1)
to get an idea of what has changed in 2.0.
Community
---------
For 1.1 users, you may refer to [Upgrading from Yii 1.1](docs/guide/intro-upgrade-from-v1.md)
to have a general idea of what has changed in 2.0.
- Participate in [discussions at forums](https://www.yiiframework.com/forum/).
- [Community Slack](https://join.slack.com/t/yii/shared_invite/MjIxMjMxMTk5MTU1LTE1MDE3MDAwMzMtM2VkMTMyMjY1Ng) and [Chat in IRC](https://www.yiiframework.com/chat/).
- Follow us on [Facebook](https://www.facebook.com/groups/yiitalk/), [Twitter](https://twitter.com/yiiframework)
and [GitHub](https://github.com/yiisoft/yii2).
- Check [other communities](https://github.com/yiisoft/yii2/wiki/communities).
Contributing
------------
HOW TO PARTICIPATE
------------------
The framework is [Open Source](LICENSE.md) powered by [an excellent community](https://github.com/yiisoft/yii2/graphs/contributors).
### Your participation to Yii 2 development is very welcome!
You may join us and:
You may participate in the following ways:
- [Report an issue](docs/internals/report-an-issue.md)
- [Translate documentation or messages](docs/internals/translation-workflow.md)
- [Give us feedback or start a design discussion](https://www.yiiframework.com/forum/index.php/forum/42-general-discussions-for-yii-20/)
- [Give us feedback or start a design discussion](http://www.yiiframework.com/forum/index.php/forum/42-general-discussions-for-yii-20/)
- [Contribute to the core code or fix bugs](docs/internals/git-workflow.md)
- [Become a sponsor](#sponsoring)
### Reporting Security issues
Please refer to a [special page at the website](https://www.yiiframework.com/security/)
describing proper workflow for security issue reports.
### Directory Structure
```
build/ internally used build tools
docs/ documentation
framework/ core framework code
tests/ tests of the core framework code
```
### Spreading the Word
Acknowledging or citing Yii 2 is as important as direct contributions.
### Acknowledging or citing Yii 2
**In presentations**
If you are giving a presentation or talk featuring work that makes use of Yii 2 and would like to acknowledge it,
we suggest using [our logo](https://www.yiiframework.com/logo/) on your title slide.
we suggest using [our logo](http://www.yiiframework.com/logo/) on your title slide.
**In projects**
@ -89,11 +77,5 @@ If you are using Yii 2 as part of an OpenSource project, a way to acknowledge it
If your code is hosted at GitHub, you can place the following in your README.md file to get the badge:
```
[![Yii2](https://img.shields.io/badge/Powered_by-Yii_Framework-green.svg?style=flat)](https://www.yiiframework.com/)
[![Yii2](https://img.shields.io/badge/Powered_by-Yii_Framework-green.svg?style=flat)](http://www.yiiframework.com/)
```
### Sponsoring
Support this project by becoming a sponsor or a backer.
[![OpenCollective sponsors](https://opencollective.com/yiisoft/sponsors/badge.svg)](https://opencollective.com/yiisoft) [![OpenCollective backers](https://opencollective.com/yiisoft/backers/badge.svg)](https://opencollective.com/yiisoft)

27
ROADMAP.md

@ -1,27 +0,0 @@
> Roadmap for Yii 3.0 and further was moved to [yiisoft/docs](https://github.com/yiisoft/docs/blob/master/003-roadmap.md).
- Enhancements are not accepted for framework version 2.0.
- Enhancements are accepted for 2.0 extensions.
- Bug and security fixes are expected.
- Pull requests and maintainers are very welcome.
Above would stand as it is [for two years after Yii 3.0 release](https://www.yiiframework.com/release-cycle).
## Additional releases
While we focus on 3.0, we tag 2.0 releases and extension releases [about once in a week](https://www.yiiframework.com/release-cycle).
## 2.0.16+ (since 2019 till 3.0 release + 2 years)
- Bugfixes.
## 2.0.15 (2nd quarter of 2018)
- Since this release main focus is bug fixing.
- No full-branch merges into 3.0.
- No enhancements are accepted.
## 2.0.14 (1st quarter of 2018)
Will be last release with features and enhancements the last one that will be merged into 3.0 directly.

4
build/build

@ -17,7 +17,7 @@ $composerAutoload = [
foreach ($composerAutoload as $autoload) {
if (file_exists($autoload)) {
require $autoload;
require($autoload);
$vendorPath = dirname($autoload);
break;
}
@ -27,7 +27,7 @@ if (!isset($vendorPath)) {
echo "composer autoloader could not be found.\nYou should run `composer install` in repo root directory.\n";
exit(1);
}
require __DIR__ . '/../framework/Yii.php';
require(__DIR__ . '/../framework/Yii.php');
Yii::setAlias('@yii/build', __DIR__);

2
build/controllers/ClassmapController.php

@ -60,7 +60,7 @@ class ClassmapController extends Controller
if (strpos($file, $root) !== 0) {
throw new Exception("Something wrong: $file\n");
}
$path = str_replace('\\', '/', substr($file, \strlen($root)));
$path = str_replace('\\', '/', substr($file, strlen($root)));
$map[$path] = " 'yii" . substr(str_replace('/', '\\', $path), 0, -4) . "' => YII2_PATH . '$path',";
}
ksort($map);

98
build/controllers/DevController.php

@ -14,45 +14,34 @@ use yii\helpers\Console;
use yii\helpers\FileHelper;
/**
* This command helps to set up a dev environment with all extensions and applications.
* This command helps to set up a dev environment with all extensions and applications
*
* It will clone an extension or app repo and link the yii2 dev installation to the contained applications/extensions vendor dirs
* to help to work on yii using the application to test it.
* It will clone an extension or app repo and link the yii2 dev installation to the containted applications/extensions vendor dirs
* to help working on yii using the application to test it.
*
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
class DevController extends Controller
{
/**
* {@inheritdoc}
*/
public $defaultAction = 'all';
/**
* @var bool whether to use HTTP when cloning GitHub repositories
* @var bool whether to use HTTP when cloning github repositories
*/
public $useHttp = false;
/**
* @var bool whether to use --no-progress option when running composer
*/
public $composerNoProgress = false;
/**
* @var array
*/
public $apps = [
'basic' => 'git@github.com:yiisoft/yii2-app-basic.git',
'advanced' => 'git@github.com:yiisoft/yii2-app-advanced.git',
'benchmark' => 'git@github.com:yiisoft/yii2-app-benchmark.git',
];
/**
* @var array
*/
public $extensions = [
'apidoc' => 'git@github.com:yiisoft/yii2-apidoc.git',
'authclient' => 'git@github.com:yiisoft/yii2-authclient.git',
'bootstrap' => 'git@github.com:yiisoft/yii2-bootstrap.git',
'bootstrap4' => 'git@github.com:yiisoft/yii2-bootstrap4.git',
'bootstrap5' => 'git@github.com:yiisoft/yii2-bootstrap5.git',
'codeception' => 'git@github.com:yiisoft/yii2-codeception.git',
'composer' => 'git@github.com:yiisoft/yii2-composer.git',
'debug' => 'git@github.com:yiisoft/yii2-debug.git',
'elasticsearch' => 'git@github.com:yiisoft/yii2-elasticsearch.git',
@ -68,13 +57,12 @@ class DevController extends Controller
'smarty' => 'git@github.com:yiisoft/yii2-smarty.git',
'sphinx' => 'git@github.com:yiisoft/yii2-sphinx.git',
'swiftmailer' => 'git@github.com:yiisoft/yii2-swiftmailer.git',
'symfonymailer' => 'git@github.com:yiisoft/yii2-symfonymailer.git',
'twig' => 'git@github.com:yiisoft/yii2-twig.git',
];
/**
* Install all extensions and advanced + basic app.
* Install all extensions and advanced + basic app
*/
public function actionAll()
{
@ -100,7 +88,7 @@ class DevController extends Controller
}
/**
* Runs a command in all extension and application directories.
* Runs a command in all extension and application directories
*
* Can be used to run e.g. `git pull`.
*
@ -110,17 +98,17 @@ class DevController extends Controller
*/
public function actionRun($command)
{
$command = implode(' ', \func_get_args());
$command = implode(' ', func_get_args());
// root of the dev repo
$base = \dirname(\dirname(__DIR__));
$base = dirname(dirname(__DIR__));
$dirs = $this->listSubDirs("$base/extensions");
$dirs = array_merge($dirs, $this->listSubDirs("$base/apps"));
asort($dirs);
$oldcwd = getcwd();
foreach($dirs as $dir) {
$displayDir = substr($dir, \strlen($base));
$displayDir = substr($dir, strlen($base));
$this->stdout("Running '$command' in $displayDir...\n", Console::BOLD);
chdir($dir);
passthru($command);
@ -130,7 +118,7 @@ class DevController extends Controller
}
/**
* This command installs a project template in the `apps` directory and links the framework and extensions.
* This command installs a project template in the `apps` directory and links the framework and extensions
*
* It basically runs the following commands in the dev repo root:
*
@ -149,7 +137,7 @@ class DevController extends Controller
public function actionApp($app, $repo = null)
{
// root of the dev repo
$base = \dirname(\dirname(__DIR__));
$base = dirname(dirname(__DIR__));
$appDir = "$base/apps/$app";
if (!file_exists($appDir)) {
@ -166,11 +154,7 @@ class DevController extends Controller
}
$this->stdout("cloning application repo '$app' from '$repo'...\n", Console::BOLD);
passthru('git clone ' . escapeshellarg($repo) . ' ' . $appDir, $returnVar);
if ($returnVar !== 0) {
$this->stdout("Error occurred while cloning repository.\n", Console::BOLD, Console::FG_RED);
return 1;
}
passthru('git clone ' . escapeshellarg($repo) . ' ' . $appDir);
$this->stdout("done.\n", Console::BOLD, Console::FG_GREEN);
}
@ -182,11 +166,7 @@ class DevController extends Controller
// composer update
$this->stdout("updating composer for app '$app'...\n", Console::BOLD);
chdir($appDir);
$command = 'composer update --prefer-dist';
if ($this->composerNoProgress) {
$command .= ' --no-progress';
}
passthru($command);
passthru('composer update --prefer-dist');
$this->stdout("done.\n", Console::BOLD, Console::FG_GREEN);
// link directories
@ -198,7 +178,7 @@ class DevController extends Controller
}
/**
* This command installs an extension in the `extensions` directory and links the framework and other extensions.
* This command installs an extension in the `extensions` directory and links the framework and other extensions
*
* @param string $extension the application name e.g. `basic` or `advanced`.
* @param string $repo url of the git repo to clone if it does not already exist.
@ -208,7 +188,7 @@ class DevController extends Controller
public function actionExt($extension, $repo = null)
{
// root of the dev repo
$base = \dirname(\dirname(__DIR__));
$base = dirname(dirname(__DIR__));
$extensionDir = "$base/extensions/$extension";
if (!file_exists($extensionDir)) {
@ -237,11 +217,7 @@ class DevController extends Controller
// composer update
$this->stdout("updating composer for extension '$extension'...\n", Console::BOLD);
chdir($extensionDir);
$command = 'composer update --prefer-dist';
if ($this->composerNoProgress) {
$command .= ' --no-progress';
}
passthru($command);
passthru('composer update --prefer-dist');
$this->stdout("done.\n", Console::BOLD, Console::FG_GREEN);
// link directories
@ -253,41 +229,39 @@ class DevController extends Controller
}
/**
* {@inheritdoc}
* @inheritdoc
*/
public function options($actionID)
{
$options = parent::options($actionID);
if (\in_array($actionID, ['ext', 'app', 'all'], true)) {
if (in_array($actionID, ['ext', 'app', 'all'], true)) {
$options[] = 'useHttp';
$options[] = 'composerNoProgress';
}
return $options;
}
/**
* Remove all symlinks in the vendor subdirectory of the directory specified.
* Remove all symlinks in the vendor subdirectory of the directory specified
* @param string $dir base directory
*/
protected function cleanupVendorDir($dir)
{
if (is_link($link = "$dir/vendor/yiisoft/yii2")) {
$this->stdout("Removing symlink $link.\n");
FileHelper::unlink($link);
$this->unlink($link);
}
$extensions = $this->findDirs("$dir/vendor/yiisoft");
foreach($extensions as $ext) {
if (is_link($link = "$dir/vendor/yiisoft/yii2-$ext")) {
$this->stdout("Removing symlink $link.\n");
FileHelper::unlink($link);
$this->unlink($link);
}
}
}
/**
* Creates symlinks to framework and extension sources for the application.
* Creates symlinks to freamework and extension sources for the application
* @param string $dir application directory
* @param string $base Yii sources base directory
*
@ -319,7 +293,21 @@ class DevController extends Controller
}
/**
* Get a list of subdirectories for directory specified.
* Properly removes symlinked directory under Windows, MacOS and Linux
*
* @param string $file path to symlink
*/
protected function unlink($file)
{
if (is_dir($file) && DIRECTORY_SEPARATOR === '\\') {
rmdir($file);
} else {
unlink($file);
}
}
/**
* Get a list of subdirectories for directory specified
* @param string $dir directory to read
*
* @return array list of subdirectories
@ -336,7 +324,7 @@ class DevController extends Controller
continue;
}
// ignore hidden directories
if (strpos($file, '.') === 0) {
if ($file[0] === '.') {
continue;
}
if (is_dir("$dir/$file")) {
@ -348,7 +336,7 @@ class DevController extends Controller
}
/**
* Finds linkable applications.
* Finds linkable applications
*
* @param string $dir directory to search in
* @return array list of applications command can link

88
build/controllers/MimeTypeController.php

@ -13,7 +13,7 @@ use yii\helpers\Console;
use yii\helpers\VarDumper;
/**
* MimeTypeController generates a map of file extensions to MIME types.
* MimeTypeController generates a map of file extensions to MIME types
*
* It uses `mime.types` file from apache http located under
* http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/conf/mime.types?view=markup
@ -27,65 +27,21 @@ use yii\helpers\VarDumper;
class MimeTypeController extends Controller
{
/**
* @var array MIME type aliases
* @param string $outFile the file to update. Defaults to @yii/helpers/mimeTypes.php
*/
private $aliases = [
'text/xml' => 'application/xml',
'image/svg' => 'image/svg+xml',
'image/x-bmp' => 'image/bmp',
'image/x-bitmap' => 'image/bmp',
'image/x-xbitmap' => 'image/bmp',
'image/x-win-bitmap' => 'image/bmp',
'image/x-windows-bmp' => 'image/bmp',
'image/ms-bmp' => 'image/bmp',
'image/x-ms-bmp' => 'image/bmp',
'application/bmp' => 'image/bmp',
'application/x-bmp' => 'image/bmp',
'application/x-win-bitmap' => 'image/bmp',
];
/**
* @var array MIME types to add to the ones parsed from Apache files
*/
private $additionalMimeTypes = [
'mjs' => 'text/javascript',
];
/**
* @param string $outFile the mime file to update. Defaults to @yii/helpers/mimeTypes.php
* @param string $aliasesOutFile the aliases file to update. Defaults to @yii/helpers/mimeAliases.php
*/
public function actionIndex($outFile = null, $aliasesOutFile = null)
public function actionIndex($outFile = null)
{
if ($outFile === null) {
$outFile = Yii::getAlias('@yii/helpers/mimeTypes.php');
}
if ($aliasesOutFile === null) {
$aliasesOutFile = Yii::getAlias('@yii/helpers/mimeAliases.php');
}
$this->stdout('Downloading mime-type file from apache httpd repository...');
if ($apacheMimeTypesFileContent = file_get_contents('http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/conf/mime.types?view=co')) {
$this->stdout("Done.\n", Console::FG_GREEN);
$this->generateMimeTypesFile($outFile, $apacheMimeTypesFileContent);
$this->generateMimeAliasesFile($aliasesOutFile);
} else {
$this->stderr("Failed to download mime.types file from apache SVN.\n");
}
}
/**
* @param string $outFile
* @param string $content
*/
private function generateMimeTypesFile($outFile, $content)
{
$this->stdout("Generating file $outFile...");
$this->stdout('downloading mime-type file from apache httpd repository...');
if ($content = file_get_contents('http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/conf/mime.types?view=co')) {
$this->stdout("done.\n", Console::FG_GREEN);
$this->stdout("generating file $outFile...");
$mimeMap = [];
foreach(explode("\n", $content) as $line) {
$line = trim($line);
if (empty($line) || strpos($line, '#') === 0) { // skip comments and empty lines
if (empty($line) || $line[0] == '#') { // skip comments and empty lines
continue;
}
$parts = preg_split('/\s+/', $line);
@ -96,14 +52,8 @@ class MimeTypeController extends Controller
}
}
}
$mimeMap = array_merge($mimeMap, $this->additionalMimeTypes);
ksort($mimeMap);
$array = VarDumper::export($mimeMap);
if (PHP_VERSION_ID >= 80100) {
$array = array_replace($array, array('xz' => 'application/octet-stream'));
}
$content = <<<EOD
<?php
/**
@ -120,26 +70,8 @@ return $array;
EOD;
file_put_contents($outFile, $content);
$this->stdout("done.\n", Console::FG_GREEN);
} else {
$this->stderr("Failed to download mime.types file from apache SVN.\n");
}
/**
* @param string $outFile
*/
private function generateMimeAliasesFile($outFile)
{
$this->stdout("generating file $outFile...");
$array = VarDumper::export($this->aliases);
$content = <<<EOD
<?php
/**
* MIME aliases.
*
* This file contains aliases for MIME types.
*/
return $array;
EOD;
file_put_contents($outFile, $content);
$this->stdout("done.\n", Console::FG_GREEN);
}
}

431
build/controllers/PhpDocController.php

@ -11,10 +11,9 @@ use Yii;
use yii\console\Controller;
use yii\helpers\Console;
use yii\helpers\FileHelper;
use yii\helpers\Json;
/**
* PhpDocController is there to help to maintain PHPDoc annotation in class files.
* PhpDocController is there to help maintaining PHPDoc annotation in class files
*
* @author Carsten Brandt <mail@cebe.cc>
* @author Alexander Makarov <sam@rmcreative.ru>
@ -22,23 +21,16 @@ use yii\helpers\Json;
*/
class PhpDocController extends Controller
{
/**
* {@inheritdoc}
*/
public $defaultAction = 'property';
/**
* @var bool whether to update class docs directly. Setting this to false will just output docs
* @var boolean whether to update class docs directly. Setting this to false will just output docs
* for copy and paste.
*/
public $updateFiles = true;
/**
* @var bool whether to add copyright header to php files. This should be skipped in application code.
*/
public $skipFrameworkRequirements = false;
/**
* Generates `@property` annotations in class files from getters and setters.
* Generates `@property` annotations in class files from getters and setters
*
* Property description will be taken from getter or setter or from an `@property` annotation
* in the getters docblock if there is one defined.
@ -74,145 +66,84 @@ class PhpDocController extends Controller
}
/**
* Fix some issues with PHPDoc in files.
* Fix some issues with PHPdoc in files
*
* @param string $root the directory to parse files from. Defaults to YII2_PATH.
*/
public function actionFix($root = null)
{
$files = $this->findFiles($root, false);
$files = $this->findFiles($root);
$nFilesTotal = 0;
$nFilesUpdated = 0;
foreach ($files as $file) {
$contents = file_get_contents($file);
$hash = $this->hash($contents);
$sha = sha1($contents);
// fix line endings
$lines = preg_split('/(\r\n|\n|\r)/', $contents);
if (!$this->skipFrameworkRequirements) {
$this->fixFileDoc($lines);
}
$this->fixDocBlockIndentation($lines);
$lines = array_values($this->fixLineSpacing($lines));
$newContent = implode("\n", $lines);
if ($hash !== $this->hash($newContent)) {
file_put_contents($file, $newContent);
if ($sha !== sha1($newContent)) {
$nFilesUpdated++;
}
file_put_contents($file, $newContent);
$nFilesTotal++;
}
$this->stdout("\nParsed $nFilesTotal files.\n");
$this->stdout("Updated $nFilesUpdated files.\n");
}
/**
* {@inheritdoc}
* @inheritdoc
*/
public function options($actionID)
{
return array_merge(parent::options($actionID), ['updateFiles', 'skipFrameworkRequirements']);
return array_merge(parent::options($actionID), ['updateFiles']);
}
/**
* @param string $root
* @param bool $needsInclude
* @return array list of files.
*/
protected function findFiles($root, $needsInclude = true)
protected function findFiles($root)
{
$except = [];
if ($needsInclude) {
$extensionExcept = [
'apidoc' => [
'/helpers/PrettyPrinter.php',
'/extensions/apidoc/helpers/ApiIndexer.php',
'/extensions/apidoc/helpers/ApiMarkdownLaTeX.php',
],
'codeception' => [
'/TestCase.php',
'/DbTestCase.php',
],
'gii' => [
'/components/DiffRendererHtmlInline.php',
'/generators/extension/default/AutoloadExample.php',
],
'swiftmailer' => [
'src/Logger.php',
],
'twig' => [
'/Extension.php',
'/Optimizer.php',
'/Template.php',
'/TwigSimpleFileLoader.php',
'/ViewRendererStaticClassProxy.php',
],
];
} else {
$extensionExcept = [];
}
if ($root === null) {
$root = \dirname(YII2_PATH);
$root = dirname(YII2_PATH);
$extensionPath = "$root/extensions";
$this->setUpExtensionAliases($extensionPath);
foreach (scandir($extensionPath) as $extension) {
if (ctype_alpha($extension) && is_dir($extensionPath . '/' . $extension)) {
Yii::setAlias("@yii/$extension", "$extensionPath/$extension");
}
}
$except = [
'.git/',
'/apps/',
'/build/',
'/docs/',
'/extensions/apidoc/helpers/PrettyPrinter.php',
'/extensions/apidoc/helpers/ApiIndexer.php',
'/extensions/apidoc/helpers/ApiMarkdownLaTeX.php',
'/extensions/codeception/TestCase.php',
'/extensions/codeception/DbTestCase.php',
'/extensions/composer/',
'/extensions/gii/components/DiffRendererHtmlInline.php',
'/extensions/gii/generators/extension/default/*',
'/extensions/twig/Extension.php',
'/extensions/twig/Optimizer.php',
'/extensions/twig/Template.php',
'/extensions/twig/TwigSimpleFileLoader.php',
'/extensions/twig/ViewRendererStaticClassProxy.php',
'/framework/BaseYii.php',
'/framework/Yii.php',
'assets/',
'tests/',
'vendor/',
];
foreach ($extensionExcept as $ext => $paths) {
foreach ($paths as $path) {
$except[] = "/extensions/$ext$path";
}
}
} elseif (preg_match('~extensions/([\w-]+)[\\\\/]?$~', $root, $matches)) {
$extensionPath = \dirname(rtrim($root, '\\/'));
$this->setUpExtensionAliases($extensionPath);
list(, $extension) = $matches;
Yii::setAlias("@yii/$extension", (string)$root);
if (is_file($autoloadFile = Yii::getAlias("@yii/$extension/vendor/autoload.php"))) {
include $autoloadFile;
}
if (isset($extensionExcept[$extension])) {
foreach ($extensionExcept[$extension] as $path) {
$except[] = $path;
}
}
$except[] = '/vendor/';
$except[] = '/tests/';
$except[] = '/docs/';
// // composer extension does not contain yii code
// if ($extension === 'composer') {
// return [];
// }
} elseif (preg_match('~apps/([\w-]+)[\\\\/]?$~', $root, $matches)) {
$extensionPath = \dirname(\dirname(rtrim($root, '\\/'))) . '/extensions';
$this->setUpExtensionAliases($extensionPath);
list(, $appName) = $matches;
Yii::setAlias("@app-$appName", (string)$root);
if (is_file($autoloadFile = Yii::getAlias("@app-$appName/vendor/autoload.php"))) {
include $autoloadFile;
}
$except[] = '/runtime/';
$except[] = '/vendor/';
$except[] = '/tests/';
$except[] = '/docs/';
}
$root = FileHelper::normalizePath($root);
$options = [
@ -228,43 +159,17 @@ class PhpDocController extends Controller
},
'only' => ['*.php'],
'except' => array_merge($except, [
'.git/',
'views/',
'requirements/',
'gii/generators/',
'vendor/',
]),
];
return FileHelper::findFiles($root, $options);
}
/**
* @param string $extensionPath root path containing extension repositories.
*/
private function setUpExtensionAliases($extensionPath)
{
foreach (scandir($extensionPath) as $extension) {
if (ctype_alpha($extension) && is_dir($extensionPath . '/' . $extension)) {
Yii::setAlias("@yii/$extension", "$extensionPath/$extension");
$composerConfigFile = $extensionPath . '/' . $extension . '/composer.json';
if (file_exists($composerConfigFile)) {
$composerConfig = Json::decode(file_get_contents($composerConfigFile));
if (isset($composerConfig['autoload']['psr-4'])) {
foreach ($composerConfig['autoload']['psr-4'] as $namespace => $subPath) {
$alias = '@' . str_replace('\\', '/', $namespace);
$path = rtrim("$extensionPath/$extension/$subPath", '/');
Yii::setAlias($alias, $path);
}
}
}
}
}
}
/**
* Fix file PHPDoc.
* Fix file PHPdoc
*/
protected function fixFileDoc(&$lines)
{
@ -291,22 +196,21 @@ class PhpDocController extends Controller
$contentAfterNamespace--;
}
$lines = array_merge([
'<?php',
'/**',
' * @link http://www.yiiframework.com/',
' * @copyright Copyright (c) 2008 Yii Software LLC',
' * @license http://www.yiiframework.com/license/',
' */',
'',
"<?php",
"/**",
" * @link http://www.yiiframework.com/",
" * @copyright Copyright (c) 2008 Yii Software LLC",
" * @license http://www.yiiframework.com/license/",
" */",
"",
$namespaceLine,
'',
""
], $lines);
}
}
/**
* Markdown aware fix of whitespace issues in doc comments.
* @param array $lines
* Markdown aware fix of whitespace issues in doc comments
*/
protected function fixDocBlockIndentation(&$lines)
{
@ -329,16 +233,16 @@ class PhpDocController extends Controller
$tag = false;
} elseif ($docBlock) {
$line = ltrim($line);
if (strpos($line, '*') === 0) {
if (isset($line[0]) && $line[0] === '*') {
$line = substr($line, 1);
}
if (strpos($line, ' ') === 0) {
if (isset($line[0]) && $line[0] === ' ') {
$line = substr($line, 1);
}
$docLine = str_replace("\t", ' ', rtrim($line));
if (empty($docLine)) {
$listIndent = '';
} elseif (strpos($docLine, '@') === 0) {
} elseif ($docLine[0] === '@') {
$listIndent = '';
$codeBlock = false;
$tag = true;
@ -348,7 +252,7 @@ class PhpDocController extends Controller
$codeBlock = !$codeBlock;
$listIndent = '';
} elseif (preg_match('/^(\s*)([0-9]+\.|-|\*|\+) /', $docLine, $matches)) {
$listIndent = str_repeat(' ', \strlen($matches[0]));
$listIndent = str_repeat(' ', strlen($matches[0]));
$tag = false;
$lines[$i] = $indent . ' * ' . $docLine;
continue;
@ -362,29 +266,22 @@ class PhpDocController extends Controller
}
}
/**
* @param string $line
* @return string
*/
protected function fixParamTypes($line)
{
return preg_replace_callback('~@(param|return) ([\w\\|]+)~i', function($matches) {
$types = explode('|', $matches[2]);
foreach($types as $i => $type) {
switch($type){
case 'integer': $types[$i] = 'int'; break;
case 'boolean': $types[$i] = 'bool'; break;
case 'int': $types[$i] = 'integer'; break;
case 'bool': $types[$i] = 'boolean'; break;
}
}
return '@' . $matches[1] . ' ' . implode('|', $types);
}, $line);
}
/**
* Fixes line spacing code style for properties and constants.
* @param string[] $lines
* @return string[]
* Fixes line spacing code style for properties and constants
*/
protected function fixLineSpacing($lines)
{
@ -453,15 +350,15 @@ class PhpDocController extends Controller
$endofPrivate = $i;
$property = 'Private';
$level = 0;
} elseif (strpos($line, 'const ') === 0) {
} elseif (substr($line,0 , 6) === 'const ') {
$endofConst = $i;
$property = false;
} elseif (strpos($line, 'use ') === 0) {
} elseif (substr($line,0 , 4) === 'use ') {
$endofUse = $i;
$property = false;
} elseif (strpos($line, '*') === 0) {
} elseif (!empty($line) && $line[0] === '*') {
$property = false;
} elseif (strpos($line, '*') !== 0 && strpos($line, 'function ') !== false || $line === '}') {
} elseif (!empty($line) && $line[0] !== '*' && strpos($line, 'function ') !== false || $line === '}') {
break;
}
@ -504,32 +401,14 @@ class PhpDocController extends Controller
protected function updateClassPropertyDocs($file, $className, $propertyDoc)
{
if ($this->shouldSkipClass($className)) {
$this->stderr("[INFO] Skipping class $className.\n", Console::FG_BLUE, Console::BOLD);
return false;
}
try {
$ref = new \ReflectionClass($className);
} catch (\Exception $e) {
$this->stderr("[ERR] Unable to create ReflectionClass for class '$className': " . $e->getMessage() . "\n", Console::FG_RED);
return false;
} catch (\Error $e) {
$this->stderr("[ERR] Unable to create ReflectionClass for class '$className': " . $e->getMessage() . "\n", Console::FG_RED);
return false;
}
if ($ref->getFileName() != $file) {
$this->stderr("[ERR] Unable to create ReflectionClass for class: $className loaded class is not from file: $file\n", Console::FG_RED);
return false;
}
if ($this->isBaseObject($className, $ref)) {
$this->stderr("[INFO] Skipping class $className as it is not a subclass of yii\\base\\BaseObject.\n", Console::FG_BLUE, Console::BOLD);
return false;
}
if (!$ref->isSubclassOf('yii\base\Object') && $className != 'yii\base\Object') {
$this->stderr("[INFO] Skipping class $className as it is not a subclass of yii\\base\\Object.\n", Console::FG_BLUE, Console::BOLD);
if ($ref->isSubclassOf('yii\db\BaseActiveRecord')) {
$this->stderr("[INFO] Skipping class $className as it is an ActiveRecord class, property handling is not supported yet.\n", Console::FG_BLUE, Console::BOLD);
return false;
}
@ -554,22 +433,21 @@ class PhpDocController extends Controller
}
}
if (!$this->skipFrameworkRequirements) {
if (!$seenSince) {
$this->stderr("[ERR] No @since found in class doc in file: $file\n", Console::FG_RED);
}
if (!$seenAuthor) {
$this->stderr("[ERR] No @author found in class doc in file: $file\n", Console::FG_RED);
}
}
if (trim($oldDoc) != trim($newDoc)) {
$fileContent = explode("\n", file_get_contents($file));
$start = $ref->getStartLine() - 2;
$docStart = $start - \count(explode("\n", $oldDoc)) + 1;
$docStart = $start - count(explode("\n", $oldDoc)) + 1;
$newFileContent = [];
$n = \count($fileContent);
$n = count($fileContent);
for ($i = 0; $i < $n; $i++) {
if ($i > $start || $i < $docStart) {
$newFileContent[] = $fileContent[$i];
@ -588,7 +466,7 @@ class PhpDocController extends Controller
}
/**
* remove multi empty lines and trim trailing whitespace.
* remove multi empty lines and trim trailing whitespace
*
* @param $doc
* @return string
@ -596,7 +474,7 @@ class PhpDocController extends Controller
protected function cleanDocComment($doc)
{
$lines = explode("\n", $doc);
$n = \count($lines);
$n = count($lines);
for ($i = 0; $i < $n; $i++) {
$lines[$i] = rtrim($lines[$i]);
if (trim($lines[$i]) == '*' && trim($lines[$i + 1]) == '*') {
@ -608,7 +486,7 @@ class PhpDocController extends Controller
}
/**
* Replace property annotations in doc comment.
* Replace property annotations in doc comment
* @param $doc
* @param $properties
* @return string
@ -620,9 +498,9 @@ class PhpDocController extends Controller
$propertyPosition = false;
foreach ($lines as $i => $line) {
$line = trim($line);
if (strncmp($line, '* @property', 11) === 0) {
if (strncmp($line, '* @property ', 12) === 0) {
$propertyPart = true;
} elseif ($propertyPart && $line === '*') {
} elseif ($propertyPart && $line == '*') {
$propertyPosition = $i;
$propertyPart = false;
}
@ -634,12 +512,6 @@ class PhpDocController extends Controller
unset($lines[$i]);
}
}
// if no properties or other tags were present add properties at the end
if ($propertyPosition === false) {
$propertyPosition = \count($lines) - 2;
}
$finalDoc = '';
foreach ($lines as $i => $line) {
$finalDoc .= $line . "\n";
@ -653,37 +525,29 @@ class PhpDocController extends Controller
protected function generateClassPropertyDocs($fileName)
{
$phpdoc = '';
$file = str_replace("\r", '', str_replace("\t", ' ', file_get_contents($fileName, true)));
$phpdoc = "";
$file = str_replace("\r", "", str_replace("\t", " ", file_get_contents($fileName, true)));
$ns = $this->match('#\nnamespace (?<name>[\w\\\\]+);\n#', $file);
$namespace = reset($ns);
if ($namespace === false) {
$namespace = '\\';
} else {
$namespace = $namespace['name'];
}
$classes = $this->match('#\n(?:abstract )?(?:final )?class (?<name>\w+)( extends .+)?( implements .+)?\n\{(?<content>.*)\n\}(\n|$)#', $file);
$classes = $this->match('#\n(?:abstract )?class (?<name>\w+)( extends .+)?( implements .+)?\n\{(?<content>.*)\n\}(\n|$)#', $file);
if (\count($classes) > 1) {
if (count($classes) > 1) {
$this->stderr("[ERR] There should be only one class in a file: $fileName\n", Console::FG_RED);
return false;
}
if (\count($classes) < 1) {
$interfaces = $this->match('#\ninterface (?<name>\w+)( extends .+)?\n\{(?<content>.*)\n\}(\n|$)#', $file);
if (\count($interfaces) == 1) {
if (count($classes) < 1) {
$interfaces = $this->match('#\ninterface (?<name>\w+)( extends .+)?\n\{(?<content>.+)\n\}(\n|$)#', $file);
if (count($interfaces) == 1) {
return false;
}
if (\count($interfaces) > 1) {
} elseif (count($interfaces) > 1) {
$this->stderr("[ERR] There should be only one interface in a file: $fileName\n", Console::FG_RED);
} else {
$traits = $this->match('#\ntrait (?<name>\w+)\n\{(?<content>.*)\n\}(\n|$)#', $file);
if (\count($traits) == 1) {
$traits = $this->match('#\ntrait (?<name>\w+)\n\{(?<content>.+)\n\}(\n|$)#', $file);
if (count($traits) == 1) {
return false;
}
if (\count($traits) > 1) {
} elseif (count($traits) > 1) {
$this->stderr("[ERR] There should be only one class/trait/interface in a file: $fileName\n", Console::FG_RED);
} else {
$this->stderr("[ERR] No class in file: $fileName\n", Console::FG_RED);
@ -695,6 +559,7 @@ class PhpDocController extends Controller
$className = null;
foreach ($classes as &$class) {
$className = $namespace . '\\' . $class['name'];
$gets = $this->match(
@ -722,44 +587,64 @@ class PhpDocController extends Controller
];
}
if (\count($props) === 0) {
continue;
}
ksort($props);
if (count($props) > 0) {
$phpdoc .= " *\n";
foreach ($props as $propName => &$prop) {
$docLine = ' * @property';
$docline = ' * @';
$docline .= 'property'; // Do not use property-read and property-write as few IDEs support complex syntax.
$note = '';
if (isset($prop['get'], $prop['set'])) {
if ($prop['get']['type'] !== $prop['set']['type']) {
if (isset($prop['get']) && isset($prop['set'])) {
if ($prop['get']['type'] != $prop['set']['type']) {
$note = ' Note that the type of this property differs in getter and setter.'
. ' See [[get' . ucfirst($propName) . '()]]'
. ' and [[set' . ucfirst($propName) . '()]] for details.';
. ' See [[get' . ucfirst($propName) . '()]] and [[set' . ucfirst($propName) . '()]] for details.';
}
} elseif (isset($prop['get'])) {
if (!$this->hasSetterInParents($className, $propName)) {
$docLine .= '-read';
// check if parent class has setter defined
$c = $className;
$parentSetter = false;
while ($parent = get_parent_class($c)) {
if (method_exists($parent, 'set' . ucfirst($propName))) {
$parentSetter = true;
break;
}
$c = $parent;
}
if (!$parentSetter) {
$note = ' This property is read-only.';
// $docline .= '-read';
}
} elseif (isset($prop['set'])) {
if (!$this->hasGetterInParents($className, $propName)) {
$docLine .= '-write';
// check if parent class has getter defined
$c = $className;
$parentGetter = false;
while ($parent = get_parent_class($c)) {
if (method_exists($parent, 'set' . ucfirst($propName))) {
$parentGetter = true;
break;
}
$c = $parent;
}
if (!$parentGetter) {
$note = ' This property is write-only.';
// $docline .= '-write';
}
} else {
continue;
}
$docLine .= ' ' . $this->getPropParam($prop, 'type') . " $$propName ";
$docline .= ' ' . $this->getPropParam($prop, 'type') . " $$propName ";
$comment = explode("\n", $this->getPropParam($prop, 'comment') . $note);
foreach ($comment as &$cline) {
$cline = ltrim(rtrim($cline), '* ');
$cline = ltrim($cline, '* ');
}
$docLine = wordwrap($docLine . implode(' ', $comment), 110, "\n * ") . "\n";
$docline = wordwrap($docline . implode(' ', $comment), 110, "\n * ") . "\n";
$phpdoc .= $docLine;
$phpdoc .= $docline;
}
$phpdoc .= " *\n";
}
}
return [$className, $phpdoc];
}
@ -775,112 +660,26 @@ class PhpDocController extends Controller
foreach($parts as $part) {
preg_match_all($pattern . 'suU', $part, $matches, PREG_SET_ORDER);
foreach ($matches as &$set) {
foreach ($set as $i => $match) {
if (is_numeric($i) /*&& $i != 0*/) {
foreach ($set as $i => $match)
if (is_numeric($i) /*&& $i != 0*/)
unset($set[$i]);
}
}
$sets[] = $set;
}
}
return $sets;
}
protected function fixSentence($str)
{
// TODO fix word wrap
if ($str == '') {
if ($str == '')
return '';
}
return strtoupper(substr($str, 0, 1)) . substr($str, 1) . ($str[\strlen($str) - 1] !== '.' ? '.' : '');
return strtoupper(substr($str, 0, 1)) . substr($str, 1) . ($str[strlen($str) - 1] != '.' ? '.' : '');
}
protected function getPropParam($prop, $param)
{
return isset($prop['property']) ? $prop['property'][$param] : (isset($prop['get']) ? $prop['get'][$param] : $prop['set'][$param]);
}
/**
* Generate a hash value (message digest)
* @param string $string message to be hashed.
* @return string calculated message digest.
*/
private function hash($string)
{
if (!function_exists('hash')) {
return sha1($string);
}
return hash('sha256', $string);
}
/**
* @param string $className
* @param string $propName
* @return bool
*/
protected function hasGetterInParents($className, $propName)
{
$class = $className;
try {
while ($parent = get_parent_class($class)) {
if (method_exists($parent, 'get' . ucfirst($propName))) {
return true;
}
$class = $parent;
}
} catch (\Throwable $t) {
$this->stderr("[ERR] Error when getting parents for $className\n", Console::FG_RED);
return false;
}
return false;
}
/**
* @param string $className
* @param string $propName
* @return bool
*/
protected function hasSetterInParents($className, $propName)
{
$class = $className;
try {
while ($parent = get_parent_class($class)) {
if (method_exists($parent, 'set' . ucfirst($propName))) {
return true;
}
$class = $parent;
}
} catch (\Throwable $t) {
$this->stderr("[ERR] Error when getting parents for $className\n", Console::FG_RED);
return false;
}
return false;
}
/**
* @param string $className
* @param \ReflectionClass $ref
* @return bool
*/
protected function isBaseObject($className, \ReflectionClass $ref)
{
$isDeprecatedObject = false;
if (PHP_VERSION_ID <= 70100) {
$isDeprecatedObject = $ref->isSubclassOf('yii\base\Object') || $className === 'yii\base\Object';
}
return !$isDeprecatedObject && !$ref->isSubclassOf('yii\base\BaseObject') && $className !== 'yii\base\BaseObject';
}
private function shouldSkipClass($className)
{
if (PHP_VERSION_ID > 70100) {
return $className === 'yii\base\Object';
}
return false;
}
}

910
build/controllers/ReleaseController.php

File diff suppressed because it is too large Load Diff

13
build/controllers/TranslationController.php

@ -29,6 +29,7 @@ class TranslationController extends Controller
* @param string $sourcePath the directory where the original documentation files are
* @param string $translationPath the directory where the translated documentation files are
* @param string $title custom title to use for report
* @return string
*/
public function actionReport($sourcePath, $translationPath, $title = 'Translation report')
{
@ -82,7 +83,7 @@ class TranslationController extends Controller
}
/**
* Checks for files existence.
* Checks for files existence
*
* @param string $translatedFilePath
* @param string $sourceFilePath
@ -103,7 +104,7 @@ class TranslationController extends Controller
}
/**
* Getting DIFF from git.
* Getting DIFF from git
*
* @param string $translatedFilePath path pointing to translated file
* @param string $sourceFilePath path pointing to original file
@ -116,7 +117,7 @@ class TranslationController extends Controller
}
/**
* Adds all necessary HTML tags and classes to diff output.
* Adds all necessary HTML tags and classes to diff output
*
* @param string $diff DIFF
* @return string highlighted DIFF
@ -125,11 +126,11 @@ class TranslationController extends Controller
{
$lines = explode("\n", $diff);
foreach ($lines as $key => $val) {
if (strpos($val, '@') === 0) {
if (mb_substr($val, 0, 1, 'utf-8') === '@') {
$lines[$key] = '<span class="info">' . Html::encode($val) . '</span>';
} elseif (strpos($val, '+') === 0) {
} elseif (mb_substr($val, 0, 1, 'utf-8') === '+') {
$lines[$key] = '<ins>' . Html::encode($val) . '</ins>';
} elseif (strpos($val, '-') === 0) {
} elseif (mb_substr($val, 0, 1, 'utf-8') === '-') {
$lines[$key] = '<del>' . Html::encode($val) . '</del>';
} else {
$lines[$key] = Html::encode($val);

126
build/controllers/Utf8Controller.php

@ -1,126 +0,0 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\build\controllers;
use yii\console\Controller;
use yii\helpers\Console;
use yii\helpers\FileHelper;
/**
* Check files for broken UTF8 and non-printable characters.
*
* @author Carsten Brandt <mail@cebe.cc>
*/
class Utf8Controller extends Controller
{
public $defaultAction = 'check-guide';
/**
* Check guide for non-printable characters that may break docs generation.
*
* @param string $directory the directory to check. If not specified, the default
* guide directory will be checked.
*/
public function actionCheckGuide($directory = null)
{
if ($directory === null) {
$directory = \dirname(\dirname(__DIR__)) . '/docs';
}
if (is_file($directory)) {
$files = [$directory];
} else {
$files = FileHelper::findFiles($directory, [
'only' => ['*.md'],
]);
}
foreach ($files as $file) {
$content = file_get_contents($file);
$chars = preg_split('//u', $content, null, PREG_SPLIT_NO_EMPTY);
$line = 1;
$pos = 0;
foreach ($chars as $c) {
$ord = $this->unicodeOrd($c);
$pos++;
if ($ord == 0x000A) {
$line++;
$pos = 0;
}
if ($ord === false) {
$this->found('BROKEN UTF8', $c, $line, $pos, $file);
continue;
}
// http://unicode-table.com/en/blocks/general-punctuation/
if (0x2000 <= $ord && $ord <= 0x200F
|| 0x2028 <= $ord && $ord <= 0x202E
|| 0x205f <= $ord && $ord <= 0x206F
) {
$this->found('UNSUPPORTED SPACE CHARACTER', $c, $line, $pos, $file);
continue;
}
if ($ord < 0x0020 && $ord != 0x000A && $ord != 0x0009 ||
0x0080 <= $ord && $ord < 0x009F) {
$this->found('CONTROL CHARACTER', $c, $line, $pos, $file);
continue;
}
// if ($ord > 0x009F) {
// $this->found("NON ASCII CHARACTER", $c, $line, $pos, $file);
// continue;
// }
}
}
}
private $_foundFiles = [];
private function found($what, $char, $line, $pos, $file)
{
if (!isset($this->_foundFiles[$file])) {
$this->stdout("$file: \n", Console::BOLD);
$this->_foundFiles[$file] = $file;
}
$hexcode = dechex($this->unicodeOrd($char));
$hexcode = str_repeat('0', max(4 - \strlen($hexcode), 0)) . $hexcode;
$this->stdout(" at $line:$pos FOUND $what: 0x$hexcode '$char' http://unicode-table.com/en/$hexcode/\n");
}
/**
* Equivalent for ord() just for unicode.
*
* http://stackoverflow.com/a/10333324/1106908
*
* @param $c
* @return bool|int
*/
private function unicodeOrd($c)
{
$h = \ord($c[0]);
if ($h <= 0x7F) {
return $h;
} elseif ($h < 0xC2) {
return false;
} elseif ($h <= 0xDF) {
return ($h & 0x1F) << 6 | (\ord($c[1]) & 0x3F);
} elseif ($h <= 0xEF) {
return ($h & 0x0F) << 12 | (\ord($c[1]) & 0x3F) << 6
| (\ord($c[2]) & 0x3F);
} elseif ($h <= 0xF4) {
return ($h & 0x0F) << 18 | (\ord($c[1]) & 0x3F) << 12
| (\ord($c[2]) & 0x3F) << 6
| (\ord($c[3]) & 0x3F);
}
return false;
}
}

73
code-of-conduct.md

@ -1,68 +1,45 @@
Yii Contributor Code of Conduct
=======================
## Our Pledge
As contributors and maintainers of this project, and in order to keep Yii community open and welcoming, we ask to respect all community members.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
We are committed to making participation in this project a good experience for everyone.
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* The use of sexualized language or imagery
* Personal attacks
* Trolling or insulting/derogatory comments, and personal or political attacks
* Trolling or insulting/derogatory comments
* Public or private harassment
* Publishing other's private information, such as physical or electronic
addresses, without explicit permission
* Other conduct which could reasonably be considered inappropriate in
a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in response
to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments,
commits, code, wiki edits, issues, and other contributions that are not aligned to this
Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors
that they deem inappropriate, threatening, offensive, or harmful.
## Scope
* Other unethical or unprofessional conduct
This Code of Conduct applies both within project spaces and in public spaces when
an individual is representing the project or its community. Examples of representing
a project or community include posting via an official social media account,
within project GitHub, official forum or acting as an appointed representative at
an online or offline event.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Enforcement
By adopting this Code of Conduct, project maintainers commit themselves to
fairly and consistently applying these principles to every aspect of managing
this project. Project maintainers who do not follow or enforce the Code of
Conduct may be permanently removed from the project team.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported
by contacting core team members. All complaints will be reviewed and investigated
and will result in a response that is deemed necessary and appropriate to the circumstances.
The project team is obligated to maintain confidentiality with regard to the reporter of
an incident. Further details of specific enforcement policies may be posted separately.
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community.
Project maintainers who do not follow or enforce the Code of Conduct in good faith
may face temporary or permanent repercussions as determined by other members of
the project's leadership.
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting core team members. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. Maintainers are
obligated to maintain confidentiality with regard to the reporter of an
incident.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 1.4.0, available at
[https://contributor-covenant.org/version/1/4/][version]
version 1.3.0, available at
[http://contributor-covenant.org/version/1/3/0/][version]
[homepage]: https://contributor-covenant.org
[version]: https://contributor-covenant.org/version/1/4/
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/3/0/

65
composer.json

@ -5,20 +5,20 @@
"yii2",
"framework"
],
"homepage": "https://www.yiiframework.com/",
"homepage": "http://www.yiiframework.com/",
"type": "yii2-extension",
"license": "BSD-3-Clause",
"authors": [
{
"name": "Qiang Xue",
"email": "qiang.xue@gmail.com",
"homepage": "https://www.yiiframework.com/",
"homepage": "http://www.yiiframework.com/",
"role": "Founder and project lead"
},
{
"name": "Alexander Makarov",
"email": "sam@rmcreative.ru",
"homepage": "https://rmcreative.ru/",
"homepage": "http://rmcreative.ru/",
"role": "Core framework development"
},
{
@ -29,7 +29,7 @@
{
"name": "Carsten Brandt",
"email": "mail@cebe.cc",
"homepage": "https://www.cebe.cc/",
"homepage": "http://cebe.cc/",
"role": "Core framework development"
},
{
@ -47,23 +47,16 @@
"name": "Dmitry Naumenko",
"email": "d.naumenko.a@gmail.com",
"role": "Core framework development"
},
{
"name": "Boudewijn Vahrmeijer",
"email": "info@dynasource.eu",
"homepage": "http://dynasource.eu",
"role": "Core framework development"
}
],
"support": {
"issues": "https://github.com/yiisoft/yii2/issues?state=open",
"forum": "https://forum.yiiframework.com/",
"wiki": "https://www.yiiframework.com/wiki",
"irc": "ircs://irc.libera.chat:6697/yii",
"forum": "http://www.yiiframework.com/forum/",
"wiki": "http://www.yiiframework.com/wiki/",
"irc": "irc://irc.freenode.net/yii",
"source": "https://github.com/yiisoft/yii2"
},
"minimum-stability": "dev",
"prefer-stable": true,
"replace": {
"yiisoft/yii2": "self.version"
},
@ -74,38 +67,24 @@
"lib-pcre": "*",
"yiisoft/yii2-composer": "~2.0.4",
"ezyang/htmlpurifier": "~4.6",
"cebe/markdown": "~1.0.0 | ~1.1.0 | ~1.2.0",
"bower-asset/jquery": "3.6.*@stable | 3.5.*@stable | 3.4.*@stable | 3.3.*@stable | 3.2.*@stable | 3.1.*@stable | 2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable",
"bower-asset/inputmask": "~3.2.2 | ~3.3.5",
"cebe/markdown": "~1.0.0 | ~1.1.0",
"bower-asset/jquery": "2.2.*@stable | 2.1.*@stable | 1.11.*@stable",
"bower-asset/jquery.inputmask": "~3.2.2",
"bower-asset/punycode": "1.3.*",
"bower-asset/yii2-pjax": "~2.0.1",
"paragonie/random_compat": ">=1"
"bower-asset/yii2-pjax": "~2.0.1"
},
"require-dev": {
"cweagans/composer-patches": "^1.7",
"phpunit/phpunit": "4.8.34",
"cebe/indent": "~1.0.2",
"friendsofphp/php-cs-fixer": "~2.2.3",
"johnkary/phpunit-speedtrap": "^1.0"
"phpunit/phpunit": "~4.4",
"cebe/indent": "*"
},
"repositories": [
{
"type": "composer",
"url": "https://asset-packagist.org"
}
],
"suggest": {
"yiisoft/yii2-coding-standards": "you can use this package to check for code style issues when contributing to yii"
},
"autoload": {
"psr-4": {
"yii\\": "framework/",
"yii\\cs\\": "cs/src/"
"yii\\": "framework/"
}
},
"config": {
"platform": {"php": "5.4"}
},
"bin": [
"framework/yii"
],
@ -113,19 +92,9 @@
"branch-alias": {
"dev-master": "2.0.x-dev"
},
"composer-exit-on-patch-failure": true,
"patches": {
"phpunit/phpunit-mock-objects": {
"Fix PHP 7 and 8 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_mock_objects.patch"
},
"phpunit/php-file-iterator": {
"Fix PHP 8.1 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_path_file_iterator.patch"
},
"phpunit/phpunit": {
"Fix PHP 7 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_php7.patch",
"Fix PHP 8 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_php8.patch",
"Fix PHP 8.1 compatibility": "https://yiisoft.github.io/phpunit-patches/phpunit_php81.patch"
}
"asset-installer-paths": {
"npm-asset-library": "vendor/npm",
"bower-asset-library": "vendor/bower"
}
}
}

2727
composer.lock generated

File diff suppressed because it is too large Load Diff

60
contrib/completion/bash/yii

@ -1,60 +0,0 @@
# This file implements bash completion for the ./yii command file.
# It completes the commands available by the ./yii command.
# See also:
# - https://debian-administration.org/article/317/An_introduction_to_bash_completion_part_2 on how this works.
# - https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion.html
# - http://www.yiiframework.com/doc-2.0/guide-tutorial-console.html#bash-completion
#
# Usage:
# Temporarily you can source this file in you bash by typing: source yii
# For permanent availability, copy or link this file to /etc/bash_completion.d/
#
_yii()
{
local cur opts yii command
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
yii="${COMP_WORDS[0]}"
# exit if ./yii does not exist
test -f $yii || return 0
# lookup for command
for word in ${COMP_WORDS[@]:1}; do
if [[ $word != -* ]]; then
command=$word
break
fi
done
[[ $cur == $command ]] && state="command"
[[ $cur != $command ]] && state="option"
[[ $cur = *=* ]] && state="value"
[[ $prev == "help" ]] && state="help"
case $state in
command|help)
# complete command/route if not given
# fetch available commands from ./yii help/list command
opts=$($yii help/list 2> /dev/null)
;;
option)
# fetch available options from ./yii help/list-action-options command
opts=$($yii help/list-action-options $command 2> /dev/null | grep -o '^--[a-zA-Z0-9\-]*')
;;
value)
# TODO allow normal file completion after an option, e.g. --migrationPath=...
;;
esac
# generate completion suggestions
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
}
# register completion for the ./yii command
# you may adjust this line if your command file is named differently
complete -o default -F _yii ./yii yii

40
contrib/completion/zsh/_yii

@ -1,40 +0,0 @@
#compdef yii
_yii() {
local state command lastArgument commands options executive
lastArgument=${words[${#words[@]}]}
prevArgument=${words[${#words[@]}-1]}
executive=$words[1]
# lookup for command
for word in ${words[@]:1}; do
if [[ $word != -* ]]; then
command=$word
break
fi
done
[[ $lastArgument == $command ]] && state="command"
[[ $lastArgument != $command ]] && state="option"
[[ $prevArgument == "help" ]] && state="help"
case $state in
command|help)
commands=("${(@f)$(${executive} help/list 2>/dev/null)}")
_describe 'command' commands
;;
option)
options=("${(@f)$(${executive} help/usage ${command} 2>/dev/null)}")
_message -r "$options"
suboptions=("${(@f)$(${executive} help/list-action-options ${command} 2>/dev/null)}")
_describe -V -o -t suboption 'action options' suboptions
;;
*)
esac
}
compdef _yii yii

1
cs/TODO.md

@ -1 +0,0 @@
This should be moved to separate package, like `yii\yii2-cs`.

172
cs/src/YiiConfig.php

@ -1,172 +0,0 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\cs;
use PhpCsFixer\Config;
use yii\helpers\ArrayHelper;
/**
* Basic rules used by Yii 2 ecosystem.
*
* @author Robert Korulczyk <robert@korulczyk.pl>
* @since 2.0.0
*/
class YiiConfig extends Config
{
/**
* {@inheritdoc}
*/
public function __construct($name = 'yii-cs-config')
{
parent::__construct($name);
$this->setRiskyAllowed(true);
$this->setRules([
'@PSR2' => true,
'array_syntax' => [
'syntax' => 'short',
],
'binary_operator_spaces' => [
'align_double_arrow' => false,
'align_equals' => false,
],
'blank_line_after_opening_tag' => true,
'cast_spaces' => true,
'concat_space' => [
'spacing' => 'one',
],
'dir_constant' => true,
'ereg_to_preg' => true,
'function_typehint_space' => true,
'hash_to_slash_comment' => true,
'include' => true,
'heredoc_to_nowdoc' => true,
'is_null' => [
'use_yoda_style' => false,
],
'linebreak_after_opening_tag' => true,
'lowercase_cast' => true,
'magic_constant_casing' => true,
// 'mb_str_functions' => true, // needs more discussion
// 'method_separation' => true, // conflicts with current Yii style with double line between properties and methods
'modernize_types_casting' => true,
'native_function_casing' => true,
'new_with_braces' => true,
'no_alias_functions' => true,
'no_blank_lines_after_class_opening' => true,
'no_blank_lines_after_phpdoc' => true,
'no_empty_comment' => true,
'no_empty_phpdoc' => true,
'no_empty_statement' => true,
'no_extra_consecutive_blank_lines' => [
'tokens' => [
'break',
'continue',
// 'extra', // conflicts with current Yii style with double line between properties and methods
'return',
'throw',
'use',
'use_trait',
// 'curly_brace_block', // breaks namespaces blocks
'parenthesis_brace_block',
'square_brace_block',
],
],
'no_leading_import_slash' => true,
'no_leading_namespace_whitespace' => true,
'no_mixed_echo_print' => true,
'no_multiline_whitespace_around_double_arrow' => true,
'no_multiline_whitespace_before_semicolons' => true,
'no_php4_constructor' => true,
'no_short_bool_cast' => true,
'no_singleline_whitespace_before_semicolons' => true,
'no_spaces_around_offset' => true,
'no_trailing_comma_in_list_call' => true,
'no_trailing_comma_in_singleline_array' => true,
'no_unneeded_control_parentheses' => true,
'no_unused_imports' => true,
'no_useless_else' => true,
'no_useless_return' => true,
'no_whitespace_before_comma_in_array' => true,
'no_whitespace_in_blank_line' => true,
'non_printable_character' => true,
'normalize_index_brace' => true,
'object_operator_without_whitespace' => true,
// 'ordered_class_elements' => [ // needs more discussion
// 'order' => [
// 'use_trait',
// 'constant_public',
// 'constant_protected',
// 'constant_private',
// 'property_public',
// 'property_protected',
// 'property_private',
// 'construct',
// 'destruct',
// 'magic',
// ],
// ],
'ordered_imports' => [
'sortAlgorithm' => 'alpha',
'importsOrder' => [
'const',
'function',
'class',
],
],
'php_unit_construct' => true,
'php_unit_dedicate_assert' => true,
'php_unit_fqcn_annotation' => true,
// 'php_unit_strict' => true, // needs more attention
'phpdoc_add_missing_param_annotation' => true,
'phpdoc_indent' => true,
// 'phpdoc_inline_tag' => true, // see https://github.com/yiisoft/yii2/issues/11635
'phpdoc_no_access' => true,
'phpdoc_no_empty_return' => true,
'phpdoc_no_package' => true,
'phpdoc_no_useless_inheritdoc' => true,
// 'phpdoc_order', // may be useful, but should be configurable: https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues/1602
'phpdoc_return_self_reference' => true,
'phpdoc_scalar' => true,
'phpdoc_single_line_var_spacing' => true,
'phpdoc_summary' => true,
// 'phpdoc_to_comment' => true, // breaks phpdoc for define('CONSTANT', $value);
'phpdoc_trim' => true,
'phpdoc_types' => true,
'phpdoc_var_without_name' => true,
'protected_to_private' => true,
'psr4' => true,
'self_accessor' => true,
'short_scalar_cast' => true,
'single_blank_line_before_namespace' => true,
'single_quote' => true,
'standardize_not_equals' => true,
'ternary_operator_spaces' => true,
'trailing_comma_in_multiline_array' => true,
'trim_array_spaces' => true,
'unary_operator_spaces' => true,
'whitespace_after_comma_in_array' => true,
]);
}
/**
* Merge current rules' config with provided list of rules.
*
* @param array $rules
* @return $this
* @see setRules()
* @see ArrayHelper::merge()
*/
public function mergeRules(array $rules)
{
$this->setRules(ArrayHelper::merge($this->getRules(), $rules));
return $this;
}
}

39
cs/src/YiisoftConfig.php

@ -1,39 +0,0 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\cs;
/**
* Basic rules used by Yii 2 official packages.
*
* @author Robert Korulczyk <robert@korulczyk.pl>
* @since 2.0.0
*/
final class YiisoftConfig extends YiiConfig
{
/**
* {@inheritdoc}
*/
public function __construct()
{
parent::__construct('yiisoft-cs-config');
$header = <<<'HEADER'
@link http://www.yiiframework.com/
@copyright Copyright (c) 2008 Yii Software LLC
@license http://www.yiiframework.com/license/
HEADER;
$this->mergeRules([
'header_comment' => [
'header' => $header,
'commentType' => 'PHPDoc',
'separate' => 'bottom',
],
]);
}
}

39
docs/documentation_style_guide.md

@ -11,16 +11,13 @@ Guidelines to go by when writing or editing any Yii documentation.
* Demonstrate ideas using code as much as possible.
* Never use "we". It's the Yii development team or the Yii core team. Better yet to put things in terms of the framework or the guide.
* Use the Oxford comma (e.g., "this, that, and the other" not "this, that and the other").
* Numeric lists should be complete sentences that end with periods (or other punctuation).
* Bullet lists should be fragments that don't end with periods.
## Formatting
* Use *italics* for emphasis, never capitalization, bold, or underlines.
## Lists
* Numeric lists should be complete sentences that end with periods.
* Bullet lists should be fragments that end with semicolon except the last item, which should end with a period.
## Blocks
Blocks use the Markdown `> Type: `. There are four block types:
@ -35,7 +32,7 @@ The sentence after the colon should begin with a capital letter.
When translating documentation, these Block indicators should not be translated.
Keeps them intact as they are and only translate the block content.
For translating the `Type` word, each guide translation should have a `blocktypes.json` file
containing the translations. The following shows an example for German:
containing the translations. The following shows an example for german:
```json
{
@ -50,38 +47,8 @@ containing the translations. The following shows an example for German:
* Yii 2.0 or Yii 2 (not Yii2 or Yii2.0)
* Each "page" of the guide is referred to as a "section".
* References to Code objects:
- Refer to classes using the full namespace: `yii\base\Model`
- Refer to class properties using the static syntax even if they are not static: `yii\base\Model::$validators`
- Refer to class methods using the static syntax even if they are not static and include parenthesis to make it clear, that it is a method: `yii\base\Model::validate()`
- references to code objects should be writting in `[[]]` to generate links to the API documentation. E.g. `[[yii\base\Model]]`, `[[yii\base\Model::$validators]]`, or `[[yii\base\Model::validate()]]`.
## Capitalizations
* Web, not web
* the guide or this guide, not the Guide
## Validating the docs
The following are some scripts that help find broken links and other issues in the guide:
Find broken links (some false-positives may occur):
grep -rniP "\[\[[^\],']+?\][^\]]" docs/guide*
grep -rniP "[^\[]\[[^\]\[,']+?\]\]" docs/guide*
## Attribution of Translators
The names of the translators will be listed among the guide authors in the
rendered versions of the guide.
Therefor in each guide directory for a different language than english a `translators.json` file
should be created that contains an array of names of the people who have participated in the translation.
```json
[
"Jane Doe",
"John Doe"
]
```
If you have contributed a significant part to the translation, feel free to send a pull request adding your name.

205
docs/guide-ar/README.md

@ -1,205 +0,0 @@
Yii 2.0 الدليل التقني الخاص ببيئة العمل
===============================
تم تحرير هذا الملف اعتمادا على [الشروط الخاصة بتوثيف ال Yii](https://www.yiiframework.com/doc/terms/).
جميع الحقوق محفوظة
2014 (c) Yii Software LLC.
المقدمة
------------
* [عن بيئة العمل Yii](intro-yii.md)
* [التحديث من الإصدار 1.1](../guide/intro-upgrade-from-v1.md)
البداية من هنا
---------------
* [ماذا يجب أن تعرف عن بيئة العمل](start-prerequisites.md)
* [تثبيت ال Yii](start-installation.md)
* [تشغيل التطبيقات - Running Applications](start-workflow.md)
* [قل مرحبا - المشروع الأول](start-hello.md)
* [التعامل مع ال forms](start-forms.md)
* [التعامل مع قواعد البيانات](start-databases.md)
* [إنشاء الشيفرة البرمجية من خلال ال gii](start-gii.md)
* [ماذا الآن - الخطوة القادمة](start-looking-ahead.md)
الهيكلية الخاصة بالتطبيق (Application Structure)
---------------------
* [نظرة عامة عن الهيكلية الخاصة بالتطبيق](../guide/structure-overview.md)
* [Entry Scripts](../guide/structure-entry-scripts.md)
* [التطبيقات](../guide/structure-applications.md)
* [مكونات التطبيقات](../guide/structure-application-components.md)
* [Controllers](../guide/structure-controllers.md)
* [Models](../guide/structure-models.md)
* [Views](../guide/structure-views.md)
* [Modules](../guide/structure-modules.md)
* [Filters](../guide/structure-filters.md)
* [Widgets](../guide/structure-widgets.md)
* [Assets](../guide/structure-assets.md)
* [Extensions](../guide/structure-extensions.md)
التعامل مع ال requests
-----------------
* [نظرة عامة عن التعامل مع ال requests](../guide/runtime-overview.md)
* [Bootstrapping](../guide/runtime-bootstrapping.md)
* [Routing and URL Creation](../guide/runtime-routing.md)
* [Requests](../guide/runtime-requests.md)
* [Responses](../guide/runtime-responses.md)
* [Sessions and Cookies](../guide/runtime-sessions-cookies.md)
* [Handling Errors - التحكم بالأخطاء](../guide/runtime-handling-errors.md)
* [Logging - تسجيل الحركات](../guide/runtime-logging.md)
المفاهيم الرئيسية (Key Concepts)
------------
* [Components](../guide/concept-components.md)
* [Properties](../guide/concept-properties.md)
* [Events](../guide/concept-events.md)
* [Behaviors](../guide/concept-behaviors.md)
* [Configurations](../guide/concept-configurations.md)
* [Aliases](../guide/concept-aliases.md)
* [Class Autoloading](../guide/concept-autoloading.md)
* [Service Locator](../guide/concept-service-locator.md)
* [Dependency Injection Container](../guide/concept-di-container.md)
التعامل مع قواعد البيانات
----------------------
* [Database Access Objects](../guide/db-dao.md): Connecting to a database, basic queries, transactions, and schema manipulation
* [Query Builder](../guide/db-query-builder.md): Querying the database using a simple abstraction layer
* [Active Record](../guide/db-active-record.md): The Active Record ORM, retrieving and manipulating records, and defining relations
* [Migrations](../guide/db-migrations.md): Apply version control to your databases in a team development environment
* [Sphinx](https://www.yiiframework.com/extension/yiisoft/yii2-sphinx/doc/guide)
* [Redis](https://www.yiiframework.com/extension/yiisoft/yii2-redis/doc/guide)
* [MongoDB](https://www.yiiframework.com/extension/yiisoft/yii2-mongodb/doc/guide)
* [ElasticSearch](https://www.yiiframework.com/extension/yiisoft/yii2-elasticsearch/doc/guide)
الحصول على البيانات من خلال المستخدمين
-----------------------
* [Creating Forms](../guide/input-forms.md)
* [Validating Input](../guide/input-validation.md)
* [Uploading Files](../guide/input-file-upload.md)
* [Collecting Tabular Input](../guide/input-tabular-input.md)
* [Getting Data for Multiple Models](../guide/input-multiple-models.md)
* [Extending ActiveForm on the Client Side](../guide/input-form-javascript.md)
عرض البيانات
---------------
* [Data Formatting](../guide/output-formatting.md)
* [Pagination](../guide/output-pagination.md)
* [Sorting](../guide/output-sorting.md)
* [Data Providers](../guide/output-data-providers.md)
* [Data Widgets](../guide/output-data-widgets.md)
* [Working with Client Scripts](../guide/output-client-scripts.md)
* [Theming](../guide/output-theming.md)
الامان والحماية
--------
* [Security Overview](../guide/security-overview.md)
* [Authentication](../guide/security-authentication.md)
* [Authorization](../guide/security-authorization.md)
* [Working with Passwords](../guide/security-passwords.md)
* [Cryptography](../guide/security-cryptography.md)
* [Auth Clients](https://www.yiiframework.com/extension/yiisoft/yii2-authclient/doc/guide)
* [Best Practices](../guide/security-best-practices.md)
Caching التخزين المؤقت
-------
* [Caching Overview](../guide/caching-overview.md)
* [Data Caching](../guide/caching-data.md)
* [Fragment Caching](../guide/caching-fragment.md)
* [Page Caching](../guide/caching-page.md)
* [HTTP Caching](../guide/caching-http.md)
RESTful Web Services
--------------------
* [Quick Start](../guide/rest-quick-start.md)
* [Resources](../guide/rest-resources.md)
* [Controllers](../guide/rest-controllers.md)
* [Routing](../guide/rest-routing.md)
* [Response Formatting](../guide/rest-response-formatting.md)
* [Authentication](../guide/rest-authentication.md)
* [Rate Limiting](../guide/rest-rate-limiting.md)
* [Versioning](../guide/rest-versioning.md)
* [Error Handling](../guide/rest-error-handling.md)
الأدوات المساعدة أثناء تطوير التطبيقات
-----------------
* [Debug Toolbar and Debugger](https://www.yiiframework.com/extension/yiisoft/yii2-debug/doc/guide)
* [Generating Code using Gii](https://www.yiiframework.com/extension/yiisoft/yii2-gii/doc/guide)
* [Generating API Documentation](https://www.yiiframework.com/extension/yiisoft/yii2-apidoc)
فحص واختبار التطبيقات
-------
* [Testing Overview](../guide/test-overview.md)
* [Testing environment setup](../guide/test-environment-setup.md)
* [Unit Tests](../guide/test-unit.md)
* [Functional Tests](../guide/test-functional.md)
* [Acceptance Tests](../guide/test-acceptance.md)
* [Fixtures](../guide/test-fixtures.md)
مواضيع وعناوين مميزة
--------------
* [Advanced Project Template](https://www.yiiframework.com/extension/yiisoft/yii2-app-advanced/doc/guide)
* [Building Application from Scratch](../guide/tutorial-start-from-scratch.md)
* [Console Commands](../guide/tutorial-console.md)
* [Core Validators](../guide/tutorial-core-validators.md)
* [Docker](../guide/tutorial-docker.md)
* [Internationalization](../guide/tutorial-i18n.md)
* [Mailing](../guide/tutorial-mailing.md)
* [Performance Tuning](../guide/tutorial-performance-tuning.md)
* [Shared Hosting Environment](../guide/tutorial-shared-hosting.md)
* [Template Engines](../guide/tutorial-template-engines.md)
* [Working with Third-Party Code](../guide/tutorial-yii-integration.md)
* [Using Yii as a micro framework](../guide/tutorial-yii-as-micro-framework.md)
Widgets
-------
* [GridView](https://www.yiiframework.com/doc-2.0/yii-grid-gridview.html)
* [ListView](https://www.yiiframework.com/doc-2.0/yii-widgets-listview.html)
* [DetailView](https://www.yiiframework.com/doc-2.0/yii-widgets-detailview.html)
* [ActiveForm](https://www.yiiframework.com/doc-2.0/guide-input-forms.html#activerecord-based-forms-activeform)
* [Pjax](https://www.yiiframework.com/doc-2.0/yii-widgets-pjax.html)
* [Menu](https://www.yiiframework.com/doc-2.0/yii-widgets-menu.html)
* [LinkPager](https://www.yiiframework.com/doc-2.0/yii-widgets-linkpager.html)
* [LinkSorter](https://www.yiiframework.com/doc-2.0/yii-widgets-linksorter.html)
* [Bootstrap Widgets](https://www.yiiframework.com/extension/yiisoft/yii2-bootstrap/doc/guide)
* [jQuery UI Widgets](https://www.yiiframework.com/extension/yiisoft/yii2-jui/doc/guide)
Helpers
-------
* [Helpers Overview](../guide/helper-overview.md)
* [ArrayHelper](../guide/helper-array.md)
* [Html](../guide/helper-html.md)
* [Url](../guide/helper-url.md)

57
docs/guide-ar/intro-yii.md

@ -1,57 +0,0 @@
# <div dir="rtl">ما هي بيئة العمل Yii</div>
<p dir="rtl">Yii هو إطار PHP عالي الأداء يعتمد على المكونات لتطوير تطبيقات الويب الحديثة بسرعة.
إن الاسم "Yii" (يُنطق بـ "يي" أو "[جي:]" يعني "بسيطًا وتطوريًا" باللغة الصينية. ومن الممكن ايضا
اعتباره اختصارًا لـ <b>Yes It Is</b>!</p>
# <div dir="rtl">ما هي أفضل التطبيقات أو البرمجيات التي يمكن برمجتها وتتناسب مع ال Yii</div>
<p dir="rtl">
Yii هو إطار عام لبرمجة الويب ، مما يعني أنه يمكن استخدامه لتطوير كافة أنواع
تطبيقات الويب باستخدام PHP. وذلك بسبب البنية القائمة على البنية التركيبة لبيئة العمل وترابطها مع المكونات والتخزين المؤقت، وهو مناسب بشكل خاص لتطوير portals, forums, content management systems (CMS), e-commerce projects, RESTful Web services. وما إلى ذلك.
</p>
# <div dir="rtl">كيف يمكن مقارنة بيئة العمل الخاصة بال Yii مع الأطر أو بيئات العمل الأخرى؟</div>
<p dir="rtl">
إذا كنت بالفعل على دراية بإطار العمل الأخرى ، فيمكنك معرفة كيف تتم مقارنة ال Yii:
<ul dir="rtl">
<li> مثل معظم أطر عمل ال PHP ، يطبق Yii النمط المعماري MVC (Model-View-Controller).</li>
<li> ال Yii يتبنى الفلسفة التي تقول أن الشيفرة البرمجية يجب أن تكتب بأسهل طريقها وادقها، ولكنها بذات الوقت يجب أن تكون أنيقة الكتابة مظهرا ومضمونا (شكلا وتطيبقا).</li>
<li> ال Yii هو إطار متكامل (full stack) يوفر العديد من الميزات الجاهزة للإستخدام والمعدة مسبقا، مثل ال query builders وال ActiveRecord لقواعد البيانات العلاقئية (relational) وغير العلائقية (Nosql)، بالإضافة الى دعم وتجهيز ال RESTful API والتخزين المؤقت (caching) وغيرها الكثير. </li>
<li> من مميزات ال Yii إمكانية التعديل (استبدال جزء معين أو تخيصيص وإضافة) جزء معين على أغلب ال Yii core code، وبالإضافة الى هذا، يمكنك بناء ملحقات برمجية اعتمادا على ال core code، ومن ثم نشر هذه الشيفرة وتوزيعها واستخدامها دون وجود أي مشاكل أو صعوبة تذكر.</li>
<li> الأداء العالي هو الهدف الأساسي من ال Yii.</li>
</ul>
</p>
<p dir="rtl">
ال Yii إطار عمل صمم من قبل فريق برمجي متكامل، فهو ليس مجرد عمل فردي ، بل يتكون من <a href="https://www.yiiframework.com/team">فريق تطوير أساسي وقوي</a> ، بالإضافة إلى منتدى كبير
من المهنيين الذين يساهمون باستمرار في تطوير هذا الإطار. فريق المطورين الخاص بال Yii
يراقب عن كثب أحدث اتجاهات تطوير الويب وأفضل الممارسات والمميزات التي
وجدت في الأطر والمشاريع الأخرى. وتدرج بانتظام بإضافة أفضل الممارسات والميزات الى ال Yii عبر واجهات بسيطة وأنيقة.
</p>
# <div dir="rtl">الإصدارات الخاصة بال Yii</div>
<p dir="rtl">
يتوفر لدى Yii حاليًا إصداران رئيسيان: 1.1 و 2.0. الإصدار 1.1 هو الجيل القديم وهو الآن في وضع الصيانة. الإصدار 2.0 هو إعادة كتابة وهيكلة كاملة لل Yii، تم اعتماد أحدث التقنيات والبروتوكولات فيها مثل including Composer, PSR, namespaces, traits والكثير من الأمور الأخرى، وفي هذه الإرشادات، سيكون الكلام كله موجها الى الإصدار الثاني من بيئة العمل ال Yii.
</p>
# <div dir="rtl">المتطلبات الأساسية للعمل على إطار ال Yii</div>
<p dir="rtl">
<ul dir="rtl">
<li>الإصدار PHP 5.4.0 أو أكثر</li>
<li>المعرفة الأساسية بمفاهيم البرمجة كائنية التوجه OOP</li>
<li>المعرفة بآخر وأحدث التقنيات الموجودة بال php مثل ال namespaces, traits، الفهم لهذه المفاهيم سيسهل عليك العمل كثيرا</li>
</ul>
</p>
<p dir="rtl">
ملاحظة: يمكن التحقق من توافق المتطلبات الخاصة بك مع ال yii من خلال الدخول الى الصفحة requirement الموجودة بال yii
</p>

290
docs/guide-ar/start-databases.md

@ -1,290 +0,0 @@
# <div dir="rtl">التعامل مع قواعد البيانات</div>
<p dir="rtl">
في هذا الجزء التعليمي ستتعلم آلية إنشاء صفحة جديدة تعرض بيانات يتم جلبها من قاعدة البيانات -في هذا المثال، البيانات تخص ال country-، هذه البيانات سيتم جلبها من جدول موجود في قاعدة البيانات يسمى ب <code>country</code>. لتحقيق هذا المهمة، ستقوم بعمل ال config الخاص بالإتصال بقاعدة بيانات، بالإضافة لإنشاء ال <a href="../guide/db-active-record.md">Active Record</a> class، وتعريف ال <a href="../guide/structure-controllers.md">action</a>، وإنشاء <a href="../guide/structure-views.md">view</a> لهذه الصفحة.
</p>
<p dir="rtl">
في هذا الشرح ستتعلم كيف يمكنك القيام بما يلي:
</p>
<ul dir="rtl">
<li>إعداد ال connection الخاص بقاعدة البيانات</li>
<li> التعرف على ال active record.</li>
<li>إنشاء جمل إستعلام عن البياتات بإستخدام ال active record class</li>
<li>عرض البيانات داخل ال view من خلال ال paginated fashion.</li>
</ul>
<p dir="rtl">
ملاحظة: من أجل الانتهاء من هذا الجزء التعليمي، يجب أن يكون لديك المعرفة الأساسية والخبرة باستخدام قواعد البيانات. وعلى وجه الخصوص، يجب أن تعرف كيفية إنشاء قواعد البيانات، وكيفية تنفيذ ال statements SQL باستخدام أي DB client tool.
</p>
## <div dir="rtl">إعداد قاعدة البيانات</div> <span id="preparing-database"></span>
<p dir="rtl">
في البداية، عليك إنشاء قاعدة بيانات تسمى ب <code>yii2basic</code>، والتي ستستخدم لجلب البيانات الخاصة بالتطبيق، ويمكنك إستخدام أي من ال SQLite, MySql, PostgreSQL, MSSQL or Oracle database, ال Yii بشكل افتراضي بدعم العديد من قواعد البيانات والتي يمكنك إستخدامها مباشرة في التطبيق الخاص بك، ولتبسيط الأمور، ال MySql هي التي سيتم إستخدامها في في هذا الشرح.
</p>
<blockquote class="info"><p dir="rtl">
معلومة: إذا كنت ترغب بالحصول على خيارات متقدمة مثل دعم ال <code>JSON</code> الموجود داخل MariaDB، فيمكنك من إستخدام أحد ال Extension المذكوره بالأسفل للقيام بهذه المهمة بدلا من الإستغناء عن ال MySql، فإستخدام MariaDB بدلا عن ال MySql لم يعد صحيحا تماما.
</p></blockquote>
<p dir="rtl">
بعد قيامك بإنشاء قاعدة البيانات، سنقوم بإنشاء جدول إسمه <code>country</code>، ومن ثم سنقوم بإدخال بعض البيانات كعينة للإختيار، وللقيام بذلك، قم بتنفيذ الأوامر التالية:
</p>
```sql
CREATE TABLE `country` (
`code` CHAR(2) NOT NULL PRIMARY KEY,
`name` CHAR(52) NOT NULL,
`population` INT(11) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `country` VALUES ('AU','Australia',24016400);
INSERT INTO `country` VALUES ('BR','Brazil',205722000);
INSERT INTO `country` VALUES ('CA','Canada',35985751);
INSERT INTO `country` VALUES ('CN','China',1375210000);
INSERT INTO `country` VALUES ('DE','Germany',81459000);
INSERT INTO `country` VALUES ('FR','France',64513242);
INSERT INTO `country` VALUES ('GB','United Kingdom',65097000);
INSERT INTO `country` VALUES ('IN','India',1285400000);
INSERT INTO `country` VALUES ('RU','Russia',146519759);
INSERT INTO `country` VALUES ('US','United States',322976000);
```
<p dir="rtl">
الآن، أصبح لديك قاعدة بيانات إسمها <code>yii2basic</code>، وتحوي بداخلها جدول بثلاث أعمدة يسمى ب <code>country</code>، وفيه 10 صفوف من البيانات.
</p>
## <div dir="rtl">إعدادات الإتصال الخاصة بقواعد البيانات - Configuring a DB Connection</div> <span id="configuring-db-connection"></span>
<p dir="rtl">
قبل أن تكمل الشرح، تأكد من تثبيت ال PHP <a href="https://www.php.net/manual/en/book.pdo.php">PDO</a> وال PDO driver، بالنسبة لهذا المثال، فإننا سنستخدم ال driver الخاص بال MySql وهو ال <code>pdo_mysql</code>، وهذه هي المتطلبات الأساسية لبناء أي التطبيق اذا كان التطبيق يستخدم ال relational database.
</p>
<blockquote class="note"><p dir="rtl">
ملاحظة: يمكنك تقعيل ال PDO مباشرة من خلال الدخول الى php.ini ومن ثم حذف الفاصلة المنقوطة قبل السطر التالي: <code>extension=php_pdo.dll</code>
كما يمكنك تفعيل ال driver المطلوب عن طريق حذف الفاصلة المنقوطة قبل ال driver المقصود مثل:
<code>extension=php_pdo_mysql.dll</code>
ويمكنك الإطلاع على المزيد من هنا:
<a href="https://www.php.net/manual/en/pdo.installation.php">pdo installation</a>
</p></blockquote>
<p dir="rtl">
بعد إتمام ما سبق، قم بفتح الملف <code>config/db.php</code> ومن ثم قم بتعديل ال parameters لتكون الإعدادات الخاصة بقاعدة البيانات صحيحة -الإعدادت الخاصة بك-، بشكل افتراضي، يحتوي الملف على ما يلي:
</p>
```php
<?php
return [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=yii2basic',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
];
```
<p dir="rtl">
يمثل ملف ال <code>config/db.php</code> أداة نموذجية تعتمد على الملفات للقيام بال <a href="../guide/concept-configurations.md">configuration</a>. يقوم ملف ال configuration بتحديد ال parameters المطلوبة لإنشاء وإعداد ال instance الخاص بال <code>[[yii\db\Connection]]</code>، ومن خلالها يمكنك إجراء عمليات الإستعلام على قاعدة البيانات.
</p>
<p dir="rtl">
الإعدادات الخاصة بالإتصال بقاعدة البيانات والمذكورة في الملف أعلاه يمكن الوصول اليها من خلال التطبيق عن طريق تنفيذ الأمر التالي
<code>Yii::$app->db</code>
</p>
<blockquote class="info"><p dir="rtl">
معلومة: سيتم تضمين ملف ال <code>config/db.php</code> من خلال ال main application configuration والذي يتمثل بالملف <code>config/web.php</code>، والذي يقوم بدوره بتحديد كيف يمكن تهيئة ال instance الخاص <a href="../guide/concept-configurations.md">بالتطبيق</a>، لمزيد من المعلومات، يرجى الإطلاع على قسم ال <a href="../guide/concept-configurations.md">Configurations</a>.
</p></blockquote>
<p dir="rtl">
إذا كنت بحاجة إلى العمل مع إحدى قواعد البيانات الغير مدعومة بشكل إفتراضي من ال Yii، فيمكنك التحقق من الإضافات التالية:
</p>
<ul dir="rtl">
<li><a href="https://github.com/edgardmessias/yii2-informix">Informix</a></li>
<li> <a href="https://github.com/edgardmessias/yii2-ibm-db2">IBM DB2</a></li>
<li> <a href="https://github.com/edgardmessias/yii2-firebird">Firebird</a></li>
<li> <a href="https://github.com/sam-it/yii2-mariadb">MariaDB</a></li>
</ul>
## <div dir="rtl">إنشاء ال Active Record<span id="creating-active-record"></span>
<p dir="rtl">
لجلب البيانات وعرضها من جدول ال <code>country</code>، سنقوم بإضافة ال <a href="../guide/db-active-record.md">Active Record</a> الى ال class المسمى ب <code>country</code>، والموجود في المسار <code>models/Country.php</code>.
</p>
```php
<?php
namespace app\models;
use yii\db\ActiveRecord;
class Country extends ActiveRecord
{
}
```
<p dir="rtl">
يرث ال <code>Country</code> Class ال [[yii\db\ActiveRecord]]، ولذلك، أنت لست بحاجة لكتابة أي شيفرة برمجية بداخله، فقط الشيفرة التي تشاهدها بالأعلى. سيقوم ال Yii بشكل تلقائي بالحصول على إسم الجدول في قاعدة البيانات من خلال إسم ال Class.
</p>
<blockquote class="info"><p dir="rtl">
معلومة: إذا لم يكن من الممكن إجراء مطابقة مباشرة بين اسم ال class واسم الجدول، فيمكنك تجاوز هذه المشكلة من خلال إستخدام الدالة [[yii\db\ActiveRecord::tableName()]] ، والتي ستقوم بعمل override على اسم الجدول.
</p></blockquote>
<p dir="rtl">
من خلال إستخدام ال <code>Country</code> class، يمكنك التحكم بكل سهولة بالبيانات الموجودة داخل جدول ال <code>country</code>، شاهد هذه الشيفرة البرمجية لتبسيط الفكرة:
</p>
```php
use app\models\Country;
// get all rows from the country table and order them by "name"
$countries = Country::find()->orderBy('name')->all();
// get the row whose primary key is "US"
$country = Country::findOne('US');
// displays "United States"
echo $country->name;
// modifies the country name to be "U.S.A." and save it to database
$country->name = 'U.S.A.';
$country->save();
```
<blockquote class="info"><p dir="rtl">
معلومة: يعتبر ال Active Record وسيلة قوية للوصول إلى بيانات قاعدة البيانات والتعامل معها بطريقة ال object oriented.
ستجد معلومات أكثر تفصيلاً في الجزء الخاص بال <a href="../guide/db-active-record.md">Active Record</a>. بالإضافة الى ذلك، يمكنك التفاعل مباشرة مع قاعدة البيانات باستخدام lower-level data accessing والتي تسمى ب <a href="../guide/db-dao.md">Database Access Objects</a>.
</p></blockquote>
## <div dir="rtl">إنشاء ال Action</a> <span id="creating-action"></span>
<p dir="rtl">
لعرض بيانات ال country للمستخدمين، يلزمك إنشاء action جديد، وبدلاً من وضع ال action الجديد في ال <code>site</code> controller كما فعلنا في المرات السابقة، سنقوم بإنشاء controller جديد، ومن ثم سنقوم بوضع ال action بداخله، والسبب المنطقي لهذا العمل أنك ستقوم بتجميع الشيفرة البرمجية المسؤولة عن أداء وظائف معينة في مكان واحد، وبهذا فإن جميع الإجرائات التي تخص ال country من المنطقي أن تكون موجودة داخل ال <code>CountryController</code>، والآن لنقم بإنشاء هذا ال controller الجديد، وال action الجديد وسيكون باسم <code>index</code>، كما هو موضح أدناه:
</p>
```php
<?php
namespace app\controllers;
use yii\web\Controller;
use yii\data\Pagination;
use app\models\Country;
class CountryController extends Controller
{
public function actionIndex()
{
$query = Country::find();
$pagination = new Pagination([
'defaultPageSize' => 5,
'totalCount' => $query->count(),
]);
$countries = $query->orderBy('name')
->offset($pagination->offset)
->limit($pagination->limit)
->all();
return $this->render('index', [
'countries' => $countries,
'pagination' => $pagination,
]);
}
}
```
<p dir="rtl">
قم بحفظ الشيفرة البرمجية التي بالأعلى داخل هذا الملف <code>controllers/CountryController.php</code>
</p>
<p dir="rtl">
يقوم ال <code>index</code> action باستخدام ال <code>Country::find()</code>، وهذه الدالة موجودة من ضمن ال <code>active record</code>، وتقوم هذه الدالة على بناء الإستعلام الخاص بقاعدة البيانات مما يسمح باسترجاع جميع البيانات الموجودة بداخل جدول ال country، ولتحديد الحد الأعلى المسموح إرجاعه في كل request، يمكنك إستخدام ال <code>[[yii\data\Pagination]]</code> object كوسيلة مساعدة، ويقدم هذا ال object غرضين أساسيين وهما:
</p>
<ul dir="rtl">
<li>كتابة جملة استعلام محددة بعدد صفوف معين، وتبدأ من مكان معين، ويتم ذلك من خلال ال <code>offset</code> وال <code>limit</code>، وبهذا التعيين فأنت ستقوم بإرجاع صفحة واحدة من البيانات وفي كل مرة سيتم عرض 5 صفوف على الأكثر. </li>
<li>كما يستخدم في صفحة ال view لعرض ال pager مع قائمة بال page buttons، وذلك كما ستشاهد في الجزء التالي من هذا الموضوع. </li>
</ul>
<p dir="rtl">
في نهاية الشيفرة البرمجية الموجودة في ال <code>index</code> action، نقوم باستدعاء صفحة ال view المسمية ب <code>index</code>، ومن ثم نقوم بإرسال معلومات ال country المنظمة على شكل صفحات (pagination) ومن ثم عرضها.
</p>
## <div dir="rtl"> إنشاء View </div> <span id="creating-view"></span>
<p dir="rtl">
الآن، سنقوم بإنشاء صفحة ال view والتي ستقوم بعرض المعلومات الخاصة بال country والقادمة من ال index action، ولذلك توجه الى المسار <code>views</code>, ومن ثم قم بإنشاء مجلد جديد بداخله باسم <code>country</code>، هذا المجلد سيحوي جمع ال views التي سيتم إستدعائها من ال <code>country</code> controller>. الآن، قم بإنشاء الصفحة index.php بداخل المسار <code>views/country</code>، ومن ثم قم بكتابة هذه الشيفرة البرمجية بداخلها:
</p>
```php
<?php
use yii\helpers\Html;
use yii\widgets\LinkPager;
?>
<h1>Countries</h1>
<ul>
<?php foreach ($countries as $country): ?>
<li>
<?= Html::encode("{$country->code} ({$country->name})") ?>:
<?= $country->population ?>
</li>
<?php endforeach; ?>
</ul>
<?= LinkPager::widget(['pagination' => $pagination]) ?>
```
<p dir="rtl">
في هذه الصفحة، هناك جزئيين رئيسيين، الجزء الأول هو المسؤول عن طباعة المعلومات الخاصة بال country داخل قائمة من نوع ul، والجزء الثاني عبارة عن widget يستخدم المعلومات الخاصة بال pagination والتي تم إرسالها من ال action، ليقوم بعد ذلك بعرض قائمة من ال page buttons، والتي بدورها ستقوم بعمل تحديث للمعلومات الموجودة بالصفحة بنائا على الصفحة المطلوبة، هذا ال widget يسمى ب <code>LinkPager -[[yii\widgets\LinkPager]]-</code>.
</p>
## <div dir="rtl">لنجرب المثال</div> <span id="trying-it-out"></span>
<p dir="rtl">
لتشاهد آلية العمل لهذا المثال، والنتائج المتعلقة به، يمكنك إستخدام المتصفح والدخول الى الرابط التالي:
</p>
```
http://hostname/index.php?r=country%2Findex
```
![Country List](../guide/images/start-country-list.png)
<p dir="rtl">
في البداية، ستشاهد البيانات الخاصة بخمسة دول، وأسفل هذه الدول، ستشاهد pager فيه 4 أزرار، اذا قمت بالضغط على الزر رقم 2، فإنك ستشاهد المعلومات الخاصة بخمسة دول أخرى، والتي تمثل صفوف أخرى من البيانات تم جلبها من قاعدة البيانات.
<br />
تابع بعناية أكبر وستجد أن عنوان ال URL في المتصفح قد تغير أيضًا:
</p>
```
http://hostname/index.php?r=country%2Findex&page=2
```
<p dir="rtl">
بالخفاء، يقوم ال <code>[[yii\data\Pagination|Pagination]]</code> بتقديم الدعم اللازم لكل الوظائف المطلوب تنفيذها لعمل الترقيم الخاص بال pagination:
</p>
<ul dir="rtl">
<li>في البداية، يمثل ال [[yii\data\Pagination|Pagination]] الصفحة الأولى التي تعكس جملة الإستعلام SELECT مع الجدول country مع العبارة <code>LIMIT 5 OFFSET 0</code>. ونتيجة لذلك، سيتم جلب البلدان الخمسة الأولى وعرضها.</li>
<li>ال [[yii\widgets\LinkPager|LinkPager]] widget يقوم على إستدعاء الأزرار الخاصة بأرقام الصفحات والتي يتم إنشاء ال Url الخاص بها من خلال ال [[yii\data\Pagination::createUrl()|Pagination]]، هذه ال Url تحتوي على parameter يسمى ب <code>page</code>، والذي يمثل بدورة مجموعة من الأرقام المختلفة والتي تمثل صفحات تعرض بيانات مختلفة كما هو في مثالنا عندما قمنا بالضغط على رقم 2.</li>
<li>عند قيامك بالنقر على الزر رقم 2، سينطلق request جديد الى ال <code>country/index</code> route، وحينها يقوم ال [[yii\data\Pagination|Pagination]] على قرائة ال <code>page</code> parameter من ال URL ,من ثم يقوم بتغيير رقم الصفحة الحالية الى الرقم الجديد، وهنا الرقم الجديد هو 2 بدلا من 1. كما أن جملة الإستعلام الجديدة ستحوي الشرط التالي <code>LIMIT 5 OFFSET 5</code> لتقم بذلك بجلب الصفوف الخمسة الأخرى من البلدان لعرضها.</li>
</ul>
## <div dir="rtl">الخلاصة</div> <span id="summary"></span>
<p dir="rtl">
في هذا الجزء من التوثيق، لقد تعلمنا كيف يمكننا التعامل مع قواعد البيانات، وكيف يمكننا جلب البيانات وعرضها وتجزئتها لصفحات من خلال إستخدام ال [[yii\data\Pagination]] وال [[yii\widgets\LinkPager]].
</p>
<p dir="rtl">
في الجزء القادم من هذا التوثيق، ستتعلم كيف يمكنك إستخدام إخدى الوسائل المميزة والموجودة في ال Yii لإنشاء الشيفرة البرمجية الخاصة بك، والتي يطلق عليها اسم <a href="https://www.yiiframework.com/extension/yiisoft/yii2-gii/doc/guide">Gii</a>، هذه الأداة ستساعدك على إنشاء وتنفيذ الشيفرات البرمجية التي يكثر كتابتها وإستخدامها بشكل دوري، مثل مجموعة العمليات Create-Read-Update-Delete، والتي يتم اختصارها ب CRUD، هذه الأداة ستقوم بالتعامل مع البيانات الموجدة بقاعدة البيانات، وفي الحقيقة، الشيفرة البرمجية الذي قمت بكتابته بالأعلى، يمكنك إنشائه بسهولة من خلال ال Gii بنقرة زر، لذلك فلننطلق الى الجزء التالي بأسرع وقت.
</p>

253
docs/guide-ar/start-forms.md

@ -1,253 +0,0 @@
# <div dir="rtl">العمل مع ال Forms</div>
<p dir="rtl">
في هذا الموضوع سنتعلم كيفية إنشاء صفحة تحتوي على form للحصول على البيانات من خلال المستخدمين، وستعرض هذه الصفحة form يحتوي على حقل لإدخال الإسم وحقل إدخال للبريد الإلكتروني.
وبعد الحصول على المعلومات الخاصة بهذه الحقول من المستخدم، ستقوم الصفحة بطباعة القيم التي تم إدخالها.
</p>
<p dir="rtl">
في هذا الشرح، ستقوم بإضافة <a href="../guide/structure-controllers.md">action</a> وصحفتين <a href="../guide/structure-views.md">views</a>، وستتعرف أيضا على طريقة إنشاء ال <a href="../guide/structure-models.md">model</a>.
</p>
<p dir="rtl">
من خلال هذا البرنامج التعليمي ، ستتعلم كيفية:
</p>
<ul dir="rtl">
<li>إنشاء model لتمثيل البيانات التي تم إدخالها من خلال المستخدم عن طريق ال form.</li>
<li>إنشاء rules للتحقق من صحة البيانات التي تم إدخالها.</li>
<li>بناء html form داخل صفحة ال view.</li>
</ul>
## <div dir="rtl">إنشاء ال Model</div> <span id="creating-model"></span>
<p dir="rtl">
يتم تمثيل البيانات التي يتم طلبها من خلال المستخدم عن طريق ال <code>EntryForm</code> model class كما هو موضح أدناه، ويتم حفظ هذا الملف داخل المسار models، ويكون إسم ال model ومساره في مثالنا هذا هو <code>models/EntryForm.php</code>. يرجى الرجوع إلى صفحة ال <a href="../guide/concept-autoloading.md">Class Autoloading</a> للحصول على مزيد من التفاصيل حول طريقة التعامل مع التسمية الخاصة بال class في Yii.
</p>
```php
<?php
namespace app\models;
use Yii;
use yii\base\Model;
class EntryForm extends Model
{
public $name;
public $email;
public function rules()
{
return [
[['name', 'email'], 'required'],
['email', 'email'],
];
}
}
```
<p dir="rtl">
هذا ال class يرث ال [[yii\base\Model]], وهو base class تم تصميمه من خلال ال Yii, وبشكل عام وظيفته هي تثمثيل البيانات الخاصة بأي نموذج.
</p>
<blockquote class="info"><p dir="rtl">
معلومة: يتم إستخدام ال [[yii\base\Model]] كأصل لل model class <b>ولا</b> يرتبط بجداول قواعد البيانات. ويستخدم ال [[yii\db\ActiveRecord]] بالشكل الإعتيادي ليكون هو الأصل الذي من خلاله يتم الإرتباط بجداول بقواعد البيانات.
</p></blockquote>
<p dir="rtl">
يحتوي class ال <code>EntryForm</code> على متغيرين إثنين من نوع Public، هما <code>name</code> و <code>email</code>، واللذان يستخدمان في تخزين البيانات التي أدخلها المستخدم. كما يحتوي أيضًا على method باسم <code>rules()</code>، والتي تُرجع مجموعة
الشروط الخاصة بالبيانات للتحقق من صحتها. والشيفرة البرمجية الموجودة داخل ال rules method تعني:
</p>
<ul dir="rtl">
<li>كل من ال <code>name</code> وال <code>email</code> حقول الزامية (required).</li>
<li>ال <code>email</code> حقل يجب أن يحتوي بداخله قيمة صحيحة تعبر عن البريد الإلكتروني (القواعد النحوية لكتابة البريد الإلكتروني).</li>
</ul>
<p dir="rtl">
إذا كان لديك object من ال <code>EntryForm</code> ويحتوي على البيانات التي أدخلها المستخدم، فيمكنك حينها إستدعاء الدالة [[yii\base\Model::validate()|validate()]] للتحقق من صحة البيانات. اذا فشلت عملية التحقق من صحة البيانات، فسيؤدي ذلك إلى تغيير قيمة ال [[yii\base\Model::hasErrors|hasErrors]] إلى <code>true</code> ، بالإضافة الى ذلك يمكنك التعرف الى الأخطاء المتعلقة بهذه البيانات من خلال الدالة [[yii\base\Model::getErrors|errors]].
</p>
```php
<?php
$model = new EntryForm();
$model->name = 'Qiang';
$model->email = 'bad';
if ($model->validate()) {
// Good!
} else {
// Failure!
// Use $model->getErrors()
}
```
## <div dir="rtl">إنشاء Action</div> <span id="creating-action"></span>
<p dir="rtl">
الآن، ستحتاج إلى إنشاء <code>action</code> جديد في ال <code>site</code> controller وليكن إسمه <code>entry</code>، والذي سيقوم بدوره باستخدام ال model الجديد الذي قمنا بإنشائه. هذه العملية تم شرحها سابقا في الجزء التالي من التوثيق <a href="start-hello.md">Saying Hello - قل مرحبا</a>.
</p>
```php
<?php
namespace app\controllers;
use Yii;
use yii\web\Controller;
use app\models\EntryForm;
class SiteController extends Controller
{
// ...existing code...
public function actionEntry()
{
$model = new EntryForm();
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
// valid data received in $model
// do something meaningful here about $model ...
return $this->render('entry-confirm', ['model' => $model]);
} else {
// either the page is initially displayed or there is some validation error
return $this->render('entry', ['model' => $model]);
}
}
}
```
<p dir="rtl">
أولا، يقوم ال action بإنشاء object من ال <code>EntryForm</code>. ثم يحاول تعبئة البيانات لل object من خلال ال <code>$ _POST</code>، والتي يتم تقديمها في ال Yii من خلال ال [[yii\web\Request::post()]].
إذا تم ملء ال object بنجاح (على سبيل المثال، إذا قام المستخدم بإدخال البيانات داخل ال form ومن ثم قام بإرسالها(submitted html form))، فسيتم استدعاء ال [[yii\base\Model::validate()|validate()]] من خلال ال action للتأكد من صلاحية القيم المدخلة.
</p>
<blockquote class="info"><p dir="rtl">
معلومة: يمثل التعبير Yii::$app ال <a href="../guide/structure-applications.md">Application</a> instance الذي يمكن الوصول اليه من خلال ال singleton <br />(singleton globally accessible). وهو أيضا <a href="../guide/concept-service-locator.md">service locator</a> بحيث يوفر الدعم لل components مثل ال request, response, db..الخ، لدعم وظائف محددة. مثلا في المثال الموجود في الأعلى، فإن ال request هو component من ال application instance والذي يستخدم للوصول الى البيانات الموجودة داخل ال $_POST.
</p></blockquote>
<p dir="rtl">
إذا كان كل شيء على ما يرام، فسوف يقوم ال action بجلب ال view التالية: <code>entry-confirm</code>، وذلك لتأكيد أن العملية قد تمت بنجاح بالنسبة للمستخدم، أما إن كانت البيانات غير صحيحة، أو لم يتم إرسال أي بيانات، فإن ال view <code>entry</code> هي التي سيتم جلبها وعرضها للمستخدم، حيث يتم عرض ال Html form، مع أي رسائل تحذير بخصوص الأخطاء التي تم العثور عليها من عملية التحقق.
</p>
<blockquote class="note"><p dir="rtl">
ملاحظة: في هذا المثال البسيط، نعرض صفحة التأكيد فقط عند إرسال البيانات بشكل صحيح. عند الممارسة العملية، يجب عليك استخدام [[yii\web\Controller::refresh()|refresh()]] أو [[yii\web\Controller::redirect()|redirect()]] لتجنب أي مشكلة تحصل عن طريق ال resubmission والتي تندرج تحت العنوان <a href="https://en.wikipedia.org/wiki/Post/Redirect/Get">form resubmission problems</a>.
</p></blockquote>
## <div dir="rtl">إنشاء ال views</div> <span id="creating-views"></span>
<p dir="rtl">
أخيرا، سنقوم بإنشاء صفحتين لل views الأولى بإسم <code>entry-confirm</code> والثانية <code>entry</code>. وهاتين الصفحتين سيتم جلبهم من خلال ال <code>entry</code> action.
</p>
<p dir="rtl">
ال <code>entry-confirm</code> ستقوم بكل بساطة بعرض الإسم والبريد الإلكتروني الذي تم إدخالهم من قبل المستخدم. ويجب حفظ هذه الصفحة بالمسار التالي: <code>views/site/entry-confirm.php</code>
</p>
```php
<?php
use yii\helpers\Html;
?>
<p>You have entered the following information:</p>
<ul>
<li><label>Name</label>: <?= Html::encode($model->name) ?></li>
<li><label>Email</label>: <?= Html::encode($model->email) ?></li>
</ul>
```
<p dir="rtl">
صفحة ال <code>entry</code> ستقوم بعرض ال HTML form. هذه الصفحة يجب أن يتم حفظها داخل المسار التالي: <code>views/site/entry.php</code>
</p>
```php
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
?>
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($model, 'name') ?>
<?= $form->field($model, 'email') ?>
<div class="form-group">
<?= Html::submitButton('Submit', ['class' => 'btn btn-primary']) ?>
</div>
<?php ActiveForm::end(); ?>
```
<p dir="rtl">
تستخدم ال view أسلوب مميز لبناء ال Forms، وذلك عن طريق ال <a href="../guide/structure-widgets.md">widget</a> الذي يسمى ب [[yii\widgets\ActiveForm|ActiveForm]]. إن الأسلوب المستخدم في هذا ال widget يقوم على إستخدام كل من الدالة <code>begin()</code> و <code>end()</code> لجلب ال opening وال closing form tags على التوالي (فتحة ال tag، ثم الإغلاق الخاص بهذا ال tag)، وبين الفتحة والإغلاق يمكنك إنشاء الحقول عن طريق إستخدام الدالة [[yii\widgets\ActiveForm::field()|field()]]. في هذا المثال كان الحقل الأول في ال form يشير الى name data، والثاني يشير الى ال email data، وبعد هذه الحقول ستجد الدالة المستخدمة لإنشاء ال Submit button وهي [[yii\helpers\Html::submitButton()]].
</p>
## <div dir="rtl">لنجرب المثال</div> <span id="trying-it-out"></span>
<p dir="rtl">
لتشاهد آلية العمل لهذا المثال، والنتائج المتعلقة به، يمكنك إستخدام المتصفح والدخول الى الرابط التالي:
</p>
```
http://hostname/index.php?r=site%2Fentry
```
<p dir="rtl">
عند دخولك الى الرابط السابق، سترى صفحة تعرض Html form يحتوي على حقلين لإدخال المعلومات. أمام كل حقل إدخال ستجد label يشير إلى البيانات المطلوب إدخالها. إذا قمت بالنقر فوق الزر "submit" بدون
أي إدخال، أو إذا لم تقم بكتابة عنوان البريد الإلكتروني بشكل صحيح، فستظهر لك رسالة خطأ بجوار الحقل المقصود.
</p>
![Form with Validation Errors](../guide/images/start-form-validation.png)
<p dir="rtl">
بعد إدخالك لإسم وبريد الكتروني صحيح، وقيامك بالنقر على زر submit، فإنك ستشاهد صفحة جديدة تقوم بعرض البيانات التي قمت بإدخالها.
</p>
![Confirmation of Data Entry](../guide/images/start-entry-confirmation.png)
## <div dir="rtl">كيف ظهر الخطأ؟ هل هو سحر؟!</div> <span id="magic-explained"></span>
<p dir="rtl">
قد تتساءل كيف يعمل ال Html form بالخفاء، وقد يبدو ذلك سحرا للوهلة الأولى، فهو يعرض ال label لكل حقل إدخال، ويعرض رسائل الخطأ إذا لم تقم بإدخال البيانات بشكل صحيح، وكل ذلك دون الحاجة لإعادة تحميل الصفحة.
</p>
<p dir="rtl">
إن السحر الموجود لدينا هنا، هو كيفية العمل الخاصة بالشيفرة البرمجية لل form، والتي تعمل بالخفاء، إن إجراء التحقق عن صحة البيانات يتم في البداية من جانب العميل -client side- وذلك باستخدام الجافا سكربت، ومن ثم -بعد تجاوز التحقق الخاص بالجافا سكربت- بتم تنفيذ التحقق من جانب ال server-side عبر ال PHP. ال [[yii\widgets\ActiveForm]] ذكية بما فيه الكفاية لاستخراج ال rule الخاصة بالتحقق والتي قمت بإنشائها وتعريفها داخل ال <code>EntryForm</code>، ومن ثم تحويل هذه القواعد إلى شيفرة برمجية بالجافا سكربت قابلة للتنفيذ، ومن ثم استخدام هذه الشيفرة من قبل الجافا سكربت لإجراء التحقق من صحة البيانات. في حال قمت بإيقاف الجافا سكربت في المتصفح الخاص بك، سوف يستمر إجراء التحقق من جانب الخادم -server side-، كما هو موضح في ال action المسمى <code>actionEntry()</code>. وهذا يضمن صحة البيانات في جميع الظروف.
</p>
<blockquote class="warning"><p dir="rtl">
تحذير: التحقق من جانب العميل -client side- يوفر تجربة أفضل للمستخدم، لكن يجب الأخذ بعين الإعتبار أن التحقق من جانب الخادم -server- مطلوب دائمًا، سواء تم التحقق من جانب العميل أم لا.
</p></blockquote>
<p dir="rtl">
يتم إنشاء ال labels الخاصة بحقول الإدخال بواسطة الدالة <code>field()</code>، وذلك من خلال إستخدام أسماء ال property الموجودة داخل ال model. على سبيل المثال، سيتم إنشاء ال label التالي <code>Name</code> للproperty التالية: <code>name</code>.
</p>
<p dir="rtl">
كما يمكنك تعديل ال label الإفتراضي لأي حقل من خلال الشيفرة البرمجية التالية:
</p>
```php
<?= $form->field($model, 'name')->label('Your Name') ?>
<?= $form->field($model, 'email')->label('Your Email') ?>
```
<blockquote class="info"><p dir="rtl">
معلومة: يوفر ال Yii العديد من ال widgets لمساعدتك في إنشاء views معقدة وديناميكية بسرعة. كما أنك ستتعلم في وقت لاحق كيف يمكنك إنشاء widget جديد، وستكتشف أن الموضوع سهل وبسيط، مما سيدفعك إلى كتابة الشيفرة البرمجية الخاصة بك داخل ال widget، والذي بدوره سيجعل من هذه الشيفرة قابلة للتطوير والإستخدام في أكثر من مكان في المستقبل.
</p></blockquote>
## <div dir="rtl">الخلاصة</div> <span id="summary"></span>
<p dir="rtl">
في هذا الجزء من التوثيق، تحدثنا عن كل جزء في ال MVC architectural pattern، لقد تعلمت الآن كيف يمكنك إنشاء model class ليقوم بتمثيل البيانات الخاصة بالمستخدمين، ومن ثم التحقق منها.
</p>
<p dir="rtl">
لقد تعلمت أيضًا كيفية الحصول على البيانات من المستخدمين، وكيفية عرض البيانات مرة أخرى في المتصفح. هذه المهمة يمكن أن تأخذ الكثير من الوقت عند تطوير أي تطبيق، ولكن، يوفر ال Yii العديد من ال widgets القوية، والتي تجعل من هذه المهمة أمرا سهلا للغاية.
</p>
<p dir="rtl">
في الجزء القادم من هذا التوثيق، ستتعلم كيف يمكنك التعامل مع قواعد البيانات، والتي سنحتاجها -غالبا- مع كل تطبيق ستعمل عليه تقريبا.
</p>

161
docs/guide-ar/start-gii.md

@ -1,161 +0,0 @@
# <div dir="rtl">إنشاء الشيفرة البرمجية من خلال ال gii</div>
<p dir="rtl">
في هذا الجزء التعليمي سنتعرف على آلية التعامل مع ال <a href="https://www.yiiframework.com/extension/yiisoft/yii2-gii/doc/guide">Gii</a>، والذي يستخدم لإنتاج الشيفرة البرمجية الخاصة بمعظم الميزات والخصائص المشتركة في أغلب المواقع بشكل تلقائي، بالإضافة الى ذلك، فإن استخدام ال Gii لإنشاء الشيفرة البرمجية بشكل تلقائي يمثل مجموعة من المعلومات الصحيحة التي بتم إدخالها إعتمادا على التعليمات الموجودة في ال Gii Web Pages.
</p>
<p dir="rtl">
من خلال هذا البرنامج التعليمي، ستتعلم كيفية:
</p>
<ul dir="rtl">
<li>تفعيل ال Gii داخل التطبيق الخاص بك</li>
<li>إستخدام ال Gii لإنشاء ال Active Record class</li>
<li>إستخدام ال Gii لإنشاء الشيفرة البرمجية الخاصة بال CRUD إعتمادا على الجداول الموجودة في قاعدة البيانات</li>
<li>تخصيص (custmize) الشيفرة البرمجية التي سيتم إنتاجها من خلال ال Gii.</li>
</ul>
## <div dir="rtl">البدء باستخدام ال Gii</a> <span id="starting-gii"></span>
<p dir="rtl">
يتم تقديم ال <a href="https://www.yiiframework.com/extension/yiisoft/yii2-gii/doc/guide">Gii</a> داخل على ال Yii على أنه <a href="../guide/structure-modules.md">module</a>، ويمكنك تفعيله من خلال الإعدادات الخاصة به والتي تجدها داخل ال application، وبالتحديد داخل ال property التالية [[yii\base\Application::modules|modules]]، واعتمادا على كيفية إنشائك للمشروع، فيمكنك إيجاد الشيفرة البرمجية التالية موجودة بشكل مسبق داخل ال <code>config/web.php</code>:
</p>
```php
$config = [ ... ];
if (YII_ENV_DEV) {
$config['bootstrap'][] = 'gii';
$config['modules']['gii'] = [
'class' => 'yii\gii\Module',
];
}
```
<p dir="rtl">
في الإعدادت الموجودة في الأعلى، فإن التطبيق سيقوم بتضمين وتفعيل ال gii في حال كانت الحالة الخاصة بالتطبيق هي <a href="../guide/concept-configurations.md#environment-constants">development enviroment</a>، بالإضافة الى ذلك، فإنه يجب تضمين واستخدام ال module <code>gii</code>، والموجود ضمن ال class التالي [[yii\gii\Module]].
</p>
<p dir="rtl">
اذا قمت بالتحقق من ال <a href="../guide/structure-entry-scripts.md">entry script</a> وبالتحديد صفحة ال <code>web/index.php</code> في التطبيق الخاص بك، ستجد هذه الأسطر، والتي يجب أن تجعل من ال <code>YII_ENV_DEV</code> ذات قيمة <code>true</code>.
</p>
```php
defined('YII_ENV') or define('YII_ENV', 'dev');
```
<p dir="rtl">
كل الشكر لهذا السطر البرمجي، التطبيق الآن أصبح بحالة ال development mode، وأصبح لديك ال Gii enabled بالفعل، والآن، يمكنك الوصول الى ال Gii من خلال عنوان ال URL التالي:
</p>
```
http://hostname/index.php?r=gii
```
<blockquote class="note"><p dir="rtl">
ملاحظة: إذا كنت تحاول الوصول إلى Gii من جهاز آخر غير ال localhost، فسيتم رفض الوصول افتراضيًا لأغراض أمنية، ولكن، يمكنك إعداد ال Gii لإضافة مجموعة من ال IP Addresses المسموح لها بالوصول وذلك من خلال:
</p></blockquote>
```php
'gii' => [
'class' => 'yii\gii\Module',
'allowedIPs' => ['127.0.0.1', '::1', '192.168.0.*', '192.168.178.20'] // عدل هذه حسب إحتياجاتك
],
```
![Gii](../guide/images/start-gii.png)
## <div dir="rtl">إنشاء ال Active Record Class من خلال ال Gii</div> <span id="generating-ar"></span>
<p dir="rtl">
لإستخدام ال Gii لإنشاء ال Active Record class, قم باختيار ال "Model Generator" (من خلال النقر على الرابط الموجود بالصفحة الرئيسية لل Gii)، ومن ثم قم بتعبئة ال form كما يلي:
</p>
<ul dir="rtl">
<li>إسم الجدول: <code>country</code></li>
<li><code>Country</code> :Model Class</li>
</ul>
![Model Generator](../guide/images/start-gii-model.png)
<p dir="rtl">
والآن، قم بالنقر على الزر "Preview"، ستشاهد الآن <code>models/Country.php</code> قد تم إنشائها وإضافتها الى قائمة النتائج، اذا قمت بالنقر على إسم ال class، فإن المحتوى الخاص بهذا ال class سيتم عرضه.
</p>
<p dir="rtl">
عند استخدام ال Gii، إذا كنت قد قمت بالفعل بإنشاء نفس الملف وستقوم بعمل overwriting عليه، فيمكنك النقر على زر <code>diff</code> الموجود بعد إسم ال class، لتشاهد الفرق بين الشيفرة البرمجية الحالية، والشيفرة البرمجية الجديدة.
</p>
![Model Generator Preview](../guide/images/start-gii-model-preview.png)
<p dir="rtl">
عند قيامك بعمل overwriting على ملف موجود، قم بالضغط على ال ckeckbox الموجودة بجانب كلمة overwrite، ومن ثم قم بالنقر على زر "Generate", اذا كان هذا الملف جديد، وغير موجود مسبقا، فيمكنك النقر مباشرة على "Generate"، بعد ذلك ستشاهد صفحة ال confirmation والتي تبين الشيفرات البرمجية التي تم إنشائها بنجاح.
</p>
<p dir="rtl">
بعد فيامك بالنقر على زر Generate، فإنك ستشاهد صفحة ال confirmation page، والتي تقوم بدورها بتوضيح الشيفرات البرمجية التي تم إنشائها بنجاح، واذا كان الملف موجود، فإنك ستشاهد أيضا رسالة تعلمك بأن الملف قد تم تعديله وتمت إضافة الشيفرة الجديدة مكان القديمة.
</p>
## <div dir="rtl">إنشاء ال CRUD Code</div> <span id="generating-crud"></span>
<p dir="rtl">
ال CRUD هي اختصار ل Create, Read, Update, And Delete (إنشاء، وقرائة، وتحديث، وحذف)، والتي تمثل أكثر المهمات المطلوبة للتعامل مع البيانات على مواقع الويب. ولإنشاء ال CRUD باستخدام ال Gii، قم باختيار ال "CRUD Generator" (من خلال النقر على الرابط الموجود بالصفحة الرئيسية لل Gii)، وهنا وبالبنسبة للمثال الخاص بال "country"، يمكنك تعبئة ال from بما يلي:
</p>
* Model Class: `app\models\Country`
* Search Model Class: `app\models\CountrySearch`
* Controller Class: `app\controllers\CountryController`
![CRUD Generator](../guide/images/start-gii-crud.png)
<p dir="rtl">
بعد ذلك، قم بالنقر على زر ال "Preivew"، وستشاهد قائمة بالملفات التي سيتم إنشائها كما في الصورة أدناه.
</p>
![CRUD Generator Preview](../guide/images/start-gii-crud-preview.png)
<p dir="rtl">
اذا قمت إنشاء الصفحتين <code>controllers/CountryController.php</code> و <code>views/country/index.php</code> عند حديثنا سابقا عند موضوع (التعامل مع قواعد البيانات)، فقم بالضغط على ال "overwrite" ليتم إستبدالهم. (الصفحات القديمة لا توجد فيها كل الخصائص التي سيتم إنتاجها من خلال ال Gii CRUD).
</p>
## <div dir="rtl"> لنجرب المثال </div> <span id="trying-it-out"></span>
<p dir="rtl">
لتشاهد آلية العمل لهذا المثال، والنتائج المتعلقة به، يمكنك إستخدام المتصفح والدخول الى الرابط التالي:
</p>
```
http://hostname/index.php?r=country%2Findex
```
<p dir="rtl">
عند دخولك إلى الرابط أعلاه، ستشاهد مجموعة الدول التي تم إستدعائها من جدول ال country من قاعدة البيانات، ويمكنك التعامل مع هذا ال grid من حيث الترتيب أو التصفية بنائا على الشروط التي ستقوم بإدخالها في مربعات النص أعلى الأعمدة.
</p>
<p dir="rtl">
لكل دولة تم جلبها وعرضها داخل ال Grid، هناك مجموعة من الخيارات التي يمكنك التعامل معها بشكل إفتراضي، مثل ال view لعرض التفاصيل الخاصة بالدولة المختارة، أو تحديث المعلومات، الخاصة بالدولة، أو حذف هذه الدولة، بالإضافة إلى ذلك يمكنك النقر على "Create Country" الموجودة في أعلى ال Grid والتي ستأخذك بدورها الى صفحة تحتوي form لإنشاء ال country.
</p>
![Data Grid of Countries](../guide/images/start-gii-country-grid.png)
![Updating a Country](../guide/images/start-gii-country-update.png)
<p dir="rtl">
فيما يلي قائمة بالملفات التي تم إنشاؤها من خلال ال Gii، في حالة رغبتك في التحقق من كيفية عمل هذه الميزات والإطلاع على الشيفرة البرمجية وتخصيصها حسب الرغبة:
</p>
* Controller: `controllers/CountryController.php`
* Models: `models/Country.php` and `models/CountrySearch.php`
* Views: `views/country/*.php`
<blockquote class="info"><p dir="rtl">
معلومة: تم تصميم ال Gii لتكون أداة إنشاء شيفرات برمجية قابلة للتخصيص بشكل كبير للغاية. اذا قمت باستخدامه بحكمة،فإنك ستقوم بتسريع وتيرة التطوير الخاصة بالتطبيق الخاص بك. لمزيد من التفاصيل، يرجى الذهاب إلى الجزء الخاص بال <a href="https://www.yiiframework.com/extension/yiisoft/yii2-gii/doc/guide">Gii</a>.
</p></blockquote>
## <div dir="rtl">الخلاصة</div> <span id="summary"></span>
<p dir="rtl">
في هذا الجزء من التوثيق، لقد تعلمنا آلية استخدام ال Gii لإنشاء الشيفرة البرمجية الخاصة بال CRUD، وتحدثنا عن الوظائف التي تقوم فيها، وكيف يمكننا من خلالها إتمام العمليات الخاصة بالبيانات من إدخال وتحديث وحذف وعرض للبيانات من قاعدة البيانات.
</p>

149
docs/guide-ar/start-hello.md

@ -1,149 +0,0 @@
# <div dir="rtl">قل مرحبا - Saying Hello</div>
<p dir="rtl">
في هذا الموضوع سنتعرف على كيفية إنشاء صفحة "Hello" جديدة في التطبيق الذي قمت بتثبيته، ولتحقيق ذلك، يجب عليك القيام بإنشاء <a href="../guide/structure-controllers.md#creating-actions">action</a> و <a href="../guide/structure-views.md">view</a> لهذه الصفحة:
</p>
<ul dir="rtl">
<li>سيقوم التطبيق بإرسال ال request الخاص بالصفحة إلى ال action.</li>
<li>وسيقوم ال action بدوره في جلب ال view التي تعرض كلمة "Hello" إلى المستخدم النهائي.</li>
</ul>
<p dir="rtl">
من خلال هذا البرنامج التعليمي ، ستتعلم ثلاثة أشياء:
</p>
<ol dir="rtl">
<li>كيفية إنشاء <a href="../guide/structure-controllers.md#creating-actions">action</a> ليقوم بإستقبال ال request ومن ثم الرد (respond) عليها.</li>
<li>كيفية إنشاء <a href="../guide/structure-views.md">view</a> وإضافة المحتوى الى ال respond.</li>
<li>و كيفية إنشاء التطبيق لل requests التي يوجهها لل <a href="../guide/structure-controllers.md#creating-actions">actions</a>. </li>
</ol>
## <div dir="rtl">إنشاء ال Action</div> <span id="creating-action"></span>
<p dir="rtl">
لإنشاء صفحة "Hello"، ستقوم بإنشاء <code>say</code> <a href="../guide/structure-controllers.md#creating-actions">action</a> والذي بدوره سيقوم بقراءة ال <code>message</code> parameter من ال request، ومن ثم عرض ال <code>message</code> مرة أخرى إلى المستخدم. إذا كان ال request لا يحمل معه ال message parameter فإن ال action سيقوم بطباعة message إفتراضية وهي "Hello".
</p>
<blockqoute class="info"><p dir="rtl">
معلومة: ال <a href="../guide/structure-controllers.md#creating-actions">Actions</a> هي الكائنات(objects) التي يمكن للمستخدمين من الوصول اليها وتنفيذ ما في بداخلها بشكل مباشر. يتم تجميع هذه ال Actions بواسطة ال <a href="../guide/structure-controllers.md">controllers</a>. ونتيجة لذلك فإن ال response الراجعة للمستخدم ستكون هي نتيجة التنفيذ الخاصة بال action.
</p></blockqoute>
<p dir="rtl">
يجب تعريف ال actions داخل ال <a href="../guide/structure-controllers.md">controller</a>، ولتبسيط الفكرة، سنقوم بتعريف ال <code>say</code> action داخل أحد ال controller الموجود مسبقا وهو ال <code>siteController</code>. هذا ال controller ستجده داخل المسار <code>controllers/siteController.php</code>. ومن هنا سنبدأ بإضافة ال action الجديد:
</p>
```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]);
}
}
```
<p dir="rtl">
في الشيفرة البرمجية السابقة ، تم تعريف ال <code>say</code> action من خلال إنشاء الدالة <code>actionSay</code> داخل الكلاس <code>siteController</code>. يستخدم ال Yii كلمة action ك prefix للدوال للتميز بين الدوال ال action و ال non-action في ال controller، كما يستخدم الإسم الخاص بال action مباشرة بعد ال prefix، ويتم عمل mapping بين ال action method name وال action id ليستطيع المستخدم من الوصول للدالة المنشئة من خلال ال action id.
</p>
<p dir="rtl">
عندما يتعلق الأمر بتسمية ال action الخاصة بك، يجب عليك أن تفهم كيف يقوم ال Yii بالتعامل مع ال action id، ال action id يجب أن يكون دائما أحرف lower case، وإذا إحتوى ال action id على عدة كلمات فإن الفاصل بينهم سيكون الداش (dashes) مثل <code>create-comment</code>، ويتم ربط ال action id بال action method name من خلال حذف ال dashes من ال IDs، ويتم عمل capitalizing لأول خرف من كل كلمة، وإضافة ال prefix الى الناتج السابق من التحويل. مثال: ال action id المسمى ب <code>create-comment</code> سيتم تحويله الى ال action method name التالي: <code>actionCreateComment</code>.
</p>
<p dir="rtl">
في المثال السابق، يقوم ال action method على إستقبال parameter يسمى ب <code>$message</code>، والذي يملك قيمة إفتراضية وهي <code>"Hello"</code> (وهي مشابة تماما لطريقة وضع القيم الإفتراضية لل argument في ال PHP). عندما يستقبل التطبيق ال request ويحدد أن ال action المطلوب للتعامل مع الطلب (request) هو <code>say</code>، فإن التطبيق سيقوم بإسناد القيمة الموجودة بال request الى ال parameter الموجود بال action بشرط أن يكون الإسم الموجود بال request هو نفسه الموجود في ال action. ولتبسيط الموضوع يمكن القول أن ال request اذا احتوى على كلمة <code>message</code> وقيمة هذا ال parameter هي <code>"GoodBye"</code>، فإن ال <code>$message</code> الموجودة في ال action ستصبح قيمتها <code>"GoodBye"</code>.
</p>
<p dir="rtl">
من خلال ال action method، يتم استدعاء ال [[yii\web\Controller::render()|render()]] لتقديم
الملف الخاص بال view والمسمى هنا ب <code>say</code>. أيضا فإن ال <code>message</code> يتم تمرريرها الى ال view مما يسمح لك باستخدام هذا ال parameter داخل ال view. النتيجة المرجعة لل view تتم معالجتها وإرجاعها من خلال ال action method، وهذه النتائج سيتم إستقبالها من خلال المتصفح الخاص بالمستخدم ليتم عرضها وكأنها (جزء من صفحة Html كاملة).
</p>
## <div dir="rtl">إنشاء ال View</div> <span id="creating-view"></span>
<p dir="rtl">
ال <a href="../guide/structure-views.md">Views</a> هي شيفرات برمجية كتبت ﻹنشاء المحتوى المناسب بنائا على ال response الراجع اليها من خلال ال action.
بالنسبة إلى مثال "Hello" ، الآن سنقوم بإنشاء view مسمى ب <code>say</code>، والذي سيقوم بدوره بطباعة ال <code>message</code> التي تم إستلامها من ال action، شاهد المثال:
</p>
```php
<?php
use yii\helpers\Html;
?>
<?= Html::encode($message) ?>
```
<p dir="rtl">
صفحة ال view <code>say</code> يجب أن يتم حفظها داخل المسار التالي: <code>views/site/say.php</code>. عندما يتم إستدعاء الدالة [[yii\web\Controller::render()|render()]] من قبل ال action، فإنه سينظر للمسار على الشكل التالي: <code>views/ControllerID/ViewName.php</code>، بحيث يكون في مثالنا السابق ال ContollerID هو ال <code>site</code> وال viewName هو <code>say</code>.
</p>
<p dir="rtl">
ملاحظة: في الشيفرة البرمجية أعلاه، تكون ال <code>message</code> مضمنة داخل ال [[yii\helpers\Html::encode()]] قبل أن يتم طباعتها، هذا الأمر ضروري لأن ال parameter التي تأتي من المستخدم النهائي لا يجب الوثوق بها، فهي يمكن أن تحتوي على شيفرات برمجية تستغل الضعف الحاص بك بموضوع الأمان مثل <a href="https://en.wikipedia.org/wiki/Cross-site_scripting">vulnerable to XSS attack</a> عن طريق دمج JS code مع ال parameter.
</p>
<p dir="rtl">
وبطبيعة الحال، يمكنك وضع المزيد من المحتوى في صفحة ال <code>say</code> view. ويمكن أن يتكون هذا المحتوى من HTML tag و plain text وحتى PHP statements.
في الواقع، تعد ال <code>say</code> view مجرد شيفرة برمجية بلغة ال PHP والتي يتم تنفيذها بواسطة [[yii\web\Controller::render()|render()]].
المحتوى الذي سيتم طباعته من خلال ال view سيتم إرجاعه الى التطبيق من خلال ال response، وسيقوم التطبيق بدوره بإخراج هذه النتيجة إلى المستخدم النهائي.
</p>
## <div dir="rtl">تطبيق المثال</div> <span id="trying-it-out"></span>
-------------
<p dir="rtl">
بعد إنشاء ال action وصفحة ال view، يمكنك الوصول إلى الصفحة الجديدة عن طريق عنوان URL التالي:
</p>
```
http://hostname/index.php?r=site%2Fsay&message=Hello+World
```
![Hello World](../guide/images/start-hello-world.png)
<p dir="rtl">
سينتج عن هذا ال URL صفحة تعرض "Hello World". هذه الصفحة لديها نفس ال Header و ال Footer لصفحات التطبيق الأخرى.
</p>
<p dir="rtl">
إذا قمت بحذف ال <code>message</code> parameter من ال URL ، فسترى الصفحة تعرض كلمة <code>" Hello "</code> فقط. ويرجع ذلك إلى أن "message" يتم تمريرها ك parameter إلى ال <code>actionSay()</code>، وعندما يتم حذفها، سيتم استخدام القيمة الافتراضية وهي <code>"Hello"</code> بدلاً من ذلك.
</p>
<blockquote class="info"><p dir="rtl">
معلومة: تتشارك الصفحة الجديدة مع الصفحات الأخرى بالتطبيق بنفس ال Header وال Footer وذلك بسبب الدالة [[yii\web\Controller::render() | render ()]] والتي ستقوم بشكل تلقائي بتضمين النتيجة الخاصة بصفحة ال view <code>say</code> مع صفحة ال <a href="../guide/structure-views.md#layouts">Layout</a>، والتي يمكنك أن تجدها داخل المسار التالي: <code>views/layouts/main.php</code>
</p></blockquote>
<p dir="rtl">
ال <code>r</code> الموجودة في ال URL أعلاه يتطلب الكثير من الشرح. ولكن باختصار يمكن القوم أنها اختصار ل <a href="../guide/runtime-routing.md">route</a> ، وهو معرف فريد من نوعه(unique ID) للتطبيق بحيث يقوم بالتأشير على ال action، والصيغة الخاصة بال route هي <code>ControllerID/ActionID</code>. عندما يتلقى التطبيق request، فإنه سيتم التحقق من <code>r</code> parameter، فيقوم باستخدام الجزء <code>ControllerID</code> لتحديد ال controller class المطلوب ليقوم بعمل instance منه، ومن ثم يقوم ال controller باستخدام ال <code>"ActionID"</code> لتحديد ال action المطلوب والذي سيقوم بالعمل الفعلي.
في المثال الخاص بنا، فإن ال route هو <code>"site/say"</code>، وهذا ال route يتم معالجته ليستدعي ال controller class المسمى ب <code>SiteController</code> و ال action المسمى ب <code>actionSay</code> داخل هذا ال controller، ونتيجة لذلك سيتم فعليا إستدعاء الدالة <code>SiteController::actionSay()</code> لتقوم بمعالجة ال request كما يلزم.
</p>
<blockquote><p dir="rtl">
معلومة: مثل ال actions، تحتوي ال controllers أيضًا على Uniquely IDs يتم تعريفها واستخدامها من خلال التطبيق. تستخدم ال Controllers IDs نفس قواعد التسمية الخاصة بال action IDs، ويتم ذلك من خلال حذف ال dashes و capitalizing أول حرف من كل كلمة، ثم إضافة كلمة <code>Controller</code> الى الإسم الناتج -وهنا الإختلاف عن ال action ID-. مثال: ال controller ID المسمى ب <code>"post-comment"</code> ستم معالجته ليصبح <code>PostCommentController</code>.
</p></blockquote>
## <div dir="rtl">الخلاصة</div> <span id="summary"></span>
<p dir="rtl">
في هذا الموضوع، قمنا بالتعرف على ال controller وال view كأجزاء من MVC architectural pattern، كما قمنا بإنشاء action داخل controller موجود ليستقبل specific request ويتحكم فيه، وقمنا أيضا بإنشاء view لعرض المحتوى. في هذا المثال البسيط، لم نتطرق الى ال model، وقمنا فقط باستخدام ال data بشكل مباشر من خلال ال <code>message</code> parameter.
</p>
<p dir="rtl">
كما تعرفنا أيضا على ال routes في ال Yii، والتي تعمل بدورها كجسر بين ال user request وال controller actions.
</p>
<p dir="rtl">
في الموضوع القادم، ستتعلم كيف يمكنك إنشاء model وكيف يمكنك إنشاء صفحة جديدة تحتوي على Html form.
</p>

303
docs/guide-ar/start-installation.md

@ -1,303 +0,0 @@
# <div dir="rtl">تثبيت ال Yii</div>
<p dir="rtl">يمكنك تثبيت ال Yii بطريقتين ، الأولى باستخدام مدير الحزم <a href="https://getcomposer.org">Composer</a> أو عن طريق تنزيل Archive File. الطريقة الأولى هي الطريقة المفضلة للعمل، ، لأنها تتيح لك تثبيت [<a href="../guide/structure-extensions.md">extensions</a> - ملحقات أو اضافات] جديدة، أو تحديث إطار العمل Yii ببساطة عن طريق تشغيل أمر واحد فقط.
</p>
<p dir="rtl">
التثبيت الإفتراضي لل Yii ينتج عنه بنية تركيبة منظمة ومرتبة للمجلدات والملفات التي بداخلها، ويوفر هذا الكلام بعض المميزات التي يتم إضافتها وإنشائها بشكل تلقائي مثل صفحة تسجيل الدخول، ونموذج اتصل بنا...الخ، هذا الأمر سيشكل نقطة إنطلاق جيدة لبدء العمل على أي مشروع.
</p>
<p dir="rtl">
في هذه الصفحة من التوثيق سنقوم بشرح ووصف كيف يمكن تثبيت إطار العمل Yii وبالتحديد Yii2 Basic Project Template.
هناك Template آخر موجود بإطار العمل Yii وهو <a href="https://www.yiiframework.com/extension/yiisoft/yii2-app-advanced/doc/guide">Yii2 Advanced Project Template</a>، وهو الأفضل للعمل وإنشاء المشاريع لفريق عمل برمجي، ولتطوير المشاريع متعددة الطبقات(multiple tires).
</p>
<blockquote class="info"><p dir="rtl">
معلومة: قالب المشروع الأساسي (Basic) مناسب لتطوير 90% من تطبيقات الويب. ويختلف القالب المتقدم (Advanced Template) عن القالب الأساسي في كيفية تنظيم وهيكلة الشيفرة البرمجية.
اذا كنت جديدا في عالم تطوير تطبيقات الويب باستخدام ال Yii، فإننا نوصيك بقوة بأن تستخدم القالب الأساسي في بناء المشروع الخاص بك.
</p></blockquote>
## <div dir="rtl">تثبيت ال Yii من خلال (Composer)</div> <span id="installing-via-composer"></span>
### <div dir="rtl">تثبيت ال Composer</div>
<p dir="rtl">
إن لم يكن لديك Composer مثبت مسبقا، فيمكنك السير بخطوات تثبيته من خلال الدخول الى هذا الرابط <a href="https://getcomposer.org/download/">https://getcomposer.org/download/</a>.
لتثبيت ال Composer في كل من نظامي Linux و Max OS X، يمكنك تنفيذ الأوامر التالية:
</p>
```bash
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
```
<p dir="rtl">
ولنظام ويندوز يمكنك تثبيت ال <a href="https://getcomposer.org/Composer-Setup.exe">Composer-Setup.exe</a> ومن ثم عمل run
</p>
<p dir="rtl">
يرجى الدخول الى <a href="https://getcomposer.org/doc/articles/troubleshooting.md">Troubleshooting section of the Composer Documentation</a> في حال واجهتك أي مشاكل متعلقة بال composer, وإذا كنت مستخدمًا جديدًا لل composer، ننصحك أيضًا بقراءة <a href="https://getcomposer.org/doc/01-basic-usage.md">قسم الاستخدام الأساسي</a> على الأقل من التوثيف الخاص بال composer.
</p>
<p dir="rtl">
في هذا الدليل ، نفترض أنك قمت بتثبيت ال composer على مستوى جميع المشاريع (<a href="https://getcomposer.org/doc/00-intro.md#globally">globally</a>) بحيث تكون أوامر ال composer متاحة لجميع المشاريع من أي مكان. أما إذا كنت تستخدم ال composer.phar لمسار محدد فقط(local directory)، فيجب عليك ضبط الأومر وفقًا لذلك.
</p>
<p dir="rtl">
إذا كان ال composer مثبتًا من قبل، فتأكد من استخدام إصدار حديث. يمكنك تحديث ال composer عن طريق تنفيذ الأمر التالي <code>composer self-update</code>
</p>
<blockquote class="note"><p dir="rtl">
ملاحظة مهمة: أثناء تثبيت ال Yii ، سيحتاج ال composer إلى طلب(request) الكثير من المعلومات من ال Github Api. يعتمد عدد الطلبات على عدد dependencies التي يمتلكها التطبيق الخاص بك، وقد يكون هذا العدد أكبر من الحد المسموح به من قبل ال Github Api <b>(Github API rate limit)</b>. إذا وصلت الى الحد الأعلى المسموح به من الطلبات، فقد يطلب منك ال composer بيانات تسجيل الدخول إلى Github، وذلك للحصول على رمز (token) للدخول إلى Github Api. اذا كانت عمليات الإتصال سريعة، فقد تصل إلى هذا الحد(limit) قبل أن يتمكن ال composer من التعامل معه ، لذالك نوصي بتكوين رمز الدخول(access token) قبل تثبيت ال Yii. يرجى الرجوع إلى التوثيق الخاص بال Composer والإطلاع على التعليمات الخاصة <a href="https://getcomposer.org/doc/articles/troubleshooting.md#api-rate-limit-and-oauth-tokens">Github API tokens</a> للحصول على الإرشادات اللازمة للقيام بذلك.
</p></blockquote>
### <div dir="rtl">تثبيت ال Yii</div> <span id="installing-from-composer"></span>
<p dir="rtl">
من خلال ال Composer، يمكنك الآن تثبيت ال Yii من خلال تنفيذ سطر الأوامر التالي داخل أي مسار يمكن الوصول اليه من قبل الويب
</p>
```bash
composer create-project --prefer-dist yiisoft/yii2-app-basic basic
```
<p dir="rtl">
سطر الأوامر السابق سيقوم بتثبيت أحدث نسخة مستقرة(stable) من إطار العمل Yii داخل مسار جديد اسمه basic، ويمكنك التعديل على سطر الأوامر السابق لتغيير اسم المشروع لأي اسم ترغب فيه.
</p>
<blockquote class="info"><p dir="rtl">
معلومة: اذا واجهتك أي مشكلة عند تنفيذ السطر `composer create-project` فيمكنك الذهاب إلى <a href="https://getcomposer.org/doc/articles/troubleshooting.md">قسم استكشاف الأخطاء في ال composer</a>.
في معظم الأخطاء الشائعة، وعند حل المشكلة أو الخطأ، يمكنك إكمال التثبيت من خلال الدخول الى المسار `basic` ومن ثم تنفيذ الأمر التالي: `composer update`.
</p></blockquote>
<blockquote class="tip"><p dir="rtl">
تلميح: اذا كنت ترغب بتثبيت أحدث نسخة خاصة بالمطورين من ال Yii، فيمكنك ذلك من خلال إضافة الخيار <a href="https://getcomposer.org/doc/04-schema.md#minimum-stability">stability</a> وذلك من خلال سطر الأوامر التالي:
</p></blockquote>
```bash
composer create-project --prefer-dist --stability=dev yiisoft/yii2-app-basic basic
```
<blockquote class="note"><p dir="rtl">
ملاحظة: نسخة المطورين من ال Yii يجب أن يتم إستخدامها للمواقع الإلكترونية التي لن تصدر كنسخة نهائية للمستخدم(Not for production) لأن ذلك يمكن أن يسبب بإيقاف المشروع أو الشيفرة البرمجية الخاصة بك.
</p></blockquote>
### <div dir="rtl">تثبيت ال Yii من خلال ال Archive File</div> <span id="installing-from-archive-file"></span>
--------------------------
<p dir="rtl">
يتضمن تثبيت Yii من ملف أرشيف ثلاث خطوات وهي:
</p>
<ol dir="rtl">
<li> تثبت الملف من خلال الموقع الرسمي <a href="https://www.yiiframework.com/download/">yiiframework.com</a>.</li>
<li> قم بفك ضغط الملف الذي تم تنزيله إلى مجلد يمكن الوصول إليه عبر الويب.</li>
<li> قم بتعديل ملف <code>config/web.php</code> عن طريق إدخال secret key ل<code> cookieValidationKey</code>
(يتم ذلك تلقائيًا إذا قمت بتثبيت ال Yii باستخدام Composer): </li>
</ol>
```php
// !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
'cookieValidationKey' => 'enter your secret key here',
```
### <div dir="rtl">خيارات تثبيت أخرى</div> <span id="other-installation-options"></span>
--------------------------
<p dir="rtl">
توضح تعليمات التثبيت أعلاه كيفية تثبيت ال Yii ، والذي يقوم أيضًا بإنشاء تطبيق ويب أساسي(basic).
هذا النهج هو نقطة انطلاق جيدة لمعظم المشاريع، صغيرة كانت أو كبيرة. خصوصا اذا كنت قد بدأت تعلم ال Yii من وقت قريب.
<br /><br />
لكن، هناك خيارات أخرى متاحة لتثبيت ال Yii وهي:
</p>
<ul dir="rtl">
<li> إذا كنت ترغب فقط في تثبيت ال core لإطار العمل Yii، وترغب ببناء المكونات الخاصة بإطار العمل كما ترغب أنت وبطريقتك أنت، يمكنك اتباع التعليمات كما هو موضح في هذه الصفحة <a href="../guide/tutorial-start-from-scratch.md"> Building Application from Scratch</a>.</li>
<li> إذا كنت تريد البدء بتطبيق أكثر تعقيدًا وأكثر إحترافية، ويتناسب بشكل أفضل مع وجود فريق عمل تقني،
فأنت اذا سترغب بتثبيت ال <a href="https://github.com/yiisoft/yii2-app-advanced/blob/master/docs/guide/README.md">Advanced Project Template</a>
</li>
</ul>
### <div dir="rtl">تثبيت ال Assets</div> <span id="installing-assets"></span>
--------------------------
<p dir="rtl">
تعتمد ال Yii على حزم <a href="https://bower.io/">Bower</a> و/أو <a href="https://www.npmjs.com/">NPM</a> لتثبيت مكتبات ال (CSS و JavaScript). ويستخدم ال composer للحصول على هذه المكتبات ، مما يسمح بالحصول على إصدارات ال PHP و CSS/JavaScript في نفس الوقت. ويمكن تحقيق ذلك إما عن طريق استخدام <a href="https://asset-packagist.org/">asset-packagist.org</a> أو من خلال ال <a href="https://github.com/fxpio/composer-asset-plugin">composer asset plugin</a>، يرجى الرجوع إلى <a href="../guide/structure-assets.md">Assets documentation</a> لمزيد من التفاصيل.
<br /><br />
قد ترغب في إدارة ال assets عبر ال native Bower/NPM أو استخدام ال CDN أو تجنب تثبيت ال assets بالكامل من حلال ال Composer ، ويمكن ذلك من خلال إضافة الأسطر التالية إلى "composer.json":
</p>
```json
"replace": {
"bower-asset/jquery": ">=1.11.0",
"bower-asset/inputmask": ">=3.2.0",
"bower-asset/punycode": ">=1.3.0",
"bower-asset/yii2-pjax": ">=2.0.0"
},
```
<blockquote class="note"><p dir="rtl">
ملاحظة: في حالة تجاوز تثبيت ال assets عبر ال Composer، فأنت المسؤول عن تثبيت ال assets وحل مشكلات التعارض بين الإصدارات والمكتبات المختلفة. وكن مستعدًا لعدم تناسق محتمل بين ملفات ال asstes والإضافات المختلفة.
</p></blockquote>
### <div dir="rtl">التحقق من التثبيت</div> <span id="verifying-installation"></span>
--------------------------
<p dir="rtl">
بعد الانتهاء من التثبيت، ستحتاج الى القيام بإعداد خادم الويب الخاص بك(your web server) (انظر القسم التالي) أو قم باستخدام <a href="https://www.php.net/manual/en/features.commandline.webserver.php">built-in PHP web server</a> عن طريق تنفيذ الأمر التالي داخل المسار web في المشروع الخاص بك:
</p>
```bash
php yii serve
```
<blockquote class="note"><p dir="rtl">
ملاحظة: افتراضيًا ال HTTP-server يعمل على البورت 8080. ومع ذلك ، إذا كان هذا البورت قيد الاستخدام بالفعل أو كنت ترغب في تشغيل أكثر من تطبيق بهذه الطريقة، حينها سيلزمك تحديد البورت الذي يجب استخدامه. ما عليك سوى إضافة --port:
</p></blockquote>
```bash
php yii serve --port=8888
```
<p dir="rtl">
يمكنك استخدام الرابط الموجود في الأسفل للوصول الى تطبيق ال Yii الذي قمت بتثبيته وتنفيذ الأوامر السابقة عليه.
</p>
```
http://localhost:8080/
```
![Successful Installation of Yii](../guide/images/start-app-installed.png)
<p dir="rtl">
اذا كانت كل الإعدادات السابقة تعمل بشكل صحيح، فيجب أن ترى الصورة الموجودة بالأعلى "Congratulations!" على المتصفح. إذا لم يكن كذلك، يرجى التحقق مما إذا كان تثبيت الPHP الخاص بك متوافق مع متطلبات ال Yii. يمكنك التحقق من ذلك باستخدام أحد الأساليب التالية:
</p>
<ul dir="rtl">
<li>قم بنسخ الملف <code>/requirements.php</code> الى المسار <code>/web/requirements.php</code> بحيث يمكنك الوصول الى الصفحة من خلال الرابط التالي: <code>http://localhost/requirements.php</code></li>
<li>قم بتنفيذ الأوامر التالية: <br /><code>
cd basic
</code><br /><code>php requirements.php</code></li>
</ul>
<p dir="rtl">
يجب عليك أن تقوم بتثبيت وإعداد ال PHP الخاص بك بحيث تلبي الحد الأدنى من متطلبات ال Yii. الأهم من ذلك يجب أن يكون الإصدار الخاص بال PHP أعلى أو يساوي 5.4. من الناحية المثالية أحدث إصدار يعمل مع ال Yii هو ال PHP 7. يجب عليك أيضًا تثبيت ال <a href="https://www.php.net/manual/en/pdo.installation.php">PDO PHP Extension</a>.
</p>
### <div dir="rtl">إعداد ال Web Servers</div> <span id="configuring-web-servers"></span>
-----------------------
<blockquote class="info"><p dir="rtl">
معلومة: يمكنك تخطي هذا الجزء الآن إذا كنت تختبر فقط إطار العمل Yii دون أي نية لنشر هذا التطبيق على الويب(بدون رفع التطبيق على production server).
</p></blockquote>
<p dir="rtl">
يجب أن يعمل التطبيق الذي تم تثبيته وفقًا للتعليمات المذكورة أعلاه مع أي من الخوادم ال <a href="https://httpd.apache.org/">Apache HTTP</a> أو ال <a href="https://nginx.org/">Nginx HTTP</a> في كل من أنظمة التشغيل Windows, Mac OS X أو Linux ممن لديها إصدار أعلى أو يساوي PHP 5.4، كما أن ال Yii 2.0 متوافق مع ال Facebook <a href="https://hhvm.com/">HHVM</a>، لكن، يجب أن تأخذ بعين الإعتبار أن ال HHVM يسلك في بعض الأحيان بطريقة مختلفة عن ال Native PHP، لذلك يجب أن تأخذ عناية إضافية عندما تعمل على ال HHVM.
</p>
<p dir="rtl">
على ال production server، قد ترغب في إعداد خادم الويب الخاص بك بحيث يمكن الوصول إلى التطبيق
الخاص بك عبر ال URL التالي <code>http://www.example.com/index.php</code> بدلاً من <code>http://www.example.com/basic/web/index.php</code>. هذا الكلام يتطلب إنشاء إعداد يقوم بتوجيه ال document root الموجود على ال web server الى مجلد ال basic/web، كما قد ترغب أيضا بإخفاء ال <code>index.php</code> من ال URL كما هو موضح في ال <a href="../guide/runtime-routing.md">Routing and URL Creation</a>. في هذا الموضوع ستتعلم كيف يمكنك إعداد ال Apache أو ال Nginx server لتحقيق هذه الأهداف.
</p>
<blockquote class="info"><p dir="rtl">
معلومة: من خلال تعيين ال <code>basic/web</code> ك <code>document root</code>، فإنك بذلك تمنع أيضًا المستخدمين النهائيين من الوصول الى الشيفرة البرمجية الخاصة بالتطبيق الخاص بك، وتمنعهم من الوصول الى الملفات الحساسة والمهمة والمخزنة في sibling directories من <code>basic/web</code>، ويعبر رفض الوصول الى المجلدات الأخرى تحسينا أمنيا مهما، يساعد في الحفاظ على مستوى أعلى من الحماية.
</p></blockquote>
<blockquote class="info"><p dir="rtl">
معلومة: إذا كان سيتم تشغيل التطبيق الخاص بك في بيئة استضافة مشتركة(shared hosting) حيث ليس لديك الصلاحية لتعديل الإعدادات الخاصة بال web server، ستحتاج حينها الى تعديل في البنية الخاصة بالمشروع للحصول على أفضل أمان ممكن. يرجى الرجوع إلى <a href="../guide/tutorial-shared-hosting.md">Shared Hosting Environment</a> لمزيد من المعلومات.
</p></blockquote>
<blockquote class="info"><p dir="rtl">
معلومة: إذا كنت تقوم بتشغيل تطبيق ال Yii بوجود ال proxy، فقد تحتاج إلى إعداد التطبيق ليكون ضمن ال <a href="../guide/runtime-requests.md#trusted-proxies">trusted proxies and header</a>.
</p></blockquote>
### <div dir="rtl">الإعدادات الموصى بها لل Apache</div> <span id="recommended-apache-configuration"></span>
-----------------------
<p dir="rtl">
استخدم الإعدادات التالية في ملف ال <code>httpd.conf</code> في Apache أو ضمن إعدادات ال virtual host.
ملاحظة: يجب عليك استبدال المسار التالي <code>path/to/basic/web</code> بالمسار الفعلي للتطبيق الخاص بك وصولا الى ال <code>basic/web</code>.
</p>
```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
# if $showScriptName is false in UrlManager, do not allow accessing URLs with script name
RewriteRule ^index.php/ - [L,R=404]
# ...other settings...
</Directory>
```
### <div dir="rtl">الإعدادات الموصى بها لل Nginx</div> <span id="recommended-nginx-configuration"></span>
-----------------------
<p dir="rtl">
لاستخدام <a href="https://wiki.nginx.org/">Nginx</a>، يجب تثبيت PHP على أنه <a href="https://www.php.net/install.fpm">FPM SAPI</a>، ويمكنك استخدام إعدادات ال Nginx التالية، مع الإنتباه على استبدال المسار من <code>path/to/basic/web</code> الى المسار الفعلي وصولا إلى <code>basic/web</code> بالإضافة الى إستبدال <code>mysite.test</code> إلى ال hostname الخاص بالتطبيق.
</p>
```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.test;
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;
# deny accessing php files for the /assets directory
location ~ ^/assets/.*\.php$ {
deny all;
}
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 ~* /\. {
deny all;
}
}
```
<p dir="rtl">
عند استخدامك لهذا الإعداد، يجب عليك أيضًا تعيين <code>cgi.fix_pathinfo = 0</code> في ملف php.ini
من أجل تجنب العديد من طلبات ال <code>stat()</code> الغير الضرورية للنظام.
</p>
<p dir="rtl">
لاحظ أيضًا أنه عند تشغيل خادم HTTPS، تحتاج إلى إضافة <code>fastcgi_param HTTPS on;</code>
بحيث يمكنك إكتشاف إذا ما كان الاتصال آمنًا أم لا.
</p>

36
docs/guide-ar/start-looking-ahead.md

@ -1,36 +0,0 @@
# <div dir="rtl">ماذا الآن - الخطوة القادمة</div>
<p dir="rtl">
إذا قمت بقرائة الفصل الخاص ب "البداية من هنا"، فأنت الآن قادر على بناء تطبيق Yii متكامل، لقد تعلمت كيف يمكنك تنفيذ وإستخدام أكثر الخصائص والمميزات المشتركة، مثل جلب البيانات من قاعدة البيانات، وأخذ البيانات من المستخدمين، ومن ثم عرضها، كما تعلمت كيف يمكنك تقسيم البيانات الى صفحات، وقمنا باستخدام ال <a href="https://www.yiiframework.com/extension/yiisoft/yii2-gii/doc/guide">Gii</a> وتعلمنا كيف يمكننا إنشاء شيفرة برمجية من خلاله بشكل تلقائي، ومن الممارسة تعلمنا أن إنشاء الشيفرة البرمجية من خلال ال Gii يجعل من عملية تطوير المواقع والوظائف المطلوبة أمرا بسيطا وسهلا للغابة، كل ما عليك القيام به هو تعبئة ال forms.
</p>
<p dir="rtl">
في هذا الجزء من التوثيق سنعرض ملخص للمصادر المتاحة لل Yii، والتي ستساعدك في تحسين إنتاجيتك عند إستخدامك لبيئة العمل Yii.
</p>
<ul dir="rtl">
<li>
التوثيق
<ul>
<li><a href="https://www.yiiframework.com/doc-2.0/guide-README.html">The Definitive Guide - الدليل الشامل</a>: كما يشير الإسم، فإن هذا الدليل يحدد آلية عمل ال Yii بدقة عالية، ويوفر إرشادات حول كيفية إستخدام ال Yii، هذا الجزء الأكثر أهمية في ال Yii، والذي يجب عليك قرائته قبل كتابة أي Yii code (ملاحظة: جزء البداية من هنا، والذي قمنا بدراسته هو أحد هذه الأجزاء، ومن أهمها للبدء بإنشاء التطبيقات من خلال ال Yii).</li>
<li><a href="https://www.yiiframework.com/doc-2.0/index.html">The Class Reference - المرجع الخاص بال Class</a> في هذا الجزء يتم تحديد الية إستخدام كل Class يقدمه ال Yii، في العادة يتم إستخدام هذا المرجع عند كتابة شيفرة برمجية وأنت ترغب في فهم آلية العمل ل Class معين، أو Method, او فهم Proporty معينة...الخ، من الأفضل إستخدام المرجع الخاص بال Class فقط عند فهم آلية العمل لل Yii. </li>
<li><a href="https://www.yiiframework.com/wiki/?tag=yii2">The Wiki Articles - مقالات الويكي</a> مقالات الويكي هي مجموعة من الخبرات العملية للمستخدمين، تمت كتابتها ونشرها على شكل مقالات لمشاركة الخبرات، ومعظم هذه الكتابات تكون مثل الوصفات الخاصة بالطبخ، موجودة لخدمة هدف معين، وحل مشكلة محددة باستخدام ال Yii، وبالرغم من أن هذه الكتابات قد لا تكون بجودة ودقة الدليل الشامل، الا أنها قد تغطي مواضيع أكثر، وتطرح أيضا حلولا مباشرة للإستخدام.</li>
<li><a href="https://www.yiiframework.com/doc/">الكتب</a></li>
</ul>
</li>
<li><a href="https://www.yiiframework.com/extensions/">Extensions - الملحقات</a>: تفتخر ال Yii بوجود مكتبة ضخمة من الملحقات التي تمت برمجتها وإضافتها من قبل المستخدمين المتطوعين الذين شاركوا أعمالهم وطورها لتجعل مهمة المطورين الآخرين أسهل وأسرع في تطوير التطبيفات المبنية بواسطة ال Yii.</li>
<li>
المجتمع
<ul>
<li>المنتدى: <a href="https://forum.yiiframework.com/">https://forum.yiiframework.com/</a></li>
<li>IRC chat: The #yii channel on the Libera (ircs://irc.libera.chat:6697/yii)</li>
<li>Slack chanel: <a href="https://yii.slack.com">https://yii.slack.com</a></li>
<li>Gitter chat: <a href="https://gitter.im/yiisoft/yii2">https://gitter.im/yiisoft/yii2</a></li>
<li>GitHub: <a href="https://github.com/yiisoft/yii2">https://github.com/yiisoft/yii2</a></li>
<li>Facebook: <a href="https://www.facebook.com/groups/yiitalk/">https://www.facebook.com/groups/yiitalk/</a></li>
<li>Twitter: <a href="https://twitter.com/yiiframework">https://twitter.com/yiiframework</a></li>
<li>LinkedIn: <a href="https://www.linkedin.com/groups/yii-framework-1483367">https://www.linkedin.com/groups/yii-framework-1483367</a></li>
<li>Stackoverflow: <a href="https://stackoverflow.com/questions/tagged/yii2">https://stackoverflow.com/questions/tagged/yii2</a></li>
</ul>
</li>
</ul>

25
docs/guide-ar/start-prerequisites.md

@ -1,25 +0,0 @@
# <div dir="rtl">ماذا يجب أن تعرف قبل البدء بال Yii</div>
<p dir="rtl">
منحنى التعلم الخاص بال Yii ليس حادًا مثل أطر PHP الأخرى، ولكن لا يزال هناك بعض الأشياء التي يجب أن تتعلمها قبل البدء بـال Yii.
</p>
## <div dir="rtl">PHP</div>
<p dir="rtl">
ال Yii هو إطار عمل PHP، لذا تأكد من قراءة وفهم المرجع الرسمي الخاص بلغة ال <a href="https://www.php.net/manual/en/langref.php">PHP</a>. عند البدء بتطوير المشاريع أو التطبيقات باستخدام ال Yii ، ستكتب التعليمات البرمجية بطريقة كائنية التوجه OOP، لذا تأكد من أنك على دراية بـمفاهيم ال <a href="https://www.php.net/manual/en/language.oop5.basic.php">OOP</a> وكذلك ال <a href="https://www.php.net/manual/en/language.namespaces.php">namespaces</a>.
</p>
## <div dir="rtl">البرمجة كائنية التوجه object oriented programming</div>
<p dir="rtl">
كمبرمج أو مطور يرغب بالعمل على ال Yii، يجب عليك أن تمتلك المعرفة الأساسية للبرمجة كائنية التوجه OOP. إذا لم تكن على دراية بها ، فيمكنك تعلم ذلك من خلال واحدة من هذه الدورات المنتشرة مثل هذه الدورة من <a href="https://code.tutsplus.com/tutorials/object-oriented-php-for-beginners--net-12762">tuts+</a>.<br />
ملاحظة: كلما زاد تعقيد التطبيق أو المشروع الذي تعمل عليه، كلما احتجت الى مستوى أعلى وإحترافي أكثر من مفاهيم ال OOP لحل وإدارة التعقديات التي ستترب على مثل هذه المشاريع.
</p>
## <div dir="rtl">Command line and composer</div>
<p dir="rtl">تستخدم ال Yii بشكل كبير de-facto standard PHP package manager، ال <a href="https://getcomposer.org/">Composer</a>، لذلك تأكد من قرائتك وفهمك لهذا الموضوع قبل أن تبدء. بالإضافة الى ذلك إذا لم تكن على دراية باستخدام سطر الأوامر (command line) ، فقد حان الوقت لبدء المحاولة. بمجرد تعلم الأساسيات ، لن ترغب في العمل بدون إستخدام سطر الأوامر.<br />
ال composer: ويترجم حرفيا الى كلمة "الملحن"، وهي عبارة عن أداة لإدارة المشاريع البرمجية والتي تسمح لك بتحديث وتنزيل المكتبات البرمجية المطلوبة للمشروع الخاص بك.
</p>

115
docs/guide-ar/start-workflow.md

@ -1,115 +0,0 @@
# <div dir="rtl">تشغيل التطبيقات</div>
<p dir="rtl">
بعد تثبيت ال Yii، سيكون لديك تطبيق Yii جاهز للعمل عليه ويمكن الوصول إليه عبر
الرابط التالي: <code>http://hostname/basic/web/index.php</code> أو <code>http://hostname/index.php</code> إعتمادا على الإعدادات
الخاصة بك (إعدادت ال web server). في هذا الجزء سنستعرض الوظائف ال built-in الموجودة في التطبيق الإفتراضي لإطار العمل Yii، وكيف يقوم بتنظيم الشيفرة البرمجية، وكيف يعالج (handling) هذا التطبيق الطلبات (requests) بشكل عام.
</p>
<blockquote class="info"><p dir="rtl">
معلومة: من أجل تبسيط الطرح، ومن خلال هذا البرنامج التعليمي " Getting Started - البداية من هنا"، من المفترض أنك قمت بتعيين <code>basic/web</code> ك <code>document root</code> لل Web server، وقد قمت أيضا بإعداد ال Url الذي يسمح لك بالوصول الى التطبيق المثبت من خلاله ليكون على الشكل التالي: <code>http://hostname/index.php</code> أو ما شابه ذلك.
اذا لم تقم بذلك، ولتلبية إحتياجاتك في هذا البرنامج التعليمي، يرجى ضبط ال Url كما هو موضح في هذه الصفحة.
يمكنك معرفة الضبط الخاص بال Web server من هنا: <a href="start-installation.md">تثبيت ال Yii </a>
</p></blockquote>
<p dir="rtl">
ملاحظة: بخلاف إطار العمل نفسه(Yii framework)، بعد تثبيت ال template الخاص بالمشروع، يكون كل شيء في هذا التطبيق يخصك أنت، بحيث تملك الحرية في إضافة أو حذف أو تعديل كل ما تحتاج اليه.
</p>
## <div dir="rtl">خصائص / وظائف التطبيق المثبت - Functionality</div> <span id="functionality"></span>
<p dir="rtl">
يحتوي ال Basic ِApplication Template الذي قمنا بتثبيته على أربع صفحات:
</p>
<ul dir="rtl">
<li>الصفحة الرئيسية(Homepage): يتم عرض هذه الصفحة من خلال الرابط التالي <code>http://hostname/index.php</code> </li>
<li>صفحة من نحن(About)</li>
<li>صفحة اتصل بنا (Contact): في هذه الصفحة يتم عرض form يسمح للأعشاء بالإتصال بك من خلال البريد الإلكتروني.</li>
<li>صفحة تسجيل الدخول (Login): في هذه الصفحة يتم عرض form يسمح للأعضاء بالحصول على الإذن لإستخدام الخصائص التي لا يجوز لغيرهم من الوصول اليها، قم بتجربة تسجيل الدخول من خلال استخدام <code>admin/admin</code> ولاحظ أن كلمة "Login" ستختفي من القائمة الرئيسية وستظهر محلها الكلمة "Logout"</li>
</ul>
<p dir="rtl">
هذه الصفحات تشترك بامتلاكها common header and footer -الترويسة أعلى الصفحة، والذيل أسفل الصفحة-. ويحتوي ال header على القائمة الرئيسية (main menu) والتي بدورها تسمح لك بالتنقل بين الصفحات المختلفة.
</p>
<p dir="rtl">
أيضا، يجب عليك أن تنظر الى ال toolbar الموجود في أسفل نافذة المتصفح. ال <a href="https://github.com/yiisoft/yii2-debug/blob/master/docs/guide/README.md">debugger tool</a> هذه تعتبر كأداة مفيدة مقدمة من ال Yii لتسجيل وعرض الكثير من المعلومات وتصحيح الأخطاء، مثل log messages, response statuses, the database queries run وما إلى ذلك.
</p>
<p dir="rtl">
بالإضافة إلى ال web application، يوجد هناك "console script" يسمى ب <code>yii</code>، والذي ستجده في المسار الرئيسي للتطبيق. هذا السكربت يمكن استخدامه لتشغيل المهام التي تعمل في الخفاء (background) أو لتنفيذ مهام الصيانة (ال maintenance). <br /> ستجد الوصف الخاص بهذا السكربت
داخل هذه الصفحة <a href="tutorial-console.md">Console Application Section</a>.
</p>
## <div dir="rtl">هيكلية التطبيق - Application Structure</a> <span id="application-structure"></span>
<p dir="rtl">
أكثر المسارات والملفات أهمية الموجودة داخل التطبيق (بافتراض أن ال application's root directory هو <code>basic</code>) هي:
</p>
```js
basic/ application base path
composer.json used by Composer, describes package information
config/ contains application and other configurations
console.php the console application configuration
web.php the Web application configuration
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
```
<p dir="rtl">
بشكل عام، يمكن تقسيم الملفات داخل التطبيق إلى نوعين: الاول تجده تحت المسار التالي: <code>basic/web</code والثاني تجده بالمسارات الأخرى.<br />
وبنائا على ذلك، فإنه من الممكن الوصول إلى النوع الأول مباشرة عبر ال HTTP (أي من خلال المتصفح) ، بينما لا يمكن أن يكون ذلك للنوع الثاني.
</p>
<p dir="rtl">
يعتمد ال Yii على إستخدام ال MVC، وال MVC هو أحد ال Architectural Pattern، وهي اختصار ل <a href="https://wikipedia.org/wiki/Model-view-controller">model-view-controller</a>،
هذا الأسلوب ينعكس في تنظيم المسارات الخاصة بالملفات كما في الشكل أعلاه. يحتوي المسار <code>models</code> على جميع الكلاس <a href="../guide/structure-models.md">(model classes)</a> ، ويحتوي مسار ال <code>views</code> على جميع الصفحات التي ستستخدم في العرض <a href="../guide/structure-controllers.md">(view scripts)</a>، ويحتوي مسار ال<code>controllers</code> على
جميع <a href="../guide/structure-views.md">(controller classes)</a>
</p>
<p dir="rtl">
يوضح المخطط التالي ال static structure للتطبيق.
</p>
![Static Structure of Application](../guide/images/application-structure.png)
<p dir="rtl">
يحتوي كل تطبيق على نص برمجي يستخدم للدخول الى التطبيق (كبوابة بعدها يظهر التطبيق للناظر)، ويسمى هذا الجزء بال entry script، وهو يمثل الصفحة <code>web/index.php</code>، ويعد هذا المدخل النص البرمجي الوحيد الذي يمكن الوصول إليه من خلال ال PHP في التطبيق، ويعمل هذا ال entry script على أخذ ال request ومن ثم إنشاء instance خاص بالتطبيق ليستطيع التعامل معه (التعامل مع التطبيق ومكوناته).
يقوم <a href="../guide/structure-applications.md">التطبيق</a> على معالجة ال request بمساعدة من ال <a href="../guide/concept-components.md">components</a>، ومن ثم بقوم التطبيق بإرسال ال request الى عناصر ال MVC، كما يتم استخدام ال <a href="../guide/structure-widgets.md">Widgets</a> في ال <a href="../guide/structure-views.md">views</a> للمساعدة في إنشاء العناصر المعقدة والمتغيرة (Complex & Dynamic user interface) لواجهة المستخدم.
</p>
## <div dir="rtl">دورة الحياة الخاصة بال request</a> <span id="request-lifecycle"></span>
<p dir="rtl">
يوضح المخطط التالي كيفية معالجة التطبيق ل request معين.
</p>
![Request Lifecycle](../guide/images/request-lifecycle.png)
<ol dir="rtl">
<li>يقوم المستخدم بعمل request لل <a href="../guide/structure-entry-scripts.md">entry script</a> <code>web/index.php</code>.</li>
<li>يقوم ال entry script على جلب <a href="../guide/concept-configurations.md">الإعدادات</a> الخاصة بالتطبيق ومن ثم إنشاء ال instance الخاص بالتطبيق ليستطيع التحكم ب request وإدارتها.</li>
<li>يقوم التطبيق بمعالجة ال <a href="../guide/runtime-routing.md">requested route</a> بمساعدة من ال <a href="../guide/runtime-requests.md">request</a> application component.</li>
<li>يقوم التطبيق على إنشاء instance من ال <a href="../guide/structure-controllers.md">controller</a> للتحكم بال request.</li>
<li>يقوم ال controller على إنشاء <a href="../guide/structure-controllers.md">action</a> instance مع مجموعة من الفلاتر(المرشحات) الخاصة بهذا ال action.</li>
<li>في حالة فشل أي فلتر، يتم إلغاء الإجراء.</li>
<li>في حال نجاح جميع الفلاتر ، يتم تنفيذ الإجراء.</li>
<li>يقوم ال action بجلب بعض البيانات الخاصة بال models, وفي الغالب ستكون من قاعدة البيانات إن أمكن ذلك.</li>
<li>سيقوم ال action بجلب ال view ليقوم بتقديم البيانات التي تم جلبها لل view.</li>
<li>عملية الجلب السابقة ستقوم على إرجاع النتائج الى <a href="../guide/runtime-responses.md">response</a> application component</li>
<li>بعد ذلك سيقوم ال response component بإرسال النتيجة النهائية الى المتصفح الخاص بالمستخدم. </li>
</ol>

2
docs/guide-de/README.md

@ -1,7 +1,7 @@
Das umfassende Handbuch für Yii 2.0
===================================
Dieses Tutorial wurde unter den [Bedingungen der Yii-Dokumentation](https://www.yiiframework.com/doc/terms/) veröffentlicht.
Dieses Tutorial wurde unter den [Bedingungen der Yii-Dokumentation](http://www.yiiframework.com/doc/terms/) veröffentlicht.
Alle Rechte vorbehalten.

3
docs/guide-de/translators.json

@ -1,3 +0,0 @@
[
"Carsten Brandt"
]

3
docs/guide-es/README.md

@ -1,7 +1,7 @@
Guía Definitiva de Yii 2.0
==========================
Este tutorial se publica bajo los [Términos de Documentación Yii](https://www.yiiframework.com/doc/terms/).
Este tutorial se publica bajo los [Términos de Documentación Yii](http://www.yiiframework.com/doc/terms/).
Todos los derechos reservados.
@ -18,7 +18,6 @@ Introducción
Primeros pasos
--------------
* [Qué necesita saber](start-prerequisites.md)
* [Instalar Yii](start-installation.md)
* [Funcionamiento de aplicaciones](start-workflow.md)
* [Hola a todos](start-hello.md)

22
docs/guide-es/caching-data.md

@ -28,7 +28,7 @@ representan diferentes tipos de almacenamiento en caché, como por ejemplo en me
Los Componentes de Caché están normalmente registrados como [componentes de la aplicación](structure-application-components.md) para que de esta forma puedan
ser configurados y accesibles globalmente. El siguiente código muestra cómo configurar el componente de aplicación
`cache` para usar [memcached](https://memcached.org/) con dos servidores caché:
`cache` para usar [memcached](http://memcached.org/) con dos servidores caché:
```php
'components' => [
@ -72,15 +72,15 @@ el código que utiliza la caché. Por ejemplo, podrías modificar la configuraci
Yii proporciona varios componentes de caché que pueden almacenar datos en diferentes medios. A continuación
se muestra un listado con los componentes de caché disponibles:
* [[yii\caching\ApcCache]]: utiliza la extensión de PHP [APC](https://www.php.net/manual/es/book.apc.php). Esta opción puede ser considerada como la más rápida de entre todas las disponibles para una aplicación centralizada. (ej. un servidor, no dedicado al balance de carga, etc).
* [[yii\caching\DbCache]]: utiliza una tabla de base de datos para almacenar los datos. Por defecto, se creará y usará como base de datos [SQLite3](https://sqlite.org/) en el directorio runtime. Se puede especificar explícitamente que base de datos va a ser utilizada configurando la propiedad `db`.
* [[yii\caching\ApcCache]]: utiliza la extensión de PHP [APC](http://php.net/manual/es/book.apc.php). Esta opción puede ser considerada como la más rápida de entre todas las disponibles para una aplicación centralizada. (ej. un servidor, no dedicado al balance de carga, etc).
* [[yii\caching\DbCache]]: utiliza una tabla de base de datos para almacenar los datos. Por defecto, se creará y usará como base de datos [SQLite3](http://sqlite.org/) en el directorio runtime. Se puede especificar explícitamente que base de datos va a ser utilizada configurando la propiedad `db`.
* [[yii\caching\DummyCache]]: dummy cache (caché tonta) que no almacena en caché nada. El propósito de este componente es simplificar el código necesario para chequear la disponibilidad de caché. Por ejemplo, durante el desarrollo o si el servidor no tiene soporte de caché actualmente, puede utilizarse este componente de caché. Cuando este disponible un soporte en caché, puede cambiarse el componente correspondiente. En ambos casos, puede utilizarse el mismo código `Yii::$app->cache->get($key)` para recuperar un dato sin la preocupación de que `Yii::$app->cache` pueda ser `null`.
* [[yii\caching\FileCache]]: utiliza un fichero estándar para almacenar los datos. Esto es adecuado para almacenar grandes bloques de datos (como páginas).
* [[yii\caching\MemCache]]: utiliza las extensiones de PHP [memcache](https://www.php.net/manual/es/book.memcache.php) y [memcached](https://www.php.net/manual/es/book.memcached.php). Esta opción puede ser considerada como la más rápida cuando la caché es manejada en una aplicación distribuida (ej. con varios servidores, con balance de carga, etc..)
* [[yii\redis\Cache]]: implementa un componente de caché basado en [Redis](https://redis.io/) que almacenan pares clave-valor (requiere la versión 2.6.12 de redis).
* [[yii\caching\WinCache]]: utiliza la extensión de PHP [WinCache](https://iis.net/downloads/microsoft/wincache-extension) ([ver también](https://www.php.net/manual/es/book.wincache.php)).
* [[yii\caching\XCache]] _(deprecated)_: utiliza la extensión de PHP [XCache](https://en.wikipedia.org/wiki/List_of_PHP_accelerators#XCache).
* [[yii\caching\ZendDataCache]] _(deprecated)_: utiliza [Zend Data Cache](https://files.zend.com/help/Zend-Server-6/zend-server.htm#data_cache_component.htm) como el medio fundamental de caché.
* [[yii\caching\MemCache]]: utiliza las extensiones de PHP [memcache](http://php.net/manual/es/book.memcache.php) y [memcached](http://php.net/manual/es/book.memcached.php). Esta opción puede ser considerada como la más rápida cuando la caché es manejada en una aplicación distribuida (ej. con varios servidores, con balance de carga, etc..)
* [[yii\redis\Cache]]: implementa un componente de caché basado en [Redis](http://redis.io/) que almacenan pares clave-valor (requiere la versión 2.6.12 de redis).
* [[yii\caching\WinCache]]: utiliza la extensión de PHP [WinCache](http://iis.net/downloads/microsoft/wincache-extension) ([ver también](http://php.net/manual/es/book.wincache.php)).
* [[yii\caching\XCache]]: utiliza la extensión de PHP [XCache](http://xcache.lighttpd.net/).
* [[yii\caching\ZendDataCache]]: utiliza [Zend Data Cache](http://files.zend.com/help/Zend-Server-6/zend-server.htm#data_cache_component.htm) como el medio fundamental de caché.
> Tip: Puedes utilizar diferentes tipos de almacenamiento de caché en la misma aplicación. Una estrategia común es la de usar almacenamiento de caché en memoria para almacenar datos que son pequeños pero que son utilizados constantemente (ej. datos estadísticos), y utilizar el almacenamiento de caché en archivos o en base de datos para guardar datos que son grandes y utilizados con menor frecuencia (ej. contenido de página).
@ -182,7 +182,7 @@ $cache->set($key, $data, 30, $dependency);
// La caché comprobará si los datos han expirado.
// También comprobará si la dependencia ha cambiado.
// Devolverá `false` si se encuentran algunas de esas condiciones.
// Devolverá false si se encuentran algunas de esas condiciones.
$data = $cache->get($key);
```
@ -221,7 +221,7 @@ $result = Customer::getDb()->cache(function ($db) {
});
```
> Note: Algunos DBMS (ej. [MySQL](https://dev.mysql.com/doc/refman/5.6/en/query-cache.html)) también soporta el almacenamiento en caché desde el mismo servidor de la BD. Puedes optar por utilizar cualquiera de los mecanismos de memoria caché. El almacenamiento en caché de consultas previamente descrito tiene la ventaja que de que se puede especificar dependencias de caché de una forma flexible y son potencialmente mucho más eficientes.
> Note: Algunos DBMS (ej. [MySQL](http://dev.mysql.com/doc/refman/5.1/en/query-cache.html)) también soporta el almacenamiento en caché desde el mismo servidor de la BD. Puedes optar por utilizar cualquiera de los mecanismos de memoria caché. El almacenamiento en caché de consultas previamente descrito tiene la ventaja que de que se puede especificar dependencias de caché de una forma flexible y son potencialmente mucho más eficientes.
### Configuraciones <span id="query-caching-configs"></span>
@ -229,7 +229,7 @@ $result = Customer::getDb()->cache(function ($db) {
Las consultas en caché tienen tres opciones configurables globales a través de [[yii\db\Connection]]:
* [[yii\db\Connection::enableQueryCache|enableQueryCache]]: activa o desactiva el cacheo de consultas.
Por defecto es `true`. Tenga en cuenta que para activar el cacheo de consultas, también necesitas tener una caché válida, especificada por [[yii\db\Connection::queryCache|queryCache]].
Por defecto es true. Tenga en cuenta que para activar el cacheo de consultas, también necesitas tener una caché válida, especificada por [[yii\db\Connection::queryCache|queryCache]].
* [[yii\db\Connection::queryCacheDuration|queryCacheDuration]]: representa el número de segundos que un resultado de la consulta permanecerá válida en la memoria caché. Puedes usar 0 para indicar que el resultado de la consulta debe permanecer en la caché para siempre. Esta propiedad es el valor usado por defecto cuando [[yii\db\Connection::cache()]] es llamada sin especificar una duración.
* [[yii\db\Connection::queryCache|queryCache]]: representa el ID del componente de aplicación de caché.
Por defecto es `'cache'`. El almacenamiento en caché de consultas se habilita sólo si hay un componente de la aplicación de caché válida.

6
docs/guide-es/caching-http.md

@ -28,7 +28,7 @@ la página. El formato de la función de llamada de retorno debe ser el siguient
/**
* @param Action $action el objeto acción que se está controlando actualmente
* @param array $params el valor de la propiedad "params"
* @return int un sello de tiempo UNIX que representa el tiempo de modificación de la página
* @return integer un sello de tiempo UNIX que representa el tiempo de modificación de la página
*/
function ($action, $params)
```
@ -110,7 +110,7 @@ La generación de un ETag que requiera muchos recursos puede echar por tierra el
introducir una sobrecarga innecesaria, ya que debe ser re-evaluada en cada solicitud (request). Trata de encontrar una
expresión sencilla para invalidar la caché si la página ha sido modificada.
> Note: En cumplimiento con [RFC 7232](https://datatracker.ietf.org/doc/html/rfc7232#section-2.4),
> Note: En cumplimiento con [RFC 7232](http://tools.ietf.org/html/rfc7232#section-2.4),
`HttpCache` enviará ambas cabeceras `ETag` y `Last-Modified` si ambas están configuradas. Y si el clientes envía tanto la cabecera `If-None-Match` como la cabecera `If-Modified-Since`, solo la primera será respetada.
## La Cabecera `Cache-Control` <span id="cache-control"></span>
@ -130,7 +130,7 @@ especifican en `session.cache_limiter` de la configuración INI de PHP. Estas ca
el almacenamiento de caché que desees de `HttpCache`. Para evitar este problema, por defecto `HttpCache` deshabilitará
automáticamente el envío de estas cabeceras. Si deseas modificar este comportamiento, tienes que configurar la propiedad
[[yii\filters\HttpCache::sessionCacheLimiter]]. La propiedad puede tomar un valor de cadena, incluyendo `public`, `private`,
`private_no_expire`, and `nocache`. Por favor, consulta el manual PHP acerca de [session_cache_limiter()](https://www.php.net/manual/es/function.session-cache-limiter.php)
`private_no_expire`, and `nocache`. Por favor, consulta el manual PHP acerca de [session_cache_limiter()](http://www.php.net/manual/es/function.session-cache-limiter.php)
para una mejor explicación sobre esos valores.

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

@ -1,17 +1,15 @@
Alias
=====
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 `@`.
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.
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.
Definiendo Alias <span id="defining-aliases"></span>
----------------
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,
Puedes llamar a [[Yii::setAlias()]] para definir un alias para una determinada ruta de archivo o URL. Por ejemplo,
```php
// un alias de una ruta de archivos
@ -85,10 +83,9 @@ 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;
@ -112,9 +109,9 @@ utilizadas regularmente. La siguiente es la lista de alias predefinidos por Yii:
- `@runtime`: la [[yii\base\Application::runtimePath|ruta de ejecución]] de la aplicación en ejecución. Por defecto `@app/runtime`.
- `@webroot`: el directorio raíz Web de la aplicación Web se está ejecutando actualmente.
- `@web`: la URL base de la aplicación web se ejecuta actualmente. Tiene el mismo valor que [[yii\web\Request::baseUrl]].
- `@vendor`: el [[yii\base\Application::vendorPath|directorio vendor de Composer]]. Por defecto `@app/vendor`.
- `@bower`, el directorio raíz que contiene [paquetes bower](https://bower.io/). Por defecto `@vendor/bower`.
- `@npm`, el directorio raíz que contiene [paquetes npm](https://www.npmjs.com/). Por defecto `@vendor/npm`.
- `@vendor`: el [[yii\base\Application::vendorPath|directorio vendor de Composer]. Por defecto `@app/vendor`.
- `@bower`, el directorio raíz que contiene [paquetes bower](http://bower.io/). Por defecto `@vendor/bower`.
- `@npm`, el directorio raíz que contiene [paquetes npm](https://www.npmjs.org/). Por defecto `@vendor/npm`.
El alias `@yii` se define cuando incluyes el archivo `Yii.php` en tu [script de entrada](structure-entry-scripts.md),
mientras que el resto de los alias están definidos en el constructor de la aplicación cuando se aplica la
@ -124,10 +121,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 automáticamente por cada [extensión](structure-extensions.md) que ha sido instalada a través de Composer.
Un alias se define automaticamente 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
automáticamente definido el alias `@yii/jui` durante la etapa [bootstrapping](runtime-bootstrapping.md) de la aplicación:
automaticamente 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');

8
docs/guide-es/concept-autoloading.md

@ -1,9 +1,9 @@
Autocarga de clases
===================
Yii depende del [mecanismo de autocarga de clases](https://www.php.net/manual/es/language.oop5.autoload.php) para localizar
Yii depende del [mecanismo de autocarga de clases](http://www.php.net/manual/es/language.oop5.autoload.php) para localizar
e incluir los archivos de las clases requiridas. Proporciona un cargador de clases de alto rendimiento que cumple con el
[estandard PSR-4](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md).
[estandard PSR-4](https://github.com/php-fig/fig-standards/blob/master/proposed/psr-4-autoloader/psr-4-autoloader.md).
El cargador se instala cuando incluyes el archivo `Yii.php`.
> Note: Para simplificar la descripción, en esta sección sólo hablaremos de la carga automática de clases. Sin embargo,
@ -73,8 +73,8 @@ sido extraido del [script de entrada](structure-entry-scripts.md) de la [Plantil
La primera línea instala el autocargador de Composer, mientras que la segunda línea instala el autocargador de Yii.
```php
require __DIR__ . '/../vendor/autoload.php';
require __DIR__ . '/../vendor/yiisoft/yii2/Yii.php';
require(__DIR__ . '/../vendor/autoload.php');
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
```
Puedes usar el autocargador de Composer sin el autocargador de Yii. Sin embargo, al hacerlo, la eficacia de la carga de

30
docs/guide-es/concept-behaviors.md

@ -2,7 +2,7 @@ Comportamientos
===============
Comportamientos son instancias de [[yii\base\Behavior]] o sus clases "hija". Comportamientos, también conocido como
[mixins](https://en.wikipedia.org/wiki/Mixin), te permiten mejorar la funcionalidad de un [[yii\base\Component|componente]]
[mixins](http://en.wikipedia.org/wiki/Mixin), te permiten mejorar la funcionalidad de un [[yii\base\Component|componente]]
existente sin necesidad de modificar su herencia de clases.
Cuando un comportamiento se une a un componente, "inyectará" sus métodos y propiedades dentro del componente, y podrás
acceder a esos métodos y propiedades como si hubieran estado definidos por la clase de componente. Además, un
@ -44,7 +44,7 @@ class MyBehavior extends Behavior
```
El código anterior define la clase de comportamiento (behavior) app\components\MyBehavior`, con dos propiedades --
`prop1` y `prop2`--y un método `foo()`. Tenga en cuenta que la propiedad `prop2`
se define a través de la getter `getProp2()` y el setter `setProp2()`. Este caso es porque [[yii\base\Behavior]] extiende [[yii\base\BaseObject]] y por lo tanto se apoya en la definición de [propiedades](concept-properties.md) via getters y setters.
se define a través de la getter `getProp2()` y el setter `setProp2()`. Este caso es porque [[yii\base\Behavior]] extiende [[yii\base\Object]] y por lo tanto se apoya en la definición de [propiedades](concept-properties.md) via getters y setters.
Debido a que esta clase es un comportamiento, cuando está unido a un componente, el componente también tienen la propiedad `prop1` y `prop2` y el método `foo()`.
@ -116,21 +116,21 @@ class User extends ActiveRecord
{
return [
// anonymous behavior, behavior class name only
MyBehavior::class,
MyBehavior::className(),
// named behavior, behavior class name only
'myBehavior2' => MyBehavior::class,
'myBehavior2' => MyBehavior::className(),
// anonymous behavior, configuration array
[
'class' => MyBehavior::class,
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop2' => 'value2',
],
// named behavior, configuration array
'myBehavior4' => [
'class' => MyBehavior::class,
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop2' => 'value2',
]
@ -151,14 +151,14 @@ que se le va a unir el comportamiento:
use app\components\MyBehavior;
// vincular un objeto comportamiento "behavior"
$component->attachBehavior('myBehavior1', new MyBehavior());
$component->attachBehavior('myBehavior1', new MyBehavior);
// vincular una clase comportamiento
$component->attachBehavior('myBehavior2', MyBehavior::class);
$component->attachBehavior('myBehavior2', MyBehavior::className());
// asociar una matriz de configuración
$component->attachBehavior('myBehavior3', [
'class' => MyBehavior::class,
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop2' => 'value2',
]);
@ -167,8 +167,8 @@ Puede vincular múltiples comportamientos a la vez mediante el uso del método [
```php
$component->attachBehaviors([
'myBehavior1' => new MyBehavior(), // un comportamiento nombrado
MyBehavior::class, // un comportamiento anónimo
'myBehavior1' => new MyBehavior, // un comportamiento nombrado
MyBehavior::className(), // un comportamiento anónimo
]);
```
@ -176,10 +176,10 @@ También puedes asociar comportamientos a traves de [configuraciones](concept-co
```php
[
'as myBehavior2' => MyBehavior::class,
'as myBehavior2' => MyBehavior::className(),
'as myBehavior3' => [
'class' => MyBehavior::class,
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop2' => 'value2',
],
@ -270,7 +270,7 @@ class User extends ActiveRecord
{
return [
[
'class' => TimestampBehavior::class,
'class' => TimestampBehavior::className(),
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => ['created_at', 'updated_at'],
ActiveRecord::EVENT_BEFORE_UPDATE => ['updated_at'],
@ -309,7 +309,7 @@ $user->touch('login_time');
Comparación con Traits <span id="comparison-with-traits"></span>
----------------------
Mientras que los comportamientos son similares a [traits](https://www.php.net/traits) en cuanto que ambos "inyectan" sus
Mientras que los comportamientos son similares a [traits](http://www.php.net/traits) en cuanto que ambos "inyectan" sus
métodos y propiedades a la clase primaria, son diferentes en muchos aspectos. Tal y como se describe abajo, los dos
tienen sus ventajas y desventajas. Son más como complementos el uno al otro en lugar de alternativas.

16
docs/guide-es/concept-components.md

@ -25,22 +25,22 @@ echo DatePicker::widget([
Las propiedades del widget son fácilmente modificables porque la clase se extiende de [[yii\base\Component]].
Mientras que los componentes son muy potentes, son un poco más pesados que los objetos normales, debido al hecho de que necesitan más memoria y tiempo de CPU para poder soportar [eventos](concept-events.md) y [comportamientos](concept-behaviors.md) en particular.
Si tus componentes no necesitan estas dos características, deberías considerar extender tu componente directamente de [[yii\base\BaseObject]] en vez de [[yii\base\Component]]. De esta manera harás que tus componentes sean mucho más eficientes que objetos PHP normales, pero con el añadido soporte para [propiedades](concept-properties.md).
Si tus componentes no necesitan estas dos características, deberías considerar extender tu componente directamente de [[yii\base\Object]] en vez de [[yii\base\Component]]. De esta manera harás que tus componentes sean mucho más eficientes que objetos PHP normales, pero con el añadido soporte para [propiedades](concept-properties.md).
Cuando extiendes tu clase de [[yii\base\Component]] o [[yii\base\BaseObject]], se recomienda que sigas las siguientes convenciones:
Cuando extiendes tu clase de [[yii\base\Component]] o [[yii\base\Object]], se recomienda que sigas las siguientes convenciones:
- Si sobrescribes el constructor, especifica un parámetro `$config` como el *último* parámetro del constructor, y después pasa este parámetro al constructor padre.
- Siempre llama al constructor padre al *final* de su propio constructor.
- Si sobrescribes el método [[yii\base\BaseObject::init()]], asegúrese de llamar la implementación padre de `init` * al principio * de su método` init`.
- Si sobrescribes el método [[yii\base\Object::init()]], asegúrese de llamar la implementación padre de `init` * al principio * de su método` init`.
Por ejemplo:
```php
namespace yii\components\MyClass;
use yii\base\BaseObject;
use yii\base\Object;
class MyClass extends BaseObject
class MyClass extends Object
{
public $prop1;
public $prop2;
@ -67,7 +67,7 @@ Siguiendo esas directrices hará que tus componentes sean [configurables](concep
$component = new MyClass(1, 2, ['prop1' => 3, 'prop2' => 4]);
// alternativamente
$component = \Yii::createObject([
'class' => MyClass::class,
'class' => MyClass::className(),
'prop1' => 3,
'prop2' => 4,
], [1, 2]);
@ -76,11 +76,11 @@ $component = \Yii::createObject([
> Info: Mientras que el enfoque de llamar [[Yii::createObject()]] parece mucho más complicado, es mucho más potente debido al hecho de que se implementa en la parte superior de un [contenedor de inyección de dependencia](concept-di-container.md).
La clase [[yii\base\BaseObject]] hace cumplir el siguiente ciclo de vida del objeto:
La clase [[yii\base\Object]] hace cumplir el siguiente ciclo de vida del objeto:
1. Pre-inicialización en el constructor. Puedes establecer los valores predeterminados de propiedades aquí.
2. Configuración del objeto a través de `$config`. La configuración puede sobrescribir los valores prdeterminados dentro del constructor.
3. Post-inicialización dentro de [[yii\base\BaseObject::init()|init()]]. Puedes sobrescribir este método para realizar comprobaciones de validez y normalización de las propiedades.
3. Post-inicialización dentro de [[yii\base\Object::init()|init()]]. Puedes sobrescribir este método para realizar comprobaciones de validez y normalización de las propiedades.
4. Llamadas a métodos del objeto.
Los tres primeros pasos ocurren dentro del constructor del objeto. Esto significa que una vez obtengas la instancia de un objeto, ésta ha sido inicializada para que puedas utilizarla adecuadamente.

10
docs/guide-es/concept-configurations.md

@ -65,7 +65,7 @@ A continuación se muestra un ejemplo de una configuración con los valores de p
## Usando Configuraciones <span id="using-configurations"></span>
Las configuraciones se utilizan en muchos lugares en Yii. Al comienzo de esta sección, hemos demostrado cómo crear un objeto según una configuración mediante el uso de [[Yii::createObject()]]. En este apartado, vamos a describir configuraciones de aplicaciones y configuraciones widget - dos principales usos de configuraciones.
Las configuraciones se utilizan en muchos lugares en Yii. Al comienzo de esta sección, hemos demostrado cómo crear un objeto según una configuración mediante el uso de [[Yii::CreateObject()]]. En este apartado, vamos a describir configuraciones de aplicaciones y configuraciones widget - dos principales usos de configuraciones.
### Configuraciones de aplicación <span id="application-configurations"></span>
@ -76,7 +76,7 @@ Configuración para una [aplicación](structure-applications.md) es probablement
$config = [
'id' => 'basic',
'basePath' => dirname(__DIR__),
'extensions' => require __DIR__ . '/../vendor/yiisoft/extensions.php',
'extensions' => require(__DIR__ . '/../vendor/yiisoft/extensions.php'),
'components' => [
'cache' => [
'class' => 'yii\caching\FileCache',
@ -143,8 +143,8 @@ Cuando una configuración es muy compleja, una práctica común es almacenarla e
return [
'id' => 'basic',
'basePath' => dirname(__DIR__),
'extensions' => require __DIR__ . '/../vendor/yiisoft/extensions.php',
'components' => require __DIR__ . '/components.php',
'extensions' => require(__DIR__ . '/../vendor/yiisoft/extensions.php'),
'components' => require(__DIR__ . '/components.php'),
];
```
@ -180,7 +180,7 @@ return [
Para obtener una configuración almacenada en un archivo de configuración, simplemente "requerir" este, como el siguiente:
```php
$config = require 'path/to/web.php';
$config = require('path/to/web.php');
(new yii\web\Application($config))->run();
```

18
docs/guide-es/concept-di-container.md

@ -2,7 +2,7 @@ Contenedor de Inyección de Dependencias
=======================================
Un contenedor de Inyección de Dependencias (ID), es un objeto que sabe como instancias y configurar objetos y sus
objetos dependientes. El [articulo de Martin](https://martinfowler.com/articles/injection.html) contiene una buena
objetos dependientes. El [articulo de Martin](http://martinfowler.com/articles/injection.html) contiene una buena
explicación de porque son útiles los contenedores de ID. A continuación explicaremos como usar el contenedor de ID que
proporciona Yii.
@ -14,7 +14,7 @@ de ID:
* Inyección de constructores;
* Inyección de setters y propiedades;
* Inyección de [llamadas de retorno PHP](https://www.php.net/manual/es/language.types.callable.php);
* Inyección de [llamadas de retorno PHP](http://php.net/manual/es/language.types.callable.php);
### Inyección de Constructores <span id="constructor-injection"></span>
@ -44,9 +44,9 @@ registra una dependencia o se crea un nuevo objeto, se puede proporcionar una co
para inyectar las dependencias a través de sus correspondientes setters y propiedades. Por ejemplo,
```php
use yii\base\BaseObject;
use yii\base\Object;
class Foo extends BaseObject
class Foo extends Object
{
public $bar;
@ -75,7 +75,7 @@ En este caso, el contenedor usará una llamada de retorno PHP registrada para co
clase. La llamada de retorno se responsabiliza de que dependencias debe inyectar al nuevo objeto creado. Por ejemplo,
```php
$container->set('Foo', function ($container, $params, $config) {
$container->set('Foo', function () {
return new Foo(new Bar);
});
@ -185,7 +185,7 @@ una nueva instancia de `UserLister` con una simple llamada a `get('userLister')`
```php
namespace app\models;
use yii\base\BaseObject;
use yii\base\Object;
use yii\db\Connection;
use yii\di\Container;
@ -194,7 +194,7 @@ interface UserFinderInterface
function findUser();
}
class UserFinder extends BaseObject implements UserFinderInterface
class UserFinder extends Object implements UserFinderInterface
{
public $db;
@ -209,7 +209,7 @@ class UserFinder extends BaseObject implements UserFinderInterface
}
}
class UserLister extends BaseObject
class UserLister extends Object
{
public $finder;
@ -316,7 +316,7 @@ Resumen <span id="summary"></span>
Tanto la inyección de dependencias como el [localizador de servicios](concept-service-locator.md) son patrones de
diseño populares que permiten construir software con acoplamiento flexible y más fácil de testear. Se recomienda
encarecida la lectura del articulo de [Martin](https://martinfowler.com/articles/injection.html) para obtener una mejor
encarecida la lectura del articulo de [Martin](http://martinfowler.com/articles/injection.html) para obtener una mejor
comprensión de la inyección de dependencias y de la localización de servicios.
Yii implementa su propio [localizador de servicios](concept-service-locator.md) por encima del contenedor de ID.

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

@ -13,7 +13,7 @@ Gestor de Eventos <span id="event-handlers"></span>
-----------------
Un gestor de eventos es una
[llamada de retorno PHP (PHP callback)](https://www.php.net/manual/es/language.types.callable.php) que se ejecuta cuando se
[llamada de retorno PHP (PHP callback)](http://php.net/manual/es/language.types.callable.php) que se ejecuta cuando se
lanza el evento al que corresponde. Se puede usar cualquier llamada de retorno de las enumeradas a continuación:
- una función de PHP global especificada como una cadena de texto (sin paréntesis), ej. `'trim'`;
@ -96,7 +96,7 @@ $foo->on(Foo::EVENT_HELLO, function ($event) {
De forma predeterminada, cada nuevo gestor añadido se pone a la cola de la lista de gestores del evento. Por lo tanto,
el gestor se ejecutará en el último lugar cuando se lance el evento. Para insertar un nuevo gestor al principio de la
cola de gestores para que sea ejecutado primero, se debe llamar a [[yii\base\Component::on()]], pasando al cuarto
parámetro `$append` el valor `false`:
parámetro `$append` el valor false:
```php
$foo->on(Foo::EVENT_HELLO, function ($event) {
@ -217,8 +217,8 @@ use Yii;
use yii\base\Event;
use yii\db\ActiveRecord;
Event::on(ActiveRecord::class, ActiveRecord::EVENT_AFTER_INSERT, function ($event) {
Yii::debug(get_class($event->sender) . ' is inserted');
Event::on(ActiveRecord::className(), ActiveRecord::EVENT_AFTER_INSERT, function ($event) {
Yii::trace(get_class($event->sender) . ' is inserted');
});
```
@ -236,11 +236,11 @@ invocación de los gestores de eventos a nivel de clase.
```php
use yii\base\Event;
Event::on(Foo::class, Foo::EVENT_HELLO, function ($event) {
var_dump($event->sender); // displays "null"
Event::on(Foo::className(), Foo::EVENT_HELLO, function ($event) {
echo $event->sender; // displays "app\models\Foo"
});
Event::trigger(Foo::class, Foo::EVENT_HELLO);
Event::trigger(Foo::className(), Foo::EVENT_HELLO);
```
Tenga en cuenta que en este caso, el `$event->sender` hace referencia al nombre de la clase que lanza el evento en
@ -248,16 +248,16 @@ lugar de a la instancia del objeto.
> Note: Debido a que los gestores a nivel de clase responderán a los eventos lanzados por cualquier instancia de la
clase, o cualquier clase hija, se debe usar con cuidado, especialmente en las clases de bajo nivel (low-level), tales
como [[yii\base\BaseObject]].
como [[yii\base\Object]].
Para desadjuntar un gestor de eventos a nivel de clase, se tiene que llamar a [[yii\base\Event::off()]]. Por ejemplo:
```php
// desadjunta $handler
Event::off(Foo::class, Foo::EVENT_HELLO, $handler);
Event::off(Foo::className(), Foo::EVENT_HELLO, $handler);
// desadjunta todos los gestores de Foo::EVENT_HELLO
Event::off(Foo::class, Foo::EVENT_HELLO);
Event::off(Foo::className(), Foo::EVENT_HELLO);
```
Eventos Globales <span id="global-events"></span>

10
docs/guide-es/concept-properties.md

@ -17,11 +17,11 @@ ejemplo que la primera letra tiene que estar en mayúsculas, se tendrán que mod
asignen el valor a la propiedad `label`. La repetición de código conlleva a bugs, y es una practica que se tiene que
evitar en la medida de lo posible.
Para solventar este problema, Yii introduce la clase base llamada [[yii\base\BaseObject]] que da soporte a la definición
Para solventar este problema, Yii introduce la clase base llamada [[yii\base\Object]] que da soporte a la definición
de propiedades basada en los métodos de clase *getter* y *setter*. Si una clase necesita más funcionalidad, debe
extender a la clase [[yii\base\BaseObject]] o a alguna de sus hijas.
extender a la clase [[yii\base\Object]] o a alguna de sus hijas.
> Info: Casi todas las clases del núcleo (core) en el framework Yii extienden a [[yii\base\BaseObject]] o a una de
> Info: Casi todas las clases del núcleo (core) en el framework Yii extienden a [[yii\base\Object]] o a una de
sus clases hijas. Esto significa que siempre que se encuentre un getter o un setter en una clase del núcleo, se
puede utilizar como una propiedad.
@ -32,9 +32,9 @@ setter `setLabel()` definen la propiedad `label`, como se muestra a continuació
```php
namespace app\components;
use yii\base\BaseObject;
use yii\base\Object;
class Foo extends BaseObject
class Foo extends Object
{
private $_label;

26
docs/guide-es/db-dao.md

@ -1,7 +1,7 @@
Objetos de Acceso a Bases de Datos
==================================
Construido sobre [PDO](https://www.php.net/manual/es/book.pdo.php), Yii DAO (Objetos de Acceso a Bases de Datos) proporciona una
Construido sobre [PDO](http://php.net/manual/es/book.pdo.php), Yii DAO (Objetos de Acceso a Bases de Datos) proporciona una
API orientada a objetos para el acceso a bases de datos relacionales. Es el fundamento para otros métodos de acceso a bases de datos
más avanzados, incluyendo el [constructor de consultas](db-query-builder.md) y [active record](db-active-record.md).
@ -11,12 +11,12 @@ Yii DAO también significa que tienes que tienes que tomar un esfuerzo adicional
Yii DAO soporta las siguientes bases de datos:
- [MySQL](https://www.mysql.com/)
- [MySQL](http://www.mysql.com/)
- [MariaDB](https://mariadb.com/)
- [SQLite](https://sqlite.org/)
- [PostgreSQL](https://www.postgresql.org/): versión 8.4 o superior.
- [CUBRID](https://www.cubrid.org/): versión 9.3 o superior.
- [Oracle](https://www.oracle.com/database/)
- [SQLite](http://sqlite.org/)
- [PostgreSQL](http://www.postgresql.org/)
- [CUBRID](http://www.cubrid.org/): versión 9.3 o superior.
- [Oracle](http://www.oracle.com/us/products/database/overview/index.html)
- [MSSQL](https://www.microsoft.com/en-us/sqlserver/default.aspx): versión 2008 o superior.
## Creando Conexiones DB <span id="creating-db-connections"></span>
@ -60,7 +60,7 @@ Puedes acceder a la conexión DB mediante la expresión `Yii::$app->db`.
Cuando configuras una conexión DB, deberías siempre especificar el Nombre de Origen de Datos (DSN) mediante la
propiedad [[yii\db\Connection::dsn|dsn]]. El formato del DSN varia para cada diferente base de datos. Por favor consulte el
[manual de PHP](https://www.php.net/manual/es/function.PDO-construct.php) para más detalles. Abajo están algunos ejemplos:
[manual de PHP](http://www.php.net/manual/es/function.PDO-construct.php) para más detalles. Abajo están algunos ejemplos:
* MySQL, MariaDB: `mysql:host=localhost;dbname=mydatabase`
* SQLite: `sqlite:/path/to/database/file`
@ -111,7 +111,7 @@ $posts = $db->createCommand('SELECT * FROM post')
->queryAll();
// retorna una sola fila (la primera fila)
// `false` es retornado si no hay resultados
// false es retornado si no hay resultados
$post = $db->createCommand('SELECT * FROM post WHERE id=1')
->queryOne();
@ -121,7 +121,7 @@ $titles = $db->createCommand('SELECT title FROM post')
->queryColumn();
// retorna un escalar
// `false` es retornado si no hay resultados
// false es retornado si no hay resultados
$count = $db->createCommand('SELECT COUNT(*) FROM post')
->queryScalar();
```
@ -185,7 +185,7 @@ $post = $db->createCommand('SELECT * FROM post WHERE id=:id AND status=:status',
->queryOne();
```
La vinculación parámetros es implementada mediante [sentencias preparadas (prepared statements)](https://www.php.net/manual/es/mysqli.quickstart.prepared-statements.php).
La vinculación parámetros es implementada mediante [sentencias preparadas (prepared statements)](http://php.net/manual/es/mysqli.quickstart.prepared-statements.php).
Además de prevenir ataques de inyección de SQL, también puede mejorar el rendimiento preparando una sola vez una sentencia SQL y ejecutándola múltiples veces con diferentes
parámetros. Por ejemplo,
@ -279,7 +279,7 @@ $count = $db->createCommand("SELECT COUNT([[id]]) FROM {{employee}}")
```
### Usando Prefijos de Tabla <span id="using-table-prefix"></span>
### Usadno Prefijos de Tabla <span id="using-table-prefix"></span>
Si la mayoría de tus tablas de BD utilizan algún prefijo común en sus tablas, puedes usar la función de prefijo de tabla soportado
por Yii DAO.
@ -396,7 +396,7 @@ En el momento de escribir esto, solo MSSQL y SQLite serán afectadas.
puede especificar el nivel de aislamiento directamente cuando empieza la transacción. Se tiene que llamar a
[[yii\db\Transaction::setIsolationLevel()]] después de que la transacción haya empezado.
[isolation levels]: https://en.wikipedia.org/wiki/Isolation_%28database_systems%29#Isolation_levels
[isolation levels]: http://en.wikipedia.org/wiki/Isolation_%28database_systems%29#Isolation_levels
### Transacciones Anidadas <span id="nesting-transactions"></span>
@ -437,7 +437,7 @@ try {
## Replicación y División Lectura-Escritura <span id="read-write-splitting"></span>
Muchos DBMS soportan [replicación de bases de datos](https://en.wikipedia.org/wiki/Replication_(computing)#Database_replication) para tener
Muchos DBMS soportan [replicación de bases de datos](http://en.wikipedia.org/wiki/Replication_(computing)#Database_replication) para tener
una mejor disponibilidad de la base de datos y un mejor tiempo de respuesta del servidor. Con la replicación de bases
de datos, los datos están replicados en los llamados *servidores maestros* (master servers) y *servidores esclavos*
(slave servers). Todas las escrituras y actualizaciones deben hacerse en el servidor maestro, mientras que las lecturas

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

@ -1,939 +0,0 @@
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#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_table` o `drop_xxx_table` 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_table
```
esto genera
```php
/**
* Handles the creation for table `post`.
*/
class m150811_220037_create_post_table 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_table --fields="title:string,body:text"
```
genera
```php
/**
* Handles the creation for table `post`.
*/
class m150811_220037_create_post_table 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_table --fields="title:string(12):notNull:unique,body:text"
```
genera
```php
/**
* Handles the creation for table `post`.
*/
class m150811_220037_create_post_table 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_table --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_table 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_table --fields="title:string(12):notNull:unique,body:text"
```
genera
```php
class m150811_220037_drop_post_table 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_column_to_yyy_table` entonces el archivo generado contendrá
las declaraciones `addColumn` y `dropColumn` necesarias.
Para agregar una columna:
```php
yii migrate/create add_position_column_to_post_table --fields="position:integer"
```
genera
```php
class m150811_220037_add_position_column_to_post_table 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_column_from_yyy_table` entonces el archivo generado contendrá
las declaraciones `addColumn` y `dropColumn` necesarias.
```php
yii migrate/create drop_position_column_from_post_table --fields="position:integer"
```
genera
```php
class m150811_220037_drop_position_column_from_post_table 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_table_for_xxx_and_yyy_tables` entonces se generará el código necesario
para una tabla de unión.
```php
yii migrate/create create_junction_table_for_post_and_tag_tables --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_table_for_post_and_tag_tables 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](https://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/createTableMigration.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.

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

@ -241,7 +241,7 @@ El operando puede ser uno de los siguientes (ver también [[yii\db\QueryInterfac
automáticamente entre un par de caracteres de porcentaje.
> Note: Cuando se usa PostgreSQL también se puede usar
[`ilike`](https://www.postgresql.org/docs/8.3/static/functions-matching.html#FUNCTIONS-LIKE) en lugar de `like` para
[`ilike`](http://www.postgresql.org/docs/8.3/static/functions-matching.html#FUNCTIONS-LIKE) en lugar de `like` para
filtrar resultados insensibles a mayúsculas (case-insensitive).
- `or like`: similar al operando `like` exceptuando que se usa `OR` para concatenar los predicados `LIKE` cuando haya

67
docs/guide-es/glossary.md

@ -1,67 +0,0 @@
# 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](https://www.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.

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

@ -1,7 +1,7 @@
ArrayHelper
===========
Adicionalmente al [rico conjunto de funciones para arrays de PHP](https://www.php.net/manual/es/book.array.php), el array helper de Yii proporciona
Adicionalmente al [rico conjunto de funciones para arrays de PHP](http://php.net/manual/es/book.array.php) Yii array helper proporciona
métodos estáticos adicionales permitiendo trabajar con arrays de manera más eficiente.
@ -66,7 +66,7 @@ Después de ejecutar el código el `$array` contendrá `['options' => [1, 2]]` y
## Comprobando la Existencia de Claves <span id="checking-existence-of-keys"></span>
`ArrayHelper::keyExists` funciona de la misma manera que [array_key_exists](https://www.php.net/manual/es/function.array-key-exists.php)
`ArrayHelper::keyExists` funciona de la misma manera que [array_key_exists](http://php.net/manual/es/function.array-key-exists.php)
excepto que también soporta case-insensitive para la comparación de claves. Por ejemplo,
```php
@ -109,94 +109,30 @@ $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 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.
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.
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:
Si el valor de la clave es null, el correspondiente elemento del array será desechado y no se pondrá en el resultado. Por ejemplo,
```php
$array = [
['id' => '123', 'data' => 'abc', 'device' => 'laptop'],
['id' => '345', 'data' => 'def', 'device' => 'tablet'],
['id' => '345', 'data' => 'hgi', 'device' => 'smartphone'],
['id' => '123', 'data' => 'abc'],
['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.
$result = ArrayHelper::index($array, 'id');
// el resultado es:
// [
// '123' => ['id' => '123', 'data' => 'abc'],
// '345' => ['id' => '345', 'data' => 'def'],
// ]
```php
// usando función anónima
$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>
@ -270,7 +206,7 @@ El tercer argumento es la dirección. En caso de ordenar por una clave podría s
direcciones de ordenación.
El último argumento es un PHP sort flag que toma los mismos valores que los pasados a
PHP [sort()](https://www.php.net/manual/es/function.sort.php).
PHP [sort()](http://php.net/manual/es/function.sort.php).
## Detectando Tipos de Array <span id="detecting-array-types"></span>
@ -305,17 +241,17 @@ La codificación utilizará el charset de la aplicación y podría ser cambiado
```php
/**
* 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)
* 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.)
*/
public static function merge($a, $b)
```
@ -323,12 +259,13 @@ La codificación utilizará el charset de la aplicación y podría ser cambiado
## 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($posts, [
$data = ArrayHelper::toArray($post, [
'app\models\Post' => [
'id',
'title',
@ -365,23 +302,3 @@ 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\helpers\ArrayHelper]] provee [[yii\helpers\ArrayHelper::isIn()|isIn()]]
y [[yii\helpers\ArrayHelper::isSubset()|isSubset()]] con la misma firma del método
[in_array()](https://www.php.net/manual/en/function.in-array.php).
```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'])
```

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

@ -3,7 +3,7 @@ Clase auxiliar Html (Html helper)
Todas las aplicaciones web generan grandes cantidades de marcado HTML (HTML markup). Si el marcado es estático, se
puede realizar de forma efectiva
[mezclando PHP y HTML en un mismo archivo](https://www.php.net/manual/es/language.basic-syntax.phpmode.php) pero cuando se
[mezclando PHP y HTML en un mismo archivo](http://php.net/manual/es/language.basic-syntax.phpmode.php) pero cuando se
generan dinámicamente empieza a complicarse su gestión sin ayuda extra. Yii ofrece esta ayuda en forma de una clase auxiliar Html
que proporciona un conjunto de métodos estáticos para gestionar las etiquetas HTML más comúnmente usadas, sus opciones y contenidos.
@ -45,7 +45,7 @@ gestión adicional que se debe conocer:
- Si un valor es `null`, el correspondiente atributo no se renderizará.
- Los atributos cuyos valores son de tipo booleano serán tratados como
[atributos booleanos](https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#boolean-attributes).
[atributos booleanos](http://www.w3.org/TR/html5/infrastructure.html#boolean-attributes).
- Los valores de los atributos se codificarán en HTML usando [[yii\helpers\Html::encode()|Html::encode()]].
- El atributo "data" puede recibir un array. En este caso, se "expandirá" y se renderizará una lista de atributos
`data` ej. `'data' => ['id' => 1, 'name' => 'yii']` se convierte en `data-id="1" data-name="yii"`.
@ -96,8 +96,8 @@ eliminara una propiedad, se puede especificar como una cadena de texto.
Para que el contenido se muestre correctamente y de forma segura con caracteres especiales HTML el contenido debe ser
codificado. En PHP esto se hace con [htmlspecialchars](https://www.php.net/manual/es/function.htmlspecialchars.php) y
[htmlspecialchars_decode](https://www.php.net/manual/es/function.htmlspecialchars-decode.php). El problema con el uso
codificado. En PHP esto se hace con [htmlspecialchars](http://www.php.net/manual/es/function.htmlspecialchars.php) y
[htmlspecialchars_decode](http://www.php.net/manual/es/function.htmlspecialchars-decode.php). El problema con el uso
de estos métodos directamente es que se tiene que especificar la codificación y opciones extra cada vez. Ya que las
opciones siempre son las mismas y la codificación debe coincidir con la de la aplicación para prevenir problemas de
seguridad, Yii proporciona dos métodos simples y compactos:

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 comúnes <span id="getting-common-urls"></span>
Obtener URLs Comunes
--------------------
Se pueden usar dos métodos para obtener URLs comunes: URL de inicio (home URL) y URL base (base URL) de la petición
(request) actual. Para obtener la URL de inicio se puede usar el siguiente código:
@ -15,7 +15,7 @@ $absoluteHomeUrl = Url::home(true);
$httpsAbsoluteHomeUrl = Url::home('https');
```
Si no se pasan parámetros, la URL generada es relativa. Se puede pasar `true`para obtener la URL absoluta del
Si no se pasan parámetros, las URLs generadas son relativas. Se puede pasar `true`para obtener la URL absoluta del
esquema actual o especificar el esquema explícitamente (`https`, `http`).
Para obtener la URL base de la petición actual, se puede usar el siguiente código:
@ -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
----------------
## 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:
Para crear una URL para una ruta determinada se puede usar `Url::toRoute()`. El metodo utiliza [[\yii\web\UrlManager]]
para crear una URL:
```php
$url = Url::toRoute(['product/view', 'id' => 42]);
@ -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%2Findex&param1=value1&param2=value2
// genera: /index.php?r=site/index&param1=value1&param2=value2
['site/index', 'param1' => 'value1', 'param2' => 'value2']
```
@ -53,8 +53,9 @@ 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 reglas:
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:
- 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
@ -62,26 +63,19 @@ no la tiene (ej. `site/index` o `index`). Una ruta relativa se convertirá en un
- 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.php?r=site%2Findex
// /index?r=site/index
echo Url::toRoute('site/index');
// /index.php?r=site%2Findex&src=ref1#name
// /index?r=site/index&src=ref1#name
echo Url::toRoute(['site/index', 'src' => 'ref1', '#' => 'name']);
// /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
// http://www.example.com/index.php?r=site/index
echo Url::toRoute('site/index', true);
// https://www.example.com/index.php?r=site%2Findex
// https://www.example.com/index.php?r=site/index
echo Url::toRoute('site/index', 'https');
```
@ -105,16 +99,13 @@ el especificado.
A continuación se muestran algunos ejemplos de uso:
```php
// /index.php?r=site%2Findex
// /index?r=site/index
echo Url::to(['site/index']);
// /index.php?r=site%2Findex&src=ref1#name
// /index?r=site/index&src=ref1#name
echo Url::to(['site/index', 'src' => 'ref1', '#' => 'name']);
// /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
// la URL solicitada actualmente
echo Url::to();
// /images/logo.gif
@ -130,24 +121,8 @@ echo Url::to('@web/images/logo.gif', true);
echo Url::to('@web/images/logo.gif', 'https');
```
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>
Recordar la URL para utilizarla más adelante
--------------------------------------------
Hay casos en que se necesita recordar la URL y después usarla durante el procesamiento de una de las peticiones
secuenciales. Se puede logar de la siguiente manera:
@ -170,9 +145,11 @@ $url = Url::previous();
$productUrl = Url::previous('product');
```
## Chequear URLs relativas <span id="checking-relative-urls"></span>
Reconocer la relatividad de URLs
--------------------------------
Para descubrir si una URL es relativa, es decir, que no contenga información del host, se puede utilizar el siguiente código:
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

@ -1,527 +0,0 @@
<?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.

Before

Width:  |  Height:  |  Size: 31 KiB

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

@ -1,368 +0,0 @@
<?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.

Before

Width:  |  Height:  |  Size: 19 KiB

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

@ -1,368 +0,0 @@
<?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.

Before

Width:  |  Height:  |  Size: 19 KiB

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

@ -1,368 +0,0 @@
<?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.

Before

Width:  |  Height:  |  Size: 19 KiB

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

@ -1,312 +0,0 @@
<?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.

Before

Width:  |  Height:  |  Size: 16 KiB

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

@ -1,368 +0,0 @@
<?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.

Before

Width:  |  Height:  |  Size: 18 KiB

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

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

@ -1,208 +0,0 @@
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\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`](https://www.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]);
}
}
```

85
docs/guide-es/input-multiple-models.md

@ -1,85 +0,0 @@
Obtención de datos para los modelos de múltiples
================================
Cuando se trata de algunos datos complejos, es posible que puede que tenga que utilizar varios modelos diferentes para recopilar
la entrada del usuario. Por ejemplo, suponiendo que la información de inicio de sesión del usuario se almacena en la tabla `user`,
mientras que el perfil de usuario la información se almacena en la tabla `Profile`, es posible que desee para recoger los datos
de entrada sobre un usuario a través de un modelo `User` y un modelo `Profile`. Con el modelo de Yii y apoyo formulario,
puede solucionar este problema de una manera que no es mucho diferente de la manipulación de un solo modelo.
En lo que sigue, vamos a mostrar cómo se puede crear un formulario que permitirá recoger datos tanto para los modelos `User` y
`Profile`.
En primer lugar, la acción del controlador para la recogida de los datos del usuario y del perfil se puede escribir de la
siguiente manera,
```php
namespace app\controllers;
use Yii;
use yii\base\Model;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use app\models\User;
use app\models\Profile;
class UserController extends Controller
{
public function actionUpdate($id)
{
$user = User::findOne($id);
if (!$user) {
throw new NotFoundHttpException("The user was not found.");
}
$profile = Profile::findOne($user->profile_id);
if (!$profile) {
throw new NotFoundHttpException("The user has no profile.");
}
$user->scenario = 'update';
$profile->scenario = 'update';
if ($user->load(Yii::$app->request->post()) && $profile->load(Yii::$app->request->post())) {
$isValid = $user->validate();
$isValid = $profile->validate() && $isValid;
if ($isValid) {
$user->save(false);
$profile->save(false);
return $this->redirect(['user/view', 'id' => $id]);
}
}
return $this->render('update', [
'user' => $user,
'profile' => $profile,
]);
}
}
```
En la acción `update`, primero cargamos los modelos `User` y `Profile` que se actualicen desde la base de datos. Luego llamamos
[[yii\base\Model::load()]] para llenar estos dos modelos con la entrada del usuario. Si tiene éxito, se validará
los dos modelos y guardarlos. De lo contrario vamos a renderizar la vista `update` que tiene el siguiente contenido:
```php
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
$form = ActiveForm::begin([
'id' => 'user-update-form',
'options' => ['class' => 'form-horizontal'],
]) ?>
<?= $form->field($user, 'username') ?>
...other input fields...
<?= $form->field($profile, 'website') ?>
<?= Html::submitButton('Update', ['class' => 'btn btn-primary']) ?>
<?php ActiveForm::end() ?>
```
Como se puede ver, en el `update` vista que haría que los campos de entrada utilizando dos modelos `User` y `Profile`.

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

@ -1,715 +0,0 @@
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 bool 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::class],
['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](https://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.

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

@ -1,5 +1,5 @@
Actualizar desde Yii 1.1
========================
Actualizando 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,8 +18,7 @@ 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
@ -29,15 +28,15 @@ Yii 2.0 requiere PHP 5.4 o mayor, lo que es un gran progreso ya que Yii 1.1 func
Como resultado, hay muchas diferencias a nivel del lenguaje a las que deberías prestar atención.
Abajo hay un resumen de los mayores cambios en relación a PHP:
- [Namespaces](https://www.php.net/manual/es/language.namespaces.php).
- [Funciones anónimas](https://www.php.net/manual/es/functions.anonymous.php).
- [Namespaces](http://php.net/manual/es/language.namespaces.php).
- [Funciones anónimas](http://php.net/manual/es/functions.anonymous.php).
- La sintaxis corta de Arrays `[...elementos...]` es utilizada en vez de `array(...elementos...)`.
- Etiquetas cortas de `echo`. Ahora en las vistas se usa `<?=`. Esto se puede utilizar desde PHP 5.4.
- [SPL - Biblioteca estándar de PHP](https://www.php.net/manual/es/book.spl.php).
- [Enlace estático en tiempo de ejecución](https://www.php.net/manual/es/language.oop5.late-static-bindings.php).
- [Fecha y Hora](https://www.php.net/manual/es/book.datetime.php).
- [Traits](https://www.php.net/manual/es/language.oop5.traits.php).
- [intl](https://www.php.net/manual/es/book.intl.php). Yii 2.0 utiliza la extensión `intl` de PHP
- [SPL - Biblioteca estándar de PHP](http://php.net/manual/es/book.spl.php).
- [Enlace estático en tiempo de ejecución](http://php.net/manual/es/language.oop5.late-static-bindings.php).
- [Fecha y Hora](http://php.net/manual/es/book.datetime.php).
- [Traits](http://php.net/manual/es/language.oop5.traits.php).
- [intl](http://php.net/manual/es/book.intl.php). Yii 2.0 utiliza la extensión `intl` de PHP
como soporte para internacionalización.
@ -56,25 +55,25 @@ al autoloader de Yii.)
Componentes y Objetos
----------------------
Yii 2.0 parte la clase `CComponent` de 1.1 en dos clases: [[yii\base\BaseObject]] y [[yii\base\Component]].
La clase [[yii\base\BaseObject|BaseObject]] es una clase base que permite definir [propiedades de object](concept-properties.md)
a través de getters y setters. La clase [[yii\base\Component|Component]] extiende de [[yii\base\BaseObject|BaseObject]] y soporta
Yii 2.0 parte la clase `CComponent` de 1.1 en dos clases: [[yii\base\Object]] y [[yii\base\Component]].
La clase [[yii\base\Object|Object]] es una clase base que permite definir [propiedades de object](concept-properties.md)
a través de getters y setters. La clase [[yii\base\Component|Component]] extiende de [[yii\base\Object|Object]] y soporta
[eventos](concept-events.md) y [comportamientos](concept-behaviors.md).
Si tu clase no necesita utilizar las características de eventos o comportamientos, puedes considerar usar
[[yii\base\BaseObject|BaseObject]] como clase base. Esto es frecuente en el caso de que las clases que representan sean
[[yii\base\Object|Object]] como clase base. Esto es frecuente en el caso de que las clases que representan sean
estructuras de datos básicas.
Configuración de objetos
------------------------
La clase [[yii\base\BaseObject|BaseObject]] introduce una manera uniforme de configurar objetos. Cualquier clase descendiente
de [[yii\base\BaseObject|BaseObject]] debería declarar su constructor (si fuera necesario) de la siguiente manera para que
La clase [[yii\base\Object|Object]] introduce una manera uniforme de configurar objetos. Cualquier clase descendiente
de [[yii\base\Object|Object]] debería declarar su constructor (si fuera necesario) de la siguiente manera para que
puede ser adecuadamente configurado:
```php
class MyClass extends \yii\base\BaseObject
class MyClass extends \yii\base\Object
{
public function __construct($param1, $param2, $config = [])
{
@ -94,7 +93,7 @@ class MyClass extends \yii\base\BaseObject
En el ejemplo de arriba, el último parámetro del constructor debe tomar un array de configuración que
contiene pares clave-valor para la inicialización de las propiedades al final del mismo.
Puedes sobrescribir el método [[yii\base\BaseObject::init()|init()]] para realizar el trabajo de inicialización
Puedes sobrescribir el método [[yii\base\Object::init()|init()]] para realizar el trabajo de inicialización
que debe ser hecho después de que la configuración haya sido aplicada.
Siguiendo esa convención, podrás crear y configurar nuevos objetos utilizando
@ -108,7 +107,7 @@ $object = Yii::createObject([
], [$param1, $param2]);
```
Se puede encontrar más detalles acerca del tema en la sección [Configuración](concept-configurations.md).
Se puede encontrar más detalles acerca del tema en la sección [Configuración de objetos](concept-configurations.md).
Eventos
@ -143,7 +142,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 autoloader de Yii sin otra configuración.
por cada namespace raíz, y así poder utilizar el autolader 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
@ -156,12 +155,15 @@ 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]);
@ -170,8 +172,7 @@ 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
@ -291,7 +292,7 @@ Por favor consulta la sección [Comandos de Consola](tutorial-console.md) para m
I18N
----
Yii 2.0 remueve el formateador de fecha y números previamente incluido en favor del [módulo de PHP PECL intl](https://pecl.php.net/package/intl).
Yii 2.0 remueve el formateador de fecha y números previamente incluido en favor del [módulo de PHP PECL intl](http://pecl.php.net/package/intl).
La traducción de mensajes ahora es ejecutada vía el componente `i18n` de la aplicación.
Este componente maneja un grupo de mensajes origen, lo que te permite utilizar diferentes mensajes
@ -430,7 +431,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 'sobre la marcha' con una condición personalizada:
código para realizar una consulta relacional 'al-vuelo' con una condición personalizada:
```php
$orders = $customer->getOrders()->andWhere('status=1')->all();
@ -503,10 +504,9 @@ 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.
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.
La plantilla de Aplicación Avanzada provee un ejemplo así.
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,14 +526,8 @@ 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.
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
-----------------------------
Utilizando 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).

44
docs/guide-es/intro-yii.md

@ -2,8 +2,8 @@
============
Yii es un framework de PHP de alto rendimiento, basado en componentes para desarrollar aplicaciones web
modernas en poco tiempo. El nombre Yii significa "simple y evolutivo" en chino. También se puede considerar como el acrónimo
de _**Yes It Is**_ (que en inglés significa _**Sí, lo es**_)!
modernas en poco tiempo. El nombre Yii significa "simple y evolutivo" en chino. También se puede considerar como un acrónimo
de _**Yes It Is**_ (que en inglés significa _**Sí, eso es**_)!
¿En qué es mejor Yii?
@ -11,33 +11,25 @@ de _**Yes It Is**_ (que en inglés significa _**Sí, lo es**_)!
Yii es un framework genérico de programación web, lo que significa que se puede utilizar para desarrollar todo tipo de aplicaciones web en PHP.
Debido a su arquitectura basada en componentes y a su sofisticada compatibilidad de caché, es especialmente apropiado para el desarrollo
de aplicaciones de gran envergadura, como páginas web, foros, sistemas de gestión de contenidos (CMS), proyectos de comercio electrónico,
servicios web compatibles con la arquitectura REST y muchos más.
de aplicaciones de gran envergadura, como portales, foros, sistemas de gestión de contenidos (CMS), proyectos de comercio electrónico,
servicios web compatibles con la arquitectura REST y muchas más.
¿Cómo se compara Yii con otros frameworks?
--------------------------------------
Si estás ya familiarizado con otros framework, puedes apreciar como se compara Yii con ellos:
- Como la mayoría de los framework de PHP, Yii implementa el patrón de diseño MVC (Modelo-Vista-Controlador) y
promueve la organización de código basada en este patrón.
- La filosofía de Yii consiste en escribir el código de manera simple y elegante, sin sobrediseñar nunca por el
mero hecho de seguir un patrón de diseño determinado.
- Yii es un framework completo (full stack) que provee muchas características probadas y listas para usar, como los
constructores de consultas y la clase ActiveRecord para las bases de datos relacionales y NoSQL,
la compatibilidad con la arquitectura REST para desarrollar API, la compatibilidad de caché en varios niveles
y muchas más.
- Yii es extremadamente extensible. Puedes personalizar o reemplazar prácticamente cualquier pieza de código de base,
como se puede también aprovechar su sólida arquitectura de extensiones para utilizar o desarrollar extensiones distribuibles.
Si estás familiarizado con otros framework, puedes apreciar como se compara Yii con ellos:
- Como la mayoría de los framework de PHP, Yii implementa el patrón de diseño MVC (Modelo-Vista-Controlador) y promueve la organización de código basada en este patrón.
- La filosofía de Yii consiste en escribir el código de manera simple y elegante, sin sobrediseñar nunca por el mero hecho de seguir un patrón de diseño determinado.
- Yii es un framework completo que provee muchas características probadas y listas para usar, como los constructores de consultas y la clase ActiveRecord para las bases de datos relacionales y NoSQL, la compatibilidad con la arquitectura REST para desarrollar API, la compatibilidad de caché en varios niveles y muchas más.
- Yii es extremadamente extensible. Puedes personalizar o reemplazar prácticamente cualquier pieza de código de base, como se puede también aprovechar su sólida arquitectura de extensiones para utilizar o desarrollar extensiones distribuibles.
- El alto rendimiento es siempre la meta principal de Yii.
Yii no es un proyecto de un sola persona, detrás de Yii hay un [sólido equipo de desarrollo](https://www.yiiframework.com/team/),
así como una gran comunidad en la que numerosos profesionales contribuyen constantemente a su desarrollo.
Yii no es un proyecto de un sola persona, detrás de Yii hay un [sólido equipo de desarrollo][about_yii], así como una gran comunidad en la que numerosos profesionales contribuyen constantemente a su desarrollo.
El equipo de desarrollo de Yii se mantiene atento a las últimas tendencias de desarrollo web, así como a las mejores prácticas y características de otros frameworks y proyectos.
Las buenas prácticas y características más relevantes de otros proyectos se incorporan regularmente a la base del framework y se exponen a través de interfaces simples y elegantes.
[about_yii]: https://www.yiiframework.com/about/
[about_yii]: http://www.yiiframework.com/about/
Versiones de Yii
----------------
@ -48,13 +40,13 @@ La versión 2.0 representa la actual generación del framework y su desarrollo r
Esta guía está basada principalmente en la versión 2.0. del framework.
Requisitos y Prerequisitos
--------------------------
Requisitos
-----------
Yii 2.0 requiere PHP 5.4.0 o una versión posterior y corre de mejor manera en la última versión de PHP 7. Se pueden encontrar requisitos más detallados de características individuales
ejecutando el script de comprobación incluido en cada lanzamiento de Yii.
Yii 2.0 requiere PHP 5.4.0 o una versión posterior. Se pueden encontrar requisitos más detallados de características individuales
ejecutando el script de comprobación incluido en cada release de Yii.
Para utilizar Yii se requieren conocimientos básicos de programación orientada a objetos (POO), porque el framework Yii se basa íntegramente en esta tecnología.
Yii 2.0 hace uso también de las últimas características de PHP, como [namespaces](https://www.php.net/manual/es/language.namespaces.php)
y [traits](https://www.php.net/manual/es/language.oop5.traits.php). Comprender estos conceptos te ayudará a entender mejor Yii 2.0.
Yii 2.0 hace uso también de las últimas características de PHP, como [namespaces](http://www.php.net/manual/es/language.namespaces.php)
y [traits](http://www.php.net/manual/es/language.oop5.traits.php). Comprender estos conceptos te ayudará a entender mejor Yii 2.0.

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

@ -1,98 +0,0 @@
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::class]]);
```
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::class],
'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.

421
docs/guide-es/output-data-providers.md

@ -1,421 +0,0 @@
Proveedores de datos
====================
En las secciones sobre [paginación](output-pagination.md) y [ordenación](output-sorting.md) se
describe como permitir a los usuarios finales elegir que se muestre una página de datos en
particular, y ordenar los datos por algunas columnas. Como la tarea de paginar y ordenar datos
es muy común, Yii proporciona un conjunto de clases *proveedoras de datos* para encapsularla.
Un proveedor de datos es una clase que implementa la interfaz [[yii\data\DataProviderInterface]].
Básicamente se encarga de obtener datos paginados y ordenados. Normalmente se usa junto con
[_widgets_ de datos](output-data-widgets.md) para que los usuarios finales puedan paginar y
ordenar datos de forma interactiva.
Yii incluye las siguientes clases proveedoras de datos:
* [[yii\data\ActiveDataProvider]]: usa [[yii\db\Query]] o [[yii\db\ActiveQuery]] para consultar datos de bases de datos y devolverlos como _arrays_ o instancias [Active Record](db-active-record.md).
* [[yii\data\SqlDataProvider]]: ejecuta una sentencia SQL y devuelve los datos de la base de datos como _arrays_.
* [[yii\data\ArrayDataProvider]]: toma un _array_ grande y devuelve una rodaja de él basándose en las especificaciones de paginación y ordenación.
El uso de todos estos proveedores de datos comparte el siguiente patrón común:
```php
// Crear el proveedor de datos configurando sus propiedades de paginación y ordenación
$provider = new XyzDataProvider([
'pagination' => [...],
'sort' => [...],
]);
// Obtener los datos paginados y ordenados
$models = $provider->getModels();
// Obtener el número de elementos de la página actual
$count = $provider->getCount();
// Obtener el número total de elementos entre todas las páginas
$totalCount = $provider->getTotalCount();
```
Se puede especificar los comportamientos de paginación y ordenación de un proveedor de datos
configurando sus propiedades [[yii\data\BaseDataProvider::pagination|pagination]] y
[[yii\data\BaseDataProvider::sort|sort]], que corresponden a las configuraciones para
[[yii\data\Pagination]] y [[yii\data\Sort]] respectivamente. También se pueden configurar a
`false` para inhabilitar las funciones de paginación y/u ordenación.
Los [_widgets_ de datos](output-data-widgets.md), como [[yii\grid\GridView]], tienen una
propiedad llamada `dataProvider` que puede tomar una instancia de un proveedor de datos y
mostrar los datos que proporciona. Por ejemplo,
```php
echo yii\grid\GridView::widget([
'dataProvider' => $dataProvider,
]);
```
Estos proveedores de datos varían principalmente en la manera en que se especifica la fuente de
datos. En las siguientes secciones se explica el uso detallado de cada uno de estos proveedores
de datos.
## Proveedor de datos activo <span id="active-data-provider"></span>
Para usar [[yii\data\ActiveDataProvider]], hay que configurar su propiedad
[[yii\data\ActiveDataProvider::query|query]].
Puede tomar un objeto [[yii\db\Query] o [[yii\db\ActiveQuery]]. En el primer caso, los datos
devueltos serán _arrays_. En el segundo, los datos devueltos pueden ser _arrays_ o instancias de
[Active Record](db-active-record.md). Por ejemplo:
```php
use yii\data\ActiveDataProvider;
$query = Post::find()->where(['state_id' => 1]);
$provider = new ActiveDataProvider([
'query' => $query,
'pagination' => [
'pageSize' => 10,
],
'sort' => [
'defaultOrder' => [
'created_at' => SORT_DESC,
'title' => SORT_ASC,
]
],
]);
// Devuelve un array de objetos Post
$posts = $provider->getModels();
```
En el ejemplo anterior, si `$query` se crea el siguiente código, el proveedor de datos
devolverá _arrays_ en bruto.
```php
use yii\db\Query;
$query = (new Query())->from('post')->where(['state' => 1]);
```
> Note: Si una consulta ya tiene la cláusula `orderBy`, las nuevas instrucciones de ordenación
dadas por los usuarios finales (mediante la configuración de `sort`) se añadirán a la cláusula
`orderBy` previa. Las cláusulas `limit` y `offset` que pueda haber se sobrescribirán por la
petición de paginación de los usuarios finales (mediante la configuración de `pagination`).
Por omisión, [[yii\data\ActiveDataProvider]] usa el componente `db` de la aplicación como
conexión con la base de datos. Se puede indicar una conexión con base de datos diferente
configurando la propiedad [[yii\data\ActiveDataProvider::db]].
## Proveedor de datos SQL <span id="sql-data-provider"></span>
[[yii\data\SqlDataProvider]] funciona con una sentencia SQL en bruto, que se usa para obtener
los datos requeridos.
Basándose en las especificaciones de [[yii\data\SqlDataProvider::sort|sort]] y
[[yii\data\SqlDataProvider::pagination|pagination]], el proveedor ajustará las cláusulas
`ORDER BY` y `LIMIT` de la sentencia SQL acordemente para obtener sólo la página de datos
solicitados en el orden deseado.
Para usar [[yii\data\SqlDataProvider]], hay que especificar las propiedades
[[yii\data\SqlDataProvider::sql|sql]] y [[yii\data\SqlDataProvider::totalCount|totalCount]].
Por ejemplo:
```php
use yii\data\SqlDataProvider;
$count = Yii::$app->db->createCommand('
SELECT COUNT(*) FROM post WHERE status=:status
', [':status' => 1])->queryScalar();
$provider = new SqlDataProvider([
'sql' => 'SELECT * FROM post WHERE status=:status',
'params' => [':status' => 1],
'totalCount' => $count,
'pagination' => [
'pageSize' => 10,
],
'sort' => [
'attributes' => [
'title',
'view_count',
'created_at',
],
],
]);
// Devuelve un array de filas de datos
$models = $provider->getModels();
```
> Info: La propiedad [[yii\data\SqlDataProvider::totalCount|totalCount]] se requiere sólo si se
necesita paginar los datos. Esto es porque el proveedor modificará la sentencia SQL
especificada vía [[yii\data\SqlDataProvider::sql|sql]] para que devuelva sólo la pagina de
datos solicitada. El proveedor sigue necesitando saber el número total de elementos de datos
para calcular correctamente el número de páginas.
## Proveedor de datos de _arrays_ <span id="array-data-provider"></span>
Se recomienda usar [[yii\data\ArrayDataProvider]] cuando se trabaja con un _array_ grande.
El proveedor permite devolver una página de los datos del _array_ ordenados por una o varias
columnas. Para usar [[yii\data\ArrayDataProvider]], hay que especificar la propiedad
[[yii\data\ArrayDataProvider::allModels|allModels]] como el _array_ grande. Los elementos
del _array_ grande pueden ser _arrays_ asociativos (por ejemplo resultados de consultas de
[DAO](db-dao.md) u objetos (por ejemplo instancias de [Active Record](db-active-record.md).
Por ejemplo:
```php
use yii\data\ArrayDataProvider;
$data = [
['id' => 1, 'name' => 'name 1', ...],
['id' => 2, 'name' => 'name 2', ...],
...
['id' => 100, 'name' => 'name 100', ...],
];
$provider = new ArrayDataProvider([
'allModels' => $data,
'pagination' => [
'pageSize' => 10,
],
'sort' => [
'attributes' => ['id', 'name'],
],
]);
// Obtener las filas de la página solicitada
$rows = $provider->getModels();
```
> Note: En comparación con [Active Data Provider](#active-data-provider) y
[SQL Data Provider](#sql-data-provider), Array Data Provider es menos eficiente porque
requiere cargar *todos* los datos en memoria.
## Trabajar con las claves de los datos <span id="working-with-keys"></span>
Al utilizar los elementos de datos devueltos por un proveedor de datos, con frecuencia
necesita identificar cada elemento de datos con una clave única.
Por ejemplo, si los elementos de datos representan información de los clientes, puede querer
usar el ID de cliente como la clave de cada conjunto de datos de un cliente.
Los proveedores de datos pueden devolver una lista de estas claves correspondientes a los
elementos de datos devueltos por [[yii\data\DataProviderInterface::getModels()]].
Por ejemplo:
```php
use yii\data\ActiveDataProvider;
$query = Post::find()->where(['status' => 1]);
$provider = new ActiveDataProvider([
'query' => $query,
]);
// Devuelve un array de objetos Post
$posts = $provider->getModels();
// Devuelve los valores de las claves primarias correspondientes a $posts
$ids = $provider->getKeys();
```
En el ejemplo superior, como se le proporciona a [[yii\data\ActiveDataProvider]] un objeto
[[yii\db\ActiveQuery]], es lo suficientemente inteligente como para devolver los valores de
las claves primarias como las claves. También puede indicar explícitamente cómo se deben
calcular los valores de la clave configurando [[yii\data\ActiveDataProvider::key]] con un
nombre de columna o un invocable que calcule los valores de la clave. Por ejemplo:
```php
// Utiliza la columna «slug» como valores de la clave
$provider = new ActiveDataProvider([
'query' => Post::find(),
'key' => 'slug',
]);
// Utiliza el resultado de md5(id) como valores de la clave
$provider = new ActiveDataProvider([
'query' => Post::find(),
'key' => function ($model) {
return md5($model->id);
}
]);
```
## Creación de un proveedor de datos personalizado <span id="custom-data-provider"></span>
Para crear su propio proveedor de datos personalizado, debe implementar
[[yii\data\DataProviderInterface]].
Una manera más fácil es extender [[yii\data\BaseDataProvider]], que le permite centrarse
en la lógica central del proveedor de datos. En particular, esencialmente necesita
implementar los siguientes métodos:
- [[yii\data\BaseDataProvider::prepareModels()|prepareModels()]]: prepara los modelos
de datos que estarán disponibles en la página actual y los devuelve como un _array_.
- [[yii\data\BaseDataProvider::prepareKeys()|prepareKeys()]]: acepta un _array_ de
modelos de datos disponibles actualmente y devuelve las claves asociadas a ellos.
- [[yii\data\BaseDataProvider::prepareTotalCount()|prepareTotalCount]]: devuelve un valor
que indica el número total de modelos de datos en el proveedor de datos.
Debajo se muestra un ejemplo de un proveedor de datos que lee datos CSV eficientemente:
```php
<?php
use yii\data\BaseDataProvider;
class CsvDataProvider extends BaseDataProvider
{
/**
* @var string nombre del fichero CSV a leer
*/
public $filename;
/**
* @var string|callable nombre de la columna clave o un invocable que la devuelva
*/
public $key;
/**
* @var SplFileObject
*/
protected $fileObject; // SplFileObject es muy práctico para buscar una línea concreta en un fichero
/**
* {@inheritdoc}
*/
public function init()
{
parent::init();
// Abrir el fichero
$this->fileObject = new SplFileObject($this->filename);
}
/**
* {@inheritdoc}
*/
protected function prepareModels()
{
$models = [];
$pagination = $this->getPagination();
if ($pagination === false) {
// En caso de que no haya paginación, leer todas las líneas
while (!$this->fileObject->eof()) {
$models[] = $this->fileObject->fgetcsv();
$this->fileObject->next();
}
} else {
// En caso de que haya paginación, leer sólo una única página
$pagination->totalCount = $this->getTotalCount();
$this->fileObject->seek($pagination->getOffset());
$limit = $pagination->getLimit();
for ($count = 0; $count < $limit; ++$count) {
$models[] = $this->fileObject->fgetcsv();
$this->fileObject->next();
}
}
return $models;
}
/**
* {@inheritdoc}
*/
protected function prepareKeys($models)
{
if ($this->key !== null) {
$keys = [];
foreach ($models as $model) {
if (is_string($this->key)) {
$keys[] = $model[$this->key];
} else {
$keys[] = call_user_func($this->key, $model);
}
}
return $keys;
}
return array_keys($models);
}
/**
* {@inheritdoc}
*/
protected function prepareTotalCount()
{
$count = 0;
while (!$this->fileObject->eof()) {
$this->fileObject->next();
++$count;
}
return $count;
}
}
```
## Filtrar proveedores de datos usando filtros de datos <span id="filtering-data-providers-using-data-filters"></span>
Si bien puede construir condiciones para un proveedor de datos activo manualmente tal
y como se describe en las secciones [Filtering Data](output-data-widgets.md#filtering-data)
y [Separate Filter Form](output-data-widgets.md#separate-filter-form) de la guía de
_widgets_ de datos, Yii tiene filtros de datos que son muy útiles si necesita
condiciones de filtro flexibles. Los filtros de datos se pueden usar así:
```php
$filter = new ActiveDataFilter([
'searchModel' => 'app\models\PostSearch'
]);
$filterCondition = null;
// Puede cargar los filtros de datos de cualquier fuente.
// Por ejemplo, si prefiere JSON en el cuerpo de la petición,
// use Yii::$app->request->getBodyParams() aquí abajo:
if ($filter->load(\Yii::$app->request->get())) {
$filterCondition = $filter->build();
if ($filterCondition === false) {
// Serializer recibiría errores
return $filter;
}
}
$query = Post::find();
if ($filterCondition !== null) {
$query->andWhere($filterCondition);
}
return new ActiveDataProvider([
'query' => $query,
]);
```
El propósito del modelo `PostSearch` es definir por qué propiedades y valores se permite filtrar:
```php
use yii\base\Model;
class PostSearch extends Model
{
public $id;
public $title;
public function rules()
{
return [
['id', 'integer'],
['title', 'string', 'min' => 2, 'max' => 200],
];
}
}
```
Los filtros de datos son bastante flexibles. Puede personalizar cómo se construyen
las condiciones y qué operadores se permiten.
Para más detalles consulte la documentación de la API en [[\yii\data\DataFilter]].

245
docs/guide-es/output-data-widgets.md

@ -1,245 +0,0 @@
Widgets de datos
================
Yii proporciona un conjunto de [widgets](structure-widgets.md) que se pueden usar para mostrar datos.
Mientras que el _widget_ [DetailView](#detail-view) se puede usar para mostrar los datos de un único
registro, [ListView](#list-view) y [GridView](#grid-view) se pueden usar para mostrar una lista o
tabla de registros de datos proporcionando funcionalidades como paginación, ordenación y filtro.
DetailView <span id="detail-view"></span>
----------
El _widget_ [[yii\widgets\DetailView|DetailView]] muestra los detalles de un único
[[yii\widgets\DetailView::$model|modelo]] de datos.
Se recomienda su uso para mostrar un modelo en un formato estándar (por ejemplo, cada atributo del
modelo se muestra como una fila en una tabla). El modelo puede ser tanto una instancia o subclase
de [[\yii\base\Model]] como un [active record](db-active-record.md) o un _array_ asociativo.
DetailView usa la propiedad [[yii\widgets\DetailView::$attributes|$attributes]] para determinar
qué atributos del modelo se deben mostrar y cómo se deben formatear.
En la [sección sobre formateadores](output-formatting.html) se pueden ver las opciones de formato
disponibles.
Un uso típico de DetailView sería así:
```php
echo DetailView::widget([
'model' => $model,
'attributes' => [
'title', // atributo title (en texto plano)
'description:html', // atributo description formateado como HTML
[ // nombre del propietario del modelo
'label' => 'Owner',
'value' => $model->owner->name,
'contentOptions' => ['class' => 'bg-red'], // atributos HTML para personalizar el valor
'captionOptions' => ['tooltip' => 'Tooltip'], // atributos HTML para personalizar la etiqueta
],
'created_at:datetime', // fecha de creación formateada como datetime
],
]);
```
Recuerde que a diferencia de [[yii\widgets\GridView|GridView]], que procesa un conjunto de modelos,
[[yii\widgets\DetailView|DetailView]] sólo procesa uno. Así que la mayoría de las veces no hay
necesidad de usar funciones anónimas ya que `$model` es el único modelo a mostrar y está disponible
en la vista como una variable.
Sin embargo, en algunos casos el uso de una función anónima puede ser útil. Por ejemplo cuando
`visible` está especificado y se desea impedir el cálculo de `value` en case de que evalúe a `false`:
```php
echo DetailView::widget([
'model' => $model,
'attributes' => [
[
'attribute' => 'owner',
'value' => function ($model) {
return $model->owner->name;
},
'visible' => \Yii::$app->user->can('posts.owner.view'),
],
],
]);
```
ListView <span id="list-view"></span>
--------
El _widget_ [[yii\widgets\ListView|ListView]] se usa para mostrar datos de un
[proveedor de datos](output-data-providers.md).
Cada modelo de datos se representa usando el [[yii\widgets\ListView::$itemView|fichero de vista]]
indicado.
Como proporciona de serie funcionalidades tales como paginación, ordenación y filtro,
es útil tanto para mostrar información al usuario final como para crear una interfaz
de usuario de gestión de datos.
Un uso típico es el siguiente:
```php
use yii\widgets\ListView;
use yii\data\ActiveDataProvider;
$dataProvider = new ActiveDataProvider([
'query' => Post::find(),
'pagination' => [
'pageSize' => 20,
],
]);
echo ListView::widget([
'dataProvider' => $dataProvider,
'itemView' => '_post',
]);
```
El fichero de vista `_post` podría contener lo siguiente:
```php
<?php
use yii\helpers\Html;
use yii\helpers\HtmlPurifier;
?>
<div class="tarea">
<h2><?= Html::encode($model->title) ?></h2>
<?= HtmlPurifier::process($model->text) ?>
</div>
```
En el fichero de vista anterior, el modelo de datos actual está disponible como `$model`.
Además están disponibles las siguientes variables:
- `$key`: mixto, el valor de la clave asociada a este elemento de datos.
- `$index`: entero, el índice empezando por cero del elemento de datos en el array de elementos devuelto por el proveedor de datos.
- `$widget`: ListView, esta instancia del _widget_.
Si se necesita pasar datos adicionales a cada vista, se puede usar la propiedad
[[yii\widgets\ListView::$viewParams|$viewParams]] para pasar parejas clave-valor como las siguientes:
```php
echo ListView::widget([
'dataProvider' => $dataProvider,
'itemView' => '_post',
'viewParams' => [
'fullView' => true,
'context' => 'main-page',
// ...
],
]);
```
Entonces éstas también estarán disponibles en la vista como variables.
GridView <span id="grid-view"></span>
--------
La cuadrícula de datos o [[yii\grid\GridView|GridView]] es uno de los _widgets_ de Yii
más potentes. Es extremadamente útil si necesita construir rápidamente la sección de
administración del sistema. Recibe los datos de un [proveedor de datos](output-data-providers.md)
y representa cada fila usando un conjunto de [[yii\grid\GridView::columns|columnas]]
que presentan los datos en forma de tabla.
Cada fila de la tabla representa los datos de un único elemento de datos, y una columna
normalmente representa un atributo del elemento (algunas columnas pueden corresponder a
expresiones complejas de los atributos o a un texto estático).
El mínimo código necesario para usar GridView es como sigue:
```php
use yii\grid\GridView;
use yii\data\ActiveDataProvider;
$dataProvider = new ActiveDataProvider([
'query' => Post::find(),
'pagination' => [
'pageSize' => 20,
],
]);
echo GridView::widget([
'dataProvider' => $dataProvider,
]);
```
El código anterior primero crea un proveedor de datos y a continuación usa GridView
para mostrar cada atributo en cada fila tomados del proveedor de datos. La tabla
mostrada está equipada de serie con las funcionalidades de ordenación y paginación.
### Columnas de la cuadrícula <span id="grid-columns"></span>
Las columnas de la tabla se configuran en términos de clase [[yii\grid\Column]], que
se configuran en la propiedad [[yii\grid\GridView::columns|columns]] de la configuración
del GridView.
Dependiendo del tipo y ajustes de las columnas éstas pueden presentar los datos de
diferentes maneras.
La clase predefinida es [[yii\grid\DataColumn]], que representa un atributo del modelo
por el que se puede ordenar y filtrar.
```php
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
// Columnas sencillas definidas por los datos contenidos en $dataProvider.
// Se usarán los datos de la columna del modelo.
'id',
'username',
// Un ejemplo más complejo.
[
'class' => 'yii\grid\DataColumn', // Se puede omitir, ya que es la predefinida.
'value' => function ($data) {
return $data->name; // $data['name'] para datos de un array, por ejemplo al usar SqlDataProvider.
},
],
],
]);
```
Observe que si no se especifica la parte [[yii\grid\GridView::columns|columns]] de la
configuración, Yii intenta mostrar todas las columnas posibles del modelo del proveedor
de datos.
### Clases de columna <span id="column-classes"></span>
Las columnas de la cuadrícula se pueden personalizar usando diferentes clases de columna:
```php
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
[
'class' => 'yii\grid\SerialColumn', // <-- aquí
// puede configurar propiedades adicionales aquí
],
```
Además de las clases de columna proporcionadas por Yii que se revisarán más abajo,
puede crear sus propias clases de columna.
Cada clase de columna extiende [[yii\grid\Column]] de modo que hay algunas opciones
comunes que puede establecer al configurar las columnas de una cuadrícula.
- [[yii\grid\Column::header|header]] permite establecer el contenida para la fila cabecera
- [[yii\grid\Column::footer|footer]] permite establece el contenido de la fila al pie
- [[yii\grid\Column::visible|visible]] define si la columna debería ser visible.
- [[yii\grid\Column::content|content]] le permite pasar una función PHP válida que devuelva datos para una fila. El formato es el siguiente:
```php
function ($model, $key, $index, $column) {
return 'una cadena';
}
```
Puede indicar varias opciones HTML del contenedor pasando _arrays_ a:
- [[yii\grid\Column::headerOptions|headerOptions]]
- [[yii\grid\Column::footerOptions|footerOptions]]
- [[yii\grid\Column::filterOptions|filterOptions]]
- [[yii\grid\Column::contentOptions|contentOptions]]

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

@ -1,72 +0,0 @@
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.

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

@ -76,7 +76,7 @@ siguiente configuración para el componente vista, tema:
```
Con la configuración anterior, se puede crear una versión de la vista `@app/widgets/currency/index.php` para que se
aplique el tema en `@app/themes/basic/widgets/currency/views/index.php`.
aplique el tema en `@app/themes/basic/widgets/currency/index.php`.
Uso de Multiples Rutas
----------------------

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

@ -1,16 +1,14 @@
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, **la API de peticiones tiene que ser siempre enviado
vía HTTPS para prevenir ataques tipo "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, **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) **.
Hay muchas maneras de enviar una token (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
* [Autorización Básica HTTP](http://en.wikipedia.org/wiki/Basic_access_authentication): 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.,
@ -18,8 +16,7 @@ Hay muchas maneras de enviar una token (pieza) de acceso:
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](https://datatracker.ietf.org/doc/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.
@ -33,22 +30,21 @@ Para activar la autenticación para tus APIs, sigue los pasos siguientes:
3. Implementa [[yii\web\IdentityInterface::findIdentityByAccessToken()]] en tu [[yii\web\User::identityClass|clase de identidad de usuarios]].
El paso 1 no es necesario pero sí recomendable para las APIs RESTful, pues son sin estado (stateless).
Cuando [[yii\web\User::enableSession|enableSession]] es `false`, el estado de autenticación del usuario puede NO persistir entre peticiones usando sesiones.
Cuando [[yii\web\User::enableSession|enableSession]] es false, el estado de autenticación del usuario puede NO persistir entre peticiones usando sesiones.
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 (behavior) `authenticator` como sigue,
Por ejemplo, para usar HTTP Basic Auth, puedes configurar el comportamiento `authenticator` como sigue,
```php
use yii\filters\auth\HttpBasicAuth;
@ -57,7 +53,7 @@ public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['authenticator'] = [
'class' => HttpBasicAuth::class,
'class' => HttpBasicAuth::className(),
];
return $behaviors;
}
@ -75,11 +71,11 @@ public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['authenticator'] = [
'class' => CompositeAuth::class,
'class' => CompositeAuth::className(),
'authMethods' => [
HttpBasicAuth::class,
HttpBearerAuth::class,
QueryParamAuth::class,
HttpBasicAuth::className(),
HttpBearerAuth::className(),
QueryParamAuth::className(),
],
];
return $behaviors;
@ -112,16 +108,14 @@ 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\ActiveController::checkAccess()|checkAccess()]] para realizar la comprobación de la autorización.
el método [[yii\rest\Controller::checkAccess()|checkAccess()]] para realizar la comprobación de la autorización.
El método será llamado por las acciones contenidas en [[yii\rest\ActiveController]].

8
docs/guide-es/rest-controllers.md

@ -69,7 +69,7 @@ public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['authenticator'] = [
'class' => HttpBasicAuth::class,
'class' => HttpBasicAuth::className(),
];
return $behaviors;
}
@ -135,7 +135,7 @@ sobrescribiendo el método [[yii\rest\ActiveController::checkAccess()|checkAcces
* If the user does not have access, a [[ForbiddenHttpException]] should be thrown.
*
* @param string $action the ID of the action to be executed
* @param \yii\base\Model $model the model to be accessed. If `null`, it means no specific model is being accessed.
* @param \yii\base\Model $model the model to be accessed. If null, it means no specific model is being accessed.
* @param array $params additional parameters
* @throws ForbiddenHttpException if the user does not have access
*/
@ -143,10 +143,6 @@ public function checkAccess($action, $model = null, $params = [])
{
// check if the user can access $action and $model
// throw ForbiddenHttpException if access should be denied
if ($action === 'update' || $action === 'delete') {
if ($model->author_id !== \Yii::$app->user->id)
throw new \yii\web\ForbiddenHttpException(sprintf('You can only %s articles that you\'ve created.', $action));
}
}
```

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

@ -6,8 +6,7 @@ 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
@ -18,7 +17,7 @@ Content-Type: application/json; charset=UTF-8
{
"name": "Not Found Exception",
"message": "The requested resource was not found.",
"message": "El recurso solicitado no ha sido encontrado.",
"code": 0,
"status": 404
}
@ -27,23 +26,21 @@ 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, comprueba 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, comprobad 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.
## Personalizar la Respuesta al Error <span id="customizing-error-response"></span>
## Personalizando 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
@ -67,7 +64,7 @@ Content-Type: application/json; charset=UTF-8
}
```
Para lograrlo, puedes responder al evento `beforeSend` del componente `response` en la configuración de la aplicación:
Para lograr este objetivo, puedes responder al evento `beforeSend` del componente `response` en la configuración de la aplicación:
```php
return [
@ -77,7 +74,7 @@ return [
'class' => 'yii\web\Response',
'on beforeSend' => function ($event) {
$response = $event->sender;
if ($response->data !== null && Yii::$app->request->get('suppress_response_code')) {
if ($response->data !== null && !empty(Yii::$app->request->get['suppress_response_code'])) {
$response->data = [
'success' => $response->isSuccessful,
'data' => $response->data,

2
docs/guide-es/rest-quick-start.md

@ -9,7 +9,7 @@ En particular, Yii soporta las siguientes características sobre APIs RESTful;
* Formato de respuesta de negocio (soporta JSON y XML por defecto);
* Personalización de objetos serializados con soporte para campos de salida seleccionables;
* Formateo apropiado de colecciones de datos y validación de errores;
* Soporte para [HATEOAS](https://en.wikipedia.org/wiki/HATEOAS);
* Soporte para [HATEOAS](http://en.wikipedia.org/wiki/HATEOAS);
* Eficiente enrutamiento con una adecuada comprobación del verbo(verb) HTTP;
* Incorporado soporte para las `OPTIONS` y `HEAD` verbos;
* Autenticación y autorización;

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

Loading…
Cancel
Save