Browse Source

merge from a600e16

tags/2.0.16
cuileon 8 years ago
parent
commit
6bb0ddcb5b
  1. 24
      .codeclimate.yml
  2. 3
      .dockerignore
  3. 1
      .eslintignore
  4. 213
      .eslintrc
  5. 8
      .gitattributes
  6. 4
      .github/CONTRIBUTING.md
  7. 2
      .github/ISSUE_TEMPLATE.md
  8. 6
      .gitignore
  9. 118
      .gitlab-ci.yml
  10. 122
      .travis.yml
  11. 8
      Dockerfile
  12. 80
      README.md
  13. 14
      build/controllers/DevController.php
  14. 4
      build/controllers/MimeTypeController.php
  15. 46
      build/controllers/PhpDocController.php
  16. 176
      build/controllers/ReleaseController.php
  17. 4
      build/controllers/TranslationController.php
  18. 130
      build/controllers/Utf8Controller.php
  19. 4
      build/controllers/views/translation/report_html.php
  20. 71
      code-of-conduct.md
  21. 22
      composer.json
  22. 208
      composer.lock
  23. 58
      contrib/completion/bash/yii
  24. 38
      contrib/completion/zsh/_yii
  25. 30
      docs/documentation_style_guide.md
  26. 3
      docs/guide-de/translators.json
  27. 4
      docs/guide-es/caching-data.md
  28. 2
      docs/guide-es/caching-http.md
  29. 2
      docs/guide-es/concept-autoloading.md
  30. 4
      docs/guide-es/concept-events.md
  31. 6
      docs/guide-es/db-dao.md
  32. 54
      docs/guide-es/db-migrations.md
  33. 7
      docs/guide-es/helper-array.md
  34. 85
      docs/guide-es/input-multiple-models.md
  35. 23
      docs/guide-es/input-validation.md
  36. 2
      docs/guide-es/rest-authentication.md
  37. 6
      docs/guide-es/rest-controllers.md
  38. 2
      docs/guide-es/rest-rate-limiting.md
  39. 2
      docs/guide-es/rest-routing.md
  40. 2
      docs/guide-es/runtime-handling-errors.md
  41. 6
      docs/guide-es/runtime-routing.md
  42. 6
      docs/guide-es/runtime-sessions-cookies.md
  43. 20
      docs/guide-es/security-authorization.md
  44. 2
      docs/guide-es/start-installation.md
  45. 2
      docs/guide-es/structure-applications.md
  46. 6
      docs/guide-es/structure-extensions.md
  47. 2
      docs/guide-es/structure-models.md
  48. 8
      docs/guide-es/test-fixtures.md
  49. 6
      docs/guide-es/translators.json
  50. 60
      docs/guide-es/tutorial-core-validators.md
  51. 2
      docs/guide-es/tutorial-start-from-scratch.md
  52. 4
      docs/guide-es/tutorial-template-engines.md
  53. 2
      docs/guide-es/tutorial-yii-integration.md
  54. 6
      docs/guide-fr/blocktypes.json
  55. 345
      docs/guide-fr/caching-data.md
  56. 143
      docs/guide-fr/caching-fragment.md
  57. 108
      docs/guide-fr/caching-http.md
  58. 15
      docs/guide-fr/caching-overview.md
  59. 33
      docs/guide-fr/caching-page.md
  60. 85
      docs/guide-fr/concept-aliases.md
  61. 64
      docs/guide-fr/concept-autoloading.md
  62. 322
      docs/guide-fr/concept-behaviors.md
  63. 86
      docs/guide-fr/concept-components.md
  64. 230
      docs/guide-fr/concept-configurations.md
  65. 340
      docs/guide-fr/concept-di-container.md
  66. 319
      docs/guide-fr/concept-events.md
  67. 61
      docs/guide-fr/concept-properties.md
  68. 101
      docs/guide-fr/concept-service-locator.md
  69. 1294
      docs/guide-fr/db-active-record.md
  70. 562
      docs/guide-fr/db-dao.md
  71. 823
      docs/guide-fr/db-migrations.md
  72. 583
      docs/guide-fr/db-query-builder.md
  73. 404
      docs/guide-fr/helper-array.md
  74. 396
      docs/guide-fr/helper-html.md
  75. 68
      docs/guide-fr/helper-overview.md
  76. 161
      docs/guide-fr/helper-url.md
  77. 527
      docs/guide-fr/images/application-lifecycle.graphml
  78. BIN
      docs/guide-fr/images/application-lifecycle.png
  79. BIN
      docs/guide-fr/images/request-lifecycle.png
  80. 189
      docs/guide-fr/input-file-upload.md
  81. 155
      docs/guide-fr/input-forms.md
  82. 77
      docs/guide-fr/input-multiple-models.md
  83. 99
      docs/guide-fr/input-tabular-input.md
  84. 610
      docs/guide-fr/input-validation.md
  85. 169
      docs/guide-fr/intro-upgrade-from-v1.md
  86. 2
      docs/guide-fr/intro-yii.md
  87. 80
      docs/guide-fr/output-client-scripts.md
  88. 299
      docs/guide-fr/output-data-providers.md
  89. 667
      docs/guide-fr/output-data-widgets.md
  90. 179
      docs/guide-fr/output-formatting.md
  91. 58
      docs/guide-fr/output-pagination.md
  92. 68
      docs/guide-fr/output-sorting.md
  93. 27
      docs/guide-fr/runtime-bootstrapping.md
  94. 195
      docs/guide-fr/runtime-handling-errors.md
  95. 314
      docs/guide-fr/runtime-logging.md
  96. 21
      docs/guide-fr/runtime-overview.md
  97. 113
      docs/guide-fr/runtime-requests.md
  98. 209
      docs/guide-fr/runtime-responses.md
  99. 508
      docs/guide-fr/runtime-routing.md
  100. 297
      docs/guide-fr/runtime-sessions-cookies.md
  101. Some files were not shown because too many files have changed in this diff Show More

24
.codeclimate.yml

@ -0,0 +1,24 @@
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/

3
.dockerignore

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

1
.eslintignore

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

213
.eslintrc

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

8
.gitattributes vendored

@ -22,17 +22,15 @@
*.gif binary
*.ttf binary
# Ignore all test and documentation for archive
# 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.
/.github export-ignore
/.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/

4
.github/CONTRIBUTING.md

@ -1,5 +1,5 @@
Contributing to Yii2
====================
Contributing to Yii 2
=====================
- [Report an issue](../docs/internals/report-an-issue.md)
- [Translate documentation or messages](../docs/internals/translation-workflow.md)

2
.github/ISSUE_TEMPLATE.md

@ -9,6 +9,6 @@
| Q | A
| ---------------- | ---
| Yii version |
| Yii version | 2.0.?
| PHP version |
| Operating system |

6
.gitignore vendored

@ -35,6 +35,10 @@ phpunit.phar
# local phpunit config
/phpunit.xml
# ignore sub directory for dev installed apps and extensions
# ignore dev installed apps and extensions
/apps
/extensions
# NPM packages
/node_modules
.env

118
.gitlab-ci.yml

@ -0,0 +1,118 @@
before_script:
# set stack isolation
- export ISOLATION=buildpipeline${CI_PIPELINE_ID}${CI_BUILD_NAME}
- export COMPOSE_PROJECT_NAME=${ISOLATION}
- export TUPLE_C=$(expr ${CI_BUILD_ID} % 99)
- echo ${TUPLE_C}
# run docker-compose commands from tests environment
- cd tests
- cp .env-dist .env
- docker-compose config
after_script:
- export ISOLATION=buildpipeline${CI_PIPELINE_ID}${CI_BUILD_NAME}
- export COMPOSE_PROJECT_NAME=${ISOLATION}
# run docker-compose commands from tests environment
- cd tests
- cp .env-dist .env
- docker-compose down -v --remove-orphans
- docker ps -f name=${ISOLATION}
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

122
.travis.yml

@ -1,3 +1,26 @@
#
# Travis Setup
#
# use ubuntu trusty for newer version of nodejs, used for JS testing
dist: trusty
# faster builds on new travis setup not using sudo
sudo: false
# build only on master branches
# commented as this prevents people from running builds on their forks:
# https://github.com/yiisoft/yii2/commit/bd87be990fa238c6d5e326d0a171f38d02dc253a
#branches:
# only:
# - master
# - 2.1
#
# Test Matrix
#
language: php
php:
@ -5,39 +28,107 @@ php:
- 5.5
- 5.6
- 7.0
- hhvm
- 7.1
- nightly
matrix:
fast_finish: true
include:
# Test against HHVM 3.12 LTS version by using trusty
- php: hhvm-3.12
sudo: true
dist: trusty
group: edge # Use edge image until the next travis CI image update
addons:
code_climate:
repo_token: 2935307212620b0e2228ab67eadd92c9f5501ddb60549d0d86007a354d56915b
apt:
packages:
- mysql-server-5.6
- mysql-client-core-5.6
- mysql-client-5.6
services:
- mysql
# test against the latest HHVM version by using a newer image
- php: hhvm
sudo: true
dist: trusty
group: edge # Use edge image until the next travis CI image update
addons:
code_climate:
repo_token: 2935307212620b0e2228ab67eadd92c9f5501ddb60549d0d86007a354d56915b
postgresql: "9.3"
apt:
packages:
- mysql-server-5.6
- mysql-client-core-5.6
- mysql-client-5.6
services:
- mysql
- postgresql
# have a separate branch for javascript tests
- language: node_js
node_js: 6
dist: trusty
# overwrite php related settings
php:
services:
addons:
install:
- travis_retry npm install
# disable xdebug for performance in composer
- phpenv config-rm xdebug.ini || echo "xdebug is not installed"
- travis_retry composer self-update && composer --version
- travis_retry composer global require "fxp/composer-asset-plugin:^1.2.0" --no-plugins
- travis_retry composer install --prefer-dist --no-interaction
before_script:
- node --version
- npm --version
- php --version
- composer --version
script: npm test
after_script:
allow_failures:
- php: nightly
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
- mysql
- postgresql
# cache vendor dirs
cache:
directories:
# - cubrid/9.3.0
- vendor
- $HOME/.composer/cache
- $HOME/.npm
# try running against postgres 9.3
addons:
postgresql: "9.3"
code_climate:
repo_token: 2935307212620b0e2228ab67eadd92c9f5501ddb60549d0d86007a354d56915b
install:
- |
if [[ $TRAVIS_PHP_VERSION != '5.6' && $TRAVIS_PHP_VERSION != hhv* ]]; then
# disable xdebug for performance reasons when code coverage is not needed. note: xdebug on hhvm is disabled by default
phpenv config-rm xdebug.ini || echo "xdebug is not installed"
fi
- travis_retry composer self-update && composer --version
- travis_retry composer global require "fxp/composer-asset-plugin:~1.1.1"
- travis_retry composer global require "fxp/composer-asset-plugin:^1.2.0" --no-plugins
- export PATH="$HOME/.composer/vendor/bin:$PATH"
# core framework:
# 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
- tests/data/travis/imagick-setup.sh
before_script:
# Disable the HHVM JIT for faster Unit Testing
- if [[ $TRAVIS_PHP_VERSION = hhv* ]]; then echo 'hhvm.jit = 0' >> /etc/hhvm/php.ini; fi
# show some versions and env information
- php -r "echo INTL_ICU_VERSION . \"\n\";"
- php -r "echo INTL_ICU_DATA_VERSION . \"\n\";"
@ -45,9 +136,12 @@ before_script:
- psql --version
# initialize databases
- mysql -e 'CREATE DATABASE yiitest;';
- travis_retry mysql -e 'CREATE DATABASE `yiitest`;';
- mysql -e "CREATE USER 'travis'@'localhost' IDENTIFIED WITH mysql_native_password;";
- mysql -e "GRANT ALL PRIVILEGES ON *.* TO 'travis'@'localhost' WITH GRANT OPTION;";
- psql -U postgres -c 'CREATE DATABASE yiitest;';
# enable code coverage on PHP 5.6, only one PHP version needs to generate coverage data
- |
if [ $TRAVIS_PHP_VERSION = '5.6' ]; then
PHPUNIT_FLAGS="--coverage-clover=coverage.clover"
@ -55,6 +149,12 @@ before_script:
script:
# ensure no files contain UTF-8 byte order mark
- if ! grep -rlI $'\xEF\xBB\xBF' framework/ ; then echo "no utf8 BOM found"; else echo "found utf8 BOM in some files. See above."; exit 1; fi
# validate composer.json
- composer validate --no-check-lock
- cd framework && composer validate --no-check-lock && cd ..
# run PHPUnit
- vendor/bin/phpunit --verbose $PHPUNIT_FLAGS --exclude-group mssql,oci,wincache,xcache,zenddata,cubrid
after_script:

8
Dockerfile

@ -0,0 +1,8 @@
FROM dmstr/php-yii2:7.0-fpm-1.9-beta2-alpine-nginx
# Project source-code
WORKDIR /project
ADD composer.* /project/
RUN /usr/local/bin/composer install --prefer-dist
ADD ./ /project
ENV PATH /project/vendor/bin:${PATH}

80
README.md

@ -1,12 +1,13 @@
Yii PHP Framework Version 2
===========================
<p align="center">
<a href="http://www.yiiframework.com/" target="_blank">
<img src="http://static.yiiframework.com/files/logo/yii.png" width="400" alt="Yii Framework" />
</a>
</p>
Thank you for choosing Yii 2 - a modern PHP framework designed for professional Web development.
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.
Yii 2 is a modern framework designed to be a solid foundation for your PHP application.
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.
[![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)
@ -18,49 +19,62 @@ Yii 2 requires PHP 5.4 and embraces the best practices and protocols found in mo
[![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
```
REQUIREMENTS
Installation
------------
The minimum requirement by Yii is that your Web server supports PHP 5.4.
- The minimum required PHP version of Yii is PHP 5.4.
- It works best with PHP 7.
- [Follow the Definitive Guide](http://www.yiiframework.com/doc-2.0/guide-start-installation.html)
in order to get step by step instructions.
DOCUMENTATION
Documentation
-------------
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
- 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) cover every detail
of the framework.
- There is 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](docs/guide/intro-upgrade-from-v1.md)
to get an idea of what has changed in 2.0.
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.
Community
---------
- Participate in [discussions at forums](http://www.yiiframework.com/forum/).
- [Chat in IRC](http://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).
HOW TO PARTICIPATE
------------------
Contributing
------------
### Your participation to Yii 2 development is very welcome!
The framework is [Open Source](LICENSE.md) powered by [an excellent community](https://github.com/yiisoft/yii2/graphs/contributors).
You may participate in the following ways:
You may join us and:
- [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)
### Acknowledging or citing Yii 2
### Reporting Security issues
Please refer to a [special page at the website](http://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.
**In presentations**

14
build/controllers/DevController.php

@ -70,14 +70,14 @@ class DevController extends Controller
return 1;
}
foreach($this->extensions as $ext => $repo) {
foreach ($this->extensions as $ext => $repo) {
$ret = $this->actionExt($ext);
if ($ret !== 0) {
return $ret;
}
}
foreach($this->apps as $app => $repo) {
foreach ($this->apps as $app => $repo) {
$ret = $this->actionApp($app);
if ($ret !== 0) {
return $ret;
@ -107,7 +107,7 @@ class DevController extends Controller
asort($dirs);
$oldcwd = getcwd();
foreach($dirs as $dir) {
foreach ($dirs as $dir) {
$displayDir = substr($dir, strlen($base));
$this->stdout("Running '$command' in $displayDir...\n", Console::BOLD);
chdir($dir);
@ -252,7 +252,7 @@ class DevController extends Controller
$this->unlink($link);
}
$extensions = $this->findDirs("$dir/vendor/yiisoft");
foreach($extensions as $ext) {
foreach ($extensions as $ext) {
if (is_link($link = "$dir/vendor/yiisoft/yii2-$ext")) {
$this->stdout("Removing symlink $link.\n");
$this->unlink($link);
@ -261,7 +261,7 @@ class DevController extends Controller
}
/**
* Creates symlinks to freamework and extension sources for the application
* Creates symlinks to framework and extension sources for the application
* @param string $dir application directory
* @param string $base Yii sources base directory
*
@ -276,7 +276,7 @@ class DevController extends Controller
symlink("$base/framework", $link);
}
$extensions = $this->findDirs("$dir/vendor/yiisoft");
foreach($extensions as $ext) {
foreach ($extensions as $ext) {
if (is_dir($link = "$dir/vendor/yiisoft/yii2-$ext")) {
$this->stdout("Removing dir $link.\n");
FileHelper::removeDirectory($link);
@ -359,7 +359,7 @@ class DevController extends Controller
}
closedir($handle);
foreach($list as $i => $e) {
foreach ($list as $i => $e) {
if ($e === 'composer') { // skip composer to not break composer update
unset($list[$i]);
}

4
build/controllers/MimeTypeController.php

@ -39,14 +39,14 @@ class MimeTypeController extends Controller
$this->stdout("done.\n", Console::FG_GREEN);
$this->stdout("generating file $outFile...");
$mimeMap = [];
foreach(explode("\n", $content) as $line) {
foreach (explode("\n", $content) as $line) {
$line = trim($line);
if (empty($line) || $line[0] == '#') { // skip comments and empty lines
continue;
}
$parts = preg_split('/\s+/', $line);
$mime = array_shift($parts);
foreach($parts as $ext) {
foreach ($parts as $ext) {
if (!empty($ext)) {
$mimeMap[$ext] = $mime;
}

46
build/controllers/PhpDocController.php

@ -23,7 +23,7 @@ class PhpDocController extends Controller
{
public $defaultAction = 'property';
/**
* @var boolean whether to update class docs directly. Setting this to false will just output docs
* @var bool whether to update class docs directly. Setting this to false will just output docs
* for copy and paste.
*/
public $updateFiles = true;
@ -167,12 +167,12 @@ class PhpDocController extends Controller
'tests/',
'vendor/',
];
foreach($extensionExcept as $ext => $paths) {
foreach($paths as $path) {
foreach ($extensionExcept as $ext => $paths) {
foreach ($paths as $path) {
$except[] = "/extensions/$ext$path";
}
}
} elseif (preg_match('~extensions/([\w\d-]+)[\\\\/]?$~', $root, $matches)) {
} elseif (preg_match('~extensions/([\w-]+)[\\\\/]?$~', $root, $matches)) {
$extensionPath = dirname(rtrim($root, '\\/'));
$this->setUpExtensionAliases($extensionPath);
@ -184,7 +184,7 @@ class PhpDocController extends Controller
}
if (isset($extensionExcept[$extension])) {
foreach($extensionExcept[$extension] as $path) {
foreach ($extensionExcept[$extension] as $path) {
$except[] = $path;
}
}
@ -196,7 +196,7 @@ class PhpDocController extends Controller
// if ($extension === 'composer') {
// return [];
// }
} elseif (preg_match('~apps/([\w\d-]+)[\\\\/]?$~', $root, $matches)) {
} elseif (preg_match('~apps/([\w-]+)[\\\\/]?$~', $root, $matches)) {
$extensionPath = dirname(dirname(rtrim($root, '\\/'))) . '/extensions';
$this->setUpExtensionAliases($extensionPath);
@ -255,7 +255,7 @@ class PhpDocController extends Controller
$namespace = false;
$namespaceLine = '';
$contentAfterNamespace = false;
foreach($lines as $i => $line) {
foreach ($lines as $i => $line) {
$line = trim($line);
if (!empty($line)) {
if (strncmp($line, 'namespace', 9) === 0) {
@ -269,7 +269,7 @@ class PhpDocController extends Controller
}
if ($namespace !== false && $contentAfterNamespace !== false) {
while($contentAfterNamespace > 0) {
while ($contentAfterNamespace > 0) {
array_shift($lines);
$contentAfterNamespace--;
}
@ -297,7 +297,7 @@ class PhpDocController extends Controller
$listIndent = '';
$tag = false;
$indent = '';
foreach($lines as $i => $line) {
foreach ($lines as $i => $line) {
if (preg_match('~^(\s*)/\*\*$~', $line, $matches)) {
$docBlock = true;
$indent = $matches[1];
@ -348,10 +348,10 @@ class PhpDocController extends Controller
{
return preg_replace_callback('~@(param|return) ([\w\\|]+)~i', function($matches) {
$types = explode('|', $matches[2]);
foreach($types as $i => $type) {
switch($type){
case 'int': $types[$i] = 'integer'; break;
case 'bool': $types[$i] = 'boolean'; break;
foreach ($types as $i => $type) {
switch ($type) {
case 'integer': $types[$i] = 'int'; break;
case 'boolean': $types[$i] = 'bool'; break;
}
}
return '@' . $matches[1] . ' ' . implode('|', $types);
@ -367,7 +367,7 @@ class PhpDocController extends Controller
// remove blank lines between properties
$skip = true;
$level = 0;
foreach($lines as $i => $line) {
foreach ($lines as $i => $line) {
if (strpos($line, 'class ') !== false) {
$skip = false;
}
@ -402,7 +402,7 @@ class PhpDocController extends Controller
$skip = true;
$level = 0; // track array properties
$property = '';
foreach($lines as $i => $line) {
foreach ($lines as $i => $line) {
if (strpos($line, 'class ') !== false) {
$skip = false;
}
@ -428,10 +428,10 @@ class PhpDocController extends Controller
$endofPrivate = $i;
$property = 'Private';
$level = 0;
} elseif (substr($line,0 , 6) === 'const ') {
} elseif (substr($line, 0, 6) === 'const ') {
$endofConst = $i;
$property = false;
} elseif (substr($line,0 , 4) === 'use ') {
} elseif (substr($line, 0, 4) === 'use ') {
$endofUse = $i;
$property = false;
} elseif (!empty($line) && $line[0] === '*') {
@ -447,7 +447,7 @@ class PhpDocController extends Controller
}
$endofAll = false;
foreach(['Private', 'Protected', 'Public', 'Const', 'Use'] as $var) {
foreach (['Private', 'Protected', 'Public', 'Const', 'Use'] as $var) {
if (${'endof'.$var} !== false) {
$endofAll = ${'endof'.$var};
break;
@ -456,7 +456,7 @@ class PhpDocController extends Controller
// $this->checkPropertyOrder($lineInfo);
$result = [];
foreach($lines as $i => $line) {
foreach ($lines as $i => $line) {
$result[] = $line;
if (!($propertiesOnly && $i === $endofAll)) {
if ($i === $endofUse || $i === $endofConst || $i === $endofPublic ||
@ -479,9 +479,15 @@ class PhpDocController extends Controller
protected function updateClassPropertyDocs($file, $className, $propertyDoc)
{
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;
}
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 (!$ref->isSubclassOf('yii\base\Object') && $className != 'yii\base\Object') {
@ -747,7 +753,7 @@ class PhpDocController extends Controller
// example: yii\di\ServiceLocator setComponents() is not recognized in the whole but in
// a part of the class.
$parts = $split ? explode("\n\n", $subject) : [$subject];
foreach($parts as $part) {
foreach ($parts as $part) {
preg_match_all($pattern . 'suU', $part, $matches, PREG_SET_ORDER);
foreach ($matches as &$set) {
foreach ($set as $i => $match)

176
build/controllers/ReleaseController.php

@ -56,6 +56,10 @@ class ReleaseController extends Controller
* @var bool whether to fetch latest tags.
*/
public $update = false;
/**
* @var string override the default version. e.g. for major or patch releases.
*/
public $version;
public function options($actionID)
@ -63,6 +67,7 @@ class ReleaseController extends Controller
$options = ['basePath'];
if ($actionID === 'release') {
$options[] = 'dryRun';
$options[] = 'version';
} elseif ($actionID === 'info') {
$options[] = 'update';
}
@ -100,7 +105,7 @@ class ReleaseController extends Controller
}
if ($this->update) {
foreach($items as $item) {
foreach ($items as $item) {
$this->stdout("fetching tags for $item...");
if ($item === 'framework') {
$this->gitFetchTags("{$this->basePath}");
@ -121,7 +126,7 @@ class ReleaseController extends Controller
// print version table
$w = $this->minWidth(array_keys($versions));
$this->stdout(str_repeat(' ', $w + 2) . "Current Version Next Version\n", Console::BOLD);
foreach($versions as $ext => $version) {
foreach ($versions as $ext => $version) {
$this->stdout($ext . str_repeat(' ', $w + 3 - mb_strlen($ext)) . $version . "");
$this->stdout(str_repeat(' ', 17 - mb_strlen($version)) . $nextVersions[$ext] . "\n");
}
@ -131,7 +136,7 @@ class ReleaseController extends Controller
private function minWidth($a)
{
$w = 1;
foreach($a as $s) {
foreach ($a as $s) {
if (($l = mb_strlen($s)) > $w) {
$w = $l;
}
@ -190,20 +195,32 @@ class ReleaseController extends Controller
$this->validateWhat($what);
$versions = $this->getCurrentVersions($what);
$newVersions = $this->getNextVersions($versions, self::PATCH);// TODO add support for minor
if ($this->version !== null) {
// if a version is explicitly given
$newVersions = [];
foreach ($versions as $k => $v) {
$newVersions[$k] = $this->version;
}
} else {
// otherwise get next patch or minor
$newVersions = $this->getNextVersions($versions, self::PATCH);
}
$this->stdout("You are about to prepare a new release for the following things:\n\n");
$this->printWhat($what, $newVersions, $versions);
$this->stdout("\n");
$this->stdout("Before you make a release briefly go over the changes and check if you spot obvious mistakes:\n\n", Console::BOLD);
$gitDir = reset($what) === 'framework' ? 'framework/' : '';
$gitVersion = $versions[reset($what)];
if (strncmp('app-', reset($what), 4) !== 0) {
$this->stdout("- no accidentally added CHANGELOG lines for other versions than this one?\n");
$this->stdout("- are all new `@since` tags for this relase version?\n");
$this->stdout("- no accidentally added CHANGELOG lines for other versions than this one?\n\n git diff $gitVersion.. ${gitDir}CHANGELOG.md\n\n");
$this->stdout("- are all new `@since` tags for this release version?\n");
}
$this->stdout("- other issues with code changes?\n\n git diff -w $gitVersion.. ${gitDir}\n\n");
$travisUrl = reset($what) === 'framework' ? '' : '-'.reset($what);
$this->stdout("- are unit tests passing on travis? https://travis-ci.org/yiisoft/yii2$travisUrl/builds\n");
$this->stdout("- other issues with code changes?\n");
$this->stdout("- also make sure the milestone on github is complete and no issues or PRs are left open.\n\n");
$this->printWhatUrls($what, $versions);
$this->stdout("\n");
@ -213,7 +230,7 @@ class ReleaseController extends Controller
return 1;
}
foreach($what as $ext) {
foreach ($what as $ext) {
if ($ext === 'framework') {
$this->releaseFramework("{$this->basePath}/framework", $newVersions['framework']);
} elseif (strncmp('app-', $ext, 4) === 0) {
@ -247,7 +264,7 @@ class ReleaseController extends Controller
$versions = $this->getCurrentVersions($what);
$this->stdout("You are about to generate packages for the following things:\n\n");
foreach($what as $ext) {
foreach ($what as $ext) {
if (strncmp('app-', $ext, 4) === 0) {
$this->stdout(" - ");
$this->stdout(substr($ext, 4), Console::FG_RED);
@ -272,7 +289,7 @@ class ReleaseController extends Controller
return 1;
}
foreach($what as $ext) {
foreach ($what as $ext) {
if ($ext === 'framework') {
throw new Exception('Can not package framework.');
} elseif (strncmp('app-', $ext, 4) === 0) {
@ -287,9 +304,37 @@ class ReleaseController extends Controller
return 0;
}
/**
* Sorts CHANGELOG for framework or extension.
*
* @param array $what what do you want to resort changelog for? this can either be:
*
* - an extension name such as `redis` or `bootstrap`,
* - or `framework` if you want to release a new version of the framework itself.
*/
public function actionSortChangelog(array $what)
{
if (count($what) > 1) {
$this->stdout("Currently only one simultaneous release is supported.\n");
return 1;
}
$this->validateWhat($what, ['framework', 'ext'], false);
$version = array_values($this->getNextVersions($this->getCurrentVersions($what), self::PATCH))[0];
$this->stdout('sorting CHANGELOG of ');
$this->stdout(reset($what), Console::BOLD);
$this->stdout(" for version ");
$this->stdout($version, Console::BOLD);
$this->stdout("...");
$this->resortChangelogs($what, $version);
$this->stdout("done.\n", Console::BOLD, Console::FG_GREEN);
}
protected function printWhat(array $what, $newVersions, $versions)
{
foreach($what as $ext) {
foreach ($what as $ext) {
if (strncmp('app-', $ext, 4) === 0) {
$this->stdout(" - ");
$this->stdout(substr($ext, 4), Console::FG_RED);
@ -308,7 +353,7 @@ class ReleaseController extends Controller
protected function printWhatUrls(array $what, $oldVersions)
{
foreach($what as $ext) {
foreach ($what as $ext) {
if ($ext === 'framework') {
$this->stdout("framework: https://github.com/yiisoft/yii2-framework/compare/{$oldVersions[$ext]}...master\n");
$this->stdout("app-basic: https://github.com/yiisoft/yii2-app-basic/compare/{$oldVersions[$ext]}...master\n");
@ -325,9 +370,9 @@ class ReleaseController extends Controller
* @param array $limit list of things to allow, or empty to allow any, can be `app`, `framework`, `extension`
* @throws \yii\base\Exception
*/
protected function validateWhat(array $what, $limit = [])
protected function validateWhat(array $what, $limit = [], $ensureGitClean = true)
{
foreach($what as $w) {
foreach ($what as $w) {
if (strncmp('app-', $w, 4) === 0) {
if (!empty($limit) && !in_array('app', $limit)) {
throw new Exception("Only the following types are allowed: ".implode(', ', $limit)."\n");
@ -335,7 +380,9 @@ class ReleaseController extends Controller
if (!is_dir($appPath = "{$this->basePath}/apps/" . substr($w, 4))) {
throw new Exception("Application path does not exist: \"{$appPath}\"\n");
}
if ($ensureGitClean) {
$this->ensureGitClean($appPath);
}
} elseif ($w === 'framework') {
if (!empty($limit) && !in_array('framework', $limit)) {
throw new Exception("Only the following types are allowed: ".implode(', ', $limit)."\n");
@ -343,7 +390,9 @@ class ReleaseController extends Controller
if (!is_dir($fwPath = "{$this->basePath}/framework")) {
throw new Exception("Framework path does not exist: \"{$this->basePath}/framework\"\n");
}
if ($ensureGitClean) {
$this->ensureGitClean($fwPath);
}
} else {
if (!empty($limit) && !in_array('ext', $limit)) {
throw new Exception("Only the following types are allowed: ".implode(', ', $limit)."\n");
@ -351,10 +400,12 @@ class ReleaseController extends Controller
if (!is_dir($extPath = "{$this->basePath}/extensions/$w")) {
throw new Exception("Extension path for \"$w\" does not exist: \"{$this->basePath}/extensions/$w\"\n");
}
if ($ensureGitClean) {
$this->ensureGitClean($extPath);
}
}
}
}
protected function releaseFramework($frameworkPath, $version)
@ -363,8 +414,10 @@ class ReleaseController extends Controller
$this->stdout($h = "Preparing framework release version $version", Console::BOLD);
$this->stdout("\n" . str_repeat('-', strlen($h)) . "\n\n", Console::BOLD);
$this->runGit('git checkout master', $frameworkPath); // TODO add compatibility for other release branches
$this->runGit('git pull', $frameworkPath); // TODO add compatibility for other release branches
if (!$this->confirm('Make sure you are on the right branch for this release and that it tracks the correct remote branch! Continue?')) {
exit(1);
}
$this->runGit('git pull', $frameworkPath);
// checks
@ -407,20 +460,22 @@ class ReleaseController extends Controller
$this->runGit("git diff --color", $frameworkPath);
$this->stdout("\n\n\nCheck whether the above diff is okay, if not you may change things as needed before continuing.\n");
$this->stdout("You may abort the program with Ctrl + C and reset the changes by running `git checkout -- .` in the repo.\n\n");
} while(!$this->confirm("Type `yes` to continue, `no` to view git diff again. Continue?"));
} while (!$this->confirm("Type `yes` to continue, `no` to view git diff again. Continue?"));
$this->stdout("\n\n");
$this->stdout(" **** RELEASE TIME! ****\n", Console::FG_YELLOW, Console::BOLD);
$this->stdout(" **** Commit, Tag and Push it! ****\n", Console::FG_YELLOW, Console::BOLD);
$this->stdout("\n\nHint: if you decide 'no' for any of the following, the command will not be executed. You may manually run them later if needed. E.g. try the release locally without pushing it.\n\n");
$this->runGit("git commit -a -m \"release version $version\"", $frameworkPath);
$this->runGit("git tag -a $version -m\"version $version\"", $frameworkPath);
$this->runGit("git push origin master", $frameworkPath);
$this->stdout("Make sure to have your git set up for GPG signing. The following tag and commit should be signed.\n\n");
$this->runGit("git commit -S -a -m \"release version $version\"", $frameworkPath);
$this->runGit("git tag -s $version -m \"version $version\"", $frameworkPath);
$this->runGit("git push", $frameworkPath);
$this->runGit("git push --tags", $frameworkPath);
$this->stdout("\n\n");
$this->stdout("CONGRATULATIONS! You have just released extension ", Console::FG_YELLOW, Console::BOLD);
$this->stdout("CONGRATULATIONS! You have just released ", Console::FG_YELLOW, Console::BOLD);
$this->stdout('framework', Console::FG_RED, Console::BOLD);
$this->stdout(" version ", Console::FG_YELLOW, Console::BOLD);
$this->stdout($version, Console::BOLD);
@ -467,13 +522,19 @@ class ReleaseController extends Controller
$this->runGit("git diff --color", $frameworkPath);
$this->stdout("\n\n");
$this->runGit("git commit -a -m \"prepare for next release\"", $frameworkPath);
$this->runGit("git push origin master", $frameworkPath);
$this->runGit("git push", $frameworkPath);
$this->stdout("\n\nDONE!", Console::FG_YELLOW, Console::BOLD);
$this->stdout("\n\nThe following steps are left for you to do manually:\n\n");
$nextVersion2 = $this->getNextVersions($nextVersion, self::PATCH); // TODO support other versions
$this->stdout("- wait for your changes to be propagated to the repo and create a tag $version on https://github.com/yiisoft/yii2-framework\n\n");
$this->stdout(" git clone git@github.com:yiisoft/yii2-framework.git\n");
$this->stdout(" cd yii2-framework/\n");
$this->stdout(" export RELEASECOMMIT=$(git log --oneline |grep $version |grep -Po \"^[0-9a-f]+\")\n");
$this->stdout(" git tag -s $version -m \"version $version\" \$RELEASECOMMIT\n");
$this->stdout(" git tag --verify $version\n");
$this->stdout(" git push --tags\n\n");
$this->stdout("- close the $version milestone on github and open new ones for {$nextVersion['framework']} and {$nextVersion2['framework']}: https://github.com/yiisoft/yii2/milestones\n");
$this->stdout("- create a release on github.\n");
$this->stdout("- release news and announcement.\n");
@ -492,8 +553,10 @@ class ReleaseController extends Controller
$this->stdout($h = "Preparing release for application $name version $version", Console::BOLD);
$this->stdout("\n" . str_repeat('-', strlen($h)) . "\n\n", Console::BOLD);
$this->runGit('git checkout master', $path); // TODO add compatibility for other release branches
$this->runGit('git pull', $path); // TODO add compatibility for other release branches
if (!$this->confirm('Make sure you are on the right branch for this release and that it tracks the correct remote branch! Continue?')) {
exit(1);
}
$this->runGit('git pull', $path);
// adjustments
@ -518,16 +581,18 @@ class ReleaseController extends Controller
$this->runGit("git diff --color", $path);
$this->stdout("\n\n\nCheck whether the above diff is okay, if not you may change things as needed before continuing.\n");
$this->stdout("You may abort the program with Ctrl + C and reset the changes by running `git checkout -- .` in the repo.\n\n");
} while(!$this->confirm("Type `yes` to continue, `no` to view git diff again. Continue?"));
} while (!$this->confirm("Type `yes` to continue, `no` to view git diff again. Continue?"));
$this->stdout("\n\n");
$this->stdout(" **** RELEASE TIME! ****\n", Console::FG_YELLOW, Console::BOLD);
$this->stdout(" **** Commit, Tag and Push it! ****\n", Console::FG_YELLOW, Console::BOLD);
$this->stdout("\n\nHint: if you decide 'no' for any of the following, the command will not be executed. You may manually run them later if needed. E.g. try the release locally without pushing it.\n\n");
$this->runGit("git commit -a -m \"release version $version\"", $path);
$this->runGit("git tag -a $version -m\"version $version\"", $path);
$this->runGit("git push origin master", $path);
$this->stdout("Make sure to have your git set up for GPG signing. The following tag and commit should be signed.\n\n");
$this->runGit("git commit -S -a -m \"release version $version\"", $path);
$this->runGit("git tag -s $version -m \"version $version\"", $path);
$this->runGit("git push", $path);
$this->runGit("git push --tags", $path);
$this->stdout("\n\n");
@ -551,7 +616,7 @@ class ReleaseController extends Controller
$this->runGit("git diff --color", $path);
$this->stdout("\n\n");
$this->runGit("git commit -a -m \"prepare for next release\"", $path);
$this->runGit("git push origin master", $path);
$this->runGit("git push", $path);
$this->stdout("\n\nDONE!", Console::FG_YELLOW, Console::BOLD);
@ -568,7 +633,7 @@ class ReleaseController extends Controller
protected function setAppAliases($app, $path)
{
$this->_oldAlias = Yii::getAlias('@app');
switch($app) {
switch ($app) {
case 'basic':
Yii::setAlias('@app', $path);
break;
@ -606,8 +671,10 @@ class ReleaseController extends Controller
$this->stdout($h = "Preparing release for extension $name version $version", Console::BOLD);
$this->stdout("\n" . str_repeat('-', strlen($h)) . "\n\n", Console::BOLD);
$this->runGit('git checkout master', $path); // TODO add compatibility for other release branches
$this->runGit('git pull', $path); // TODO add compatibility for other release branches
if (!$this->confirm('Make sure you are on the right branch for this release and that it tracks the correct remote branch! Continue?')) {
exit(1);
}
$this->runGit('git pull', $path);
// adjustments
@ -632,16 +699,18 @@ class ReleaseController extends Controller
$this->runGit("git diff --color", $path);
$this->stdout("\n\n\nCheck whether the above diff is okay, if not you may change things as needed before continuing.\n");
$this->stdout("You may abort the program with Ctrl + C and reset the changes by running `git checkout -- .` in the repo.\n\n");
} while(!$this->confirm("Type `yes` to continue, `no` to view git diff again. Continue?"));
} while (!$this->confirm("Type `yes` to continue, `no` to view git diff again. Continue?"));
$this->stdout("\n\n");
$this->stdout(" **** RELEASE TIME! ****\n", Console::FG_YELLOW, Console::BOLD);
$this->stdout(" **** Commit, Tag and Push it! ****\n", Console::FG_YELLOW, Console::BOLD);
$this->stdout("\n\nHint: if you decide 'no' for any of the following, the command will not be executed. You may manually run them later if needed. E.g. try the release locally without pushing it.\n\n");
$this->runGit("git commit -a -m \"release version $version\"", $path);
$this->runGit("git tag -a $version -m\"version $version\"", $path);
$this->runGit("git push origin master", $path);
$this->stdout("Make sure to have your git set up for GPG signing. The following tag and commit should be signed.\n\n");
$this->runGit("git commit -S -a -m \"release version $version\"", $path);
$this->runGit("git tag -s $version -m \"version $version\"", $path);
$this->runGit("git push", $path);
$this->runGit("git push --tags", $path);
$this->stdout("\n\n");
@ -664,7 +733,7 @@ class ReleaseController extends Controller
$this->runGit("git diff --color", $path);
$this->stdout("\n\n");
$this->runGit("git commit -a -m \"prepare for next release\"", $path);
$this->runGit("git push origin master", $path);
$this->runGit("git push", $path);
$this->stdout("\n\nDONE!", Console::FG_YELLOW, Console::BOLD);
@ -756,7 +825,7 @@ class ReleaseController extends Controller
{
$headline = "\n$version under development\n";
$headline .= str_repeat('-', strlen($headline) - 2) . "\n\n- no changes in this release.\n";
foreach($this->getChangelogs($what) as $file) {
foreach ($this->getChangelogs($what) as $file) {
$lines = explode("\n", file_get_contents($file));
$hl = [
array_shift($lines),
@ -770,7 +839,7 @@ class ReleaseController extends Controller
protected function resortChangelogs($what, $version)
{
foreach($this->getChangelogs($what) as $file) {
foreach ($this->getChangelogs($what) as $file) {
// split the file into relevant parts
list($start, $changelog, $end) = $this->splitChangelog($file, $version);
$changelog = $this->resortChangelog($changelog);
@ -791,7 +860,7 @@ class ReleaseController extends Controller
$end = [];
$state = 'start';
foreach($lines as $l => $line) {
foreach ($lines as $l => $line) {
// starting from the changelogs headline
if (isset($lines[$l-2]) && strpos($lines[$l-2], $version) !== false &&
isset($lines[$l-1]) && strncmp($lines[$l-1], '---', 3) === 0) {
@ -800,8 +869,14 @@ class ReleaseController extends Controller
if ($state === 'changelog' && isset($lines[$l+1]) && strncmp($lines[$l+1], '---', 3) === 0) {
$state = 'end';
}
// add continued lines to the last item to keep them together
if (!empty(${$state}) && trim($line !== '') && strpos($line, '- ') !== 0) {
end(${$state});
${$state}[key(${$state})] .= "\n" . $line;
} else {
${$state}[] = $line;
}
}
return [$start, $changelog, $end];
}
@ -811,14 +886,14 @@ class ReleaseController extends Controller
protected function resortChangelog($changelog)
{
// cleanup whitespace
foreach($changelog as $i => $line) {
foreach ($changelog as $i => $line) {
$changelog[$i] = rtrim($line);
}
$changelog = array_filter($changelog);
$i = 0;
ArrayHelper::multisort($changelog, function($line) use (&$i) {
if (preg_match('/^- (Chg|Enh|Bug|New)( #\d+(, #\d+)*)?: .+$/', $line, $m)) {
if (preg_match('/^- (Chg|Enh|Bug|New)( #\d+(, #\d+)*)?: .+/', $line, $m)) {
$o = ['Bug' => 'C', 'Enh' => 'D', 'Chg' => 'E', 'New' => 'F'];
return $o[$m[1]] . ' ' . (!empty($m[2]) ? $m[2] : 'AAAA' . $i++);
}
@ -851,7 +926,7 @@ class ReleaseController extends Controller
protected function getExtensionChangelogs($what)
{
return array_filter(glob($this->basePath . '/extensions/*/CHANGELOG.md'), function($elem) use ($what) {
foreach($what as $ext) {
foreach ($what as $ext) {
if (strpos($elem, "extensions/$ext/CHANGELOG.md") !== false) {
return true;
}
@ -904,7 +979,7 @@ class ReleaseController extends Controller
protected function sed($pattern, $replace, $files)
{
foreach((array) $files as $file) {
foreach ((array) $files as $file) {
file_put_contents($file, preg_replace($pattern, $replace, file_get_contents($file)));
}
}
@ -912,7 +987,7 @@ class ReleaseController extends Controller
protected function getCurrentVersions(array $what)
{
$versions = [];
foreach($what as $ext) {
foreach ($what as $ext) {
if ($ext === 'framework') {
chdir("{$this->basePath}/framework");
} elseif (strncmp('app-', $ext, 4) === 0) {
@ -936,18 +1011,25 @@ class ReleaseController extends Controller
protected function getNextVersions(array $versions, $type)
{
foreach($versions as $k => $v) {
foreach ($versions as $k => $v) {
if (empty($v)) {
$versions[$k] = '2.0.0';
continue;
}
$parts = explode('.', $v);
switch($type) {
switch ($type) {
case self::MINOR:
$parts[1]++;
$parts[2] = 0;
if (isset($parts[3])) {
unset($parts[3]);
}
break;
case self::PATCH:
$parts[2]++;
if (isset($parts[3])) {
unset($parts[3]);
}
break;
default:
throw new Exception('Unknown version type.');

4
build/controllers/TranslationController.php

@ -47,7 +47,7 @@ class TranslationController extends Controller
$errors = $this->checkFiles($translatedFilePath);
$diff = empty($errors) ? $this->getDiff($translatedFilePath, $sourceFilePath) : '';
if(!empty($diff)) {
if (!empty($diff)) {
$errors[] = 'Translation outdated.';
}
@ -68,7 +68,7 @@ class TranslationController extends Controller
$translatedFilePath = $translationPath . '/' . $fileinfo->getFilename();
$errors = $this->checkFiles(null, $translatedFilePath);
if(!empty($errors)) {
if (!empty($errors)) {
$results[$fileinfo->getFilename()]['errors'] = $errors;
}
}

130
build/controllers/Utf8Controller.php

@ -0,0 +1,130 @@
<?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 CHARARCTER", $c, $line, $pos, $file);
continue;
}
// if ($ord > 0x009F) {
// $this->found("NON ASCII CHARARCTER", $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");
}
/**
* Equvalent 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;
} else if ($h < 0xC2) {
return false;
} else if ($h <= 0xDF) {
return ($h & 0x1F) << 6 | (ord($c{1}) & 0x3F);
} else if ($h <= 0xEF) {
return ($h & 0x0F) << 12 | (ord($c{1}) & 0x3F) << 6
| (ord($c{2}) & 0x3F);
} else if ($h <= 0xF4) {
return ($h & 0x0F) << 18 | (ord($c{1}) & 0x3F) << 12
| (ord($c{2}) & 0x3F) << 6
| (ord($c{3}) & 0x3F);
} else {
return false;
}
}
}

4
build/controllers/views/translation/report_html.php

@ -36,9 +36,9 @@ use yii\helpers\Html;
<li><strong>Translation:</strong> <?= Html::encode($translationPath) ?></li>
</ul>
<?php foreach($results as $name => $result): ?>
<?php foreach ($results as $name => $result): ?>
<h2 class="<?= empty($result['errors']) ? 'ok' : 'errors' ?>"><?= $name ?></h2>
<?php foreach($result['errors'] as $error): ?>
<?php foreach ($result['errors'] as $error): ?>
<p><?= Html::encode($error) ?></p>
<?php endforeach ?>
<?php if (!empty($result['diff'])): ?>

71
code-of-conduct.md

@ -1,45 +1,68 @@
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.
We are committed to making participation in this project a good experience for everyone.
## 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
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Personal attacks
* Trolling or insulting/derogatory comments
* Trolling or insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing other's private information, such as physical or electronic
addresses, without explicit permission
* Other unethical or unprofessional conduct
* 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
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.
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.
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.
## Enforcement
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community.
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.
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.
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.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 1.3.0, available at
[http://contributor-covenant.org/version/1/3/0/][version]
version 1.4.0, available at
[http://contributor-covenant.org/version/1/4/][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/3/0/
[version]: http://contributor-covenant.org/version/1/4/

22
composer.json

@ -47,6 +47,12 @@
"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": {
@ -57,6 +63,7 @@
"source": "https://github.com/yiisoft/yii2"
},
"minimum-stability": "dev",
"prefer-stable": true,
"replace": {
"yiisoft/yii2": "self.version"
},
@ -68,14 +75,14 @@
"yiisoft/yii2-composer": "~2.0.4",
"ezyang/htmlpurifier": "~4.6",
"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/jquery": "2.2.*@stable | 2.1.*@stable | 1.11.*@stable | 1.12.*@stable",
"bower-asset/jquery.inputmask": "~3.2.2 | ~3.3.3",
"bower-asset/punycode": "1.3.*",
"bower-asset/yii2-pjax": "~2.0.1"
},
"require-dev": {
"phpunit/phpunit": "~4.4",
"cebe/indent": "*"
"cebe/indent": "~1.0.2"
},
"suggest": {
"yiisoft/yii2-coding-standards": "you can use this package to check for code style issues when contributing to yii"
@ -85,6 +92,9 @@
"yii\\": "framework/"
}
},
"config": {
"platform": {"php": "5.4"}
},
"bin": [
"framework/yii"
],
@ -95,6 +105,10 @@
"asset-installer-paths": {
"npm-asset-library": "vendor/npm",
"bower-asset-library": "vendor/bower"
}
},
"asset-vcs-driver-options": {
"github-no-api": true
},
"asset-pattern-skip-version": "(-build|-patch)"
}
}

208
composer.lock generated

@ -4,21 +4,21 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "d2005b487c5ff761d806b9a94bfe4cac",
"content-hash": "de99885237d7d9364d74fb5f93389801",
"hash": "db4e038c0e8ca747784fb195c82bfdad",
"content-hash": "cc4b01a602c948040169ebbc1ac30186",
"packages": [
{
"name": "bower-asset/jquery",
"version": "2.2.3",
"version": "2.2.4",
"source": {
"type": "git",
"url": "https://github.com/jquery/jquery-dist.git",
"reference": "af22a351b2ea5801ffb1695abb3bb34d5bed9198"
"reference": "c0185ab7c75aab88762c5aae780b9d83b80eda72"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/jquery/jquery-dist/zipball/af22a351b2ea5801ffb1695abb3bb34d5bed9198",
"reference": "af22a351b2ea5801ffb1695abb3bb34d5bed9198",
"url": "https://api.github.com/repos/jquery/jquery-dist/zipball/c0185ab7c75aab88762c5aae780b9d83b80eda72",
"reference": "c0185ab7c75aab88762c5aae780b9d83b80eda72",
"shasum": ""
},
"type": "bower-asset-library",
@ -44,12 +44,12 @@
"source": {
"type": "git",
"url": "https://github.com/RobinHerbots/jquery.inputmask.git",
"reference": "5a72c563b502b8e05958a524cdfffafe9987be38"
"reference": "ec7726993217ee7b01023ad4f7f1b6a51446a39d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/RobinHerbots/jquery.inputmask/zipball/5a72c563b502b8e05958a524cdfffafe9987be38",
"reference": "5a72c563b502b8e05958a524cdfffafe9987be38",
"url": "https://api.github.com/repos/RobinHerbots/jquery.inputmask/zipball/ec7726993217ee7b01023ad4f7f1b6a51446a39d",
"reference": "ec7726993217ee7b01023ad4f7f1b6a51446a39d",
"shasum": ""
},
"require": {
@ -148,16 +148,16 @@
},
{
"name": "cebe/markdown",
"version": "dev-master",
"version": "1.1.1",
"source": {
"type": "git",
"url": "https://github.com/cebe/markdown.git",
"reference": "e2a490ceec590bf5bfd1b43bd424fb9dceceb7c5"
"reference": "c30eb5e01fe021cc5bba2f9ee0eeef96d4931166"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/cebe/markdown/zipball/e2a490ceec590bf5bfd1b43bd424fb9dceceb7c5",
"reference": "e2a490ceec590bf5bfd1b43bd424fb9dceceb7c5",
"url": "https://api.github.com/repos/cebe/markdown/zipball/c30eb5e01fe021cc5bba2f9ee0eeef96d4931166",
"reference": "c30eb5e01fe021cc5bba2f9ee0eeef96d4931166",
"shasum": ""
},
"require": {
@ -204,20 +204,20 @@
"markdown",
"markdown-extra"
],
"time": "2016-03-18 13:28:11"
"time": "2016-09-14 20:40:20"
},
{
"name": "ezyang/htmlpurifier",
"version": "v4.7.0",
"version": "v4.8.0",
"source": {
"type": "git",
"url": "https://github.com/ezyang/htmlpurifier.git",
"reference": "ae1828d955112356f7677c465f94f7deb7d27a40"
"reference": "d0c392f77d2f2a3dcf7fcb79e2a1e2b8804e75b2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/ae1828d955112356f7677c465f94f7deb7d27a40",
"reference": "ae1828d955112356f7677c465f94f7deb7d27a40",
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/d0c392f77d2f2a3dcf7fcb79e2a1e2b8804e75b2",
"reference": "d0c392f77d2f2a3dcf7fcb79e2a1e2b8804e75b2",
"shasum": ""
},
"require": {
@ -248,25 +248,28 @@
"keywords": [
"html"
],
"time": "2015-08-05 01:03:42"
"time": "2016-07-16 12:58:58"
},
{
"name": "yiisoft/yii2-composer",
"version": "dev-master",
"version": "2.0.5",
"source": {
"type": "git",
"url": "https://github.com/yiisoft/yii2-composer.git",
"reference": "f5fe6ba58dbc92b37daed5d9bd94cda777852ee4"
"reference": "3f4923c2bde6caf3f5b88cc22fdd5770f52f8df2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/yiisoft/yii2-composer/zipball/f5fe6ba58dbc92b37daed5d9bd94cda777852ee4",
"reference": "f5fe6ba58dbc92b37daed5d9bd94cda777852ee4",
"url": "https://api.github.com/repos/yiisoft/yii2-composer/zipball/3f4923c2bde6caf3f5b88cc22fdd5770f52f8df2",
"reference": "3f4923c2bde6caf3f5b88cc22fdd5770f52f8df2",
"shasum": ""
},
"require": {
"composer-plugin-api": "^1.0"
},
"require-dev": {
"composer/composer": "^1.0"
},
"type": "composer-plugin",
"extra": {
"class": "yii\\composer\\Plugin",
@ -295,22 +298,22 @@
"extension installer",
"yii2"
],
"time": "2016-04-14 08:46:37"
"time": "2016-12-20 13:26:02"
}
],
"packages-dev": [
{
"name": "cebe/indent",
"version": "dev-master",
"version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/cebe/indent.git",
"reference": "0f33ba3cb567726a726e7024072232839a0d7cd0"
"reference": "c500ed74d30ed2d7e085f9cf07f8092d32d70776"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/cebe/indent/zipball/0f33ba3cb567726a726e7024072232839a0d7cd0",
"reference": "0f33ba3cb567726a726e7024072232839a0d7cd0",
"url": "https://api.github.com/repos/cebe/indent/zipball/c500ed74d30ed2d7e085f9cf07f8092d32d70776",
"reference": "c500ed74d30ed2d7e085f9cf07f8092d32d70776",
"shasum": ""
},
"bin": [
@ -324,24 +327,26 @@
"authors": [
{
"name": "Carsten Brandt",
"email": "mail@cebe.cc"
"email": "mail@cebe.cc",
"homepage": "http://cebe.cc/",
"role": "Core framework development"
}
],
"description": "a small tool to convert text file indentation",
"time": "2015-11-22 14:46:59"
"time": "2014-05-23 14:40:08"
},
{
"name": "doctrine/instantiator",
"version": "dev-master",
"version": "1.0.5",
"source": {
"type": "git",
"url": "https://github.com/doctrine/instantiator.git",
"reference": "416fb8ad1d095a87f1d21bc40711843cd122fd4a"
"reference": "8e884e78f9f0eb1329e445619e04456e64d8051d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/416fb8ad1d095a87f1d21bc40711843cd122fd4a",
"reference": "416fb8ad1d095a87f1d21bc40711843cd122fd4a",
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d",
"reference": "8e884e78f9f0eb1329e445619e04456e64d8051d",
"shasum": ""
},
"require": {
@ -382,7 +387,7 @@
"constructor",
"instantiate"
],
"time": "2016-03-31 10:24:22"
"time": "2015-06-14 21:17:01"
},
{
"name": "phpdocumentor/reflection-docblock",
@ -435,27 +440,28 @@
},
{
"name": "phpspec/prophecy",
"version": "dev-master",
"version": "v1.6.2",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
"reference": "b02221e42163be673f9b44a0bc92a8b4907a7c6d"
"reference": "6c52c2722f8460122f96f86346600e1077ce22cb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/b02221e42163be673f9b44a0bc92a8b4907a7c6d",
"reference": "b02221e42163be673f9b44a0bc92a8b4907a7c6d",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/6c52c2722f8460122f96f86346600e1077ce22cb",
"reference": "6c52c2722f8460122f96f86346600e1077ce22cb",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.0.2",
"php": "^5.3|^7.0",
"phpdocumentor/reflection-docblock": "~2.0",
"sebastian/comparator": "~1.1",
"sebastian/recursion-context": "~1.0"
"phpdocumentor/reflection-docblock": "^2.0|^3.0.2",
"sebastian/comparator": "^1.1",
"sebastian/recursion-context": "^1.0|^2.0"
},
"require-dev": {
"phpspec/phpspec": "~2.0"
"phpspec/phpspec": "^2.0",
"phpunit/phpunit": "^4.8 || ^5.6.5"
},
"type": "library",
"extra": {
@ -493,11 +499,11 @@
"spy",
"stub"
],
"time": "2016-02-21 17:41:21"
"time": "2016-11-21 14:58:47"
},
{
"name": "phpunit/php-code-coverage",
"version": "2.2.x-dev",
"version": "2.2.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
@ -559,16 +565,16 @@
},
{
"name": "phpunit/php-file-iterator",
"version": "dev-master",
"version": "1.4.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
"reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0"
"reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0",
"reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0",
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
"reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
"shasum": ""
},
"require": {
@ -602,7 +608,7 @@
"filesystem",
"iterator"
],
"time": "2015-06-21 13:08:43"
"time": "2016-10-03 07:40:28"
},
{
"name": "phpunit/php-text-template",
@ -647,21 +653,24 @@
},
{
"name": "phpunit/php-timer",
"version": "1.0.7",
"version": "1.0.8",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-timer.git",
"reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b"
"reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3e82f4e9fc92665fafd9157568e4dcb01d014e5b",
"reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b",
"url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260",
"reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~4|~5"
},
"type": "library",
"autoload": {
"classmap": [
@ -684,20 +693,20 @@
"keywords": [
"timer"
],
"time": "2015-06-21 08:01:12"
"time": "2016-05-12 18:03:57"
},
{
"name": "phpunit/php-token-stream",
"version": "dev-master",
"version": "1.4.9",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
"reference": "cab6c6fefee93d7b7c3a01292a0fe0884ea66644"
"reference": "3b402f65a4cc90abf6e1104e388b896ce209631b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/cab6c6fefee93d7b7c3a01292a0fe0884ea66644",
"reference": "cab6c6fefee93d7b7c3a01292a0fe0884ea66644",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3b402f65a4cc90abf6e1104e388b896ce209631b",
"reference": "3b402f65a4cc90abf6e1104e388b896ce209631b",
"shasum": ""
},
"require": {
@ -733,20 +742,20 @@
"keywords": [
"tokenizer"
],
"time": "2015-09-23 14:46:55"
"time": "2016-11-15 14:06:22"
},
{
"name": "phpunit/phpunit",
"version": "4.8.x-dev",
"version": "4.8.31",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "3c4becbce99732549949904c47b76ffe602a7595"
"reference": "98b2b39a520766bec663ff5b7ff1b729db9dbfe3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3c4becbce99732549949904c47b76ffe602a7595",
"reference": "3c4becbce99732549949904c47b76ffe602a7595",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/98b2b39a520766bec663ff5b7ff1b729db9dbfe3",
"reference": "98b2b39a520766bec663ff5b7ff1b729db9dbfe3",
"shasum": ""
},
"require": {
@ -762,7 +771,7 @@
"phpunit/php-text-template": "~1.2",
"phpunit/php-timer": "^1.0.6",
"phpunit/phpunit-mock-objects": "~2.3",
"sebastian/comparator": "~1.1",
"sebastian/comparator": "~1.2.2",
"sebastian/diff": "~1.2",
"sebastian/environment": "~1.3",
"sebastian/exporter": "~1.2",
@ -805,11 +814,11 @@
"testing",
"xunit"
],
"time": "2016-04-25 09:17:33"
"time": "2016-12-09 02:45:31"
},
{
"name": "phpunit/phpunit-mock-objects",
"version": "2.3.x-dev",
"version": "2.3.8",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
@ -865,22 +874,22 @@
},
{
"name": "sebastian/comparator",
"version": "dev-master",
"version": "1.2.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
"reference": "937efb279bd37a375bcadf584dec0726f84dbf22"
"reference": "6a1ed12e8b2409076ab22e3897126211ff8b1f7f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22",
"reference": "937efb279bd37a375bcadf584dec0726f84dbf22",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/6a1ed12e8b2409076ab22e3897126211ff8b1f7f",
"reference": "6a1ed12e8b2409076ab22e3897126211ff8b1f7f",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"sebastian/diff": "~1.2",
"sebastian/exporter": "~1.2"
"sebastian/exporter": "~1.2 || ~2.0"
},
"require-dev": {
"phpunit/phpunit": "~4.4"
@ -925,11 +934,11 @@
"compare",
"equality"
],
"time": "2015-07-26 15:48:44"
"time": "2016-11-19 09:18:40"
},
{
"name": "sebastian/diff",
"version": "dev-master",
"version": "1.4.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/diff.git",
@ -981,23 +990,23 @@
},
{
"name": "sebastian/environment",
"version": "dev-master",
"version": "1.3.8",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/environment.git",
"reference": "dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf"
"reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf",
"reference": "dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf",
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea",
"reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
"php": "^5.3.3 || ^7.0"
},
"require-dev": {
"phpunit/phpunit": "~4.4"
"phpunit/phpunit": "^4.8 || ^5.0"
},
"type": "library",
"extra": {
@ -1027,20 +1036,20 @@
"environment",
"hhvm"
],
"time": "2016-02-26 18:40:46"
"time": "2016-08-18 05:49:44"
},
{
"name": "sebastian/exporter",
"version": "dev-master",
"version": "1.2.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
"reference": "f88f8936517d54ae6d589166810877fb2015d0a2"
"reference": "42c4c2eec485ee3e159ec9884f95b431287edde4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/f88f8936517d54ae6d589166810877fb2015d0a2",
"reference": "f88f8936517d54ae6d589166810877fb2015d0a2",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4",
"reference": "42c4c2eec485ee3e159ec9884f95b431287edde4",
"shasum": ""
},
"require": {
@ -1094,7 +1103,7 @@
"export",
"exporter"
],
"time": "2015-08-09 04:23:41"
"time": "2016-06-17 09:04:28"
},
{
"name": "sebastian/global-state",
@ -1149,16 +1158,16 @@
},
{
"name": "sebastian/recursion-context",
"version": "dev-master",
"version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/recursion-context.git",
"reference": "7ff5b1b3dcc55b8ab8ae61ef99d4730940856ee7"
"reference": "913401df809e99e4f47b27cdd781f4a258d58791"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/7ff5b1b3dcc55b8ab8ae61ef99d4730940856ee7",
"reference": "7ff5b1b3dcc55b8ab8ae61ef99d4730940856ee7",
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791",
"reference": "913401df809e99e4f47b27cdd781f4a258d58791",
"shasum": ""
},
"require": {
@ -1198,7 +1207,7 @@
],
"description": "Provides functionality to recursively process PHP variables",
"homepage": "http://www.github.com/sebastianbergmann/recursion-context",
"time": "2016-01-28 05:39:29"
"time": "2015-11-11 19:50:13"
},
{
"name": "sebastian/version",
@ -1237,16 +1246,16 @@
},
{
"name": "symfony/yaml",
"version": "2.8.x-dev",
"version": "v2.8.16",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "e4fbcc65f90909c999ac3b4dfa699ee6563a9940"
"reference": "dbe61fed9cd4a44c5b1d14e5e7b1a8640cfb2bf2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/e4fbcc65f90909c999ac3b4dfa699ee6563a9940",
"reference": "e4fbcc65f90909c999ac3b4dfa699ee6563a9940",
"url": "https://api.github.com/repos/symfony/yaml/zipball/dbe61fed9cd4a44c5b1d14e5e7b1a8640cfb2bf2",
"reference": "dbe61fed9cd4a44c5b1d14e5e7b1a8640cfb2bf2",
"shasum": ""
},
"require": {
@ -1282,7 +1291,7 @@
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
"time": "2016-03-29 19:00:15"
"time": "2017-01-03 13:49:52"
}
],
"aliases": [],
@ -1290,7 +1299,7 @@
"stability-flags": {
"bower-asset/jquery": 0
},
"prefer-stable": false,
"prefer-stable": true,
"prefer-lowest": false,
"platform": {
"php": ">=5.4.0",
@ -1298,5 +1307,8 @@
"ext-ctype": "*",
"lib-pcre": "*"
},
"platform-dev": []
"platform-dev": [],
"platform-overrides": {
"php": "5.4"
}
}

58
contrib/completion/bash/yii

@ -0,0 +1,58 @@
# 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]}"
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"
case $state in
command)
# 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 -F _yii ./yii yii

38
contrib/completion/zsh/_yii

@ -0,0 +1,38 @@
#compdef yii
_yii() {
local state command lastArgument commands options executive
lastArgument=${words[${#words[@]}]}
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"
case $state in
command)
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

30
docs/documentation_style_guide.md

@ -11,13 +11,16 @@ 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:
@ -32,7 +35,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
{
@ -47,13 +50,18 @@ 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
## Validating the docs
The following are some scripts that help find broken links and other issues in the guide:
@ -62,4 +70,18 @@ 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.

3
docs/guide-de/translators.json

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

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

@ -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);
```
@ -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.

2
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 integer un sello de tiempo UNIX que representa el tiempo de modificación de la página
* @return int un sello de tiempo UNIX que representa el tiempo de modificación de la página
*/
function ($action, $params)
```

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

@ -3,7 +3,7 @@ Autocarga de clases
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/proposed/psr-4-autoloader/psr-4-autoloader.md).
[estandard PSR-4](https://github.com/php-fig/fig-standards/blob/master/accepted/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,

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

@ -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) {
@ -237,7 +237,7 @@ invocación de los gestores de eventos a nivel de clase.
use yii\base\Event;
Event::on(Foo::className(), Foo::EVENT_HELLO, function ($event) {
echo $event->sender; // displays "app\models\Foo"
var_dump($event->sender); // displays "null"
});
Event::trigger(Foo::className(), Foo::EVENT_HELLO);

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

@ -14,7 +14,7 @@ Yii DAO soporta las siguientes bases de datos:
- [MySQL](http://www.mysql.com/)
- [MariaDB](https://mariadb.com/)
- [SQLite](http://sqlite.org/)
- [PostgreSQL](http://www.postgresql.org/)
- [PostgreSQL](http://www.postgresql.org/): versión 8.4 o superior.
- [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.
@ -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();
```

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

@ -136,7 +136,7 @@ class m150101_185401_create_news_table extends Migration
La clase de migración de base de datos [[yii\db\Migration]] expone una conexión a la base de datos mediante la propiedad [[yii\db\Migration::db|db]].
Puedes utilizar esto para manipular el esquema de la base de datos utilizando métodos como se describen en
[Trabajando con Esquemas de Base de Datos](db-dao.md#working-with-database-schema-).
[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
@ -147,7 +147,7 @@ serán traducidos a los tipos físicos correspondientes. En el caso de MySQL, `T
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.
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`.
@ -185,14 +185,14 @@ Existe una lista de todos los métodos disponibles para la definición de tipos
Desde la versión 2.0.7 la consola provee una manera muy conveniente de generar migraciones.
Si el nombre de la migración tiene una forma especial, por ejemplo `create_xxx` o `drop_xxx` entonces el archivo de la migración generada
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
yii migrate/create create_post_table
```
esto genera
@ -201,7 +201,7 @@ esto genera
/**
* Handles the creation for table `post`.
*/
class m150811_220037_create_post extends Migration
class m150811_220037_create_post_table extends Migration
{
/**
* @inheritdoc
@ -226,7 +226,7 @@ class m150811_220037_create_post extends Migration
Para crear las columnas en ese momento, las puedes especificar vía la opción `--fields`.
```php
yii migrate/create create_post --fields="title:string,body:text"
yii migrate/create create_post_table --fields="title:string,body:text"
```
genera
@ -235,7 +235,7 @@ genera
/**
* Handles the creation for table `post`.
*/
class m150811_220037_create_post extends Migration
class m150811_220037_create_post_table extends Migration
{
/**
* @inheritdoc
@ -263,7 +263,7 @@ class m150811_220037_create_post extends Migration
Puedes especificar más parámetros para las columnas.
```php
yii migrate/create create_post --fields="title:string(12):notNull:unique,body:text"
yii migrate/create create_post_table --fields="title:string(12):notNull:unique,body:text"
```
genera
@ -272,7 +272,7 @@ genera
/**
* Handles the creation for table `post`.
*/
class m150811_220037_create_post extends Migration
class m150811_220037_create_post_table extends Migration
{
/**
* @inheritdoc
@ -304,7 +304,7 @@ class m150811_220037_create_post extends Migration
Desde 2.0.8 el generador soporta claves foráneas utilizando la palabra clave `foreignKey`.
```php
yii migrate/create create_post --fields="author_id:integer:notNull:foreignKey(user),category_id:integer:defaultValue(1):foreignKey,title:string,body:text"
yii migrate/create create_post_table --fields="author_id:integer:notNull:foreignKey(user),category_id:integer:defaultValue(1):foreignKey,title:string,body:text"
```
genera
@ -317,7 +317,7 @@ genera
* - `user`
* - `category`
*/
class m160328_040430_create_post extends Migration
class m160328_040430_create_post_table extends Migration
{
/**
* @inheritdoc
@ -422,13 +422,13 @@ una columna llamada `author_id` con una clave foránea a la tabla `user` mientra
### Eliminar Tabla
```php
yii migrate/create drop_post --fields="title:string(12):notNull:unique,body:text"
yii migrate/create drop_post_table --fields="title:string(12):notNull:unique,body:text"
```
genera
```php
class m150811_220037_drop_post extends Migration
class m150811_220037_drop_post_table extends Migration
{
public function up()
{
@ -448,19 +448,19 @@ class m150811_220037_drop_post extends Migration
### Agregar Columna
Si el nombre de la migración está en la forma `add_xxx_to_yyy` entonces el archivo generado contendrá
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_to_post --fields="position:integer"
yii migrate/create add_position_column_to_post_table --fields="position:integer"
```
genera
```php
class m150811_220037_add_position_to_post extends Migration
class m150811_220037_add_position_column_to_post_table extends Migration
{
public function up()
{
@ -476,17 +476,17 @@ class m150811_220037_add_position_to_post extends Migration
### Eliminar Columna
Si el nombre de la migración está en la forma `drop_xxx_from_yyy` entonces el archivo generado contendrá
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_from_post --fields="position:integer"
yii migrate/create drop_position_column_from_post_table --fields="position:integer"
```
genera
```php
class m150811_220037_drop_position_from_post extends Migration
class m150811_220037_drop_position_column_from_post_table extends Migration
{
public function up()
{
@ -502,11 +502,11 @@ class m150811_220037_drop_position_from_post extends Migration
### Agregar Tabla de Unión
Si el nombre de la migración está en la forma `create_junction_xxx_and_yyy` entonces se generará el código necesario
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_post_and_tag --fields="created_at:dateTime"
yii migrate/create create_junction_table_for_post_and_tag_tables --fields="created_at:dateTime"
```
genera
@ -519,7 +519,7 @@ genera
* - `post`
* - `tag`
*/
class m160328_041642_create_junction_post_and_tag extends Migration
class m160328_041642_create_junction_table_for_post_and_tag_tables extends Migration
{
/**
* @inheritdoc
@ -818,9 +818,9 @@ Hay varias maneras de personalizar el comando de migración.
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.
* `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.
@ -843,13 +843,13 @@ El comando de migración trae algunas opciones de línea de comandos que pueden
'drop_table' => '@yii/views/dropTableMigration.php',
'add_column' => '@yii/views/addColumnMigration.php',
'drop_column' => '@yii/views/dropColumnMigration.php',
'create_junction' => '@yii/views/createJunctionMigration.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.
una columna string de tamaño 12 que es not `null`.
El siguiente ejemplo muestra cómo se pueden utilizar estas opciones.

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

@ -116,7 +116,7 @@ del objeto, o una función anónima que debe devolver el valor que será utiliza
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
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.
@ -371,8 +371,9 @@ mediante la implementación de la interfaz [[yii\base\Arrayable|Arrayable]] en e
A menudo necesitarás comprobar está en un array o un grupo de elementos es un sub-grupo de otro.
A pesar de que PHP ofrece `in_array()`, este no soporta sub-grupos u objetos de tipo `\Traversable`.
Para ayudar en este tipo de pruebas, [[yii\base\ArrayHelper]] provee [[yii\base\ArrayHelper::isIn()|isIn()]]
y [[yii\base\ArrayHelper::isSubset()|isSubset()]] con la misma firma del método [[in_array()]].
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()](http://php.net/manual/en/function.in-array.php).
```php
// true

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

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

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

@ -97,6 +97,7 @@ es un atributo activo declarado en `scenarios()` y está asociado a una o varias
declaradas en `rules()`.
> Note: Es práctico darle nombre a las reglas, por ej:
>
> ```php
> public function rules()
> {
@ -175,7 +176,7 @@ La propiedad [[yii\validators\Validator::when|when]] toma un método invocable P
/**
* @param Model $model el modelo siendo validado
* @param string $attribute al atributo siendo validado
* @return boolean si la regla debe ser aplicada o no
* @return bool si la regla debe ser aplicada o no
*/
function ($model, $attribute)
```
@ -198,7 +199,7 @@ cuyo valor de retorno determina si debe aplicarse la regla o no. Por ejemplo,
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 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
@ -222,7 +223,7 @@ si estas están vacías. Puedes hacerlo utilizando el validador [default](tutori
```php
return [
// convierte "username" y "email" en null si estos están vacíos
// convierte "username" y "email" en `null` si estos están vacíos
[['username', 'email'], 'default'],
// convierte "level" a 1 si está vacío
@ -230,7 +231,7 @@ return [
];
```
Por defecto, una entrada se considera vacía si su valor es un string vacío, un array vacío o null.
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,
@ -241,7 +242,7 @@ con una función PHP invocable. Por ejemplo,
```
> 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.
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.
@ -374,7 +375,7 @@ class MyForm extends Model
> 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:
como `false` en las declaraciones de las reglas. Por ejemplo:
>
> ```php
> [
@ -511,9 +512,9 @@ y generará el código JavaScript apropiado para los validadores que soportan va
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
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,
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>
@ -665,7 +666,7 @@ Puedes utilizar validación basada en AJAX en este caso. Esta lanzará una petic
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:
de ese campo como `true` y especifica un único `id` de formulario:
```php
use yii\widgets\ActiveForm;
@ -682,7 +683,7 @@ ActiveForm::end();
```
Para habiliar la validación AJAX en el formulario entero, configura [[yii\widgets\ActiveForm::enableAjaxValidation|enableAjaxValidation]]
como true a nivel del formulario:
como `true` a nivel del formulario:
```php
$form = ActiveForm::begin([
@ -710,5 +711,5 @@ esta petición ejecutando la validación y devolviendo los errores en formato JS
> 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
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.

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

@ -33,7 +33,7 @@ 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

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

@ -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,6 +143,10 @@ 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));
}
}
```

2
docs/guide-es/rest-rate-limiting.md

@ -40,5 +40,5 @@ información sobre el límite actual de rango:
* `X-Rate-Limit-Remaining`, el número de peticiones restantes en el periodo de tiempo actual
* `X-Rate-Limit-Reset`, el número de segundos a esperar para pedir el máximo número de peticiones permitidas
Puedes desactivar estas cabeceras configurando [[yii\filters\RateLimiter::enableRateLimitHeaders]] a false,
Puedes desactivar estas cabeceras configurando [[yii\filters\RateLimiter::enableRateLimitHeaders]] a `false`,
tal y como en el anterior ejemplo.

2
docs/guide-es/rest-routing.md

@ -75,7 +75,7 @@ Por ejemplo, para soportar una nueva acción `search` por el punto final `GET /
Puedes haber notado que el ID del controlador `user` aparece en formato plural `users` en los puntos finales de las URLs.
Esto se debe a que [[yii\rest\UrlRule]] automáticamente pluraliza los IDs de los controladores al crear reglas URL hijas.
Puedes desactivar este comportamiento definiendo la propiedad [[yii\rest\UrlRule::pluralize]] como false.
Puedes desactivar este comportamiento definiendo la propiedad [[yii\rest\UrlRule::pluralize]] como `false`.
> Info: La pluralización de los IDs de los controladores es realizada por [[yii\helpers\Inflector::pluralize()]]. Este método respeta
reglas especiales de pluralización. Por ejemplo, la palabra `box` (caja) será pluralizada como `boxes` en vez de `boxs`.

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

@ -11,7 +11,7 @@ anteriormente. En particular, el gestor de errores de Yii hace lo siguiente para
* Soporta diferentes formatos de respuesta (response) de errores.
El [[yii\web\ErrorHandler|error handler]] esta habilitado de forma predeterminada. Se puede deshabilitar definiendo la
constante `YII_ENABLE_ERROR_HANDLER` con valor false en el [script de entrada (entry script)](structure-entry-scripts.md) de la aplicación.
constante `YII_ENABLE_ERROR_HANDLER` con valor `false` en el [script de entrada (entry script)](structure-entry-scripts.md) de la aplicación.
## Uso del Gestor de Errores <span id="using-error-handler"></span>

6
docs/guide-es/runtime-routing.md

@ -247,7 +247,7 @@ amigable. El resto de propiedades son opcionales. Sin embargo, la anterior confi
* [[yii\web\UrlManager::showScriptName|showScriptName]]: esta propiedad determina si el script de entrada debe ser
incluido en las URLs generadas. Por ejemplo, en lugar de crear una URL `/index.php/post/100`, estableciendo la
propiedad con valor true, la URL que se generará sera `/post/100`.
propiedad con valor `true`, la URL que se generará sera `/post/100`.
* [[yii\web\UrlManager::enableStrictParsing|enableStrictParsing]]: esta propiedad determina si se habilita la
conversión de petición estricta, si se habilita, la URL solicitada tiene que encajar al menos con uno de las
[[yii\web\UrlManager::rules|rules]] para poder ser tratada como una petición valida, o se lanzará una
@ -351,8 +351,8 @@ Cuando se usen las reglas para convertir URLs:
- `/index.php/post/100` se convierte en la ruta `post/view` y el parámetro `id` cuyo valor es 100 usando la segunda
regla;
- `/index.php/posts/php` provocara una [[yii\web\NotFoundHttpException]] cuando
[[yii\web\UrlManager::enableStrictParsing]] sea true, ya que no coincide ninguno de los parámetros . Si
[[yii\web\UrlManager::enableStrictParsing]] es false (valor predeterminado), se devolverá como ruta la parte de
[[yii\web\UrlManager::enableStrictParsing]] sea `true`, ya que no coincide ninguno de los parámetros . Si
[[yii\web\UrlManager::enableStrictParsing]] es `false` (valor predeterminado), se devolverá como ruta la parte de
información `posts/php`.
Y cuando las se usen las reglas para crear URLs:

6
docs/guide-es/runtime-sessions-cookies.md

@ -179,7 +179,7 @@ $session->setFlash('postDeleted', 'You have successfully deleted your post.');
echo $session->getFlash('postDeleted');
// Petición #3
// $result será false ya que el mensaje flash ha sido borrado automáticamente
// $result será `false` ya que el mensaje flash ha sido borrado automáticamente
$result = $session->hasFlash('postDeleted');
```
@ -262,7 +262,7 @@ unset($cookies['language']);
Además de [[yii\web\Cookie::name|name]], [[yii\web\Cookie::value|value]] las propiedades que se muestran en los anteriores ejemplos, la clase [[yii\web\Cookie]] también define otras propiedades para representar toda la información posible de las cookies, tal como [[yii\web\Cookie::domain|domain]], [[yii\web\Cookie::expire|expire]]. Puedes configurar estas propiedades según sea necesario para preparar una cookie y luego añadirlo a la colección de cookies de la respuesta.
> Note: Para mayor seguridad, el valor por defecto de [[yii\web\Cookie::httpOnly]] es true. Esto ayuda a mitigar el riesgo del acceso a la cookie protegida por script desde el lado del cliente (si el navegador lo soporta). Puedes leer el [httpOnly wiki article](https://www.owasp.org/index.php/HttpOnly) para más detalles.
> Note: Para mayor seguridad, el valor por defecto de [[yii\web\Cookie::httpOnly]] es `true`. Esto ayuda a mitigar el riesgo del acceso a la cookie protegida por script desde el lado del cliente (si el navegador lo soporta). Puedes leer el [httpOnly wiki article](https://www.owasp.org/index.php/HttpOnly) para más detalles.
### Validación de la Cookie <span id="cookie-validation"></span>
@ -271,7 +271,7 @@ Cuando estás leyendo y enviando cookies a través de los componentes `request`
> Info: Si falla la validación de una cookie, aún puedes acceder a la misma a través de `$_COOKIE`. Esto sucede porque librerías de terceros pueden manipular de forma propia las cookies, lo cual no implica la validación de las mismas.
La validación de cookies es habilitada por defecto. Puedes desactivar lo ajustando la propiedad [[yii\web\Request::enableCookieValidation]] a false, aunque se recomienda encarecidamente que no lo haga.
La validación de cookies es habilitada por defecto. Puedes desactivar lo ajustando la propiedad [[yii\web\Request::enableCookieValidation]] a `false`, aunque se recomienda encarecidamente que no lo haga.
> Note: Las cookies que son directamente leídas/enviadas vía `$_COOKIE` y `setcookie()` no serán validadas.

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

@ -304,11 +304,11 @@ class RbacController extends Controller
```
> Note: Si estas utilizando el template avanzado, necesitas poner tu `RbacController` dentro del directorio `console/controllers`
y cambiar el espacio de nombres a `console/controllers`.
y cambiar el espacio de nombres a `console\controllers`.
Después de ejecutar el comando `yii rbac/init`, obtendremos la siguiente jerarquía:
![Simple RBAC hierarchy](../guide/images/rbac-hierarchy-1.png "Simple RBAC hierarchy")
![Simple RBAC hierarchy](images/rbac-hierarchy-1.png "Simple RBAC hierarchy")
"Author" puede crear un post, "admin" puede actualizar posts y hacer todo lo que puede hacer "author".
@ -362,10 +362,10 @@ class AuthorRule extends Rule
public $name = 'isAuthor';
/**
* @param string|integer $user el ID de usuario.
* @param string|int $user el ID de usuario.
* @param Item $item el rol o permiso asociado a la regla
* @param array $params parámetros pasados a ManagerInterface::checkAccess().
* @return boolean un valor indicando si la regla permite al rol o permiso con el que está asociado.
* @return bool un valor indicando si la regla permite al rol o permiso con el que está asociado.
*/
public function execute($user, $item, $params)
{
@ -399,7 +399,7 @@ $auth->addChild($author, $updateOwnPost);
Ahora tenemos la siguiente jerarquía:
![RBAC hierarchy with a rule](../guide/images/rbac-hierarchy-2.png "RBAC hierarchy with a rule")
![RBAC hierarchy with a rule](images/rbac-hierarchy-2.png "RBAC hierarchy with a rule")
### Comprobación de Acceso <span id="access-check"></span>
@ -416,7 +416,7 @@ if (\Yii::$app->user->can('createPost')) {
Si el usuario actual es Jane con `ID=1`, comenzamos desde `createPost` y tratamos de alcanzar a `Jane`:
![Access check](../guide/images/rbac-access-check-1.png "Access check")
![Access check](images/rbac-access-check-1.png "Access check")
Con el fin de comprobar si un usuario puede actualizar un post, necesitamos pasarle un parámetro adicional requerido por `AuthorRule`, descrito antes:
@ -429,7 +429,7 @@ if (\Yii::$app->user->can('updatePost', ['post' => $post])) {
Aquí es lo que sucede si el usuario actual es John:
![Access check](../guide/images/rbac-access-check-2.png "Access check")
![Access check](images/rbac-access-check-2.png "Access check")
Comenzamos desde `updatePost` y pasamos por `updateOwnPost`. Con el fin de pasar la comprobación de acceso, `AuthorRule`
debe devolver `true` desde su método `execute()`. El método recive `$params` desde la llamada al método `can()`, cuyo valor es
@ -437,7 +437,7 @@ debe devolver `true` desde su método `execute()`. El método recive `$params` d
En caso de Jane es un poco más simple, ya que ella es un "admin":
![Access check](../guide/images/rbac-access-check-3.png "Access check")
![Access check](images/rbac-access-check-3.png "Access check")
### Utilizar Roles por Defecto <span id="using-default-roles"></span>
@ -503,7 +503,7 @@ $auth->addChild($admin, $author);
Tenga en cuenta que en el ejemplo anterior, dado que "author" es agregado como hijo de "admin", cuando implementes el método `execute()`
de la clase de la regla, necesitas respetar esta jerarquía. Esto se debe a que cuando el nombre del rol es "author",
el método `execute()` devolverá true si el grupo de usuario es tanto 1 como 2 (lo que significa que el usuario se encuentra en
el método `execute()` devolverá `true` si el grupo de usuario es tanto 1 como 2 (lo que significa que el usuario se encuentra en
cualquiera de los dos grupos, "admin" o "author").
Luego, configura `authManager` enumerando los dos roles en [[yii\rbac\BaseManager::$defaultRoles]]:
@ -522,6 +522,6 @@ return [
```
Ahora si realizas una comprobación de acceso, tanto el rol `admin` y como el rol `author` serán comprobados evaluando
las reglas asociadas con ellos. Si la regla devuelve true, significa que la regla aplica al usuario actual.
las reglas asociadas con ellos. Si la regla devuelve `true`, significa que la regla aplica al usuario actual.
Basado en la implementación de la regla anterior, esto significa que si el valor `group` en un usuario es 1, el rol `admin`
se aplicaría al usuario; y si el valor de `group` es 2, se le aplicaría el rol `author`.

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

@ -40,7 +40,7 @@ ejecutando el comando `composer self-update`
Teniendo Composer instalado, puedes instalar Yii ejecutando los siguientes comandos en un directorio accesible vía Web:
```bash
composer global require "fxp/composer-asset-plugin:~1.1.1"
composer global require "fxp/composer-asset-plugin:^1.2.0"
composer create-project --prefer-dist yiisoft/yii2-app-basic basic
```

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

@ -215,14 +215,12 @@ para controladores específicos. En el siguiente ejemplo, `account` será mapead
```php
[
'controllerMap' => [
[
'account' => 'app\controllers\UserController',
'article' => [
'class' => 'app\controllers\PostController',
'enableCsrfValidation' => false,
],
],
],
]
```

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

@ -43,7 +43,7 @@ a continuación:
"require": {
// ... otras dependencias
"yiisoft/yii2-imagine": "*"
"yiisoft/yii2-imagine": "~2.0.0"
}
}
```
@ -149,7 +149,7 @@ muestra el archivo `composer.json` para la extensión `yiisoft/yii2-imagine`:
// dependencias del paquete
"require": {
"yiisoft/yii2": "*",
"yiisoft/yii2": "~2.0.0",
"imagine/imagine": "v0.5.0"
},
@ -420,6 +420,8 @@ se describe en la subsección [Uso de Extensiones](#using-extensions)
[Faker](https://github.com/fzaninotto/Faker) y generar datos automáticamente.
- [yiisoft/yii2-gii](https://github.com/yiisoft/yii2-gii): proporciona un generador de código basado den Web altamente
extensible y que puede usarse para generar modelos, formularios, módulos, CRUD, etc. rápidamente.
- [yiisoft/yii2-httpclient](https://github.com/yiisoft/yii2-httpclient):
provides an HTTP client.
- [yiisoft/yii2-imagine](https://github.com/yiisoft/yii2-imagine): proporciona funciones comunes de manipulación de
imágenes basadas en [Imagine](http://imagine.readthedocs.org/).
- [yiisoft/yii2-jui](https://github.com/yiisoft/yii2-jui): proporciona un conjunto de widgets que encapsulan las

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

@ -234,7 +234,7 @@ para ayudar al usuario a corregir estos errores.
Se puede llamar a [[yii\base\Model::validate()]] para validar los datos recibidos. El método se usará para validar las
reglas declaradas en [[yii\base\Model::rules()]] para validar cada atributo relevante. Si no se encuentran errores, se
devolverá true. De otro modo, este almacenará los errores en la propiedad [[yii\base\Model::errors]] y devolverá falso.
devolverá `true`. De otro modo, este almacenará los errores en la propiedad [[yii\base\Model::errors]] y devolverá falso.
Por ejemplo:
```php

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

@ -310,7 +310,7 @@ yii fixture/load User
yii fixture User
// carga varios fixtures
yii fixture User UserProfile
yii fixture "User, UserProfile"
// carga todos los fixtures
yii fixture/load "*"
@ -319,7 +319,7 @@ yii fixture/load "*"
yii fixture "*"
// carga todos los fixtures excepto uno
yii fixture "*" -DoNotLoadThisOne
yii fixture "*, -DoNotLoadThisOne"
// carga fixtures, pero los busca en diferente espacio de nombre. El espacio de nombre por defecto es: tests\unit\fixtures.
yii fixture User --namespace='alias\my\custom\namespace'
@ -340,13 +340,13 @@ Para descargar un fixture, ejecuta el siguiente comando:
yii fixture/unload User
// descarga varios fixtures
yii fixture/unload User,UserProfile
yii fixture/unload "User, UserProfile"
// descarga todos los fixtures
yii fixture/unload "*"
// descarga todos los fixtures excepto uno
yii fixture/unload "*" -DoNotUnloadThisOne
yii fixture/unload "*, -DoNotUnloadThisOne"
```

6
docs/guide-es/translators.json

@ -0,0 +1,6 @@
[
"Antonio Ramirez",
"Daniel Gómez Pan",
"'larnu'",
"Luciano Baraglia"
]

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

@ -25,19 +25,19 @@ A continuación, vamos a describir el uso principal y las propiedades de cada va
// comprueba si "selected" es 0 o 1, sin mirar el tipo de dato
['selected', 'boolean'],
// comprueba si "deleted" es del tipo booleano, alguno entre true o false
// comprueba si "deleted" es del tipo booleano, alguno entre `true` o `false`
['deleted', 'boolean', 'trueValue' => true, 'falseValue' => false, 'strict' => true],
]
```
Este validador comprueba si el valor de la entrada (input) es booleano.
- `trueValue`: El valor representando *true*. Valor por defecto a `'1'`.
- `falseValue`: El valor representando *false*. Valor por defecto a `'0'`.
- `trueValue`: El valor representando `true`. Valor por defecto a `'1'`.
- `falseValue`: El valor representando `false`. Valor por defecto a `'0'`.
- `strict`: Si el tipo del valor de la entrada (input) debe corresponder con `trueValue` y `falseValue`. Valor por defecto a `false`.
> Note: Ya que los datos enviados con la entrada, vía formularios HTML,son todos cadenas (strings), usted debe normalmente dejar la propiedad [[yii\validators\BooleanValidator::strict|strict]] a false.
> Note: Ya que los datos enviados con la entrada, vía formularios HTML,son todos cadenas (strings), usted debe normalmente dejar la propiedad [[yii\validators\BooleanValidator::strict|strict]] a `false`.
## [[yii\captcha\CaptchaValidator|captcha]] <span id="captcha"></span>
@ -50,10 +50,10 @@ Este validador comprueba si el valor de la entrada (input) es booleano.
Este validador es usualmente usado junto con [[yii\captcha\CaptchaAction]] y [[yii\captcha\Captcha]] para asegurarse que una entrada es la misma que lo es el código de verificación que enseña el widget [[yii\captcha\Captcha|CAPTCHA]].
- `caseSensitive`: cuando la comparación del código de verificación depende de que sean mayúsculas y minúsculas (case sensitive). Por defecto a false.
- `caseSensitive`: cuando la comparación del código de verificación depende de que sean mayúsculas y minúsculas (case sensitive). Por defecto a `false`.
- `captchaAction`: la [ruta](structure-controllers.md#routes) correspondiente a
[[yii\captcha\CaptchaAction|CAPTCHA action]] que representa (render) la imagen CAPTCHA. Por defecto`'site/captcha'`.
- `skipOnEmpty`: cuando la validación puede saltarse si la entrada está vacía. Por defecto a false, lo caul permite que la entrada sea necesaria (required).
- `skipOnEmpty`: cuando la validación puede saltarse si la entrada está vacía. Por defecto a `false`, lo caul permite que la entrada sea necesaria (required).
## [[yii\validators\CompareValidator|compare]] <span id="compare"></span>
@ -158,12 +158,12 @@ Esta validador comprueba si el valor de entrada es un número de tipo doble. Es
Este validador comprueba si el valor de entrada es una dirección válida de email.
- `allowName`: indica cuando permitir el nombre en la dirección de email (p.e. `John Smith <john.smith@example.com>`). Por defecto a false.
- `allowName`: indica cuando permitir el nombre en la dirección de email (p.e. `John Smith <john.smith@example.com>`). Por defecto a `false`.
- `checkDNS`, comprobar cuando el dominio del email existe y tiene cualquier registro A o MX.
Es necesario ser consciente que esta comprobación puede fallar debido a problemas temporales de DNS, incluso si el la dirección es válida actualmente.
Por defecto a false.
Por defecto a `false`.
- `enableIDN`, indica cuando el proceso de validación debe tener en cuenta el informe de IDN (internationalized domain names).
Por defecto a false. Dese cuenta que para poder usar la validación de IDN has de instalar y activar la extensión de PHP `intl`, o será lanzada una excepción.
Por defecto a `false`. Dese cuenta que para poder usar la validación de IDN has de instalar y activar la extensión de PHP `intl`, o será lanzada una excepción.
## [[yii\validators\ExistValidator|exist]] <span id="exist"></span>
@ -197,7 +197,7 @@ Este validador comprueba si el valor de entrada puede ser encontrado en una colu
Puede usar una array para validar la existencia de múltiples columnas al mismo tiempo. El array de valores son los atributos que pueden ser usados para validar la existencia, mientras que las claves del array son los atributos a ser validados. Si la clave y el valor son los mismos, solo en ese momento puedes especificar el valor.
- `filter`: filtro adicional a aplicar a la consulta de la base de datos usado para comprobar la existencia de una valor de entrada.
Esto puede ser una cadena o un array representando la condición de la consulta (referirse a [[yii\db\Query::where()]] sobre el formato de la condición de consulta), o una función anónima con la signatura `function ($query)`, donde `$query` es el objeto [[yii\db\Query|Query]] que puedes modificar en la función.
- `allowArray`: indica cuando permitir que el valor de entrada sea un array. Por defecto a false.Si la propiedad es true y la entrada es un array, cada elemento del array debe existir en la columna destino. Nota que esta propiedad no puede ser true si estás validando, por el contrario, múltiple columnas poniendo el valor del atributo `targetAttribute` como que es un array.
- `allowArray`: indica cuando permitir que el valor de entrada sea un array. Por defecto a `false`.Si la propiedad es `true` y la entrada es un array, cada elemento del array debe existir en la columna destino. Nota que esta propiedad no puede ser `true` si estás validando, por el contrario, múltiple columnas poniendo el valor del atributo `targetAttribute` como que es un array.
## [[yii\validators\FileValidator|file]] <span id="file"></span>
@ -213,13 +213,13 @@ Este validador comprueba si el valor de entrada puede ser encontrado en una colu
Este validador comprueba que el fichero subido es el adecuado.
- `extensions`: una lista de extensiones de ficheros que pueden ser subidos. Esto puede ser tanto un array o una cadena conteniendo nombres de extensiones de ficheros separados por un espacio o coma (p.e. "gif, jpg").
Los nombres de las extensiones no diferencian mayúsculas de minúsculas (case-insensitive). Por defecto a null, permitiendo todas los nombres de extensiones de fichero.
Los nombres de las extensiones no diferencian mayúsculas de minúsculas (case-insensitive). Por defecto a `null`, permitiendo todas los nombres de extensiones de fichero.
- `mimeTypes`: una lista de tipos de ficheros MIME que están permitidos subir. Esto puede ser tanto un array como una cadena conteniendo tipos de fichero MIME separados por un espacio o una coma (p.e. "image/jpeg, image/png").
Los tipos Mime no diferencian mayúsculas de minúsculas (case-insensitive). Por defecto a null, permitiendo todos los tipos MIME.
- `minSize`: el número de bytes mínimo requerido para el fichero subido. El tamaño del fichero ha de ser superior a este valor. Por defecto a null, lo que significa sin límite inferior.
- `maxSize`: El número máximo de bytes del fichero a subir. El tamaño del fichero ha de ser inferior a este valor. Por defecto a null, significando no tener límite superior.
Los tipos Mime no diferencian mayúsculas de minúsculas (case-insensitive). Por defecto a `null`, permitiendo todos los tipos MIME.
- `minSize`: el número de bytes mínimo requerido para el fichero subido. El tamaño del fichero ha de ser superior a este valor. Por defecto a `null`, lo que significa sin límite inferior.
- `maxSize`: El número máximo de bytes del fichero a subir. El tamaño del fichero ha de ser inferior a este valor. Por defecto a `null`, significando no tener límite superior.
- `maxFiles`: el máximo número de ficheros que determinado atributo puede manejar. Por defecto a 1, lo que significa que la entrada debe de ser sólo un fichero. Si es mayor que 1, entonces la entrada tiene que ser un array conteniendo como máximo el número `maxFiles` de elementos que representan los ficheros a subir.
- `checkExtensionByMimeType`: cuando comprobar la extensión del fichero por el tipo MIME. Si la extensión producida por la comprobación del tipo MIME difiere la extensión del fichero subido, el fichero será considerado como no válido. Por defecto a true, significando que realiza este tipo de comprobación.
- `checkExtensionByMimeType`: cuando comprobar la extensión del fichero por el tipo MIME. Si la extensión producida por la comprobación del tipo MIME difiere la extensión del fichero subido, el fichero será considerado como no válido. Por defecto a `true`, significando que realiza este tipo de comprobación.
`FileValidator` es usado con [[yii\web\UploadedFile]]. Por favor, refiérase a la sección [Subida de ficheros](input-file-upload.md) para una completa cobertura sobre la subida de ficheros y llevar a cabo la validación de los ficheros subidos.
@ -243,8 +243,8 @@ Este validador no valida datos. En su lugar, aplica un filtro sobre el valor de
- `filter`: una retrollamada (callback) de PHP que define un filtro. Tiene que ser un nombre de función global, una función anónima, etc.
La forma de la función ha de ser `function ($value) { return $newValue; }`. Tiene que contener un valor esta propiedad.
- `skipOnArray`: cuando evitar el filtro si el valor de la entrada es un array. Por defecto a false.
A tener en cuenta que si el filtro no puede manejar una entrada de un array, debes poner esta propiedad a true. En otro caso algún error PHP puede ocurrir.
- `skipOnArray`: cuando evitar el filtro si el valor de la entrada es un array. Por defecto a `false`.
A tener en cuenta que si el filtro no puede manejar una entrada de un array, debes poner esta propiedad a `true`. En otro caso algún error PHP puede ocurrir.
> Consejo (Tip): Si quieres recortar los valores de entrada, puedes usar directamente el validador [Recorte (trim)](#trim).
@ -263,10 +263,10 @@ Este validador no valida datos. En su lugar, aplica un filtro sobre el valor de
Este validador comprueba si el valor de entrada representa un fichero de imagen válido. Extiende al validador [Fichero (file)](#file) y, por lo tanto, hereda todas sus propiedades. Además, soporta las siguientes propiedades adicionales específicas para la validación de imágenes:
- `minWidth`: el mínimo ancho de la imagen. Por defecto a null, indicando que no hay límite inferior.
- `maxWidth`: el máximo ancho de la imagen. Por defecto a null, indicando que no hay límite superior.
- `minHeight`: el mínimo alto de la imagen. Por defecto a null, indicando que no hay límite inferior.
- `maxHeight`: el máximo alto de la imagen. Por defecto a null, indicando que no hay límite superior.
- `minWidth`: el mínimo ancho de la imagen. Por defecto a `null`, indicando que no hay límite inferior.
- `maxWidth`: el máximo ancho de la imagen. Por defecto a `null`, indicando que no hay límite superior.
- `minHeight`: el mínimo alto de la imagen. Por defecto a `null`, indicando que no hay límite inferior.
- `maxHeight`: el máximo alto de la imagen. Por defecto a `null`, indicando que no hay límite superior.
## [[yii\validators\RangeValidator|in]] <span id="in"></span>
@ -281,9 +281,9 @@ Este validador comprueba si el valor de entrada representa un fichero de imagen
Este validador comprueba si el valor de entrada puede encontrarse entre determinada lista de valores.
- `range`: una lista de determinados valores dentro de los cuales el valor de entrada debe de ser mirado.
- `strict`: cuando la comparación entre el valor de entrada y los valores determinados debe de ser estricta (ambos el tipo y el valor han de ser iguales). Por defecto a false.
- `not`: cuando el resultado de la validación debe de ser invertido. Por defecto a false. Cuando esta propiedad está a true, el validador comprueba que el valor de entrada NO ESTÁ en la determinada lista de valores.
- `allowArray`: si se permite que el valor de entrada sea un array. Cuando es true y el valor de entrada es un array, cada elemento en el array debe de ser encontrado en la lista de valores determinada,o la validación fallará.
- `strict`: cuando la comparación entre el valor de entrada y los valores determinados debe de ser estricta (ambos el tipo y el valor han de ser iguales). Por defecto a `false`.
- `not`: cuando el resultado de la validación debe de ser invertido. Por defecto a `false`. Cuando esta propiedad está a `true`, el validador comprueba que el valor de entrada NO ESTÁ en la determinada lista de valores.
- `allowArray`: si se permite que el valor de entrada sea un array. Cuando es `true` y el valor de entrada es un array, cada elemento en el array debe de ser encontrado en la lista de valores determinada,o la validación fallará.
## [[yii\validators\NumberValidator|integer]] <span id="integer"></span>
@ -313,7 +313,7 @@ Esta validador comprueba si el valor de entrada es un entero.
Este validador comprueba si el valor de entrada coincide con la expresión regular especificada.
- `pattern`: la expresión regular conla que el valor de entrada debe coincidir. Esta propiedad no puede estar vacía, o se lanzará una excepción.
- `not`: indica cuando invertir el resultado de la validación. Por defecto a false, significando que la validación es exitosa solamente si el valor de entrada coincide con el patrón. Si esta propiedad está a true, la validación es exitosa solamente si el valor de entrada NO coincide con el patrón.
- `not`: indica cuando invertir el resultado de la validación. Por defecto a `false`, significando que la validación es exitosa solamente si el valor de entrada coincide con el patrón. Si esta propiedad está a `true`, la validación es exitosa solamente si el valor de entrada NO coincide con el patrón.
## [[yii\validators\NumberValidator|number]] <span id="number"></span>
@ -343,9 +343,9 @@ Este validador comprueba si el valor de entrada es un número. Es equivalente al
El validador comprueba si el valor de entrada es provisto y no está vacío.
- `requiredValue`: el valor deseado que la entrada debería tener. Si no tiene valor, significa que la entrada no puede estar vacía.
- `strict`: indica como comprobar los tipos de los datos al validar un valor. Por defecto a false.
Cuando `requiredValue` no tiene valor, si esta propiedad es true, el validador comprueba si el valor de entrada no es estrictamente null; si la propiedad es false, el validador puede usar una regla suelta para determinar si el valor está vacío o no.
Cuando `requiredValue` tiene valor, la comparación entre la entrada y `requiredValue` comprobará tambien los tipos de los datos si esta propiedad es true.
- `strict`: indica como comprobar los tipos de los datos al validar un valor. Por defecto a `false`.
Cuando `requiredValue` no tiene valor, si esta propiedad es `true`, el validador comprueba si el valor de entrada no es estrictamente `null`; si la propiedad es `false`, el validador puede usar una regla suelta para determinar si el valor está vacío o no.
Cuando `requiredValue` tiene valor, la comparación entre la entrada y `requiredValue` comprobará tambien los tipos de los datos si esta propiedad es `true`.
> Info: Como determinar si un valor está vacío o no es un tópico separado cubierto en la sección [Valores vacíos](input-validation.md#handling-empty-inputs).
@ -439,7 +439,7 @@ Este validador comprueba si el valor de entrada es una URL válida.
- `validSchemes`: un array especificando el esquema URI que debe ser considerado válido. Por defecto contiene `['http', 'https']`, significando que ambas URLS `http` y `https` son consideradas válidas.
- `defaultScheme`: el esquema de URI a poner como prefijo a la entrada si no tiene la parte del esquema.
Por defecto a null, significando que no modifica el valor de entrada.
Por defecto a `null`, significando que no modifica el valor de entrada.
- `enableIDN`: Si el validador debe formar parte del registro IDN (internationalized domain names).
Por defecto a false. Nota que para usar la validación IDN tienes que instalar y activar la extensión PHP `intl`, en otro caso una excepción será lanzada.
Por defecto a `false`. Nota que para usar la validación IDN tienes que instalar y activar la extensión PHP `intl`, en otro caso una excepción será lanzada.

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

@ -50,6 +50,6 @@ Utilizar el Template
Eso es todo lo que se necesita para crear un nuevo template de proyecto Yii. Ahora puedes crear tus propios proyectos a partir de este template:
```
composer global require "fxp/composer-asset-plugin:~1.1.1"
composer global require "fxp/composer-asset-plugin:^1.2.0"
composer create-project --prefer-dist --stability=dev mysoft/yii2-app-coolone new-project
```

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

@ -38,8 +38,8 @@ En el código de arriba, tanto Smarty como Twig son configurados para ser utiliz
tu archivo `composer.json` para incluirlos:
```
"yiisoft/yii2-smarty": "*",
"yiisoft/yii2-twig": "*",
"yiisoft/yii2-smarty": "~2.0.0",
"yiisoft/yii2-twig": "~2.0.0",
```
Ese código será agregado a la sección `require` de `composer.json`. Después de realizar ese cambio y guardar el archivo, puedes instalar estas extensiones ejecutando `composer update --prefer-dist` en la línea de comandos.

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

@ -82,7 +82,7 @@ instalar Yii , e iniciar Yii.
Si el sistema de terceros usa Composer para manejar sus dependencias, simplemente ejecuta estos comandos
para instalar Yii:
composer global require "fxp/composer-asset-plugin:~1.1.1"
composer global require "fxp/composer-asset-plugin:^1.2.0"
composer require yiisoft/yii2
composer install

6
docs/guide-fr/blocktypes.json

@ -0,0 +1,6 @@
{
"Warning:": "Attention :",
"Note:": "Note :",
"Info:": "Info :",
"Tip:": "Conseil :"
}

345
docs/guide-fr/caching-data.md

@ -0,0 +1,345 @@
Mise en cache de données
========================
La mise en cache de données consiste à stocker quelques variables PHP dans un cache et à les y retrouver plus tard.
C'est également la base pour des fonctionnalités de mise en cache plus avancées, comme la [mise en cache de requêtes](#query-caching) et la [mise en cache de pages](caching-page.md).
Le code qui suit est un modèle d'utilisation typique de la mise en cache de données, dans lequel `cache` fait référence à un [composant de mise en cache](#cache-components) :
```php
// tente de retrouver la donnée $data dans le cache
$data = $cache->get($key);
if ($data === false) {
// la donnée $data n'a pas été trouvée dans le cache, on la recalcule
$data = $this->calculateSomething();
// stocke la donnée $data dans le cache de façon à la retrouver la prochaine fois
$cache->set($key, $data);
}
// la donnée $data est disponible ici
```
Depuis la version 2.0.11, le [composant de mise en cache](#cache-components) fournit la méthode [[yii\caching\Cache::getOrSet()|getOrSet()]] qui simplifie le code pour l'obtention, le calcul et le stockage des données. Le code qui suit fait exactement la même chose que l'exemple précédent :
```php
$data = $cache->getOrSet($key, function () {
return $this->calculateSomething();
});
```
Lorsque le cache possède une donnée associée à la clé `$key`, la valeur en cache est retournée. Autrement, la fonction anonyme passée est exécutée pour calculer cette valeur qui est mise en cache et retournée.
Si la fonction anonyme a besoin de quelques données en dehors de la portée courante, vous pouvez les passer en utilisant l'instruction `use`. Par exemple :
```php
$user_id = 42;
$data = $cache->getOrSet($key, function () use ($user_id) {
return $this->calculateSomething($user_id);
});
```
> Note : la méthode [[yii\caching\Cache::getOrSet()|getOrSet()]] prend également en charge la durée et les dépendances.
Reportez-vous à [Expiration de la mise en cache](#cache-expiration) et à [Dépendances de mise en cache](#cache-dependencies) pour en savoir plus.
## Composants de mise en cache <span id="cache-components"></span>
La mise en cache s'appuie sur ce qu'on appelle les *composants de mise en cache* qui représentent des supports de mise en cache tels que les mémoires, les fichiers et les bases de données.
Les composants de mise en cache sont généralement enregistrés en tant que [composants d'application](structure-application-components.md) de façon à ce qu'ils puissent être configurables et accessibles globalement. Le code qui suit montre comment configurer le composant d'application `cache` pour qu'il utilise [memcached](http://memcached.org/) avec deux serveurs de cache :
```php
'components' => [
'cache' => [
'class' => 'yii\caching\MemCache',
'servers' => [
[
'host' => 'server1',
'port' => 11211,
'weight' => 100,
],
[
'host' => 'server2',
'port' => 11211,
'weight' => 50,
],
],
],
],
```
Vous pouvez accéder au composant de mise en cache configuré ci-dessus en utilisant l'expression `Yii::$app->cache`.
Comme tous les composants de mise en cache prennent en charge le même jeux d'API, vous pouvez remplacer le composant de mise en cache sous-jacent par un autre en le reconfigurant dans la configuration de l'application, cela sans modifier le code qui utilise le cache. Par exemple, vous pouvez modifier le code ci-dessus pour utiliser [[yii\caching\ApcCache|APC cache]] :
```php
'components' => [
'cache' => [
'class' => 'yii\caching\ApcCache',
],
],
```
> Tip: vous pouvez enregistrer de multiples composants d'application de mise en cache. Le composant nommé `cache` est utilisé par défaut par de nombreuses classes dépendantes d'un cache (p. ex.[[yii\web\UrlManager]]).
### Supports de stockage pour cache pris en charge <span id="supported-cache-storage"></span>
Yii prend en charge un large panel de supports de stockage pour cache. Ce qui suit est un résumé :
* [[yii\caching\ApcCache]]: utilise l'extension PHP [APC](http://php.net/manual/en/book.apc.php). Cette option peut être considérée comme la plus rapide lorsqu'on utilise un cache pour une grosse application centralisée (p. ex. un serveur, pas d'équilibrage de charge dédié, etc.).
* [[yii\caching\DbCache]]: utilise une table de base de données pour stocker les données en cache. Pour utiliser ce cache, vous devez créer une table comme spécifié dans [[yii\caching\DbCache::cacheTable]].
* [[yii\caching\DummyCache]]: tient lieu de cache à remplacer qui n'assure pas de mise en cache réelle. Le but de ce composant est de simplifier le code qui a besoin de vérifier la disponibilité du cache. Par exemple, lors du développement ou si le serveur ne dispose pas de la prise en charge d'un cache, vous pouvez configurer un composant de mise en cache pour qu'il utilise ce cache. Lorsque la prise en charge réelle de la mise en cache est activée, vous pouvez basculer sur le composant de mise en cache correspondant. Dans les deux cas, vous pouvez utiliser le même code `Yii::$app->cache->get($key)` pour essayer de retrouver les données du cache sans vous préoccuper du fait que `Yii::$app->cache` puisse être `null`.
* [[yii\caching\FileCache]]: utilise des fichiers standards pour stocker les données en cache. Cela est particulièrement adapté à la mise en cache de gros blocs de données, comme le contenu d'une page.
* [[yii\caching\MemCache]]: utilise le [memcache](http://php.net/manual/en/book.memcache.php) PHP et l'extension [memcached](http://php.net/manual/en/book.memcached.php). Cette option peut être considérée comme la plus rapide lorsqu'on utilise un cache dans des applications distribuées (p. ex. avec plusieurs serveurs, l'équilibrage de charge, etc.).
* [[yii\redis\Cache]]: met en œuvre un composant de mise en cache basé sur un stockage clé-valeur [Redis](http://redis.io/)
(une version de redis égale ou supérieure à 2.6.12 est nécessaire).
* [[yii\caching\WinCache]]: utilise le [WinCache](http://iis.net/downloads/microsoft/wincache-extension) PHP
([voir aussi l'extension](http://php.net/manual/en/book.wincache.php)).
* [[yii\caching\XCache]]: utilise l'extension PHP [XCache](http://xcache.lighttpd.net/).
* [[yii\caching\ZendDataCache]]: utilise le
[cache de données Zend](http://files.zend.com/help/Zend-Server-6/zend-server.htm#data_cache_component.htm)
en tant que médium de cache sous-jacent.
> Tip: vous pouvez utiliser différents supports de stockage pour cache dans la même application. Une stratégie courante est d'utiliser un support de stockage pour cache basé sur la mémoire pour stocker des données de petite taille mais d'usage constant (p. ex. des données statistiques), et d'utiliser des supports de stockage pour cache basés sur des fichiers ou des bases de données pour stocker des données volumineuses et utilisées moins souvent (p. ex. des contenus de pages).
## Les API Cache <span id="cache-apis"></span>
Tous les composants de mise en cache dérivent de la même classe de base [[yii\caching\Cache]] et par conséquent prennent en charge les API suivantes :
* [[yii\caching\Cache::get()|get()]]: retrouve une donnée dans le cache identifiée par une clé spécifiée. Une valeur `false` (faux) est retournée si la donnée n'est pas trouvée dans le cache ou si elle a expiré ou été invalidée.
* [[yii\caching\Cache::set()|set()]]: stocke une donnée sous une clé dans le cache.
* [[yii\caching\Cache::add()|add()]]: stocke une donnée identifiée par une clé dans le cache si la clé n'existe pas déjà dans le cache.
* [[yii\caching\Cache::getOrSet()|getOrSet()]]: retrouve une donnée dans le cache identifiée par une clé spécifiée ou exécute la fonction de rappel passée, stocke la valeur retournée par cette fonction dans le cache sous cette clé et retourne la donnée.
* [[yii\caching\Cache::multiGet()|multiGet()]]: retrouve de multiples données dans le cache identifiées par les clés spécifiées.
* [[yii\caching\Cache::multiSet()|multiSet()]]: stocke de multiples données dans le cache. Chaque donnée est identifiée par une clé.
* [[yii\caching\Cache::multiAdd()|multiAdd()]]: stocke de multiples données dans le cache. Chaque donnée est identifiée par une clé. Si la clé existe déjà dans le cache, la donnée est ignorée.
* [[yii\caching\Cache::exists()|exists()]]: retourne une valeur indiquant si la clé spécifiée existe dans le cache.
* [[yii\caching\Cache::delete()|delete()]]: retire du cache une donnée identifiée par une clé.
* [[yii\caching\Cache::flush()|flush()]]: retire toutes les données du cache.
> Note : ne mettez pas directement en cache une valeur booléenne `false` parce que la méthode [[yii\caching\Cache::get()|get()]] utilise la valeur `false` pour indiquer que la donnée n'a pas été trouvée dans le cache. Au lieu de cela, vous pouvez placer cette donnée dans un tableau et mettre ce tableau en cache pour éviter le problème.
Quelques supports de cache, tels que MemCache, APC, prennent en charge la récupération de multiples valeurs en cache en mode « batch » (lot), ce qui réduit la surcharge occasionnée par la récupération des données en cache. Les API [[yii\caching\Cache::multiGet()|multiGet()]] et [[yii\caching\Cache::multiAdd()|multiAdd()]] sont fournies pour exploiter cette fonctionnalité. Dans le cas où le support de cache sous-jacent ne prend pas en charge cette fonctionnalité, elle est simulée.
Comme [[yii\caching\Cache]] implémente `ArrayAccess`, un composant de mise en cache peut être utilisé comme un tableau. En voici quelques exemples :
```php
$cache['var1'] = $value1; // équivalent à : $cache->set('var1', $value1);
$value2 = $cache['var2']; // équivalent à : $value2 = $cache->get('var2');
```
### Clés de cache <span id="cache-keys"></span>
Chacune des données stockée dans le cache est identifiée de manière unique par une clé. Lorsque vous stockez une donnée dans le cache, vous devez spécifier une clé qui lui est attribuée. Plus tard, pour récupérer la donnée, vous devez fournir cette clé.
Vous pouvez utiliser une chaîne de caractères ou une valeur arbitraire en tant que clé de cache. Lorsqu'il ne s'agit pas d'une chaîne de caractères, elle est automatiquement sérialisée sous forme de chaîne de caractères.
Une stratégie courante pour définir une clé de cache consiste à inclure tous les facteurs déterminants sous forme de tableau. Par exemple,[[yii\db\Schema]] utilise la clé suivante par mettre en cache les informations de schéma d'une table de base de données :
```php
[
__CLASS__, // schema class name
$this->db->dsn, // DB connection data source name
$this->db->username, // DB connection login user
$name, // table name
];
```
Comme vous le constatez, la clé inclut toutes les informations nécessaires pour spécifier de manière unique une table de base de données.
> Note : les valeurs stockées dans le cache via [[yii\caching\Cache::multiSet()|multiSet()]] ou [[yii\caching\Cache::multiAdd()|multiAdd()]] peuvent n'avoir que des clés sous forme de chaînes de caractères ou de nombres entiers. Si vous avez besoin de définir des clés plus complexes, stockez la valeur séparément via [[yii\caching\Cache::set()|set()]] ou [[yii\caching\Cache::add()|add()]].
Lorsque le même support de cache est utilisé par différentes applications, vous devriez spécifier un préfixe de clé de cache pour chacune des applications afin d'éviter les conflits de clés de cache. Cela peut être fait en configurant la propriété [[yii\caching\Cache::keyPrefix]]. Par exemple, dans la configuration de l'application vous pouvez entrer le code suivant :
```php
'components' => [
'cache' => [
'class' => 'yii\caching\ApcCache',
'keyPrefix' => 'myapp', // a unique cache key prefix
],
],
```
Pour garantir l'interopérabilité, vous ne devez utiliser que des caractères alpha-numériques.
### Expiration de la mise en cache <span id="cache-expiration"></span>
Une donnée stockée dans le cache y restera à jamais sauf si elle en est retirée par l'application d'une quelconque politique de mise en cache (p. ex. l'espace de mise en cache est plein et les données les plus anciennes sont retirées). Pour modifier ce comportement, vous pouvez fournir un paramètre d'expiration lors de l'appel de la fonction [[yii\caching\Cache::set()|set()]] pour stocker une donnée. Le paramètre indique pour combien de secondes la donnée restera valide dans le cache. Lorsque vous appelez la fonction [[yii\caching\Cache::get()|get()]] pour récupérer une donnée, si cette dernière a expiré, la méthode retourne `false`, pour indiquer que la donnée n'a pas été trouvée dans le cache. Par exemple,
```php
// conserve la donnée dans le cache pour un maximum de 45 secondes
$cache->set($key, $data, 45);
sleep(50);
$data = $cache->get($key);
if ($data === false) {
// $data a expiré ou n'a pas été trouvée dans le cache
}
```
Depuis la version 2.0.11, vous pouvez définir une valeur [[yii\caching\Cache::$defaultDuration|defaultDuration]] dans la configuration de votre composant de mise en cache si vous préférez utiliser une durée de mise en cache personnalisée au lieu de la durée illimitée par défaut. Cela vous évitera d'avoir à passer la durée personnalisée à la fonction [[yii\caching\Cache::set()|set()]] à chaque fois.
### Dépendances de mise en cache <span id="cache-dependencies"></span>
En plus de la définition du temps d'expiration, les données mises en cache peuvent également être invalidées par modification de ce qu'on appelle les *dépendances de mise en cache*.
Par exemple, [[yii\caching\FileDependency]] représente la dépendance à la date de modification d'un fichier.
Lorsque cette dépendance est modifiée, cela signifie que le fichier correspondant est modifié. En conséquence, tout contenu de fichier périmé trouvé dans le cache devrait être invalidé et l'appel de la fonction [[yii\caching\Cache::get()|get()]] devrait retourner `false`.
Les dépendances de mise en cache sont représentées sous forme d'objets dérivés de [[yii\caching\Dependency]]. Lorsque vous appelez la fonction [[yii\caching\Cache::set()|set()]] pour stocker une donnée dans le cache, vous pouvez lui passer un objet de dépendance (« Dependency ») associé. Par exemple,
```php
// Crée une dépendance à la date de modification du fichier example.txt
$dependency = new \yii\caching\FileDependency(['fileName' => 'example.txt']);
// La donnée expirera dans 30 secondes.
// Elle sera également invalidée plus tôt si le fichier example.txt est modifié.
$cache->set($key, $data, 30, $dependency);
// Le cache vérifiera si la donnée a expiré.
// Il vérifiera également si la dépendance associée a été modifiée.
// Il retournera `false` si l'une de ces conditions est vérifiée.
$data = $cache->get($key);
```
Ci-dessous nous présentons un résumé des dépendances de mise en cache disponibles :
- [[yii\caching\ChainedDependency]]: la dépendance est modifiée si l'une des dépendances de la chaîne est modifiée.
- [[yii\caching\DbDependency]]: la dépendance est modifiée si le résultat de le requête de l'instruction SQL spécifiée est modifié.
- [[yii\caching\ExpressionDependency]]: la dépendance est modifiée si le résultat de l'expression PHP spécifiée est modifié.
- [[yii\caching\FileDependency]]: la dépendance est modifiée si la date de dernière modification du fichier est modifiée.
- [[yii\caching\TagDependency]]: associe une donnée mise en cache à une ou plusieurs balises. Vous pouvez invalider la donnée mise en cache associée à la balise spécifiée en appelant [[yii\caching\TagDependency::invalidate()]].
> Note : évitez d'utiliser la méthode [[yii\caching\Cache::exists()|exists()]] avec des dépendances. Cela ne vérifie pas si la dépendance associée à la donnée mise en cache, s'il en existe une, a changé. Ainsi, un appel de la fonction [[yii\caching\Cache::get()|get()]] peut retourner `false` alors que l'appel de la fonction [[yii\caching\Cache::exists()|exists()]] retourne `true`.
## Mise en cache de requêtes <span id="query-caching"></span>
La mise en cache de requêtes est une fonctionnalité spéciale de la mise en cache construite sur la base de la mise en cache de données. Elle est fournie pour permettre la mise en cache du résultat de requêtes de base de données.
La mise en cache de requêtes nécessite une [[yii\db\Connection|connexion à une base de données]] et un [composant d'application](#cache-components)`cache` valide.
L'utilisation de base de la mise en cache de requêtes est la suivante, en supposant que `$db` est une instance de [[yii\db\Connection]] :
```php
$result = $db->cache(function ($db) {
// le résultat d'une requête SQL sera servi à partir du cache
// si la mise en cache de requêtes est activée et si le résultat de la requête est trouvé dans le cache
return $db->createCommand('SELECT * FROM customer WHERE id=1')->queryOne();
});
```
La mise en cache de requêtes peut être utilisée pour des [DAO](db-dao.md) ainsi que pour des [enregistrements actifs](db-active-record.md):
```php
$result = Customer::getDb()->cache(function ($db) {
return Customer::find()->where(['id' => 1])->one();
});
```
> Info : quelques systèmes de gestion de bases de données (DBMS) (p. ex. [MySQL](http://dev.mysql.com/doc/refman/5.1/en/query-cache.html))
prennent également en charge la mise en cache de requêtes du côté serveur de base de données. Vous pouvez choisir d'utiliser l'un ou l'autre des ces mécanismes de mise en cache de requêtes. Les mises en cache de requêtes décrites ci-dessus offrent l'avantage de pouvoir spécifier des dépendances de mise en cache flexibles et sont potentiellement plus efficaces.
### Vidage du cache <span id="cache-flushing">
Lorsque vous avez besoin d'invalider toutes les données stockées dans le cache, vous pouvez appeler [[yii\caching\Cache::flush()]].
Vous pouvez aussi vider le cache depuis la console en appelant `yii cache/flush`.
- `yii cache`: liste les caches disponibles dans une application
- `yii cache/flush cache1 cache2`: vide les composants de mise en cache `cache1`, `cache2` (vous pouvez passer de multiples composants en les séparant par une virgule)
- `yii cache/flush-all`: vide tous les composants de mise en cache de l'application
> Info : les applications en console utilisent un fichier de configuration séparé par défaut. Assurez-vous que vous utilisez le même composant de mise en cache dans les configurations de vos application web et console pour obtenir l'effet correct.
### Configurations <span id="query-caching-configs"></span>
La mise en cache de requêtes dispose de trois options globales configurables via [[yii\db\Connection]] :
* [[yii\db\Connection::enableQueryCache|enableQueryCache]] : pour activer ou désactiver la mise en cache de requêtes.
Valeur par défaut : `true`. Notez que pour activer effectivement la mise en cache de requêtes, vous devez également disposer d'un cache valide, tel que spécifié par [[yii\db\Connection::queryCache|queryCache]].
* [[yii\db\Connection::queryCacheDuration|queryCacheDuration]] : ceci représente le nombre de secondes durant lesquelles le résultat d'une requête reste valide dans le cache. Vous pouvez utiliser 0 pour indiquer que le résultat de la requête doit rester valide indéfiniment dans le cache. Cette propriété est la valeur par défaut utilisée lors de l'appel [[yii\db\Connection::cache()]] sans spécifier de durée.
* [[yii\db\Connection::queryCache|queryCache]] : ceci représente l'identifiant du composant d'application de mise en cache.
Sa valeur par défaut est : `'cache'`. La mise en cache de requêtes est activée seulement s'il existe un composant d'application de mise en cache valide.
### Utilisations <span id="query-caching-usages"></span>
Vous pouvez utiliser [[yii\db\Connection::cache()]] si vous avez de multiples requêtes SQL qui doivent bénéficier de la mise en cache de requêtes. On l'utilise comme suit :
```php
$duration = 60; // mettre le résultat de la requête en cache durant 60 secondes.
$dependency = ...; // dépendance optionnelle
$result = $db->cache(function ($db) {
// ... effectuer les requêtes SQL ici ...
return $result;
}, $duration, $dependency);
```
Toutes les requêtes SQL dans la fonction anonyme sont mises en cache pour la durée spécifiée avec la dépendance spécifiée. Si le résultat d'une requête est trouvé valide dans le cache, la requête est ignorée et, à la place, le résultat est servi à partir du cache. Si vous ne spécifiez pas le paramètre `$duration`, la valeur de [[yii\db\Connection::queryCacheDuration|queryCacheDuration]] est utilisée en remplacement.
Parfois, dans `cache()`, il se peut que vous vouliez désactiver la mise en cache de requêtes pour des requêtes particulières. Dans un tel cas, vous pouvez utiliser [[yii\db\Connection::noCache()]].
```php
$result = $db->cache(function ($db) {
// requêtes SQL qui utilisent la mise en cache de requêtes
$db->noCache(function ($db) {
// requêtes qui n'utilisent pas la mise en cache de requêtes
});
// ...
return $result;
});
```
Si vous voulez seulement utiliser la mise en cache de requêtes pour une requête unique, vous pouvez appeler la fonction [[yii\db\Command::cache()]] lors de la construction de la commande. Par exemple :
```php
// utilise la mise en cache de requêtes et définit la durée de mise en cache de la requête à 60 secondes
$customer = $db->createCommand('SELECT * FROM customer WHERE id=1')->cache(60)->queryOne();
```
Vous pouvez aussi utiliser la fonction [[yii\db\Command::noCache()]] pour désactiver la mise en cache de requêtes pour une commande unique. Par exemple :
```php
$result = $db->cache(function ($db) {
// requêtes SQL qui utilisent la mise en cache de requêtes
// ne pas utiliser la mise en cache de requêtes pour cette commande
$customer = $db->createCommand('SELECT * FROM customer WHERE id=1')->noCache()->queryOne();
// ...
return $result;
});
```
### Limitations <span id="query-caching-limitations"></span>
La mise en cache de requêtes ne fonctionne pas avec des résultats de requêtes qui contiennent des gestionnaires de ressources. Par exemple, lorsque vous utilisez de type de colonne `BLOB` dans certains systèmes de gestion de bases de données (DBMS), la requête retourne un gestionnaire de ressources pour la donnée de la colonne.
Quelques supports de stockage pour cache sont limités en taille. Par exemple, avec memcache, chaque entrée est limitée en taille à 1MO. En conséquence, si le résultat d'une requête dépasse cette taille, la mise en cache échoue.

143
docs/guide-fr/caching-fragment.md

@ -0,0 +1,143 @@
Mise en cache de fragments
==========================
La mise en cache de fragments fait référence à la mise en cache de fragments de pages Web. Par exemple, si une page affiche un résumé des ventes annuelles dans un tableau, vous pouvez stocker ce tableau en cache pour éliminer le temps nécessaire à sa génération à chacune des requêtes. La mise en cache de fragments est construite au-dessus de la [mise en cache de données](caching-data.md).
Pour utiliser la mise en cache de fragments, utilisez la construction qui suit dans une [vue](structure-views.md):
```php
if ($this->beginCache($id)) {
// ... générez le contenu ici ...
$this->endCache();
}
```
C'est à dire, insérez la logique de génération du contenu entre les appels [[yii\base\View::beginCache()|beginCache()]] et
[[yii\base\View::endCache()|endCache()]]. Si le contenu est trouvé dans le cache, [[yii\base\View::beginCache()|beginCache()]]
rendra le contenu en cache et retournera `false` (faux), ignorant la logique de génération de contenu.
Autrement, votre logique de génération de contenu sera appelée, et quand [[yii\base\View::endCache()|endCache()]] sera appelée, le contenu généré sera capturé et stocké dans le cache.
Comme pour la [mise en cache de données](caching-data.md), un `$id` (identifiant) unique est nécessaire pour identifier un cache de contenu.
## Options de mise en cache <span id="caching-options"></span>
Vous pouvez spécifier des options additionnelles sur la mise en cache de fragments en passant le tableau d'options comme second paramètre à la méthode [[yii\base\View::beginCache()|beginCache()]]. En arrière plan, ce tableau d'options est utilisé pour configurer un composant graphique [[yii\widgets\FragmentCache]] qui met en œuvre la fonctionnalité réelle de mise en cache de fragments.
### Durée <span id="duration"></span>
L'option [[yii\widgets\FragmentCache::duration|duration]] (durée) est peut-être l'option de la mise en cache de fragments la plus couramment utilisée. Elle spécifie pour combien de secondes le contenu peut demeurer valide dans le cache. Le code qui suit met le fragment de contenu en cache pour au maximum une heure :
```php
if ($this->beginCache($id, ['duration' => 3600])) {
// ... générez le contenu ici...
$this->endCache();
}
```
Si cette option n'est pas définie, la valeur utilisée par défaut est 60, ce qui veut dire que le contenu mise en cache expirera au bout de 60 secondes.
### Dépendances <span id="dependencies"></span>
Comme pour la [mise en cache de données](caching-data.md#cache-dependencies), le fragment de contenu mis en cache peut aussi avoir des dépendances. Par exemple, le contenu d'un article affiché dépend du fait que l'article a été modifié ou pas.
Pour spécifier une dépendance, définissez l'option [[yii\widgets\FragmentCache::dependency|dependency]], soit sous forme d'objet [[yii\caching\Dependency]], soit sous forme d'un tableau de configuration pour créer un objet [[yii\caching\Dependency]]. Le code qui suit spécifie que le fragment de contenu dépend du changement de la valeur de la colonne `updated_at` (mis à jour le) :
```php
$dependency = [
'class' => 'yii\caching\DbDependency',
'sql' => 'SELECT MAX(updated_at) FROM post',
];
if ($this->beginCache($id, ['dependency' => $dependency])) {
// ... générez le contenu ici ...
$this->endCache();
}
```
### Variations <span id="variations"></span>
Le contenu mise en cache peut connaître quelques variations selon certains paramètres. Par exemple, pour une application Web prenant en charge plusieurs langues, le même morceau de code d'une vue peut générer le contenu dans différentes langues. Par conséquent, vous pouvez souhaitez que le contenu mis en cache varie selon la langue courante de l'application.
Pour spécifier des variations de mise en cache, définissez l'option [[yii\widgets\FragmentCache::variations|variations]], qui doit être un tableau de valeurs scalaires, représentant chacune un facteur de variation particulier. Par exemple, pour que le contenu mis en cache varie selon la langue, vous pouvez utiliser le code suivant :
```php
if ($this->beginCache($id, ['variations' => [Yii::$app->language]])) {
// ... générez le contenu ici ...
$this->endCache();
}
```
### Activation désactivation de la mise en cache <span id="toggling-caching"></span>
Parfois, vous désirez activer la mise en cache de fragments seulement lorsque certaines conditions sont rencontrées. Par exemple, pour une page qui affiche un formulaire, vous désirez seulement mettre le formulaire en cache lorsqu'il est initialement demandé (via une requête GET). Tout affichage subséquent du formulaire (via des requêtes POST) ne devrait pas être mise en cache car il contient des données entrées par l'utilisateur. Pour mettre en œuvre ce mécanisme, vous pouvez définir l'option [[yii\widgets\FragmentCache::enabled|enabled]], comme suit :
```php
if ($this->beginCache($id, ['enabled' => Yii::$app->request->isGet])) {
// ... générez le contenu ici ...
$this->endCache();
}
```
## Mises en cache imbriquées <span id="nested-caching"></span>
La mise en cache de fragments peut être imbriquée. C'est à dire qu'un fragment mis en cache peut être contenu dans un autre fragment lui aussi mis en cache.
Par exemple, les commentaires sont mis en cache dans un cache de fragment interne, et sont mis en cache en même temps et avec le contenu de l'article dans un cache de fragment externe. Le code qui suit montre comment deux caches de fragment peuvent être imbriqués :
```php
if ($this->beginCache($id1)) {
// ...logique de génération du contenu ...
if ($this->beginCache($id2, $options2)) {
// ...logique de génération du contenu...
$this->endCache();
}
// ... logique de génération de contenu ...
$this->endCache();
}
```
Différentes options de mise en cache peuvent être définies pour les caches imbriqués. Par exemple, les caches internes et les caches externes peuvent utiliser des valeurs de durée différentes. Même lorsque les données mises en cache dans le cache externe sont invalidées, le cache interne peut continuer à fournir un fragment interne valide. Néanmoins, le réciproque n'est pas vraie; si le cache externe est évalué comme valide, il continue à fournir la même copie mise en cache après que le contenu du cache interne a été invalidé. Par conséquent, vous devez être prudent lors de la définition des durées ou des dépendances des caches imbriqués, autrement des fragments internes périmés peuvent subsister dans le fragment externe.
## Contenu dynamique <span id="dynamic-content"></span>
Lors de l'utilisation de la mise en cache de fragments, vous pouvez rencontrer une situation dans laquelle un gros fragment de contenu est relativement statique en dehors de quelques endroits particuliers. Par exemple, l'entête d'une page peut afficher le menu principal avec le nom de l'utilisateur courant. Un autre problème se rencontre lorsque le contenu mis en cache, contient du code PHP qui doit être exécuté à chacune des requêtes (p. ex. le code pour enregistrer un paquet de ressources). Ces deux problèmes peuvent être résolus par une fonctionnalité qu'on appelle *contenu dynamique*.
Un contenu dynamique signifie un fragment de sortie qui ne doit jamais être mis en cache même s'il est contenu dans un fragment mis en cache. Pour faire en sorte que le contenu soit dynamique en permanence, il doit être généré en exécutant un code PHP à chaque requête, même si le contenu l'englobant est servi à partir du cache.
Vous pouvez appeler la fonction [[yii\base\View::renderDynamic()]] dans un fragment mis en cache pour y insérer un contenu dynamique à l'endroit désiré, comme ceci :
```php
if ($this->beginCache($id1)) {
// ... logique de génération de contenu ...
echo $this->renderDynamic('return Yii::$app->user->identity->name;');
// ... logique de génération de contenu ...
$this->endCache();
}
```
La méthode [[yii\base\View::renderDynamic()|renderDynamic()]] accepte un morceau de code PHP en paramètre. La valeur retournée est traitée comme un contenu dynamique. Le même code PHP est exécuté à chacune des requêtes, peu importe que le fragment englobant soit servi à partir du cache ou pas.

108
docs/guide-fr/caching-http.md

@ -0,0 +1,108 @@
Mise en cache HTTP
============
En plus de la mise en cache côté serveur que nous avons décrite dans les sections précédentes, les applications Web peuvent aussi exploiter la mise en cache côté client pour économiser le temps de génération et de transfert d'un contenu de page inchangé.
Pour utiliser la mise en cache côté client, vous pouvez configurer [[yii\filters\HttpCache]] comme un filtre pour des actions de contrôleur dont le résultat rendu peut être mis en cache du côté du client. [[yii\filters\HttpCache|HttpCache]]
ne fonctionne que pour les requêtes `GET` et `HEAD`. Il peut gérer trois sortes d'entêtes HTTP relatifs à la mise en cache pour ces requêtes :
* [[yii\filters\HttpCache::lastModified|Last-Modified]]
* [[yii\filters\HttpCache::etagSeed|Etag]]
* [[yii\filters\HttpCache::cacheControlHeader|Cache-Control]]
## Entête `Last-Modified` <span id="last-modified"></span>
L'entête `Last-Modified` (dernière modification) utilise un horodatage pour indiquer si la page a été modifiée depuis sa mise en cache par le client.
Vous pouvez configurer la propriété [[yii\filters\HttpCache::lastModified]] pour activer l'envoi de l'entête `Last-modified`. La propriété doit être une fonction de rappel PHP qui retourne un horodatage UNIX concernant la modification de la page. La signature de la fonction de rappel PHP doit être comme suit :
```php
/**
* @param Action $action l'objet action qui est actuellement géré
* @param array $params la valeur de la propriété "params"
* @return int un horodatage UNIX représentant l'instant de modification de la page
*/
function ($action, $params)
```
Ce qui suit est un exemple d'utilisation de l'entête `Last-Modified` :
```php
public function behaviors()
{
return [
[
'class' => 'yii\filters\HttpCache',
'only' => ['index'],
'lastModified' => function ($action, $params) {
$q = new \yii\db\Query();
return $q->from('post')->max('updated_at');
},
],
];
}
```
Le code précédent établit que la mise en cache HTTP doit être activée pour l'action `index` seulement. Il doit générer un entête HTTP `Last-Modified` basé sur l'instant de la dernière mise à jour d'articles (posts). Lorsque le navigateur visite la page `index` pour la première fois, la page est générée par le serveur et envoyée au navigateur. Si le navigateur visite à nouveau la même page, et qu'aucun article n'a été modifié, le serveur ne régénère par la page, et le navigateur utilise la version mise en cache du côté du client. En conséquence, le rendu côté serveur et la transmission de la page sont tous deux évités.
## Entête `ETag` <span id="etag"></span>
L'entête "Entity Tag" (or `ETag` en raccourci) utilise une valeur de hachage pour représenter le contenu d'une page. Si la page est modifiée, la valeur de hachage change également. En comparant la valeur de hachage conservée sur le client avec la valeur de hachage générée côté serveur, le cache peut déterminer si la page a été modifiée et doit être retransmise.
Vous pouvez configurer la propriété [[yii\filters\HttpCache::etagSeed]] pour activer l'envoi de l'entête `ETag`. La propriété doit être une fonction de rappel PHP qui retourne un nonce (sel) pour la génération de la valeur de hachage Etag. La signature de la fonction de rappel PHP doit être comme suit :
```php
/**
* @param Action $action l'objet action qui est actuellement géré
* @param array $params la valeur de la propriété "params"
* @return string une chaîne de caractères à utiliser comme nonce (sel) pour la génération d'une valeur de hachage ETag
*/
function ($action, $params)
```
Ce qui suit est un exemple d'utilisation de l'entête `ETag` :
```php
public function behaviors()
{
return [
[
'class' => 'yii\filters\HttpCache',
'only' => ['view'],
'etagSeed' => function ($action, $params) {
$post = $this->findModel(\Yii::$app->request->get('id'));
return serialize([$post->title, $post->content]);
},
],
];
}
```
Le code ci-dessus établit que la mise en cache HTTP doit être activée pour l'action `view` seulement. Il doit générer un entête HTTP `ETag` basé sur le titre et le contenu de l'article demandé. Lorsque le navigateur visite la page pour la première fois, la page est générée par le serveur et envoyée au navigateur. Si le navigateur visite à nouveau la même page et que ni le titre, ni le contenu de l'article n'ont changé, le serveur ne régénère pas la page et le navigateur utilise la version mise en cache côté client. En conséquence, le rendu par le serveur et la transmission de la page sont tous deux évités.
ETags vous autorise des stratégies de mises en cache plus complexes et/ou plus précises que l'entête `Last-Modified`. Par exemple, un ETag peut être invalidé si on a commuté le site sur un nouveau thème.
Des génération coûteuses d'ETag peuvent contrecarrer l'objectif poursuivi en utilisant `HttpCache` et introduire une surcharge inutile, car il faut les réévaluer à chacune des requêtes. Essayez de trouver une expression simple qui invalide le cache si le contenu de la page a été modifié.
> Note : en conformité avec la norme [RFC 7232](http://tools.ietf.org/html/rfc7232#section-2.4),
`HttpCache` envoie les entêtes `ETag` et `Last-Modified` à la fois si ils sont tous deux configurés. Et si le client envoie les entêtes `If-None-Match` et `If-Modified-Since` à la fois, seul le premier est respecté.
## Entête `Cache-Control` <span id="cache-control"></span>
L'entête `Cache-Control` spécifie la politique de mise en cache générale pour les pages. Vous pouvez l'envoyer en configurant la propriété [[yii\filters\HttpCache::cacheControlHeader]] avec la valeur de l'entête. Par défaut, l'entête suivant est envoyé :
```
Cache-Control: public, max-age=3600
```
## Propriété "Session Cache Limiter" <span id="session-cache-limiter"></span>
Lorsqu'une page utilise une session, PHP envoie automatiquement quelques entêtes HTTP relatifs à la mise en cache comme spécifié dans la propriété `session.cache_limiter` de PHP INI. Ces entêtes peuvent interférer ou désactiver la mise en cache que vous voulez obtenir de `HttpCache`. Pour éviter ce problème, par défaut, `HttpCache` désactive l'envoi de ces entêtes automatiquement. Si vous désirez modifier ce comportement, vous devez configurer la propriété [[yii\filters\HttpCache::sessionCacheLimiter]]. Cette propriété accepte une chaîne de caractères parmi `public`, `private`, `private_no_expire` et `nocache`. Reportez-vous au manuel de PHP à propos de [session_cache_limiter()](http://www.php.net/manual/en/function.session-cache-limiter.php) pour des explications sur ces valeurs.
## Implications SEO <span id="seo-implications"></span>
Les robots moteurs de recherche ont tendance à respecter les entêtes de mise en cache. Comme certains moteurs d'indexation du Web sont limités quant aux nombre de pages par domaine qu'ils sont à même de traiter dans un certain laps de temps, l'introduction d'entêtes de mise en cache peut aider à l'indexation de votre site car ils limitent le nombre de pages qui ont besoin d'être traitées.

15
docs/guide-fr/caching-overview.md

@ -0,0 +1,15 @@
Mise en cache
=============
La mise en cache est un moyen peu coûteux et efficace d'améliorer la performance d'une application Web. En stockant des données relativement statiques en cache et en les servant à partir de ce cache lorsqu'elles sont demandées, l'application économise le temps qu'il aurait fallu pour générer ces données à partir de rien à chaque demande.
La mise en cache se produit à différents endroits et à différents niveaux dans une application Web. Du côté du serveur, au niveau le plus bas, le cache peut être utilisé pour stocker des données de base, telles qu'une liste des informations sur des articles recherchée dans une base de données; et à un niveau plus élevé, il peut être utilisé pour stocker des fragments ou l'intégralité de pages Web, telles que le rendu des articles les plus récents.
Du côté client, la mise en cache HTTP peut être utilisée pour conserver le contenu des pages visitées les plus récentes dans le cache du navigateur.
Yii prend en charge tous ces mécanismes de mise en cache :
* [Mise en cache de données](caching-data.md)
* [Mise en cache de fragments](caching-fragment.md)
* [Mise en cache de pages](caching-page.md)
* [Mise en cache HTTP](caching-http.md)

33
docs/guide-fr/caching-page.md

@ -0,0 +1,33 @@
Mise en cache de pages
======================
La mise en cache de pages fait référence à la mise en cache du contenu d'une page entière du côté serveur. Plus tard, lorsque la même page est demandée à nouveau, son contenu est servi à partir du cache plutôt que d'être régénéré entièrement.
La mise en cache de pages est prise en charge par [[yii\filters\PageCache]], un [filtre d'action](structure-filters.md). On peut l'utiliser de la manière suivante dans une classe contrôleur :
```php
public function behaviors()
{
return [
[
'class' => 'yii\filters\PageCache',
'only' => ['index'],
'duration' => 60,
'variations' => [
\Yii::$app->language,
],
'dependency' => [
'class' => 'yii\caching\DbDependency',
'sql' => 'SELECT COUNT(*) FROM post',
],
],
];
}
```
Le code ci-dessus établit que la mise en cache de pages doit être utilisée uniquement pour l'action `index`. Le contenu de la page doit être mis en cache pour au plus 60 secondes et doit varier selon la langue courante de l'application. De plus, le contenu de la page mis en cache doit être invalidé si le nombre total d'articles (post) change.
Comme vous pouvez le constater, la mise en cache de pages est très similaire à la [mise en cache de fragments](caching-fragment.md). Les deux prennent en charge les options telles que `duration`, `dependencies`, `variations` et `enabled`. La différence principale est que la mise en cache de pages est mis en œuvre comme un [filtre d'action](structure-filters.md) alors que la mise en cache de framgents l'est comme un [composant graphique](structure-widgets.md).
Vous pouvez utiliser la [mise en cache de fragments](caching-fragment.md) ainsi que le [contenu dynamique](caching-fragment.md#dynamic-content) en simultanéité avec la mise en cache de pages.

85
docs/guide-fr/concept-aliases.md

@ -1,13 +1,14 @@
Les Alias
=========
Les alias sont utilisés pour représenter des chemins de fichier ou des URLs de sorte que vous n'ayez pas à spécifier des chemins ou des URLs explicitement dans votre projet. Un alias doit commencer par le caractère `@` de façon à le différencier des chemins de fichiers habituels et des URLs. Yii dispose déjà d'un nombre important d'alias prédéfinis. Par exemple, l'alias `@yii` représéente le chemin d'installation du framework Yii; `@web` représente l'URL de base pour l'application web courante.
Alias
=====
Les alias sont utilisés pour représenter des chemins de fichier ou des URL de façon à ce que vous n'ayez pas besoin d'écrire ces chemins ou ces URL en entier dans votre code. Un alias doit commencer par le caractère arobase `@` pour être différentié des chemins de fichier et des URL normaux. Les alias définis sans ce caractère de tête `@` sont automatiquement préfixés avec ce dernier.
Yii possèdent de nombreux alias pré-définis déjà disponibles. Par exemple, l'alias `@yii` représente le chemin d'installation de la base structurée de développement PHP (*framework*), Yii; L'alias `@web` représente l'URL de base de l'application Web en cours d'exécution.
Définir des alias <span id="defining-aliases"></span>
-----------------
Définition des alias <span id="defining-aliases"></span>
--------------------
Vous pouvez définir un alias soit pour un chemin de fichier ou pour une URL en appelant [[Yii::setAlias()]]:
Vous pouvez définir un alias pour un chemin de fichier ou pour une URL en appelant [[Yii::setAlias()]]:
```php
// un alias pour un chemin de fichier
@ -16,58 +17,62 @@ Yii::setAlias('@foo', '/path/to/foo');
// un alias pour une URL
Yii::setAlias('@bar', 'http://www.example.com');
```
> Note: le chemin de fichier ou l'URL cible de l'alias *ne* doit *pas* nécessairement référencer un fichier ou une ressource existante.
Etant donné un alias défini, il est possible de faire dériver un nouvel alias (sans appeler la commande [[Yii::setAlias()]]) en ajoutant une barre oblique `/` suivi d'un ou de plusieurs segments de chemin de fichier. Les alias définis via la commande [[Yii::setAlias()]] sont des *alias racines*, les alias qui en dérivent sont des *alias dérivés*. Par example, `@foo` est un alias racine, tandis que `@foo/bar/file.php` est un alias dérivé.
> Note: le chemin de fichier ou l'URL pour qui un alias est créé peut *ne pas* nécessairement faire référence à un fichier ou une ressource existante.
Étant donné un alias, vous pouvez dériver un autre alias – sans faire appel à [[Yii::setAlias()]]) – en y ajoutant une barre oblique de division `/` suivi d'un ou plusieurs segments de chemin. Les alias définis via [[Yii::setAlias()]] sont des *alias racines*, tandis que les alias qui en dérivent sont des *alias dérivés*. Par exemple, `@foo` est un alias racine, alors que `@foo/bar/file.php` est un alias dérivé.
Il est possible de définir une alias en utilisant un autre alias (qu'il soit racine ou dérivé):
Vous pouvez définir un alias en utilisant un autre alias (qu'il soit racine ou dérivé) :
```php
Yii::setAlias('@foobar', '@foo/bar');
```
Les alias racines sont habituellement définit pendant l'étape d'[amorçage](runtime-bootstrapping.md). Vous pouvez par exemple appeler la commande [[Yii::setAlias()]] dans le [script d'entrée](structure-entry-scripts.md). Pour plus de commodité, [Application](structure-applications.md) propose une propriété modifiable appelée `aliases` que vous pouvez définir dans la [configuration](concept-configurations.md) de l'application:
Les alias racines sont ordinairement définis pendant l'étape d'[amorçage](runtime-bootstrapping.md). Par exemple, vous pouvez appeler [[Yii::setAlias()]] dans le [script d'entrée](structure-entry-scripts.md). Pour commodité, la classe [Application](structure-applications.md) fournit une propriété nommée `aliases` que vous pouvez configurer dans la [configuration](concept-configurations.md) de l'application :
```php
return [
// ...
'aliases' => [
'@foo' => '/chemin/vers/foo',
'@foo' => '/path/to/foo',
'@bar' => 'http://www.example.com',
],
];
```
Résolution des alias <span id="resolving-aliases"></span>
--------------------
Vous pouvez appeler la méthode [[Yii::getAlias()]] pour obtenir le chemin de fichier ou l'URL qu'un alias représente. La même méthode peut aussi convertir des alias dérivés dans leur chemin de fichier ou URL correspondants:
Vous pouvez appeler [[Yii::getAlias()]] pour résoudre un alias racine en le chemin de fichier ou l'URL qu'il représente. La même méthode peut aussi résoudre un alias dérivé en le chemin de fichier ou l'URL correspondant :
```php
echo Yii::getAlias('@foo'); // displays: /path/to/foo
echo Yii::getAlias('@bar'); // displays: http://www.example.com
echo Yii::getAlias('@foo/bar/file.php'); // displays: /path/to/foo/bar/file.php
echo Yii::getAlias('@foo'); // affiche : /path/to/foo
echo Yii::getAlias('@bar'); // affiche : http://www.example.com
echo Yii::getAlias('@foo/bar/file.php'); // affiche : /path/to/foo/bar/file.php
```
Le chemin/URL représenté par un alias dérivé est déterminé en renplaçant la partie alias racine avec son chemain/URL correspondant dans l'alias dérivé.
> Note: La méthode [[Yii::getAlias()]] ne vérifie pas si le chemin/URL obtenu représente un fichier ou une ressource existante.
Le chemin ou l'URL que représente un alias dérivé est déterminé en remplaçant l'alias racine par le chemin ou l'URL qui lui correspond dans l'alias dérivé.
> Note: la méthode [[Yii::getAlias()]] ne vérifie pas que le chemin ou l'URL qui en résulte fait référence à un fichier existant ou à une ressource existante.
Un alias racine peut également conctenir des barres obliques `/`. La méthode [[Yii::getAlias()]] est suffisement intelligeante pour déterminer quelle part de l'alias est un alias racine et donc détermine correctement le chemin de fichier ou l'url correspondant:
Un alias racine peut également contenir des barres obliques de division `/`. La méthode [[Yii::getAlias()]] est suffisamment intelligente pour dire quelle partie d'un alias est un alias racine et, par conséquent, déterminer correctement le chemin de fichier ou l'URL qui correspond :
```php
Yii::setAlias('@foo', '/chemin/vers/foo');
Yii::setAlias('@foo/bar', '/chemin2/bar');
Yii::getAlias('@foo/test/file.php'); // affiche /chemin/vers/foo/test/file.php
Yii::getAlias('@foo/bar/file.php'); // affiche /chemin2/bar/file.php
Yii::setAlias('@foo', '/path/to/foo');
Yii::setAlias('@foo/bar', '/path2/bar');
Yii::getAlias('@foo/test/file.php'); // affiche : /path/to/foo/test/file.php
Yii::getAlias('@foo/bar/file.php'); // affiche : /path2/bar/file.php
```
Si `@foo/bar` n'est pas défini comme un alias racine, le dernier exemple affichierait `/chemin/vers/foo/bar/file.php`.
Si `@foo/bar` n'est pas défini en tant qu'alias racine, la dernière instruction affiche `/path/to/foo/bar/file.php`.
Utilisation des alias <span id="using-aliases"></span>
----------------------
---------------------
Les alias sont reconnus en de nombreux endroits de Yii sans avoir besoin d'appeler la méthode [[Yii::getAlias()]] pour les convertir en chemin ou URLs. A titre d'exemple, la méthode [[yii\caching\FileCache::cachePath]] accepte aussi bien un chemin de fichier et un alias représentant un chemin de fichier, grâce au préfixe `@` qui permet de différencier le chemin de fichier d'un alias.
Les alias sont reconnus en différents endroits dans Yii sans avoir besoin d'appeler [[Yii::getAlias()]] pour les convertir en chemin ou URL. Par exemple, [[yii\caching\FileCache::cachePath]] accepte soit un chemin de fichier, soit un alias représentant un chemin de fichier, grâce au préfixe `@` qui permet de différentier un chemin de fichier d'un alias.
```php
use yii\caching\FileCache;
@ -76,30 +81,32 @@ $cache = new FileCache([
'cachePath' => '@runtime/cache',
]);
```
Merci de porter attention à la documentation de l'API pour vérifier si une propriété ou un paramètre d'une méthode supporte les alias.
Reportez-vous à la documentation de l'API pour savoir si une propriété ou une méthode prend en charge les alias.
Alias prédéfinis <span id="predefined-aliases"></span>
----------------
Yii définit une série d'alias pour faciliter le référencement des chemins de fichier et URLs souvent utilisés:
- `@yii`, le répertoire où se situe le fichier `BaseYii.php` (aussi appelé le répertoire framework).
- `@app`, le [[yii\base\Application::basePath|chemin de base]] de l'application courante.
- `@runtime`, le [[yii\base\Application::runtimePath|le chemin d'exécution]] de l'application courante. Valeur par défaut: `@app/runtime`.
- `@webroot`, La répertoire web racine de l'application web courante. It is determined based on the directory
containing the [entry script](structure-entry-scripts.md).
- `@web`, l'url de base de l'application courante. Cet alias a la même valeur que la propriété [[yii\web\Request::baseUrl]].
- `@vendor`, le [[yii\base\Application::vendorPath|Le répertoire vendor de Composer]]. Valeur par défaut: `@app/vendor`.
- `@bower`, le répertoire racine qui contient [les paquets bower](http://bower.io/). Valeur par défaut: `@vendor/bower`.
- `@npm`, le répertoire racine qui contient [les paquets npm](https://www.npmjs.org/). Valeur par défaut: `@vendor/npm`.
Yii prédéfinit un jeu d'alias pour faire référence à des chemins de fichier ou à des URL d'utilisation courante :
- `@yii`, le dossier où le fichier `BaseYii.php` se trouve – aussi appelé dossier de la base structurée de développement PHP (*framework*).
- `@app`, le [[yii\base\Application::basePath|chemin de base]] de l'application en cours d'exécution.
- `@runtime`, le [[yii\base\Application::runtimePath|chemin du dossier runtime]] de l'application en cours d'exécution. Valeur par défaut `@app/runtime`.
- `@webroot`, le dossier Web racine de l'application en cours d'exécution. Il est déterminé en se basant sur le dossier qui contient le [script d'entrée](structure-entry-scripts.md).
- `@web`, l'URL de base de l'application en cours d'exécution. Cet alias a la même valeur que [[yii\web\Request::baseUrl]].
- `@vendor`, le [[yii\base\Application::vendorPath|dossier vendor de Composer]]. Valeur par défaut `@app/vendor`.
- `@bower`, le dossier racine des [paquets bower](http://bower.io/). Valeur par défaut `@vendor/bower`.
- `@npm`, le dossier racine des [paquets npm](https://www.npmjs.org/). Valeur par défaut `@vendor/npm`.
L'alias `@yii` est défini lorsque vous incluez le fichier `Yii.php` dans votre [script d'entrée](structure-entry-scripts.md). Les alias restants sont définis dans le constructeur de l'application au moment où la [configuration](concept-configurations.md) de l'application est appliquée.
.
L'alias `@yii` est défini quand le fichier `Yii.php`est inclu dans votre [script d'entrée](structure-entry-scripts.md). Le reste des alias sont définit dans le constructeur de l'application au moment ou la [configuration](concept-configurations.md) de cette dernière est appliquée
Alias d'extension <span id="extension-aliases"></span>
-----------------
Un alias est automatiquement définit pour chaque [extension](structure-extensions.md) installée via Composer.
Chacun de ces alias est nommé par l'espace de nom (namespace) racine de l'extension tel que déclaré dans son fichier `composer.json`, et chacun pointe sur le répertoire racine du paquet. Par exemple, si vous installez l'extension `yiisoft/yii2-jui`, vous obtiendrez automatiquement un alias `@yii/jui` défini pendant la [phase d'amorçage](runtime-bootstrapping.md), équivalent à
Un alias est automatiquement défini par chacune des [extensions](structure-extensions.md) qui sont installées par Composer. Chaque alias est nommé d'après le nom de l'extension déclaré dans le fichier `composer.json`. Chaque alias représente le dossier racine du paquet. Par exemple, si vous installez l'extension `yiisoft/yii2-jui`, vous obtiendrez automatiquement l'alias `@yii/jui` défini durant l'étape d'[amorçage](runtime-bootstrapping.md), et équivalent à :
```php
Yii::setAlias('@yii/jui', 'VendorPath/yiisoft/yii2-jui');

64
docs/guide-fr/concept-autoloading.md

@ -0,0 +1,64 @@
Chargement automatique des classes
==================================
Yii compte sur le [mécanisme de chargement automatique des classes](http://www.php.net/manual/en/language.oop5.autoload.php) pour localiser et inclure tous les fichiers de classes requis. Il fournit un chargeur automatique de classes de haute performance qui est conforme à la [norme PSR-4](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md). Le chargeur automatique est installé lorsque vous incluez le fichier `Yii.php`.
> Note: pour simplifier la description, dans cette section, nous ne parlerons que du chargement automatique des classes. Néanmoins, gardez présent à l'esprit que le contenu que nous décrivons ici s'applique aussi au chargement automatique des interfaces et des traits.
Utilisation du chargeur automatique de Yii <span id="using-yii-autoloader"></span>
------------------------------------------
Pour utiliser le chargeur automatique de classes de Yii, vous devez suivre deux règles simples lorsque vous créez et nommez vos classes :
* Chaque classe doit être placée sous un [espace de noms](http://php.net/manual/en/language.namespaces.php) (p. ex. `foo\bar\MyClass`)
* Chaque classe doit être sauvegardée sous forme d'un fichier individuel dont le chemin est déterminé par l'algorithme suivant :
```php
// $className est un nom de classe pleinement qualifié sans la barre oblique inversée de tête
$classFile = Yii::getAlias('@' . str_replace('\\', '/', $className) . '.php');
```
For exemple, si le nom de classe et l'espace de noms sont `foo\bar\MyClass`, l'[alias](concept-aliases.md) pour le chemin du fichier de classe correspondant est `@foo/bar/MyClass.php`. Pour que cet alias puisse être résolu en un chemin de fichier, soit `@foo`, soit `@foo/bar` doit être un [alias racine](concept-aliases.md#defining-aliases).
Lorsque vous utilisez le [modèle de projet *basic*](start-installation.md), vous pouvez placer vos classes sous l'espace de noms de niveau le plus haut `app` afin qu'elles puissent être chargées automatiquement par Yii sans avoir besoin de définir un nouvel alias. Cela est dû au fait que `@app` est un [alias prédéfini](concept-aliases.md#predefined-aliases), et qu'un nom de classe comme `app\components\MyClass` peut être résolu en le fichier de classe `AppBasePath/components/MyClass.php`, en appliquant l'algorithme précédemment décrit.
Dans le [modèle de projet avancé](https://github.com/yiisoft/yii2-app-advanced/blob/master/docs/guide/README.md), chaque niveau possède son propre alias. Par exemple, le niveau « interface utilisateur » a l'alias `@frontend`, tandis que le niveau « interface d'administration » a l'alias `@backend`. En conséquence, vous pouvez mettre les classes de l'interface utilisateur sous l'espace de noms `frontend`, tandis que les classes de l'interface d'administration sont sous l'espace de noms `backend`. Cela permet à ces classes d'être chargées automatiquement par le chargeur automatique de Yii.
Table de mise en correspondance des classes <span id="class-map"></span>
-------------------------------------------
Le chargeur automatique de classes de Yii prend en charge la fonctionnalité *table de mise en correspondance des classes*, qui met en correspondance les noms de classe avec les chemins de classe de fichiers. Lorsque le chargeur automatique charge une classe, il commence par chercher si la classe existe dans la table de mise en correspondance. Si c'est le cas, le chemin de fichier correspondant est inclus directement sans plus de recherche. Cela rend le chargement des classes très rapide. En fait, toutes les classes du noyau de Yii sont chargées de cette manière.
Vous pouvez ajouter une classe à la table de mise en correspondance des classes, stockée dans `Yii::$classMap`, avec l'instruction :
```php
Yii::$classMap['foo\bar\MyClass'] = 'path/to/MyClass.php';
```
Les [alias](concept-aliases.md) peuvent être utilisés pour spécifier des chemins de fichier de classe. Vous devez définir la table de mise en correspondance dans le processus d'[amorçage](runtime-bootstrapping.md) afin qu'elle soit prête avant l'utilisation de vos classes.
Utilisation d'autres chargeurs automatiques <span id="using-other-autoloaders"></span>
-------------------------------------------
Comme Yii utilise Composer comme gestionnaire de dépendances de paquets, il est recommandé que vous installiez aussi le chargeur automatique de Composer. Si vous utilisez des bibliothèques de tierces parties qui ont besoin de leurs propres chargeurs, vous devez installer ces chargeurs également.
Lors de l'utilisation conjointe du chargeur automatique de Yii et d'autres chargeurs automatiques, vous devez inclure le fichier `Yii.php` *après* que tous les autres chargeurs automatiques sont installés. Cela fait du chargeur automatique de Yii le premier à répondre à une requête de chargement automatique de classe. Par exemple, le code suivant est extrait du [script d'entrée](structure-entry-scripts.md) du [modèle de projet *basic*](start-installation.md). La première ligne installe le chargeur automatique de Composer, tandis que la seconde installe le chargeur automatique de Yii :
```php
require(__DIR__ . '/../vendor/autoload.php');
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
```
Vous pouvez utiliser le chargeur automatique de Composer seul sans celui de Yii. Néanmoins, en faisant de cette manière, la performance de chargement de vos classes est dégradée et vous devez appliquer les règles de Composer pour que vos classes puissent être chargées automatiquement.
> Info: si vous voulez ne pas utiliser le chargeur automatique de Yii, vous devez créer votre propre version du fichier `Yii.php` et l'inclure dans votre [script d'entrée](structure-entry-scripts.md).
Chargement automatique des classes d'extension <span id="autoloading-extension-classes"></span>
----------------------------------------------
Le chargeur automatique de Yii est capable de charger automatiquement des classes d'[extension](structure-extensions.md). La seule exigence est que cette extension spécifie la section `autoload` correctement dans son fichier `composer.json`. Reportez-vous à la [documentation de Composer](https://getcomposer.org/doc/04-schema.md#autoload) pour plus de détails sur la manière de spécifier `autoload`.
Dans le cas où vous n'utilisez pas le chargeur automatique de Yii, le chargeur automatique de Composer peut toujours charger les classes d'extensions pour vous.

322
docs/guide-fr/concept-behaviors.md

@ -0,0 +1,322 @@
Comportements
=============
Les comportements (*behaviors* sont des instances de la classe [[yii\base\Behavior]], ou de ses classes filles. Les comportements, aussi connus sous le nom de [mixins](http://en.wikipedia.org/wiki/Mixin), vous permettent d'améliorer les fonctionnalités d'une classe de [[yii\base\Component|composant]] existante sans avoir à modifier les héritages de cette classe. Le fait d'attacher un comportement à un composant injecte les méthodes et les propriétés de ce comportement dans le composant, rendant ces méthodes et ces propriétés accessibles comme si elles avaient été définies dans la classe du composant lui-même. En outre, un comportement peut répondre aux [événements](concept-events.md) déclenchés par le composant, ce qui permet aux comportements de personnaliser l'exécution normale du code du composant.
Définition des comportements <span id="defining-behaviors"></span>
---------------------------
Pour définir un comportement, vous devez créer une classe qui étend la classe [[yii\base\Behavior]], ou une des ses classes filles. Par exemple :
```php
namespace app\components;
use yii\base\Behavior;
class MyBehavior extends Behavior
{
public $prop1;
private $_prop2;
public function getProp2()
{
return $this->_prop2;
}
public function setProp2($value)
{
$this->_prop2 = $value;
}
public function foo()
{
// ...
}
}
```
Le code ci-dessus définit la classe de comportement `app\components\MyBehavior` avec deux propriété — `prop1` et `prop2` — et une méthode `foo()`. Notez que la propriété `prop2` est définie via la méthode d'obtention `getProp2` et la méthode d'assignation `setProp2`. Cela est le cas parce que la classe [[yii\base\Behavior]] étend la classe [[yii\base\Object]] et, par conséquent, prend en charge la définition des [propriétés](concept-properties.md) via les méthodes d'obtention et d'assignation.
Comme cette classe est un comportement, lorsqu'elle est attachée à un composant, ce composant acquiert alors les propriétés `prop1` et `prop2`, ainsi que la méthode `foo()`.
> Tip: depuis l'intérieur d'un comportement, vous avez accès au composant auquel le comportement est attaché via la propriété [[yii\base\Behavior::owner]].
> Note: dans le cas où les méthodes [[yii\base\Behavior::__get()]] et/ou [[yii\base\Behavior::__set()]] du comportement sont redéfinies, vous devez redéfinir les méthodes [[yii\base\Behavior::canGetProperty()]] et/ou [[yii\base\Behavior::canSetProperty()]] également.
Gestion des événements du composant
-----------------------------------
Si un comportement a besoin de répondre aux événements déclenchés par le composant auquel il est attaché, il doit redéfinir la méthode [[yii\base\Behavior::events()]]. Par exemple:
```php
namespace app\components;
use yii\db\ActiveRecord;
use yii\base\Behavior;
class MyBehavior extends Behavior
{
// ...
public function events()
{
return [
ActiveRecord::EVENT_BEFORE_VALIDATE => 'beforeValidate',
];
}
public function beforeValidate($event)
{
// ...
}
}
```
La méthode [[yii\base\Behavior::events()|events()]] doit retourner une liste d'événements avec leur gestionnaire correspondant. L'exemple ci-dessus déclare que l'événement [[yii\db\ActiveRecord::EVENT_BEFORE_VALIDATE|EVENT_BEFORE_VALIDATE]] existe et définit son gestionnaire `beforeValidate()`. En spécifiant un gestionnaire d'événement, vous pouvez utiliser un des formats suivants :
* une chaîne de caractères qui fait référence au nom d'une méthode de la classe du comportement, comme dans l'exemple ci-dessus;
* un tableau constitué d'un nom d'objet ou de classe et d'un nom de méthode sous forme de chaîne de caractères (sans les parenthèses), p. ex. `[$object, 'methodName']`;
* une fonction anonyme.
La signature d'un gestionnaire d'événement doit être similaire à ce qui suit, où `event` fait référence au paramètre événement. Reportez-vous à la section [Événements](concept-events.md) pour plus de détail sur les événements.
```php
function ($event) {
}
```
Attacher des comportements <span id="attaching-behaviors"></span>
-----------------------------
Vous pouvez attacher un comportement à un [[yii\base\Component|composant]] soit de manière statique, soit de manière dynamique. Le première manière est une pratique plus habituelle.
Pour attacher un comportement de manière statique, redéfinissez la méthode [[yii\base\Component::behaviors()|behaviors()]] de la classe du composant auquel le comportement va être attaché. La méthode [[yii\base\Component::behaviors()|behaviors()]] doit retourner une liste de [configurations](concept-configurations.md) de comportements. Chaque comportement peut être soit un nom de classe de comportement, soit un tableau de configuration :
```php
namespace app\models;
use yii\db\ActiveRecord;
use app\components\MyBehavior;
class User extends ActiveRecord
{
public function behaviors()
{
return [
// comportement anonyme, nom de la classe de comportement seulement
MyBehavior::className(),
// comportement nommé, nom de classe de comportement seulement
'myBehavior2' => MyBehavior::className(),
// comportement anonyme, tableau de configuration
[
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop2' => 'value2',
],
// comportement nommé, tableau de configuration
'myBehavior4' => [
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop2' => 'value2',
]
];
}
}
```
Vous pouvez associer un nom au comportement en spécifiant la clé de tableau correspondant à la configuration du comportement. Dans ce cas, le comportement est appelé *comportement nommé*. Dans l'exemple ci-dessus, il y a deux comportements nommés : `myBehavior2` et `myBehavior4`. Si un comportement n'est pas associé à un nom, il est appelé *comportement anonyme*.
Pour attacher un comportement de manière dynamique, appelez la méthode [[yii\base\Component::attachBehavior()]] du composant auquel le comportement va être attaché:
```php
use app\components\MyBehavior;
// attache un objet comportement
$component->attachBehavior('myBehavior1', new MyBehavior);
// attache un classe de comportement
$component->attachBehavior('myBehavior2', MyBehavior::className());
// attache un tableau de configuration
$component->attachBehavior('myBehavior3', [
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop2' => 'value2',
]);
```
Vous pouvez attacher plusieurs comportements à la fois en utilisant la méthode [[yii\base\Component::attachBehaviors()]] :
```php
$component->attachBehaviors([
'myBehavior1' => new MyBehavior, // un comportement nommé
MyBehavior::className(), // un comportement anonyme
]);
```
Vous pouvez aussi attacher des comportements via les [configurations](concept-configurations.md) comme ceci :
```php
[
'as myBehavior2' => MyBehavior::className(),
'as myBehavior3' => [
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop2' => 'value2',
],
]
```
Pour plus de détails, reportez-vous à la section [Configurations](concept-configurations.md#configuration-format).
Utilisation des comportements <span id="using-behaviors"></span>
-----------------------------
Pour utiliser un comportement, commencez par l'attacher à un [[yii\base\Component|composant]] en suivant les instructions données ci-dessus. Une fois le comportement attaché au composant, son utilisation est évidente.
Vous pouvez accéder à une variable membre *publique*, ou à une [propriété](concept-properties.md) définie par une méthode d'obtention et/ou une méthode d'assignation (*getter* et *setter*), du comportement, via le composant auquel ce comportement est attaché :
```php
// "prop1" est une propriété définie dans la classe du comportement
echo $component->prop1;
$component->prop1 = $value;
```
Vous pouvez aussi appeler une méthode *publique* du comportement de façon similaire :
```php
// foo() est une méthode publique définie dans la classe du comportement
$component->foo();
```
Comme vous pouvez le voir, bien que le composant `$component` ne définissent pas `prop1` et`foo()`, elles peuvent être utilisées comme si elles faisaient partie de la définition du composant grâce au comportement attaché.
Si deux comportement définissent la même propriété ou la même méthode, et que ces deux comportement sont attachés au même composant, le comportement qui a été attaché le *premier* prévaut lorsque la propriété ou la méthode est accédée.
Un comportement peut être associé à un nom lorsqu'il est attaché à un composant. Dans un tel cas, vous pouvez accéder à l'objet comportement en utilisant ce nom :
```php
$behavior = $component->getBehavior('myBehavior');
```
Vous pouvez aussi obtenir tous les comportements attachés au composant :
```php
$behaviors = $component->getBehaviors();
```
Détacher des comportements <span id="detaching-behaviors"></span>
--------------------------
Pour détacher un comportement, appelez [[yii\base\Component::detachBehavior()]] avec le nom associé au comportement :
```php
$component->detachBehavior('myBehavior1');
```
Vous pouvez aussi détacher *tous les* comportements :
```php
$component->detachBehaviors();
```
Utilisation de `TimestampBehavior` <span id="using-timestamp-behavior"></span>
-------------------------
Pour aller à l'essentiel, jetons un coup d'œil à [[yii\behaviors\TimestampBehavior]]. Ce comportement prend automatiquement en charge la mise à jour de l'attribut *timestamp* (horodate) d'un modèle [[yii\db\ActiveRecord|enregistrement actif]] à chaque fois qu'il est sauvegardé via les méthodes `insert()`, `update()` ou `save()`.
Tout d'abord, attachez ce comportement à la classe [[yii\db\ActiveRecord|Active Record (enregistrement actif)]] que vous envisagez d'utiliser :
```php
namespace app\models\User;
use yii\db\ActiveRecord;
use yii\behaviors\TimestampBehavior;
class User extends ActiveRecord
{
// ...
public function behaviors()
{
return [
[
'class' => TimestampBehavior::className(),
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => ['created_at', 'updated_at'],
ActiveRecord::EVENT_BEFORE_UPDATE => ['updated_at'],
],
// si vous utilisez datetime au lieur de l'UNIX timestamp:
// 'value' => new Expression('NOW()'),
],
];
}
}
```
Le comportement ci-dessus spécifie que lorsque l'enregistrement est :
* inséré, le comportement doit assigner l'horodate UNIX courante aux attributs `created_at` (créé le) et `updated_at` (mis à jour le) ;
* mis à jour, le comportement doit assigner l'horodate UNIX courante à l'attribut `updated_at`;
> Note: pour que la mise en œuvre ci-dessus fonctionne avec une base de données MySQL, vous devez déclarer les colonnes (`created_at`, `updated_at`) en tant que `int(11)` pour qu'elles puissent représenter des horodates UNIX.
Avec ce code en place, si vous avez un objet `User` (utilisateur) et que vous essayez de le sauvegarder, il verra ses attributs `created_at` et `updated_at` automatiquement remplis avec l'horodate UNIX :
```php
$user = new User;
$user->email = 'test@example.com';
$user->save();
echo $user->created_at; // affiche l'horodate courante
```
Le comportement [[yii\behaviors\TimestampBehavior|TimestampBehavior]] offre également une méthode utile [[yii\behaviors\TimestampBehavior::touch()|touch()]], qui assigne l'horodate courante à un attribut spécifié et le sauvegarde dans la base de données :
```php
$user->touch('login_time');
```
Autres comportements
--------------------
Il existe plusieurs comportements pré-inclus et extérieurs disponibles :
- [[yii\behaviors\BlameableBehavior]] – remplit automatiquement les attributs spécifiés avec l'identifiant de l'utilisateur courant.
- [[yii\behaviors\SluggableBehavior]] – remplit automatiquement l'attribut spécifié avec une valeur utilisable en tant que chaîne purement ASCII (*slug*) dans une URL.
- [[yii\behaviors\AttributeBehavior]] – assigne automatiquement une valeur spécifiée à un ou plusieurs attributs d'un objet enregistrement actif lorsque certains événements se produisent.
- [yii2tech\ar\softdelete\SoftDeleteBehavior](https://github.com/yii2tech/ar-softdelete) – fournit des méthodes pour une suppression douce et une restauration douce d'un enregistrement actif c.-à-d. positionne un drapeau ou un état qui marque l'enregistrement comme étant effacé.
- [yii2tech\ar\position\PositionBehavior](https://github.com/yii2tech/ar-position) – permet la gestion de l'ordre des enregistrements dans un champ entier (*integer*) en fournissant les méthodes de remise dans l'ordre.
Comparaison des comportement et des traits <span id="comparison-with-traits"></span>
------------------------------------------
Bien que les comportements soient similaires aux [traits](http://www.php.net/traits) par le fait qu'ils *injectent* tous deux leurs propriétés et leurs méthodes dans la classe primaire, ils diffèrent par de nombreux aspects. Comme nous l'expliquons ci-dessous, ils ont chacun leurs avantages et leurs inconvénients. Ils sont plus des compléments l'un envers l'autre, que des alternatives.
### Raisons d'utiliser des comportements <span id="pros-for-behaviors"></span>
Les classes de comportement, comme les classes normales, prennent en charge l'héritage. Les traits, par contre, peuvent être considérés comme des copier coller pris en charge par le langage. Ils ne prennent pas en charge l'héritage.
Les comportements peuvent être attachés et détachés à un composant de manière dynamique sans qu'une modification de la classe du composant soit nécessaire. Pour utiliser un trait, vous devez modifier le code de la classe qui l'utilise.
Les comportements sont configurables mais les traits ne le sont pas.
Les comportement peuvent personnaliser l'exécution du code d'un composant en répondant à ses événements.
Lorsqu'il se produit des conflits de noms entre les différents comportements attachés à un même composant, les conflits sont automatiquement résolus en donnant priorité au comportement attaché le premier. Les conflits de noms causés par différents traits nécessitent une résolution manuelle en renommant les propriétés et méthodes concernées.
### Raisons d'utiliser des traits <span id="pros-for-traits"></span>
Les traits sont beaucoup plus efficaces que les comportements car les comportements sont des objets qui requièrent plus de temps du processeur et plus de mémoire.
Les environnement de développement intégrés (EDI) sont plus conviviaux avec les traits car ces derniers sont des constructions natives du langage.

86
docs/guide-fr/concept-components.md

@ -0,0 +1,86 @@
Composants
==========
Les composants sont les blocs de constructions principaux de vos applications Yii. Les composants sont des instances de la classe [[yii\base\Component]],
ou de ses classes filles. Les trois fonctionnalités principales fournies par les composants aux autres classes sont :
* [Les propriétés](concept-properties.md);
* [Les événements](concept-events.md);
* [Les comportements](concept-behaviors.md).
Séparément et en combinaisons, ces fonctionnalités rendent les classes de Yii beaucoup plus personnalisables et faciles à utiliser. Par exemple, l'[[yii\jui\DatePicker|objet graphique de sélection de date]] inclus, un composant d'interface utilisateur, peut être utilisé dans une [vue](structure-view.md) pour générer un sélecteur de date interactif :
```php
use yii\jui\DatePicker;
echo DatePicker::widget([
'language' => 'ru',
'name' => 'country',
'clientOptions' => [
'dateFormat' => 'yy-mm-dd',
],
]);
```
Les propriétés de l'objet graphique sont faciles à écrire car la classe étend [[yii\base\Component]].
Tandis que les composants sont très puissants, ils sont un peu plus lourds que les objets normaux. Cela est dû au fait que, en particulier, la prise en charge des fonctionnalités [event](concept-events.md) et [behavior](concept-behaviors.md) requiert un peu plus de mémoire et de temps du processeur. Si vos composants n'ont pas besoin de ces deux fonctionnalités, vous devriez envisager d'étendre la classe [[yii\base\Object]] au lieu de la classe [[yii\base\Component]]. Ce faisant, votre composant sera aussi efficace que les objets PHP normaux, mais avec la prise en charge des [propriétés](concept-properties.md).
Lorsque votre classe étend la classe [[yii\base\Component]] ou [[yii\base\Object]], il est recommandé que suiviez ces conventions :
- Si vous redéfinissez le constructeur, spécifiez un paramètre `$config` en tant que *dernier* paramètre du constructeur est passez le au constructeur du parent.
- Appelez toujours le constructeur du parent *à la fin* de votre constructeur redéfini.
- Si vous redéfinissez la méthode [[yii\base\Object::init()]], assurez-vous que vous appelez la méthode `init()` mise en œuvre par le parent *au début* de votre méthodes `init()`.
Par exemple :
```php
<?php
namespace yii\components\MyClass;
use yii\base\Object;
class MyClass extends Object
{
public $prop1;
public $prop2;
public function __construct($param1, $param2, $config = [])
{
// ... initialisation avant l'application de la configuration
parent::__construct($config);
}
public function init()
{
parent::init();
// ... initialization après l'application de la configuration
}
}
```
Le respect de ces conseils rend vos composants [configurables](concept-configurations.md) lors de leur création. Par exemple :
```php
$component = new MyClass(1, 2, ['prop1' => 3, 'prop2' => 4]);
// alternatively
$component = \Yii::createObject([
'class' => MyClass::className(),
'prop1' => 3,
'prop2' => 4,
], [1, 2]);
```
> Info: bien que l'approche qui consiste à appeler la méthode [[Yii::createObject()]] semble plus compliquée, elle est plus puissante car elle est mise en œuvre sur un [conteneur d'injection de dépendances](concept-di-container.md).
La classe [[yii\base\Object]] fait appliquer le cycle de vie suivant de l'objet :
1. Pré-initialisation dans le constructeur. Vous pouvez définir les propriétés par défaut à cet endroit.
2. Configuration de l'objet via `$config`. La configuration peut écraser les valeurs par défaut définies dans le constructeur.
3. Post-initialisation dans la méthode [[yii\base\Object::init()|init()]]. Vous pouvez redéfinir cette méthode pour effectuer des tests sanitaires et normaliser les propriétés.
4. Appel des méthodes de l'objet.
Les trois premières étapes arrivent toutes durant la construction de l'objet. Cela signifie qu'une fois que vous avez obtenu une instance de la classe (c.-à-d. un objet), cet objet a déjà été initialisé dans un état propre et fiable.

230
docs/guide-fr/concept-configurations.md

@ -0,0 +1,230 @@
Configurations
==============
Les configurations sont très largement utilisées dans Yii lors de la création d'objets ou l'initialisation d'objets existants. Les configurations contiennent généralement le nom de la classe de l'objet en cours de création, et une liste de valeurs initiales qui doivent être assignées aux [propriétés](concept-properties.md) de l'objet. Elles peuvent aussi comprendre une liste de gestionnaires qui doivent être attachés aux [événements](concept-events.md) de l'objet et/ou une liste de [comportements](concept-behaviors.md) qui doivent être attachés à l'objet.
Dans ce qui suit, une configuration est utilisée pour créer et initialiser une connexion à une base de données :
```php
$config = [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
];
$db = Yii::createObject($config);
```
La méthode [[Yii::createObject()]] prend un tableau de configuration en tant qu'argument et crée un objet en instanciant la classe nommée dans la configuration. Lorsque l'objet est instancié, le reste de la configuration est utilisé pour initialiser les propriétés de l'objet, ses gestionnaires d'événement et ses comportements.
Si vous disposez déjà d'un objet, vous pouvez utiliser la méthode [[Yii::configure()]] pour initialiser les propriétés de l'objet avec un tableau de configuration :
```php
Yii::configure($object, $config);
```
Notez bien que dans ce cas, le tableau de configuration ne doit pas contenir d'élément `class`.
## Format d'une configuration <span id="configuration-format"></span>
Le format d'une configuration peut être formellement décrit comme suit :
```php
[
'class' => 'ClassName',
'propertyName' => 'propertyValue',
'on eventName' => $eventHandler,
'as behaviorName' => $behaviorConfig,
]
```
* L'élément `class` spécifie un nom de classe pleinement qualifié pour l'objet à créer.
* L'élément `propertyName` spécifie les valeurs initiales d'une propriété nommé property. Les clés sont les noms de propriété et les valeurs correspondantes les valeurs initiales. Seules les variables membres publiques et les [propriétés](concept-properties.md) définies par des méthodes d'obtention (*getters*) et/ou des méthodes d'assignation (*setters*) peuvent être configurées.
* Les éléments `on eventName` spécifient quels gestionnaires doivent être attachés aux [événements](concept-events.md) de l'objet. Notez que les clés du tableau sont formées en préfixant les noms d'événement par `on`. Reportez-vous à la section [événements](concept-events.md) pour connaître les formats des gestionnaires d'événement pris en charge.
* L'élément `as behaviorName` spécifie quels [comportements](concept-behaviors.md) doivent être attachés à l'objet. Notez que les clés du tableau sont formées en préfixant les noms de comportement par `as `; la valeur `$behaviorConfig` représente la configuration pour la création du comportement, comme une configuration normale décrite ici.
Ci-dessous, nous présentons un exemple montrant une configuration avec des valeurs initiales de propriétés, des gestionnaires d'événement et des comportements.
```php
[
'class' => 'app\components\SearchEngine',
'apiKey' => 'xxxxxxxx',
'on search' => function ($event) {
Yii::info("Keyword searched: " . $event->keyword);
},
'as indexer' => [
'class' => 'app\components\IndexerBehavior',
// ... property init values ...
],
]
```
## Utilisation des configurations <span id="using-configurations"></span>
Les configurations sont utilisées en de nombreux endroits dans Yii. Au début de cette section, nous avons montré comment créer un objet obéissant à une configuration en utilisant la méthode [[Yii::createObject()]]. Dans cette sous-section, nous allons décrire les configurations d'applications et les configurations d'objets graphiques (*widget*) – deux utilisations majeures des configurations.
### Configurations d'applications <span id="application-configurations"></span>
La configuration d'une [application](structure-applications.md) est probablement l'un des tableaux les plus complexes dans Yii. Cela est dû au fait que la classe [[yii\web\Application|application]] dispose d'un grand nombre de propriétés et événements configurables. De première importance, se trouve sa propriété [[yii\web\Application::components|components]] qui peut recevoir un tableau de configurations pour créer des composants qui sont enregistrés durant l'exécution de l'application. Ce qui suit est un résumé de la configuration de l'application du [modèle de projet *basic*](start-installation.md).
```php
$config = [
'id' => 'basic',
'basePath' => dirname(__DIR__),
'extensions' => require(__DIR__ . '/../vendor/yiisoft/extensions.php'),
'components' => [
'cache' => [
'class' => 'yii\caching\FileCache',
],
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
],
'log' => [
'class' => 'yii\log\Dispatcher',
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
],
],
],
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=stay2',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
],
],
];
```
La configuration n'a pas de clé `class`. Cela tient au fait qu'elle est utilisée comme indiqué ci-dessous dans un [script d'entrée](structure-entry-scripts.md), dans lequel le nom de la classe est déjà donné :
```php
(new yii\web\Application($config))->run();
```
Plus de détails sur la configuration de la propriété `components` d'une application sont donnés dans la section [Applications](structure-applications.md) et dans la section [Localisateur de services](concept-service-locator.md).
### Configurations des objets graphiques <span id="widget-configurations"></span>
Lorsque vous utilisez des [objets graphiques](structure-widgets.md), vous avez souvent besoin d'utiliser des configurations pour personnaliser les propriétés de ces objets graphiques. Les méthodes [[yii\base\Widget::widget()]] et [[yii\base\Widget::begin()]] peuvent toutes deux être utilisées pour créer un objet graphique. Elles acceptent un tableau de configuration, comme celui qui suit :
```php
use yii\widgets\Menu;
echo Menu::widget([
'activateItems' => false,
'items' => [
['label' => 'Home', 'url' => ['site/index']],
['label' => 'Products', 'url' => ['product/index']],
['label' => 'Login', 'url' => ['site/login'], 'visible' => Yii::$app->user->isGuest],
],
]);
```
La configuration ci-dessus crée un objet graphique nommé `Menu` et initialise sa propriété `activateItems` à `false` (faux). La propriété `items` est également configurée avec les items de menu à afficher.
Notez que, comme le nom de classe est déjà donné, le tableau de configuration ne doit PAS contenir de clé `class`.
## Fichiers de configuration <span id="configuration-files"></span>
Lorsqu'une configuration est très complexe, une pratique courante est de la stocker dans un ou plusieurs fichiers PHP appelés *fichiers de configuration*. Un fichier de configuration retourne un tableau PHP représentant la configuration. Par exemple, vous pouvez conserver une configuration d'application dans un fichier nommé `web.php`, comme celui qui suit :
```php
return [
'id' => 'basic',
'basePath' => dirname(__DIR__),
'extensions' => require(__DIR__ . '/../vendor/yiisoft/extensions.php'),
'components' => require(__DIR__ . '/components.php'),
];
```
Parce que la configuration `components` et elle aussi complexe, vous pouvez la stocker dans un fichier séparé appelé `components.php` et requérir ce fichier dans `web.php` comme c'est montré ci-dessus. Le contenu de `components.php` ressemble à ceci :
```php
return [
'cache' => [
'class' => 'yii\caching\FileCache',
],
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
],
'log' => [
'class' => 'yii\log\Dispatcher',
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
],
],
],
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=stay2',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
],
];
```
Pour obtenir une configuration stockée dans un fichier de configuration, il vous suffit requérir ce fichier avec "require", comme ceci :
```php
$config = require('path/to/web.php');
(new yii\web\Application($config))->run();
```
## Configurations par défaut <span id="default-configurations"></span>
La méthode [[Yii::createObject()]] est implémentée sur la base du [conteneur d'injection de dépendances](concept-di-container.md). Cela vous permet de spécifier un jeu de configurations dites *configurations par défaut* qui seront appliquées à TOUTES les instances des classes spécifiées lors de leur création en utilisant [[Yii::createObject()]]. Les configurations par défaut peuvent être spécifiées en appelant `Yii::$container->set()` dans le code d'[amorçage](runtime-bootstrapping.md).
Par exemple, si vous voulez personnaliser l'objet graphique [[yii\widgets\LinkPager]] de façon à ce que TOUS les pagineurs affichent au plus 5 boutons de page (la valeur par défaut est 10), vous pouvez utiliser le code suivant pour atteindre ce but :
```php
\Yii::$container->set('yii\widgets\LinkPager', [
'maxButtonCount' => 5,
]);
```
Sans les configurations par défaut, vous devez configurer la propriété `maxButtonCount` partout où vous utilisez un pagineur.
## Constantes d'environment <span id="environment-constants"></span>
Les configurations varient souvent en fonction de l'environnement dans lequel les applications s'exécutent. Par exemple, dans l'environnement de développement, vous désirez peut être utiliser la base de données nommée `mydb_dev`, tandis que sur un serveur en production, vous désirez utiliser la base de données nommée `mydb_prod`. Pour faciliter le changement d'environnement, Yii fournit une constante nommée `YII_ENV` que vous pouvez définir dans le [script d'entrée](structure-entry-scripts.md) de votre application. Par exemple :
```php
defined('YII_ENV') or define('YII_ENV', 'dev');
```
Vous pouvez assigner à `YII_ENV` une des valeurs suivantes :
- `prod`: environnement de production. La constante `YII_ENV_PROD` est évaluée comme étant `true` (vrai). C'est la valeur par défaut de `YII_ENV`.
- `dev`: environnement de développement. La constante `YII_ENV_DEV` est évaluée comme étant `true` (vrai).
- `test`: environnement de test. La constante `YII_ENV_TEST` est évaluée comme étant `true` (vrai).
Avec ces constantes d'environnement, vous pouvez spécifier les configurations en fonction de l'environnement courant. Par exemple, votre configuration d'application peut contenir le code suivant pour activer la [barre de débogage et le module de débogage](tool-debugger.md) dans l'environnement de développement seulement :
```php
$config = [...];
if (YII_ENV_DEV) {
// ajustement de la configuration pour l'environnement 'dev'
$config['bootstrap'][] = 'debug';
$config['modules']['debug'] = 'yii\debug\Module';
}
return $config;
```

340
docs/guide-fr/concept-di-container.md

@ -0,0 +1,340 @@
Conteneur d'injection de dépendances
====================================
Un conteneur d'injection de dépendances (DI container) est un objet qui sait comment instancier et configurer des objets et tous leurs objets dépendants. [Cet article de Martin Fowler](http://martinfowler.com/articles/injection.html) explique très bien en quoi un conteneur d'injection de dépendances est utile. Ici nous expliquons essentiellement l'utilisation qui est faite du conteneur d'injection de dépendances que fournit Yii.
Injection de dépendances <span id="dependency-injection"></span>
------------------------
Yii fournit la fonctionnalité conteneur d'injection de dépendances via la classe [[yii\di\Container]]. Elle prend en charge les sortes d'injections de dépendance suivantes :
* Injection par le constructeur;
* Injection par les méthodes;
* Injection par les méthodes d'assignation et les propriétés;
* Injection par une méthode de rappel PHP;
### Injection par le constructeur <span id="constructor-injection"></span>
Le conteneur d'injection de dépendances prend en charge l'injection dans le constructeur grâce à l'allusion au type pour les paramètres du constructeur. L'allusion au type indique au conteneur de quelles classes ou de quelles interfaces dépend l'objet concerné par la construction. Le conteneur essaye de trouver les instances des classes dont l'objet dépend pour les injecter dans le nouvel objet via le constructeur. Par exemple :
```php
class Foo
{
public function __construct(Bar $bar)
{
}
}
$foo = $container->get('Foo');
// qui est équivalent à ce qui suit
$bar = new Bar;
$foo = new Foo($bar);
```
### Injection par les méthodes <span id="method-injection"></span>
Ordinairement, les classes dont une classe dépend sont passées à son constructeur et sont disponibles dans la classe durant tout son cycle de vie. Avec l'injection par les méthodes, il est possible de fournir une classe qui est seulement nécessaire à une unique méthode de la classe, et qu'il est impossible de passer au constructeur, ou qui pourrait entraîner trop de surplus de travail dans la majorité des classes qui l'utilisent.
Une méthode de classe peut être définie comme la méthode `doSomething()` de l'exemple suivant :
```php
class MyClass extends \yii\base\Component
{
public function __construct(/*ici, quelques classes légères dont la classe dépend*/, $config = [])
{
// ...
}
public function doSomething($param1, \ma\dependance\Lourde $something)
{
// faire quelque chose avec $something
}
}
```
Vous pouvez appeler la méthode, soit en passant une instance de `\ma\dependance\Lourde` vous-même, soit en utilisant [[yii\di\Container::invoke()]] comme ceci :
```php
$obj = new MyClass(/*...*/);
Yii::$container->invoke([$obj, 'doSomething'], ['param1' => 42]); // $something est fournie par le conteneur d'injection de dépendances
```
### Injection par les méthodes d'assignation et les propriétés <span id="setter-and-property-injection"></span>
L'injection par les méthodes d'assignation et les propriétés est prise en charge via les [configurations](concept-configurations.md). Lors de l'enregistrement d'une dépendance ou lors de la création d'un nouvel objet, vous pouvez fournir une configuration qui est utilisée par le conteneur pour injecter les dépendances via les méthodes d'assignation ou les propriétés correspondantes. Par exemple :
```php
use yii\base\Object;
class Foo extends Object
{
public $bar;
private $_qux;
public function getQux()
{
return $this->_qux;
}
public function setQux(Qux $qux)
{
$this->_qux = $qux;
}
}
$container->get('Foo', [], [
'bar' => $container->get('Bar'),
'qux' => $container->get('Qux'),
]);
```
> Info: la méthode [[yii\di\Container::get()]] accepte un tableau de configuration qui peut être appliqué à l'objet en création comme troisième paramètre. Si la classe implémente l'interface [[yii\base\Configurable]] (p. ex. [[yii\base\Object]]), le tableau de configuration est passé en tant que dernier paramètre du constructeur de la classe; autrement le tableau de configuration serait appliqué *après* la création de l'objet.
### Injection par une méthode de rappel PHP <span id="php-callable-injection"></span>
Dans ce cas, le conteneur utilise une fonction de rappel PRP enregistrée pour construire de nouvelles instances d'une classe. À chaque fois que [[yii\di\Container::get()]] est appelée, la fonction de rappel correspondante est invoquée. Cette fonction de rappel est chargée de la résolution des dépendances et de leur injection appropriée dans les objets nouvellement créés. Par exemple :
```php
$container->set('Foo', function () {
$foo = new Foo(new Bar);
// ... autres initialisations ...
return $foo;
});
$foo = $container->get('Foo');
```
Pour cacher la logique complexe de construction des nouveaux objets, vous pouvez utiliser un méthode de classe statique en tant que fonction de rappel. Par exemple :
```php
class FooBuilder
{
public static function build()
{
$foo = new Foo(new Bar);
// ... autres initialisations ...
return $foo;
}
}
$container->set('Foo', ['app\helper\FooBuilder', 'build']);
$foo = $container->get('Foo');
```
En procédant de cette manière, la personne qui désire configurer la classe `Foo` n'a plus besoin de savoir comment elle est construite.
Enregistrement des dépendances <span id="registering-dependencies"></span>
------------------------------
Vous pouvez utiliser [[yii\di\Container::set()]] pour enregistrer les dépendances. L'enregistrement requiert un nom de dépendance et une définition de dépendance. Un nom de dépendance peut être un nom de classe, un nom d'interface, ou un nom d'alias ; et une définition de dépendance peut être une nom de classe, un tableau de configuration, ou une fonction de rappel PHP.
```php
$container = new \yii\di\Container;
// enregistre un nom de classe tel quel. Cela peut être sauté.
$container->set('yii\db\Connection');
// enregistre une interface
// Lorsqu'une classe dépend d'une interface, la classe correspondante
// est instanciée en tant qu'objet dépendant
$container->set('yii\mail\MailInterface', 'yii\swiftmailer\Mailer');
// enregistre un nom d'alias. Vous pouvez utiliser $container->get('foo')
// pour créer une instance de Connection
$container->set('foo', 'yii\db\Connection');
// enregistre une classe avec une configuration. La configuration
// est appliquée lorsque la classe est instanciée par get()
$container->set('yii\db\Connection', [
'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
]);
// enregistre un nom d'alias avec une configuration de classe
// Dans ce cas, un élément "class" est requis pour spécifier la classe
$container->set('db', [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
]);
// enregistre une fonction de rappel PHP
// La fonction de rappel est exécutée à chaque fois que $container->get('db') est appelée
$container->set('db', function ($container, $params, $config) {
return new \yii\db\Connection($config);
});
// enregistre une interface de composant
// $container->get('pageCache') retourne la même instance à chaque fois qu'elle est appelée
$container->set('pageCache', new FileCache);
```
> Tip: si un nom de dépendance est identique à celui de la définition de dépendance correspondante, vous n'avez pas besoin de l'enregistrer dans le conteneur d'injection de dépendances.
Une dépendance enregistrée via `set()` génère une instance à chaque fois que la dépendance est nécessaire. Vous pouvez utiliser [[yii\di\Container::setSingleton()]] pour enregistrer une dépendance qui ne génère qu'une seule instance :
```php
$container->setSingleton('yii\db\Connection', [
'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
]);
```
Résolution des dépendances <span id="resolving-dependencies"></span>
--------------------------
Une fois que vous avez enregistré des dépendances, vous pouvez utiliser le conteneur d'injection de dépendances pour créer de nouveau objets, et le conteneur résout automatiquement les dépendances en les instanciant et en les injectant dans les nouveaux objets. Le résolution des dépendances est récursive, ce qui signifie que si une dépendance a d'autres dépendances, ces dépendances sont aussi résolue automatiquement.
Vous pouvez utiliser [[yii\di\Container::get()]] pour créer de nouveaux objets. La méthode accepte un nom de dépendance qui peut être un nom de classe, un nom d'interface ou un nom d'alias. Le nom de dépendance, peut être, ou ne pas être, enregistré via `set()` ou `setSingleton()`. En option, vous pouvez fournir une liste de paramètre du constructeur de la classe et une [configuration](concept-configurations.md) pour configurer l'objet nouvellement créé. Par exemple :
```php
// "db" est un nom d'alias enregistré préalablement
$db = $container->get('db');
// équivalent à : $engine = new \app\components\SearchEngine($apiKey, $apiSecret, ['type' => 1]);
$engine = $container->get('app\components\SearchEngine', [$apiKey, $apiSecret], ['type' => 1]);
```
En coulisses, le conteneur d'injection de dépendances ne fait rien de plus que de créer l'objet. Le conteneur inspecte d'abord le constructeur de la classe pour trouver les classes dépendantes ou les noms d'interface et résout ensuite ces dépendances récursivement.
Le code suivant montre un exemple plus sophistiqué. La classe `UserLister` dépend d'un objet implémentant l'interface `UserFinderInterface`; la classe `UserFinder` implémente cet interface et dépend de l'objet `Connection`. Toutes ces dépendances sont déclarées via l'allusion au type des paramètres du constructeur de la classe. Avec l'enregistrement des dépendances de propriétés, le conteneur d'injection de dépendances est capable de résoudre ces dépendances automatiquement et de créer une nouvelle instance de `UserLister` par un simple appel à `get('userLister')`.
```php
namespace app\models;
use yii\base\Object;
use yii\db\Connection;
use yii\di\Container;
interface UserFinderInterface
{
function findUser();
}
class UserFinder extends Object implements UserFinderInterface
{
public $db;
public function __construct(Connection $db, $config = [])
{
$this->db = $db;
parent::__construct($config);
}
public function findUser()
{
}
}
class UserLister extends Object
{
public $finder;
public function __construct(UserFinderInterface $finder, $config = [])
{
$this->finder = $finder;
parent::__construct($config);
}
}
$container = new Container;
$container->set('yii\db\Connection', [
'dsn' => '...',
]);
$container->set('app\models\UserFinderInterface', [
'class' => 'app\models\UserFinder',
]);
$container->set('userLister', 'app\models\UserLister');
$lister = $container->get('userLister');
// qui est équivalent à :
$db = new \yii\db\Connection(['dsn' => '...']);
$finder = new UserFinder($db);
$lister = new UserLister($finder);
```
Utilisation pratique <span id="practical-usage"></span>
--------------------
Yii crée un conteneur d'injection de dépendances lorsque vous incluez le fichier `Yii.php` dans le [script d'entrée](structure-entry-scripts.md) de votre application. Le conteneur d'injection de dépendances est accessible via [[Yii::$container]]. Lorsque vous appelez [[Yii::createObject()]], la méthode appelle en réalité la méthode [[yii\di\Container::get()|get()]] du conteneur pour créer le nouvel objet. Comme c'est dit plus haut, le conteneur d'injection de dépendances résout automatiquement les dépendances (s'il en existe) et les injecte dans l'objet créé. Parce que Yii utilise [[Yii::createObject()]] dans la plus grande partie du code de son noyau pour créer de nouveaux objets, cela signifie que vous pouvez personnaliser ces objets globalement en utilisant [[Yii::$container]].
Par exemple, vous pouvez personnaliser globalement le nombre de boutons de pagination par défaut de l'objet graphique [[yii\widgets\LinkPager]] :
```php
\Yii::$container->set('yii\widgets\LinkPager', ['maxButtonCount' => 5]);
```
Maintenant, si vous utilisez l'objet graphique dans une vue avec le code suivant, la propriété `maxButtonCount` est initialisée à la valeur 5 au lieu de la valeur par défaut 10 qui est définie dans la classe.
```php
echo \yii\widgets\LinkPager::widget();
```
Vous pouvez encore redéfinir la valeur définie par le conteneur d'injection de dépendances via :
```php
echo \yii\widgets\LinkPager::widget(['maxButtonCount' => 20]);
```
> Tip: peu importe de quel type de valeur il s'agit, elle est redéfinie, c'est pourquoi vous devez vous montrer prudent avec les tableaux d'options. Ils ne sont pas fusionnés.
Un autre exemple est de profiter de l'injection automatique par le constructeur du conteneur d'injection de dépendances. Supposons que votre classe de contrôleur dépende de quelques autres objets, comme un service de réservation d'hôtel. Vous pouvez déclarer la dépendance via un paramètre de constructeur et laisser le conteneur d'injection de dépendances la résoudre pour vous.
```php
namespace app\controllers;
use yii\web\Controller;
use app\components\BookingInterface;
class HotelController extends Controller
{
protected $bookingService;
public function __construct($id, $module, BookingInterface $bookingService, $config = [])
{
$this->bookingService = $bookingService;
parent::__construct($id, $module, $config);
}
}
```
Si vous accédez au contrôleur à partir du navigateur, vous verrez un message d'erreur se plaignant que l'interface `BookingInterface` ne peut pas être instanciée. Cela est dû au fait que vous devez dire au conteneur d'injection de dépendances comment s'y prendre avec cette dépendance :
```php
\Yii::$container->set('app\components\BookingInterface', 'app\components\BookingService');
```
Maintenant, si vous accédez à nouveau au contrôleur, une instance de `app\components\BookingService` est créée et injectée en tant que troisième paramètre du constructeur.
À quel moment enregistrer les dépendances <span id="when-to-register-dependencies"></span>
-----------------------------------------
Comme les dépendances sont nécessaires lorsque de nouveaux objets sont créés, leur enregistrement doit être fait aussi tôt que possible. Les pratiques recommandées sont :
* Si vous êtes le développeur d'une application, vous pouvez enregistrer les dépendances dans le [script d'entrée](structure-entry-scripts.md) de votre application ou dans un script qui est inclus par le script d'entrée.
* Si vous êtes le développeur d'une [extension](structure-extensions.md) distribuable, vous pouvez enregistrer les dépendances dans la classe d'amorçage de l'extension.
Résumé <span id="summary"></span>
-------
L'injection de dépendances et le [localisateur de services](concept-service-locator.md) sont tous deux des modèles de conception populaires qui permettent des construire des logiciels d'une manière faiblement couplée et plus testable. Nous vous recommandons fortement de lire [l'article de Martin](http://martinfowler.com/articles/injection.html) pour acquérir une compréhension plus profonde de l'injection de dépendances et du localisateur de services.
Yii implémente son [localisateur de services](concept-service-locator.md) par dessus le conteneur d'injection de dépendances. Lorsqu'un localisateur de services essaye de créer une nouvelle instance d'un objet, il appelle le conteneur d'injection de dépendances. Ce dernier résout les dépendances automatiquement comme c'est expliqué plus haut.

319
docs/guide-fr/concept-events.md

@ -0,0 +1,319 @@
Événements
==========
Les événement vous permettent d'injecter du code personnalisé dans le code existant à des points précis de son exécution. Vous pouvez attacher du code personnalisé à un événement de façon à ce que, lorsque l'événement est déclenché, le code s'exécute automatiquement. Par exemple, un objet serveur de courriel peut déclencher un événement `messageSent` (message envoyé) quand il réussit à envoyer un message. Si vous voulez conserver une trace des messages dont l'envoi a réussi, vous pouvez simplement attacher le code de conservation de la trace à l'événement `messageSent`.
Yii introduit une classe de base appelée [[yii\base\Component]] pour prendre en charge les événements. Si une classe a besoin de déclencher des événements, elle doit êtendre la classe [[yii\base\Component]], ou une de ses classes filles.
Gestionnaires d'événements <span id="event-handlers"></span>
--------------------------
Un gestionnaire d'événement est une [fonction de rappel PHP](http://www.php.net/manual/en/language.types.callable.php) qui est exécutée lorsque l'événement à laquelle elle est attachée est déclenché. Vous pouvez utiliser n'importe laquelle des fonctions de rappel suivantes :
- une fonction PHP globale spécifiée sous forme de chaîne de caractères (sans les parenthèses) p. ex., `'trim'` ;
- une méthode d'objet spécifiée sous forme de tableau constitué d'un nom d'objet et d'un nom de méthode sous forme de chaîne de caractères (sans les parentèses), p. ex., `[$object, 'methodName']`;
- une méthode d'une classe statique spécifiée sous forme de tableau constitué d'un nom de classe et d'un nom de méthode sous forme de chaîne de caractères (sans les parenthèses), p. ex., `['ClassName', 'methodName']`;
- une fonction anonyme p. ex., `function ($event) { ... }`.
La signature d'un gestionnaire d'événement est :
```php
function ($event) {
// $event est un objet de la classe yii\base\Event ou des ses classes filles
}
```
Via le paramètre `$event`, un gestionnaire d'événement peut obtenir l'information suivante sur l'événement qui vient de se produire :
- le [[yii\base\Event::name|nom de l'événement]];
- l'[[yii\base\Event::sender|émetteur de l'événement]]: l'objet dont la méthode `trigger()` a été appelée ;
- les [[yii\base\Event::data|données personnalisées]]: les données fournies lorsque le gestionnaire d'événement est attaché (les explications arrivent bientôt).
Attacher des gestionnaires d'événements <span id="attaching-event-handlers"></span>
---------------------------------------
Vous pouvez attacher un gestionnaire d'événement en appelant la méthode [[yii\base\Component::on()]] du composant. Par exemple :
```php
$foo = new Foo;
// le gestionnaire est une fonction globale
$foo->on(Foo::EVENT_HELLO, 'function_name');
// le gestionnaire est une méthode d'objet
$foo->on(Foo::EVENT_HELLO, [$object, 'methodName']);
// le gestionnaire est une méthode d'une classe statique
$foo->on(Foo::EVENT_HELLO, ['app\components\Bar', 'methodName']);
// le gestionnaire est un fonction anonyme
$foo->on(Foo::EVENT_HELLO, function ($event) {
// event handling logic
});
```
Vous pouvez aussi attacher des gestionnaires d'événements via les [configurations](concept-configurations.md). Pour plus de détails, reportez-vous à la section [Configurations](concept-configurations.md#configuration-format).
Losque vous attachez un gestionnaire d'événement, vous pouvez fournir des données additionnelles telles que le troisième paramètre de [[yii\base\Component::on()]]. Les données sont rendues disponibles au gestionnaire lorsque l'événement est déclenché et que le gestionnaire est appelé. Par exemple :
```php
// Le code suivant affiche "abc" lorsque l'événement est déclenché
// parce que $event->data contient les données passées en tant que troisième argument à la méthode "on"
$foo->on(Foo::EVENT_HELLO, 'function_name', 'abc');
function function_name($event) {
echo $event->data;
}
```
Ordre des gestionnaires d'événements
------------------------------------
Vous pouvez attacher un ou plusieurs gestionnaires à un seul événement. Lorsqu'un événement est déclenché, les gestionnaires attachés sont appelés dans l'ordre dans lequel ils ont été attachés à l'événement. Si un gestionnaire a besoin d'arrêter l'appel des gestionnaires qui viennent après lui, il doit définir la propriété [[yii\base\Event::handled (géré)]] du paramètre `$event` parameter à `true`:
```php
$foo->on(Foo::EVENT_HELLO, function ($event) {
$event->handled = true;
});
```
Par défaut, un gestionnaire nouvellement attaché est ajouté à la file des gestionnaires de l'événement. En conséquence, le gestionnaire est appelé en dernier lorsque l'événement est déclenché. Pour insérer un événement nouvellement attaché en tête de file pour qu'il soit appelé le premier, vous devez appeler [[yii\base\Component::on()]], en lui passant `false` pour le quatrième paramètre `$append`:
```php
$foo->on(Foo::EVENT_HELLO, function ($event) {
// ...
}, $data, false);
```
Déclenchement des événements <span id="triggering-events"></span>
----------------------------
Les événements sont déclenchés en appelant la méthode [[yii\base\Component::trigger()]]. La méthode requiert un *nom d'événement* et, en option, un objet événement qui décrit les paramètres à passer aux gestionnaires de cet événement. Par exemple :
```php
namespace app\components;
use yii\base\Component;
use yii\base\Event;
class Foo extends Component
{
const EVENT_HELLO = 'hello';
public function bar()
{
$this->trigger(self::EVENT_HELLO);
}
}
```
Avec le code précédent, tout appel à `bar()` déclenche un événement nommé `hello`.
> Tip: il est recommandé d'utiliser des constantes de classe pour représenter les noms d'événement. Dans l'exemple qui précède, la constante `EVENT_HELLO` représente l'événement `hello`. Cette approche procure trois avantages. Primo, elle évite les erreurs de frappe. Secondo, elle permet aux événements d'être reconnus par le mécanisme d'auto-complètement des EDI. Tertio, vous pouvez dire quels événements sont pris en charge par une classe en vérifiant la déclaration de ses constantes.
Parfois, lors du déclenchement d'un événement, vous désirez passer des informations additionnelles aux gestionnaires de cet événement. Par exemple, un serveur de courriels peut souhaiter passer les informations sur le message aux gestionnaires de l'événement `messageSent` pour que ces derniers soient informés de certaines particularités des messages envoyés. Pour ce faire, vous pouvez fournir un objet événement comme deuxième paramètre de la méthode [[yii\base\Component::trigger()]]. L'objet événement doit simplement être une instance de la classe [[yii\base\Event]] ou d'une de ses classes filles. Par exemple :
```php
namespace app\components;
use yii\base\Component;
use yii\base\Event;
class MessageEvent extends Event
{
public $message;
}
class Mailer extends Component
{
const EVENT_MESSAGE_SENT = 'messageSent';
public function send($message)
{
// ...sending $message...
$event = new MessageEvent;
$event->message = $message;
$this->trigger(self::EVENT_MESSAGE_SENT, $event);
}
}
```
Lorsque la méthode [[yii\base\Component::trigger()]] est appelée, elle appelle tous les gestionnaires attachés à l'événement nommé.
Détacher des gestionnaires d'événements <span id="detaching-event-handlers"></span>
---------------------------------------
Pour détacher un gestionnaire d'un événement, appelez la méthode [[yii\base\Component::off()]]. Par exemple :
```php
// le gestionnaire est une fonction globale
$foo->off(Foo::EVENT_HELLO, 'function_name');
// le gestionnaire est une méthode d'objet
$foo->off(Foo::EVENT_HELLO, [$object, 'methodName']);
// le gestionnaire est une méthode d'une classe statique
$foo->off(Foo::EVENT_HELLO, ['app\components\Bar', 'methodName']);
// le gestionnaire est une fonction anonyme
$foo->off(Foo::EVENT_HELLO, $anonymousFunction);
```
Notez qu'en général, vous ne devez pas essayer de détacher une fonction anonyme sauf si vous l'avez stokée quelque part lorsque vous l'avez attachée à un événement. Dans l'exemple ci-dessus, on suppose que la fonctions anonyme est stockée dans une variable nommée `$anonymousFunction`.
Pour détacher *tous* les gestionnaires d'un événement, appelez simplement la méthode [[yii\base\Component::off()]] sans le deuxième paramètre :
```php
$foo->off(Foo::EVENT_HELLO);
```
Gestionnaire d'événement au niveau de la classe <span id="class-level-event-handlers"></span>
-----------------------------------------------
Les sections précédent décrivent comment attacher un gestionnaire à un événement au *niveau d'une instance*. Parfois, vous désirez répondre à un événement déclenché par *chacune des* instances d'une classe plutôt que par une instance spécifique. Au lieu d'attacher l'événement à chacune des instances, vous pouvez attacher le gestionnaire au *niveau de la classe* en appelant la méthode statique [[yii\base\Event::on()]].
Par exemple, un objet [Active Record](db-active-record.md) déclenche un événement [[yii\db\BaseActiveRecord::EVENT_AFTER_INSERT|EVENT_AFTER_INSERT]]
à chaque fois qu'il insère un nouvel enregistrement dans la base de données. Afin de suivre les insertions faites par tous les objets [Active Record](db-active-record.md), vous pouvez utiliser le code suivant :
```php
use Yii;
use yii\base\Event;
use yii\db\ActiveRecord;
Event::on(ActiveRecord::className(), ActiveRecord::EVENT_AFTER_INSERT, function ($event) {
Yii::trace(get_class($event->sender) . ' is inserted');
});
```
Le gestionnaire d'événement est invoqué à chaque fois qu'une instance de la classe [[yii\db\ActiveRecord|ActiveRecord]], ou d'une de ses classes filles, déclenche l'événement [[yii\db\BaseActiveRecord::EVENT_AFTER_INSERT|EVENT_AFTER_INSERT]]. Dans le gestionnaire, vous pouvez obtenir l'objet qui a déclenché l'événement via `$event->sender`.
Losqu'un objet déclenche un événement, il commence par appeler les gestionnaires attachés au niveau de l'instance, puis les gestionnaires attachés au niveau de la classe.
Vous pouvez déclencher un événement au *niveau de la classe* en appelant la méthode statique [[yii\base\Event::trigger()]]. Un événement déclenché au niveau de la classe n'est associé à aucun objet en particulier. En conséquence, il provoque l'appel des gestionnaires attachés au niveau de la classe seulement. Par exemple :
```php
use yii\base\Event;
Event::on(Foo::className(), Foo::EVENT_HELLO, function ($event) {
var_dump($event->sender); // displays "null"
});
Event::trigger(Foo::className(), Foo::EVENT_HELLO);
```
Notez que, dans ce cas, `$event->sender` fait référence au nom de la classe qui a déclenché l'événement plutôt qu'à une instance de classe.
> Note: comme les gestionnaires attachés au niveau de la classe répondent aux événements déclenchés par n'importe quelle instance de cette classe, ou de ses classes filles, vous devez utiliser cette fonctionnalité avec précaution, en particulier si la classe est une classe de bas niveau comme la classe [[yii\base\Object]].
Pour détacher un gestionnaire attaché au niveau de la classe, appelez [[yii\base\Event::off()]]. Par exemple :
```php
// détache $handler
Event::off(Foo::className(), Foo::EVENT_HELLO, $handler);
// détache tous les gestionnaires de Foo::EVENT_HELLO
Event::off(Foo::className(), Foo::EVENT_HELLO);
```
Événement utilisant des interfaces <span id="interface-level-event-handlers"></span>
----------------------------------
Il y a encore une manière plus abstraite d'utiliser les événements. Vous pouvez créer une interface séparée pour un événement particulier et l'implémenter dans des classes dans lesquelles vous en avez besoin.
Par exemple, vous pouvez créer l'interface suivante :
```php
namespace app\interfaces;
interface DanceEventInterface
{
const EVENT_DANCE = 'dance';
}
```
Et ajouter deux classes qui l'implémente :
```php
class Dog extends Component implements DanceEventInterface
{
public function meetBuddy()
{
echo "Woof!";
$this->trigger(DanceEventInterface::EVENT_DANCE);
}
}
class Developer extends Component implements DanceEventInterface
{
public function testsPassed()
{
echo "Yay!";
$this->trigger(DanceEventInterface::EVENT_DANCE);
}
}
```
Pour gérer l'évenement `EVENT_DANCE` déclenché par n'importe laquelle de ces classes, appelez [[yii\base\Event::on()|Event::on()]] et passez-lui le nom de l'interface comme premier argument :
```php
Event::on('app\interfaces\DanceEventInterface', DanceEventInterface::EVENT_DANCE, function ($event) {
Yii::trace(get_class($event->sender) . ' just danced'); // Will log that Dog or Developer danced
});
```
Vous pouvez déclencher l'événement de ces classes :
```php
// trigger event for Dog class
Event::trigger(Dog::className(), DanceEventInterface::EVENT_DANCE);
// trigger event for Developer class
Event::trigger(Developer::className(), DanceEventInterface::EVENT_DANCE);
```
Notez bien que vous ne pouvez pas déclencher l'événement de toutes les classes qui implémentent l'interface :,
```php
// NE FONCTIONNE PAS
Event::trigger('app\interfaces\DanceEventInterface', DanceEventInterface::EVENT_DANCE);
```
Pour détacher le gestionnaire d'événement, appelez [[yii\base\Event::off()|Event::off()]]. Par exemple :
```php
// détache $handler
Event::off('app\interfaces\DanceEventInterface', DanceEventInterface::EVENT_DANCE, $handler);
// détache tous les gestionnaires de DanceEventInterface::EVENT_DANCE
Event::off('app\interfaces\DanceEventInterface', DanceEventInterface::EVENT_DANCE);
```
Événements globaux <span id="global-events"></span>
------------------
Yii prend en charge ce qu'on appelle les *événements globaux*, qui est une astuce basée sur le mécanisme des événements décrit ci-dessus. L'événement global requiert un singleton accessible globalement tel que l'instance de l'[application](structure-applications.md) elle-même.
Pour créer l'événement global, un émetteur d'événement appelle la méthode `trigger()` du singleton pour déclencher l'événement au lieu d'appeler la méthode `trigger()` propre à l'émetteur. De façon similaire, les gestionnaires d'événement sont attachés à l'événement sur le singleton. Par exemple :
```php
use Yii;
use yii\base\Event;
use app\components\Foo;
Yii::$app->on('bar', function ($event) {
echo get_class($event->sender); // affiche "app\components\Foo"
});
Yii::$app->trigger('bar', new Event(['sender' => new Foo]));
```
Un avantage de l'utilisation d'événement globaux est que vous n'avez pas besoin d'un objet lorsque vous attachez un gestionnaire à l'événement qui est déclenché par l'objet. Au lieu de cela, vous attachez le gestionnaire et déclenchez l'événement via le singleton (p. ex. l'instance d'application).
Néanmoins, parce que l'espace de noms des événements globaux est partagé par toutes les parties, vous devez nommer les événements globaux avec prudence, par exemple en introduisant une sorte d'espace de noms (p. ex. "frontend.mail.sent", "backend.mail.sent").

61
docs/guide-fr/concept-properties.md

@ -0,0 +1,61 @@
Propriétés
==========
En PHP, les variables membres des classes sont aussi appelées *propriétés*. Ces variables font partie de la définition de la classe et sont utilisées pour représenter l'état d'une instance de cette classe (c.-à-d. à différentier une instance de la classe d'une autre). En pratique, vous désirez souvent gérer la lecture et l'écriture de ces propriété d'une manière particulière. Par exemple, vous pouvez désirer qu'une chaîne de caractères soit toujours nettoyée avant de l'assigner à une propriété `label`. Vous *pouvez* utiliser le code suivant pour arriver à cette fin :
```php
$object->label = trim($label);
```
Le revers du code ci-dessus est que vous devez appeler `trim()` partout ou vous voulez définir la propriété `label`. Si, plus tard, la propriété `label` devient sujette à de nouvelles exigences, telles que la première lettre doit être une capitale, vous auriez à modifier toutes les parties de code qui assigne une valeur à la propriété `label`. La répétition de code conduit à des bogues, et c'est une pratique courant de l'éviter autant que faire se peut.
Pour résoudre ce problème, Yii introduit une classe de base nommée [[yii\base\Object]] qui prend en charge la définition de propriétés sur la base de méthodes d'obtention (*getter*) et de méthode d'assignation (*setters*). Si une classe a besoin de cette fonctionnalité, il suffit qu'elle étende la classe[[yii\base\Object]], ou une de ses classes filles.
> Info: presque toutes les classes du noyau du framework Yii étendent la classe [[yii\base\Object]] ou une de ses classes filles. Cela veut dire, que chaque fois que vous trouvez une méthode d'obtention ou d'assignation dans une classe du noyau, vous pouvez l'utiliser comme une propriété.
Une méthode d'obtention est une méthode dont le nom commence par le mot `get` (obtenir) et une méthode d'assignation est une méthode dont le nom commence par le mot `set` (assigner, définir). Le nom après les mots préfixes `get` ou `set` définit le nom d'une propriété. Par exemple, une méthode d'obtention `getLabel` et/ou une méthode d'assignation `setLabel` obtient et assigne, respectivement, une propriété nommée `label`, comme le montre le code suivant :
```php
namespace app\components;
use yii\base\Object;
class Foo extends Object
{
private $_label;
public function getLabel()
{
return $this->_label;
}
public function setLabel($value)
{
$this->_label = trim($value);
}
}
```
Pour être tout à fait exact, les méthodes d'obtention et d'assignation créent la propriété `label`, qui dans ce cas fait référence en interne à une propriété privée nommée `_label`.
Les propriétés définies par les méthodes d'obtention et d'assignation peuvent être utilisées comme des variables membres de la classe. La différence principale est que, lorsqu'une telle propriété est lue, la méthode d'obtention correspondante est appelée; lorsqu'une valeur est assignée à la propriété, la méthode d'assignation correspondante est appelée. Par exemple :
```php
// équivalent à $label = $object->getLabel();
$label = $object->label;
// équivalent à $object->setLabel('abc');
$object->label = 'abc';
```
Une propriété définie par une méthode d'obtention (*getter*) sans méthode d'assignation (*setter*) est une propriété *en lecture seule*. Essayer d'assigner une valeur à une telle propriété provoque une exception [[yii\base\InvalidCallException|InvalidCallException]]. De façon similaire, une propriété définie par une méthode d'assignation sans méthode d'obtention est *en écriture seule*. Essayer de lire une telle propriété provoque une exception. Il n'est pas courant d'avoir des propriétés *en écriture seule*.
Il existe plusieurs règles spéciales pour les propriétés définies via des méthodes d'obtention et d'assignation, ainsi que certaines limitations sur elles.
* Le nom de telles propriétés sont *insensibles à la casse*. Par exempe, `$object->label` et `$object->Label` sont identiques. Cela est dû au fait que le nom des méthodes dans PHP est insensible à la casse.
* Si le nom d'uen telle propriété est identique à celui d'une variable membre de la classe, la dernier prévaut. Par exemple, si la classe ci-dessus `Foo` possède une variable mommée `label`, alors l'assignation `$object->label = 'abc'` affecte la *variable membre* `label` ; cette ligne ne fait pas appel à la méthode d'assignation `setLabel()`.
* Ces propriétés en prennent pas en charge la visibilité. Cela ne fait aucune différence pour les méthodes d'obtention et d'assignation qui définissent une propriété, que cette propriété soit publique, protégée ou privée.
* Les propriétés peuvent uniquement être définies par des méthodes d'obtention et d'assignation *non-statiques*. Les méthodes statiques ne sont pas traitées de la même manière.
* Un appel normal à la méthode `property_exists()` ne fonctionne pas pour déterminer des propriétés magiques. Vous devez appeler [[yii\base\Object::canGetProperty()|canGetProperty()]] ou [[yii\base\Object::canSetProperty()|canSetProperty()]] respectivement.
En revenant au problème évoqué au début de ce guide, au lieu d'appeler `trim()` partout où une valeur est assignée à `label`, vous pouvez vous contenter d'appeler `trim()` dans la méthode d'assignation `setLabel()`. Et si une nouvelle exigence apparaît – comme celle de mettre la première lettre en capitale – la méthode `setLabel()` peut être rapidement modifiée sans avoir à toucher à d'autres parties du code. Cet unique modification affecte l'ensemble des assignation de `label`.

101
docs/guide-fr/concept-service-locator.md

@ -0,0 +1,101 @@
Localisateur de services
========================
Un localisateur de services est un objet que sait comment fournir toutes sortes de services (ou composants) dont une application peut avoir besoin. Dans le localisateur de services, chaque composant existe seulement sous forme d'une unique instance, identifiée de manière unique par un identifiant. Vous utilisez l'identifiant pour retrouver un composant du localisateur de services.
Dans Yii, un localisateur de service est simplement une instance de [[yii\di\ServiceLocator]] ou d'une de ses classes filles.
Le localisateur de service le plus couramment utilisé dans Yii est l'objet *application*, auquel vous avez accès via `\Yii::$app`. Les services qu'il procure, tels les composants `request`, `response` et `urlManager`, sont appelés *composants d'application*. Vous pouvez configurer ces trois composants, ou même les remplacer facilement avec votre propre implémentation, en utilisant les fonctionnalités procurées par le localisateur de services.
En plus de l'objet application, chaque objet module est aussi un localisateur de services.
Pour utiliser un localisateur de service, la première étape est d'enregistrer le composant auprès de lui. Un composant peut être enregistré via la méthode [[yii\di\ServiceLocator::set()]]. Le code suivant montre différentes manières d'enregistrer des composants :
```php
use yii\di\ServiceLocator;
use yii\caching\FileCache;
$locator = new ServiceLocator;
// enregistre "cache" en utilisant un nom de classe qui peut être utilisé pour créer un composant
$locator->set('cache', 'yii\caching\ApcCache');
// enregistre "db" en utilisant un tableau de configuration qui peut être utilisé pour créer un composant
$locator->set('db', [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=demo',
'username' => 'root',
'password' => '',
]);
// enregistre "search" en utilisant une fonction anonyme qui construit un composant
$locator->set('search', function () {
return new app\components\SolrService;
});
// enregistre "pageCache" en utilisant un composant
$locator->set('pageCache', new FileCache);
```
Une fois qu'un composant a été enregistré, vous pouvez y accéder via son identifiant, d'une des deux manières suivantes :
```php
$cache = $locator->get('cache');
// ou en alternative
$cache = $locator->cache;
```
Comme montré ci-dessus, [[yii\di\ServiceLocator]] vous permet d'accéder à un composant comme à une propriété en utilisant l'identifiant du composant.
Lorsque vous accédez à un composant pour la première fois, [[yii\di\ServiceLocator]] utilise l'information d'enregistrement du composant pour créer une nouvelle instance du composant et la retourner. Par la suite, si on accède à nouveau au composant, le localisateur de service retourne la même instance.
Vous pouvez utiliser [[yii\di\ServiceLocator::has()]] pour savoir si un identifiant de composant a déjà été enregistré. Si vous appelez [[yii\di\ServiceLocator::get()]] avec un identifiant invalide, une exception est levée.
Comme les localisateurs de services sont souvent créés avec des [configurations](concept-configurations.md), une propriété accessible en écriture, et nommée [[yii\di\ServiceLocator::setComponents()|components]], est fournie. Cela vous permet de configurer et d'enregistrer plusieurs composants à la fois. Le code suivant montre un tableau de configuration qui peut être utilisé pour configurer un localisateur de services (p. ex. une [application](structure-applications.md)) avec les composants `db`, `cache` et `search` :
```php
return [
// ...
'components' => [
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=demo',
'username' => 'root',
'password' => '',
],
'cache' => 'yii\caching\ApcCache',
'search' => function () {
$solr = new app\components\SolrService('127.0.0.1');
// ... other initializations ...
return $solr;
},
],
];
```
Dans ce qui précède, il y a une façon alternative de configurer le composant `search`. Au lieu d'écrire directement une fonction de rappel PHP qui construit une instance de `SolrService`, vous pouvez utiliser une méthode de classe statique pour retourner une telle fonction de rappel, comme c'est montré ci-dessous :
```php
class SolrServiceBuilder
{
public static function build($ip)
{
return function () use ($ip) {
$solr = new app\components\SolrService($ip);
// ... autres initialisations ...
return $solr;
};
}
}
return [
// ...
'components' => [
// ...
'search' => SolrServiceBuilder::build('127.0.0.1'),
],
];
```
Cette approche alternative est à utiliser de préférence lorsque vous publiez une composant Yii qui encapsule quelques bibliothèques de tierces parties. Vous utilisez la méthode statique comme c'est montré ci-dessus pour représenter la logique complexe de construction de l'objet de tierce partie, et l'utilisateur de votre composant doit seulement appeler la méthode statique pour configurer le composant.

1294
docs/guide-fr/db-active-record.md

File diff suppressed because it is too large Load Diff

562
docs/guide-fr/db-dao.md

@ -0,0 +1,562 @@
Objets d'accès aux bases de données
===================================
Construits au dessus des [objets de bases de données PHP (PDO – PHP Data Objects)](http://www.php.net/manual/en/book.pdo.php), les objets d'accès aux bases de données de Yii (DAO – Database Access Objects) fournissent une API orientée objets pour accéder à des bases de données relationnelles. C'est la fondation pour d'autres méthodes d'accès aux bases de données plus avancées qui incluent le [constructeur de requêtes (*query builder*)](db-query-builder.md) et l'[enregistrement actif (*active record*)](db-active-record.md).
Lorsque vous utilisez les objets d'accès aux bases de données de Yii, vous manipulez des requêtes SQL et des tableaux PHP. En conséquence, cela reste le moyen le plus efficace pour accéder aux bases de données. Néanmoins, étant donné que la syntaxe du langage SQL varie selon le type de base de données, l'utilisation des objets d'accès aux bases de données de Yii signifie également que vous avez à faire un travail supplémentaire pour créer une application indifférente au type de base de données.
Les objets d'accès aux bases de données de Yii prennent en charge les bases de données suivantes sans installation supplémentaire :
- [MySQL](http://www.mysql.com/)
- [MariaDB](https://mariadb.com/)
- [SQLite](http://sqlite.org/)
- [PostgreSQL](http://www.postgresql.org/): version 8.4 or higher.
- [CUBRID](http://www.cubrid.org/): version 9.3 or higher.
- [Oracle](http://www.oracle.com/us/products/database/overview/index.html)
- [MSSQL](https://www.microsoft.com/en-us/sqlserver/default.aspx): version 2008 or higher.
## Création de connexions à une base de données <span id="creating-db-connections"></span>
Pour accéder à une base de données, vous devez d'abord vous y connecter en créant une instance de la classe [[yii\db\Connection]] :
```php
$db = new yii\db\Connection([
'dsn' => 'mysql:host=localhost;dbname=example',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
]);
```
Comme souvent vous devez accéder à une base de données en plusieurs endroits, une pratique commune est de la configurer en terme de [composant d'application ](structure-application-components.md) comme ci-après :
```php
return [
// ...
'components' => [
// ...
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=example',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
],
],
// ...
];
```
Vous pouvez ensuite accéder à la base de données via l'expression `Yii::$app->db`.
> Tip: vous pouvez configurer plusieurs composants d'application « base de données » si votre application a besoin d'accéder à plusieurs bases de données.
Lorsque vous conifigurez une connexion à une base de données, vous devez toujours spécifier le nom de sa source de données (DSN – Data Source Name) via la propriété [[yii\db\Connection::dsn|dsn]]. Les formats des noms de source de données varient selon le type de base de données. Reportez-vous au [manuel de PHP](http://www.php.net/manual/en/function.PDO-construct.php) pour plus de détails. Ci-dessous, nous donnons quelques exemples :
* MySQL, MariaDB: `mysql:host=localhost;dbname=mydatabase`
* SQLite: `sqlite:/path/to/database/file`
* PostgreSQL: `pgsql:host=localhost;port=5432;dbname=mydatabase`
* CUBRID: `cubrid:dbname=demodb;host=localhost;port=33000`
* MS SQL Server (via sqlsrv driver): `sqlsrv:Server=localhost;Database=mydatabase`
* MS SQL Server (via dblib driver): `dblib:host=localhost;dbname=mydatabase`
* MS SQL Server (via mssql driver): `mssql:host=localhost;dbname=mydatabase`
* Oracle: `oci:dbname=//localhost:1521/mydatabase`
Notez que si vous vous connectez à une base de données en utilisant ODBC (Open Database Connectivity), vous devez configurer la propriété [[yii\db\Connection::driverName]] afin que Yii connaisse le type réel de base de données. Par exemple :
```php
'db' => [
'class' => 'yii\db\Connection',
'driverName' => 'mysql',
'dsn' => 'odbc:Driver={MySQL};Server=localhost;Database=test',
'username' => 'root',
'password' => '',
],
```
En plus de la propriété [[yii\db\Connection::dsn|dsn]], vous devez souvent configurer les propriétés [[yii\db\Connection::username|username (nom d'utilisateur)]] et [[yii\db\Connection::password|password (mot de passe)]]. Reportez-vous à [[yii\db\Connection]] pour une liste exhaustive des propriétés configurables.
> Info: lorsque vous créez une instance de connexion à une base de données, la connexion réelle à la base de données n'est pas établie tant que vous n'avez pas exécuté la première requête SQL ou appelé la méthode [[yii\db\Connection::open()|open()]] explicitement.
> Tip: parfois, vous désirez effectuer quelques requêtes juste après l'établissement de la connexion à la base de données pour initialiser quelques variables d'environnement (p. ex. pour définir le fuseau horaire ou le jeu de caractères). Vous pouvez le faire en enregistrant un gestionnaire d'événement pour l'événement [[yii\db\Connection::EVENT_AFTER_OPEN|afterOpen]] de la connexion à la base de données. Vous pouvez enregistrer le gestionnaire directement dans la configuration de l'application comme ceci :
>
> ```php
> 'db' => [
> // ...
> 'on afterOpen' => function($event) {
> // $event->sender refers to the DB connection
> $event->sender->createCommand("SET time_zone = 'UTC'")->execute();
> }
> ],
> ```
## Execution de requêtes SQL <span id="executing-sql-queries"></span>
Une fois que vous avez une instance de connexion à la base de données, vous pouvez exécuter une requête SQL en suivant les étapes suivantes :
1. Créer une [[yii\db\Command|commande]] avec une requête SQL simple;
2. Lier les paramètres (facultatif);
3. Appeler l'une des méthodes d'exécution SQL dans la [[yii\db\Command|commande]].
L'exemple qui suit montre différentes façons d'aller chercher des données dans une base de données :
```php
// retourne un jeu de lignes. Chaque ligne est un tableau associatif (couples clé-valeur) dont les clés sont des noms de colonnes
// retourne un tableau vide si la requête ne retourne aucun résultat
$posts = Yii::$app->db->createCommand('SELECT * FROM post')
->queryAll();
// retourne une ligne unique (la première ligne)
// retourne false si la requête ne retourne aucun résultat
$post = Yii::$app->db->createCommand('SELECT * FROM post WHERE id=1')
->queryOne();
// retourne une colonne unique (la première colonne)
//retourne un tableau vide si la requête ne retourne aucun résultat
$titles = Yii::$app->db->createCommand('SELECT title FROM post')
->queryColumn();
// retourne une valeur scalaire
// retourne false si la requête ne retourne aucun résultat
$count = Yii::$app->db->createCommand('SELECT COUNT(*) FROM post')
->queryScalar();
```
> Note: pour préserver la précision, les données extraites des bases de données sont toutes représentées sous forme de chaînes de caractères, même si les colonnes sont de type numérique.
### Liaison des paramètres <span id="binding-parameters"></span>
Lorsque vous créez une commande de base de données à partir d'une requête SQL avec des paramètres, vous devriez presque toujours utiliser l'approche de liaison des paramètres pour éviter les attaques par injection SQL. Par exemple :
```php
$post = Yii::$app->db->createCommand('SELECT * FROM post WHERE id=:id AND status=:status')
->bindValue(':id', $_GET['id'])
->bindValue(':status', 1)
->queryOne();
```
Dans l'instruction SQL, vous pouvez incorporer une ou plusieurs valeurs à remplacer pour les paramètres (p. ex. `:id` dans l'exemple ci-dessus). Une valeur à remplacer pour un paramètre doit être une chaîne de caractères commençant par le caractère deux-points `:`. Vous pouvez ensuite appeler l'une des méthodes de liaison de paramètres suivantes pour lier les valeurs de paramètre :
* [[yii\db\Command::bindValue()|bindValue()]]: lie une unique valeur de paramètre
* [[yii\db\Command::bindValues()|bindValues()]]: lie plusieurs valeurs de paramètre en un seul appel
* [[yii\db\Command::bindParam()|bindParam()]]: similaire à [[yii\db\Command::bindValue()|bindValue()]] mais prend aussi en charge la liaison de références à des paramètres
L'exemple suivant montre les manières alternatives de lier des paramètres :
```php
$params = [':id' => $_GET['id'], ':status' => 1];
$post = Yii::$app->db->createCommand('SELECT * FROM post WHERE id=:id AND status=:status')
->bindValues($params)
->queryOne();
$post = Yii::$app->db->createCommand('SELECT * FROM post WHERE id=:id AND status=:status', $params)
->queryOne();
```
La liaison des paramètres est implémentée via des [instructions préparées](http://php.net/manual/en/mysqli.quickstart.prepared-statements.php). En plus d'empêcher les attaques par injection SQL, cela peut aussi améliorer la performance en préparant l'instruction SQL une seule fois et l'exécutant de multiples fois avec des paramètres différents. Par exemple :
```php
$command = Yii::$app->db->createCommand('SELECT * FROM post WHERE id=:id');
$post1 = $command->bindValue(':id', 1)->queryOne();
$post2 = $command->bindValue(':id', 2)->queryOne();
// ...
```
Comme la méthode [[yii\db\Command::bindParam()|bindParam()]] prend en charge la liaison des paramètres par référence, le code ci-dessus peut aussi être écrit comme suit :
```php
$command = Yii::$app->db->createCommand('SELECT * FROM post WHERE id=:id')
->bindParam(':id', $id);
$id = 1;
$post1 = $command->queryOne();
$id = 2;
$post2 = $command->queryOne();
// ...
```
Notez que vous devez lier la valeur à remplacer à la variable `$id` avant l'exécution, et ensuite changer la valeur de cette variable avant chacune des exécutions subséquentes (cela est souvent réalisé dans une boucle). L'exécution de requêtes de cette façon peut être largement plus efficace que d'exécuter une nouvelle requête pour chacune des valeurs du paramètre).
### Exécution de requête sans sélection <span id="non-select-queries"></span>
Les méthodes `queryXyz()` introduites dans les sections précédentes concernent toutes des requêtes SELECT qui retournent des données de la base de données. Pour les instructions qui ne retournent pas de donnée, vous devez appeler la méthode [[yii\db\Command::execute()]] à la place. Par exemple :
```php
Yii::$app->db->createCommand('UPDATE post SET status=1 WHERE id=1')
->execute();
```
La méthode [[yii\db\Command::execute()]] exécute retourne le nombre de lignes affectées par l'exécution de la requête SQL.
Pour les requeêtes INSERT, UPDATE et DELETE, au lieu d'écrire des instructions SQL simples, vous pouvez appeler les méthodes [[yii\db\Command::insert()|insert()]], [[yii\db\Command::update()|update()]] ou [[yii\db\Command::delete()|delete()]], respectivement, pour construire les instructions SQL correspondantes. Ces méthodes entourent correctement les noms de tables et de colonnes par des marques de citation et lient les paramètres. Par exemple :
```php
// INSERT (table name, column values)
Yii::$app->db->createCommand()->insert('user', [
'name' => 'Sam',
'age' => 30,
])->execute();
// UPDATE (table name, column values, condition)
Yii::$app->db->createCommand()->update('user', ['status' => 1], 'age > 30')->execute();
// DELETE (table name, condition)
Yii::$app->db->createCommand()->delete('user', 'status = 0')->execute();
```
Vous pouvez aussi appeler [[yii\db\Command::batchInsert()|batchInsert()]] pour insérer plusieurs lignes en un seul coup, ce qui est bien plus efficace que d'insérer une ligne à la fois :
```php
// noms de table, noms de colonne, valeurs de colonne
Yii::$app->db->createCommand()->batchInsert('user', ['name', 'age'], [
['Tom', 30],
['Jane', 20],
['Linda', 25],
])->execute();
```
Notez que les méthodes mentionnées ci-dessus ne font que créer les requêtes, vous devez toujours appeler [[yii\db\Command::execute()|execute()]] pour les exécuter réellement.
## Entourage de noms de table et de colonne par des marque de citation <span id="quoting-table-and-column-names"></span>
Lorsque l'on écrit du code indifférent au type de base de données, entourer correctement les noms table et de colonne avec des marques de citation et souvent un casse-tête parce que les différentes base de données utilisent des règles de marquage de citation différentes. Pour vous affranchir de cette difficulté, vous pouvez utiliser la syntaxe de citation introduite par Yii :
* `[[column name]]`: entourez un nom de colonne qui doit recevoir les marques de citation par des doubles crochets;
* `{{table name}}`: entourez un nom de table qui doit recevoir les marques de citation par des doubles accolades;
Les objets d'accès aux base de données de Yii convertissent automatiquement de telles constructions en les noms de colonne ou de table correspondants en utilisant la syntaxe spécifique au système de gestion de la base de données. Par exemple :
```php
// exécute cette instruction SQL pour MySQL: SELECT COUNT(`id`) FROM `employee`
$count = Yii::$app->db->createCommand("SELECT COUNT([[id]]) FROM {{employee}}")
->queryScalar();
```
### Utilisation des préfixes de table <span id="using-table-prefix"></span>
La plupart des noms de table de base de données partagent un préfixe commun. Vous pouvez utiliser la fonctionnalité de gestion du préfixe de noms de table procurée par les objets d'accès aux bases de données de Yii.
Tout d'abord, spécifiez un préfixe de nom de table via la propriété [[yii\db\Connection::tablePrefix]] dans la configuration de l'application :
```php
return [
// ...
'components' => [
// ...
'db' => [
// ...
'tablePrefix' => 'tbl_',
],
],
];
```
Ensuite dans votre code, à chaque fois que vous faites référence à une table dont le nom commence par ce préfixe, utilisez la syntaxe `{{%table_name}}`. Le caractère pourcentage `%` est automatiquement remplacé par le préfixe que vous avez spécifié dans la configuration de la connexion à la base de données. Par exemple :
```php
// exécute cette instruction SQL pour MySQL: SELECT COUNT(`id`) FROM `tbl_employee`
$count = Yii::$app->db->createCommand("SELECT COUNT([[id]]) FROM {{%employee}}")
->queryScalar();
```
## Réalisation de transactions <span id="performing-transactions"></span>
Lorsque vous exécutez plusieurs requêtes liées en séquence, il arrive que vous ayez besoin de les envelopper dans une transactions pour garantir l'intégrité et la cohérence de votre base de données. Si une des requêtes échoue, la base de données est ramenée en arrière dans l'état dans lequel elle se trouvait avant qu'aucune de ces requêtes n'ait été exécutée.
Le code suivant montre une façon typique d'utiliser les transactions :
```php
Yii::$app->db->transaction(function($db) {
$db->createCommand($sql1)->execute();
$db->createCommand($sql2)->execute();
// ... exécution des autres instruction SQL ...
});
```
Le code précédent est équivalent à celui qui suit, et qui vous donne plus de contrôle sur le code de gestion des erreurs :
```php
$db = Yii::$app->db;
$transaction = $db->beginTransaction();
try {
$db->createCommand($sql1)->execute();
$db->createCommand($sql2)->execute();
// ... exécution des autres instruction SQL ...
$transaction->commit();
} catch(\Exception $e) {
$transaction->rollBack();
throw $e;
}
```
En appelant la méthode [[yii\db\Connection::beginTransaction()|beginTransaction()]], une nouvelle transaction est démarrée. La transaction est représentée sous forme d'objet [[yii\db\Transaction]] stocké dans la variable `$transaction`. Ensuite, les requêtes à exécuter sont placées dans un bloc `try...catch...`. Si toutes les requêtes réussissent, la méthode [[yii\db\Transaction::commit()|commit()]] est appelée pour entériner la transaction. Autrement, si une exception a été levée et capturée, la méthode [[yii\db\Transaction::rollBack()|rollBack()]] est appelée pour défaire les changements faits par les requêtes de la transaction antérieures à celle qui a échoué. `throw $e` est alors à nouveau exécutée comme si l'exception n'avait jamais été capturée, ce qui permet au processus normal de gestion des erreurs de s'en occuper.
### Spécification de niveaux d'isolation <span id="specifying-isolation-levels"></span>
Yii prend aussi en charge la définition de [niveaux d'isolation] pour vos transactions. Par défaut, lors du démarrage d'une nouvelle transaction, il utilise le niveau d'isolation par défaut défini par votre système de base de données. Vous pouvez redéfinir le niveau d'isolation comme indiqué ci-après :
```php
$isolationLevel = \yii\db\Transaction::REPEATABLE_READ;
Yii::$app->db->transaction(function ($db) {
....
}, $isolationLevel);
// ou alternativement
$transaction = Yii::$app->db->beginTransaction($isolationLevel);
```
Yii fournit quatre constantes pour les niveaux d'isolation les plus courants :
- [[\yii\db\Transaction::READ_UNCOMMITTED]] – le niveau le plus faible, des lectures sales (*dirty reads*) , des lectures non répétables) (*non-repeatable reads*) et des lectures phantomes (*phantoms*) peuvent se produire.
- [[\yii\db\Transaction::READ_COMMITTED]] – évite les lectures sales.
- [[\yii\db\Transaction::REPEATABLE_READ]] – évite les lectures sales et les lectures non répétables.
- [[\yii\db\Transaction::SERIALIZABLE]] – le niveau le plus élevé, évite tous les problèmes évoqués ci-dessus.
En plus de l'utilisation des constantes présentées ci-dessus pour spécifier un niveau d'isolation, vous pouvez également utiliser des chaînes de caractères avec une syntaxe valide prise en charges par le système de gestion de base de données que vous utilisez. Par exemple, dans PostgreSQL, vous pouvez utiliser `SERIALIZABLE READ ONLY DEFERRABLE`.
Notez que quelques systèmes de gestion de base de données autorisent la définition des niveaux d'isolation uniquement au niveau de la connexion tout entière. Toutes les transactions subséquentes auront donc le même niveau d'isolation même si vous n'en spécifiez aucun. En utilisant cette fonctionnalité, vous avez peut-être besoin de spécifier le niveau d'isolation de manière explicite pour éviter les conflits de définition. Au moment d'écrire ces lignes, seules MSSQL et SQLite sont affectées par cette limitation.
> Note: SQLite ne prend en charge que deux niveaux d'isolation, c'est pourquoi vous ne pouvez utiliser que `READ UNCOMMITTED` et `SERIALIZABLE`. L'utilisation d'autres niveaux provoque la levée d'une exception.
> Note: PostgreSQL n'autorise pas la définition du niveau d'isolation tant que la transaction n'a pas démarré, aussi ne pouvez-vous pas spécifier le niveau d'isolation directement en démarrant la transaction. Dans ce cas, vous devez appeler [[yii\db\Transaction::setIsolationLevel()]] après que la transaction a démarré.
[isolation levels]: http://en.wikipedia.org/wiki/Isolation_%28database_systems%29#Isolation_levels
### Imbrication des transactions <span id="nesting-transactions"></span>
Si votre système de gestion de base de données prend en charge Savepoint, vous pouvez imbriquer plusieurs transactions comme montré ci-dessous :
```php
Yii::$app->db->transaction(function ($db) {
// transaction extérieure
$db->transaction(function ($db) {
// transaction intérieure
});
});
```
Ou en alternative,
```php
$db = Yii::$app->db;
$outerTransaction = $db->beginTransaction();
try {
$db->createCommand($sql1)->execute();
$innerTransaction = $db->beginTransaction();
try {
$db->createCommand($sql2)->execute();
$innerTransaction->commit();
} catch (\Exception $e) {
$innerTransaction->rollBack();
throw $e;
}
$outerTransaction->commit();
} catch (\Exception $e) {
$outerTransaction->rollBack();
throw $e;
}
```
## Réplication et éclatement lecture-écriture <span id="read-write-splitting"></span>
Beaucoup de systèmes de gestion de bases de données prennent en charge la [réplication de la base de données](http://en.wikipedia.org/wiki/Replication_(computing)#Database_replication) pour obtenir une meilleure disponibilité et des temps de réponse de serveur plus courts. Avec la réplication de la base de données, les données sont répliquées depuis les serveurs dits *serveurs maîtres* vers les serveurs dit *serveurs esclaves*. Toutes les écritures et les mises à jour ont lieu sur les serveurs maîtres, tandis que les lectures ont lieu sur les serveurs esclaves.
Pour tirer parti de la réplication des bases de données et réaliser l'éclatement lecture-écriture, vous pouvez configurer un composant [[yii\db\Connection]] comme le suivant :
```php
[
'class' => 'yii\db\Connection',
// configuration pour le maître
'dsn' => 'dsn pour le serveur maître',
'username' => 'master',
'password' => '',
// configuration commune pour les esclaves
'slaveConfig' => [
'username' => 'slave',
'password' => '',
'attributes' => [
// utilise un temps d'attente de connexion plus court
PDO::ATTR_TIMEOUT => 10,
],
],
// liste des configurations d'esclave
'slaves' => [
['dsn' => 'dsn pour le serveur esclave 1'],
['dsn' => 'dsn pour le serveur esclave 2'],
['dsn' => 'dsn pour le serveur esclave 3'],
['dsn' => 'dsn pour le serveur esclave 4'],
],
]
```
La configuration ci-dessus spécifie une configuration avec un unique maître et de multiples esclaves. L'un des esclaves est connecté et utilisé pour effectuer des requêtes en lecture, tandis que le maître est utilisé pour effectuer les requêtes en écriture. Un tel éclatement lecture-écriture est accompli automatiquement avec cette configuration. Par exemple :
```php
// crée une instance de Connection en utilisant la configuration ci-dessus
Yii::$app->db = Yii::createObject($config);
// effectue une requête auprès d'un des esclaves
$rows = Yii::$app->db->createCommand('SELECT * FROM user LIMIT 10')->queryAll();
// effectue une requête auprès du maître
Yii::$app->db->createCommand("UPDATE user SET username='demo' WHERE id=1")->execute();
```
> Info: les requêtes effectuées en appelant [[yii\db\Command::execute()]] sont considérées comme des requêtes en écriture, tandis que toutes les autres requêtes faites via l'une des méthodes « *query* » sont des requêtes en lecture. Vous pouvez obtenir la connexion couramment active à un des esclaves via `Yii::$app->db->slave`.
Le composant `Connection` prend en charge l'équilibrage de charge et de basculement entre esclaves. Lorsque vous effectuez une requête en lecture par la première fois, le composant `Connection` sélectionne un esclave de façon aléatoire et essaye de s'y connecter. Si l'esclave set trouvé « mort », il en essaye un autre. Si aucun des esclaves n'est disponible, il se connecte au maître. En configurant un [[yii\db\Connection::serverStatusCache|cache d'état du serveur]], le composant mémorise le serveur « mort » et ainsi, pendant un [[yii\db\Connection::serverRetryInterval|certain intervalle de temps]], n'essaye plus de s'y connecter.
> Info: dans la configuration précédente, un temps d'attente de connexion de 10 secondes est spécifié pour chacun des esclaves. Cela signifie que, si un esclave ne peut être atteint pendant ces 10 secondes, il est considéré comme « mort ». Vous pouvez ajuster ce paramètre en fonction de votre environnement réel.
Vous pouvez aussi configurer plusieurs maîtres avec plusieurs esclaves. Par exemple :
```php
[
'class' => 'yii\db\Connection',
// configuration commune pour les maîtres
'masterConfig' => [
'username' => 'master',
'password' => '',
'attributes' => [
// utilise un temps d'attente de connexion plus court
PDO::ATTR_TIMEOUT => 10,
],
],
// liste des configurations de maître
'masters' => [
['dsn' => 'dsn for master server 1'],
['dsn' => 'dsn for master server 2'],
],
// configuration commune pour les esclaves
'slaveConfig' => [
'username' => 'slave',
'password' => '',
'attributes' => [
// use a smaller connection timeout
PDO::ATTR_TIMEOUT => 10,
],
],
// liste des configurations d'esclave
'slaves' => [
['dsn' => 'dsn for slave server 1'],
['dsn' => 'dsn for slave server 2'],
['dsn' => 'dsn for slave server 3'],
['dsn' => 'dsn for slave server 4'],
],
]
```
La configuration ci-dessus spécifie deux maîtres et quatre esclaves. Le composant `Connection` prend aussi en charge l'équilibrage de charge et le basculement entre maîtres juste comme il le fait pour les esclaves. Une différence est que, si aucun des maîtres n'est disponible, une exception est levée.
> Note: lorsque vous utilisez la propriété [[yii\db\Connection::masters|masters]] pour configurer un ou plusieurs maîtres, toutes les autres propriétés pour spécifier une connexion à une base de données (p. ex. `dsn`, `username`, `password`) avec l'objet `Connection` lui-même sont ignorées.
Par défaut, les transactions utilisent la connexion au maître. De plus, dans une transaction, toutes les opérations de base de données utilisent la connexion au maître. Par exemple :
```php
$db = Yii::$app->db;
// la transaction est démarrée sur la connexion au maître
$transaction = $db->beginTransaction();
try {
// les deux requêtes sont effectuées auprès du maître
$rows = $db->createCommand('SELECT * FROM user LIMIT 10')->queryAll();
$db->createCommand("UPDATE user SET username='demo' WHERE id=1")->execute();
$transaction->commit();
} catch(\Exception $e) {
$transaction->rollBack();
throw $e;
}
```
Si vous voulez démarrer une transaction avec une connexion à un esclave, vous devez le faire explicitement, comme ceci :
```php
$transaction = Yii::$app->db->slave->beginTransaction();
```
Parfois, vous désirez forcer l'utilisation de la connexion au maître pour effectuer une requête en lecture . Cela est possible avec la méthode `useMaster()` :
```php
$rows = Yii::$app->db->useMaster(function ($db) {
return $db->createCommand('SELECT * FROM user LIMIT 10')->queryAll();
});
```
Vous pouvez aussi définir directement `Yii::$app->db->enableSlaves` à `false` (faux) pour rediriger toutes les requêtes vers la connexion au maître.
## Travail avec le schéma de la base de données <span id="database-schema"></span>
Les objets d'accès aux bases de données de Yii DAO fournissent un jeu complet de méthodes pour vous permettre de manipuler le schéma de la base de données, comme créer de nouvelles tables, supprimer une colonne d'une table, etc. Ces méthodes sont listées ci-après :
* [[yii\db\Command::createTable()|createTable()]]: crée une table
* [[yii\db\Command::renameTable()|renameTable()]]: renomme une table
* [[yii\db\Command::dropTable()|dropTable()]]: supprime une table
* [[yii\db\Command::truncateTable()|truncateTable()]]: supprime toutes les lignes dans une table
* [[yii\db\Command::addColumn()|addColumn()]]: ajoute une colonne
* [[yii\db\Command::renameColumn()|renameColumn()]]: renomme une colonne
* [[yii\db\Command::dropColumn()|dropColumn()]]: supprime une colonne
* [[yii\db\Command::alterColumn()|alterColumn()]]: modifie une colonne
* [[yii\db\Command::addPrimaryKey()|addPrimaryKey()]]: ajoute une clé primaire
* [[yii\db\Command::dropPrimaryKey()|dropPrimaryKey()]]: supprime une clé primaire
* [[yii\db\Command::addForeignKey()|addForeignKey()]]: ajoute un clé étrangère
* [[yii\db\Command::dropForeignKey()|dropForeignKey()]]: supprime une clé étrangère
* [[yii\db\Command::createIndex()|createIndex()]]: crée un index
* [[yii\db\Command::dropIndex()|dropIndex()]]: supprime un index
Ces méthodes peuvent être utilisées comme suit :
```php
// CREATE TABLE
Yii::$app->db->createCommand()->createTable('post', [
'id' => 'pk',
'title' => 'string',
'text' => 'text',
]);
```
Le tableau ci-dessus décrit le nom et le type des colonnes à créer. Pour les types de colonne, Yii fournit un jeu de types de donnée abstraits, qui permettent de définir un schéma de base de données indifférent au type de base de données. Ces types sont convertis en définition de types spécifiques au système de gestion de base de données qui dépendent de la base de données dans laquelle la table est créée. Reportez-vous à la documentation de l'API de la méthode [[yii\db\Command::createTable()|createTable()]] pour plus d'informations.
En plus de changer le schéma de la base de données, vous pouvez aussi retrouver les informations de définition d'une table via la méthode [[yii\db\Connection::getTableSchema()|getTableSchema()]] d'une connexion à une base de données. Par exemple :
```php
$table = Yii::$app->db->getTableSchema('post');
```
La méthode retourne un objet [[yii\db\TableSchema]] qui contient les information sur les colonnes de la table, les clés primaires, les clés étrangères, etc. Toutes ces informations sont essentiellement utilisées par le [constructeur de requêtes](db-query-builder.md) et par l'[enregistrement actif](db-active-record.md) pour vous aider à écrire du code indifférent au type de la base de données.

823
docs/guide-fr/db-migrations.md

@ -0,0 +1,823 @@
Migrations de base de données
=============================
Durant la période de développement et de maintenance d'une application s'appuyant sur une base de données, la structure de la base de données évolue tout comme le code source. Par exemple, durant développement une nouvelle table peut devenir nécessaire; après que l'application est déployée en production, on peut s'apercevoir qu'un index doit être créé pour améliorer la performance des requêtes; et ainsi de suite. Comme un changement dans la base de données nécessite souvent des changements dans le code, Yii prend en charge une fonctionnalité qu'on appelle *migrations de base de données*. Cette fonctionnalité permet de conserver la trace des changements de la base de données en termes de *migrations de base de données* dont les versions sont contrôlées avec celles du code.
Les étapes suivantes montrent comment des migrations de base de données peuvent être utilisées par une équipe durant la phase de développement :
1. Tim crée une nouvelle migration (p. ex. créer une nouvelle table, changer la définition d'une colonne, etc.).
2. Tim entérine (commit) la nouvelle migration dans le système de contrôle de version (p. ex. Git, Mercurial).
3. Doug met à jour son dépôt depuis le système de contrôle de version et reçoit la nouvelle migration.
4. Doug applique la migration à sa base de données de développement locale, et ce faisant synchronise sa base de données pour refléter les changements que Tim a faits.
Les étapes suivantes montrent comment déployer une nouvelle version avec les migrations de base de données en production :
1. Scott crée une balise de version pour le dépôt du projet qui contient quelques nouvelles migrations de base de données.
2. Scott met à jour le code source sur le serveur de production à la version balisée.
3. Scott applique toutes les migrations accumulées à la base de données de production.
Yii fournit un jeu de commandes de migration en ligne de commande qui vous permet de :
* créer de nouvelles migrations;
* appliquer les migrations;
* défaire les migrations;
* ré-appliquer les migrations;
* montrer l'historique de l'état des migrations.
Tous ces outils sont accessibles via la commande `yii migrate`. Dans cette section nous décrivons en détails comment accomplir des tâches variées en utilisant ces outils. Vous pouvez aussi obtenir les conseils d'utilisation de chacun des outils via la commande d'aide `yii help migrate`.
> Tip: les migrations peuvent non seulement affecter le schéma de base de données mais aussi ajuster les données existantes pour s'adapter au nouveau schéma, créer la hiérarchie RBAC (Role Based Acces Control - Contrôle d'accès basé sur les rôles), ou vider le cache.
## Création de migrations <span id="creating-migrations"></span>
Pour créer une nouvelle migration, exécutez la commande suivante :
```
yii migrate/create <name>
```
L'argument `name` requis donne une brève description de la nouvelle migration. Par exemple, si la création concerne la création d'une nouvelle table nommée *news*, vous pouvez utiliser le nom `create_news_table` et exécuter la commande suivante :
```
yii migrate/create create_news_table
```
> Note: comme l'argument `name` est utilisé comme partie du nom de la classe migration générée, il ne doit contenir que des lettres, des chiffre et/ou des caractères *souligné*.
La commande ci-dessus crée une nouvelle classe PHP nommée `m150101_185401_create_news_table.php` dans le dossier `@app/migrations`. Le fichier contient le code suivant qui déclare principalement une classe de migration `m150101_185401_create_news_table` avec le squelette de code suivant :
```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()
{
}
*/
}
```
Chaque migration de base de données est définie sous forme de classe PHP étendant la classe [[yii\db\Migration]]. Le nom de la classe de migration est généré automatiquement dans le format `m<YYMMDD_HHMMSS>_<Name>`, dans lequel :
* `<YYMMDD_HHMMSS>` fait référence à l'horodatage UTC auquel la commande de création de la migration a été exécutée.
* `<Name>` est le même que la valeur que vous donnez à l'argument `name` dans la commande.
Dans la classe de migration, vous devez écrire du code dans la méthode `up()` qui effectue les modifications dans la structure de la base de données. Vous désirez peut-être écrire du code dans la méthode `down()` pour défaire les changements apportés par `up()`. La méthode `up()` est invoquée lorsque vous mettez à jour la base de données avec la migration, tandis que la méthode `down()` est invoquée lorsque vous ramenez la base de données à l'état antérieur. Le code qui suit montre comment mettre en œuvre la classe de migration pour créer une table `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: toutes les migrations ne sont pas réversibles. Par exemple, si la méthode `up()` supprime une ligne dans une table, il se peut que vous soyez incapable de récupérer cette ligne dans la méthode `down()`. Parfois, vous pouvez simplement être trop paresseux pour implémenter la méthode `down`, parce que défaire une migration de base de données n'est pas chose courante. Dans ce cas, vous devriez retourner `false` dans la méthode `down()` pour indiquer que la migration n'est pas réversible.
La classe de migration de base [[yii\db\Migration]] expose une connexion à une base de données via la propriété [[yii\db\Migration::db|db]]. Vous pouvez utiliser cette connexion pour manipuler le schéma en utilisant les méthodes décrites dans la sous-section [Travail avec le schéma de base de données](db-dao.md#database-schema).
Plutôt que d'utiliser des types physiques, lors de la création d'une table ou d'une colonne, vous devez utiliser des *types abstraits* afin que vos migrations soient indépendantes d'un système de gestion de base de données en particulier. La classe [[yii\db\Schema]] définit une jeu de constantes pour représenter les types abstraits pris en charge. Ces constantes sont nommées dans le format `TYPE_<Name>`. Par exemple, `TYPE_PK` fait référence au type clé primaire à auto-incrémentation; `TYPE_STRING` fait référence au type chaîne de caractères. Lorsqu'une migration est appliquée à une base de données particulière, le type abstrait est converti dans le type physique correspondant. Dans le cas de MySQL, `TYPE_PK` est transformé en `int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY`, tandis que `TYPE_STRING` est transformé en `varchar(255)`.
Vous pouvez ajouter des contraintes additionnelles lors de l'utilisation des types abstraits. Dans l'exemple ci-dessus,` NOT NULL` est ajouté à `Schema::TYPE_STRING` pour spécifier que la colonne ne peut être *null* (nulle).
> Info: la mise en correspondance entre les types abstraits et les types physiques est spécifiée par la propriété [[yii\db\QueryBuilder::$typeMap|$typeMap]] dans chacune des classes `QueryBuilder` concrètes.
Depuis la version 2.0.6, vous pouvez utiliser le constructeur de schéma récemment introduit qui procure un moyen plus pratique de définir le schéma d'une colonne. Ainsi, la migration ci-dessus pourrait s'écrire comme ceci :
```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');
}
}
```
Une liste de toutes les méthodes disponibles pour définir les types de colonne est disponible dans la documentation de l'API de [[yii\db\SchemaBuilderTrait]].
## Génération des migrations <span id="generating-migrations"></span>
Depuis la version 2.0.7, la commande de migration procure un moyen pratique de créer des migrations.
Si le nom de la migration est d'une forme spéciale, par exemple, `create_xxx_table` ou `drop_xxx_table` alors le fichier de la migration générée contient du code supplémentaire, dans ce cas pour créer/supprimer des tables. Dans ce qui suit, toutes les variantes de cette fonctionnalité sont décrites.
### Création d'une table
```php
yii migrate/create create_post_table
```
génère
```php
/**
* prend en charge la création de la 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');
}
}
```
Pour créer les champs de table tout de suite, spécifiez les via l'option `--fields`.
```php
yii migrate/create create_post_table --fields="title:string,body:text"
```
génère
```php
/**
* prend en charge la création de la 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');
}
}
```
Vous pouvez spécifier plus de paramètres de champs.
```php
yii migrate/create create_post_table --fields="title:string(12):notNull:unique,body:text"
```
génère
```php
/**
* prend en charge la création de la 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: par défaut, une clé primaire nommée `id` est ajoutée automatiquement. Si vous voulez utiliser un autre nom, vous devez le spécifier explicitement comme dans `--fields="name:primaryKey"`.
#### Clés étrangères
Depuis 2.0.8 le générateur prend en charge les clés étrangères en utilisant le mot clé `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"
```
génère
```php
/**
* prend en charge la création de la table `post`.
* possède des clés étrangères vers les 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(),
]);
// crée un index pour la colonne `author_id`
$this->createIndex(
'idx-post-author_id',
'post',
'author_id'
);
// ajoute une clé étrangère vers la table `user`
$this->addForeignKey(
'fk-post-author_id',
'post',
'author_id',
'user',
'id',
'CASCADE'
);
// crée un index pour la colonne `category_id`
$this->createIndex(
'idx-post-category_id',
'post',
'category_id'
);
// ajoute une clé étrangère vers la table `category`
$this->addForeignKey(
'fk-post-category_id',
'post',
'category_id',
'category',
'id',
'CASCADE'
);
}
/**
* @inheritdoc
*/
public function down()
{
// supprime la clé étrangère vers la table `user`
$this->dropForeignKey(
'fk-post-author_id',
'post'
);
// supprime l'index pour la colonne `author_id`
$this->dropIndex(
'idx-post-author_id',
'post'
);
// supprime la clé étrangère vers la table `category`
$this->dropForeignKey(
'fk-post-category_id',
'post'
);
// supprime l'index pour la colonne `category_id`
$this->dropIndex(
'idx-post-category_id',
'post'
);
$this->dropTable('post');
}
}
```
La position du mot clé `foreignKey` dans la description de la colonne ne change pas le code généré. Ce qui signifie que les expressions :
- `author_id:integer:notNull:foreignKey(user)`
- `author_id:integer:foreignKey(user):notNull`
- `author_id:foreignKey(user):integer:notNull`
génèrent toutes le même code.
Le mot clé `foreignKey` accepte un paramètre entre parenthèses qui est le nom de la table en relation pour la clé étrangère générée. Si aucun paramètre n'est passé, le nom de table est déduit du nom de la colonne.
Dans l'exemple ci-dessus `author_id:integer:notNull:foreignKey(user)` génère une colonne nommée `author_id` avec une clé étrangère pointant sur la table `user`, tandis que `category_id:integer:defaultValue(1):foreignKey` génère une colonne `category_id` avec une clé étrangère pointant sur la table `category`.
### Suppression de tables
```php
yii migrate/create drop_post_table --fields="title:string(12):notNull:unique,body:text"
```
génère
```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()
]);
}
}
```
### Ajout de colonnes
Si le nom de la migration est de la forme `add_xxx_column_to_yyy_table` alors le fichier doit contenir les instructions `addColumn` et `dropColumn` nécessaires.
Pour ajouter une colonne :
```php
yii migrate/create add_position_column_to_post_table --fields="position:integer"
```
génère
```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');
}
}
```
### Supprimer une colonne
Si le nom de la migration est de la forme `drop_xxx_column_from_yyy_table` alors le fichier doit contenir les instructions `addColumn` et `dropColumn` néessaires.
```php
yii migrate/create drop_position_column_from_post_table --fields="position:integer"
```
génère
```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());
}
}
```
### Ajout d'une table de jointure
Si le nom de la migration est de la forme `create_junction_table_for_xxx_and_yyy_tables` ou `create_junction_xxx_and_yyy_tables`, alors le code nécessaire à la création de la table de jointure est généré.
```php
yii migrate/create create_junction_table_for_post_and_tag_tables --fields="created_at:dateTime"
```
génère
```php
/**
* prend en charge la création de la table `post_tag`.
* possède des clés étrangères vers les 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)',
]);
// crée un index pour la colonne`post_id`
$this->createIndex(
'idx-post_tag-post_id',
'post_tag',
'post_id'
);
// ajoute un clé étrangère vers la table `post`
$this->addForeignKey(
'fk-post_tag-post_id',
'post_tag',
'post_id',
'post',
'id',
'CASCADE'
);
// crée un index pour la colonne `tag_id`
$this->createIndex(
'idx-post_tag-tag_id',
'post_tag',
'tag_id'
);
// ajoute une clé étrangère vers la table `tag`
$this->addForeignKey(
'fk-post_tag-tag_id',
'post_tag',
'tag_id',
'tag',
'id',
'CASCADE'
);
}
/**
* @inheritdoc
*/
public function down()
{
// supprime la clé étrangère vers la table `post`
$this->dropForeignKey(
'fk-post_tag-post_id',
'post_tag'
);
// supprime l'index pour la colonne `post_id`
$this->dropIndex(
'idx-post_tag-post_id',
'post_tag'
);
// supprime la clé étrangère vers la table `tag`
$this->dropForeignKey(
'fk-post_tag-tag_id',
'post_tag'
);
// supprime l'index pour la column `tag_id`
$this->dropIndex(
'idx-post_tag-tag_id',
'post_tag'
);
$this->dropTable('post_tag');
}
}
```
### Migrations transactionnelles <span id="transactional-migrations"></span>
En effectuant des migration de base de données complexes, il est important de garantir que chacune des migrations soit réussisse, soit échoue dans son ensemble, de manière à ce que la base de données reste cohérente et intègre. Pour atteindre ce but, il est recommandé que vous englobiez les opérations de base de données de chacune des migrations dans une [transaction](db-dao.md#performing-transactions).
Une manière encore plus aisée pour mettre en œuvre des migrations transactionnelles est de placer le code de migration dans les méthodes `safeUp()` et `safeDown()`. Ces deux méthodes diffèrent de `up()` et `down()` par le fait qu'elles sont implicitement englobées dans une transaction. En conséquence, si n'importe quelle opération de ces méthodes échoue, toutes les opérations antérieures à elle sont automatiquement défaites.
Dans l'exemple suivant, en plus de créer la table `news`, nous insérons une ligne initiale dans cette table.
```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');
}
}
```
Notez que, généralement, si vous effectuez de multiples opérations de base de données dans `safeUp()`, vous devriez les défaire dans `safeDown()`. Dans l'exemple ci-dessus, dans `safeUp()`, nous créons d'abord la table puis nous insérons une ligne, tandis que, dans `safeDown`, nous commençons par supprimer la ligne, puis nous supprimons la table.
> Note: tous les systèmes de gestion de bases de données NE prennent PAS en charge les transactions. De plus, quelques requêtes de base de données ne peuvent être placées dans une transaction. Pour quelques exemples, reportez-vous à [entérinement implicite](http://dev.mysql.com/doc/refman/5.7/en/implicit-commit.html). Si c'est le cas, vous devez simplement mettre en œuvre `up()` et`down()`, à la place.
### Méthodes d'accès aux bases de données <span id="db-accessing-methods"></span>
La classe de base de migration [[yii\db\Migration]] fournit un jeu de méthodes pour vous permettre d'accéder aux bases de données et de les manipuler. Vous vous apercevrez que ces méthodes sont nommées de façon similaires aux [méthodes d'objets d'accès aux données](db-dao.md) fournies par la classe [[yii\db\Command]]. Par exemple, la méthode [[yii\db\Migration::createTable()]] vous permet de créer une nouvelle table, tout comme [[yii\db\Command::createTable()]].
L'avantage d'utiliser les méthodes fournies par [[yii\db\Migration]] est que vous n'avez pas besoin de créer explicitement des instances de [[yii\db\Command]] et que l'exécution de chacune des méthodes affiche automatiquement des messages utiles vous indiquant que les opérations de base de données sont effectuées et combien de temps ces opérations ont pris.
Ci-dessous, nous présentons la liste de toutes les méthodes d'accès aux bases de données :
* [[yii\db\Migration::execute()|execute()]]: exécute une instruction SQL
* [[yii\db\Migration::insert()|insert()]]: insère une unique ligne
* [[yii\db\Migration::batchInsert()|batchInsert()]]: insère de multiples lignes
* [[yii\db\Migration::update()|update()]]: met à jour des lignes
* [[yii\db\Migration::delete()|delete()]]: supprime des lignes
* [[yii\db\Migration::createTable()|createTable()]]: crée une table
* [[yii\db\Migration::renameTable()|renameTable()]]: renomme une table
* [[yii\db\Migration::dropTable()|dropTable()]]: supprime une table
* [[yii\db\Migration::truncateTable()|truncateTable()]]: supprime toutes les lignes d'une table
* [[yii\db\Migration::addColumn()|addColumn()]]: ajoute une colonne
* [[yii\db\Migration::renameColumn()|renameColumn()]]: renomme une colonne
* [[yii\db\Migration::dropColumn()|dropColumn()]]: supprime une colonne
* [[yii\db\Migration::alterColumn()|alterColumn()]]: modifie une colonne
* [[yii\db\Migration::addPrimaryKey()|addPrimaryKey()]]: ajoute une clé primaire
* [[yii\db\Migration::dropPrimaryKey()|dropPrimaryKey()]]: supprime une clé primaire
* [[yii\db\Migration::addForeignKey()|addForeignKey()]]: ajoute une clé étrangère
* [[yii\db\Migration::dropForeignKey()|dropForeignKey()]]: supprime une clé étrangère
* [[yii\db\Migration::createIndex()|createIndex()]]: crée un index
* [[yii\db\Migration::dropIndex()|dropIndex()]]: supprime un index
* [[yii\db\Migration::addCommentOnColumn()|addCommentOnColumn()]]: ajoute un commentaire à une colonne
* [[yii\db\Migration::dropCommentFromColumn()|dropCommentFromColumn()]]: supprime un commentaire d'une colonne
* [[yii\db\Migration::addCommentOnTable()|addCommentOnTable()]]: ajoute un commentaire à une table
* [[yii\db\Migration::dropCommentFromTable()|dropCommentFromTable()]]: supprime un commentaire d'une table
> Info: [[yii\db\Migration]] ne fournit pas une méthode de requête de base de données. C'est parce que, normalement, vous n'avez pas besoin d'afficher de messages supplémentaire à propos de l'extraction de données dans une base de données. C'est aussi parce que vous pouvez utiliser le puissant [constructeur de requêtes](db-query-builder.md) pour construire et exécuter des requêtes complexes.
> Note: lors de la manipulation des données en utilisant une migration, vous pouvez trouver qu'utiliser vos classes d'[enregistrement actif](db-active-record.md) pour cela peut être utile parce qu'une partie de la logique y est déjà mise en œuvre. Soyez conscient cependant que, par contraste avec le code écrit dans les migrations, dont la nature est de rester constant à jamais, la logique d'application est sujette à des changements. Ainsi, en utilisant un enregistrement actif dans du code de migration, les changements apportés à la logique dans la couche enregistrement actif peuvent casser accidentellement des migrations existantes. Pour cette raison, le code doit être gardé indépendant de toute autre logique d'application telle que les classes d'enregistrement actif.
## Application des migrations <span id="applying-migrations"></span>
Pour mettre une base de données à jour à sa dernière structure, vous devez appliquer toutes les nouvelles migrations disponibles en utilisant la commande suivante :
```
yii migrate
```
Cette commande liste toutes les migrations qui n'ont pas encore été appliquées. Si vous confirmez que vous voulez appliquer ces migrations, cela provoque l'exécution des méthodes `up()` ou `safeUp()` de chacune des nouvelles migrations, l'une après l'autre, dans l'ordre de leur horodatage. Si l'une de ces migrations échoue, la commande se termine sans appliquer les migrations qui restent.
> Tip: dans le cas où votre serveur ne vous offre pas de ligne de commande, vous pouvez essayer [Web shell](https://github.com/samdark/yii2-webshell).
Pour chaque migration qui n'a pas été appliqué avec succès, la commande insère une ligne dans une table de base de données nommée `migration` pour enregistrer les applications réussies de la migration. Cela permet à l'outil de migration d'identifier les migrations qui ont été appliquées et celles qui ne l'ont pas été.
> Info: l'outil de migration crée automatiquement la table de `migration` dans la base de données spécifiée par l'option [[yii\console\controllers\MigrateController::db|db]] de la commande. Par défaut, la base de données est spécifiée dans le [composant d'application](structure-application-components.md) `db`.
Parfois, vous désirez peut-être appliquer une ou quelques migrations plutôt que toutes les migrations disponibles. Vous pouvez le faire en spécifiant le nombre de migrations que vous voulez appliquer en exécutant la commande. Par exemple, la commande suivante essaye d'appliquer les trois prochaines migrations disponibles :
```
yii migrate 3
```
Vous pouvez également spécifier explicitement une migration particulière à laquelle la base de données doit être amenée en utilisant la commande `migrate/to` dans l'un des formats suivants :
```
yii migrate/to 150101_185401 # utiliser l'horodatage pour spécifier la migration
yii migrate/to "2015-01-01 18:54:01" # utilise une chaîne de caractères qui peut être analysée par strtotime()
yii migrate/to m150101_185401_create_news_table # utilise le nom complet
yii migrate/to 1392853618 # utilise un horodatage UNIX
```
S'il existe des migrations non appliquée antérieures à celle spécifiée, elles sont toutes appliquées avant que la migration spécifiée ne le soit.
Si la migration spécifiée a déjà été appliquée auparavant, toutes les migrations postérieures qui ont été appliquées sont défaites.
## Défaire des migrations <span id="reverting-migrations"></span>
Pour défaire une ou plusieurs migrations que ont été appliquées auparavant, vous pouvez exécuter la commande suivante :
```
yii migrate/down # défait la migration appliquée le plus récemment
yii migrate/down 3 # défait les 3 migrations appliquées le plus récemment
> Note: toutes les migrations ne sont PAS réversibles. Essayer de défaire de telles migrations provoque une erreur et arrête tout le processus de retour à l'état initial.
## Refaire des migrations <span id="redoing-migrations"></span>
Refaire (ré-appliquer) des migrations signifie d'abord défaire les migrations spécifiées puis les appliquer à nouveau. Cela peut être fait comme suit :
```
yii migrate/redo # refait la dernière migration appliquée
yii migrate/redo 3 # refait les 3 dernière migrations appliquées
```
> Note: si une migration n'est pas réversible, vous ne serez pas en mesure de la refaire.
## Lister des migrations <span id="listing-migrations"></span>
Pour lister quelles migrations ont été appliquées et quelles migrations ne l'ont pas été, vous pouvez utiliser les commandes suivantes :
```
yii migrate/history # montre les 10 dernières migrations appliquées
yii migrate/history 5 # montre les 5 dernières migrations appliquées
yii migrate/history all # montre toutes les migrations appliquées
yii migrate/new # montre les 10 premières nouvelles migrations
yii migrate/new 5 # montre les 5 premières nouvelles migrations
yii migrate/new all # montre toutes les nouvelles migrations
```
## Modification de l'historique des migrations <span id="modifying-migration-history"></span>
Au lieu d'appliquer ou défaire réellement des migrations, parfois, vous voulez peut-être simplement marquer que votre base de données a été portée à une certaine migration. Cela arrive souvent lorsque vous changer manuellement la base de données pour l'amener à un état particulier et que vous ne voulez pas que la migration correspondant à ce changement soit appliquée de nouveau par la suite. Vous pouvez faire cela avec la commande suivante :
```
yii migrate/mark 150101_185401 # utilise un horodatage pour spécifier la migration
yii migrate/mark "2015-01-01 18:54:01" # utilise une chaîne de caractères qui peut être analysée par strtotime()
yii migrate/mark m150101_185401_create_news_table # utilise le nom complet
yii migrate/mark 1392853618 # utilise un horodatage UNIX
```
La commande modifie la table `migration` en ajoutant ou en supprimant certaines lignes pour indiquer que la base de données s'est vue appliquer toutes les migrations jusqu'à celle spécifiée. Aucune migration n'est appliquée ou défaite par cette commande.
## Personnalisation des migrations <span id="customizing-migrations"></span>
Il y a plusieurs manières de personnaliser la commande de migration.
### Utilisation des options de ligne de commande <span id="using-command-line-options"></span>
La commande de migration possède quelques options en ligne de commande qui peuvent être utilisées pour personnaliser son comportement :
* `interactive`: boolean (valeur par défaut `true`), spécifie si la migration doit être effectuées en mode interactif. Lorsque cette option est `true`, l'utilisateur reçoit un message avant que la commande n'effectue certaines actions. Vous désirez peut-être définir cette valeur à `false` si la commande s'exécute en arrière plan.
* `migrationPath`: string (valeur par défaut `@app/migrations`), spécifie le dossier qui stocke tous les fichiers de classe de migration. Cela peut être spécifié soit comme un chemin de dossier, soit comme un [alias](concept-aliases.md) de chemin. Notez que le dossier doit exister sinon la commande déclenche une erreur.
* `migrationTable`: string (valeur par défaut `migration`), spécifie le nom de la table de base de données pour stocker l'historique de migration. La table es créée automatiquement par la commande si elle n'existe pas encore. Vous pouvez aussi la créer à la main en utilisant la structure `version varchar(255) primary key, apply_time integer`.
* `db`: string (valeur par défaut `db`), spécifie l'identifiant du [composant d'application](structure-application-components.md) base de données. Il représente la base de données à laquelle les migrations sont appliquées avec cette commande.
* `templateFile`: string (valeur par défaut `@yii/views/migration.php`), spécifie le chemin vers le fichier modèle qui est utilisé pour générer le squelette des fichiers de classe de migration. Cela peut être spécifié soit sous forme de chemin de fichier, soit sous forme d'[alias](concept-aliases.md).de chemin. Le fichier modèle est un script PHP dans lequel vous pouvez utiliser une variable prédéfinie nommée `$className` pour obtenir le nom de la classe de migration.
* `generatorTemplateFiles`: array (valeur par défaut `[
'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'
]`), spécifie les fichiers modèles pour générer le code de migration. Voir "[Génération des migrations](#generating-migrations)" pour plus de détails.
* `fields`: array (tableau) de chaîne de caractères de définition de colonnes utilisées pour créer le code de migration. Valeur par défaut `[]`. Le format de chacune des définitions est `COLUMN_NAME:COLUMN_TYPE:COLUMN_DECORATOR`. Par exemple, `--fields=name:string(12):notNull` produit une colonne chaîne de caractères de taille 12 qui n'est pas nulle.
L'exemple suivant montre comment vous pouvez utiliser ces options.
Par exemple, si vous voulez appliquer des migrations à un module `forum` dont les fichiers de migration sont situés dans le dossier `migrations` du module, vous pouvez utiliser la commande suivante :
```
# appliquer les migrations d'un module forum sans interactivité
yii migrate --migrationPath=@app/modules/forum/migrations --interactive=0
```
### Configuration globale des commandes <span id="configuring-command-globally"></span>
Au lieu de répéter les mêmes valeurs d'option à chaque fois que vous exécutez une commande de migration, vous pouvez la configurer une fois pour toute dans la configuration de l'application comme c'est montré ci-après :
```php
return [
'controllerMap' => [
'migrate' => [
'class' => 'yii\console\controllers\MigrateController',
'migrationTable' => 'backend_migration',
],
],
];
```
Avec la configuration ci-dessus, à chaque fois que vous exécutez la commande de migration, la table `backend_migration` est utilisée pour enregistrer l'historique de migration. Vous n'avez plus besoin de le spécifier via l'option en ligne de commande `migrationTable`.
## Migration de multiples base de données <span id="migrating-multiple-databases"></span>
Par défaut, les migrations sont appliquées à la même base de données spécifiée par le [composant d'application](structure-application-components.md) `db`. Si vous voulez que celles-ci soient appliquées à des bases de données différentes, vous pouvez spécifier l'option en ligne de commande `db` comme indiqué ci-dessous :
```
yii migrate --db=db2
```
La commande ci-dessus applique les migration à la base de données `db2`.
Parfois, il est possible que vous vouliez appliquer *quelques unes* des migrations à une base de données, et *quelques autres* à une autre base de données. Pour y parvenir, lorsque vous implémentez une classe de migration, vous devez spécifier explicitement l'identifiant du composant base de données que la migration doit utiliser, comme ceci :
```php
<?php
use yii\db\Migration;
class m150101_185401_create_news_table extends Migration
{
public function init()
{
$this->db = 'db2';
parent::init();
}
}
```
La migration ci-dessus est appliquée à `db2`, même si vous spécifiez une autre base via l'option en ligne de commande `db`. Notez que l'historique de migration est toujours enregistré dans la base de données spécifiée par l'option en ligne de commande `db`.
Si vous avez de multiples migrations qui utilisent la même base de données, il est recommandé que vous créiez une classe de migration de base avec le code `init()` ci-dessus. Ensuite, chaque classe de migration peut étendre cette classe de base.
> Tip: en plus de définir la propriété [[yii\db\Migration::db|db]], vous pouvez aussi opérer sur différentes bases de données en créant de nouvelles connexions à ces bases de données dans vos classes de migration. Ensuite,vous utilisez les [méthodes des objets d'accès aux bases de données](db-dao.md) avec ces connexions pour manipuler différentes bases de données.
Une autre stratégie que vous pouvez adopter pour appliquer des migrations à de multiples bases de données est de tenir ces migrations de différentes bases de données dans des chemins différents. Ensuite vous pouvez appliquer les migrations à ces bases de données dans des commandes séparées comme ceci :
```
yii migrate --migrationPath=@app/migrations/db1 --db=db1
yii migrate --migrationPath=@app/migrations/db2 --db=db2
...
```
La première commande applique les migrations dans `@app/migrations/db1` à la base de données `db1`, la seconde commande applique les migrations dans `@app/migrations/db2` à `db2`, et ainsi de suite.

583
docs/guide-fr/db-query-builder.md

@ -0,0 +1,583 @@
Le constructeur de requêtes
===========================
Construit sur la base des [objets d'accès aux bases de données (DAO)](db-dao.md), le constructeur de requêtes vous permet de construire des requêtes SQL par programme qui sont indifférentes au système de gestion de base de données utilisé. Comparé à l'écriture d'instructions SQL brutes, l'utilisation du constructeur de requêtes vous aide à écrire du code relatif à SQL plus lisible et à générer des instructions SQL plus sûres.
L'utilisation du constructeur de requêtes comprend ordinairement deux étapes :
1. Construire un objet [[yii\db\Query]] pour représenter différentes parties (p. ex. `SELECT`, `FROM`) d'une instruction SQL.
2. Exécuter une méthode de requête (p. ex. `all()`) de [[yii\db\Query]] pour retrouver des données dans la base de données.
Le code suivant montre une manière typique d'utiliser le constructeur de requêtes.
```php
$rows = (new \yii\db\Query())
->select(['id', 'email'])
->from('user')
->where(['last_name' => 'Smith'])
->limit(10)
->all();
```
Le code ci-dessus génère et exécute la requête SQL suivante, dans laquelle le paramètre `:last_name` est lié à la chaîne de caractères `'Smith'`.
```sql
SELECT `id`, `email`
FROM `user`
WHERE `last_name` = :last_name
LIMIT 10
```
> Info: génélalement vous travaillez essentiellement avec [[yii\db\Query]] plutôt qu'avec [[yii\db\QueryBuilder]]. Le dernier est implicitement invoqué par le premier lorsque vous appelez une des méthodes de requête. [[yii\db\QueryBuilder]] est la classe en charge de la génération des instructions SQL dépendantes du système de gestion de base de données (p. ex. entourer les noms de table/colonne par des marques de citation différemment) à partir d'objets [[yii\db\Query]] indifférents au système de gestion de base de données.
## Construction des requêtes <span id="building-queries"></span>
Pour construire un objet [[yii\db\Query]], vous appelez différentes méthodes de construction de requêtes pour spécifier différentes parties de la requête SQL. Les noms de ces méthodes ressemblent aux mots clés de SQL utilisés dans les parties correspondantes de l'instruction SQL. Par exemple, pour spécifier la partie `FROM` d'une requête SQL, vous appelez la méthode [[yii\db\Query::from()|from()]]. Toutes les méthodes de construction de requêtes retournent l'objet *query* lui-même, ce qui vous permet d'enchaîner plusieurs appels.
Dans ce qui suit, nous décrivons l'utilisation de chacune des méthodes de requête.
### [[yii\db\Query::select()|select()]] <span id="select"></span>
La méthode [[yii\db\Query::select()|select()]] spécifie le fragment `SELECT` d'une instruction SQL. Vous pouvez spécifier les colonnes à sélectionner soit sous forme de chaînes de caractères, soit sous forme de tableaux, comme ci-apès. Les noms de colonne sélectionnées sont automatiquement entourés des marques de citation lorsque l'instruction SQL est générée à partir de l'objet *query* (requête).
```php
$query->select(['id', 'email']);
// équivalent à:
$query->select('id, email');
```
Les noms des colonnes sélectionnées peuvent inclure des préfixes de table et/ou de alias de colonne, comme vous le faites en écrivant une requête SQL brute. Par exemple :
```php
$query->select(['user.id AS user_id', 'email']);
// équivalent à:
$query->select('user.id AS user_id, email');
```
Si vous utilisez le format tableau pour spécifier les colonnes, vous pouvez aussi utiliser les clés du tableau pour spécifier les alias de colonne. Par exemple, le code ci-dessus peut être réécrit comme ceci :
```php
$query->select(['user_id' => 'user.id', 'email']);
```
Si vous n'appelez pas la méthode [[yii\db\Query::select()|select()]] en construisant une requête, `*` est sélectionné, ce qui signifie la sélection de *toutes* les colonnes.
En plus des noms de colonne, vous pouvez aussi sélectionner des expression de base de données. Vous devez utiliser le format tableau en sélectionnant une expression de base de données qui contient des virgules pour éviter des entourages automatiques incorrects des noms par des marques de citation. Par exemple :
```php
$query->select(["CONCAT(first_name, ' ', last_name) AS full_name", 'email']);
```
Comme en tout lieu où il est fait appel à du SQL brut, vous devez utiliser la [syntaxe des marques de citation indifférentes au système de gestion de base de données](db-dao.md#quoting-table-and-column-names) pour les noms de table et de colonne lorsque vous écrivez les expressions de base de données dans `select`.
Depuis la version 2.0.1, vous pouvez aussi sélectionner des sous-requêtes. Vous devez spécifier chacune des sous-requêtes en termes d'objet [[yii\db\Query]]. Par exemple :
```php
$subQuery = (new Query())->select('COUNT(*)')->from('user');
// SELECT `id`, (SELECT COUNT(*) FROM `user`) AS `count` FROM `post`
$query = (new Query())->select(['id', 'count' => $subQuery])->from('post');
```
Pour sélectionner des lignes distinctes, vous pouvez appeler [[yii\db\Query::distinct()|distinct()]], comme ceci :
```php
// SELECT DISTINCT `user_id` ...
$query->select('user_id')->distinct();
```
Vous pouvez appeler [[yii\db\Query::addSelect()|addSelect()]] pour sélectionner des colonnes additionnelles. Par exemple :
```php
$query->select(['id', 'username'])
->addSelect(['email']);
```
### [[yii\db\Query::from()|from()]] <span id="from"></span>
La méthode [[yii\db\Query::from()|from()]] spécifie le fragment `FROM`d'une instruction. Par exemple :
```php
// SELECT * FROM `user`
$query->from('user');
```
Vous pouvez spécifier les tables à sélectionner soit sous forme de chaînes de caractères, soit sous forme de tableaux. Les noms de table peuvent contenir des préfixes et/ou des alias de table. Par exemple :
```php
$query->from(['public.user u', 'public.post p']);
// équivalent à :
$query->from('public.user u, public.post p');
```
Si vous utilisez le format tableau, vous pouvez aussi utiliser les clés du tableau pour spécifier les alias de table, comme suit :
```php
$query->from(['u' => 'public.user', 'p' => 'public.post']);
```
En plus des noms de table, vous pouvez aussi sélectionner à partir de sous-requêtes en les spécifiant en termes d'objets [[yii\db\Query]].
Par exemple :
```php
$subQuery = (new Query())->select('id')->from('user')->where('status=1');
// SELECT * FROM (SELECT `id` FROM `user` WHERE status=1) u
$query->from(['u' => $subQuery]);
```
### [[yii\db\Query::where()|where()]] <span id="where"></span>
La méthode [[yii\db\Query::where()|where()]] spécifie le fragment `WHERE`d'une requête SQL. Vous pouvez utiliser un des trois formats suivants pour spécifier une condition `WHERE` :
- format chaîne de caractères, p. ex. `'status=1'`
- format haché, p. ex. `['status' => 1, 'type' => 2]`
- format opérateur, p. ex. `['like', 'name', 'test']`
#### Format chaîne de caractères <span id="string-format"></span>
Le format chaîne de caractères est celui qui convient le mieux pour spécifier des conditions très simples ou si vous avez besoin d'utiliser les fonctions incorporées au système de gestion de base de données. Il fonctionne comme si vous écriviez une requête SQL brute. Par exemple :
```php
$query->where('status=1');
// ou utilisez la liaison des paramètres pour lier des valeurs dynamiques des paramètres.
$query->where('status=:status', [':status' => $status]);
// SQL brute utilisant la fonction MySQL YEAR() sur un champ de date
```
N'imbriquez PAS les variables directement dans la condition comme ce qui suit, spécialement si les valeurs des variables proviennent d'entrées utilisateur, parce que cela rendrait votre application SQL sujette aux attaques par injections SQL.
```php
// Dangereux! Ne faites PAS cela sauf si vous êtes tout à fait sûr que $status est un entier
$query->where("status=$status");
```
Lorsque vous utilisez la liaison des paramètres, vous pouvez appeler [[yii\db\Query::params()|params()]] ou [[yii\db\Query::addParams()|addParams()]] pour spécifier les paramètres séparément.
```php
$query->where('status=:status')
->addParams([':status' => $status]);
```
Comme dans tous les endroits ou il est fait appel à du SQL, vous pouvez utiliser la [syntaxe d'entourage par des marques de citation indifférente au système de gestion de base de données](db-dao.md#quoting-table-and-column-names) pour les noms de table et de colonne lorsque vous écrivez les conditions au format chaîne de caractères.
#### Format haché <span id="hash-format"></span>
Le format valeur de hachage convient le mieux pour spécifier de multiples sous-conditions `AND` concaténées, chacune étant une simple assertion d'égalité. Il se présente sous forme de tableau dont les clés sont les noms des colonnes et les valeurs les valeurs correspondantes que les valeurs des colonnes devraient avoir. Par exemple :
```php
// ...WHERE (`status` = 10) AND (`type` IS NULL) AND (`id` IN (4, 8, 15))
$query->where([
'status' => 10,
'type' => null,
'id' => [4, 8, 15],
]);
```
Comme vous pouvez le voir, le constructeur de requêtes est assez intelligent pour manipuler correctement les valeurs qui sont soit nulles, soit des tableaux.
Vous pouvez utiliser aussi des sous-requêtes avec le format haché comme suit :
```php
$userQuery = (new Query())->select('id')->from('user');
// ...WHERE `id` IN (SELECT `id` FROM `user`)
$query->where(['id' => $userQuery]);
```
En utilisant le format haché, Yii, en interne, utilise la liaison des paramètres de façon à ce que, contrairement au [format chaîne de caractères](#string-format), vous n'ayez pas à ajouter les paramètres à la main.
#### Format opérateur <span id="operator-format"></span>
Le format opérateur vous permet de spécifier des conditions arbitraires par programmation. Il accepte les formats suivants : a
```php
[operator, operand1, operand2, ...]
```
dans lequel chacun des opérandes peut être spécifié au format chaîne de caractères, au format haché ou au format opérateur de façon récursive, tandis que l'opérateur peut être un de ceux qui suivent :
- `and`: les opérandes doivent être concaténés en utilisant `AND`. Par exemple, `['and', 'id=1', 'id=2']` génère `id=1 AND id=2`. Si l'opérande est un tableau, il est converti en une chaîne de caractères en utilisant les règles décrites ici. Par exemple, `['and', 'type=1', ['or', 'id=1', 'id=2']]` génère `type=1 AND (id=1 OR id=2)`. La méthode ne procède à aucun entourage par des marques de citation, ni à aucun échappement.
- `or`: similaire à l'opérateur `and` sauf que les opérandes sont concaténés en utilisant `OR`.
- `between`: l'opérande 1 doit être le nom de la colonne, et les opérandes 2 et 3 doivent être les valeurs de départ et de fin de la plage dans laquelle la colonne doit être. Par exemple, `['between', 'id', 1, 10]` génère `id BETWEEN 1 AND 10`.
- `not between`: similaire à `between` sauf que `BETWEEN` est remplacé par `NOT BETWEEN` dans la condition générée.
- `in`: l'opérande 1 doit être une colonne ou une expression de base de données. L'opérande 2 peut être soit un tableau, soit un objet `Query`. Il génère une condition `IN`. Si l'opérande 2 est un tableau, il représente la plage des valeurs que la colonne ou l'expression de base de données peut prendre. Si l'opérande 2 est un objet `Query`, une sous-requête est générée et utilisée comme plage pour la colonne ou l'expression de base de données. Par exemple, `['in', 'id', [1, 2, 3]]` génère `id IN (1, 2, 3)`. La méthode assure correctement l'entourage des noms de colonnes par des marques de citation et l'échappement des valeurs de la plage. L'opérateur `in` prend aussi en charge les colonnes composites. Dans ce case, l'opérande 1 doit être un tableau des colonnes, tandis que l'opérateur 2 doit être un tableau de tableaux, ou un objet `Query` représentant la plage de colonnes.
- `not in`: similaire à l'opérateur `in` sauf que `IN` est remplacé par `NOT IN` dans la condition générée.
- `like`: l'opérande 1 doit être une colonne ou une expression de base de données, tandis que l'opérande 2 doit être une chaîne de caractères ou un tableau représentant les valeurs que cette colonne ou cette expression de base de données peuvent être. Par exemple, `['like', 'name', 'tester']` génère `name LIKE '%tester%'`. Lorsque la plage de valeurs est donnée sous forme de tableau, de multiples prédicats `LIKE` sont générés et concaténés en utilisant `AND`. Par exemple, `['like', 'name', ['test', 'sample']]` génère `name LIKE '%test%' AND name LIKE '%sample%'`. Vous pouvez également fournir un troisième paramètre facultatif pour spécifier comment échapper les caractères spéciaux dans les valeurs. Les opérandes doivent être un tableau de correspondance entre les caractères spéciaux et les contre-parties échappées. Si cet opérande n'est pas fourni, une mise en correspondance par défaut est utilisée. Vous pouvez utiliser `false` ou un tableau vide pour indiquer que les valeurs sont déjà échappées et qu'aucun échappement ne doit être appliqué. Notez que lorsqu'un tableau de mise en correspondance pour l'échappement est utilisé (ou quand le troisième opérande n'est pas fourni), les valeurs sont automatiquement entourées par une paire de caractères `%`.
> Note: lors de l'utilisation de PostgreSQL vous pouvez aussi utiliser [`ilike`](http://www.postgresql.org/docs/8.3/static/functions-matching.html#FUNCTIONS-LIKE) à la place de `like` pour une mise en correspondance insensible à la casse.
- `or like`: similaire à l'opérateur `like` sauf que `OR`est utilisé pour concaténer les prédicats `LIKE` quand l'opérande 2 est un tableau.
- `not like`: similaire à l'opérateur `like` sauf que `LIKE` est remplacé par `NOT LIKE` dans la condition générée.
- `or not like`: similaire à l'opérateur `not like` sauf que `OR` est utilisé pour concaténer les prédicats `NOT LIKE`.
- `exists`: requiert un opérande que doit être une instance de [[yii\db\Query]] représentant la sous-requête. Il construit une expression `EXISTS (sub-query)`.
- `not exists`: similaire à l'opérateur `exists` et construit une expression `NOT EXISTS (sub-query)`.
- `>`, `<=`, ou tout autre opérateur de base de données valide qui accepte deux opérandes : le premier opérande doit être un nom de colonne, tandis que le second doit être une valeur. Par exemple, `['>', 'age', 10]` génère `age>10`.
En utilisant le format opérateur, Yii, en interne, utilise la liaison des paramètres afin, que contrairement au [format chaîne de caractères](#string-format), ici, vous n'avez pas besoin d'ajouter les paramètres à la main.
#### Ajout de conditions <span id="appending-conditions"></span>
Vous pouvez utiliser [[yii\db\Query::andWhere()|andWhere()]] ou [[yii\db\Query::orWhere()|orWhere()]] pour ajouter des conditions supplémentaires à une condition existante. Vous pouvez les appeler plusieurs fois pour ajouter plusieurs conditions séparément. Par exemple :
```php
$status = 10;
$search = 'yii';
$query->where(['status' => $status]);
if (!empty($search)) {
$query->andWhere(['like', 'title', $search]);
}
```
Si `$search` n'est pas vide, la condition `WHERE` suivante est générée :
```sql
WHERE (`status` = 10) AND (`title` LIKE '%yii%')
```
#### Filtrage des conditions <span id="filter-conditions"></span>
Lors de la construction de conditions `WHERE` basées sur des entrées de l'utilisateur final, vous voulez généralement ignorer les valeurs entrées qui sont vides. Par exemple, dans un formulaire de recherche par nom d'utilisateur ou par adresse de courriel, vous aimeriez ignorer la condition nom d'utilisateur/adresse de courriel si l'utilisateur n'a rien saisi les champs correspondants. Vous pouvez faire cela en utilisant la méthode [[yii\db\Query::filterWhere()|filterWhere()]] :
```php
// $username et $email sont entrées par l'utilisateur
$query->filterWhere([
'username' => $username,
'email' => $email,
]);
```
La seule différence entre [[yii\db\Query::filterWhere()|filterWhere()]] et [[yii\db\Query::where()|where()]] est que la première ignore les valeurs vides fournies dans la condition au [format haché](#hash-format). Ainsi si `$email` est vide alors que `$username` ne l'est pas, le code ci dessus produit la condition SQL `WHERE username=:username`.
> Info: une valeur est considérée comme vide si elle est nulle, un tableau vide, ou un chaîne de caractères vide, ou un chaîne de caractères constituée d'espaces uniquement.
Comme avec [[yii\db\Query::andWhere()|andWhere()]] et [[yii\db\Query::orWhere()|orWhere()]], vous pouvez utiliser [[yii\db\Query::andFilterWhere()|andFilterWhere()]] et [[yii\db\Query::orFilterWhere()|orFilterWhere()]] pour ajouter des conditions de filtrage supplémentaires à une condition existante.
En outre, il y a [[yii\db\Query::andFilterCompare()]] qui peut déterminer intelligemment l'opérateur en se basant sur ce qu'il y a dans les valeurs :
```php
$query->andFilterCompare('name', 'John Doe');
$query->andFilterCompare('rating', '>9');
$query->andFilterCompare('value', '<=100');
```
Vous pouvez aussi utiliser un opérateur explicitement :
```php
$query->andFilterCompare('name', 'Doe', 'like');
```
### [[yii\db\Query::orderBy()|orderBy()]] <span id="order-by"></span>
La méthode [[yii\db\Query::orderBy()|orderBy()]] spécifie le fragment `ORDER BY` d'une requête SQL. Par exemple :
```php
// ... ORDER BY `id` ASC, `name` DESC
$query->orderBy([
'id' => SORT_ASC,
'name' => SORT_DESC,
]);
```
Dans le code ci-dessus, les clés du tableau sont des noms de colonnes, tandis que les valeurs sont les instructions de direction de tri. La constante PHP `SORT_ASC` spécifie un tri ascendant et `SORT_DESC`, un tri descendant.
Si `ORDER BY` ne fait appel qu'à des noms de colonnes simples, vous pouvez le spécifier en utilisant une chaîne de caractères, juste comme vous le faites en écrivant des instructions SQL brutes. Par exemple :
```php
$query->orderBy('id ASC, name DESC');
```
> Note: vous devez utiliser le format tableau si `ORDER BY` fait appel à une expression de base de données.
Vous pouvez appeler [[yii\db\Query::addOrderBy()|addOrderBy()]] pour ajouter des colonnes supplémentaires au fragment `ORDER BY`. Par exemple :
```php
$query->orderBy('id ASC')
->addOrderBy('name DESC');
```
### [[yii\db\Query::groupBy()|groupBy()]] <span id="group-by"></span>
La méthode [[yii\db\Query::groupBy()|groupBy()]] spécifie le fragment `GROUP BY` d'une requête SQL. Par exemple :
```php
// ... GROUP BY `id`, `status`
$query->groupBy(['id', 'status']);
```
Si `GROUP BY` ne fait appel qu'à des noms de colonnes simples, vous pouvez le spécifier en utilisant un chaîne de caractères, juste comme vous le faîtes en écrivant des instructions SQL brutes. Par exemple :
```php
$query->groupBy('id, status');
```
> Note: vous devez utiliser le format tableau si `GROUP BY` fait appel à une expression de base de données.
Vous pouvez appeler [[yii\db\Query::addGroupBy()|addGroupBy()]] pour ajouter des colonnes au fragment `GROUP BY`. Par exemple :
```php
$query->groupBy(['id', 'status'])
->addGroupBy('age');
```
### [[yii\db\Query::having()|having()]] <span id="having"></span>
La méthode [[yii\db\Query::having()|having()]] spécifie le fragment `HAVING` d'un requête SQL. Elle accepte une condition qui peut être spécifiée de la même manière que celle pour [where()](#where). Par exemple :
```php
// ... HAVING `status` = 1
$query->having(['status' => 1]);
```
Reportez-vous à la documentation de [where()](#where) pour plus de détails sur la manière de spécifier une condition.
Vous pouvez appeler [[yii\db\Query::andHaving()|andHaving()]] ou [[yii\db\Query::orHaving()|orHaving()]] pour ajouter des conditions supplémentaires au fragment `HAVING` fragment. Par exemple :
```php
// ... HAVING (`status` = 1) AND (`age` > 30)
$query->having(['status' => 1])
->andHaving(['>', 'age', 30]);
```
### [[yii\db\Query::limit()|limit()]] et [[yii\db\Query::offset()|offset()]] <span id="limit-offset"></span>
Les méthodes [[yii\db\Query::limit()|limit()]] et [[yii\db\Query::offset()|offset()]] spécifient les fragments `LIMIT` et `OFFSET` d'une requête SQL. Par exemple :
```php
// ... LIMIT 10 OFFSET 20
$query->limit(10)->offset(20);
```
Si vous spécifiez une limite ou un décalage (p. ex. une valeur négative), il est ignoré.
> Info: pour les systèmes de gestion de base de données qui prennent en charge `LIMIT` et `OFFSET` (p. ex. MSSQL), le constructeur de requêtes génère une instruction SQL qui émule le comportement `LIMIT`/`OFFSET`.
### [[yii\db\Query::join()|join()]] <span id="join"></span>
La méthode [[yii\db\Query::join()|join()]] spécifie le fragment `JOIN` d'une requête SQL. Par exemple :
```php
// ... LEFT JOIN `post` ON `post`.`user_id` = `user`.`id`
$query->join('LEFT JOIN', 'post', 'post.user_id = user.id');
```
La méthode [[yii\db\Query::join()|join()]] accepte quatre paramètres :
- `$type`: type de jointure , p. ex. `'INNER JOIN'`, `'LEFT JOIN'`.
- `$table`: le nom de la table à joindre.
- `$on`: facultatif, la condition de jointure, c.-à-d. le fragment `ON`. Reportez-vous à [where()](#where) pour des détails sur la manière de spécifier une condition. Notez, que la syntaxe tableau ne fonctionne **PAS** pour spécifier une condition basée sur une colonne, p. ex. `['user.id' => 'comment.userId']` conduit à une condition où l'identifiant utilisateur doit être égal à la chaîne de caractères `'comment.userId'`. Vous devez utiliser la syntaxe chaîne de caractères à la place et spécifier la condition `'user.id = comment.userId'`.
- `$params`: facultatif, les paramètres à lier à la condition de jointure.
Vous pouvez utiliser les méthodes raccourcies suivantes pour spécifier `INNER JOIN`, `LEFT JOIN` et `RIGHT JOIN`, respectivement.
- [[yii\db\Query::innerJoin()|innerJoin()]]
- [[yii\db\Query::leftJoin()|leftJoin()]]
- [[yii\db\Query::rightJoin()|rightJoin()]]
Par exemple :
```php
$query->leftJoin('post', 'post.user_id = user.id');
```
Pour joindre plusieurs tables, appelez les méthodes join ci-dessus plusieurs fois, une fois pour chacune des tables.
En plus de joindre des tables, vous pouvez aussi joindre des sous-requêtes. Pour faire cela, spécifiez les sous-requêtes à joindre sous forme d'objets [[yii\db\Query]]. Par exemple :
```php
$subQuery = (new \yii\db\Query())->from('post');
$query->leftJoin(['u' => $subQuery], 'u.id = author_id');
```
Dans ce cas, vous devez mettre la sous-requête dans un tableau et utiliser les clés du tableau pour spécifier les alias.
### [[yii\db\Query::union()|union()]] <span id="union"></span>
La méthode [[yii\db\Query::union()|union()]] spécifie le fragment `UNION` d'une requête SQL. Par exemple :
```php
$query1 = (new \yii\db\Query())
->select("id, category_id AS type, name")
->from('post')
->limit(10);
$query2 = (new \yii\db\Query())
->select('id, type, name')
->from('user')
->limit(10);
$query1->union($query2);
```
Vous pouvez appeler [[yii\db\Query::union()|union()]] plusieurs fois pour ajouter plus de fragments `UNION`.
## Méthodes de requête <span id="query-methods"></span>
L'objet [[yii\db\Query]] fournit un jeu complet de méthodes pour différents objectifs de requêtes :
- [[yii\db\Query::all()|all()]]: retourne un tableau de lignes dont chacune des lignes est un tableau associatif de paires clé-valeur.
- [[yii\db\Query::one()|one()]]: retourne la première ligne du résultat.
- [[yii\db\Query::column()|column()]]: retourne la première colonne du résultat.
- [[yii\db\Query::scalar()|scalar()]]: retourne une valeur scalaire située au croisement de la première ligne et de la première colonne du résultat.
- [[yii\db\Query::exists()|exists()]]: retourne une valeur précisant si le résultat de la requête contient un résultat.
- [[yii\db\Query::count()|count()]]: retourne le résultat d'une requête `COUNT`..
- D'autres méthodes d'agrégation de requêtes, y compris [[yii\db\Query::sum()|sum($q)]], [[yii\db\Query::average()|average($q)]], [[yii\db\Query::max()|max($q)]], [[yii\db\Query::min()|min($q)]]. Le paramètre `$q` est obligatoire pour ces méthodes et peut être soit un nom de colonne, soit une expression de base de données.
Par exemple :
```php
// SELECT `id`, `email` FROM `user`
$rows = (new \yii\db\Query())
->select(['id', 'email'])
->from('user')
->all();
// SELECT * FROM `user` WHERE `username` LIKE `%test%`
$row = (new \yii\db\Query())
->from('user')
->where(['like', 'username', 'test'])
->one();
```
> Note: la méthode [[yii\db\Query::one()|one()]] retourne seulement la première ligne du résultat de la requête. Elle n'ajoute PAS `LIMIT 1` à l'instruction SQL générée. Cela est bon et préférable si vous savez que la requête ne retourne qu'une seule ou quelques lignes de données (p. ex. si vous effectuez une requête avec quelques clés primaires). Néanmoins, si la requête peut potentiellement retourner de nombreuses lignes de données, vous devriez appeler `limit(1)` explicitement pour améliorer la performance, p. ex. `(new \yii\db\Query())->from('user')->limit(1)->one()`.
Toutes ces méthodes de requête accepte un paramètre supplémentaire `$db` représentant la [[yii\db\Connection|connexion à la base de données]] qui doit être utilisée pour effectuer la requête. Si vous omettez ce paramètre, le [composant d'application](structure-application-components.md) `db` est utilisé en tant que connexion à la base de données. Ci-dessous, nous présentons un autre exemple utilisant la méthode [[yii\db\Query::count()|count()]] :
```php
// exécute SQL: SELECT COUNT(*) FROM `user` WHERE `last_name`=:last_name
$count = (new \yii\db\Query())
->from('user')
->where(['last_name' => 'Smith'])
->count();
```
Lorsque vous appelez une méthode de requête de [[yii\db\Query]], elle effectue réellement le travail suivant en interne :
* Appelle [[yii\db\QueryBuilder]] pour générer une instruction SQL basée sur la construction courante de [[yii\db\Query]];
* Crée un objet [[yii\db\Command]] avec l'instruction SQL générée;
* Appelle une méthode de requête (p. ex. [[yii\db\Command::queryAll()|queryAll()]]) de [[yii\db\Command]] pour exécuter une instruction SQL et retrouver les données.
Parfois, vous voulez peut-être examiner ou utiliser une instruction SQL construite à partir d'un objet [[yii\db\Query]]. Vous pouvez faire cela avec le code suivant :
```php
$command = (new \yii\db\Query())
->select(['id', 'email'])
->from('user')
->where(['last_name' => 'Smith'])
->limit(10)
->createCommand();
// affiche l'instruction SQL
echo $command->sql;
// affiche les paramètres à lier
print_r($command->params);
// retourne toutes les lignes du résultat de la requête
$rows = $command->queryAll();
```
### Indexation des résultats de la requête <span id="indexing-query-results"></span>
Lorsque vous appelez [[yii\db\Query::all()|all()]], elle retourne un tableau de lignes qui sont indexées par des entiers consécutifs. Parfois, vous désirez peut-être les indexer différemment, comme les indexer par une colonne particulière ou par des expressions donnant une valeur. Vous pouvez le faire en appelant [[yii\db\Query::indexBy()|indexBy()]] avant [[yii\db\Query::all()|all()]]. Par exemple :
```php
// retourne [100 => ['id' => 100, 'username' => '...', ...], 101 => [...], 103 => [...], ...]
$query = (new \yii\db\Query())
->from('user')
->limit(10)
->indexBy('id')
->all();
```
Pour indexer par des valeurs d'expressions, passez une fonction anonyme à la méthode [[yii\db\Query::indexBy()|indexBy()]] :
```php
$query = (new \yii\db\Query())
->from('user')
->indexBy(function ($row) {
return $row['id'] . $row['username'];
})->all();
```
Le fonction anonyme accepte un paramètre `$row` qui contient les données de la ligne courante et retourne une valeur scalaire qui est utilisée comme la valeur d'index de la ligne courante.
> Note: contrairement aux méthodes de requête telles que [[yii\db\Query::groupBy()|groupBy()]] ou [[yii\db\Query::orderBy()|orderBy()]] qui sont converties en SQL et font partie de la requête, cette méthode ne fait son travail qu'après que les données ont été retrouvées dans la base de données. Cela signifie que seules les noms de colonne qui on fait partie du fragement SELECT dans votre requête peuvent être utilisés. De plus, si vous avez sélectionné une colonne avec un préfixe de table, p. ex. `customer.id`, le jeu de résultats ne contient que `id` c'est pourquoi vous devez appeler `->indexBy('id')` sans préfixe de table.
### Requêtes par lots <span id="batch-query"></span>
Lorsque vous travaillez sur de grandes quantités de données, des méthodes telles que [[yii\db\Query::all()]] ne conviennent pas car elles requièrent le chargement de toutes les données en mémoire. Pour conserver l'exigence de capacité mémoire basse, Yii fournit la prise en charge appelé requêtes par lots.
Les requêtes par lots peuvent être utilisées comme suit :
```php
use yii\db\Query;
$query = (new Query())
->from('user')
->orderBy('id');
foreach ($query->batch() as $users) {
// $users est dans un tableau de 100 ou moins lignes du la table user.
}
// ou si vous voulez itérer les lignes une par une
foreach ($query->each() as $user) {
// $user représente une ligne de données de la table user.
```
Les méthodes [[yii\db\Query::batch()]] et [[yii\db\Query::each()]] retournent un objet [[yii\db\BatchQueryResult]] qui implémente l'interface `Iterator` et qui, par conséquent, peut être utilisé dans une construction `foreach`.
Durant la première iteration, une requête SQL est faite à la base de données. Les données sont retrouvées en lots dans les itérations suivantes. Par défaut, la taille du lot est 100, ce qui signifie que 100 lignes sont retrouvées dans chacun des lots. Vous pouvez changer la taille du lot en passant le premier paramètre des méthodes `batch()` ou `each()`.
Comparée à la requête [[yii\db\Query::all()]], la requête par lots ne charge que 100 lignes de données à la fois en mémoire. Si vous traitez les données et les détruisez tout de suite, la requête par lots réduit l'utilisation de la mémoire.
Si vous spécifiez l'indexation du résultat de la requête par une colonne via [[yii\db\Query::indexBy()]], la requête par lots conserve l'index approprié. Par exemple :
```php
$query = (new \yii\db\Query())
->from('user')
->indexBy('username');
foreach ($query->batch() as $users) {
// $users est indexé par la colonne "username"
}
foreach ($query->each() as $username => $user) {
// ...
}
```

404
docs/guide-fr/helper-array.md

@ -0,0 +1,404 @@
Classe assistante ArrayHelper
=============================
En plus du jeu riche de [fonctions de tableaux](http://php.net/manual/en/book.array.php) qu'offre PHP, la classe assistante traitant les tableaux dans Yii fournit des méthodes statiques supplémentaires qui vous permettent de traiter les tableaux avec plus d'efficacité.
## Obtention de valeurs <span id="getting-values"></span>
Récupérer des valeurs d'un tableau ou d'un objet ou une structure complexe écrits tous deux en PHP standard est un processus assez répétitif. Vous devez d'abord vérifier que la clé existe avec `isset`, puis si c'est le cas, vous récupérez la valeur associée, sinon il vous faut fournir une valeur par défaut :
```php
class User
{
public $name = 'Alex';
}
$array = [
'foo' => [
'bar' => new User(),
]
];
$value = isset($array['foo']['bar']->name) ? $array['foo']['bar']->name : null;
```
Yii fournit une méthode très pratique pour faire cela :
```php
$value = ArrayHelper::getValue($array, 'foo.bar.name');
```
Le premier argument de la méthode indique de quelle source nous voulons récupérer une valeur. Le deuxième spécifie comment récupérer la donnée. Il peut s'agir d'un des éléments suivants :
- Nom d'une clé de tableau ou de la propriété d'un objet de laquelle récupérer une valeur.
- Un jeu de noms de clé de tableau ou de propriétés d'objet séparées par des points, comme dans l'exemple que nous venons de présenter ci-dessus.
- Une fonction de rappel qui retourne une valeur.
Le fonction de rappel doit être la suivante :
```php
$fullName = ArrayHelper::getValue($user, function ($user, $defaultValue) {
return $user->firstName . ' ' . $user->lastName;
});
```
Le troisième argument facultatif est la valeur par défaut qui est `null` si on ne la spécifie pas. Il peut être utilisé comme ceci :
```php
$username = ArrayHelper::getValue($comment, 'user.username', 'Unknown');
```
Dans le cas où vous voulez récupérer la valeur tout en la retirant immédiatement du tableau, vous pouvez utiliser la méthode `remove` :
```php
$array = ['type' => 'A', 'options' => [1, 2]];
$type = ArrayHelper::remove($array, 'type');
```
Après exécution du code, `$array` contiendra `['options' => [1, 2]]` et `$type` sera `A`. Notez que contrairement à la méthode `getValue`, `remove` accepte seulement les noms de clé.
## Tester l'existence des clés <span id="checking-existence-of-keys"></span>
`ArrayHelper::keyExists` fonctionne comme [array_key_exists](http://php.net/manual/en/function.array-key-exists.php) sauf qu'elle prend également en charge la comparaison de clés insensible à la casse. Par exemple,
```php
$data1 = [
'userName' => 'Alex',
];
$data2 = [
'username' => 'Carsten',
];
if (!ArrayHelper::keyExists('username', $data1, false) || !ArrayHelper::keyExists('username', $data2, false)) {
echo "Veuillez fournir un nom d'utilisateur (username).";
}
```
## Récupération de colonnes <span id="retrieving-columns"></span>
Il arrive souvent que vous ayez à récupérer une colonne de valeurs d'un tableau de lignes de données ou d'objets. Un exemple courant est l'obtention d'une liste d'identifiants.
```php
$array = [
['id' => '123', 'data' => 'abc'],
['id' => '345', 'data' => 'def'],
];
$ids = ArrayHelper::getColumn($array, 'id');
```
Le résultat sera `['123', '345']`.
Si des transformations supplémentaires sont nécessaires ou si la manière de récupérer les valeurs est complexe, le second argument peut être formulé sous forme de fonction anonyme :
```php
$result = ArrayHelper::getColumn($array, function ($element) {
return $element['id'];
});
```
## Réindexation de tableaux <span id="reindexing-arrays"></span>
La méthode `index` peut être utilisées pour indexer un tableau selon une clé spécifiée. L'entrée doit être soit un tableau multidimensionnel, soit un tableau d'objets. `$key` peut être un nom de clé du sous-tableau, un nom de propriété d'objet ou une fonction anonyme qui doit retourner la valeur à utiliser comme clé.
L'attribut `$groups` est un tableau de clés qui est utilisé pour regrouper le tableau d'entrée en un ou plusieurs sous-tableaux basés sur les clés spécifiées.
Si l'argument `$key` ou sa valeur pour l'élément particulier est `null` alors que `$groups` n'est pas défini, l'élément du tableau est écarté. Autrement, si `$groups` est spécifié, l'élément du tableau est ajouté au tableau résultant sans aucune clé.
Par exemple :
```php
$array = [
['id' => '123', 'data' => 'abc', 'device' => 'laptop'],
['id' => '345', 'data' => 'def', 'device' => 'tablet'],
['id' => '345', 'data' => 'hgi', 'device' => 'smartphone'],
];
$result = ArrayHelper::index($array, 'id');
```
Le résultat est un tableau associatif, dans lequel la clé est la valeur de l'attribut `id` :
```php
[
'123' => ['id' => '123', 'data' => 'abc', 'device' => 'laptop'],
'345' => ['id' => '345', 'data' => 'hgi', 'device' => 'smartphone']
// Le second élément du tableau d'origine est écrasé par le dernier élément parce que les identifiants sont identiques.
]
```
Une fonction anonyme passée en tant que `$key`, conduit au même résultat :
```php
$result = ArrayHelper::index($array, function ($element) {
return $element['id'];
});
```
Passer `id` comme troisième argument regroupe `$array` par `id`:
```php
$result = ArrayHelper::index($array, null, 'id');
```
Le résultat est un tableau multidimensionnel regroupé par `id` au premier niveau et non indexé au deuxième niveau :
```php
[
'123' => [
['id' => '123', 'data' => 'abc', 'device' => 'laptop']
],
'345' => [ // all elements with this index are present in the result array
['id' => '345', 'data' => 'def', 'device' => 'tablet'],
['id' => '345', 'data' => 'hgi', 'device' => 'smartphone'],
]
]
```
Une fonction anonyme peut également être utilisée dans le tableau de regroupement :
```php
$result = ArrayHelper::index($array, 'data', [function ($element) {
return $element['id'];
}, 'device']);
```
Le résultat est un tableau multidimensionnel regroupé par `id` au premier niveau, par `device` au deuxième niveau et par `data` au troisième niveau :
```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']
]
]
]
```
## Construction de tableaux de mise en correspondance <span id="building-maps"></span>
Afin de construire un tableau de mise en correspondance (paires clé-valeur) sur la base d'un tableau multidimensionnel ou d'un tableau d'objets, vous pouvez utiliser la méthode `map`.
Les paramètres `$from` et `$to` spécifient les noms de clé ou les noms des propriétés pour construire le tableau de mise en correspondance. Le paramètre facultatif `$group` est un nom de clé ou de propriété qui permet de regrouper les éléments du tableau au premier niveau. Par exemple :
```php
$array = [
['id' => '123', 'name' => 'aaa', 'class' => 'x'],
['id' => '124', 'name' => 'bbb', 'class' => 'x'],
['id' => '345', 'name' => 'ccc', 'class' => 'y'],
];
$result = ArrayHelper::map($array, 'id', 'name');
// le résultat est :
// [
// '123' => 'aaa',
// '124' => 'bbb',
// '345' => 'ccc',
// ]
$result = ArrayHelper::map($array, 'id', 'name', 'class');
// le résultat est :
// [
// 'x' => [
// '123' => 'aaa',
// '124' => 'bbb',
// ],
// 'y' => [
// '345' => 'ccc',
// ],
// ]
```
## Tri multidimensionnel <span id="multidimensional-sorting"></span>
La méthode `multisort` facilite le tri d'un tableau d'objets ou de tableaux imbriqués selon une ou plusieurs clés. Par exemple :
```php
$data = [
['age' => 30, 'name' => 'Alexander'],
['age' => 30, 'name' => 'Brian'],
['age' => 19, 'name' => 'Barney'],
];
ArrayHelper::multisort($data, ['age', 'name'], [SORT_ASC, SORT_DESC]);
```
Après le tri, `data` contient ce qui suit :
```php
[
['age' => 19, 'name' => 'Barney'],
['age' => 30, 'name' => 'Brian'],
['age' => 30, 'name' => 'Alexander'],
];
```
Le deuxième argument, qui spécifie les clés de tri peut être une chaîne de caractères si la clé est unique, un tableau dans le cas de clés multiples, ou une fonction anonyme telle que celle qui suit :
```php
ArrayHelper::multisort($data, function($item) {
return isset($item['age']) ? ['age', 'name'] : 'name';
});
```
Le troisième argument précise la direction. Dans le cas d'un tri selon une clé unique, il s'agit soit de `SORT_ASC`, soit de `SORT_DESC`. Si le tri se fait selon des valeurs multiples, vous pouvez préciser des directions de tri différentes pour chacune des clés en présentant ces directions sous forme de tableau.
Le dernier argument est une option de tri de PHP qui peut prendre les mêmes valeurs que celles acceptées par la fonction [sort()](http://php.net/manual/en/function.sort.php) de PHP.
## Détection des types de tableau <span id="detecting-array-types"></span>
Il est pratique de savoir si un tableau est indexé ou associatif. Voici un exemple :
```php
// aucune clé spécifiée
$indexed = ['Qiang', 'Paul'];
echo ArrayHelper::isIndexed($indexed);
// toutes les clés sont des chaînes de caractères
$associative = ['framework' => 'Yii', 'version' => '2.0'];
echo ArrayHelper::isAssociative($associative);
```
## Encodage et décodage de valeurs HTML <span id="html-encoding-values"></span>
Afin d'encoder ou décoder des caractères spéciaux dans un tableau de chaînes de caractères en/depuis des entités HTML, vous pouvez utiliser les fonctions suivantes :
```php
$encoded = ArrayHelper::htmlEncode($data);
$decoded = ArrayHelper::htmlDecode($data);
```
Seules les valeurs sont encodées par défaut. En passant un deuxième argument comme `false` vous pouvez également encoder les clés d'un tableau. L'encodage utilise le jeu de caractères de l'application et on peut le changer via un troisième argument.
## Fusion de tableaux <span id="merging-arrays"></span>
La fonction [[yii\helpers\ArrayHelper::merge()|ArrayHelper::merge()]] vous permet de fusionner deux, ou plus, tableaux en un seul de manière récursive. Si chacun des tableaux possède un élément avec la même chaîne clé valeur, le dernier écrase le premier (ce qui est un fonctionnement différent de [array_merge_recursive()](http://php.net/manual/en/function.array-merge-recursive.php)).
La fusion récursive est entreprise si les deux tableaux possèdent un élément de type tableau avec la même clé. Pour des éléments dont la clé est un entier, les éléments du deuxième tableau sont ajoutés aux éléments du premier tableau. Vous pouvez utiliser l'objet [[yii\helpers\UnsetArrayValue]] pour supprimer la valeur du premier tableau ou [[yii\helpers\ReplaceArrayValue]] pour forcer le remplacement de la première valeur au lieu de la fusion récursive.
Par exemple :
```php
$array1 = [
'name' => 'Yii',
'version' => '1.1',
'ids' => [
1,
],
'validDomains' => [
'example.com',
'www.example.com',
],
'emails' => [
'admin' => 'admin@example.com',
'dev' => 'dev@example.com',
],
];
$array2 = [
'version' => '2.0',
'ids' => [
2,
],
'validDomains' => new \yii\helpers\ReplaceArrayValue([
'yiiframework.com',
'www.yiiframework.com',
]),
'emails' => [
'dev' => new \yii\helpers\UnsetArrayValue(),
],
];
$result = ArrayHelper::merge($array1, $array2);
```
Le résultat est :
```php
[
'name' => 'Yii',
'version' => '2.0',
'ids' => [
1,
2,
],
'validDomains' => [
'yiiframework.com',
'www.yiiframework.com',
],
'emails' => [
'admin' => 'admin@example.com',
],
]
```
## Conversion d'objets en tableaux <span id="converting-objects-to-arrays"></span>
Il arrive souvent que vous ayez besoin de convertir un objet, ou un tableau d'objets, en tableau. Le cas le plus courant est la conversion de modèles d'enregistrements actifs afin de servir des tableaux de données via une API REST ou pour un autre usage. Le code suivant peut alors être utilisé :
```php
$posts = Post::find()->limit(10)->all();
$data = ArrayHelper::toArray($posts, [
'app\models\Post' => [
'id',
'title',
// the key name in array result => property name
'createTime' => 'created_at',
// the key name in array result => anonymous function
'length' => function ($post) {
return strlen($post->content);
},
],
]);
```
Le premier argument contient les données à convertir. Dans notre cas, nous convertissons un modèle d'enregistrements actifs `Post`.
The second argument est un tableau de mise en correspondance de conversions par classe. Nous définissons une mise en correspondance pour le modèle `Post`. Chaque tableau de mise en correspondance contient un jeu de mise en correspondance. Chaque mise en correspondance peut être :
- Un nom de champ à inclure tel quel.
- Une paire clé-valeur dans laquelle la clé est donnée sous forme de chaîne de caractères et la valeur sous forme du nom de la colonne dont on doit prendre la valeur.
- Une paire clé-valeur dans laquelle la clé est donnée sous forme de chaîne de caractères et la valeur sous forme de fonction de rappel qui la retourne.
Le résultat de la conversion ci-dessus pour un modèle unique est :
```php
[
'id' => 123,
'title' => 'test',
'createTime' => '2013-01-01 12:00AM',
'length' => 301,
]
```
Il est possible de fournir une manière par défaut de convertir un objet en tableau pour une classe spécifique en implémentant l'interface [[yii\base\Arrayable|Arrayable]] dans cette classe.
## Test de l'appartenance à un tableau <span id="testing-arrays"></span>
Souvent, vous devez savoir si un élément se trouve dans un tableau ou si un jeu d'éléments est un sous-ensemble d'un autre. Bien que PHP offre la fonction `in_array()`, cette dernière ne prend pas en charge les sous-ensembles ou les objets `\Traversable`.
Pour faciliter ce genre de tests, [[yii\helpers\ArrayHelper]] fournit les méthodes [[yii\helpers\ArrayHelper::isIn()|isIn()]]
et [[yii\helpers\ArrayHelper::isSubset()|isSubset()]] avec la même signature que [in_array()](http://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']));
```

396
docs/guide-fr/helper-html.md

@ -0,0 +1,396 @@
Classe assistante Html
======================
Toutes les applications Web génèrent un grand nombre de balises HTML. Si le code HTML est statique, il peut être créé efficacement sous forme de [mélange de code PHP et de code HTML dans un seul fichier](http://php.net/manual/en/language.basic-syntax.phpmode.php), mais lorsqu'il est généré dynamiquement, cela commence à être compliqué à gérer sans une aide supplémentaire. Yii fournit une telle aide sous la forme de la classe assistante Html, qui offre un jeu de méthodes statiques pour manipuler les balises Html les plus courantes, leurs options et leur contenu.
> Note: si votre code HTML est presque statique, il vaut mieux utiliser HTML directement. Il n'est pas nécessaire d'envelopper tout dans des appels aux méthodes de la classe assistante Html.
## Les bases <span id="basics"></span>
Comme la construction de code HTML dynamique en concaténant des chaînes de caractère peut très vite tourner à la confusion, Yii fournit un jeu de méthodes pour manipuler les options de balises et construire des balises s'appuyant sur ces options.
### Génération de balises <span id="generating-tags"></span>
Le code pour générer une balise ressemble à ceci :
```php
<?= Html::tag('p', Html::encode($user->name), ['class' => 'username']) ?>
```
Le premier argument est le nom de la balise. Le deuxième est le contenu qui apparaît entre l'ouverture de la balise et sa fermeture.
Notez que nous utilisons `Html::encode` – c'est parce que le contenu n'est pas encodé automatiquement pour permetre l'utilisation de HTML quand c'est nécessaire.
Le troisième est un tableau d'options HTML ou, en d'autres mots, les attributs de la balise.
Dans ce tableau, la clé est le nom de l'attribut (comme `class`, `href` ou `target`) et la valeur est sa valeur.
Le code ci-dessus génère le code HTML suivant :
```html
<p class="username">samdark</p>
```
Dans le cas où vous avez simplement besoin d'ouvrir ou de fermer la balise, vous pouvez utiliser les méthodes `Html::beginTag()` et `Html::endTag()`.
Des options sont utilisées dans de nombreuses méthodes de la classe assistante Html et de nombreux composants graphiques (widgets). Dans tous ces cas, il y a quelques manipulations supplémentaires à connaître :
- Si une valeur est `null`, l'attribut correspondant n'est pas rendu.
- Les attributs du type booléen sont traités comme des
[attributs booléens ](http://www.w3.org/TR/html5/infrastructure.html#boolean-attributes).
- Les valeurs des attributs sont encodés HTML à l'aide de la méthode [[yii\helpers\Html::encode()|Html::encode()]].
- Si la valeur d'un attribut est un tableau, il est géré comme suit :
* Si l'attribut est un attribut de donnée tel que listé dans [[yii\helpers\Html::$dataAttributes]], tel que `data` ou `ng`,
une liste d'attributs est rendue, un pour chacun des élément dans le tableau de valeurs. Par exemple,
`'data' => ['id' => 1, 'name' => 'yii']` génère `data-id="1" data-name="yii"`; et
`'data' => ['params' => ['id' => 1, 'name' => 'yii'], 'status' => 'ok']` génère
`data-params='{"id":1,"name":"yii"}' data-status="ok"`. Notez que dans le dernier exemple le format JSON est utilisé pour rendre le sous-tableau.
* Si l'attribut n'est PAS un attribut de donnée, la valeur est encodée JSON. Par exemple,
`['params' => ['id' => 1, 'name' => 'yii']` génère `params='{"id":1,"name":"yii"}'`.
### Formation des classes et des styles CSS <span id="forming-css"></span>
Lors de la construction des options pour des balises HTML, nous démarrons souvent avec des valeurs par défaut qu'il faut modifier. Afin d'ajouter ou de retirer une classe, vous pouvez utiliser ce qui suit :
```php
$options = ['class' => 'btn btn-default'];
if ($type === 'success') {
Html::removeCssClass($options, 'btn-default');
Html::addCssClass($options, 'btn-success');
}
echo Html::tag('div', 'Pwede na', $options);
// si la valeur de $type est 'success' le rendu sera
// <div class="btn btn-success">Pwede na</div>
```
Vous pouvez spécifier de multiples classe CSS en utilisant le tableau de styles également :
```php
$options = ['class' => ['btn', 'btn-default']];
echo Html::tag('div', 'Save', $options);
// rend '<div class="btn btn-default">Save</div>'
```
Vous pouvez aussi utiliser le tableau de styles pour ajouter ou retirer des classes :
```php
$options = ['class' => 'btn'];
if ($type === 'success') {
Html::addCssClass($options, ['btn-success', 'btn-lg']);
}
echo Html::tag('div', 'Save', $options);
// rend '<div class="btn btn-success btn-lg">Save</div>'
```
`Html::addCssClass()` empêche la duplication, vous n'avez donc pas à vous préoccuper de savoir si une classe apparaît deux fois :
```php
$options = ['class' => 'btn btn-default'];
Html::addCssClass($options, 'btn-default'); // class 'btn-default' is already present
echo Html::tag('div', 'Save', $options);
// rend '<div class="btn btn-default">Save</div>'
```
Si l'option classe CSS est spécifiée en utilisant le tableau de styles, vous pouvez utiliser une clé nommée pour indiquer le but logique de la classe. Dans ce cas, une classe utilisant la même clé dans le tableau de styles passé à `Html::addClass()` est ignorée :
```php
$options = [
'class' => [
'btn',
'theme' => 'btn-default',
]
];
Html::addCssClass($options, ['theme' => 'btn-success']); // la clé 'theme' est déjà utilisée
echo Html::tag('div', 'Save', $options);
// rend '<div class="btn btn-default">Save</div>'
```
Les styles CSS peuvent être définis d'une façon similaire en utilisant l'attribut `style` :
```php
$options = ['style' => ['width' => '100px', 'height' => '100px']];
// donne style="width: 100px; height: 200px; position: absolute;"
Html::addCssStyle($options, 'height: 200px; position: absolute;');
// gives style="position: absolute;"
Html::removeCssStyle($options, ['width', 'height']);
```
Lors de l'utilisation de [[yii\helpers\Html::addCssStyle()|addCssStyle()]], vous pouvez spécifier soit un tableau de paires clé-valeur qui correspond aux propriétés CSS noms et valeurs, soit une chaîne de caractères telle que `width: 100px; height: 200px;`. Ces formats peuvent être convertis de l'un en l'autre en utilisant les méthodes [[yii\helpers\Html::cssStyleFromArray()|cssStyleFromArray()]] et
[[yii\helpers\Html::cssStyleToArray()|cssStyleToArray()]]. La méthode [[yii\helpers\Html::removeCssStyle()|removeCssStyle()]]
accepte un tableau de propriétés à retirer. S'il s'agit d'une propriété unique, elle peut être spécifiée sous forme de chaîne de caractères.
### Encodage et décodage du contenu <span id="encoding-and-decoding-content"></span>
Pour que le contenu puisse être affiché en HTML de manière propre et en toute sécurité, les caractères spéciaux du contenu doivent être encodés. En PHP, cela s'obtient avec [htmlspecialchars](http://www.php.net/manual/en/function.htmlspecialchars.php) et
[htmlspecialchars_decode](http://www.php.net/manual/en/function.htmlspecialchars-decode.php). Le problème rencontré en utilisant ces méthodes directement est que vous devez spécifier l'encodage et des options supplémentaires tout le temps. Comme ces options restent toujours les mêmes et que l'encodage doit correspondre à celui de l'application pour éviter les problèmes de sécurité, Yii fournit deux méthodes compactes et faciles à utiliser :
```php
$userName = Html::encode($user->name);
echo $userName;
$decodedUserName = Html::decode($userName);
```
## Formulaires <span id="forms"></span>
Manipuler des formulaires dans le code HTML est tout à fait répétitif et sujet à erreurs. À cause de cela, il existe un groupe de méthodes pour aider à les manipuler.
> Note : envisagez d'utiliser [[yii\widgets\ActiveForm|ActiveForm]] dans le cas où vous avez affaire à des modèles et que ces derniers doivent être validés.
### Création de formulaires <span id="creating-forms"></span>
Les formulaires peut être ouverts avec la méthode [[yii\helpers\Html::beginForm()|beginForm()]] comme ceci :
```php
<?= Html::beginForm(['order/update', 'id' => $id], 'post', ['enctype' => 'multipart/form-data']) ?>
```
Le premier argument est l'URL à laquelle le formulaire sera soumis. Il peut être spécifié sous la forme d'une route Yii et de paramètres acceptés par [[yii\helpers\Url::to()|Url::to()]].
Le deuxième est la méthode à utiliser. `post` est la méthode par défaut. Le troisième est un tableau d'options pour la balise form. Dans ce cas, nous modifions l'encodage des données du formulaire dans la requête POST en `multipart/form-data`, ce qui est requis pour envoyer des fichiers.
La fermeture du formulaire se fait simplement par :
```php
<?= Html::endForm() ?>
```
### Boutons <span id="buttons"></span>
Pour générer des boutons, vous pouvez utiliser le code suivant :
```php
<?= Html::button('Pressez-mo!', ['class' => 'teaser']) ?>
<?= Html::submitButton('Envoyer', ['class' => 'submit']) ?>
<?= Html::resetButton('Ré-initialiser', ['class' => 'reset']) ?>
```
Le premier argument pour les trois méthodes est l'intitulé du bouton, le deuxième est un tableau d'options.
L'intitulé n'est pas encodé, mais si vous affichez des données en provenance de l'utilisateur, encodez les avec [[yii\helpers\Html::encode()|Html::encode()]].
### Champs d'entrée <span id="input-fields"></span>
Il y a deux groupes de méthodes d'entrée de données. Celles qui commencent par `active`, est qui sont appelées entrées actives, et celles qui ne commencent pas par ce mot. Les entrées actives prennent leurs données dans le modèle à partir des attributs spécifiés, tandis que pour les entrées régulières, les données sont spécifiées directement.
Les méthodes les plus génériques sont :
```php
type, nom de l'entrée, valeur de l'entrée, options
<?= Html::input('text', 'username', $user->name, ['class' => $username]) ?>
type, modèle, nom de l'attribut du modèle, options
<?= Html::activeInput('text', $user, 'name', ['class' => $username]) ?>
```
Si vous connaissez le type de l'entrée à l'avance, il est plus commode d'utiliser les méthodes raccourcis :
- [[yii\helpers\Html::buttonInput()]]
- [[yii\helpers\Html::submitInput()]]
- [[yii\helpers\Html::resetInput()]]
- [[yii\helpers\Html::textInput()]], [[yii\helpers\Html::activeTextInput()]]
- [[yii\helpers\Html::hiddenInput()]], [[yii\helpers\Html::activeHiddenInput()]]
- [[yii\helpers\Html::passwordInput()]] / [[yii\helpers\Html::activePasswordInput()]]
- [[yii\helpers\Html::fileInput()]], [[yii\helpers\Html::activeFileInput()]]
- [[yii\helpers\Html::textarea()]], [[yii\helpers\Html::activeTextarea()]]
Les listes radio et les boîtes à cocher sont un peu différentes en matière de signature de méthode :
```php
<?= Html::radio('agree', true, ['label' => 'I agree']);
<?= Html::activeRadio($model, 'agree', ['class' => 'agreement'])
<?= Html::checkbox('agree', true, ['label' => 'I agree']);
<?= Html::activeCheckbox($model, 'agree', ['class' => 'agreement'])
```
Les listes déroulantes et les boîtes listes peuvent être rendues comme suit :
```php
<?= Html::dropDownList('list', $currentUserId, ArrayHelper::map($userModels, 'id', 'name')) ?>
<?= Html::activeDropDownList($users, 'id', ArrayHelper::map($userModels, 'id', 'name')) ?>
<?= Html::listBox('list', $currentUserId, ArrayHelper::map($userModels, 'id', 'name')) ?>
<?= Html::activeListBox($users, 'id', ArrayHelper::map($userModels, 'id', 'name')) ?>
```
Le premier argument est le nom de l'entrée, le deuxième est la valeur sélectionnée actuelle et le troisième est un tableau de paires clé-valeur, dans lequel la clé est la valeur d'entrée dans la liste et la valeur est l'étiquette qui correspond à cette valeur dans la liste.
Si vous désirez que des choix multiples soient sélectionnables, vous pouvez utiliser la liste à sélection multiples (checkbox list) :
```php
<?= Html::checkboxList('roles', [16, 42], ArrayHelper::map($roleModels, 'id', 'name')) ?>
<?= Html::activeCheckboxList($user, 'role', ArrayHelper::map($roleModels, 'id', 'name')) ?>
```
Sinon utilisez la liste radio :
```php
<?= Html::radioList('roles', [16, 42], ArrayHelper::map($roleModels, 'id', 'name')) ?>
<?= Html::activeRadioList($user, 'role', ArrayHelper::map($roleModels, 'id', 'name')) ?>
```
### Étiquettes et erreurs <span id="labels-and-errors"></span>
Comme pour les entrées, il existe deux méthodes pour générer les étiquettes de formulaire. Celles pour les entrées « actives » qui prennent leurs étiquettes dans le modèle, et celles « non actives » qui sont étiquetées directement :
```php
<?= Html::label('User name', 'username', ['class' => 'label username']) ?>
<?= Html::activeLabel($user, 'username', ['class' => 'label username']) ?>
```
Pour afficher les erreurs de formulaire à partir d'un modèle ou sous forme de résumé pour un modèle, vous pouvez utiliser :
```php
<?= Html::errorSummary($posts, ['class' => 'errors']) ?>
```
Pour afficher une erreur individuellement :
```php
<?= Html::error($post, 'title', ['class' => 'error']) ?>
```
### Nom et valeur des entrées <span id="input-names-and-values"></span>
Il existe deux méthodes pour obtenir des noms, des identifiants et des valeurs pour des champs d'entrée basés sur un modèle. Elles sont essentiellement utilisées en interne, mais peuvent être pratiques quelques fois :
```php
// Post[title]
echo Html::getInputName($post, 'title');
// post-title
echo Html::getInputId($post, 'title');
// my first post
echo Html::getAttributeValue($post, 'title');
// $post->authors[0]
echo Html::getAttributeValue($post, '[0]authors[0]');
```
Dans ce qui précède, le premier argument est le modèle, tandis que le deuxième est l'expression d'attribut. Dans sa forme la plus simple, l'expression est juste un nom d'attribut, mais il peut aussi s'agir d'un nom d'attribut préfixé et-ou suffixé par des index de tableau, ce qui est essentiellement le cas pour des entrées tabulaires :
- `[0]content` est utilisé dans des entrées de données tabulaires pour représenter l'attribut `content` pour le premier modèle des entrées tabulaires ;
- `dates[0]` représente le premier élément du tableau de l'attribut `dates` ;
- `[0]dates[0]` représente le premier élément du tableau de l'attribut `dates` pour le premier modèle des entrées tabulaires.
Afin d'obtenir le nom de l'attribut sans suffixe ou préfixe, vous pouvez utiliser ce qui suit :
```php
// dates
echo Html::getAttributeName('dates[0]');
```
## Styles et scripts <span id="styles-and-scripts"></span>
Il existe deux méthodes pour générer les balises enveloppes des styles et des scripts :
```php
<?= Html::style('.danger { color: #f00; }') ?>
Produit
<style>.danger { color: #f00; }</style>
<?= Html::script('alert("Hello!");', ['defer' => true]);
Produit
<script defer>alert("Hello!");</script>
```
Si vous désirez utiliser utiliser un style externe d'un fichier CSS :
```php
<?= Html::cssFile('@web/css/ie5.css', ['condition' => 'IE 5']) ?>
génère
<!--[if IE 5]>
<link href="http://example.com/css/ie5.css" />
<![endif]-->
```
Le premier argument est l'URL. Le deuxième est un tableau d'options. En plus des options normales, vous pouvez spécifier :
- `condition` pour envelopper `<link` dans des commentaires conditionnels avec la condition spécifiée. Nous espérons que vous n'aurez jamais besoin de commentaires conditionnels ;
- `noscript` peut être défini à `true` pour envelopper `<link` dans une balise `<noscript>` de façon à ce qu'elle soit incluse seulement si le navigateur ne prend pas en charge JavaScript ou si l'utilisateur l'a désactivé.
Pour lier un fichier JavaScript :
```php
<?= Html::jsFile('@web/js/main.js') ?>
```
Se passe comme avec CSS, le premier argument spécifie l'URL du fichier à inclure. Les options sont passées via le deuxième argument. Dans les options vous pouvez spécifier `condition` de la même manière que dans les options pour un fichier CSS (méthode `cssFile`).
## Hyperliens <span id="hyperlinks"></span>
Il y a une méthode commode pour générer les hyperliens :
```php
<?= Html::a('Profile', ['user/view', 'id' => $id], ['class' => 'profile-link']) ?>
```
Le premier argument est le titre. Il n'est pas encodé, mais si vous utilisez des données entrées par l'utilisateur, vous devez les encoder avec `Html::encode()`. Le deuxième argument est ce qui se retrouvera dans l'attribut `href` de la balise `<a`.
Voir [Url::to()](helper-url.md) pour les détails sur les valeurs acceptées.
Le troisième argument est un tableau pour les attributs de la balise.
Si vous devez générer des liens `mailto`, vous pouvez utiliser le code suivant :
```php
<?= Html::mailto('Contact us', 'admin@example.com') ?>
```
## Images <span id="images"></span>
Pour générer une balise image, utilisez le code suivant :
```php
<?= Html::img('@web/images/logo.png', ['alt' => 'My logo']) ?>
qui génère
<img src="http://example.com/images/logo.png" alt="My logo" />
```
En plus des [alias](concept-aliases.md), le premier argument accepte les routes, les paramètres et les URL, tout comme [Url::to()](helper-url.md).
## Listes <span id="lists"></span>
Les listes non ordonnées peuvent être générées comme suit :
```php
<?= Html::ul($posts, ['item' => function($item, $index) {
return Html::tag(
'li',
$this->render('post', ['item' => $item]),
['class' => 'post']
);
}]) ?>
```
Pour une liste ordonnée, utilisez plutôt `Html::ol()`.

68
docs/guide-fr/helper-overview.md

@ -0,0 +1,68 @@
Classes assistantes
===================
> Note: cette section est en cours de développement.
Yii procure de nombreuses classes qui vous aident à simplifier le code de tâches courantes, telles que la manipulation de chaînes de caractères ou de tableaux, la génération de code HTML, et ainsi de suite. Ces classes assistantes sont organisées dans l'espace de noms `yii\helpers` et sont toutes des classes statiques (ce qui signifie qu'elles ne contiennent que des propriétés et des méthodes statiques et ne doivent jamais être instanciées).
Vous utilisez une classe assistante en appelant directement une de ses méthodes statiques, comme ceci :
```php
use yii\helpers\Html;
echo Html::encode('Test > test');
```
> Note: pour prendre en charge la [personnalisation des classes assistantes](#customizing-helper-classes), Yii éclate chacune des classes assistantes du noyau en deux classes : une classe de base (p. ex. `BaseArrayHelper`) et une classe concrète (p. ex. `ArrayHelper`). Lorsque vous utilisez une classe assistante, vous devez utiliser la version concrète uniquement et ne jamais utiliser la classe de base.
Classes assistantes du noyau
----------------------------
Les versions de Yii fournissent les classes assistantes du noyau suivantes :
- [ArrayHelper](helper-array.md)
- Console
- FileHelper
- FormatConverter
- [Html](helper-html.md)
- HtmlPurifier
- Imagine (provided by yii2-imagine extension)
- Inflector
- Json
- Markdown
- StringHelper
- [Url](helper-url.md)
- VarDumper
Personnalisation des classes assistantes <span id="customizing-helper-classes"></span>
----------------------------------------
Pour personnaliser une classe assistante du noyau (p. ex. [[yii\helpers\ArrayHelper]]), vous devez créer une nouvelle classe qui étend la classe de base correspondant à la classe assistante (p. ex. [[yii\helpers\ArrayHelper]]), y compris son espace de noms. Cette classe sera ensuite configurée pour remplacer l'implémentation originale de Yii.
L'exemple qui suit montre comment personnaliser la méthode [[yii\helpers\ArrayHelper::merge()|merge()]] de la classe [[yii\helpers\ArrayHelper]] :
```php
<?php
namespace yii\helpers;
class ArrayHelper extends BaseArrayHelper
{
public static function merge($a, $b)
{
// votre implémentation personnalisée
}
}
```
Sauvegardez votre classe dans un fichier nommé `ArrayHelper.php`. Le fichier peut se trouver dans n'importe quel dossier, par exemple, `@app/components`.
Ensuite, dans le [script d'entrée](structure-entry-scripts.md) de votre application, ajoutez la ligne de code suivante, après l'inclusion du fichier `yii.php` pour dire à la [classe autoloader de Yii](concept-autoloading.md) de charger votre classe personnalisée au lieu de la classe assistance originale de Yii.
```php
Yii::$classMap['yii\helpers\ArrayHelper'] = '@app/components/ArrayHelper.php';
```
Notez que la personnalisation d'une classe assistante n'est utile que si vous désirez changer le comportement d'une fonction existante de la classe assistante. Si vous désirez ajouter une fonction additionnelle à utiliser dans votre application, le mieux est de créer une classe assistante séparée pour cela.

161
docs/guide-fr/helper-url.md

@ -0,0 +1,161 @@
Classe assistante Url
=====================
La classe assistante Url fournit un jeu de méthodes statiques pour gérer les URL.
## Obtenir des URL communes <span id="getting-common-urls"></span>
Vous pouvez utiliser deux méthodes pour obtenir des URL communes : l'URL de la page d'accueil et l'URL de base de la requête courante. Pour obtenir l'URL de la page d'accueil, utilisez ce qui suit :
```php
$relativeHomeUrl = Url::home();
$absoluteHomeUrl = Url::home(true);
$httpsAbsoluteHomeUrl = Url::home('https');
```
Si aucun paramètre n'est passé, l'URL générée est relative. Vous pouvez passer `true` pour obtenir une URL absolue pour le schéma courant ou spécifier un schéma explicitement (`https`, `http`).
Pour obtenir l'URL de base de la requête courante utilisez ceci :
```php
$relativeBaseUrl = Url::base();
$absoluteBaseUrl = Url::base(true);
$httpsAbsoluteBaseUrl = Url::base('https');
```
L'unique paramètre de la méthode fonctionne comme pour `Url::home()`.
## Création d'URL <span id="creating-urls"></span>
En vue de créer une URL pour une route donnée, utilisez la méthode `Url::toRoute()`. La méthode utilise [[\yii\web\UrlManager]] pour créer une URL :
```php
$url = Url::toRoute(['product/view', 'id' => 42]);
```
Vous pouvez spécifier la route sous forme de chaîne de caractère, p. ex. `site/index`. Vous pouvez également utiliser un tableau si vous désirez spécifier des paramètres de requête supplémentaires pour l'URL créée. Le format du tableau doit être :
```php
// génère : /index.php?r=site%2Findex&param1=value1&param2=value2
['site/index', 'param1' => 'value1', 'param2' => 'value2']
```
Si vous voulez créer une URL avec une ancre, vous pouvez utiliser le format de tableau avec un paramètre `#`. Par exemple :
```php
// génère: /index.php?r=site%2Findex&param1=value1#name
['site/index', 'param1' => 'value1', '#' => 'name']
```
Une route peut être ,soit absolue, soit relative. Une route absolue commence par une barre oblique de division (p. ex. `/site/index`) tandis que route relative commence sans ce caractère (p. ex. `site/index` ou `index`). Une route relative peut être convertie en une route absolue en utilisant une des règles suivantes :
- Si la route est une chaîne de caractères vide, la [[\yii\web\Controller::route|route]] est utilisée ;
- Si la route ne contient aucune barre oblique de division (p. ex. `index`), elle est considérée être un identifiant d'action dans le contrôleur courant et sera préfixée par l'identifiant du contrôleur ([[\yii\web\Controller::uniqueId]]);
- Si la route ne commence pas par une barre oblique de division (p. ex. `site/index`), elle est considérée être une route relative au module courant et sera préfixée par l'identifiant du module ([[\yii\base\Module::uniqueId|uniqueId]]).
Depuis la version 2.0.2, vous pouvez spécifier une route sous forme d'[alias](concept-aliases.md). Si c'est le cas, l'alias sera d'abord converti en la route réelle puis transformé en une route absolue en respectant les règles ci-dessus.
Voci quelques exemple d'utilisation de cette méthode :
```php
// /index.php?r=site%2Findex
echo Url::toRoute('site/index');
// /index.php?r=site%2Findex&src=ref1#name
echo Url::toRoute(['site/index', 'src' => 'ref1', '#' => 'name']);
// /index.php?r=post%2Fedit&id=100 assume the alias "@postEdit" is defined as "post/edit"
echo Url::toRoute(['@postEdit', 'id' => 100]);
// http://www.example.com/index.php?r=site%2Findex
echo Url::toRoute('site/index', true);
// https://www.example.com/index.php?r=site%2Findex
echo Url::toRoute('site/index', 'https');
```
Il existe une autre méthode `Url::to()` très similaire à [[toRoute()]]. La seule différence est que cette méthode requiert la spécification d'une route sous forme de tableau seulement. Si une chaîne de caractères est données, elle est traitée comme une URL.
Le premier argument peut être :
- un tableau : [[toRoute()]] sera appelée pour générer l'URL. Par exemple :
`['site/index']`, `['post/index', 'page' => 2]`. Reportez-vous à la méthode [[toRoute()]] pour plus de détails sur la manière de spécifier une route.
- une chaîne de caractères commençant par `@`: elle est traitée commme un alias, et la chaine aliasée correspondante est retournée ;
- une chaîne de caractères vide : l'URL couramment requise est retournée ;
- une chaîne de caractères normale : elle est retournée telle que.
Lorsque `$scheme` est spécifié (soit une chaîne de caractères, soit `true`), une URL absolue avec l'information hôte tirée de [[\yii\web\UrlManager::hostInfo]]) est retournée. Si`$url` est déjà une URL absolue, son schéma est remplacé par celui qui est spécifié.
Voici quelques exemples d'utilisation :
```php
// /index.php?r=site%2Findex
echo Url::to(['site/index']);
// /index.php?r=site%2Findex&src=ref1#name
echo Url::to(['site/index', 'src' => 'ref1', '#' => 'name']);
// /index.php?r=post%2Fedit&id=100 assume the alias "@postEdit" is defined as "post/edit"
echo Url::to(['@postEdit', 'id' => 100]);
// l'URL couramment requise
echo Url::to();
// /images/logo.gif
echo Url::to('@web/images/logo.gif');
// images/logo.gif
echo Url::to('images/logo.gif');
// http://www.example.com/images/logo.gif
echo Url::to('@web/images/logo.gif', true);
// https://www.example.com/images/logo.gif
echo Url::to('@web/images/logo.gif', 'https');
```
Depuis la version 2.0.3, vous pouvez utiliser [[yii\helpers\Url::current()]] pour créer une URL basée sur la route couramment requise et sur les paramètres de la méthode GET. Vous pouvez modifier ou retirer quelques uns des paramètres GET et en ajouter d'autres en passant le paramètre `$params` à la méthode. Par exemple :
```php
// suppose que $_GET = ['id' => 123, 'src' => 'google'],et que la route courante est "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]);
```
## Se souvenir d'URL <span id="remember-urls"></span>
Il y a des cas dans lesquels vous avez besoin de mémoriser une URL et ensuite de l'utiliser durant le traitement d'une des requêtes séquentielles. Cela peut être fait comme suit :
```php
// se souvenir de l'URL courante
Url::remember();
// Se souvenir de l'URL spécifiée. Voir Url::to() pour le format des arguments.
Url::remember(['product/view', 'id' => 42]);
// Se souvenir de l'URL spécifiée avec un nom
Url::remember(['product/view', 'id' => 42], 'product');
```
Dans la prochaine requête, vous pouvez récupérer l'URL mémorisée comme ceci :
```php
$url = Url::previous();
$productUrl = Url::previous('product');
```
## Vérification des URL relatives <span id="checking-relative-urls"></span>
Pour savoir si une URL est relative, c.-à-d. n'a pas de partie « hôte », vous pouvez utiliser le code suivant :
```php
$isRelative = Url::isRelative('test/it');
```

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

@ -0,0 +1,527 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
<!--Created by yEd 3.13-->
<key attr.name="Description" attr.type="string" for="graph" id="d0"/>
<key for="port" id="d1" yfiles.type="portgraphics"/>
<key for="port" id="d2" yfiles.type="portgeometry"/>
<key for="port" id="d3" yfiles.type="portuserdata"/>
<key attr.name="url" attr.type="string" for="node" id="d4"/>
<key attr.name="description" attr.type="string" for="node" id="d5"/>
<key for="node" id="d6" yfiles.type="nodegraphics"/>
<key for="graphml" id="d7" yfiles.type="resources"/>
<key attr.name="url" attr.type="string" for="edge" id="d8"/>
<key attr.name="description" attr.type="string" for="edge" id="d9"/>
<key for="edge" id="d10" yfiles.type="edgegraphics"/>
<graph edgedefault="directed" id="G">
<data key="d0"/>
<node id="n0" yfiles.foldertype="group">
<data key="d4"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="571.4472707112631" width="763.2772213171534" x="-1269.9373595143054" y="-207.17439524332679"/>
<y:Fill color="#FFCC0024" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="node_width" backgroundColor="#FFCC00" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="763.2772213171534" x="0.0" y="0.0">Entry script (index.php or yii)</y:NodeLabel>
<y:Shape type="rectangle"/>
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
<y:GroupNode>
<y:Geometry height="50.0" width="50.0" x="313.2978515625" y="225.33495140075684"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="59.02685546875" x="-4.513427734375" y="0.0">Folder 4</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
</y:Realizers>
</y:ProxyAutoBoundsNode>
</data>
<graph edgedefault="directed" id="n0:">
<node id="n0::n0">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="324.9258883570935" x="-1249.511914911339" y="-169.79793039957679"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="126.759765625" x="99.08306136604676" y="5.6494140625">Load application config<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n1" yfiles.foldertype="group">
<data key="d4"/>
<data key="d5"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="309.37646484374994" width="330.35133296005984" x="-1254.9373595143054" y="35.272875467936274"/>
<y:Fill color="#FFEFD6" transparent="false"/>
<y:BorderStyle hasColor="false" type="dashed" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="node_width" backgroundColor="#FF9900" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="330.35133296005984" x="0.0" y="0.0">Create application instance</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
<y:BorderInsets bottom="19" bottomF="19.15489692687993" left="5" leftF="5.425444602966309" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
<y:GroupNode>
<y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="59.02685546875" x="-4.513427734375" y="0.0">Folder 5</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
</y:Realizers>
</y:ProxyAutoBoundsNode>
</data>
<graph edgedefault="directed" id="n0::n1:">
<node id="n0::n1::n0">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="294.92588835709347" x="-1234.511914911339" y="72.64934031168627"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="45.34375" x="124.79106917854676" y="5.6494140625">preInit()<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n1::n1">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="294.92588835709347" x="-1234.511914911339" y="122.64524027506516"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="120.71875" x="87.10356917854676" y="5.6494140625">Register error handler<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n1::n2">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="294.92588835709347" x="-1234.511914911339" y="174.96110788981125"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="173.435546875" x="60.74517074104676" y="5.6494140625">Configure application properties<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n1::n3">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="294.92588835709347" x="-1234.511914911339" y="226.56779181162517"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="27.33203125" x="133.79692855354676" y="5.6494140625">init()<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n1::n4">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="294.9258883570935" x="-1234.511914911339" y="280.4944433848063"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="62.025390625" x="116.45024886604676" y="5.6494140625">bootstrap()<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
</graph>
</node>
<node id="n0::n2" yfiles.foldertype="group">
<data key="d4"/>
<data key="d5"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="411.6943410237631" width="324.9258883570935" x="-846.5860265542456" y="-169.79793039957679"/>
<y:Fill color="#FFEFD6" transparent="false"/>
<y:BorderStyle hasColor="false" type="dashed" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="node_width" backgroundColor="#FF9900" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="324.9258883570935" x="0.0" y="0.0">Run application</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="1.1368683772161603E-13"/>
</y:GroupNode>
<y:GroupNode>
<y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="59.02685546875" x="-4.513427734375" y="0.0">Folder 3</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
</y:Realizers>
</y:ProxyAutoBoundsNode>
</data>
<graph edgedefault="directed" id="n0::n2:">
<node id="n0::n2::n0">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="294.9258883570935" x="-831.5860265542456" y="-132.42146555582667"/>
<y:Fill color="#99CC00" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="164.705078125" x="65.11040511604676" y="5.6494140625">EVENT_BEFORE_REQUEST<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n2::n1" yfiles.foldertype="group">
<data key="d4"/>
<data key="d5"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="204.37646484375" width="294.9258883570935" x="-831.5860265542456" y="-78.79793039957679"/>
<y:Fill color="#99336635" transparent="false"/>
<y:BorderStyle hasColor="false" type="dashed" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="node_width" backgroundColor="#993366" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" modelName="internal" modelPosition="t" textColor="#FFFFFF" visible="true" width="294.9258883570935" x="0.0" y="0.0">Handle request</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
<y:BorderInsets bottom="8" bottomF="7.929194132486941" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
<y:GroupNode>
<y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="59.02685546875" x="-4.513427734375" y="0.0">Folder 4</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
</y:Realizers>
</y:ProxyAutoBoundsNode>
</data>
<graph edgedefault="directed" id="n0::n2::n1:">
<node id="n0::n2::n1::n0">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="264.9258883570935" x="-816.5860265542456" y="-41.421465555826785"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="231.4609375" x="16.732475428546763" y="5.6494140625">Resolve request into route and parameters<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n2::n1::n1">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="264.9258883570935" x="-816.5860265542456" y="18.578534444173215"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="197.44140625" x="33.74224105354676" y="5.6494140625">Create module, controller and action<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n2::n1::n2">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="264.9258883570935" x="-816.5860265542456" y="72.64934031168627"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="61.369140625" x="101.77837386604676" y="5.649414062500057">Run action<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
</graph>
</node>
<node id="n0::n2::n2">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="294.9258883570935" x="-831.5860265542456" y="149.20206960042316"/>
<y:Fill color="#99CC00" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="154.697265625" x="70.11431136604676" y="5.6494140625">EVENT_AFTER_REQUEST<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n2::n3">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="294.92588835709347" x="-831.5860265542456" y="196.89641062418633"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="148.099609375" x="73.41313949104676" y="5.6494140625">Send response to end user<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
</graph>
</node>
<node id="n0::n3">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="324.9258883570935" x="-846.5860265542456" y="319.2728754679363"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="160.08203125" x="82.42192855354676" y="5.6494140625">Complete request processing<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
</graph>
</node>
<edge id="e0" source="n0" target="n0::n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="-179.83580569315376" sy="-180.3944529152355" tx="-13.869777491410105" ty="-154.8008369539754"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e0" source="n0::n0" target="n0::n1">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:EdgeLabel alignment="center" backgroundColor="#99CCFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" height="18.701171875" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="106.052734375" x="-130.76131968438426" y="78.18481445312506">Configuration array<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="77.04379339868619" distanceToCenter="true" position="right" ratio="0.5" segment="0"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::n1::e0" source="n0::n1::n0" target="n0::n1::n1">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::n1::e1" source="n0::n1::n1" target="n0::n1::n2">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::n1::e2" source="n0::n1::n2" target="n0::n1::n3">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::n1::e3" source="n0::n1::n3" target="n0::n1::n4">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e1" source="n0::n1" target="n0::n2">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="2.8060680342755404" sy="-48.37646484374994" tx="-162.49660512430125" ty="105.53540293375653"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::n2::e0" source="n0::n2::n0" target="n0::n2::n1">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::n2::n1::e0" source="n0::n2::n1::n0" target="n0::n2::n1::n1">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::n2::n1::e1" source="n0::n2::n1::n1" target="n0::n2::n1::n2">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::n2::e1" source="n0::n2::n1" target="n0::n2::n2">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::n2::e2" source="n0::n2::n2" target="n0::n2::n3">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e2" source="n0::n2" target="n0::n3">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:EdgeLabel alignment="center" backgroundColor="#99CCFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" height="18.701171875" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="59.353515625" x="-93.67673227804266" y="28.318773905436274">Exit status<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="63.99999999999999" distanceToCenter="true" position="right" ratio="0.47945569632951074" segment="-1"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
</graph>
<data key="d7">
<y:Resources/>
</data>
</graphml>

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
docs/guide-fr/images/request-lifecycle.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 46 KiB

189
docs/guide-fr/input-file-upload.md

@ -0,0 +1,189 @@
Chargement de fichiers sur le serveur
=====================================
Le chargement de fichiers sur le serveur dans Yii est ordinairement effectué avec l'aide de [[yii\web\UploadedFile]] qui encapsule chaque fichier chargé dans un objet `UploadedFile`. Combiné avec les [[yii\widgets\ActiveForm]] et les [modèles](structure-models.md), vous pouvez aisément mettre en œuvre un mécanisme sûr de chargement de fichiers sur le serveur.
## Création de modèles <span id="creating-models"></span>
Comme on le ferait avec des entrées de texte simple, pour charger un unique fichier sur le serveur, vous devez créer une classe de modèle et utliser un attribut du modèle pour conserver un instance du fichier chargé. Vous devez également déclarer une règle de validation pour valider le fichier chargé. Par exemple :
```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;
}
}
}
```
Dans le code ci-dessus, l'attribut `imageFile` est utilisé pur conserver une instance du fichier chargé. Il est associé à une règle de validation de fichier (`file`) qui utilise [[yii\validators\FileValidator]] pour garantir que l'extension du nom de fichier chargé est `png` ou `jpg`. La méthode `upload()` effectue l'examen de validation et sauvegarde le fichier sur le serveur.
Le validateur `file` vous permet de vérifier l'extension du fichier, sa taille, son type MIME, etc. Reportez-vous à la section [Validateurs de noyau](tutorial-core-validators.md#file) pour plus de détails.
> Tip: si vous chargez une image sur le serveur, vous pouvez envisager l'utilisation du validateur `image` au lieu de `file`. Le validateur `image` est mis en œuvre via [[yii\validators\ImageValidator]] qui vérifie si un attribut a reçu une image valide qui peut être, soit sauvegardée, soit traitée en utilisant l'[extension Imagine](https://github.com/yiisoft/yii2-imagine).
## Rendu d'une entrée de fichier <span id="rendering-file-input"></span>
Ensuite, créez une entrée de fichier dans une vue :
```php
<?php
use yii\widgets\ActiveForm;
?>
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]) ?>
<?= $form->field($model, 'imageFile')->fileInput() ?>
<button>Submit</button>
<?php ActiveForm::end() ?>
```
Il est important de se rappeler que vous devez ajouter l'option `enctype` au formulaire afin que le fichier soit proprement chargé sur le serveur. L'appel de `fileInput()` rend une balise `<input type="file">` qui permet à l'utilisateur de sélectionner un fichier à charger sur le serveur.
> Tip: depuis la version 2.0.8, [[yii\web\widgets\ActiveField::fileInput|fileInput]] ajoute l'option `enctype` au formulaire automatiquement lorsqu'un champ d'entrée de fichier est utilisé.
## Câblage <span id="wiring-up"></span>
Maintenant dans une action de contrôleur, écrivez le code de câblage entre le modèle et la vue pour mettre en œuvre le chargement sur le serveur :
```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()) {
// le fichier a été chargé avec succès sur le serveur
return;
}
}
return $this->render('upload', ['model' => $model]);
}
}
```
Dans le code ci-dessus, lorsque le formulaire est soumis, la méthode [[yii\web\UploadedFile::getInstance()]] est appelée pour représenter le fichier chargé sous forme d'instance de `UploadedFile`. Nous comptons ensuite sur la validation du modèle pour garantir que le fichier chargé est valide et le sauvegarder sur le serveur.
## Chargement sur le serveur de plusieurs fichiers <span id="uploading-multiple-files"></span>
Vous pouvez également charger sur le serveur plusieurs fichiers à la fois, avec quelques ajustements au code présenté dans les sous-sections précédentes.
Tout d'abord, vous devez ajuster la classe du modèle en ajoutant l'option `maxFiles` dans la règle de validation de `file` pour limiter le nombre maximum de fichiers à charger simultanément. Définir `maxFiles` à `0` signifie que ce nombre n'est pas limité. Le nombre maximal de fichiers que l'on peut charger simultanément est aussi limité par la directive PHP [`max_file_uploads`](http://php.net/manual/en/ini.core.php#ini.max-file-uploads), dont la valeur par défaut est 20. La méthode `upload()` doit aussi être modifiée pour permettre la sauvegarde des fichiers un à un.
```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;
}
}
}
```
Dans le fichier de vue, vous devez ajouter l'option `multiple` à l'appel de `fileInput()` afin que le champ d'entrée puisse recevoir plusieurs fichiers :
```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>Submit</button>
<?php ActiveForm::end() ?>
```
Pour finir, dans l'action du contrôleur, vous devez appeler `UploadedFile::getInstances()` au lieu de `UploadedFile::getInstance()` pour assigner un tableau d'instances de `UploadedFile` à `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()) {
// file is uploaded successfully
return;
}
}
return $this->render('upload', ['model' => $model]);
}
}
```

155
docs/guide-fr/input-forms.md

@ -0,0 +1,155 @@
Création de formulaires
=======================
La manière primaire d'utiliser des formulaires dans Yii de faire appel aux [[yii\widgets\ActiveForm]]. Cette approche doit être privilégiée lorsque le formulaire est basé sur un modèle. En plus, il existe quelques méthodes utiles dans [[yii\helpers\Html]] qui sont typiquement utilisées pour ajouter des boutons et des textes d'aides de toute forme.
Un formulaire, qui est affiché du côté client, possède dans la plupart des cas, un [modèle](structure-models.md) correspondant qui est utilisé pour valider ses entrées du côté serveur (lisez la section [Validation des entrées](input-validation.md) pour plus de détails sur la validation). Lors de la création de formulaires basés sur un modèle, la première étape est de définir le modèle lui-même. Le modèle peut être soit basé sur une classe d'[enregistrement actif](db-active-record.md) représentant quelques données de la base de données, soit sur une classe de modèle générique qui étend la classe [[yii\base\Model]]) pour capturer des entrées arbitraires, par exemple un formulaire de connexion. Dans l'exemple suivant, nous montrons comment utiliser un modèle générique pour un formulaire de connexion :
```php
<?php
class LoginForm extends \yii\base\Model
{
public $username;
public $password;
public function rules()
{
return [
// les règles de validation sont définies ici
];
}
}
```
Dans le contrôleur, nous passons une instance de ce modèle à la vue, dans laquelle le composant graphique [[yii\widgets\ActiveForm|ActiveForm]] est utilisé pour afficher le formulaire :
```php
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
$form = ActiveForm::begin([
'id' => 'login-form',
'options' => ['class' => 'form-horizontal'],
]) ?>
<?= $form->field($model, 'username') ?>
<?= $form->field($model, 'password')->passwordInput() ?>
<div class="form-group">
<div class="col-lg-offset-1 col-lg-11">
<?= Html::submitButton('Login', ['class' => 'btn btn-primary']) ?>
</div>
</div>
<?php ActiveForm::end() ?>
```
Dans le code précédent, [[yii\widgets\ActiveForm::begin()|ActiveForm::begin()]] ne crée pas seulement une instance de formulaire, mais il marque également le début du formulaire. Tout le contenu placé entre [[yii\widgets\ActiveForm::begin()|ActiveForm::begin()]] et [[yii\widgets\ActiveForm::end()|ActiveForm::end()]] sera enveloppé dans la balise HTML `<form>`. Comme avec tout composant graphique, vous pouvez spécifier quelques options sur la façon dont le composant graphique est configuré en passant un tableau à la méthode `begin`. Dans ce cas précis, une classe CSS supplémentaire et un identifiant sont passés pour être utilisés dans l'ouverture de balise `<form>`. Pour connaître toutes les options disponibles, reportez-vous à la documentation de l'API de [[yii\widgets\ActiveForm]].
Afin de créer un élément *form* dans le formulaire, avec l'élément *label* et toute validation JavaScript applicable, la méthode [[yii\widgets\ActiveForm::field()|ActiveForm::field()]] est appelée. Elle retourne une instance de [[yii\widgets\ActiveField]]. Lorsque le résultat de cette méthode est renvoyé en écho directement, le résultat est un champ de saisie de texte régulier. Pour personnaliser la sortie, vous pouvez enchaîner des méthodes additionnelles de [[yii\widgets\ActiveField|ActiveField]] à cet appel :
```php
// un champ de saisie du mot de passe
<?= $form->field($model, 'password')->passwordInput() ?>
// ajoute une invite et une étiquette personnalisée
<?= $form->field($model, 'username')->textInput()->hint('Please enter your name')->label('Name') ?>
// crée un élément HTML5 de saisie d'une adresse de courriel
<?= $form->field($model, 'email')->input('email') ?>
```
Cela crée toutes les balises `<label>`, `<input>` et autres, selon le [[yii\widgets\ActiveField::$template|modèle]] défini par le champ de formulaire. Le nom du champ de saisie est déterminé automatiquement à partir du [[yii\base\Model::formName()|nom de formulaire]] du modèle et du nom d'attribut. Par exemple, le nom du champ de saisie de l'attribut `username` dans l'exemple ci-dessus est `LoginForm[username]`. Cette règle de nommage aboutit à un tableau de tous les attributs du formulaire de connexion dans `$_POST['LoginForm']` côté serveur.
> Tip: si vous avez seulement un modèle dans un formulaire et que vous voulez simplifier le nom des champs de saisie, vous pouvez sauter la partie tableau en redéfinissant la méthode [[yii\base\Model::formName()|formName()]] du modèle pour qu'elle retourne une chaîne vide. Cela peut s'avérer utile pour les modèles de filtres utilisés dans le composant graphique [GridView](output-data-widgets.md#grid-view) pour créer des URL plus élégantes.
Spécifier l'attribut de modèle peut se faire de façon plus sophistiquée. Par exemple, lorsqu'un attribut peut prendre une valeur de tableau lors du chargement sur le serveur de multiples fichiers ou lors de la sélection de multiples items, vous pouvez le spécifier en ajoutant `[]` au nom d'attribut :
```php
// permet à de multiples fichiers d'être chargés sur le serveur :
echo $form->field($model, 'uploadFile[]')->fileInput(['multiple'=>'multiple']);
// permet à de multiples items d'être cochés :
echo $form->field($model, 'items[]')->checkboxList(['a' => 'Item A', 'b' => 'Item B', 'c' => 'Item C']);
```
Soyez prudent lorsque vous nommez des éléments de formulaire tels que des boutons de soumission. Selon la [documentation de jQuery](https://api.jquery.com/submit/), certains noms sont réservés car ils peuvent créer des conflits :
> Les éléments *forms* et leurs éléments enfants ne devraient par utiliser des noms de champ de saisie, ou des identifiants que entrent en conflit avec les propriétés d'un élément de *form*, tels que `submit`, `length`, ou `method`. Les conflits de noms peuvent créer des échecs troublants. Pour une liste complètes des règles et pour vérifier votre code HTML à propos de ces problèmes, reportez-vous à [DOMLint](http://kangax.github.io/domlint/).
Des balises additionnelles HTML peuvent être ajoutées au formulaire en utilisant du HTML simple ou en utilisant les méthodes de la classe [[yii\helpers\Html|Html]]-helper comme cela est fait dans l'exemple ci-dessus avec le [[yii\helpers\Html::submitButton()|bouton de soumission]].
> Tip: si vous utilisez la base structurée *Twitter Bootstrap CSS* dans votre application, vous désirez peut-être utiliser [[yii\bootstrap\ActiveForm]] à la place de [[yii\widgets\ActiveForm]]. La première étend la deuxième et utilise les styles propres à Bootstrap lors de la génération des champs de saisie du formulaire.
> Tip: afin de styler les champs requis avec une astérisque, vous pouvez utiliser le CSS suivant :
>
> ```css
> div.required label.control-label:after {
> content: " *";
> color: red;
> }
> ```
Création d'une liste déroulante <span id="creating-activeform-dropdownlist"></span>
-------------------------------
Vous pouvez utiliser la méthode [dropDownList()](http://www.yiiframework.com/doc-2.0/yii-widgets-activefield.html#dropDownList()-detail) de ActiveForm pour créer une liste déroulante :
```php
use app\models\ProductCategory;
/* @var $this yii\web\View */
/* @var $form yii\widgets\ActiveForm */
/* @var $model app\models\Product */
echo $form->field($model, 'product_category')->dropdownList(
ProductCategory::find()->select(['category_name', 'id'])->indexBy('id')->column(),
['prompt'=>'Select Category']
);
```
La valeur du champ de saisie de votre modèle est automatiquement pré-selectionnée
Travail avec Pjax <span id="working-with-pjax"></span>
-----------------------
Le composant graphique [[yii\widgets\Pjax|Pjax]] vous permet de mettre à jour une certaine section d'une page plutôt que de recharger la page entière. Vous pouvez l'utiliser pour mettre à jour seulement le formulaire et remplacer son contenu après la soumission.
Vous pouvez configurer [[yii\widgets\Pjax::$formSelector|$formSelector]] pour spécifier quelles soumissions de formulaire peuvent déclencher pjax. Si cette propriété n'est pas définie, tous les formulaires avec l'attribut `data-pjax` dans le contenu englobé par Pjax déclenchent des requêtes pjax.
```php
use yii\widgets\Pjax;
use yii\widgets\ActiveForm;
Pjax::begin([
// Pjax options
]);
$form = ActiveForm::begin([
'options' => ['data' => ['pjax' => true]],
// plus d'options d'ActiveForm
]);
// contenu de ActiveForm
ActiveForm::end();
Pjax::end();
```
> Tip: soyez prudent avec les liens à l'intérieur du composant graphique [[yii\widgets\Pjax|Pjax]] car la réponse est également rendue dans le composant graphique. Pour éviter cela, utilisez l'attribut HTML `data-pjax="0"`.
#### Valeurs dans les boutons de soumission et dans les chargement de fichiers sur le serveur
Il y a des problèmes connus avec l'utilisation de `jQuery.serializeArray()` lorsqu'on manipule des [fichiers](https://github.com/jquery/jquery/issues/2321) et des [valeurs de boutons de soumission](https://github.com/jquery/jquery/issues/2321) qui ne peuvent être résolus et sont plutôt rendus obsolète en faveur de la classe `FormData` introduite en HTML5.
Cela siginifie que la seule prise en charge officielle pour les fichiers et les valeurs de boutons de soumission avec ajax, ou en utilisant le composant graphique [[yii\widgets\Pjax|Pjax]], dépend de la [prise en charge par le navigateur](https://developer.mozilla.org/en-US/docs/Web/API/FormData#Browser_compatibility) de la classe `FormData`.
Lectures d'approfondissement <span id="further-reading"></span>
----------------------------
La section suivante, [Validation des entrées](input-validation.md) prend en charge la validation des données soumises par le formulaire du côté serveur ainsi que la validation ajax et du côté client.
Pour en apprendre plus sur les utilisations complexes de formulaires, vous pouvez lire les sections suivantes :
- [Collecte des champs de saisie tabulaires](input-tabular-input.md), pour collecter des données à destination de multiples modèles du même genre.
- [Obtention de données pour de multiples modèles](input-multiple-models.md), pour manipuler plusieurs modèles différents dans le même formulaire.
- [Chargement de fichiers sur le serveur](input-file-upload.md), sur la manière d'utiliser les formulaires pour charger des fichiers sur le serveur.

77
docs/guide-fr/input-multiple-models.md

@ -0,0 +1,77 @@
Obtenir des données pour plusieurs modèles
==========================================
Lorsque vous avez affaire à des données complexes, il est possible que vous ayez besoin d'utiliser plusieurs modèles différents pour collecter des saisies de l'utilisateur. Par exemple, en supposant que les informations de connexion de l'utilisateur sont stockées dans la table `user` tandis que les informations de son profil sont stockées dans la table `profil`, vous désirez peut-être collecter les données de l'utilisateur via un modèle `User` et un modèle `Profile`. Avec la prise en charge par Yii des modèles et des formulaires, vous pouvez résoudre ce problème d'une façon qui ne diffère qu'assez peu de celle consistant à utiliser un modèle unique.
Dans ce qui suit, nous montrons comment créer un formulaire que permet la collecte de données pour les deux modèles, `User` et `Profile`, à la fois.
Tout d'abord, l'action de contrôleur pour la collecte des données de connexion (user) et des données de profil, peut être écrite comme suit :
```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,
]);
}
}
```
Dans l'action `update`, nous commençons par charger les données des modèles, `$user` et `$profile`, à mettre à jour dans la base de données. Puis nous appelons [[yii\base\Model::load()]] pour remplir les deux modèles avec les entrées de l'utilisateur. Si tout se passe bien, nous validons les deux modèles et les sauvegardons. Autrement, nous rendons la vue `update` avec le contenu suivant :
```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') ?>
...autres champs de saisie...
<?= $form->field($profile, 'website') ?>
<?= Html::submitButton('Update', ['class' => 'btn btn-primary']) ?>
<?php ActiveForm::end() ?>
```
Comme vous le voyez, la vue `update` rend les champs de saisie de deux modèles `$user` et `$profile`.

99
docs/guide-fr/input-tabular-input.md

@ -0,0 +1,99 @@
Collecte d'entrées tabulaires
=============================
Il arrive parfois que vous ayez besoin de manipuler plusieurs modèles de même sorte dans un formulaire unique. Par exemple, de multiples réglages où chacun des réglages est stocké sous forme de paire nom-valeur et est représenté par un modèle d'[enregistrement actif](db-active-record.md) `Setting`. Cette sorte de formulaire est aussi appelé « entrées tabulaires ». Par opposition à cela, la manipulation des modèles de différente sortes, est traitée dans la section [Formulaires complexes avec plusieurs modèles](input-multiple-models.md).
Ce qui suit montre comment mettre en œuvre les entrées tabulaires avec Yii.
Il y a trois situations différentes à couvrir, qui doivent être traitées avec de légères différences :
- La mise à jour d'un jeu fixe d'enregistrement de la base de données.
- La création d'un jeu dynamique d'enregistrements.
- La mise à jour, création et suppression d'enregistrements sur une page.
Par contraste avec les formulaires de modèle unique expliqué précédemment, nous travaillons maintenant sur un tableau de modèles. Ce tableau est passé à la vue pour afficher les champs de saisie de chacun des modèles sous une forme ressemblant à un tableau. Nous allons utiliser les méthodes d'aide de [[yii\base\Model]] qui nous permettent le chargement et la validation de plusieurs modèles à la fois :
- [[yii\base\Model::loadMultiple()|Model::loadMultiple()]] charge les données d'une requête `POST` dans un tableau de modèles.
- [[yii\base\Model::validateMultiple()|Model::validateMultiple()]] valide un tableau de modèles.
### Mise à jour d'un jeu fixe d'enregistrements
Commençons par l'action du contrôleur :
```php
<?php
namespace app\controllers;
use Yii;
use yii\base\Model;
use yii\web\Controller;
use app\models\Setting;
class SettingsController extends Controller
{
// ...
public function actionUpdate()
{
$settings = Setting::find()->indexBy('id')->all();
if (Model::loadMultiple($settings, Yii::$app->request->post()) && Model::validateMultiple($settings)) {
foreach ($settings as $setting) {
$setting->save(false);
}
return $this->redirect('index');
}
return $this->render('update', ['settings' => $settings]);
}
}
```
Dans le code ci-dessus, nous utilisons [[yii\db\ActiveQuery::indexBy()|indexBy()]] lors de l'extraction de modèles depuis la base de données pour remplir un tableau indexé par les clés primaires des modèles. Celles-ci seront utilisées plus tard pour identifier les champs de formulaires. [[yii\base\Model::loadMultiple()|Model::loadMultiple()]] remplit de multiples modèles avec les données du formulaire issues de la méthode `POST` et [[yii\base\Model::validateMultiple()|Model::validateMultiple()]] valide tous les modèles en une seule fois. Comme nous avons validé auparavant, nous passons maintenant `false` en paramètre à [[yii\db\ActiveRecord::save()|save()]] pour ne pas exécuter la validation deux fois.
Maintenant, voyons le formulaire qui se trouve dans la vue `update` (mise à jour) :
```php
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
$form = ActiveForm::begin();
foreach ($settings as $index => $setting) {
echo $form->field($setting, "[$index]value")->label($setting->name);
}
ActiveForm::end();
```
Ici, pour chaque réglage, nous rendons un champ de saisie avec un nom indexé. Il est important d'ajouter un index approprié au nom d'un champ de saisie car c'est avec cela que [[yii\base\Model::loadMultiple()|Model::loadMultiple()]] détermine à quel modèle attribuer telles valeurs.
### Création d'un jeu dynamique d'enregistrements
La création d'enregistrements est similaire à leur mise à jour, sauf que nous avons a instancier les modèles :
```php
public function actionCreate()
{
$count = count(Yii::$app->request->post('Setting', []));
$settings = [new Setting()];
for($i = 1; $i < $count; $i++) {
$settings[] = new Setting();
}
// ...
}
```
Ici nous créons un tableau initial de `$settings` (réglages) contenant un modèle par défaut de façon à ce qu'au moins un champ de texte soit visible dans la vue. De plus, nous ajoutons un modèle pour chacune des lignes d'entrée que nous recevons.
Dans la vue, nous pouvons utiliser JavaScript pour ajouter de nouvelles lignes dynamiquement.
### Combinaison, mise à jour, création et suppression sur une page
> Note: Cette section est en cours de création
>
> Elle est vide pour le moment.
TBD

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

@ -0,0 +1,610 @@
Validation des entrées utilisateur
==================================
En général, vous ne devriez jamais faire confiance aux données entrées par l'utilisateur et devriez toujours les valider avant de les utiliser.,
Étant donné un [modèle](structure-models.md) rempli par les données entrées par l'utilisateur, il est possible de valider ces entrées en appelant la méthode [[yii\base\Model::validate()]]. La méthode retourne une valeur booléenne qui indique si la validation a réussi ou pas. Si ce n'est pas le cas, vous pouvez obtenir les messages d'erreur depuis la propriété [[yii\base\Model::errors]]. Par exemple :
```php
$model = new \app\models\ContactForm();
// remplit les attributs du modèle avec les entrées de l'utilisateur
$model->load(\Yii::$app->request->post());
// ce qui est équivalent à :
// $model->attributes = \Yii::$app->request->post('ContactForm');
if ($model->validate()) {
// toutes les entrées sont valides
} else {
// la validation a échoué: $errors est un tableau contenant les messages d'erreur
$errors = $model->errors;
}
```
## Déclaration de règles <span id="declaring-rules"></span>
Pour que `validate()` fonctionne réellement, vous devez déclarer des règles de validation pour les attributs que vous envisagez de valider. Cela peut être réalisé en redéfinissant la méthode [[yii\base\Model::rules()]]. L'exemple suivant montre comment les règles de validation pour le modèle `ContactForm` sont déclarées :
```php
public function rules()
{
return [
// les attributs name, email, subject et body sont à saisir obligatoirement
[['name', 'email', 'subject', 'body'], 'required'],
// l'attribut email doit être une adresse de courriel valide
['email', 'email'],
];
}
```
La méthode [[yii\base\Model::rules()|rules()]] doit retourner un tableau de règles, dont chacune est un tableau dans le format suivant :
```php
[
// obligatoire, spécifie quels attributs doivent être validés par cette règle.
// Pour un attribut unique, vous pouvez utiliser le nom de l'attribut directement
// sans le mettre dans un tableau
['attribute1', 'attribute2', ...],
// obligatoire, spécifier le type de cette règle.
// Il peut s'agir d'un nom de classe, d'un alias de validateur ou du nom d'une méthode de validation
'validator',
// facultatif, spécifie dans quel(s) scénario(s) cette règle doit être appliquée
// si absent, cela signifie que la règle s'applique à tous les scénarios
// Vous pouvez aussi configurer l'option "except" si vous voulez que la règle
// s'applique à tous les scénarios sauf à ceux qui sont listés
'on' => ['scenario1', 'scenario2', ...],
// facultatif, spécifie des configurations additionnelles pour l'objet validateur
'property1' => 'value1', 'property2' => 'value2', ...
]
```
Pour chacune des règles vous devez spécifier au moins à quels attributs la règle s'applique et quel est le type de cette règle. Vous pouvez spécifier le type de la règle sous l'une des formes suivantes :
* l'alias d'un validateur du noyau, comme `required`, `in`, `date`, etc. Reportez-vous à la sous-section [Validateurs du noyau](tutorial-core-validators.md) pour une liste complète des validateurs du noyau.
* le nom d'une méthode de validation dans la classe du modèle, ou une fonction anonyme. Reportez-vous à la sous-section [Inline Validators](#inline-validators) pour plus de détails.
* un nom de classe de validateur pleinement qualifié. Reportez-vous à la sous-section [Validateurs autonomes](#standalone-validators) pour plus de détails.
Une règle peut être utilisée pour valider un ou plusieurs attributs, et un attribut peut être validé par une ou plusieurs règles. Une règle peut s'appliquer dans certains [scenarios](structure-models.md#scenarios) seulement en spécifiant l'option `on`. Si vous ne spécifiez pas l'option `on`, la règle s'applique à tous les scénarios.
Quand la méthode `validate()` est appelée, elle suit les étapes suivantes pour effectuer l'examen de validation :
1. Détermine quels attributs doivent être validés en obtenant la liste des attributs de [[yii\base\Model::scenarios()]] en utilisant le [[yii\base\Model::scenario|scenario]] courant. Ces attributs sont appelés *attributs actifs*.
2. Détermine quelles règles de validation doivent être appliquées en obtenant la liste des règles de [[yii\base\Model::rules()]] en utilisant le [[yii\base\Model::scenario|scenario]] courant. Ces règles sont appelées *règles actives*.
3. Utilise chacune des règles actives pour valider chacun des attributs qui sont associés à cette règle. Les règles sont évaluées dans l'ordre dans lequel elles sont listées.
Selon les étapes de validation décrites ci-dessus, un attribut est validé si, et seulement si, il est un attribut actif déclaré dans `scenarios()` et est associé à une ou plusieurs règles actives déclarées dans `rules()`.
> Note: il est pratique le nommer les règles, c.-à-d.
>
> ```php
> public function rules()
> {
> return [
> // ...
> 'password' => [['password'], 'string', 'max' => 60],
> ];
> }
> ```
>
> Vous pouvez l'utiliser dans un modèle enfant :
>
> ```php
> public function rules()
> {
> $rules = parent::rules();
> unset($rules['password']);
> return $rules;
> }
### Personnalisation des messages d'erreur <span id="customizing-error-messages"></span>
La plupart des validateurs possèdent des messages d'erreurs qui sont ajoutés au modèle en cours de validation lorsque ses attributs ne passent pas la validation. Par exemple, le validateur [[yii\validators\RequiredValidator|required]] ajoute le message "Username cannot be blank." (Le nom d'utilisateur ne peut être vide.) au modèle lorsque l'attribut `username` ne passe pas la règle de validation utilisant ce validateur.
Vous pouvez personnaliser le message d'erreur d'une règle en spécifiant la propriété `message` lors de la déclaration de la règle, comme ceci :
```php
public function rules()
{
return [
['username', 'required', 'message' => 'Please choose a username.'],
];
}
```
Quelques validateurs peuvent prendre en charge des messages d'erreur additionnels pour décrire précisément les différentes causes de non validation. Par exemple, le validateur [[yii\validators\NumberValidator|number]] prend en charge[[yii\validators\NumberValidator::tooBig|tooBig (trop grand)]] et [[yii\validators\NumberValidator::tooSmall|tooSmall (trop petit)]] pour décrire la cause de non validation lorsque la valeur à valider est trop grande ou trop petite, respectivement. Vous pouvez configurer ces messages d'erreur comme vous configureriez d'autres propriétés de validateurs dans une règle de validation.
### Événement de validation <span id="validation-events"></span>
Losque la méthode [[yii\base\Model::validate()]] est appelée, elle appelle deux méthodes que vous pouvez redéfinir pour personnaliser le processus de validation :
* [[yii\base\Model::beforeValidate()]]: la mise en œuvre par défaut déclenche un événement [[yii\base\Model::EVENT_BEFORE_VALIDATE]]. Vous pouvez, soit redéfinir cette méthode, soit répondre à cet événement pour accomplir un travail de pré-traitement (p. ex. normaliser les données entrées) avant que l'examen de validation n'ait lieu. La méthode retourne une valeur booléenne indiquant si l'examen de validation doit avoir lieu ou pas.
* [[yii\base\Model::afterValidate()]]: la mise en œuvre par défaut déclenche un événement [[yii\base\Model::EVENT_AFTER_VALIDATE]]. Vous pouvez, soit redéfinir cette méthode, soit répondre à cet événement pour accomplir un travail de post-traitement après que l'examen de validation a eu lieu.
### Validation conditionnelle <span id="conditional-validation"></span>
Pour valider des attributs seulement lorsque certaines conditions sont réalisées, p. ex. la validation d'un attribut dépend de la valeur d'un autre attribut, vous pouvez utiliser la propriété [[yii\validators\Validator::when|when]] pour définir de telles conditions. Par exemple :
```php
['state', 'required', 'when' => function($model) {
return $model->country == 'USA';
}]
```
La propriété [[yii\validators\Validator::when|when]] accepte une fonction de rappel PHP avec la signature suivante :
```php
/**
* @param Model $model le modèle en cours de validation
* @param string $attribute l'attribut en cours de validation
* @return bool `true` si la règle doit être appliqué, `false` si non
*/
function ($model, $attribute)
```
Si vous avez aussi besoin de la prise en charge côté client de la validation conditionnelle, vous devez configurer la propriété [[yii\validators\Validator::whenClient|whenClient]] qui accepte une chaîne de caractères représentant une fonction JavaScript dont la valeur de retour détermine si la règles doit être appliquée ou pas. Par exemple :
```php
['state', 'required', 'when' => function ($model) {
return $model->country == 'USA';
}, 'whenClient' => "function (attribute, value) {
return $('#country').val() == 'USA';
}"]
```
### Filtrage des données <span id="data-filtering"></span>
Les entrées utilisateur nécessitent souvent d'être filtrées ou pré-traitées. Par exemple, vous désirez peut-être vous débarrasser des espaces devant et derrière l'entrée `username`. Vous pouvez utiliser les règles de validation pour le faire.
Les exemples suivants montrent comment se débarrasser des espaces dans les entrées et transformer des entrées vides en `nulls` en utilisant les validateurs du noyau [trim](tutorial-core-validators.md#trim) et [default](tutorial-core-validators.md#default) :
```php
return [
[['username', 'email'], 'trim'],
[['username', 'email'], 'default'],
];
```
Vous pouvez également utiliser le validateur plus général [filter](tutorial-core-validators.md#filter) pour accomplir un filtrage plus complexe des données.
Comme vous le voyez, ces règles de validation ne pratiquent pas un examen de validation proprement dit. Plus exactement, elles traitent les valeurs et les sauvegardent dans les attributs en cours de validation.
### Gestion des entrées vides <span id="handling-empty-inputs"></span>
Lorsque les entrées sont soumises par des formulaires HTML, vous devez souvent assigner des valeurs par défaut aux entrées si elles restent vides. Vous pouvez le faire en utilisant le validateur [default](tutorial-core-validators.md#default). Par exemple :
```php
return [
// définit "username" et "email" comme *null* si elles sont vides
[['username', 'email'], 'default'],
// définit "level" à 1 si elle est vide
['level', 'default', 'value' => 1],
];
```
Par défaut, une entrée est considérée vide si sa valeur est une chaîne de caractères vide, un tableau vide ou un `null`. Vous pouvez personnaliser la logique de détection de vide en configurant la propriété [[yii\validators\Validator::isEmpty]] avec une fonction de rappel PHP. Par exemple :
```php
['agree', 'required', 'isEmpty' => function ($value) {
return empty($value);
}]
```
> Note: la plupart des validateurs ne traitent pas les entrées vides si leur propriété [[yii\validators\Validator::skipOnEmpty]] prend la valeur par défaut `true` (vrai). Ils sont simplement sautés lors de l'examen de validation si leurs attributs associés reçoivent des entrées vides. Parmi les [validateurs de noyau](tutorial-core-validators.md), seuls les validateurs `captcha`, `default`, `filter`, `required`, et `trim` traitent les entrées vides.
## Validation ad hoc <span id="ad-hoc-validation"></span>
Parfois vous avez besoin de faire une *validation ad hoc* pour des valeurs qui ne sont pas liées à un modèle.
Si vous n'avez besoin d'effectuer qu'un seul type de validation (p. ex. valider une adresse de courriel), vous pouvez appeler la méthode [[yii\validators\Validator::validate()|validate()]] du validateur désiré, comme ceci :
```php
$email = 'test@example.com';
$validator = new yii\validators\EmailValidator();
if ($validator->validate($email, $error)) {
echo 'Email is valid.';
} else {
echo $error;
}
```
> Note: tous les validateurs ne prennent pas en charge ce type de validation. Le validateur du noyau [unique](tutorial-core-validators.md#unique), qui est conçu pour travailler avec un modèle uniquement, en est un exemple.
Si vous avez besoin de validations multiples pour plusieurs valeurs, vous pouvez utiliser [[yii\base\DynamicModel]] qui prend en charge, à la fois les attributs et les règles à la volée. Son utilisation ressemble à ce qui suit :
```php
public function actionSearch($name, $email)
{
$model = DynamicModel::validateData(compact('name', 'email'), [
[['name', 'email'], 'string', 'max' => 128],
['email', 'email'],
]);
if ($model->hasErrors()) {
// validation fails
} else {
// validation succeeds
}
}
```
La méthode [[yii\base\DynamicModel::validateData()]] crée une instance de `DynamicModel`, définit les attributs utilisant les données fournies (`name` et `email` dans cet exemple), puis appelle [[yii\base\Model::validate()]] avec les règles données.
En alternative, vous pouvez utiliser la syntaxe plus *classique* suivante pour effectuer la validation 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()) {
// la validation a échoué
} else {
// la validation a réussi
}
}
```
Après l'examen de validation, vous pouvez vérifier si la validation a réussi ou pas en appelant la méthode [[yii\base\DynamicModel::hasErrors()|hasErrors()]] et obtenir les erreurs de validation de la propriété [[yii\base\DynamicModel::errors|errors]], comme vous le feriez avec un modèle normal. Vous pouvez aussi accéder aux attributs dynamiques définis via l'instance de modèle, p. ex. `$model->name` et `$model->email`.
## Création de validateurs <span id="creating-validators"></span>
En plus de pouvoir utiliser les [validateurs du noyau](tutorial-core-validators.md) inclus dans les versions publiées de Yii, vous pouvez également créer vos propres validateurs. Vous pouvez créer des validateurs en ligne et des validateurs autonomes.
### Validateurs en ligne <span id="inline-validators"></span>
Un validateur en ligne est un validateur défini sous forme de méthode de modèle ou de fonction anonyme. La signature de la méthode/fonction est :
```php
/**
* @param string $attribute l'attribut en cours de validation
* @param mixed $params la valeur des *paramètres* donnés dans la règle
*/
function ($attribute, $params)
```
Si un attribut ne réussit pas l'examen de validation, la méthode/fonction doit appeler [[yii\base\Model::addError()]] pour sauvegarder le message d'erreur dans le modèle de manière à ce qu'il puisse être retrouvé plus tard pour être présenté à l'utilisateur.
Voici quelques exemples :
```php
use yii\base\Model;
class MyForm extends Model
{
public $country;
public $token;
public function rules()
{
return [
// un validateur en ligne défini sous forme de méthode de modèle validateCountry()
['country', 'validateCountry'],
// un validateur en ligne défini sous forme de fonction anonyme
['token', function ($attribute, $params) {
if (!ctype_alnum($this->$attribute)) {
$this->addError($attribute, 'The token must contain letters or digits.');
}
}],
];
}
public function validateCountry($attribute, $params)
{
if (!in_array($this->$attribute, ['USA', 'Web'])) {
$this->addError($attribute, 'The country must be either "USA" or "Web".');
}
}
}
```
> Note: Par défaut, les validateurs en ligne ne sont pas appliqués si leurs attributs associés reçoivent des entrées vides ou s'ils ont déjà échoué à des examen de validation selon certaines règles. Si vous voulez être sûr qu'une règle sera toujours appliquée, vous devez configurer les propriétés [[yii\validators\Validator::skipOnEmpty|skipOnEmpty]] et/ou [[yii\validators\Validator::skipOnError|skipOnError]] à `false` (faux) dans les déclarations des règles. Par exemple :
>
> ```php
> [
> ['country', 'validateCountry', 'skipOnEmpty' => false, 'skipOnError' => false],
> ]
> ```
### Validateurs autonomes <span id="standalone-validators"></span>
Un validateur autonome est une classe qui étend la classe [[yii\validators\Validator]] ou une de ses classe filles. Vous pouvez mettre en œuvre sa logique de validation en redéfinissant la méthode [[yii\validators\Validator::validateAttribute()]]. Si un attribut ne réussit pas l'exament de validation, appellez [[yii\base\Model::addError()]] pour sauvegarder le message d'erreur dans le modèle, comme vous le feriez avec des [validateurs en ligne](#inline-validators).
Par exemple, le validateur en ligne ci-dessus peut être transformé en une nouvelle classe [[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, 'The country must be either "USA" or "Web".');
}
}
}
```
Si vous voulez que votre validateur prennent en charge la validation d'une valeur sans modèle, vous devez redéfinir la méthode [[yii\validators\Validator::validate()]]. Vous pouvez aussi redéfinir [[yii\validators\Validator::validateValue()]] au lieu de `validateAttribute()` et `validate()`, parce que, par défaut, les deux dernières méthodes sont appelées en appelant `validateValue()`.
Ci-dessous, nous présentons un exemple de comment utiliser la classe de validateur précédente dans votre modèle.
```php
namespace app\models;
use Yii;
use yii\base\Model;
use app\components\validators\CountryValidator;
class EntryForm extends Model
{
public $name;
public $email;
public $country;
public function rules()
{
return [
[['name', 'email'], 'required'],
['country', CountryValidator::className()],
['email', 'email'],
];
}
}
```
## Validation côté client <span id="client-side-validation"></span>
La validation côté client basée sur JavaScript est souhaitable lorsque l'utilisateur fournit les entrées via des formulaires HTML, parce que cela permet à l'utilisateur de détecter plus vite les erreurs et lui apporte ainsi un meilleur ressenti. Vous pouvez utiliser ou implémenter un validateur qui prend en charge la validation côté client *en plus* de la validation côté serveur.
> Info: bien que la validation côté client soit souhaitable, ce n'est pas une obligation. Son but principal est d'apporter un meilleur ressenti à l'utilisateur. Comme pour les données venant de l'utilisateur, vous ne devriez jamais faire confiance à la validation côté client. Pour cette raison, vous devez toujours effectuer la validation côté serveur en appelant [[yii\base\Model::validate()]], comme nous l'avons décrit dans les sous-sections précédentes.
### Utilisation de la validation côté client <span id="using-client-side-validation"></span>
Beaucoup de [validateurs du noyau](tutorial-core-validators.md) prennent en charge la validation côté client directement. Tout ce que vous avez à faire c'est utiliser [[yii\widgets\ActiveForm]] pour construire vos formulaires HTML. Par exemple, `LoginForm` ci-dessous déclare deux règles : l'une utilise le validateur du noyau [required](tutorial-core-validators.md#required) qui est pris en charge à la fois côté serveur et côté client; l'autre utilise le validateur en ligne `validatePassword` qui ne prend pas en charge la validation côté client.
```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 et password sont tous deux obligatoires
[['username', 'password'], 'required'],
// password est validé par validatePassword()
['password', 'validatePassword'],
];
}
public function validatePassword()
{
$user = User::findByUsername($this->username);
if (!$user || !$user->validatePassword($this->password)) {
$this->addError('password', 'Incorrect username or password.');
}
}
}
```
Le formulaire HTML construit par le code suivant contient deux champs de saisie `username` et `password`. Si vous soumettez le formulaire sans rien saisir, vous recevrez directement les messages d'erreur vous demandant d'entrer quelque chose sans qu'aucune communication avec le serveur n'ait lieu.
```php
<?php $form = yii\widgets\ActiveForm::begin(); ?>
<?= $form->field($model, 'username') ?>
<?= $form->field($model, 'password')->passwordInput() ?>
<?= Html::submitButton('Login') ?>
<?php yii\widgets\ActiveForm::end(); ?>
```
En arrière plan, [[yii\widgets\ActiveForm]] lit les règles de validation déclarées dans le modèle et génère le code JavaScript approprié pour la prise en charge de la validation côté client. Lorsqu'un utilisateur modifie la valeur d'un champ de saisie ou soumet le formulaire, le code JavaScript est appelé.
Si vous désirez inhiber la validation côté client complètement, vous pouvez configurer la propriété [[yii\widgets\ActiveForm::enableClientValidation]] à `false` (faux). Vous pouvez aussi inhiber la validation côté client pour des champs de saisie individuels en configurant leur propriété [[yii\widgets\ActiveField::enableClientValidation]] à `false`. Lorsque `enableClientValidation` est configurée à la fois au niveau du champ et au niveau du formulaire, c'est la première configuration qui prévaut.
### Mise en œuvre de la validation côté client <span id="implementing-client-side-validation"></span>
Pour créer un validateur qui prend en charge la validation côté client, vous devez implémenter la méthode [[yii\validators\Validator::clientValidateAttribute()]] qui retourne un morceau de code JavaScript propre à effectuer l'examen de validation côté client. Dans ce code JavaScript, vous pouvez utiliser les variables prédéfinies suivantes :
- `attribute`: le nom de l'attribut en cours de validation ;
- `value`: la valeur en cours de validation;
- `messages`: un tableau utilisé pour contenir les messages d'erreurs pour l'attribut;
- `deferred`: un tableau dans lequel les objets différés peuvent être poussés (explication dans la prochaine sous-section).
Dans l'exemple suivant, nous créons un `StatusValidator` qui valide une entrée si elle représente l'identifiant d'une donnée existante ayant un état valide. Le validateur prend en charge à la fois la validation côté serveur et la validation côté client.
```php
namespace app\components;
use yii\validators\Validator;
use app\models\Status;
class StatusValidator extends Validator
{
public function init()
{
parent::init();
$this->message = 'Invalid status input.';
}
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: le code ci-dessus est donné essentiellement pour démontrer comment prendre en charge la validation côté client. En pratique, vous pouvez utiliser le validateur du noyau [in](tutorial-core-validators.md#in) pour arriver au même résultat. Vous pouvez écrire la règle de validation comme suit :
>
> ```php
> [
> ['status', 'in', 'range' => Status::find()->select('id')->asArray()->column()],
> ]
> ```
> Tip: si vous avez besoin de travailler à la main avec la validation côté client, c.-à-d. ajouter des champs dynamiquement ou effectuer quelque logique d'interface utilisateur, reportez-vous à [Travail avec ActiveForm via JavaScript](https://github.com/samdark/yii2-cookbook/blob/master/book/forms-activeform-js.md) dans le *Cookbook* de Yii 2.0 .
### Validation différée <span id="deferred-validation"></span>
Si vous devez effectuer une validation asynchrone côté client, vous pouvez créer des [objets différés](http://api.jquery.com/category/deferred-object/). Par exemple, pour effectuer une validation AJAX personnalisée, vous pouvez utiliser le code suivant :
```php
public function clientValidateAttribute($model, $attribute, $view)
{
return <<<JS
deferred.push($.get("/check", {value: value}).done(function(data) {
if ('' !== data) {
messages.push(data);
}
}));
JS;
}
```
Dans ce qui précède, la variable `deferred` est fournie par Yii, et représente un tableau de d'objets différés. La méthode `$.get()` crée un objet différé qui est poussé dans le tableau `deferred`.
Vous pouvez aussi créer explicitement un objet différé et appeler sa méthode `resolve()` lorsque la fonction de rappel asynchrone est activée . L'exemple suivant montre comment valider les dimensions d'une image à charger sur le serveur du côté client.
```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('Image too wide!!');
}
def.resolve();
}
var reader = new FileReader();
reader.onloadend = function() {
img.src = reader.result;
}
reader.readAsDataURL(file);
deferred.push(def);
JS;
}
```
> Note: La méthode `resolve()` doit être appelée après que l'attribut a été validé. Autrement la validation principale du formulaire ne se terminera pas.
Pour faire simple, le tableau `deferred` est doté d'une méthode raccourci `add()` qui crée automatiquement un objet différé et l'ajoute au tableau `deferred`. En utilisant cette méthode, vous pouvez simplifier l'exemple ci-dessus comme suit :
```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('Image too wide!!');
}
def.resolve();
}
var reader = new FileReader();
reader.onloadend = function() {
img.src = reader.result;
}
reader.readAsDataURL(file);
});
JS;
}
```
### Validation AJAX <span id="ajax-validation"></span>
Quelques validations ne peuvent avoir lieu que côté serveur, parce que seul le serveur dispose des informations nécessaires. Par exemple, pour valider l'unicité d'un nom d'utilisateur, il est nécessaire de consulter la table des utilisateurs côté serveur. Vous pouvez utiliser la validation basée sur AJAX dans ce cas. Elle provoquera une requête AJAX en arrière plan pour exécuter l'examen de validation tout en laissant à l'utilisateur le même ressenti que lors d'une validation côté client normale.
Pour activer la validation AJAX pour un unique champ de saisie, configurez la propriété [[yii\widgets\ActiveField::enableAjaxValidation|enableAjaxValidation]] de ce champ à `true` et spécifiez un `identifiant` unique de formulaire :
```php
use yii\widgets\ActiveForm;
$form = ActiveForm::begin([
'id' => 'registration-form',
]);
echo $form->field($model, 'username', ['enableAjaxValidation' => true]);
// ...
ActiveForm::end();
```
Pour étendre la validation AJAX à tout le formulaire, configurez la propriété [[yii\widgets\ActiveForm::enableAjaxValidation|enableAjaxValidation]] à `true` au niveau du formulaire :
```php
$form = ActiveForm::begin([
'id' => 'contact-form',
'enableAjaxValidation' => true,
]);
```
> Note: lorsque la propriété `enableAjaxValidation` est configurée à la fois au niveau du champ et au niveau du formulaire, la première configuration prévaut.
Vous devez aussi préparer le serveur de façon à ce qu'il puisse prendre en charge les requêtes de validation AJAX . Cela peut se faire à l'aide d'un fragment de code comme celui qui suit dans les actions de contrôleur :
```php
if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
Yii::$app->response->format = Response::FORMAT_JSON;
return ActiveForm::validate($model);
}
```
Le code ci-dessus vérifie si la requête courante est une requête AJAX. Si oui, il répond à la requête en exécutant l'examen de validation et en retournant les erreurs au format JSON.
> Info: vous pouvez aussi utiliser la [validation différée](#deferred-validation) pour effectuer une validation AJAX. Néanmoins, la fonctionnalité de validation AJAX décrite ici est plus systématique et nécessite moins de codage.
Quand, à la fois `enableClientValidation` et `enableAjaxValidation` sont définies à `true`, la requête de validation AJAX est déclenchée seulement après une validation réussie côté client.

169
docs/guide-fr/intro-upgrade-from-v1.md

@ -5,8 +5,8 @@ Il y a beaucoup de différences entre les versions 1.1 et 2.0 de Yii, le framewo
la 2.0. En conséquence, la mise à jour depuis la version 1.1 n'est pas aussi triviale que la mise à jour entre deux
versions mineures. Dans ce guide, vous trouverez les principales différences entre les deux versions.
Si vous n'avez pas utilisé Yii 1.1 avant, vous pouvez ignorer cette section et passer directement à la partie
"[Mise en route] (start-installation.md)".
Si vous n'avez pas utilisé Yii 1.1 avant, vous pouvez ignorer cette section et passer directement à la section
"[Mise en route](start-installation.md)".
Merci de noter que Yii 2.0 introduit plus de nouvelles fonctionnalités que celles abordées ici. Il est fortement
recommandé de lire tout le guide de référence pour en apprendre davantage. Il y a des chances que certaines
@ -16,11 +16,11 @@ fonctionnalités, que vous aviez préalablement développées pour vous, fassent
Installation
------------
Yii 2.0 exploite pleinement [Composer] (https://getcomposer.org/), le gestionnaire de paquet PHP. L'installation
du framework, ainsi que des extensions, sont gérées par Composer. Merci de lire la partie
Yii 2.0 exploite pleinement [Composer](https://getcomposer.org/), le gestionnaire de paquet PHP. L'installation
du framework, ainsi que des extensions, sont gérées par Composer. Reportez-vous à la section
[Installer Yii](start-installation.md) pour apprendre comment installer Yii 2.0. Si vous voulez
créer de nouvelles extensions, ou rendre vos extensions existantes 1.1 compatibles 2.0, merci de lire
la partie [Créer des extensions](extend-creating-extensions.md) de ce guide.
créer de nouvelles extensions, ou rendre vos extensions existantes 1.1 compatibles 2.0, reportez-vous à
la section [Créer des extensions](extend-creating-extensions.md) de ce guide.
Pré-requis PHP
@ -28,7 +28,7 @@ Pré-requis PHP
Yii 2.0 requiert PHP 5.4 ou plus, ce qui est une grosse amélioration par rapport à PHP 5.2 qui était requis pour Yii 1.1.
Par conséquent, il y a beaucoup de différences au niveau du langage pour lesquelles vous devriez prêter attention.
Par conséquent, il y a beaucoup de différences au niveau du langage auxquelles vous devriez prêter attention.
Voici un résumé des principaux changements concernant PHP:
- [Espaces de noms](http://php.net/manual/fr/language.namespaces.php).
@ -43,7 +43,7 @@ Voici un résumé des principaux changements concernant PHP:
d'internationalisation.
Espaces de Noms
Espaces de noms
---------------
Le changement le plus évident dans Yii 2.0 est l'utilisation des espaces de noms. La majorité des classes du noyau
@ -61,27 +61,27 @@ Composants et objets
Yii 2.0 décompose la classe `CComponent` 1.1 en deux classes: [[yii\base\Object]] et [[yii\base\Component]].
Le classe [[yii\base\Object|Object]] est une classe de base légère qui permet de définir les
[Propriétés de l'objet](concept-properties.md) via des accesseurs. La classe [[yii\base\Component|Component]] est une
sous classe de [[yii\base\Object|Object]] et supporte les [Evénements] (concept events.md) et les
sous classe de [[yii\base\Object|Object]] et prend en charge les [Evénements](concept events.md) et les
[Comportements](concept-behaviors.md).
Si votre classe n'a pas besoin des événements et des comportements, vous devriez envisager d'utiliser
[[yii\base\Object|Object]] comme classe de base. C'est généralement le cas pour les classes qui représentent
une structures de données basique.
une structure de données basique.
Configuration d'Objet
Configuration d'objets
---------------------
La classe [[yii\base\Object|Object]] introduit une manière uniforme pour configurer les objets. Toute sous classe
La classe [[yii\base\Object|Object]] introduit une manière uniforme de configurer les objets. Toute sous-classe
de [[yii\base\Object|Object]] doit déclarer son constructeur (si besoin) de la manière suivante afin qu'elle
puisse être configurée correctement:
puisse être configurée correctement :
```php
class MyClass extends \yii\base\Object
{
public function __construct($param1, $param2, $config = [])
{
// ... initialisation avant que la configuration soit appliquée
// ... initialisation avant que la configuration ne soit appliquée
parent::__construct($config);
}
@ -90,7 +90,7 @@ class MyClass extends \yii\base\Object
{
parent::init();
// ... initialisation après que la configuration soit appliquée
// ... initialisation après que la configuration est appliquée
}
}
```
@ -98,7 +98,7 @@ class MyClass extends \yii\base\Object
Dans ce qui précède, le dernier paramètre du constructeur doit être un tableau de configuration
qui contient des entrées nom-valeur pour initialiser les propriétés à la fin du constructeur.
Vous pouvez remplacer la méthode [[yii\base\Object::init()|init()]] pour le travail d'initialisation qui doit être fait
après que la configuration ait été appliquée.
après que la configuration a été appliquée.
En suivant cette convention, vous serez en mesure de créer et de configurer de nouveaux objets en utilisant un tableau
de configuration :
@ -111,11 +111,11 @@ $object = Yii::createObject([
], [$param1, $param2]);
```
Plus de détails sur les configurations peuvent être trouvés dans la partie
[Configurations d'objet](concept-configurations.md).
Plus de détails sur les configurations peuvent être trouvés dans la section
[Configurations](concept-configurations.md).
Evénements
Événements
----------
Avec Yii 1, les événements étaient créés par la définition d'une méthode `on` (par exemple `onBeforeSave`). Avec Yii 2,
@ -134,7 +134,7 @@ $component->on($eventName, $handler);
// Pour détacher le gestionnaire, utilisez :
// $component->off($eventName, $handler);
```
Il y a de nombreuses améliorations dans la gestion des événements. Pour plus de détails, merci de lire la partie [Evénements](concept-events.md).
Il y a de nombreuses améliorations dans la gestion des événements. Pour plus de détails, reportez-vous à la section [Evénements](concept-events.md).
Alias
@ -146,34 +146,34 @@ Par exemple, l'alias `@yii` fait référence au répertoire d'installation de Yi
supportés dans la plupart du code de Yii. Par exemple, [[yii\caching\FileCache::cachePath]] peut prendre
à la fois un alias et un chemin de répertoire normal.
Un alias est aussi étroitement liée aux espaces de noms des classes. Il est recommandé de définir
un alias pour chaque espace de nom racine, ce qui vous permet d'utiliser le chargeur automatique de classe de Yii sans
Un alias est aussi étroitement lié aux espaces de noms des classes. Il est recommandé de définir
un alias pour chaque espace de noms racine, ce qui vous permet d'utiliser le chargeur automatique de classe de Yii sans
sans devoir en faire d'avantage. Par exemple, vu que `@yii` fait référence au dossier d'installation de Yii,
une classe comme `yii\web\Request` peut être chargée automatiquement. Si vous utilisez une librairie tierce,
telle que Zend Framework, vous pouvez définir un alias de chemin `@Zend` qui fera référence au dossier
d'installation de Zend Framework. Une fois que vous avez fait cela, Yii sera aussi en mesure de charger automatiquement une classe de ce framework.
Pour en savoir plus, consultez la partie [Alias](concept-aliases.md).
Pour en savoir plus, consultez la section [Alias](concept-aliases.md).
Vues
----
Le changement le plus significatif à propos des vues dans Yii 2 est que la variable spéciale `$this` dans une vue ne fait plus référence au
contrôleur ou widget. Au lieu de cela, `$this` correspond maintenant à un objet *vue*, un nouveau concept
contrôleur ou à l'objet graphique. Au lieu de cela, `$this` correspond maintenant à un objet *vue*, un nouveau concept
introduit dans la version 2.0. L'objet *vue* est de type [[yii\web\View]], et représente la partie vue
du modèle MVC. Si vous souhaitez accéder au contrôleur ou widget dans une vue, vous pouvez utiliser `$this->context`.
du modèle MVC. Si vous souhaitez accéder au contrôleur ou à l'objet graphique dans une vue, vous pouvez utiliser `$this->context`.
Pour afficher une vue depuis une autre vue, utilisez `$this->render()`, et non `$this->renderPartial()`. Le résultat retourné par la méthode `render()` doit être explictement envoyé à la sortie, en effet `render()` retournera la vue au lieu de l'afficher. Par exemple :
Pour afficher une vue depuis une autre vue, utilisez `$this->render()`, et non `$this->renderPartial()`. Le résultat retourné par la méthode `render()` doit être explicitement envoyé à la sortie, en effet `render()` retournera la vue au lieu de l'afficher. Par exemple :
```php
echo $this->render('_item', ['item' => $item]);
```
Outre l'utilisation de PHP comme langage principal de gabarit, Yii 2.0 supporte également
deux moteurs de gabarit populaires : Smarty et Twig. Le moteur de gabarit Prado n'est plus supporté.
Outre l'utilisation de PHP comme langage principal de gabarit, Yii 2.0 prend également en charge
deux moteurs de gabarit populaires : Smarty et Twig. Le moteur de gabarit Prado n'est plus pris en charge.
Pour utiliser ces moteurs de gabarit, vous devez configurer le composant `view` de l'application en définissant la propriété
[[yii\base\View::$renderers|View::$renderers]]. Merci de lire la partie [Moteur de gabarit](tutorial-template-engines.md) pour en savoir plus.
[[yii\base\View::$renderers|View::$renderers]]. Reportez-vous à la section [Moteur de gabarit](tutorial-template-engines.md) pour en savoir plus.
Modèles
@ -183,7 +183,7 @@ Yii 2.0 utilise la classe [[yii\base\Model]] comme modèle de base, similaire à
La classe `CFormModel` a été supprimée. Vous pouvez, à la place, étendre la classe [[yii\base\Model]] afin de créer une classe modèle pour un formulaire.
Yii 2.0 introduit une nouvelle méthode appelée [[yii\base\Model::scenarios()|scenarios()]] pour déclarer
les scénarios pris en charge, et indiquer dans quel scénario un attribut doit être validé, peut être considéré comme sûr ou non, etc. Par exemple:
les scénarios pris en charge, indiquer dans quel scénario un attribut doit être validé et si cet attribut peut être considéré comme sûr ou non, etc. Par exemple:
```php
public function scenarios()
@ -196,21 +196,21 @@ public function scenarios()
```
Dans ce qui précède, deux scénarios sont déclarés: `backend` et `frontend`. Pour le scénario `backend` les
propriétés `email` et `role` sont sûres et peuvent être affectées massivement. Pour le scénario `frontend`,
`email` peut être affectée massivement tandis que `role` ne peut pas. `email` et `rôle` doivent être validées en utilisant des règles.
attribut `email` et `role` sont sûrs et peuvent être affectés massivement. Pour le scénario `frontend`,
`email` peut être affecté massivement tandis que `role` ne le peut pas. `email` et `rôle` doivent être validées en utilisant des règles.
La méthode [[yii\base\Model::rules()|rules()]] est toujours utilisée pour déclarer les règles de validation. Remarque : suite à l'introduction de la méthode [[yii\base\Model::scenarios()|scenarios()]], le validateur `unsafe` n'as plus de raison d'être.
Dans la plupart des cas, vous n'avez pas besoin de surcharger la méthode [[yii\base\Model::scenarios()|scenarios()]]
lorsque les scénarios existants sont déclarés via la méthode [[yii\base\Model::rules()|rules()]], et il n'y a pas besoin de déclarer de propriétés `unsafe`.
Pour en savoir plus sur les modèles, merci de lire la partie [Modèles](structure-models.md).
Pour en savoir plus sur les modèles, reportez-vous à la section [Modèles](structure-models.md).
Contrôleurs
-----------
Yii 2.0 utilise la classe [[yii\web\Controller]] comme classe de base des contrôleurs, similaire à la classe `CWebController` dans la version Yii 1.1.
Yii 2.0 utilise la classe [[yii\web\Controller]] comme classe de base des contrôleurs, similaire à la classe `CController` dans la version Yii 1.1.
[[yii\base\Action]] est la classe de base pour les actions.
L'impact le plus évident de ces changements sur votre code est qu'une action de contrôleur doit retourner le contenu
@ -228,15 +228,15 @@ public function actionView($id)
}
```
Merci de lire la partie [Contrôleurs](structure-controllers.md) pour plus de détails.
Reportez-vous à la section [Contrôleurs](structure-controllers.md) pour plus de détails.
Widgets
-------
Objets graphiques
-----------------
Yii 2.0 utilise la classe [[yii\base\Widget]] comme classe de base pour les widgets, similaire à la classe `CWidget` de Yii 1.1.
Yii 2.0 utilise la classe [[yii\base\Widget]] comme classe de base pour les objets graphiques, similaire à la classe `CWidget` de Yii 1.1.
Pour avoir un meilleur support du framework dans les EDI, Yii2 introduit une nouvelle syntaxe pour utiliser les widgets. Les methodes statiques
Pour avoir une meilleure prise en charge du framework dans les EDI, Yii 2 introduit une nouvelle syntaxe pour utiliser les objets graphiques. Les méthodes statiques
[[yii\base\Widget::begin()|begin()]], [[yii\base\Widget::end()|end()]], et [[yii\base\Widget::widget()|widget()]]
ont été créées et sont utilisables comme suit :
@ -256,22 +256,22 @@ $form = ActiveForm::begin([
ActiveForm::end();
```
Merci de lire la partie [Widgets](structure-widgets.md) pour en savoir plus.
Reportez-vous à la section [Objets graphiques](structure-widgets.md) pour en savoir plus.
Thèmes
------
Les thèmes fonctionnent tout à fait différemment dans la version 2.0. Ils sont maintenant basés sur un mécanisme de mappage de chemin qui mappe un chemin
de fichier de vue à un chemin de fichier de vue thématisée. Par exemple, si le mappage pour un thème est
Les thèmes fonctionnent tout à fait différemment dans la version 2.0. Ils sont maintenant basés sur un mécanisme de mise en correspondance de chemin qui met un chemin
de fichier de vue en correspondance avec un chemin de fichier de vue thématisée. Par exemple, si la mise en correspondance pour un thème est
`['/web/views' => '/web/themes/basic']`, alors la version thématisée du fichier de vue
`/web/views/site/index.php` sera `/web/themes/basic/site/index.php`. Pour cette raison, les thèmes peuvent maintenant
être appliqués à n'importe quel fichier de vue, même une vue utilisée en dehors du contexte d'un contrôleur ou d'un widget.
être appliqués à n'importe quel fichier de vue, même une vue utilisée en dehors du contexte d'un contrôleur ou d'un objet graphique.
En outre, il n'y a plus de composant `CThemeManager`. A la place, `theme` est une propriété configurable du composant `view`
de l'application.
Merci de lire la partie [Thématisation](tutorial-theming.md) pour plus de détails.
Reportez-vous à la section [Thématisation](tutorial-theming.md) pour plus de détails.
Applications en ligne de commande
@ -287,26 +287,26 @@ les options déclarées dans la méthode [[yii\console\Controller::options()]].
Yii 2.0 prend en charge la génération automatique d'aide à partir des blocs de commentaire.
Merci de lire la partie [Commandes console](tutorial-console.md) pour plus de détails.
Reportez-vous à la section [Commandes console](tutorial-console.md) pour plus de détails.
I18N
----
Yii 2.0 supprime les fonctionnalités internes de formattage de dates et nombres, en faveur du [module PHP PECL intl] (http://pecl.php.net/package/intl).
Yii 2.0 supprime les fonctionnalités internes de formatage des dates et des nombres, en faveur du [module PHP PECL intl](http://pecl.php.net/package/intl).
La traduction de message est désormais effectuée via le composant d'application `i18n`.
La traduction des messages est désormais effectuée via le composant d'application `i18n`.
Ce composant gère un ensemble de sources de messages, ce qui vous permet d'utiliser différentes
sources de messages en fonction de catégories.
Merci de lire la partie [Internationalisation](tutorial-i18n.md) pour plus de détails.
Reportez-vous à la section [Internationalisation](tutorial-i18n.md) pour plus de détails.
Filtres d'action
----------------
Les filtres d'action sont maintenant implémentés comme des comportements. Pour définir un nouveau filtre personnalisé, étendez la classe [[yii\base\ActionFilter]]. Pour utiliser un filtre, déclarez le
comme un comportement du contrôleur. Par exemple, pour utilser le filtre [[yii\filters\AccessControl]], vous aurez le code suivant dans le contrôleur :
comme un comportement du contrôleur. Par exemple, pour utiliser le filtre [[yii\filters\AccessControl]], vous aurez le code suivant dans le contrôleur :
```php
public function behaviors()
@ -322,26 +322,26 @@ public function behaviors()
}
```
Merci de lire la partie [Filtres](structure-filters.md) pour plus de détails.
Reportez-vous à la section [Filtres](structure-filters.md) pour plus de détails.
Ressources
----------
Yii 2.0 introduit un nouveau concept de packet de ressources (*asset bundle*) qui remplace le concept de gestionnaire de ressources (*asset manager*) de la version 1.1.
Yii 2.0 introduit un nouveau concept de paquet de ressources (*asset bundle*) qui remplace le concept de gestionnaire de ressources (*asset manager*) de la version 1.1.
Un packet de ressources est une collection de fichiers (par exemple : fichier JavaScript, CSS, image, etc.)
Un paquet de ressources est une collection de fichiers (par exemple : fichier JavaScript, CSS, image, etc.)
dans un dossier. Chaque paquet est représenté par une classe étendant [[yii\web\AssetBundle]].
En *enregistrant* un packet via [[yii\web\AssetBundle::register()]], vous rendez les ressources du packet accessibles via le Web. Contrairement à Yii 1.1, la page *enregistrant* le paquet
En *enregistrant* un paquet de ressources via [[yii\web\AssetBundle::register()]], vous rendez les ressources du paquet accessibles via le Web. Contrairement à Yii 1.1, la page *enregistrant* le paquet
contiendra automatiquement les références vers les fichiers déclarés dans le paquet.
Merci de lire la partie [Assets](structure-assets.md) pour plus de détails.
Reportez-vous à la section [Assets](structure-assets.md) pour plus de détails.
Assistants
----------
Yii 2.0 introduit de nombreuses assistants couramment utilisés, sous la forme de classes statiques, y compris :
Yii 2.0 introduit de nombreux assistants couramment utilisés, sous la forme de classes statiques, y compris :
* [[yii\helpers\Html]]
* [[yii\helpers\ArrayHelper]]
@ -349,7 +349,7 @@ Yii 2.0 introduit de nombreuses assistants couramment utilisés, sous la forme d
* [[yii\helpers\FileHelper]]
* [[yii\helpers\Json]]
Merci de lire la partie [Assistants](helper-overview.md) pour plus de détails.
Reportez-vous à la section [Assistants](helper-overview.md) pour plus de détails.
Formulaires
@ -370,10 +370,10 @@ En utilisant des champs, vous pouvez construire un formulaire plus proprement qu
<?php yii\widgets\ActiveForm::end(); ?>
```
Merci de lire la partie [Créer des formulaires](input-forms.md) pour plus de détails.
Reportez-vous à la section [Créer des formulaires](input-forms.md) pour plus de détails.
Constructeur de requête
Constructeur de requêtes
-----------------------
Dans la version 1.1, la construction des requêtes était dispersée dans plusieurs classes, y compris `CDbCommand`,
@ -394,7 +394,7 @@ $rows = $command->queryAll();
De plus, ces méthodes de construction de requête peuvent également être utilisées lorsque vous travaillez avec [Active Record](db-active-record.md).
Merci de lire la partie [Constructeur de requête](db-query-builder.md) pour plus de détails.
Reportez-vous à la section [Constructeur de requête](db-query-builder.md) pour plus de détails.
Active Record
@ -443,14 +443,14 @@ primaires des enregistrements principaux.
Au lieu de retourner des objets [[yii\db\ActiveRecord|ActiveRecord]], vous pouvez utiliser la méthode
[[yii\db\ActiveQuery::asArray()|asArray()]] lors de la construction d'une requête pour renvoyer un grand nombre
d'enregistrements. Ainsi le résultat retourné sera sous forme de tableaux, ce qui peut réduire considérablement le temps de calcul nécessaire et la mémoire dans le cas d'un grand nombre d'enregistrements. Par exemple:
d'enregistrements. Ainsi le résultat sera retourné sous forme de tableaux, ce qui peut réduire considérablement le temps de calcul et la mémoire nécessaires dans le cas d'un grand nombre d'enregistrements. Par exemple:
```php
$customers = Customer::find()->asArray()->all();
```
Un autre changement est que vous ne pouvez plus définir les valeurs par défaut des attributs en utilisant des propriétés
publiques. Si vous avez besoin, vous devez utiliser la méthode `init` de la classe de votre modèle.
Un autre changement fait que vous ne pouvez plus définir les valeurs par défaut des attributs en utilisant des propriétés
publiques. Si vous en avez besoin, vous devez utiliser la méthode `init` de la classe de votre modèle.
```php
public function init()
@ -465,25 +465,52 @@ la version 2.0. Notez que lorsque vous ajoutez des paramètres au constructeur,
la méthode [[yii\db\ActiveRecord::instantiate()]].
Il y a beaucoup d'autres modifications et améliorations à Active Record.
Merci de lire la partie [Active Record](db-active-record.md) pour en savoir plus.
Reportez-vous à la section [Active Record](db-active-record.md) pour en savoir plus.
Comportement des Enregistrements actifs)
---------------------------------------------------------
Dans la version 2.0, nous avons la classe de base des *behaviors* (comportements) `CActiveRecordBehavior`. Si vous voulez créer une classe de comportement d'enregistrement actif (Active Record), vous devez étendre directement la classe `yii\base\Behavior`. Si la classe de comportement doit réagir à certains événements du propriétaire, vous devez redéfinir les méthodes `events()` comme suit :
```php
namespace app\components;
use yii\db\ActiveRecord;
use yii\base\Behavior;
class MyBehavior extends Behavior
{
// ...
public function events()
{
return [
ActiveRecord::EVENT_BEFORE_VALIDATE => 'beforeValidate',
];
}
public function beforeValidate($event)
{
// ...
}
}
```
User et IdentityInterface
-------------------------
La classe `CWebUser` 1.1 est maintenant remplacé par [[yii\web\User]], et il n'y a plus de classe `CUserIdentity`.
La classe `CWebUser` 1.1 est maintenant remplacée par [[yii\web\User]], et il n'y a plus de classe `CUserIdentity`.
Au lieu de cela, vous devez implémenter [[yii\web\IdentityInterface]] qui est beaucoup plus simple à utiliser.
Le modèle d'application avancé fournit un exemple.
Le modèle de projet avancé fournit un exemple.
Merci de lire les parties [Authentification](security-authentication.md), [Authorisation](security-authorization.md), et
[Modèle application avancée](tutorial-advanced-app.md) pour en savoir plus.
Reportez-vous aux sections [Authentification](security-authentication.md), [Authorisation](security-authorization.md), et
[Modèle de projet avancé](tutorial-advanced-app.md) pour en savoir plus.
Gestion des URL
---------------
La gestion des URL dans Yii 2 est similaire à celle disponible dans la version 1.1. Une amélioration majeure est que la
gestion des URL supporte désormais les paramètres optionnels. Par exemple, si vous avez une règle déclarée comme suit,
gestion des URL prend désormais en charge les paramètres optionnels. Par exemple, si vous avez une règle déclarée comme suit,
cela fera correspondre `post/popular` et `post/1/popular`. Dans la version 1.1, il fallait utiliser deux règles pour
atteindre le même objectif.
@ -495,11 +522,13 @@ atteindre le même objectif.
]
```
Merci de lire la partie [Gestion des URL](url.md) pour en savoir plus.
Reportez-vous à la section [Documentation de la gestion des URL](runtime-routing.md) pour en savoir plus.
Un changement important dans la convention de nommage pour les routes est que les noms utilisant la *casse en dos de chameau* des contrôleurs et des actions utilisent désormais uniquement des mots en bas de casse séparés par des tirets, p. ex. l'identifiant du contrôleur Reportez-vous à la section traitant des [Identifiants de contrôleur](structure-controllers.md#controller-ids) et [Identifiants d'action](structure-controllers.md#action-ids) pour plus de détails.
Utiliser Yii 1.1 et 2.x ensemble
--------------------------------
Si vous avez du code Yii 1.1 que vous souhaitez réutiliser avec Yii 2, merci de lire la partie [Utiliser Yii 1.1 et 2.0 ensemble](extend-using-v1-v2.md).
Si vous avez du code Yii 1.1 que vous souhaitez réutiliser avec Yii 2, reportez-vous à la section [Utiliser Yii 1.1 et 2.0 ensemble](tutorial-yii-integration.md).

2
docs/guide-fr/intro-yii.md

@ -31,7 +31,7 @@ profiter de son architecture extensible solide, afin d'utiliser ou développer d
Yii n'est pas un one-man show, il est soutenu par une [solide équipe de développement du noyau][about_yii] ainsi que d'une grande communauté
avec de nombreux professionnels qui contribuent constamment au développement de Yii. L'équipe de développeurs de Yii
garde un œil attentif sur les dernières tendances en développement Web, et sur les meilleures pratiques et caractéristiques
garde un œil attentif sur les dernières tendances en développement Web, et sur les meilleures pratiques et caractéristiques
trouvées dans d'autres frameworks ou projets. Les meilleures pratiques et caractéristiques les plus pertinentes trouvées ailleurs sont régulièrement intégrées dans le code du noyau et utilisables
via des interfaces simples et élégantes.

80
docs/guide-fr/output-client-scripts.md

@ -0,0 +1,80 @@
Travail avec des scripts clients
===================================
> Note: cette section est encore en développement.
### Enregistrement des scripts
Avec l'objet [[yii\web\View]] vous êtes en mesure d'enregistrer des scripts. Il existe deux méthodes dédiées pour cela :
[[yii\web\View::registerJs()|registerJs()]] pour les scripts en ligne et [[yii\web\View::registerJsFile()|registerJsFile()]] pour les scripts externes.
Les scripts en ligne sont utiles pour la configuration et le code généré dynamiquement. La méthode pour les ajouter est la suivante :
```php
$this->registerJs("var options = ".json_encode($options).";", View::POS_END, 'my-options');
```
Le premier argument est le code JS réel à insérer dans la page. Le deuxième argument détermine à quel endroit le script doit être inséré dans la page. Les valeurs possibles sont :
- [[yii\web\View::POS_HEAD|View::POS_HEAD]] pour le placer dans la section d'entête (`<head></head>`).
- [[yii\web\View::POS_BEGIN|View::POS_BEGIN]] pour le placer juste après la balise d'ouverture du corps de la page (`<body>`).
- [[yii\web\View::POS_END|View::POS_END]] pour le placer juste avant la balise de fermeture du corps de la page (`</body>`).
- [[yii\web\View::POS_READY|View::POS_READY]] pour l'exéuter sur l'événement « document `ready` ». Cela enregistre [[yii\web\JqueryAsset|jQuery]] automatiquement.
- [[yii\web\View::POS_LOAD|View::POS_LOAD]] pour l'exécuter sur l'événement « document `load` » . Cela enregistre [[yii\web\JqueryAsset|jQuery]] automatiquement.
Le dernier argument est un identifiant unique du script utilisé pour identifier le bloc de code et remplacer un bloc existant de même identifiant au lieu de simplement l'ajouter. Si vous ne le fournissez pas, le code JS lui-même est utilisé en tant qu'identifiant.
Un script externe peut être ajouté comme expliqué ci-dessous :
```php
$this->registerJsFile('http://example.com/js/main.js', ['depends' => [\yii\web\JqueryAsset::className()]]);
```
Les arguments pour [[yii\web\View::registerJsFile()|registerJsFile()]] sont semblables à ceux utilisés pour [[yii\web\View::registerCssFile()|registerCssFile()]]. Dans l'exemple précédent, nous enregistrons le fichier `main.js` avec une dépendance sur `JqueryAsset`. Cela siginifie que le fichier `main.js` sera ajouté APRÈS `jquery.js`. Sans la spécification de cette dépendance, l'ordre relatif entre `main.js` et `jquery.js` resterait indéfini.
Comme pour [[yii\web\View::registerCssFile()|registerCssFile()]], il est également fortement recommandé que vous utilisiez les [paquets de ressources](structure-assets.md) (asset bundles) pour enregistrer des fichiers JS externes plutôt que d'utiliser [[yii\web\View::registerJsFile()|registerJsFile()]].
### Enregistrement de paquets de ressources
Comme cela a été mentionné plus tôt, il est préférable d'utiliser des paquets de ressources plutôt que d'utiliser CSS et JavaScript directement. Vous pouvez obtenir des détails sur les paquets de ressources dans la section [Ressources](structure-assets.md) de ce guide. Comme lors de l'utilisation des paquets de ressources déjà définis, c'est très simple :
```php
\frontend\assets\AppAsset::register($this);
```
### Enregistrement des CSS
Vous pouvez enregistrer les CSS en utilisant [[yii\web\View::registerCss()|registerCss()]] ou [[yii\web\View::registerCssFile()|registerCssFile()]]. Le premier enregistre un bloc de code CSS tandis que le second enregistre un fichier CSS externe. Par exemple :
```php
$this->registerCss("body { background: #f00; }");
```
Le code ci-dessus provoque l'ajout de ce qui suit à la section « head » :
```html
<style>
body { background: #f00; }
</style>
```
Si vous désirez spécifier des propriétés additionnelles du style balise, passez un tableau des paires nom-valeur en tant que troisième argument. Si vous avez besoin de vous assurer qu'il y a seulement une balise style unique, utilisez un quatrième argument comme cela a été mentionné dans la description des balises méta.
```php
$this->registerCssFile("http://example.com/css/themes/black-and-white.css", [
'depends' => [BootstrapAsset::className()],
'media' => 'print',
], 'css-print-theme');
```
Le code ci-dessus provoque l'ajout d'un lien vers un fichier CSS à la section « head » de la page.
* Le premier argument spécifie le fichier CSS à enregistrer.
* Le deuxième argument spécifie l'attribut HTML pour la balise `<link>` résultant. L'option `depends` fait l'objet d'une interprétation particulière. Elle spécifie de quel paquet de ressources ce fichier dépend. Dans ce cas, le paquet de ressources dont le ficher dépend est [[yii\bootstrap\BootstrapAsset|BootstrapAsset]]. Cela veut dire que le fichier CSS sera ajouté *après* les fichiers CSS contenus dans [[yii\bootstrap\BootstrapAsset|BootstrapAsset]].
* Le dernier argument spécifie un identifiant pour ce fichier CSS. S'il n'est pas fourni, l'URL du fichier CSS est utilisée à sa place.
Il est fortement recommandé que vous utilisiez des [paquets de ressources](structure-assets.md) pour enregistrer des fichers CSS externes plutôt que [[yii\web\View::registerCssFile()|registerCssFile()]]. L'utilisation des paquets de ressources vous permet de combiner et de comprimer plusieurs fichiers CSS, ce qui est souhaitable pour les sites Web à trafic intense.

299
docs/guide-fr/output-data-providers.md

@ -0,0 +1,299 @@
Fournisseurs de données
=======================
Dans les sections [Pagination](output-pagination.md) et [Tri](output-sorting.md), nous avons décrit comment permettre à l'utilisateur de choisir une page particulière de données à afficher et de trier ces données en fonction de certaines colonnes. Comme les tâches de pagination et de tri sont très courantes, Yii met à votre disposition un jeu de classes *fournisseurs de données* pour les encapsuler.
Un fournisseur de données est une classe qui implémente l'interface [[yii\data\DataProviderInterface]]. Il prend en essentiellement en charge l'extraction de données paginées et triées. Il fonctionne ordinairement avec des [composants graphiques de données](output-data-widgets.md) pour que l'utilisateur final puisse paginer et trier les données de manière interactive.
Les classes fournisseurs de données suivantes sont incluses dans les versions publiées de Yii :
* [[yii\data\ActiveDataProvider]]: utilise [[yii\db\Query]] ou [[yii\db\ActiveQuery]] pour demander des données à des bases de données et les retourner sous forme de tableaux ou d'instances d'[enregistrement actif](db-active-record.md).
* [[yii\data\SqlDataProvider]]: exécute une instruction SQL et retourne les données sous forme de tableaux.
* [[yii\data\ArrayDataProvider]]: prend un gros tableau et en retourne une tranche en se basant sur les spécifications de pagination et de tri.
Tous ces fournisseurs de données sont utilisés selon un schéma commun :
```php
// créer le fournisseur de données en configurant ses propriétés de pagination et de tri
$provider = new XyzDataProvider([
'pagination' => [...],
'sort' => [...],
]);
// retrouver les données paginées et triées
$models = $provider->getModels();
// obtenir le nombre d'items de données dans la page courante
$count = $provider->getCount();
// obtenir le nombre total d'items de données de l'ensemble des pages
$totalCount = $provider->getTotalCount();
```
Vous spécifiez les comportements de pagination et de tri d'un fournisseur de données en configurant ses propriétés [[yii\data\BaseDataProvider::pagination|pagination]] et [[yii\data\BaseDataProvider::sort|sort (tri)]] qui correspondent aux configurations de [[yii\data\Pagination]] et [[yii\data\Sort]], respectivement. Vous pouvez également les configurer à `false` pour désactiver la pagination et/ou le tri.
Les [composants graphiques de données](output-data-widgets.md), tels que [[yii\grid\GridView]], disposent d'une propriété nommée `dataProvider` qui accepte une instance de fournisseur de données et affiche les données qu'il fournit. Par exemple :
```php
echo yii\grid\GridView::widget([
'dataProvider' => $dataProvider,
]);
```
Ces fournisseurs de données varient essentiellement en fonction de la manière dont la source de données est spécifiée. Dans les sections qui suivent, nous expliquons l'utilisation détaillée de chacun des ces fournisseurs de données.
## Fournisseur de données actif <span id="active-data-provider"></span>
Pour utiliser le [[yii\data\ActiveDataProvider|fournisseur de données actif (classe *ActiveDataProvider*)]], vous devez configurer sa propriété [[yii\data\ActiveDataProvider::query|query]]. Elle accepte soit un objet [[yii\db\Query]], soit un objet [[yii\db\ActiveQuery]]. Avec le premier, les données peuvent être soit des tableaux, soit des instances d'[enregistrement actif](db-active-record.md). Par exemple :
```php
use yii\data\ActiveDataProvider;
$query = Post::find()->where(['status' => 1]);
$provider = new ActiveDataProvider([
'query' => $query,
'pagination' => [
'pageSize' => 10,
],
'sort' => [
'defaultOrder' => [
'created_at' => SORT_DESC,
'title' => SORT_ASC,
]
],
]);
// retourne un tableau d'objets Post
$posts = $provider->getModels();
```
Si la requête `$query` de l'exemple ci-dessus est créée en utilisant le code suivant, alors le fournisseur de données retourne des tableaux bruts.
```php
use yii\db\Query;
$query = (new Query())->from('post')->where(['status' => 1]);
```
> Note: si une requête spécifie déjà la clause `orderBy`, les nouvelles instructions de tri données par l'utilisateur final (via la configuration `sort`) sont ajoutées à la clause `orderBy` existante. Toute clause `limit` et `offset` existante est écrasée par la requête de pagination de l'utilisateur final (via la configuration `pagination`).
Par défaut, [[yii\data\ActiveDataProvider]] utilise le composant d'application `db` comme connexion à la base de données. Vous pouvez utiliser une connexion différente en configurant la propriété [[yii\data\ActiveDataProvider::db]].
## Fournisseur de données SQL <span id="sql-data-provider"></span>
[[yii\data\SqlDataProvider]] travaille avec des instructions SQL brutes pour aller chercher les données. Selon les spécifications de [[yii\data\SqlDataProvider::sort|sort]] et de [[yii\data\SqlDataProvider::pagination|pagination]], le fournisseur ajuste les clauses `ORDER BY` et `LIMIT` de l'instruction SQL en conséquence pour n'aller chercher que la page de données requise dans l'ordre désiré.
Pour utiliser [[yii\data\SqlDataProvider]], vous devez spécifier la propriété [[yii\data\SqlDataProvider::sql|sql]], ainsi que la propriété [[yii\data\SqlDataProvider::totalCount|totalCount]]. Par exemple :
```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',
],
],
]);
// retourne un tableau de lignes de données
$models = $provider->getModels();
```
> Info: la propriété [[yii\data\SqlDataProvider::totalCount|totalCount]] est requise seulement si vous avez besoin de paginer les données.Cela est dû au fait que l'instruction SQL spécifiée via [[yii\data\SqlDataProvider::sql|sql]] est modifiée par le fournisseur pour ne retourner que la page de données couramment requise. Le fournisseur a donc besoin de connaître le nombre total d'items de données pour calculer correctement le nombre de pages disponibles.
## Fournisseur de données tableau <span id="array-data-provider"></span>
L'utilisation de [[yii\data\ArrayDataProvider]] est préférable lorsque vous travaillez avec un grand tableau. Le fournisseur vous permet de retourner une page des données du tableau, triées selon une ou plusieurs colonnes. Pour utiliser [[yii\data\ArrayDataProvider]], vous devez spécifier la propriété [[yii\data\ArrayDataProvider::allModels|*allModels* (tous les modèles)]] comme un grand tableau. Les éléments dans le grand tableau peuvent être, soit des tableaux associatifs (p. ex. des résultats de requête d'[objets d'accès aux données (DAO)](db-dao.md)) ou des objets (p. ex. les instances d'[Active Record](db-active-record.md). Par exemple :
```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'],
],
]);
// obtient les lignes de la page couramment requise
$rows = $provider->getModels();
```
> Note: comparé au [fournisseur de données actif](#active-data-provider) et au fournisseur de données SQL](#sql-data-provider), le fournisseur de données tableau est moins efficient car il requiert de charger *toutes* les données en mémoire.
## Travail avec les clés de données <span id="working-with-keys"></span>
Lorsque vous utilisez les items de données retournés par le fournisseur de données, vous avez souvent besoin d'identifier chacun des items de données par une clé unique. Par exemple, si les items de donnés représentent des informations sur un client, vous désirez peut-être utiliser l'identifiant du client en tant que clé pour chacun de lots d'informations sur un client. Les fournisseurs de données peuvent retourner une liste de telles clés correspondant aux items de données retournés par [[yii\data\DataProviderInterface::getModels()]]. Par exemple :
```php
use yii\data\ActiveDataProvider;
$query = Post::find()->where(['status' => 1]);
$provider = new ActiveDataProvider([
'query' => $query,
]);
// retourne un tableau d'objets Post
$posts = $provider->getModels();
// retourne les valeurs des clés primaires correspondant à $posts
```
Dans l'exemple ci-dessus, comme vous fournissez un objet [[yii\db\ActiveQuery]] à [[yii\data\ActiveDataProvider]]. Il est suffisamment intelligent pour retourner les valeurs de la clé primaire en tant que clés. Vous pouvez aussi spécifier comment les valeurs de la clé sont calculées en configurant [[yii\data\ActiveDataProvider::key]] avec un nom de colonne ou une fonction de rappel qui calcule les valeurs de la clé. Par exemple :
```php
// utilise la colonne "slug" comme valeurs de la clé
$provider = new ActiveDataProvider([
'query' => Post::find(),
'key' => 'slug',
]);
// utilise le résultat de md5(id) comme valeurs de la clé
$provider = new ActiveDataProvider([
'query' => Post::find(),
'key' => function ($model) {
return md5($model->id);
}
]);
```
## Création d'un fournisseur de données personnalisé <span id="custom-data-provider"></span>
Pour créer votre fournisseur de données personnalisé, vous devez implémenter [[yii\data\DataProviderInterface]]. Une manière plus facile est d'étendre [[yii\data\BaseDataProvider]],ce qui vous permet de vous concentrer sur la logique centrale du fournisseur de données. En particulier, vous devez essentiellement implémenter les méthodes suivantes :
- [[yii\data\BaseDataProvider::prepareModels()|prepareModels()]]: prépare les modèles de données qui seront disponibles dans la page courante et les retourne sous forme de tableau.
- [[yii\data\BaseDataProvider::prepareKeys()|prepareKeys()]]: accepte un tableau de modèles de données couramment disponibles et retourne les clés qui leur sont associés.
- [[yii\data\BaseDataProvider::prepareTotalCount()|prepareTotalCount]]: retourne une valeur indiquant le nombre total de modèles de données dans le fournisseur.
Nous présentons ci-dessous un exemple de fournisseur de données que lit des données CSV efficacement :
```php
<?php
use yii\data\BaseDataProvider;
class CsvDataProvider extends BaseDataProvider
{
/**
* @var string name of the CSV file to read
*/
public $filename;
/**
* @var string|callable nom de la colonne clé ou fonction de rappel la retournant
*/
public $key;
/**
* @var SplFileObject
*/
protected $fileObject; // SplFileObject est très pratique pour rechercher une ligne particulière dans un fichier
/**
* @inheritdoc
*/
public function init()
{
parent::init();
// open file
$this->fileObject = new SplFileObject($this->filename);
}
/**
* @inheritdoc
*/
protected function prepareModels()
{
$models = [];
$pagination = $this->getPagination();
if ($pagination === false) {
// dans le cas où il n'y a pas de pagination, lit toutes les lignes
while (!$this->fileObject->eof()) {
$models[] = $this->fileObject->fgetcsv();
$this->fileObject->next();
}
} else {
// s'il y a une pagination, ne lit qu'une seule page
$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;
} else {
return array_keys($models);
}
}
/**
* @inheritdoc
*/
protected function prepareTotalCount()
{
$count = 0;
while (!$this->fileObject->eof()) {
$this->fileObject->next();
++$count;
}
return $count;
}
}
```

667
docs/guide-fr/output-data-widgets.md

@ -0,0 +1,667 @@
Composants graphiques d'affichage de données
============================================
Yii fournit un jeu de [composants graphiques](structure-widgets.md) utilisables pour afficher des données. Tandis que le componsant graphique [DetailView](#detail-view) (vue détaillée) peut être utilisé pour afficher un enregistrement unique, les composants graphiques [ListView](#list-view) (vue en liste) et [GridView](#grid-view) (vue en grille) peuvent être utilisés pour afficher plusieurs enregistrements en liste ou en grille assortis de fonctionnalités telles que la pagination, le tri et le filtrage.
Vue détaillée (classe *DetailView*) <a name="detail-view"></a>
----------------------------------
Le composant graphique [[yii\widgets\DetailView|DetailView]] (vue détaillée) affiche les détails d'un [[yii\widgets\DetailView::$model|modèle]] de données unique.
Il est le plus adapté à l'affichage d'un modèle dans un format courant (p. ex. chacun des attributs du modèle est affiché en tant que ligne d'une grille). Le modèle peut être, soit une instance, ou une classe fille, de [[\yii\base\Model]] telle que la classe [ActiveRecord](db-active-record.md), soit un tableau associatif.
*DetailView* utilise la propriété [[yii\widgets\DetailView::$attributes|$attributes]] pour déterminer quels attributs du modèle doivent être affichés et comment ils doivent être formatés. Reportez-vous à la section [formatage des données](output-formatting.md) pour des informations sur les options de formatage.
Une utilisation typique de *DetailView* ressemble à ce qui suit :
```php
echo DetailView::widget([
'model' => $model,
'attributes' => [
'title', // attribut title (en texte simple)
'description:html', // attribut description formaté en HTML
[ // le nom du propriétaire du modèle
'label' => 'Owner',
'value' => $model->owner->name,
],
'created_at:datetime', // date de création formaté comme une date/temps
],
]);
```
Vue en liste (class *ListView*)<a name="list-view"></a>
------------------------------
Le composant graphique [[yii\widgets\ListView|ListView]] (vue en liste) est utilisé pour afficher des données issues d'un [fournisseur de données](output-data-providers.md). Chacun des modèles est rendu en utilisant le composant [[yii\widgets\ListView::$itemView|ListView]] (vue en liste) spécifié. Comme ce composant fournit des fonctionnalités telles que la pagination, le tri et le filtrage de base, il est pratique, à la fois pour afficher des informations et pour créer des interfaces utilisateur de gestion des données.
Typiquement, on l'utilise comme ceci :
```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',
]);
```
Le fichier de vue, `_post`, contient ce qui suit :
```php
<?php
use yii\helpers\Html;
use yii\helpers\HtmlPurifier;
?>
<div class="post">
<h2><?= Html::encode($model->title) ?></h2>
<?= HtmlPurifier::process($model->text) ?>
</div>
```
Dans le fichier ci-dessus, le modèle de données courant est disponible comme `$model`. En outre, les variables suivantes sont disponibles :
- `$key`: mixed, la valeur de la clé associée à l'item de données
- `$index`: integer, l'index commençant à zéro de l'item de données dans le tableau d'items retourné par le fournisseur de données.
- `$widget`: ListView, l'instance de ce composant graphique.
Si vous avez besoin de passer des données additionnelles à chacune des vues, vous pouvez utiliser la propriété [[yii\widgets\ListView::$viewParams|$viewParams]] pour passer des paires clé valeur, comme ceci :
```php
echo ListView::widget([
'dataProvider' => $dataProvider,
'itemView' => '_post',
'viewParams' => [
'fullView' => true,
'context' => 'main-page',
// ...
],
]);
```
Celles-ci sont alors disponibles aussi dans la vue en tant que variables.
Vue en grille (classe *GridView*)<a name="grid-view"></a>
--------------------------------
La vue en grille, ou composant [[yii\grid\GridView|GridView]], est un des composants les plus puissants de Yii. Ce composant est extrêmement utile si vous devez rapidement construire l'interface d'administration du système. Il accepte des données d'un [fournisseur de données](output-data-providers.md) et rend chacune des lignes en utilisant un jeu de [[yii\grid\GridView::columns|columns]] (colonnes), présentant ainsi l'ensemble des données sous forme d'une grille.
Chacune des lignes de la grille représente un item unique de données, et une colonne représente ordinairement un attribut de l'item (quelques colonnes peuvent correspondre à des expressions complexes utilisant les attributs ou à un texte statique).
Le code minimal pour utiliser le composant *GridView* se présente comme suit :
```php
use yii\grid\GridView;
use yii\data\ActiveDataProvider;
$dataProvider = new ActiveDataProvider([
'query' => Post::find(),
'pagination' => [
'pageSize' => 20,
],
]);
echo GridView::widget([
'dataProvider' => $dataProvider,
]);
```
Le code précédent crée un fournisseur de données, puis utilise le composant *GridView* pour afficher chacun des attributs dans une ligne en le prélevant dans le fournisseur de données. La grille affichée est doté de fonctionnalités de pagination et de tri sans autre intervention.
### Colonnes de la grille
Les colonnes de la grille sont exprimées en terme de classe [[yii\grid\Column]], qui sont configurées dans la propriété [[yii\grid\GridView::columns|columns]] (colonnes) de la configuration du composant *GridView*. En fonction du type de colonne et des réglages, celles-ci sont en mesure de présenter les données différemment. La classe par défaut est [[yii\grid\DataColumn]] (colonne de données), qui représente un attribut de modèle et peut être triée et filtrée.
```php
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
// colonnes simples définies par les données contenues dans le fournisseur de données
// les données de la colonne du modèle sont utilisées
'id',
'username',
// un exemple plus complexe
[
'class' => 'yii\grid\DataColumn', // peut être omis car c'est la valeur par défaut
'value' => function ($data) {
return $data->name; // $data['name'] pour une donnée tableau p. ex. en utilisant SqlDataProvider.
},
],
],
]);
```
Notez que si la partie [[yii\grid\GridView::columns|columns]] de la configuration n'est pas spécifiée, Yii essaye de montrer toutes les colonnes possibles du modèle du fournisseur de données.
### Classes de colonne
Les colonnes du composant *GridView* peuvent être personnalisées en utilisant différentes classes de colonnes :
```php
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
[
'class' => 'yii\grid\SerialColumn', // <-- ici
// vous pouvez configurer des propriété additionnelles ici
],
```
En plus des classes de colonne fournies par Yii que nous allons passer en revue ci-après, vous pouvez créer vos propres classes de colonne.
Chacune des classes de colonne étend la classe [[yii\grid\Column]] afin que quelques options communes soient disponibles lors de la configuration des colonnes.
- [[yii\grid\Column::header|header]] permet de définir une ligne d'entête
- [[yii\grid\Column::footer|footer]] permet de définir le contenu d'une ligne de pied de grille
- [[yii\grid\Column::visible|visible]] définit si la colonne doit être visible.
- [[yii\grid\Column::content|content]] vous permet de passer une fonction de rappel PHP valide qui retourne les données d'une ligne. Le format est le suivant :
```php
function ($model, $key, $index, $column) {
return 'a string';
}
```
Vous pouvez spécifier différentes options HTML de conteneurs en passant des tableaux à :
- [[yii\grid\Column::headerOptions|headerOptions]]
- [[yii\grid\Column::footerOptions|footerOptions]]
- [[yii\grid\Column::filterOptions|filterOptions]]
- [[yii\grid\Column::contentOptions|contentOptions]]
#### Colonne de données (*DataColumn*) <span id="data-column"></span>
La classe [[yii\grid\DataColumn|DataColumn]] (colonne de données) est utilisée pour afficher et trier des données. C'est le type de colonne par défaut, c'est pourquoi la spécification de la classe peut être omise.
Le réglage principal de la colonne de données est celui de sa propriété [[yii\grid\DataColumn::format|format]]. Ses valeurs correspondent aux méthodes du [composant d'application](structure-application-components.md) `formatter` qui est de classe [[\yii\i18n\Formatter|Formatter]] par défaut :
```php
echo GridView::widget([
'columns' => [
[
'attribute' => 'name',
'format' => 'text'
],
[
'attribute' => 'birthday',
'format' => ['date', 'php:Y-m-d']
],
],
]);La valeur de la colonne est passée en tant que premier argument
```
Dans cet exemple, `text` correspond à la méthode [[\yii\i18n\Formatter::asText()]]. La valeur de la colonne est passée en tant que premier argument. Dans la deuxième définition de colonne, `date` correspond à la méthode [[\yii\i18n\Formatter::asDate()]]. La valeur de la colonne est passée en tant que premier argument tandis que 'php:Y-m-d' est utilisé en tant que valeur du deuxième argument.
Pour une liste complète de tous les formateurs, reportez-vous à la section [Formatage des données](output-formatting.md).
Pour configurer des colonnes de données, il y a aussi un format raccourci qui est décrit dans la documentation de l'API de [[yii\grid\GridView::columns|columns]].
#### Colonne d'actions (*ActionColumn*)
La classe [[yii\grid\ActionColumn|ActionColumn]] (colonne d'action) affiche des boutons d'action tels que mise à jour ou supprimer pour chacune des lignes.
```php
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
[
'class' => 'yii\grid\ActionColumn',
// vous pouvez configurer des propriétés additionnelles ici
],
```
Les propriétés additionnelles configurables sont :
- [[yii\grid\ActionColumn::controller|controller]] qui est l'identifiant du contrôleur qui prend en charge l'action. Si cette propriété n'est pas définie, le contrôleur courant est utilisé.
- [[yii\grid\ActionColumn::template|template]] qui définit le modèle utilisé pour composer chacune des cellules dans la colonne d'actions. Les marqueurs (textes à l'intérieur d'accolades) sont traités comme des identifiants d'action (aussi appelé *noms de bouton* dans le contexte d'une colonne d'actions. Il sont remplacés par les fonctions de rappel correspondantes spécifiées dans la propriété [[yii\grid\ActionColumn::$buttons|buttons]]. Par exemple, le marqueur `{view}` sera remplacé par le résultat de la fonction de rappel `buttons['view']`. Si une fonction de rappel n'est pas trouvée, le texte est remplacé par une chaîne vide. Les marqueurs par défaut sont `{view} {update} et {delete}`.
- [[yii\grid\ActionColumn::buttons|buttons]] est un tableau de fonctions de rappel pour le rendu des boutons. Les clés du tableau sont les noms des boutons (sans les accolades), et les valeurs sont les fonctions de rappel de rendu des boutons. Les fonctions de rappel ont la signature suivante :
```php
function ($url, $model, $key) {
// retourne le code HTML du bouton
}
```
dans le code qui précède, `$url` est l'URL que la colonne crée pour le bouton, `$model` est l'objet modèle qui est en train d'être rendu pour la ligne courante, et `$key` est la clé du modèle dans le tableau du fournisseur de données.
- [[yii\grid\ActionColumn::urlCreator|urlCreator]] est une fonction de rappel qui crée une URL de bouton en utilisant les informations spécifiées sur le modèle. La signature de la fonction de rappel doit être le même que celle de [[yii\grid\ActionColumn::createUrl()]]. Si cette propriété n'est pas définie, les URL de bouton sont créées en utilisant [[yii\grid\ActionColumn::createUrl()]].
- [[yii\grid\ActionColumn::visibleButtons|visibleButtons]] est un tableau des conditions de visibilité pour chacun des boutons. Les clés du tableau sont les noms des boutons (sans les accolades), et les valeurs sont les valeurs booleénnes `true` ou `false` (vrai ou faux) ou la fonction anonyme. Lorsque le nom du bouton n'est pas spécifié dans ce tableau, il est montré par défaut. Les fonctions de rappel utilisent la signature suivante :
```php
function ($model, $key, $index) {
return $model->status === 'editable';
}
```
Ou vous pouvez passer une valeur booléenne :
```php
[
'update' => \Yii::$app->user->can('update')
]
```
#### Colonne boîte à cocher (*CheckboxColumn*)
La classe [[yii\grid\CheckboxColumn|CheckboxColumn]] (colonne de boîtes à cocher) affiche une colonne de boîtes à cocher.
Pour ajouter une colonne de boîtes à cocher à la vue en grille (*GridView*), ajoutez la configuration de [[yii\grid\GridView::$columns|columns]] comme ceci :
```php
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
// ...
[
'class' => 'yii\grid\CheckboxColumn',
// vous pouvez configurer des propriétés additionnelles ici
],
],
```
L'utilisateur peut cliquer sur les boîtes à cocher pour sélectionner des lignes dans la grille. Les lignes sélectionnées peuvent être obtenues en appelant le code JavaScript suivant :
```javascript
var keys = $('#grid').yiiGridView('getSelectedRows');
// keys est un tableau constitué des clés associées aux lignes sélectionnées.
```
#### Colonne série (*SerialColumn*)
La classe [[yii\grid\SerialColumn|SerialColumn]] (colonne série) rend les numéros de ligne en commençant à `1` et en continuant.
L'utilisation est aussi simple que ce que nous présentons ci-après :
```php
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
['class' => 'yii\grid\SerialColumn'], // <-- ici
// ...
```
### Tri des données
> Note: cette section est en cours de développement.
>
> - https://github.com/yiisoft/yii2/issues/1576
### Filtrage des données
Pour filtrer les données, la vue en grille (*GridView*) requiert un [modèle](structure-models.md) qui représente le critère de recherche qui est ordinairement pris dans les champs du filtre dans la vue en grille. Une pratique courante lorsqu'on utilise des [enregistrements actifs](db-active-record.md) est de créer une classe modèle de recherche qui fournit les fonctionnalités nécessaires (elle peut être générée pour vous par [Gii](start-gii.md)). Cette classe définit les règles de validation pour la recherche et fournit une méthode `search()` (recherche) qui retourne le fournisseur de données avec une requête ajustée qui respecte les critères de recherche.
Pour ajouter la fonctionnalité de recherche au modèle `Post`, nous pouvons créer un modèle `PostSearch` comme celui de l'exemple suivant :
```php
<?php
namespace app\models;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
class PostSearch extends Post
{
public function rules()
{
// seuls les champs dans rules() peuvent être recherchés
return [
[['id'], 'integer'],
[['title', 'creation_date'], 'safe'],
];
}
public function scenarios()
{
// bypasse l'implémentation de scenarios() dans la classe parent
return Model::scenarios();
}
public function search($params)
{
$query = Post::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
// charge les données du formulaire de recherche et valide
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
// ajuste la requête en ajoutant les filtres
$query->andFilterWhere(['id' => $this->id]);
$query->andFilterWhere(['like', 'title', $this->title])
->andFilterWhere(['like', 'creation_date', $this->creation_date]);
return $dataProvider;
}
}
```
> Tip: reportez-vous au [Constructeur de requêtes ](db-query-builder.md) (*Query Builder*) et en particulier aux [conditions de filtrage](db-query-builder.md#filter-conditions) pour savoir comment construire la requête de filtrage.
Vous pouvez utiliser cette fonction dans le contrôleur pour obtenir le fournisseur de données de la vue en grille :
```php
$searchModel = new PostSearch();
$dataProvider = $searchModel->search(Yii::$app->request->get());
return $this->render('myview', [
'dataProvider' => $dataProvider,
'searchModel' => $searchModel,
]);
```
Et dans la vue, vous assignez ensuite le fournisseur de données (`$dataProvider`) et le modèle de recherche (`$searchModel`) à la vue en grille (*GridView*) :
```php
echo GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
// ...
],
]);
```
### Formulaire de filtrage séparé
La plupart du temps, utiliser les filtres de l'entête de la vue en grille suffit, mais dans le cas où vous avez besoin d'un formulaire de filtrage séparé, vous pouvez facilement l'ajouter aussi. Vous pouvez créer une vue partielle `_search.php` avec le contenu suivant :
```php
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
/* @var $this yii\web\View */
/* @var $model app\models\PostSearch */
/* @var $form yii\widgets\ActiveForm */
?>
<div class="post-search">
<?php $form = ActiveForm::begin([
'action' => ['index'],
'method' => 'get',
]); ?>
<?= $form->field($model, 'title') ?>
<?= $form->field($model, 'creation_date') ?>
<div class="form-group">
<?= Html::submitButton('Search', ['class' => 'btn btn-primary']) ?>
<?= Html::submitButton('Reset', ['class' => 'btn btn-default']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>
```
et l'inclure dans la vue `index.php`, ainsi :
```php
<?= $this->render('_search', ['model' => $searchModel]) ?>
```
> Note: si vous utilisez Gii pour générer le code des méthodes CRUD, le formulaire de filtrage séparé (`_search.php`) est généré par défaut, mais est commenté dans la vue `index.php`. Il vous suffit de supprimer la marque du commentaire pour l'utiliser !
Un formulaire de filtrage séparé est utile quand vous avez besoin de filtrer selon des champs qui ne sont pas visibles dans la vue en grille, ou pour des conditions particulières de filtrage, telles qu'une plage de dates. Pour filtrer selon une plage de dates, nous pouvons ajouter les attributs non DB `createdFrom` et`createdTo` au modèle de recherche :
```php
class PostSearch extends Post
{
/**
* @var string
*/
public $createdFrom;
/**
* @var string
*/
public $createdTo;
}
```
Étendez les conditions de la requête dans la méthode `search()` comme ceci :
```php
$query->andFilterWhere(['>=', 'creation_date', $this->createdFrom])
->andFilterWhere(['<=', 'creation_date', $this->createdTo]);
```
Et ajoutez les champs représentatifs au formulaire de filtrage :
```php
<?= $form->field($model, 'creationFrom') ?>
<?= $form->field($model, 'creationTo') ?>
```
### Travail avec des relations entre modèles
Lorsque vous affichez des enregistrements actifs dans la vue en grille, vous pouvez rencontrer le cas où vous affichez des valeurs de colonne en relation telles que le nom de l'auteur de l'article (post) au lieu d'afficher simplement son identifiant (`id`). Vous pouvez le faire en définissant le nom de l'attribut dans [[yii\grid\GridView::$columns]] comme étant `author.name` lorsque le modèle de l'article (`Post`) possède une relation nommée `author` (auteur) et que le modèle possède un attribut nommé `name` (nom). La vue en grille affiche alors le nom de l'auteur mais le tri et le filtrage ne sont pas actifs par défaut. Vous devez ajuster le modèle `PostSearch` que nous avons introduit dans la section précédente pour y ajouter cette fonctionnalité.
Pour activer le tri sur une colonne en relation, vous devez joindre la table en relation et ajouter la règle de tri au composant *Sort* du fournisseur de données :
```php
$query = Post::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
// joingnez avec la relation nommée `author` qui est une relation avec la table `users`
// et définissez l'alias à `author`
$query->joinWith(['author' => function($query) { $query->from(['author' => 'users']); }]);
// depuis la version 2.0.7, l'écriture ci-dessus peut être simplifiée en $query->joinWith('author AS author');
// active le tri pour la colonne en relation
$dataProvider->sort->attributes['author.name'] = [
'asc' => ['author.name' => SORT_ASC],
'desc' => ['author.name' => SORT_DESC],
];
// ...
```
Le filtrage nécessite aussi l'appel de la fonction *joinWith* ci-dessus. Vous devez également autoriser la recherche sur la colonne dans les attributs et les règles comme ceci :
```php
public function attributes()
{
// ajoute les champs en relation avec les attributs susceptibles d'être cherchés
return array_merge(parent::attributes(), ['author.name']);
}
public function rules()
{
return [
[['id'], 'integer'],
[['title', 'creation_date', 'author.name'], 'safe'],
];
}
```
Dans `search()`, il vous suffit ensuite d'ajouter une autre condition de filtrage avec :
```php
$query->andFilterWhere(['LIKE', 'author.name', $this->getAttribute('author.name')]);
```
> Info: dans ce qui précède, nous utilisons la même chaîne de caractères pour le nom de la relation et pour l'alias de table; cependant, lorsque votre nom de relation et votre alias diffèrent, vous devez faire attention aux endroits où vous utilisez l'alias et à ceux où vous utilisez le nom de la relation. Une règle simple pour cela est d'utiliser l'alias partout où cela sert à construire le requête de base de données et le nom de la relation dans toutes les autres définitions telles que `attributes()` et `rules()` etc.
>
> Par exemple, si vous utilisez l'alias `au` pour la table auteur en relation, l'instruction *joinWith* ressemble à ceci :
>
> ```php
> $query->joinWith(['author au']);
> ```
>
> Il est également possible d'appeler simplement `$query->joinWith(['author']);` lorsque l'alias est défini dans la définition de la relation.
>
> L'alias doit être utilisé dans la condition de filtrage mais le nom d'attribut reste le même :
>
> ```php
> $query->andFilterWhere(['LIKE', 'au.name', $this->getAttribute('author.name')]);
> ```
>
> La même chose est vraie pour la définition du tri :
>
> ```php
> $dataProvider->sort->attributes['author.name'] = [
> 'asc' => ['au.name' => SORT_ASC],
> 'desc' => ['au.name' => SORT_DESC],
> ];
> ```
>
> Également, lorsque vous spécifiez la propriété [[yii\data\Sort::defaultOrder|defaultOrder]] (ordre de tri par défaut) pour le tri, vous avez besoin d'utiliser le nom de la relation au lieu de l'alias :
>
> ```php
> $dataProvider->sort->defaultOrder = ['author.name' => SORT_ASC];
> ```
> Info: pour plus d'informations sur `joinWith` et sur les requêtes effectuées en arrière-plan, consultez la documentation sur l'enregistrement actif à la section [Jointure avec des relations](db-active-record.md#joining-with-relations).
#### Utilisation de vues SQL pour le filtrage, le tri et l'affichage des données
Il existe une autre approche qui peut être plus rapide et plus utile – les vues SQL. Par exemple, si vous avez besoin d'afficher la vue en grille avec des utilisateurs et leur profil, vous pouvez le faire de cette manière :
```sql
CREATE OR REPLACE VIEW vw_user_info AS
SELECT user.*, user_profile.lastname, user_profile.firstname
FROM user, user_profile
WHERE user.id = user_profile.user_id
```
Ensuite vous devez créer l'enregistrement actif qui représente cette vue :
```php
namespace app\models\views\grid;
use yii\db\ActiveRecord;
class UserView extends ActiveRecord
{
/**
* @inheritdoc
*/
public static function tableName()
{
return 'vw_user_info';
}
public static function primaryKey()
{
return ['id'];
}
/**
* @inheritdoc
*/
public function rules()
{
return [
// définissez vos règle ici
];
}
/**
* @inheritdoc
*/
public static function attributeLabels()
{
return [
// définissez vos étiquettes d'attribut ici
];
}
}
```
Après cela, vous pouvez utiliser l'enregistrement actif *UserView* dans vos modèle de recherche, sans spécification additionnelle d'attribut de tri et de filtrage. Tous les attributs fonctionneront directement. Notez que cette approche a ses avantages et ses inconvénients :
- vous n'avez pas besoin de spécifier des conditions de tri et de filtrage. Tout fonctionne d'emblée;
- cela peut être beaucoup plus rapide à cause de la taille des données et du nombre de requêtes SQL effectuées (pour chacune des relations vous n'avez pas besoin de requête supplémentaire);
- comme cela n'est qu'une simple mise en relation de l'interface utilisateur avec la vue SQL, il lui manque un peu de la logique qui apparaît dans vos entités, ainsi, si vous avez des méthodes comme `isActive`, `isDeleted` ou autres qui influencent l'interface utilisateur, vous devez les dupliquer dans cette classe également.
### Plusieurs vues en grille par page
Vous pouvez utiliser plus d'une vue en grille sur une page unique mais quelques éléments de configuration additionnels sont nécessaires afin qu'elles n'entrent pas en interférence entre elles. Lorsque vous utilisez plusieurs instances de la vue en grille, vous devez configurer des noms de paramètre différents pour les liens de tri et de pagination générés de manière à ce que chacune des vues en grille possède ses propres liens de tri et de pagination. Vous faites cela en définissant les paramètres [[yii\data\Sort::sortParam|sortParam]] (tri) et [[yii\data\Pagination::pageParam|pageParam]] (page) des instances [[yii\data\BaseDataProvider::$sort|sort]] et [[yii\data\BaseDataProvider::$pagination|pagination]] du fournisseur de données.
Supposez que vous vouliez lister les modèles `Post` et `User` pour lesquels vous avez déjà préparé deux fournisseurs de données `$userProvider` et `$postProvider`:
```php
use yii\grid\GridView;
$userProvider->pagination->pageParam = 'user-page';
$userProvider->sort->sortParam = 'user-sort';
$postProvider->pagination->pageParam = 'post-page';
$postProvider->sort->sortParam = 'post-sort';
echo '<h1>Users</h1>';
echo GridView::widget([
'dataProvider' => $userProvider,
]);
echo '<h1>Posts</h1>';
echo GridView::widget([
'dataProvider' => $postProvider,
]);
```
### Utilisation de la vue en grille avec Pjax
Le composant graphique [[yii\widgets\Pjax|Pjax]] vous permet de mettre à jour une certaine section de votre page plutôt que d'avoir à recharger la page toute entière. Vous pouvez l'utiliser pour mettre uniquement à jour le contenu de la [[yii\grid\GridView|GridView]] (vue en grille) lors de l'utilisation de filtres.
```php
use yii\widgets\Pjax;
use yii\grid\GridView;
Pjax::begin([
// PJax options
]);
Gridview::widget([
// GridView options
]);
Pjax::end();
```
Pjax fonctionne également pour les liens à l'intérieur du composant graphique [[yii\widgets\Pjax|Pjax]] et pour les liens spécifiés par [[yii\widgets\Pjax::$linkSelector|Pjax::$linkSelector]]. Mais cela peut être un problème pour les liens d'une [[yii\grid\ActionColumn|ActionColumn]] (colonne d'action). Pour empêcher cela, ajoutez l'attribut HTML `data-pjax="0"` aux liens lorsque vous définissez la propriété [[yii\grid\ActionColumn::$buttons|ActionColumn::$buttons]].
#### Vue en grille et vue en liste avec Pjax dans Gii
Depuis la version 2.0.5, le générateur d'actions CRUD de [Gii](start-gii.md) dispose d'une option appelée `$enablePjax` qui peut être utilisée, soit via l'interface web, soit en ligne de commande.
```php
yii gii/crud --controllerClass="backend\\controllers\PostController" \
--modelClass="common\\models\\Post" \
--enablePjax=1
```
Qui génère un composant graphique [[yii\widgets\Pjax|Pjax]] enveloppant les composants graphiques [[yii\grid\GridView|GridView]] ou [[yii\widgets\ListView|ListView]].
Lectures complémentaires
------------------------
- [Rendering Data in Yii 2 with GridView and ListView](http://www.sitepoint.com/rendering-data-in-yii-2-with-gridview-and-listview/) d'Arno Slatius.

179
docs/guide-fr/output-formatting.md

@ -0,0 +1,179 @@
Formatage des données
=====================
Pour afficher des données dans un format plus facile à lire par les utilisateurs, vous pouvez les formater en utilisant le [composant d'application](structure-application-components.md) `formatter`. Par défaut, le formateur est mis en œuvre par [[yii\i18n\Formatter]] qui fournit un jeu de méthodes pour formater des données telles que des dates, des temps, des nombres, des monnaies et autres données couramment utilisées. Vous pouvez utiliser le formateur de la manière indiquée ci-dessous :
```php
$formatter = \Yii::$app->formatter;
// affiche : January 1, 2014
echo $formatter->asDate('2014-01-01', 'long');
// affiche : 12.50%
echo $formatter->asPercent(0.125, 2);
// affiche : <a href="mailto:cebe@example.com">cebe@example.com</a>
echo $formatter->asEmail('cebe@example.com');
// affiche : Yes
echo $formatter->asBoolean(true);
// il prend aussi en charge l'affichage de valeurs nulles :
// affiche : (Not set)
echo $formatter->asDate(null);
```
Comme vous pouvez le voir, ces trois méthodes sont nommées selon le format suivant `asXyz()`, où `Xyz` représente un format pris en charge. En alternative, vous pouvez formater les données en utilisant la méthode générique [[yii\i18n\Formatter::format()|format()]], qui vous permet de contrôler le format désiré par programmation et qui est communément utilisé par les composants graphiques tels que [[yii\grid\GridView]] et [[yii\widgets\DetailView]]. Par exemple :
```php
// affiche : January 1, 2014
echo Yii::$app->formatter->format('2014-01-01', 'date');
// vous pouvez aussi utiliser un tableau pour spécifier les paramètres de votre méthode de formatage :
// `2` est la valeur du paramètre `$decimals` (nombre de décimales) pour la méthode asPercent().
// affiche : 12.50%
echo Yii::$app->formatter->format(0.125, ['percent', 2]);
```
> Note: le composant de formatage est conçu pour formater des valeurs à présenter à l'utilisateur. Si vous voulez convertir des entrées utilisateur en un format lisible par la machine, ou simplement formater une date dans un format lisible par la machine, le formateur n'est pas l'outil adapté à cela. Pour convertir une entrée utilisateur pour une date et un temps, vous pouvez utiliser [[yii\validators\DateValidator]] et [[yii\validators\NumberValidator]] respectivement. Pour une simple conversion entre les formats lisibles par la machine de date et de temps, la fonction PHP [date()](http://php.net/manual/en/function.date.php) suffit.
## Configuration du formateur <span id="configuring-formatter"></span>
Vous pouvez configurer les règles de formatage en configurant le composant `formatter` dans la [configuration de l'application](concept-configurations.md#application-configurations). Par exemple :
```php
return [
'components' => [
'formatter' => [
'dateFormat' => 'dd.MM.yyyy',
'decimalSeparator' => ',',
'thousandSeparator' => ' ',
'currencyCode' => 'EUR',
],
],
];
```
Reportez-vous à la classe [[yii\i18n\Formatter]] pour connaître les propriétés qui peuvent être configurées.
## Formatage de valeurs de dates et de temps <span id="date-and-time"></span>
Le formateur prend en charge les formats de sortie suivants en relation avec les dates et les temps :
- [[yii\i18n\Formatter::asDate()|date]]: la valeur est formatée sous la forme d'une date, p. ex. `January 01, 2014`.
- [[yii\i18n\Formatter::asTime()|time]]: la valeur est formatée sous la forme d'un temps, p. ex. `14:23`.
- [[yii\i18n\Formatter::asDatetime()|datetime]]: la valeur est formatée sous la forme d'une date et d'un temps, p. ex. `January 01, 2014 14:23`.
- [[yii\i18n\Formatter::asTimestamp()|timestamp]]: la valeur est formatée sous la forme d'un [horodatage unix ](http://en.wikipedia.org/wiki/Unix_time), p. ex. `1412609982`.
- [[yii\i18n\Formatter::asRelativeTime()|relativeTime]]: la valeur est formatée sous la forme d'un intervalle de temps entre un temps et le temps actuel dans une forme lisible par l'homme, p.ex. `1 hour ago`.
- [[yii\i18n\Formatter::asDuration()|duration]]: la valeur est formatée comme une durée dans un format lisible par l'homme, p. ex. `1 day, 2 minutes`.
Les formats par défaut pour les dates et les temps utilisés pour les méthodes [[yii\i18n\Formatter::asDate()|date]], [[yii\i18n\Formatter::asTime()|time]],
et [[yii\i18n\Formatter::asDatetime()|datetime]] peuvent être configurés globalement en configurant [[yii\i18n\Formatter::dateFormat|dateFormat]], [[yii\i18n\Formatter::timeFormat|timeFormat]], et [[yii\i18n\Formatter::datetimeFormat|datetimeFormat]].
Vous pouvez spécifier les formats de date et de temps en utilisant la [syntaxe ICU](http://userguide.icu-project.org/formatparse/datetime). Vous pouvez aussi utiliser la [syntaxe date() de PHP](http://php.net/manual/en/function.date.php) avec le préfixe `php:` pour la différentier de la syntaxe ICU. Par exemple :
```php
// format ICU
echo Yii::$app->formatter->asDate('now', 'yyyy-MM-dd'); // 2014-10-06
// format date() de PHP
echo Yii::$app->formatter->asDate('now', 'php:Y-m-d'); // 2014-10-06
```
Lorsque vous travaillez avec des applications qui requièrent une prise en charge de plusieurs langues, vous devez souvent spécifier différents formats de dates et de temps pour différentes locales. Pour simplifier cette tâche, vous pouvez utiliser les raccourcis de formats (p. ex. `long`, `short`), à la place. Le formateur transforme un raccourci de formats en un format approprié en prenant en compte la [[yii\i18n\Formatter::locale|locale]] courante. Les raccourcis de formats suivants sont pris en charge (les exemples supposent que `en_GB` est la locale courante) :
- `short`: affiche `06/10/2014` pour une date et `15:58` pour un temps;
- `medium`: affiche `6 Oct 2014` et `15:58:42`;
- `long`: affiche `6 October 2014` et `15:58:42 GMT`;
- `full`: affiche `Monday, 6 October 2014` et `15:58:42 GMT`.
Depuis la version 2.0.7, il est aussi possible de formater les dates dans différents systèmes calendaires. Reportez-vous à la documentation de l'API pour la propriété [[yii\i18n\Formatter::$calendar|$calendar]] des formateurs pour savoir comment définir un autre système calendaire.
### Fuseaux horaires <span id="time-zones"></span>
Lors du formatage des dates et des temps, Yii les convertit dans le [[yii\i18n\Formatter::timeZone|fuseau horaire]] cible. La valeur à formater est supposée être donnée en UTC, sauf si un fuseau horaire est explicitement défini ou si vous avez configuré [[yii\i18n\Formatter::defaultTimeZone]].
Dans les exemples qui suivent, nous supposons que la cible [[yii\i18n\Formatter::timeZone|fuseau horaire]] est définie à `Europe/Berlin`.
```php
// formatage d'un horodatage UNIX comme un temps
echo Yii::$app->formatter->asTime(1412599260); // 14:41:00
// formatage d'une chaîne de caractère date-temps (en UTC) comme un temps
echo Yii::$app->formatter->asTime('2014-10-06 12:41:00'); // 14:41:00
// formatage d'une chaîne de caractères date-temps (en CEST) comme un temps
echo Yii::$app->formatter->asTime('2014-10-06 14:41:00 CEST'); // 14:41:00
```
> Note: comme les fuseaux horaires sont assujettis à des règles fixées par les gouvernements du monde entier, et que ces règles peuvent varier fréquemment, il est vraisemblable que vous n'ayez pas la dernière information dans la base de données des fuseaux horaires installée sur votre système. Vous pouvez vous reporter au [manuel d'ICU](http://userguide.icu-project.org/datetime/timezone#TOC-Updating-the-Time-Zone-Data) pour des informations sur la manière de mettre cette base de données à jour. Reportez-vous aussi au tutoriel [Configurer votre environnement PHP pour l'internationalisation](tutorial-i18n.md#setup-environment).
## Formatage des nombres <span id="numbers"></span>
Pour les nombres, le formateur prend en charge les formats de sortie suivants :
- [[yii\i18n\Formatter::asInteger()|integer]]: la valeur est formatée comme un entier, p. ex. `42`.
- [[yii\i18n\Formatter::asDecimal()|decimal]]: la valeur est formatée comme un nombre décimal en portant attention aux décimales et aux séparateurs de milliers, p. ex. `2,542.123` ou `2.542,123`.
- [[yii\i18n\Formatter::asPercent()|percent]]: la valeur est formatée comme un pourcentage p. ex. `42%`.
- [[yii\i18n\Formatter::asScientific()|scientific]]: la valeur est formatée comme un nombre dans le format scientifique p. ex. `4.2E4`.
- [[yii\i18n\Formatter::asCurrency()|currency]]: la valeur est formatée comme une valeur monétaire, p. ex. `£420.00`. Notez que pour que cette fonction fonctionne correctement, la locale doit inclure la partie correspondant au pays p. ex. `en_GB` ou `en_US` parce que la partie langue seulement reste ambigüe dans ce cas.
- [[yii\i18n\Formatter::asSize()|size]]: la valeur, qui est un nombre d'octets est formatée sous une forme lisible par l'homme, p. ex. `410 kibibytes`.
- [[yii\i18n\Formatter::asShortSize()|shortSize]]: est la version courte de [[yii\i18n\Formatter::asSize()|size]], e.g. `410 KiB`.
Le format pour un nombre peut être ajusté en utilisant [[yii\i18n\Formatter::decimalSeparator|decimalSeparator (séparateur de décimales)]] et
[[yii\i18n\Formatter::thousandSeparator|thousandSeparator (séparateur de milliers) ]], qui prennent tous les deux les valeurs par défaut déterminées par la [[yii\i18n\Formatter::locale|locale]] courante.
Pour une configuration plus avancée, [[yii\i18n\Formatter::numberFormatterOptions]] et [[yii\i18n\Formatter::numberFormatterTextOptions]] peuvent être utilisés pour configurer la classe [NumberFormater (formateur de nombres)](http://php.net/manual/en/class.numberformatter.php) utilisée en interne pour implémenter le formateur. Par exemple, pour ajuster la valeur minimum et maximum des chiffres fractionnaires, vous pouvez configurer la propriété [[yii\i18n\Formatter::numberFormatterOptions]] comme ceci :
```php
'numberFormatterOptions' => [
NumberFormatter::MIN_FRACTION_DIGITS => 0,
NumberFormatter::MAX_FRACTION_DIGITS => 2,
]
```
## Autres formats <span id="other"></span>
En plus des formats de date, temps et nombre, Yii prend aussi en charge les autres formats communément utilisés, y compris :
- [[yii\i18n\Formatter::asRaw()|raw]]: la valeur est affichée telle quelle, il s'agit d'un pseudo-formateur qui n'a pas d'effet, à l'exception des valeurs `null` qui sont affichées en utilisant la propriété [[nullDisplay]].
- [[yii\i18n\Formatter::asText()|text]]: la valeur est encodée HTML. C'est le format par défaut utilisé par les [données des colonnes du widget GridView](output-data-widgets.md#data-column).
- [[yii\i18n\Formatter::asNtext()|ntext]]: la valeur est formatée comme un texte simple encodé HTML avec conversion des retours à la ligne en balise break.
- [[yii\i18n\Formatter::asParagraphs()|paragraphs]]: la valeur est formatée comme un paragraphe de texte encodé HTML à l'intérieur d'une balise `<p>`.
- [[yii\i18n\Formatter::asHtml()|html]]: la valeur est purifiée en utilisant [[HtmlPurifier]] pour éviter les attaques XSS. Vous pouvez passer les options additionnelles telles que `['html', ['Attr.AllowedFrameTargets' => ['_blank']]]`.
- [[yii\i18n\Formatter::asEmail()|email]]: la valeur est encodé comme un lien `mailto`.
- [[yii\i18n\Formatter::asImage()|image]]: la valeur est formatée comme une balise image.
- [[yii\i18n\Formatter::asUrl()|url]]: la valeur est formatée comme un hyperlien.
- [[yii\i18n\Formatter::asBoolean()|boolean]]: la valeur est formatée comme une valeur booléenne. Par défaut `true` est rendu par `Yes` et `false` par `No`, traduit dans la langue courante de l'application. Vous pouvez ajuster cela en configurant la propriété [[yii\i18n\Formatter::booleanFormat]].
## Valeurs nulles (null) <span id="null-values"></span>
Les valeurs *null* sont formatées spécialement. Au lieu d'afficher une chaîne de caractères vide, le formateur la convertit en une chaîne de caractères prédéfinie dont la valeur par défaut est `(not set)` traduite dans la langue courante de l'application. Vous pouvez configurer la propriété [[yii\i18n\Formatter::nullDisplay|nullDisplay]] pour personnaliser cette chaîne de caractères.
## Localisation des formats de données <span id="localizing-data-format"></span>
Comme nous l'avons mentionné précédemment, le formateur utilise la [[yii\i18n\Formatter::locale|locale]] courante pour déterminer comment formater une valeur qui soit convenable dans la cible pays/région. Par exemple, la même valeur de date est formatée différemment pour différentes locales :
```php
Yii::$app->formatter->locale = 'en-US';
echo Yii::$app->formatter->asDate('2014-01-01'); // affiche : January 1, 2014
Yii::$app->formatter->locale = 'de-DE';
echo Yii::$app->formatter->asDate('2014-01-01'); // affiche : 1. Januar 2014
Yii::$app->formatter->locale = 'ru-RU';
echo Yii::$app->formatter->asDate('2014-01-01'); // affiche : 1 января 2014 г.
```
Par défaut, la [[yii\i18n\Formatter::locale|locale]] est déterminée par la valeur de [[yii\base\Application::language]]. Vous pouvez la redéfinir en définissant la propriété [[yii\i18n\Formatter::locale]] explicitement.
> Note: le formateur de Yii a besoin de l'[extension intl de PHP](http://php.net/manual/en/book.intl.php) pour prendre en charge la localisation des formats de données. Parce que différentes versions de la bibliothèque ICU compilées par PHP produisent des résultats de formatage différents, il est recommandé que vous utilisiez la même version de la bibliothèque ICU pour tous vos environnements. Pour plus de détails, reportez-vous au tutoriel [Configuration de votre environnement PHP pour l'internationalisation](tutorial-i18n.md#setup-environment).
>
> Si l'extension intl extension n'est pas installée, les données ne sont pas localisées.
>
> Notez que pour les valeurs de dates qui sont antérieures à l'année 1901, ou postérieures à 2038, la localisation n'est pas faite sur les systèmes 32bits, même si l'extension intl est installée. Cela est dû au fait que, dans ce cas, ICU utilise des horodatages UNIX 32bits pour les valeurs de date.

58
docs/guide-fr/output-pagination.md

@ -0,0 +1,58 @@
Pagination
==========
Lorsqu'il y a trop de données à afficher sur une seule page, une stratégie courante consiste à les afficher en de multiples pages, et sur chacune des pages, à n'afficher qu'une fraction réduite des données. Cette stratégie est connue sous le nom de *pagination*.
Yii utilise un objet [[yii\data\Pagination]] pour représenter les informations d'un schéma de pagination. En particulier :
* [[yii\data\Pagination::$totalCount|nombre total (*total count*)]] spécifie le nombre total d'items de données. Notez que cela est ordinairement beaucoup plus élevé que le nombre d'items de données que l'on a besoin d'afficher sur une unique page.
* [[yii\data\Pagination::$pageSize|taille de la page (*page size*)]] spécifie combien d'items de données chaque page contient. La valeur par défaut est 20.
* [[yii\data\Pagination::$page|page courante (*current page*)]] donne la numéro de la page courante (qui commence à zéro). La valeur par défaut est 0, ce qui indique la première page.
Avec un objet [[yii\data\Pagination]] pleinement spécifié, vous pouvez retrouver et afficher partiellement des données. Par exemple, si vous allez chercher des données dans une base de données, vous pouvez spécifier les clauses `OFFSET` et `LIMIT` de la requête de base de données avec les valeurs correspondantes fournies par l'objet pagination. Un exemple est présenté ci-dessous.
```php
use yii\data\Pagination;
// construit une requêt de base de données pour obtenir tous les articles dont le *status* vaut 1
$query = Article::find()->where(['status' => 1]);
// obtient le nombre total d'articles (mais ne va pas chercher les données articles pour le moment)
$count = $query->count();
// crée un objet pagination en lui passant le nombre total d'items
$pagination = new Pagination(['totalCount' => $count]);
// limite la requête en utilisant l'objet pagination et va chercher les articles
$articles = $query->offset($pagination->offset)
->limit($pagination->limit)
->all();
```
Mais quelle page d'article est retournée par l'exemple ci-dessus ? Cela dépend d'un paramètre de la requête nommé `page`. Par défaut, l'objet pagination essaye de définir le paramètre `page` avec la valeur de la [[yii\data\Pagination::$page|page courante (*current page*)]]. Si le paramètre n'est pas fourni, il prend la valeur par défaut `0`.
Pour faciliter la construction des élément de l'interface utilisateur qui prennent en charge la pagination, Yii fournit le composant graphique [[yii\widgets\LinkPager]] qui affiche une liste de boutons de page sur lesquels l'utilisateur peut cliquer pour préciser quelle page de données doit être affichée. Ce composant graphique accepte en paramètre un objet pagination afin de savoir quelle est la page courante et combien de boutons de page afficher. Par exemple :
```php
use yii\widgets\LinkPager;
echo LinkPager::widget([
'pagination' => $pagination,
]);
```
Si vous voulez construire des éléments d'interface graphique à la main, vous pouvez utiliser [[yii\data\Pagination::createUrl()]] pour créer des URL qui conduisent à différentes pages. La méthode requiert un paramètre de page et crée une URL formatée correctement qui contient le paramètre de page. Par exemple :
```php
// spécifie la route que l'URL à créer doit utiliser,
// si vous ne la spécifiez pas, la route actuellement requise est utilisée
$pagination->route = 'article/index';
// affiche : /index.php?r=article%2Findex&page=100
echo $pagination->createUrl(100);
// affiche : /index.php?r=article%2Findex&page=101
echo $pagination->createUrl(101);
```
> Tip: vous pouvez personnaliser le nom du paramètre de requête `page` en configurant la propriété [[yii\data\Pagination::pageParam|pageParam]] lors de la création de l'objet pagination.

68
docs/guide-fr/output-sorting.md

@ -0,0 +1,68 @@
Tri
===
Lors de l'affichage de multiples lignes de données, on a souvent besoin des trier les données en fonction des valeurs de certaines colonnes spécifiées par l'utilisateur. Yii utilise l'objet [[yii\data\Sort]] pour représenter les information sur le schéma de triage. En particulier :
* [[yii\data\Sort::$attributes|attributes]] spécifie les *attributs* grâce auxquels les données peuvent être triées. Un attribut peut être aussi simple qu'un [attribut de modèle](structure-models.md#attributes). Il peut aussi être un composite combinant le multiples attributs de modèles ou de colonnes de base de données. Nous apportons des informations plus détaillées dans la suite de cette page.
* [[yii\data\Sort::$attributeOrders|attributeOrders]] fournit la direction de l'ordre de tri pour chacun des attributs.
* [[yii\data\Sort::$orders|orders]] fournit les directions de tri en terme de colonnes de bas niveau.
Pour utiliser [[yii\data\Sort]], commencez par déclarer quels attributs peuvent être triés. Puis retrouvez les informations d'ordre de tri courantes de [[yii\data\Sort::$attributeOrders|attributeOrders]] ou [[yii\data\Sort::$orders|orders]], et utilisez-les pour personnaliser votre requête de données. Par exemple :
```php
use yii\data\Sort;
$sort = new Sort([
'attributes' => [
'age',
'name' => [
'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC],
'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC],
'default' => SORT_DESC,
'label' => 'Name',
],
],
]);
$articles = Article::find()
->where(['status' => 1])
->orderBy($sort->orders)
->all();
```
Dans l'exemple qui précède, deux attributs sont déclarés pour l'objet [[yii\data\Sort|Sort]] : `age` et `name`.
L'attribut `age` est un attribut *simple* correspondant à l'attribut `age` de la classe d'enregistrement actif `Article`. Il équivaut à la déclaration suivante :
```php
'age' => [
'asc' => ['age' => SORT_ASC],
'desc' => ['age' => SORT_DESC],
'default' => SORT_ASC,
'label' => Inflector::camel2words('age'),
]
```
L'attribut `name` est un attribut *composite* défini par `first_name` et `last_name` de la classe `Article`. Il est déclaré en utilisant la structure de tableau suivante :
- Les éléments `asc` et `desc` spécifient comment trier selon l'attribut dans la direction croissante et décroissante, respectivement. Leurs valeurs représentent les colonnes réelles et les directions dans lesquelles les données sont triées. Vous pouvez spécifier une ou plusieurs colonnes pour préciser un tri simple ou un tri composite.
- L'élément `default` spécifie la direction dans laquelle l'attribut doit être trié lorsqu'il est initialement requis. Sa valeur par défaut est l'ordre croissant, ce qui signifie que si les données n'ont pas été triées auparavant et que vous demandez leur tri par cet attribut, elles sont triées par cette attribut dans la direction croissante.
- L'élément `label` spécifie quelle étiquette doit être utilisée lors de l'appel de [[yii\data\Sort::link()]] pour créer un lien de tri. Si cet élément n'est pas spécifié, la fonction [[yii\helpers\Inflector::camel2words()]] est appelée pour générer une étiquette à partir du nom de l'attribut. Notez que cette étiquette n'est pas encodée HTML.
> Info: vous pouvez fournir la valeur de [[yii\data\Sort::$orders|orders]] à la requête de base de données pour construire sa clause `ORDER BY`. N'utilisez pas [[yii\data\Sort::$attributeOrders|attributeOrders]], parce que certains attributs peuvent être composites et ne peuvent pas être reconnus par la requête de base de données.
Vous pouvez appeler [[yii\data\Sort::link()]] pour générer un hyperlien sur lequel l'utilisateur peut cliquer pour demander le tri des données selon l'attribut spécifié. Vous pouvez aussi appeler [[yii\data\Sort::createUrl()]] pour créer une URL susceptible d'être triée. Par exemple :
```php
// spécifie la route que l'URL à créer doit utiliser,
// si vous ne la spécifiez pas, la route couramment requise est utilisée
$sort->route = 'article/index';
// affiche des liens conduisant à trier par *name* (nom) et *age*, respectivement
echo $sort->link('name') . ' | ' . $sort->link('age');
// affiche : /index.php?r=article%2Findex&sort=age
echo $sort->createUrl('age');
```
[[yii\data\Sort]] vérifie le paramètre `sort` pour savoir quels attributs sont requis pour le tri. Vous pouvez spécifier un ordre de tri par défaut via [[yii\data\Sort::defaultOrder]] lorsque le paramètre de requête est absent. Vous pouvez aussi personnaliser le nom du paramètre de requête en configurant la porpriété [[yii\data\Sort::sortParam|sortParam]].

27
docs/guide-fr/runtime-bootstrapping.md

@ -0,0 +1,27 @@
Amorçage
=============
L'amorçage fait référence au processus de préparation de l'environnement avant qu'une application ne démarre, pour résoudre et traiter une requête d'entrée. L'amorçage se fait en deux endroits : le [script d'entrée](structure-entry-scripts.md) et l'[application](structure-applications.md).
Dans le [script d'entrée](structure-entry-scripts.md), les classes de chargement automatique (*autoloaders*) pour différentes bibliothèques sont enregistrées. Cela inclut la classe de chargement automatique de Composer via son fichier `autoload.php` et la classe de chargement automatique de Yii via son fichier de classe `Yii`. Ensuite, le script d'entrée charge la [configuration](concept-configurations.md) de l'application et crée une instance d'[application](structure-applications.md).
Dans le constructeur de l'application, le travail d'amorçage suivant est effectué :
1. La méthode [[yii\base\Application::preInit()|preInit()]] est appelée. Elle configure quelques propriétés de haute priorité de l'application, comme [[yii\base\Application::basePath|le chemin de base (*basePath*)]].
2. Le [[yii\base\Application::errorHandler|gestionnaire d'erreurs]] est enregistré.
3. Les propriétés qui utilisent la configuration de l'application sont initialisées.
4. La méthode [[yii\base\Application::init()|init()]] est appelée. À son tour elle appelle la méthode [[yii\base\Application::bootstrap()|bootstrap()]] pour exécuter les composants d'amorçage.
- Le fichier de manifeste des extensions `vendor/yiisoft/extensions.php` est inclus.
- Les[composants d'amorçage](structure-extensions.md#bootstrapping-classes) déclarés par les extensions sont créés et exécutés
- Les [composants d'application(structure-application-components.md) et/ou les [modules](structure-modules.md) déclarés dans la [propriété bootstrap](structure-applications.md#bootstrap) de l'application sont créés et exécutés.
Comme le travail d'amorçage doit être fait avant *chacune* des requêtes, il est très important de conserver ce processus aussi léger et optimisé que possible.
Évitez d'enregistrer trop de composants d'amorçage. Un composant d'amorçage est seulement nécessaire s'il doit participer à tout le cycle de vie de la prise en charge des requêtes. Par exemple,si un module a besoin d'enregistrer des règles d'analyse additionnelles, il doit être listé dans la [propriété bootstrap](structure-applications.md#bootstrap) afin que les nouvelles règles d'URL prennent effet avant qu'elles ne soient utilisées pour résoudre des requêtes.
Dans le mode production, activez un cache bytecode, tel que [PHP OPcache] ou [APC], pour minimiser le temps nécessaire à l'inclusion et à l'analyse des fichiers PHP.
[PHP OPcache]: http://php.net/manual/en/intro.opcache.php
[APC]: http://php.net/manual/en/book.apc.php
Quelques applications volumineuses ont des [configurations](concept-configurations.md) d'application très complexes qui sont divisées en fichiers de configuration plus petits. Si c'est le cas, envisagez de mettre tout le tableau de configuration en cache et de le charger directement à partir cache avant la création de l'instance d'application dans le script d'entrée.

195
docs/guide-fr/runtime-handling-errors.md

@ -0,0 +1,195 @@
Gestion des erreurs
===================
Yii inclut un [[yii\web\ErrorHandler|gestionnaire d'erreur]] pré-construit qui rend la gestion des erreurs bien plus agréable qu'auparavant. En particulier, le gestionnaire d'erreurs de Yii possède les fonctionnalités suivantes pour améliorer la gestion des erreurs.
* Toutes les erreurs PHP non fatales (p. ex. avertissements, notifications) sont converties en exceptions susceptibles d'être interceptées.
* Les exceptions et les erreurs fatales sont affichées avec les informations détaillées de la pile des appels et les lignes de code source en mode *debug*.
* Prise en charge de l'utilisation d'une [action de contrôleur](structure-controllers.md#actions) dédiée à l'affichage des erreurs.
* Prise en charge de différents formats de réponse d'erreur.
Le [[yii\web\ErrorHandler|gestionnaire d'erreur]] est activé par défaut. Vous pouvez le désactiver en définissant la constante `YII_ENABLE_ERROR_HANDLER` à `false` (faux) dans le [script d'entrée](structure-entry-scripts.md) de votre application.
## Utilisation du gestionnaire d'erreurs <span id="using-error-handler"></span>
Le [[yii\web\ErrorHandler|gestionnaire d'erreurs]] est enregistré en tant que [composant d'application](structure-application-components.md) nommé `errorHandler`. Vous pouvez le configurer dans la configuration de l'application comme indiqué ci-dessous :
```php
return [
'components' => [
'errorHandler' => [
'maxSourceLines' => 20,
],
],
];
```
Avec la configuration qui précède, le nombre de lignes de code source à afficher dans les pages d'exception est limité à 20.
Comme cela a déjà été dit, le gestionnaire d'erreur transforme toutes les erreurs PHP non fatales en exception susceptibles d'être interceptées. Cela signifie que vous pouvez utiliser le code suivant pour vous servir de cette gestion d'erreurs :
```php
use Yii;
use yii\base\ErrorException;
try {
10/0;
} catch (ErrorException $e) {
Yii::warning("Division by zero.");
}
// l'exécution continue...
```
Si vous désirez afficher une page d'erreur disant à l'utilisateur que sa requête est invalide ou inattendue, vous pouvez simplement lever une [[yii\web\HttpException|exception HTTP]], comme l'exception [[yii\web\NotFoundHttpException]]. Le gestionnaire d'erreurs définit alors correctement le code d'état HTTP de la réponse et utilise une vue d'erreur appropriée pour afficher le message d'erreur.
```php
use yii\web\NotFoundHttpException;
throw new NotFoundHttpException();
```
## Personnalisation de l'affichage des erreurs <span id="customizing-error-display"></span>
Le [[yii\web\ErrorHandler|gestionnaire d'erreurs]] ajuste l'affichage de l'erreur en tenant compte de la valeur de la constante `YII_DEBUG`. Quand `YII_DEBUG` est égale à `true` (vrai) (ce qui signifie que le mode *debug* est activé), le gestionnaire d'erreurs affiche les exceptions avec le détail de la pile des appels et les lignes de code apportant de l'aide au débogage. Quand `YII_DEBUG` est égale à `false` (faux), seule le message d'erreur est affiché pour ne pas révéler des informations sensibles sur l'application.
> Info: si une exception est un descendant de la classe [[yii\base\UserException]], aucune pile des appels n'est affichée, et ceci indépendamment de la valeur `YII_DEBUG`. Cela tient au fait que de telles exceptions résultent d'erreurs commises par l'utilisateur et que les développeurs n'ont rien à corriger.
Par défaut, le [[yii\web\ErrorHandler|gestionnaire d'erreurs]] affiche les erreurs en utilisant deux [vues](structure-views.md):
* `@yii/views/errorHandler/error.php`: utilisée lorsque les erreurs doivent être affichées SANS les informations sur la pile des appels. Quand `YII_DEBUG` est égale à `false`, c'est la seule vue d'erreur à afficher.
* `@yii/views/errorHandler/exception.php`: utilisée lorsque les erreurs doivent être affichées AVEC les informations sur la pile des appels.
Vous pouvez configurer les propriétés [[yii\web\ErrorHandler::errorView|errorView]] et [[yii\web\ErrorHandler::exceptionView|exceptionView]] du gestionnaire d'erreur pour utiliser vos propres vues afin de personnaliser l'affichage des erreurs.
### Utilisation des actions d'erreurs <span id="using-error-actions"></span>
Une meilleure manière de personnaliser l'affichage des erreurs est d'utiliser des [actions](structure-controllers.md) d'erreur dédiées. Pour cela, commencez par configurer la propriété [[yii\web\ErrorHandler::errorAction|errorAction]] du composant `errorHandler` comme indiqué ci-après :
```php
return [
'components' => [
'errorHandler' => [
'errorAction' => 'site/error',
],
]
];
```
La propriété [[yii\web\ErrorHandler::errorAction|errorAction]] accepte une [route](structure-controllers.md#routes) vers une action. La configuration ci-dessus établit que lorsqu'une erreur doit être affichée sans information de la pile des appels, l'action `site/error` doit être exécutée.
Vous pouvez créer une action `site/error` comme ceci :
```php
namespace app\controllers;
use Yii;
use yii\web\Controller;
class SiteController extends Controller
{
public function actions()
{
return [
'error' => [
'class' => 'yii\web\ErrorAction',
],
];
}
}
```
Le code ci-dessus définit l'action `error` en utilisant la classe [[yii\web\ErrorAction]] qui rend une erreur en utilisant une vue nommée `error`.
En plus d'utiliser [[yii\web\ErrorAction]], vous pouvez aussi définir l'action `error` en utilisant une méthode d'action similaire à la suivante :
```php
public function actionError()
{
$exception = Yii::$app->errorHandler->exception;
if ($exception !== null) {
return $this->render('error', ['exception' => $exception]);
}
}
```
Vous devez maintenant créer un fichier de vue `views/site/error.php`. Dans ce fichier de vue, vous pouvez accéder aux variables suivantes si l'action d'erreur est définie en tant que [[yii\web\ErrorAction]]:
* `name`: le nom de l'erreur ;
* `message`: le message d'erreur ;
* `exception`: l'objet exception via lequel vous pouvez retrouver encore plus d'informations utiles telles que le code d'état HTTP, le code d'erreur, la pile des appels de l'erreur, etc.
> Info: si vous êtes en train d'utiliser le [modèle de projet *basic*](start-installation.md) ou le [modèle de projet avancé](https://github.com/yiisoft/yii2-app-advanced/blob/master/docs/guide/README.md), l'action d'erreur est la vue d'erreur sont déjà définies pour vous.
> Note: si vous avez besoin de rediriger dans un gestionnaire d'erreur, faites-le de la manière suivante :
>
> ```php
> Yii::$app->getResponse()->redirect($url)->send();
> return;
> ```
### Personnalisation du format de la réponse d'erreur <span id="error-format"></span>
Le gestionnaire d'erreurs affiche les erreurs en respectant le réglage de format de la [réponse](runtime-responses.md). Si le [[yii\web\Response::format|format de la réponse]] est `html`, il utilise la vue d'erreur ou d'exception pour afficher les erreurs, comme c'est expliqué dans la sous-section précédente. Pour les autres formats de réponse, le gestionnaire d'erreurs assigne la représentation de l'erreur sous forme de tableau à la propriété [[yii\web\Response::data]] qui est ensuite convertie dans le format désiré. Par exemple, si le format de la réponse est `json`, vous pourriez voir une réponse similaire à la suivante :
```
HTTP/1.1 404 Not Found
Date: Sun, 02 Mar 2014 05:31:43 GMT
Server: Apache/2.2.26 (Unix) DAV/2 PHP/5.4.20 mod_ssl/2.2.26 OpenSSL/0.9.8y
Transfer-Encoding: chunked
Content-Type: application/json; charset=UTF-8
{
"name": "Not Found Exception",
"message": "The requested resource was not found.",
"code": 0,
"status": 404
}
```
Vous pouvez personnaliser le format de réponse d'erreur en répondant à l'événement `beforeSend` du composant `response` dans la configuration de l'application :
```php
return [
// ...
'components' => [
'response' => [
'class' => 'yii\web\Response',
'on beforeSend' => function ($event) {
$response = $event->sender;
if ($response->data !== null) {
$response->data = [
'success' => $response->isSuccessful,
'data' => $response->data,
];
$response->statusCode = 200;
}
},
],
],
];
```
Le code précédent formate la réponse d'erreur comme suit :
```
HTTP/1.1 200 OK
Date: Sun, 02 Mar 2014 05:31:43 GMT
Server: Apache/2.2.26 (Unix) DAV/2 PHP/5.4.20 mod_ssl/2.2.26 OpenSSL/0.9.8y
Transfer-Encoding: chunked
Content-Type: application/json; charset=UTF-8
{
"success": false,
"data": {
"name": "Not Found Exception",
"message": "The requested resource was not found.",
"code": 0,
"status": 404
}
}
```

314
docs/guide-fr/runtime-logging.md

@ -0,0 +1,314 @@
Enregistrements des messages
============================
Yii fournit une puissante base structurée d'enregistrement des messages qui est très personnalisable et extensible. En utilisant cette base structurée, vous pouvez facilement enregistrer des types variés de messages, les filtrer et les rassembler dans différentes cibles comme les bases de données et les courriels.
L'utilisation de la base structurée d'enregistrement des messages de Yii nécessite de suivre les étapes suivantes :
* Enregistrer les [messages](#log-messages) à différents endroits de votre code ;
* Configurer [cibles d'enregistrement](#log-targets) dans la configuration de l'application pour filtrer et exporter les messages enregistrés ;
* Examiner les messages enregistrés, filtrés et exportés par les différentes cibles (p. ex. [débogueur de Yii](tool-debugger.md)).
Dans cette section, nous décrivons principalement les deux premières étapes.
## Messages enregistrés <span id="log-messages"></span>
Enregistrer des messages est aussi simple que d'appeler une des méthodes suivantes :
* [[Yii::trace()]]: enregistre un message pour garder une trace de comment un morceau de code fonctionne. Cela est utilisé principalement en développement.
* [[Yii::info()]]: enregistre un message qui contient quelques informations utiles.
* [[Yii::warning()]]: enregistre un message d'avertissement qui indique que quelque chose d'inattendu s'est produit.
* [[Yii::error()]]: enregistre une erreur fatale qui doit être analysée dès que possible.
Ces méthodes enregistrent les messages à différents niveaux de sévérité et dans différentes catégories. Elles partagent la même signature `function ($message, $category = 'application')`, où `$message` représente le message à enregistrer, tandis que `$category` est la catégorie de ce message. Le code de l'exemple qui suit enregistre un message de trace dans la catégorie `application`:
```php
Yii::trace('start calculating average revenue');
```
> Info: les messages enregistrés peuvent être des chaînes de caractères aussi bien que des données complexes telles que des tableaux ou des objets. Il est de la responsabilité des [cibles d'enregistrement](#log-targets) de traiter correctement ces messages. Par défaut, si un message enregistré n'est pas un chaîne de caractères, il est exporté comme une chaîne de caractères en appelant la méthode [[yii\helpers\VarDumper::export()]].
Pour mieux organiser et filtrer les messages enregistrés, il est recommandé que vous spécifiiez une catégorie appropriée pour chacun des messages. Vous pouvez choisir une schéma de nommage hiérarchisé pour les catégories, ce qui facilitera le filtrage des messages par les [cibles d'enregistrement](#log-targets) sur la base de ces catégories. Un schéma de nommage simple et efficace est d'utiliser la constante magique `__METHOD__` de PHP dans les noms de catégorie. Par exemple :
```php
Yii::trace('start calculating average revenue', __METHOD__);
```
La constante magique `__METHOD__` est évaluée comme le nom de la méthode (préfixée par le nom pleinement qualifié de la classe), là où la constante apparaît. Par exemple, elle est égale à `'app\controllers\RevenueController::calculate'` si la ligne suivante est utilisée dans cette méthode.
> Info: les méthodes d'enregistrement décrites plus haut sont en fait des raccourcis pour la méthode [[yii\log\Logger::log()|log()]] de l'[[yii\log\Logger|objet logger]] qui est un singleton accessible via l'expression `Yii::getLogger()`. Lorsque suffisamment de messages ont été enregistrés, ou quand l'application se termine, l'objet *logger* appelle un [[yii\log\Dispatcher|distributeur de messages]] pour envoyer les messages enregistrés aux [cibles d'enregistrement](#log-targets).
## Cibles d'enregistrement <span id="log-targets"></span>
Une cible d'enregistrement est une instance de la classe [[yii\log\Target]] ou d'une de ses classe filles. Elle filtre les messages enregistrés selon leur degré de sévérité et leur catégorie et les exporte vers un média donné. Par exemple, une [[yii\log\DbTarget|cible base données]] exporte les messages enregistrés et filtrés vers une base de données, tandis qu'une [[yii\log\EmailTarget|cible courriel]] exporte les messages vers l'adresse de courriel spécifiée.
Vous pouvez enregistrer plusieurs cibles d'enregistrement dans votre application en les configurant, via le [composant d'application](structure-application-components.md)`log` dans la configuration de l'application, de la manière suivante :
```php
return [
// le composant "log" doit être chargé lors de la période d'amorçage
'bootstrap' => ['log'],
'components' => [
'log' => [
'targets' => [
[
'class' => 'yii\log\DbTarget',
'levels' => ['error', 'warning'],
],
[
'class' => 'yii\log\EmailTarget',
'levels' => ['error'],
'categories' => ['yii\db\*'],
'message' => [
'from' => ['log@example.com'],
'to' => ['admin@example.com', 'developer@example.com'],
'subject' => 'Database errors at example.com',
],
],
],
],
],
];
```
> Note: le composant `log` doit être chargé durant le [processus d'amorçage](runtime-bootstrapping.md) afin qu'il puisse distribuer les messages enregistrés aux cibles rapidement. C'est pourquoi il est listé dans le tableau `bootstrap` comme nous le montrons ci-dessus.
Dans le code précédent, deux cibles d'enregistrement sont enregistrées dan la propriété [[yii\log\Dispatcher::targets]] :
* la première cible sélectionne les messages d'erreurs et les avertissements et les sauvegarde dans une table de base de données;
* la deuxième cible sélectionne les messages d'erreur dont le nom de la catégorie commence par `yii\db\`, et les envoie dans un courriel à la fois à `admin@example.com` et à `developer@example.com`.
Yii est fourni avec les cibles pré-construites suivantes. Reportez-vous à la documentation de l'API pour en savoir plus sur ces classes, en particulier comment les configurer et les utiliser.
* [[yii\log\DbTarget]]: stocke les messages enregistrés dans une table de base de données.
* [[yii\log\EmailTarget]]: envoie les messages enregistrés vers une adresse de courriel spécifiée préalablement.
* [[yii\log\FileTarget]]: sauvegarde les messages enregistrés dans des fichiers.
* [[yii\log\SyslogTarget]]: sauvegarde les messages enregistrés vers *syslog* en appelant la fonction PHP `syslog()`.
Dans la suite de ce document, nous décrivons les fonctionnalités communes à toutes les cibles d'enregistrement.
### Filtrage des messages <span id="message-filtering"></span>
Vous pouvez configurer les propriétés [[yii\log\Target::levels|levels]] et [[yii\log\Target::categories|categories]] de chacune des cibles d'enregistrement pour spécifier les niveaux de sévérité et les catégories que la cible doit traiter.
La propriété [[yii\log\Target::levels|levels]] accepte un tableau constitué d'une ou plusieurs des valeurs suivantes :
* `error`: correspondant aux messages enregistrés par [[Yii::error()]].
* `warning`: correspondant aux messages enregistrés par [[Yii::warning()]].
* `info`: correspondant aux messages enregistrés par [[Yii::info()]].
* `trace`: correspondant aux messages enregistrés par [[Yii::trace()]].
* `profile`: correspondant aux messages enregistrés par [[Yii::beginProfile()]] et [[Yii::endProfile()]], et qui sera expliqué en détails dans la sous-section [Profilage de la performance](#performance-profiling).
Si vous ne spécifiez pas la propriété [[yii\log\Target::levels|levels]], cela signifie que la cible traitera les messages de *n'importe quel* niveau de sévérité.
La propriété [[yii\log\Target::categories|categories]] accepte un tableau constitué de noms ou de motifs de noms de catégorie de messages. Une cible ne traite
que les messages dont la catégorie est trouvée ou correspond aux motifs de ce tableau. Un motif de nom de catégorie est un préfixe de nom de catégorie
suivi d'une astérisque `*`. Un nom de catégorie correspond à un motif de nom de catégorie s'il commence par le préfixe du motif.
Par exemple, `yii\db\Command::execute` et `yii\db\Command::query` sont utilisés comme noms de catégorie pour les messages enregistrés dans la classe [[yii\db\Command]]. Ils correspondent tous deux au motif `yii\db\*`.
Si vous ne spécifiez pas la propriété [[yii\log\Target::categories|categories]], cela signifie que le cible traite les messages de *n'importe quelle* catégorie.
En plus d'inscrire des catégories en liste blanche via la propriété [[yii\log\Target::categories|categories]], vous pouvez également inscrire certaines catégories
en liste noire via la propriété [[yii\log\Target::except|except]]. Si la catégorie d'un message est trouvée ou correspond à un des motifs de cette propriété, ce message n'est PAS traité par la cible.
La configuration suivante de cible spécifie que la cible traitera les messages d'erreur ou d'avertissement des catégories dont le nom correspond soit à `yii\db\*`, soit `yii\web\HttpException:*`, mais pas `yii\web\HttpException:404`.
```php
[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
'categories' => [
'yii\db\*',
'yii\web\HttpException:*',
],
'except' => [
'yii\web\HttpException:404',
],
]
```
> Info: lorsqu'une exception HTTP est capturée par le [gestionnaire d'erreur](runtime-handling-errors.md), un message d'erreur est enregistré avec un non de catégorie dont le format est `yii\web\HttpException:ErrorCode`. Par exemple, l'exception [[yii\web\NotFoundHttpException]] provoque un message d'erreur de catégorie `yii\web\HttpException:404`.
### Formatage des messages <span id="message-formatting"></span>
Les cibles d'enregistrement exportent les messages enregistrés et filtrés dans un certain format. Par exemple, si vous installez une cible d'enregistrement de classe [[yii\log\FileTarget]], vous pouvez trouver un message enregistré similaire au suivant dans le fichier `runtime/log/app.log` file:
```
2014-10-04 18:10:15 [::1][][-][trace][yii\base\Module::getModule] Loading module: debug
```
Par défaut, les messages enregistrés sont formatés comme suit par la méthode [[yii\log\Target::formatMessage()]]:
```
Horodate [adresse IP][identifiant utilisateur][identifiant de session][niveau de sévérité][catégorie] Texte du message
```
Vous pouvez personnaliser ce format en configurant la propriété [[yii\log\Target::prefix]] qui accepte une fonction PHP appelable qui retourne un message de préfixe personnalisé. Par exemple, le code suivant configure une cible d'enregistrement pour qu'elle préfixe chaque message enregistré avec l'identifiant de l'utilisateur courant (l'adresse IP et l'identifiant de session étant retirés pour des raisons de protection de la vie privée).
```php
[
'class' => 'yii\log\FileTarget',
'prefix' => function ($message) {
$user = Yii::$app->has('user', true) ? Yii::$app->get('user') : null;
$userID = $user ? $user->getId(false) : '-';
return "[$userID]";
}
]
```
En plus des préfixes de messages, les cibles d'enregistrement ajoutent aussi quelques informations de contexte à chaque lot de messages enregistrés.
Par défaut, les valeurs de ces variables PHP globales sont incluses : `$_GET`, `$_POST`, `$_FILES`, `$_COOKIE`, `$_SESSION` et `$_SERVER`. Vous pouvez ajuster ce comportement en configurant la propriété [[yii\log\Target::logVars]] avec les noms des variables globales que vous voulez que la cible d'enregistrement inclue. Par exemple, la cible d'enregistrement suivante spécifie que seules les valeurs de la variable `$_SERVER` seront ajoutées aux messages enregistrés.
```php
[
'class' => 'yii\log\FileTarget',
'logVars' => ['_SERVER'],
]
```
Vous pouvez configurer `logVars` comme un tableau vide pour désactiver totalement l'inclusion d'informations de contexte. Ou si vous voulez mettre en œuvre votre propre façon de fournir les informations contextuelles, vous pouvez redéfinir la méthode [[yii\log\Target::getContextMessage()]].
### Niveaux de la trace de message <span id="trace-level"></span>
Lors du développement, vous cherchez souvent à voir d'où provient chacun des messages enregistrés. Cela est possible en configurant la propriété [[yii\log\Dispatcher::traceLevel|traceLevel]] du composant`log` de la façon suivante :
```php
return [
'bootstrap' => ['log'],
'components' => [
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [...],
],
],
];
```
La configuration de l'application ci-dessus statue que le [[yii\log\Dispatcher::traceLevel|niveau de trace ]] sera 3 si `YII_DEBUG` est activé et 0 si `YII_DEBUG` est désactivé. Cela veut dire que, si `YII_DEBUG` est activé, au plus trois niveaux de la pile des appels seront ajoutés à chaque message enregistré, là où le messages est enregistré; et, si `YII_DEBUG` est désactivé, aucune information de la pile des appels ne sera incluse.
> Info: obtenir les informations de la pile des appels n'a rien de trivial. En conséquence, vous ne devriez utiliser cette fonctionnalité que durant le développement ou le débogage d'une application.
### Purge et exportation des messages <span id="flushing-exporting"></span>
Comme nous l'avons dit plus haut, les messages enregistrés sont conservés dans un tableau par l'[[yii\log\Logger|objet *logger*]]. Pour limiter la consommation de mémoire par ce tableau, l'objet *logger* purge les messages enregistrés vers les [cibles d'enregistrement](#log-targets) chaque fois que leur nombre atteint une certaine valeur. Vous pouvez personnaliser ce nombre en configurant la propriété [[yii\log\Dispatcher::flushInterval|flushInterval]] du composant `log` :
```php
return [
'bootstrap' => ['log'],
'components' => [
'log' => [
'flushInterval' => 100, // default is 1000
'targets' => [...],
],
],
];
```
> Info: la purge des messages intervient aussi lorsque l'application se termine, ce qui garantit que les cibles d'enregistrement reçoivent des messages enregistrés complets.
Lorsque l'[[yii\log\Logger|objet *logger*]] purge les messages enregistrés vers les [cibles d'enregistrement](#log-targets), ils ne sont pas exportés immédiatement. Au lieu de cela, l'exportation des messages ne se produit que lorsque la cible d'enregistrement a accumulé un certain nombre de messages filtrés. Vous pouvez personnaliser ce nombre en configurant la propriété [[yii\log\Target::exportInterval|exportInterval]] de chacune des [cibles d'enregistrement](#log-targets), comme ceci :
```php
[
'class' => 'yii\log\FileTarget',
'exportInterval' => 100, // default is 1000
]
```
À cause des niveaux de purge et d'exportation, par défaut, lorsque vous appelez `Yii::trace()` ou toute autre méthode d'enregistrement, vous ne voyez PAS immédiatement le message enregistré dans la cible. Cela peut représenter un problème pour pour certaines applications de console qui durent longtemps. Pour faire en sorte que les messages apparaissent immédiatement dans les cibles d'enregistrement, vous devriez définir les propriétés [[yii\log\Dispatcher::flushInterval|flushInterval]] et [[yii\log\Target::exportInterval|exportInterval]] toutes deux à 1, comme montré ci-après :
```php
return [
'bootstrap' => ['log'],
'components' => [
'log' => [
'flushInterval' => 1,
'targets' => [
[
'class' => 'yii\log\FileTarget',
'exportInterval' => 1,
],
],
],
],
];
```
> Note: la purge et l'exportation fréquentes de vos messages dégradent la performance de votre application.
### Activation, désactivation des cibles d'enregistrement <span id="toggling-log-targets"></span>
Vous pouvez activer ou désactiver une cible d'enregistrement en configurant sa propriété [[yii\log\Target::enabled|enabled]]. Vous pouvez le faire via la configuration de la cible d'enregistrement ou en utilisant l'instruction suivante dans votre code PHP :
```php
Yii::$app->log->targets['file']->enabled = false;
```
Le code ci-dessus, nécessite que nommiez une cible `file`, comme montré ci-dessous en utilisant des clés sous forme de chaînes de caractères dans le tableau `targets` :
```php
return [
'bootstrap' => ['log'],
'components' => [
'log' => [
'targets' => [
'file' => [
'class' => 'yii\log\FileTarget',
],
'db' => [
'class' => 'yii\log\DbTarget',
],
],
],
],
];
```
### Création d'une cible d'enregistrement <span id="new-targets"></span>
La création d'une classe de cible d'enregistrement est très simple. Vous devez essentiellement implémenter [[yii\log\Target::export()]] en envoyant le contenu du tableau des [[yii\log\Target::messages]] vers un média désigné. Vous pouvez appeler la méthode [[yii\log\Target::formatMessage()]] pour formater chacun des messages. Pour plus de détails, reportez-vous à n'importe quelle classe de cible de messages incluse dans la version de Yii.
## Profilage de la performance <span id="performance-profiling"></span>
Le profilage de la performance est un type particulier d'enregistrement de messages qui est utilisé pour mesurer le temps d'exécution de certains blocs de code et pour déterminer les goulots d'étranglement. Par exemple, la classe [[yii\db\Command]] utilise le profilage de performance pour connaître le temps d'exécution de chacune des requêtes de base de données.
Pour utiliser le profilage de la performance, commencez par identifier les blocs de code qui ont besoin d'être profilés. Puis, entourez-les de la manière suivante :
```php
\Yii::beginProfile('myBenchmark');
...le bloc de code à profiler...
\Yii::endProfile('myBenchmark');
```
`myBenchmark` représente un jeton unique identifiant un bloc de code. Plus tard, lorsque vous examinez le résultat du profilage, vous pouvez utiliser ce jeton pour localiser le temps d'exécution du bloc correspondant.
Il est important de vous assurer que les paires `beginProfile` et `endProfile` sont correctement imbriquées.
Par exemple,
```php
\Yii::beginProfile('block1');
// du code à profiler
\Yii::beginProfile('block2');
// un autre bloc de code à profiler
\Yii::endProfile('block2');
\Yii::endProfile('block1');
```
Si vous omettez `\Yii::endProfile('block1')` ou inversez l'ordre de `\Yii::endProfile('block1')` et de `\Yii::endProfile('block2')`, le profilage de performance ne fonctionnera pas.
Pour chaque bloc de code profilé, un message est enregistré avec le niveau de sévérité `profile`. Vous pouvez configurer une [cible d'enregistrement](#log-targets) pour collecter de tels messages et les exporter. L'outil [*Yii debugger*](tool-debugger.md) comporte un panneau d'affichage pré-construit des résultats de profilage.

21
docs/guide-fr/runtime-overview.md

@ -0,0 +1,21 @@
Vue d'ensemble
==============
À chaque fois qu'une application Yii prend en charge une requête, elle entreprend un flux de travail similaire.
1. Un utilisateur effectue une requête auprès du [script d'entrée](structure-entry-scripts.md) `web/index.php`.
2. Le script d'entrée charge la [configuration](concept-configurations.md) de l'application et crée une instance d'[application](structure-applications.md) pour prendre en charge la requête.
3. L'application résoud la [route](runtime-routing.md) requise avec l'aide du composant d'application [request](runtime-requests.md).
4. L'application crée une instance de [contrôleur](structure-controllers.md) pour prendre en charge le requête.
5. Le contrôleur crée une instance d'[action](structure-controllers.md) et exécute les filtres de l'action.
6. Si un [filtre](structure-filters.md) échoue, l'exécution de l'action est annulée.
7. Si tous les filtres réussissent l'action est exécutée.
8. L'action charge un [modèle](structure-models.md) de données, possiblement à partir d'une base de données.
9. L'action rend une [vue](structure-views.md), en lui passant le modèle de données.
10. Le résultat rendu est retourné au composant d'application [response](runtime-responses.md).
11. Le composant *response* envoye le résultat rendu au navigateur de l'utilisateur.
Le diagramme ci-dessous illustre comment une application prend une requête en charge.
![Cycle de vie d'une requête](images/request-lifecycle.png)
Dans cette section, nous décrivons en détails comment se déroulent quelques unes de ces étapes.

113
docs/guide-fr/runtime-requests.md

@ -0,0 +1,113 @@
Requêtes
========
Les requêtes faites à l'application sont représentées en terme d'objets [[yii\web\Request]] qui fournissent des informations telles que les paramètres de requête, les entêtes HTTP, les cookies, etc. Pour une requête donnée, vous avez accès au [composant d'application](structure-application-components.md)`request` qui, par défaut, est une instance de [[yii\web\Request]]. Dans cette section, nous décrivons comment utiliser ce composant dans vos applications.
## Paramètres de requête <span id="request-parameters"></span>
Pour obtenir les paramètres de requête, vous pouvez appeler les méthodes [[yii\web\Request::get()|get()]] et [[yii\web\Request::post()|post()]] du composant `request` component. Elles retournent les valeurs de `$_GET` et `$_POST`, respectivement. Pas exemple :
```php
$request = Yii::$app->request;
$get = $request->get();
// équivalent à : $get = $_GET;
$id = $request->get('id');
// équivalent à : $id = isset($_GET['id']) ? $_GET['id'] : null;
$id = $request->get('id', 1);
// équivalent à : $id = isset($_GET['id']) ? $_GET['id'] : 1;
$post = $request->post();
// équivalent à : $post = $_POST;
$name = $request->post('name');
// equivalent to: $name = isset($_POST['name']) ? $_POST['name'] : null;
$name = $request->post('name', '');
// équivalent à : $name = isset($_POST['name']) ? $_POST['name'] : '';
```
> Info: plutôt que d'accéder directement à `$_GET` et `$_POST` pour récupérer les paramètres de requête, il est recommandé de les obtenir via le composant `request` comme indiqué ci-dessus. Cela rend l'écriture des tests plus facile parce que vous pouvez créer un simulacre de composant request avec des données de requête factices.
Lorsque vous mettez en œuvre des [API pleinement REST](rest-quick-start.md), vous avez souvent besoin de récupérer les paramètres qui sont soumis via les [méthodes de requête](#request-methods) PUT, PATCH ou autre . Vous pouvez obtenir ces paramètres en appelant la méthode [[yii\web\Request::getBodyParam()]]. par exemple :
```php
$request = Yii::$app->request;
// retourne tous les paramètres
$params = $request->bodyParams;
// retourne le paramètre "id"
$param = $request->getBodyParam('id');
```
> Info: à la différence des paramètres de `GET`, les paramètres soumis via `POST`, `PUT`, `PATCH` etc. sont envoyés dans le corps de la requête. Le composant `request` analyse ces paramètres lorsque vous y accédez via les méthodes décrites ci-dessus. Vous pouvez personnaliser la manière dont ces paramètres sont analysés en configurant la propriété [[yii\web\Request::parsers]].
## Méthodes de requête <span id="request-methods"></span>
Vous pouvez obtenir la méthode HTTP utilisée par la requête courante via l'expression `Yii::$app->request->method`. Un jeu entier de propriétés booléennes est également fourni pour que vous puissiez déterminer le type de la méthode courante. Par exemple :
For example,
```php
$request = Yii::$app->request;
if ($request->isAjax) { /* la méthode de requête est requête AJAX */ }
if ($request->isGet) { /* la méthode de requête est requête GET */ }
if ($request->isPost) { /* la méthode de requête est requête POST */ }
if ($request->isPut) { /* la méthode de requête est requête PUT */ }
```
## URL de requête <span id="request-urls"></span>
Le composant `request` fournit plusieurs manières d'inspecter l'URL couramment requise.
En supposant que l'URL requise soit `http://example.com/admin/index.php/product?id=100`, vous pouvez obtenir différentes parties de cette URL comme c'est résumé ci-dessous :
* [[yii\web\Request::url|url]]: retourne`/admin/index.php/product?id=100`, qui est l'URL sans la partie hôte.
* [[yii\web\Request::absoluteUrl|absoluteUrl]]: retourne `http://example.com/admin/index.php/product?id=100`, qui est l'URL complète y compris la partie hôte.
* [[yii\web\Request::hostInfo|hostInfo]]: retourne `http://example.com`, qui est la partie hôte de l'URL.
* [[yii\web\Request::pathInfo|pathInfo]]: retourne `/product`, qui est la partie après le script d'entrée et avant le point d'interrogation (chaîne de requête).
* [[yii\web\Request::queryString|queryString]]: retourne `id=100`, qui est la partie après le point d'interrogation.
* [[yii\web\Request::baseUrl|baseUrl]]: retourne `/admin`, qui est la partie après l'hôte et avant le nom du script d'entrée.
* [[yii\web\Request::scriptUrl|scriptUrl]]: retourne `/admin/index.php`, qui set l'URL sans le chemin et la chaîne de requête.
* [[yii\web\Request::serverName|serverName]]: retourne `example.com`, qui est le nom d'hôte dans l'URL.
* [[yii\web\Request::serverPort|serverPort]]: retourne 80, qui est le numéro de port utilisé par le serveur Web.
## Enntêtes HTTP <span id="http-headers"></span>
Vous pouvez obtenir les entêtes HTTP via la [[yii\web\HeaderCollection|collection d'entêtes]] qui est retournée par la propriété [[yii\web\Request::headers]]. Par exemple :
```php
// $headers est un objet yii\web\HeaderCollection
$headers = Yii::$app->request->headers;
// retourne la valeur de l'entête Accept
$accept = $headers->get('Accept');
if ($headers->has('User-Agent')) { /* il existe un entête User-Agent */ }
```
Le composant `request` fournit aussi la prise en charge de l'accès rapide à quelques entêtes couramment utilisés. Cela inclut :
* [[yii\web\Request::userAgent|userAgent]]: retourne la valeur de l'entête `User-Agent`.
* [[yii\web\Request::contentType|contentType]]: retourne la valeur de l'entête `Content-Type` qui indique le type MIME des données dans le corps de la requête.
* [[yii\web\Request::acceptableContentTypes|acceptableContentTypes]]: retourne les types MIME acceptés par l'utilisateur. Les types retournés sont classés par ordre de score de qualité. Les types avec les plus hauts scores sont retournés en premier.
* [[yii\web\Request::acceptableLanguages|acceptableLanguages]]: retourne les langues acceptées par l'utilisateur. Les langues retournées sont classées par niveau de préférence. Le premier élément représente la langue préférée. Si votre application prend en charge plusieurs langues et que vous voulez afficher des pages dans la langue préférée de l'utilisateur, vous pouvez utiliser la méthode de négociation de la langue [[yii\web\Request::getPreferredLanguage()]].
Cette méthode accepte une liste des langues prises en charge par votre application, la compare avec les [[yii\web\Request::acceptableLanguages (langues acceptées)|acceptableLanguages]], et retourne la langue la plus appropriée.
> Tip: vous pouvez également utiliser le filtre [[yii\filters\ContentNegotiator|ContentNegotiator]] pour déterminer dynamiquement quel type de contenu et quelle langue utiliser dans la réponse. Le filtre met en œuvre la négociation de contenu en plus des propriétés et méthodes décrites ci-dessus.
## Informations sur le client <span id="client-information"></span>
Vous pouvez obtenir le nom d'hôte et l'adresse IP de la machine cliente via [[yii\web\Request::userHost|userHost]] et [[yii\web\Request::userIP|userIP]], respectivement. Par exemple :
```php
$userHost = Yii::$app->request->userHost;
$userIP = Yii::$app->request->userIP;
```

209
docs/guide-fr/runtime-responses.md

@ -0,0 +1,209 @@
Réponses
=========
Quand une application a terminé la prise en charge d'une [requête](runtime-requests.md), elle génère un objet [[yii\web\Response|response]] et l'envoie à l'utilisateur final. L'objet `response` contient des informations telles que le code d'état HTTP, les entêtes HTTP et le corps. Le but ultime du développement d'applications Web est essentiellement du construire de tels objets `response` pour des requêtes variées.
Dans la plupart des cas, vous devez travailler avec le [composant d'application](structure-application-components.md) `response` qui, par défaut, est une instance de [[yii\web\Response]]. Néanmoins, Yii vous permet également de créer vos propres objets `response` et de les envoyer à l'utilisateur final comme nous l'exliquons dans ce qui suit.
Dans cette section, nous décrivons comment composer et enovoyer des réponses à l'utilisateur final.
## Code d'état <span id="status-code"></span>
Une de première chose que vous devez faire lorsque vous construisez une réponse est de déclarer si la requête a été correctement prise en charge ou pas. Cela se fait en définissant la propriété [[yii\web\Response::statusCode (code d'état)]] qui peut prendre un des [code d'état HTTP](http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html) valides. Par exemple, pour indiquer que la requête a été prise en charge avec succès, vous pouvez définir le code à 200, comme ceci :
```php
Yii::$app->response->statusCode = 200;
```
Néanmoins, dans la plupart des cas, vous n'avez pas besoin de définir ce code explicitement. Cela tient au fait que la valeur par défaut de [[yii\web\Response::statusCode]] est 200. Et, si vous voulez indiquer que la prise en charge de la requête a échoué vous pouvez lever une exception appropriée comme ceci :
```php
throw new \yii\web\NotFoundHttpException;
```
Lorsque le [gestionnaire d'erreurs](runtime-handling-errors.md) intercepte l'exception, il extraie le code d'état de l'exception et l'assigne à la réponse. Concernant l'exception [[yii\web\NotFoundHttpException]] ci-dessus, elle est associée au code d'état HTTP 404. Les exception HTTP suivantes sont prédéfinies dans Yii :
* [[yii\web\BadRequestHttpException]]: code d'état 400.
* [[yii\web\ConflictHttpException]]: code d'état 409.
* [[yii\web\ForbiddenHttpException]]: code d'état 403.
* [[yii\web\GoneHttpException]]: code d'état 410.
* [[yii\web\MethodNotAllowedHttpException]]: code d'état 405.
* [[yii\web\NotAcceptableHttpException]]: code d'état 406.
* [[yii\web\NotFoundHttpException]]: code d'état 404.
* [[yii\web\ServerErrorHttpException]]: code d'état 500.
* [[yii\web\TooManyRequestsHttpException]]: code d'état 429.
* [[yii\web\UnauthorizedHttpException]]: code d'état 401.
* [[yii\web\UnsupportedMediaTypeHttpException]]: code d'état 415.
Si l'exception que vous voulez lever ne fait pas partie de cette liste, vous pouvez en créer une en étendant la classe [[yii\web\HttpException]], ou en en levant une à laquelle vous passez directement le code d'état. Par exemple :
```php
throw new \yii\web\HttpException(402);
```
## Entêtes HTTP <span id="http-headers"></span>
Vous pouvez envoyer les entêtes HTTP en manipulant la [[yii\web\Response::headers|collection d'entêtes]] dans le composant `response`. Par exemple :
```php
$headers = Yii::$app->response->headers;
// ajoute un entête Pragma . L'entête Pragma existant n'est PAS écrasé.
$headers->add('Pragma', 'no-cache');
// définit un entête Pragma. Tout entête Pragma existant est supprimé.
$headers->set('Pragma', 'no-cache');
// retire un (des) entêtes Pragma et retourne les valeurs de l'entête Pragma retiré dans un tableau
$values = $headers->remove('Pragma');
```
> Info: les noms d'entête ne sont pas sensibles à la casse. Les nouveaux entêtes enregistrés ne sont pas envoyés à l'utilisateur tant que la méthode [[yii\web\Response::send()]] n'est pas appelée.
## Corps de la réponse <span id="response-body"></span>
La plupart des réponses doivent avoir un corps qui transporte le contenu que vous voulez montrer à l'utilisateur final.
Si vous disposez déjà d'une chaîne de caractères formatée pour le corps, vous pouvez l'assigner à la propriété [[yii\web\Response::content]] de la réponse. Par exemple :
```php
Yii::$app->response->content = 'hello world!';
```
Si vos données doivent être formatées avant l'envoi à l'utilisateur final, vous devez définir les propriétés [[yii\web\Response::format|format]] et [[yii\web\Response::data|data]]. La propriété [[yii\web\Response::format|format]] spécifie dans quel format les [[yii\web\Response::data|données]] doivent être formatées. Par exemple :
```php
$response = Yii::$app->response;
$response->format = \yii\web\Response::FORMAT_JSON;
$response->data = ['message' => 'hello world'];
```
De base, Yii prend en charge les formats suivants, chacun mis en œuvre par une classe [[yii\web\ResponseFormatterInterface|formatter]]. Vous pouvez personnaliser les formateurs ou en ajouter de nouveaux en configurant la propriété [[yii\web\Response::formatters]].
* [[yii\web\Response::FORMAT_HTML|HTML]]: mise en œuvre par [[yii\web\HtmlResponseFormatter]].
* [[yii\web\Response::FORMAT_XML|XML]]: mise en œuvre par [[yii\web\XmlResponseFormatter]].
* [[yii\web\Response::FORMAT_JSON|JSON]]: mise en œuvre par [[yii\web\JsonResponseFormatter]].
* [[yii\web\Response::FORMAT_JSONP|JSONP]]: mise en œuvre par [[yii\web\JsonResponseFormatter]].
* [[yii\web\Response::FORMAT_RAW|RAW]]: utilisez ce format si vous voulez envoyer la réponse directement sans lui appliquer aucun formatage.
Bien que le corps de la réponse puisse être défini explicitement comme montré ci-dessus, dans la plupart des cas, vous pouvez le définir implicitement en utilisant la valeur retournée par les méthodes d'[action](structure-controllers.md). Un cas d'usage courant ressemble à ceci :
```php
public function actionIndex()
{
return $this->render('index');
}
```
L'action `index` ci-dessus retourne le résultat du rendu de la vue `index`. La valeur de retour est interceptée par le composant `response`, formatée et envoyée à l'utilisateur final.
Parce que le format par défaut de la réponse est [[yii\web\Response::FORMAT_HTML|HTML]], vous devez seulement retourner un chaîne de caractères dans une méthode d'action. Si vous utilisez un format de réponse différent, vous devez le définir avant de retourner les donnés. Par exemple :
```php
public function actionInfo()
{
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
return [
'message' => 'hello world',
'code' => 100,
];
}
```
Comme mentionné plus haut, en plus d'utiliser le composant d'application `response`, vous pouvez également créer vos propres objets `response` et les envoyer à l'utilisateur final. Vous pouvez faire cela en retournant un tel objet dans une méthode d'action, comme le montre l'exemple suivant :
```php
public function actionInfo()
{
return \Yii::createObject([
'class' => 'yii\web\Response',
'format' => \yii\web\Response::FORMAT_JSON,
'data' => [
'message' => 'hello world',
'code' => 100,
],
]);
}
```
> Note : si vous êtes en train de créer vos propres objets `response`, vous ne pourrez par bénéficier des configurations que vous avez établies pour le composant `response` dans la configuration de l'application. Vous pouvez néanmoins, utiliser l'[injection de dépendances](concept-di-container.md) pour appliquer une configuration commune à vos nouveaux objets `response`.
## Redirection du navigateur <span id="browser-redirection"></span>
La redirection du navigateur s'appuie sur l'envoi d'un entête HTTP `Location`. Comme cette fonctionnalité est couramment utilisée, Yii fournit une prise en charge spéciale pour cela.
Vous pouvez rediriger le navigateur sur une URL en appelant la méthode [[yii\web\Response::redirect()]]. Cette méthode définit l'entête `Location` approprié avec l'URL donnée et retourne l'objet `response` lui-même. Dans une méthode d'action vous pouvez appeler sa version abrégée [[yii\web\Controller::redirect()]]. Par exemple :
```php
public function actionOld()
{
return $this->redirect('http://example.com/new', 301);
}
```
Dans le code précédent, la méthode d'action retourne le résultat de la méthode `redirect()`. Comme expliqué ci-dessus, l'objet `response` retourné par une méthode d'action est utilisé en tant que réponse à envoyer à l'utilisateur final.
Dans des endroits autres que les méthodes d'action, vous devez appeler la méthode [[yii\web\Response::redirect()]] directement, suivi d'un appel chaîné à la méthode [[yii\web\Response::send()]] pour garantir qu'aucun contenu supplémentaire ne sera ajouté à la réponse.
```php
\Yii::$app->response->redirect('http://example.com/new', 301)->send();
```
> Info: par défaut la méthode [[yii\web\Response::redirect()]] définit le code d'état à 302 pour indiquer au navigateur que la ressource requise est *temporairement* située sous un URI différent. Vous pouvez passer un code 301 pour dire au navigateur que la ressource a été déplacée *de manière permanente*.
Lorsque la requête courante est une requête AJAX, l'envoi d'un entête `Location` ne provoque pas automatiquement une redirection du navigateur. Pour pallier ce problème, la méthode [[yii\web\Response::redirect()]] définit un entête `X-Redirect` avec l'URL de redirection comme valeur. Du côté client, vous pouvez écrire un code JavaScript pour lire l'entête et rediriger le navigateur sur l'URL transmise.
> Info: Yii est fourni avec un fichier JavaScript `yii.js` qui fournit un jeu d'utilitaires JavaScript, y compris l'utilitaire de redirection basé sur l'entête `X-Redirect`. Par conséquent, si vous utilisez ce fichier JavaScript (en enregistrant le paquet de ressources [[yii\web\YiiAsset]] ), vous n'avez rien à écrire pour prendre en charge la redirection AJAX.
## Envoi de fichiers <span id="sending-files"></span>
Comme la redirection du navigateur, l'envoi de fichiers est une autre fonctionnalité qui s'appuie sur les entêtes HTTP spécifiques. Yii fournit un jeu de méthodes pour prendre en charge différents besoins d'envoi de fichiers. Elles assurent toutes la prise en charge de la plage d'entêtes HTTP.
* [[yii\web\Response::sendFile()]]: envoie un fichier existant à un client.
* [[yii\web\Response::sendContentAsFile()]]: envoie un chaîne de caractères en tant que fichier à un client.
* [[yii\web\Response::sendStreamAsFile()]]: envoie un flux de fichier existant en tant que fichier à un client.
Ces méthodes ont la même signature avec l'objet `response` comme valeur de retour. Si le fichier à envoyer est trop gros, vous devez envisager d'utiliser [[yii\web\Response::sendStreamAsFile()]] parce qu'elle fait un usage plus efficace de la mémoire. L'exemple qui suit montre comment envoyer un fichier dans une action de contrôleur.
```php
public function actionDownload()
{
return \Yii::$app->response->sendFile('path/to/file.txt');
}
```
Si vous appelez la méthode d'envoi de fichiers dans des endroits autres qu'une méthode d'action, vous devez aussi appeler la méthode [[yii\web\Response::send()]] immédiatement après pour garantir qu'aucun contenu supplémentaire ne sera ajouté à la réponse.
```php
\Yii::$app->response->sendFile('path/to/file.txt')->send();
```
Quelques serveurs Web assurent une prise en charge spéciale de l'envoi de fichiers appelée *X-Sendfile*. L'idée est de rediriger la requête d'un fichier sur le serveur Web qui sert directement le fichier. En conséquence, l'application Web peut terminer plus rapidement tandis que le serveur Web est en train d'envoyer le fichier. Pour utiliser cette fonctionnalité, vous pouvez appeler la méthode [[yii\web\Response::xSendFile()]]. La liste suivante résume, comment activer la fonctionnalité `X-Sendfile` pour quelques serveurs Web populaires :
- Apache: [X-Sendfile](http://tn123.org/mod_xsendfile)
- Lighttpd v1.4: [X-LIGHTTPD-send-file](http://redmine.lighttpd.net/projects/lighttpd/wiki/X-LIGHTTPD-send-file)
- Lighttpd v1.5: [X-Sendfile](http://redmine.lighttpd.net/projects/lighttpd/wiki/X-LIGHTTPD-send-file)
- Nginx: [X-Accel-Redirect](http://wiki.nginx.org/XSendfile)
- Cherokee: [X-Sendfile and X-Accel-Redirect](http://www.cherokee-project.com/doc/other_goodies.html#x-sendfile)
## Envoi de la réponse <span id="sending-response"></span>
Le contenu d'une réponse n'est pas envoyé à l'utilisateur tant que la méthode [[yii\web\Response::send()]] n'est pas appelée. Par défaut, cette méthode est appelée automatiquement à la fin de [[yii\base\Application::run()]]. Vous pouvez néanmoins appeler cette méthode explicitement pour forcer l'envoi de la réponse immédiatement.
La méthode [[yii\web\Response::send()]] entreprend les étapes suivantes pour envoyer la réponse :
1. Elle déclenche l'événement [[yii\web\Response::EVENT_BEFORE_SEND]].
2. Elle appelle [[yii\web\Response::prepare()]] pour formater [[yii\web\Response::data|les données de la réponse]] du [[yii\web\Response::content|contenu de la réponse]].
3. Elle déclenche l'événement [[yii\web\Response::EVENT_AFTER_PREPARE]].
4. Elle appelle la méthode [[yii\web\Response::sendHeaders()]] pour envoyer les entêtes HTTP enregistrés.
5. Elle appelle la méthode [[yii\web\Response::sendContent()]] pour envoyer le corps de la réponse.
6. Elle déclenche l'événement [[yii\web\Response::EVENT_AFTER_SEND]].
Après que la méthode [[yii\web\Response::send()]] est appelée une fois, tout appel suivant de cette méthode est ignoré. Cela signifie qu'une fois la réponse expédiée, vous ne pouvez lui ajouter aucun contenu.
Comme vous pouvez le voir, la méthode [[yii\web\Response::send()]] déclenche plusieurs événements utiles. En répondant à ces événements, il est possible d'ajuster ou d'enjoliver la réponse.

508
docs/guide-fr/runtime-routing.md

@ -0,0 +1,508 @@
Routage et création d'URL
=========================
Lorsqu'une application Yii commence à traiter une URL objet d'une requête, sa première étape consiste à analyser cette URL pour la résoudre en une [route](structure-controllers.md#routes). La route est ensuite utilisée pour instancier l'[action de contrôleur](structure-controllers.md) correspondante pour la prise en charge de la requête. Ce processus est appelé *routage*.
Le processus inverse du routage, qui consiste à créer une URL à partir d'une route et des paramètres associés de la requête, est appelé *création d'URL*. Lorsque l'URL créée est ensuite requise, le processus de routage est capable de la résoudre en la route originale avec les paramètres de requête.
L'élément central en charge du routage et de la création d'URL est le [[yii\web\UrlManager|gestionnaire d'URL]], qui est enregistré en tant que [composant d'application](structure-application-components.md) sous le nom `urlManager`. Le [[yii\web\UrlManager|gestionnaire d'URL]] fournit la méthode [[yii\web\UrlManager::parseRequest()|parseRequest()]] pour analyser une requête entrante et la résoudre en une route et les paramètres de requête associés, et la méthode [[yii\web\UrlManager::createUrl()|createUrl()]] pour créer une URL en partant d'une route avec ses paramètres de requête associés.
En configurant le composant `urlManager` dans la configuration de l'application, vous pouvez laisser votre application reconnaître les formats d'URL arbitraires sans modifier le code existant de votre application. Par exemple, vous pouvez utiliser le code suivant pour créer une URL pour l'action `post/view` :
```php
use yii\helpers\Url;
// Url::to() appelle UrlManager::createUrl() pour créer une URL
$url = Url::to(['post/view', 'id' => 100]);
```
Selon la configuration de `urlManager`, l'URL créée peut ressenmbler à l'une des URL suivantes (ou autre formats). Et si l'URL est requise plus tard, elle sera toujours analysée pour revenir à la route originale et aux valeurs des paramètres de la requête.
```
/index.php?r=post%2Fview&id=100
/index.php/post/100
/posts/100
```
## Formats d'URL <span id="url-formats"></span>
Le [[yii\web\UrlManager|gestionnaire d'URL]] prend en charge deux formats d'URL : le format d'URL par défaut et le format d'URL élégantes.
Le format d'URL par défaut utilise un paramètre de requête nommé `r` qui représente la route et les paramètres de requête normaux associés à la route. Par exemple, l'URL `/index.php?r=post/view&id=100` represente la route `post/view` et le paramètre de requête `id` dont la valeur est 100. Le format d'URL par défaut ne requiert aucune configuration du [[yii\web\UrlManager|gestionnaire d'URL] et fonctionne dans toutes les configurations de serveur Web.
Le format d'URL élégantes utilise le chemin additionnel qui suit le nom du script d'entrée pour représenter la route et les paramètres de requête associés. Par exemple, le chemin additionnel dans l'URL `/index.php/post/100` est `/post/100` qui, avec une [[yii\web\UrlManager::rules|règle d'URL]] appropriée, peut représenter la route `post/view` et le paramètre des requête `id` avec une valeur de 100 . Pour utiliser le format d'URL élégantes, vous devez définir un jeu de [[yii\web\UrlManager::rules|règles d'URL]] en cohérence avec les exigences réelles sur la présentation d'une URL.
Vous pouvez passer d'un format d'URL à l'autre en inversant la propriété [[yii\web\UrlManager::enablePrettyUrl|enablePrettyUrl]] du [[yii\web\UrlManager|gestionnaire d'URL]] sans changer quoi que ce soit au code de votre application.
## Routage <span id="routing"></span>
Le routage se fait en deux étapes. Dans la première étape, la requête entrante est analysée et résolue en une route et les paramètres de requête associés. Dans la seconde étape, l'[action de contrôleur](structure-controllers.md#actions) correspondant à la route analysée est créée pour prendre la requête en charge.
Lors de l'utilisation du format d'URL par défaut, la résolution d'une requête en route est aussi simple que d'obtenir le paramètre nommé `r` de la méthode `GET`.
Lors de l'utilisation du format d'URL élégantes, le [[yii\web\UrlManager|gestionnaire d'URL] examine les [[yii\web\UrlManager::rules|règles d'URL]] enregistrées pour trouver une règle qui correspond et résoudre la requête en une route. Si une telle règle n'est pas trouvée, une exception [[yii\web\NotFoundHttpException]] est levée.
Une fois que la requête est résolue en une route, il est temps de créer l'action de contrôleur identifiée par la route. La route est éclatée en de multiples parties par des barres oblique de division. Par exemple, `site/index` est éclatée en `site` et `index`. Chacune des parties est considérée comme un identifiant qui peut faire référence à un module, un contrôleur ou une action. En partant de la première partie dans la route, l'application entreprend les étapes suivantes pour créer un module (s'il en existe un), un contrôleur et une action.
1. Définit l'application comme étant le module courant.
2. Vérifie si la [[yii\base\Module::controllerMap|table de mise en correspondance des contrôleurs]] du module courant contient l'identifiant courant. Si c'est le cas, un objet *controller* est créé en respectant la configuration du contrôleur trouvé dans la table de mise en correspondance, et on passe à l'étape 5 pour prendre en compte le reste de la route.
3. Vérifie si l'identifiant fait référence à un module listé dans la propriété [[yii\base\Module::modules|modules]] du module courant. Si c'est le cas, un module est créé en respectant la configuration trouvée dans la liste des modules et on passe à l'étape 2 pour prendre en compte le reste de la route dans le contexte du nouveau module.
4. Traite l'identifiant comme un [identifiant de contrôleur](structure-controllers.md#controller-ids), crée un objet *controller* et passe à l'étape suivante avec le reste de la route.
5. Le contrôleur recherche l'identifiant courant dans sa [[yii\base\Controller::actions()|table de mise en correspondance des actions]]. s'il le trouve, il crée une action respectant la configuration trouvée dans la table de mise en correspondance. Autrement, le contrôleur essaye de créer une action en ligne dont le nom de méthode correspond à l' [identifiant d'action](structure-controllers.md#action-ids) courant.
Si une erreur se produit dans l'une des étapes décrites ci-dessus, une exception [[yii\web\NotFoundHttpException]] est levée, indiquant l'échec du processus de routage.
### Route par défaut <span id="default-route"></span>
Quand une requête est analysée et résolue en une route vide, la route dite *route par défaut* est utilisée à sa place. Par défaut, la route par défaut est `site/index`, qui fait référence à l'action `index` du contrôleur `site`. Vous pouvez la personnaliser en configurant la propriété [[yii\web\Application::defaultRoute|defaultRoute]] de l'application dans la configuration de l'application comme indiqué ci-dessous :
```php
[
// ...
'defaultRoute' => 'main/index',
];
```
### La route `attrape-tout` <span id="catchall-route"></span>
Parfois, vous désirez mettre votre application Web en mode maintenance temporairement et afficher la même page d'information pour toutes les requêtes. Il y a plusieurs moyens de faire cela. L'une des manières les plus simples est de configurer la propriété [[yii\web\Application::catchAll]] dans la configuration de l'application comme indiqué ci-dessous :
```php
[
// ...
'catchAll' => ['site/offline'],
];
```
Avec la configuration ci-dessus, l'action `site/offline` est utilisée pour prendre toutes les requêtes entrantes en charge.
La propriété `catchAll` accepte un tableau dont le premier élément spécifie une route et le reste des éléments des couples clé-valeur pour les paramètres [liés à l'action](structure-controllers.md#action-parameters).
> Info: le paneau de débogage de l'environnement de développement ne fonctionne pas lorsque cette propriété est activée.
## Création d'URL <span id="creating-urls"></span>
Yii fournit une méthode d'aide [[yii\helpers\Url::to()]] pour créer différentes sortes d'URL à partir de routes données et de leurs paramètres de requête associés. Par exemple :
```php
use yii\helpers\Url;
// crée une URL d'une route: /index.php?r=post%2Findex
echo Url::to(['post/index']);
// crée une URL d'une route avec paramètres : /index.php?r=post%2Fview&id=100
echo Url::to(['post/view', 'id' => 100]);
// crée une URL avec ancre : /index.php?r=post%2Fview&id=100#content
echo Url::to(['post/view', 'id' => 100, '#' => 'content']);
// crée une URL absolue : http://www.example.com/index.php?r=post%2Findex
echo Url::to(['post/index'], true);
// crée une URL absolue en utilisant le schéam https : https://www.example.com/index.php?r=post%2Findex
echo Url::to(['post/index'], 'https');
```
Notez que dans l'exemple ci-dessus, nous supposons que le format d'URL est le format par défaut. Si le format d'URL élégantes est activé, les URL créées sont différentes et respectent les [[yii\web\UrlManager::rules|règles d'URL]] en cours d'utilisation.
La route passée à la méthode [[yii\helpers\Url::to()]] est sensible au contexte. Elle peut être soit *relative*, soit *absolue* et normalisée en respect des règles suivantes :
- Si la route est une chaîne vide, la [[yii\web\Controller::route|route]] couramment requise est utilisée;
- Si la route ne contient aucune barre oblique de division, elle est considérée comme un identifiant d'action du contrôleur courant et est préfixée par la valeur de l'identifiant [[\yii\web\Controller::uniqueId|uniqueId]] du contrôleur courant ;
- Si la route n'a pas de barre oblique de division, elle est considérée comme une route relative au module courant et préfixée par la valeur de l'identifiant [[\yii\base\Module::uniqueId|uniqueId]] du module courant.
À partir de la version 2.0.2, vous pouvez spécifier une route en terme d'[alias](concept-aliases.md). Si c'est le cas, l'alias est d'abord converti en la route réelle qui est ensuite transformée en route absolue dans le respect des règles précédentes.
Par exemple, en supposant que le module courant est `admin` et que le contrôleur courant est `post`,
```php
use yii\helpers\Url;
// route couramment requise : /index.php?r=admin%2Fpost%2Findex
echo Url::to(['']);
// une route relative avec un identifiant d'action seulement : /index.php?r=admin%2Fpost%2Findex
echo Url::to(['index']);
// une route relative : /index.php?r=admin%2Fpost%2Findex
echo Url::to(['post/index']);
// une route absoulue: /index.php?r=post%2Findex
echo Url::to(['/post/index']);
// /index.php?r=post%2Findex suppose que l'alias "@posts" est défini comme "/post/index"
echo Url::to(['@posts']);
```
La méthode [[yii\helpers\Url::to()]] est mise en œuvre en appelant les méthodes [[yii\web\UrlManager::createUrl()|createUrl()]] et [[yii\web\UrlManager::createAbsoluteUrl()|createAbsoluteUrl()]] du [[yii\web\UrlManager|gestionnaire d'URL]]. Dans les quelques sous-sections suivantes, nous expliquons comment configurer le [[yii\web\UrlManager|gestionnaire d'URL]] pour personnaliser le format des URL créées.
La méthode [[yii\helpers\Url::to()]] prend aussi en charge la création d'URL qui n'ont PAS de relation avec des routes particulières. Au lieu de passer un tableau comme premier paramètre, vous devez, dans ce cas, passer une chaîne de caractères. Par exemple :
```php
use yii\helpers\Url;
// URL couramment requise : /index.php?r=admin%2Fpost%2Findex
echo Url::to();
// un alias d'URL: http://example.com
Yii::setAlias('@example', 'http://example.com/');
echo Url::to('@example');
// une URL absolue : http://example.com/images/logo.gif
echo Url::to('/images/logo.gif', true);
```
En plus de la méthode `to()`, la classe d'aide [[yii\helpers\Url]] fournit aussi plusieurs méthode pratiques de création d'URL. Par exemple :
```php
use yii\helpers\Url;
// URL de page d'accueil: /index.php?r=site%2Findex
echo Url::home();
// URL de base, utile si l'application est déployée dans un sous-dossier du dossier Web racine
echo Url::base();
// l'URL canonique de l'URL couramment requise
// see https://en.wikipedia.org/wiki/Canonical_link_element
echo Url::canonical();
// mémories l'URL couramment requise et la retrouve dans les requêtes subséquentes
Url::remember();
echo Url::previous();
```
## Utilisation des URL élégantes <span id="using-pretty-urls"></span>
Pour utiliser les URL élégantes, configurez le composant `urlManager` dans la configuration de l'application comme indiqué ci-dessous :
```php
[
'components' => [
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'enableStrictParsing' => false,
'rules' => [
// ...
],
],
],
]
```
La propriété [[yii\web\UrlManager::enablePrettyUrl|enablePrettyUrl]] est obligatoire car elle active/désactive le format d'URL élégantes. Le reste des propriétés est facultatif. Néanmoins, leur configuration montrée plus haut est couramment utilisée.
* [[yii\web\UrlManager::showScriptName|showScriptName]]: cette propriété détermine si le script d'entrée doit être inclus dans l'URL créée. Par exemple, au lieu de créer une URL `/index.php/post/100`, en définissant cette propriété à `false`, l'URL `/post/100` est générée.
* [[yii\web\UrlManager::enableStrictParsing|enableStrictParsing]]: cette propriété détermine si l'analyse stricte est activée . Si c'est le cas, l'URL entrante doit correspondre à au moins une des [[yii\web\UrlManager::rules|règles]] afin d'être traitée comme une requête valide, sinon une exception [[yii\web\NotFoundHttpException]] est levée. Si l'analyse stricte est désactivée, lorsqu'aucune [[yii\web\UrlManager::rules|règle]] ne correspond à l'URL requise, la partie chemin de l'URL est considérée comme étant la route requise.
* [[yii\web\UrlManager::rules|rules]]: cette propriété contient une liste de règles spécifiant comme analyser et créer des URL. C'est la propriété principale avec laquelle vous devez travailler afin de créer des URL dont le format satisfait les exigences particulières de votre application.
> Note: afin de cacher le nom du script d'entrée dans l'URL créée, en plus de définir la propriété [[yii\web\UrlManager::showScriptName|showScriptName]] à `false`, vous pouvez aussi configurer votre serveur Web de manière à ce qu'il puisse identifier correctement quel script PHP doit être exécuté lorsqu'une URL requise n'en précise aucun explicitement. Si vous utilisez le serveur Apache, vous pouvez vous reporter à la configuration recommandée décrite dans la section [Installation](start-installation.md#recommended-apache-configuration).
### Règles d'URL <span id="url-rules"></span>
Une règle d'URL est une instance de la classe [[yii\web\UrlRule]] ou de ses classes filles. Chaque règle d'URL consiste en un motif utilisé pour être mis en correspondance avec la partie chemin de l'URL, une route, et quelques paramètres de requête. Une règle d'URL peut être utilisée pour analyser une requête si son motif correspond à l'URL requise. Une règle d'URL peut être utilisée pour créer une URL si sa route et le nom de ses paramètres de requête correspondent à ceux qui sont fournis.
Quand le format d'URL élégantes est activé, le [[yii\web\UrlManager|gestionnaire d'URL]] utilise les règles d'URL déclarées dans sa propriété
[[yii\web\UrlManager::rules|rules]] pour analyser les requêtes entrantes et créer des URL. En particulier, pour analyser une requête entrante, le [[yii\web\UrlManager|gestionnaire d'URL]] examine les règles dans l'ordre de leur déclaration et cherche la *première* règle qui correspond à l'URL requise. La règle correspondante est ensuite utilisée pour analyser l'URL et la résoudre en une route et ses paramètres de requête associés. De façon similaire, pour créer une URL, le [[yii\web\UrlManager|gestionnaire d'URL]] cherche la première règle qui correspond à la route donnée et aux paramètres et l'utilise pour créer l'URL.
Vous pouvez configurer la propriété [[yii\web\UrlManager::rules]] sous forme de tableau dont les clés sont les motifs et les valeurs, les routes correspondantes. Chacune des paires motif-route construit une règle d'URL. Par exemple, la configuration des [[yii\web\UrlManager::rules|règles]] suivantes déclare deux règles d'URL. La première correspond à l'URL `posts` et la met en correspondance avec la route `post/index`. La seconde correspond à une URL qui correspond à l'expression régulière `post/(\d+)` et la met en correspondance avec la route `post/view` et le paramètre nommé `id`.
```php
[
'posts' => 'post/index',
'post/<id:\d+>' => 'post/view',
]
```
> Info: le motif dans une règle est utilisé pour correspondre à la partie chemin d'une URL. Par exemple, la partie chemin de `/index.php/post/100?source=ad` est `post/100` (les barres obliques de division de début et de fin sont ignorées) et correspond au motif `post/(\d+)`.
En plus de déclarer des règles d'URL sous forme de paires motif-route, vous pouvez aussi les déclarer sous forme de tableaux de configuration. Chacun des tableaux de configuration est utilisé pour configurer un simple objet règle d'URL. C'est souvent nécessaire lorsque vous voulez configurer d'autres propriétés d'une règle d'URL. Par exemple :
```php
[
// ...autres règels d'url ...
[
'pattern' => 'posts',
'route' => 'post/index',
'suffix' => '.json',
],
]
```
Par défaut, si vous ne spécifiez pas l'option `class` pour une configuration de règle, elle prend la valeur par défaut [[yii\web\UrlRule]].
### Paramètres nommés <span id="named-parameters"></span>
Une règle d'URL peut être associée à quelques paramètres de requête nommés qui sont spécifiés dans le motif et respectent le format `<ParamName:RegExp>`, où `ParamName` spécifie le nom du paramètre et `RegExp` est une expression régulière facultative utilisée pour établir la correspondance avec une valeur de paramètre. Si `RegExp` n'est pas spécifié, cela signifie que la valeur du paramètre doit être une chaîne de caractères sans aucune barre oblique de division.
> Note: vous pouvez seulement spécifier des expressions régulières pour les paramètres. La partie restante du motif est considérée être du texte simple.
Lorsqu'une règle est utilisée pour analyser une URL, elle remplit les paramètres associés avec les valeurs des parties de l'URL qui leur correspondent, et ces paramètres sont rendus disponibles dans `$_GET` et plus tard dans le composant d'application `request`. Lorsque la règle est utilisée pour créer une URL, elle prend les valeurs des paramètres fournis et les insère à l'endroit où ces paramètres sont déclarés.
Prenons quelques exemples pour illustrer comment les paramètres nommés fonctionnent. Supposons que nous ayons déclaré les règles d'URL suivantes :
```php
[
'posts/<year:\d{4}>/<category>' => 'post/index',
'posts' => 'post/index',
'post/<id:\d+>' => 'post/view',
]
```
Lorsque les règles sont utilisées pour analyser des URL :
- `/index.php/posts` est analysée et résolue en la route `post/index` en utilisant la deuxième règle;
- `/index.php/posts/2014/php` est analysée et résolue en la route `post/index`, le paramètre `year` dont la valeur est 2014 et le paramètre `category` dont la valeur est `php` en utilisant la première règle;
- `/index.php/post/100` est analysée et résolue en la route `post/view` et le paramètre `id` dont la valeur est 100 en utilisant la troisième règle;
- `/index.php/posts/php` provoque la levée d'une exception [[yii\web\NotFoundHttpException]] quand la propriété [[yii\web\UrlManager::enableStrictParsing]]
est définie à `true`, parce qu'elle ne correspond à aucun des motifs. Si [[yii\web\UrlManager::enableStrictParsing]] est définie à `false` (la valeur par défaut), la partie chemin `posts/php` est retournée en tant que route.
Et quand les règles sont utilisées pour créer des URL :
- `Url::to(['post/index'])` crée `/index.php/posts` en utilisant la deuxième règle ;
- `Url::to(['post/index', 'year' => 2014, 'category' => 'php'])` crée `/index.php/posts/2014/php` en utilisant la première règle;
- `Url::to(['post/view', 'id' => 100])` crée `/index.php/post/100` en utilisant la troisième règle;
- `Url::to(['post/view', 'id' => 100, 'source' => 'ad'])` crée `/index.php/post/100?source=ad` en utilisant la troisième règle.
Comme le paramètre `source` n'est pas spécifié dans la règle, il est ajouté en tant que paramètre de requête à l'URL créée.
- `Url::to(['post/index', 'category' => 'php'])` crée `/index.php/post/index?category=php` en utilisant aucune des règles.
Notez que, aucune des règles n'étant utilisée, l'URL est créée en ajoutant simplement la route en tant que partie chemin et tous les paramètres en tant que partie de la chaîne de requête.
### Paramétrage des routes <span id="parameterizing-routes"></span>
Vous pouvez inclure les noms des paramètres dans la route d'une règle d'URL. Cela permet à une règle d'URL d'être utilisée pour correspondre à de multiples routes. Par exemple, les règles suivantes incluent les paramètres `controller` et `action` dans les routes.
```php
[
'<controller:(post|comment)>/<id:\d+>/<action:(create|update|delete)>' => '<controller>/<action>',
'<controller:(post|comment)>/<id:\d+>' => '<controller>/view',
'<controller:(post|comment)>s' => '<controller>/index',
]
```
Pour analyser l'URL `/index.php/comment/100/create`, la première règle s'applique et définit le paramètre `controller` comme étant `comment` et le paramètre `action` comme étant `create`. La route `<controller>/<action>` est par conséquent résolue comme `comment/create`.
De façon similaire, pour créer une URL à partir de la route `comment/index`, la troisième règle s'applique, ce qui donne l'URL `/index.php/comments`.
> Info: en paramétrant les routes, il est possible de réduire grandement le nombre de règles d'URL, ce qui peut accroître significativement la performance du [[yii\web\UrlManager|gestionnaire d'URL]].
Par défaut, tous les paramètres déclarés dans une règle sont requis. Si une URL requise ne contient pas un paramètre particulier, ou si une URL est créée sans un paramètre particulier, la règle ne s'applique pas. Pour rendre certains paramètres facultatifs, vous pouvez configurer la propriété [[yii\web\UrlRule::defaults|defaults]] de la règle. Les paramètres listés dans cette propriété sont facultatifs et prennent les valeurs spécifiées lorsqu'elles ne sont pas fournies.
Dans la déclaration suivante d'une règle, les paramètres `page` et `tag` sont tous les deux facultatifs et prennent la valeur 1 et vide, respectivement quand ils ne sont pas fournis.
```php
[
// ...autres règles...
[
'pattern' => 'posts/<page:\d+>/<tag>',
'route' => 'post/index',
'defaults' => ['page' => 1, 'tag' => ''],
],
]
```
La règle ci-dessus peut être utilisée pour analyser ou créer l'une quelconque des URL suivantes :
* `/index.php/posts`: `page` est 1, `tag` est ''.
* `/index.php/posts/2`: `page` est 2, `tag` est ''.
* `/index.php/posts/2/news`: `page` est 2, `tag` est `'news'`.
* `/index.php/posts/news`: `page` est 1, `tag` est `'news'`.
Sans les paramètres facultatifs, vous devriez créer quatre règles pour arriver au même résultat.
### Règles avec des noms de serveur <span id="rules-with-server-names"></span>
Il est possible d'inclure des noms de serveur Web dans le motif d'une règle d'URL. Cela est principalement utilisé lorsque votre application doit se comporter différemment selon le nom du serveur Web. Par exemple, les règles suivantes analysent et résolvent l'URL `http://admin.example.com/login` en la route `admin/user/login` et `http://www.example.com/login` en la route `site/login`.
```php
[
'http://admin.example.com/login' => 'admin/user/login',
'http://www.example.com/login' => 'site/login',
]
```
Vous pouvez aussi inclure des paramètres dans les noms de serveurs pour en extraire de l'information dynamique. Par exemple, la règle suivante analyse et résout l'URL `http://en.example.com/posts` en la route `post/index` et le paramètre `language=en`.
```php
[
'http://<language:\w+>.example.com/posts' => 'post/index',
]
```
> Note: les règles avec des noms de serveur ne doivent pas comprendre le sous-dossier du script d'entrée dans leur motif. Par exemple, si l'application est sous `http://www.example.com/sandbox/blog`, alors vous devez utiliser le motif `http://www.example.com/posts` au lieu de `http://www.example.com/sandbox/blog/posts`. Cela permet à votre application d'être déployée sous n'importe quel dossier sans avoir à changer son code.
### Suffixes d'URL <span id="url-suffixes"></span>
Vous désirez peut-être ajouter des suffixes aux URL pour des raisons variées. Par exemple, vous pouvez ajouter `.html` aux URL de manière à ce qu'elles ressemblent à des URL de pages HTML statiques. Vous pouvez aussi y ajouter `.json` pour indiquer le type de contenu attendu pour la réponse. Vous pouvez faire cela en configurant la propriété [[yii\web\UrlManager::suffix]] dans la configuration de l'application comme ceci :
```php
[
'components' => [
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'enableStrictParsing' => true,
'suffix' => '.html',
'rules' => [
// ...
],
],
],
]
```
La configuration ci-dessus permet au [[yii\web\UrlManager|gestionnaire d'URL]] de reconnaître les URL requises et aussi de créer des URL avec le suffixe `.html`.
> Tip: vous pouvez définir `/` en tant que suffixe des URL de manière à ce que tous les URL se terminent par la barre oblique de division.
> Note: lorsque vous configurez un suffixe d'URL, si une URL requise ne contient pas ce suffixe, elle est considérée comme une URL non reconnue. Cela est une pratique recommandée pour l'optimisation des moteurs de recherche (SE0 – Search Engine Optimization).
Parfois vous désirez utiliser des suffixes différents pour différentes URL. Cela peut être fait en configurant la propriété [[yii\web\UrlRule::suffix|suffix]] des règles d'URL individuelles. Lorsqu'une URL a cette propriété définie, elle écrase la valeur définie au niveau du [[yii\web\UrlManager|gestionnaire d'URL]]. Par exemple, la configuration suivante contient une règle d'URL personnalisée qui utilise `.json` en tant que suffixe à la place du suffixe défini globalement `.html`.
```php
[
'components' => [
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'enableStrictParsing' => true,
'suffix' => '.html',
'rules' => [
// ...
[
'pattern' => 'posts',
'route' => 'post/index',
'suffix' => '.json',
],
],
],
],
]
```
### Méthodes HTTP <span id="http-methods"></span>
En mettant en œuvre des API pleinement REST, il est couramment nécessaire que la même URL puisse être résolue en différentes routes selon la méthode HTTP utilisée par la requête. Cela peut être fait facilement en préfixant les motifs des règles avec les méthodes HTTP prises en charge. Si une règle prend en charge plusieurs méthodes HTTP, il faut séparer les noms de méthode par une virgule. Par exemple, les règles suivantes ont le même motif `post/<id:\d+>` mais des méthodes HTTP différentes. Un requête de `PUT post/100` est résolue en la route `post/create`, tandis que la requête de `GET post/100` en la route `post/view`.
```php
[
'PUT,POST post/<id:\d+>' => 'post/create',
'DELETE post/<id:\d+>' => 'post/delete',
'post/<id:\d+>' => 'post/view',
]
```
> Note: si une règle d'URL contient des méthodes HTTP dans son motif, la règle n'est utilisée qu'à des fins d'analyse résolution. Elle est ignorée quand le [[yii\web\UrlManager|gestionnaire d'URL]] est sollicité pour créer une URL.
> Tip: pour simplifier le routage des API pleinement REST, Yii fournit la classe spéciale de règle d'URL [[yii\rest\UrlRule]] qui est très efficace et prend en charge quelques fonctionnalités originales comme la pluralisation automatique des identifiants de contrôleur. Pour plus de détails, reportez-vous à la section [Routage](rest-routing.md) sur le développement d'API pleinement REST.
### Personnalisation des règles <span id="customizing-rules"></span>
Dans l'exemple précédent, les règles d'URL sont essentiellement déclarées en terme de paires motif-route. Cela est un format raccourci communément utilisé. Dans certains scénarios, vous désirez personnaliser une règle d'URL en configurant ses autres propriétés, telles que [[yii\web\UrlRule::suffix]]. Cela peut être fait en utilisant un tableau complet de configuration pour spécifier une règle. L'exemple suivant est tiré de la sous-section [suffixes d'URL](#url-suffixes) :
```php
[
// ...other url rules...
[
'pattern' => 'posts',
'route' => 'post/index',
'suffix' => '.json',
],
]
```
> Info: Par défaut, si vous ne spécifiez pas l'option `class` dans la configuration d'une règle, elle prend la valeur par défaut [[yii\web\UrlRule]].
### Ajout dynamique de règles <span id="adding-rules"></span>
Des règles d'URL peuvent être ajoutées dynamiquement au [[yii\web\UrlManager|gestionnaire d'URL]]. Cela est souvent nécessaire pour les [modules](structure-modules.md) distribuables qui veulent gérer leurs propres règles d'URL. Pour que les règles ajoutées dynamiquement prennent effet dans de processus de routage, vous devez les ajouter dans l'étape d'[amorçage](runtime-bootstrapping.md). Pour les modules, cela signifie qu'ils doivent implémenter l'interface [[yii\base\BootstrapInterface]] et ajouter les règles dans leur méthode [[yii\base\BootstrapInterface::bootstrap()|bootstrap()]] comme l'exemple suivant le montre :
```php
public function bootstrap($app)
{
$app->getUrlManager()->addRules([
// rule declarations here
], false);
}
```
Notez que vous devez également lister ces modules dans la propriété [[yii\web\Application::bootstrap]] afin qu'ils puissent participer au processus d'[amorçage](runtime-bootstrapping.md).
### Création des classes règles <span id="creating-rules"></span>
En dépit du fait que la classe par défaut [[yii\web\UrlRule]] est suffisamment flexible pour la majorité des projets, il y a des situations dans lesquelles vous devez créer votre propres classes de règle. Par exemple, dans un site Web de vendeur de voitures, vous désirerez peut-être prendre en charge des formats d'URL du type `/Manufacturer/Model`, où `Manufacturer` et `Model` doivent correspondre à quelques données stockées dans une base de données. La classe de règle par défaut ne fonctionne pas dans ce cas car elle s'appuie sur des motifs déclarés de manière statique.
Vous pouvez créer les classes de règle d'URL suivantes pour résoudre ce problème :
```php
namespace app\components;
use yii\web\UrlRuleInterface;
use yii\base\Object;
class CarUrlRule extends Object implements UrlRuleInterface
{
public function createUrl($manager, $route, $params)
{
if ($route === 'car/index') {
if (isset($params['manufacturer'], $params['model'])) {
return $params['manufacturer'] . '/' . $params['model'];
} elseif (isset($params['manufacturer'])) {
return $params['manufacturer'];
}
}
return false; // this rule does not apply
}
public function parseRequest($manager, $request)
{
$pathInfo = $request->getPathInfo();
if (preg_match('%^(\w+)(/(\w+))?$%', $pathInfo, $matches)) {
// vérifie $matches[1] et $matches[3] pour voir si
// elles correspondent à un manufacturer et à un model dans la base de données
// si oui, définit $params['manufacturer'] et/ou $params['model']
// et retourne ['car/index', $params]
}
return false; // cette règle ne s'applique pas
}
}
```
Et utilisez la nouvelle classe de règle dans la configuration de [[yii\web\UrlManager::rules]] :
```php
[
// ...other rules...
[
'class' => 'app\components\CarUrlRule',
// ...configure d'autres propriétés...
],
]
```
## Considérations de performance <span id="performance-consideration"></span>
Lors du développement d'une application Web, il est important d'optimiser les règles d'URL afin que l'analyse des requêtes et la création d'URL prennent moins de temps.
En utilisant les routes paramétrées, vous pouvez réduire le nombre de règles d'URL, ce qui accroît significativement la performance.
Lors de l'analyse d'URL ou de la création d'URL, le [[yii\web\UrlManager|gestionnaire d'URL]] examine les règles d'URL dans l'ordre de leur déclaration. En conséquence, vous devez envisager d'ajuster cet ordre afin que les règles les plus spécifiques et/ou utilisées couramment soient placée avant les règles les moins utilisées.
Si quelques règles d'URL partagent le même préfixe dans leur motif ou dans leur route, vous pouvez envisager d'utiliser [[yii\web\GroupUrlRule]] pour qu'elles puissent être examinées plus efficacement par le [[yii\web\UrlManager|gestionnaire d'URL]] en tant que groupe. Cela est souvent le cas quand votre application est composée de modules, chacun ayant son propre jeu de règles d'URL avec l'identifiant de module comme préfixe commun.

297
docs/guide-fr/runtime-sessions-cookies.md

@ -0,0 +1,297 @@
Sessions et témoins de connexion
================================
Les sessions et les témoins de connexion permettent à des données d'être conservées à travers des requêtes multiples. Avec le langage PHP simple, vous pouvez y accéder via les variables globales `$_SESSION` et `$_COOKIE`, respectivement. Yii encapsule les sessions et les témoins de connexion sous forme d'objets et, par conséquent, vous permet d'y accéder d'une manière orientée objet avec des améliorations utiles.
## Sessions <span id="sessions"></span>
Comme pour les [requêtes](runtime-requests.md) et les [réponses](runtime-responses.md), vous pouvez accéder aux sessions via le [composant d'application component](structure-application-components.md) `session` qui, par défaut, est une instance de la classe [[yii\web\Session]].
### Ouverture et fermeture d'une session <span id="opening-closing-sessions"></span>
Pour ouvrir et fermer une session, vous pouvez procéder comme ceci :
```php
$session = Yii::$app->session;
// vérifie si une session est déjà ouverte
if ($session->isActive) ...
// ouvre une session
$session->open();
// ferme une session
$session->close();
// détruit toutes les données enregistrée dans une session.
$session->destroy();
```
Vous pouvez appeler les méthodes [[yii\web\Session::open()|open()]] et [[yii\web\Session::close()|close()]] plusieurs fois sans causer d'erreur ; en interne les méthodes commencent par vérifier si la session n'est pas déjà ouverte.
### Accès aux données de session <span id="access-session-data"></span>
Pour accéder aux données stockées dans une session, vous pouvez procéder comme indiqué ci-après :
```php
$session = Yii::$app->session;
// obtient une variable de session. Les utilisations suivantes sont équivalentes :
$language = $session->get('language');
$language = $session['language'];
$language = isset($_SESSION['language']) ? $_SESSION['language'] : null;
// définit une variable de session variable. Les utilisations suivantes sont équivalentes :
$session->set('language', 'en-US');
$session['language'] = 'en-US';
$_SESSION['language'] = 'en-US';
// supprime une variable session. Les utilisations suivantes sont équivalentes :
$session->remove('language');
unset($session['language']);
unset($_SESSION['language']);
// vérifie si une session possède la variable 'language'. Les utilisations suivantes sont équivalentes :
if ($session->has('language')) ...
if (isset($session['language'])) ...
if (isset($_SESSION['language'])) ...
// boucle sur toutes les sessions. Les utilisations suivantes sont équivalentes :
foreach ($session as $name => $value) ...
foreach ($_SESSION as $name => $value) ...
```
> Info: lorsque vous accédez aux données d'une session via le composant `session`, une session est automatiquement ouverte si elle ne l'a pas déjà été. Cela est différent de l'accès aux données via la variable globale `$_SESSION`, qui réclame un appel préalable explicite de `session_start()`.
Lorsque vous travaillez avec les données de session qui sont des tableaux, le composant `session` possède une limitation qui vous empêche de modifier directement un des élément de ces tableaux. Par exemple :
```php
$session = Yii::$app->session;
// le code suivant ne fonctionne PAS
$session['captcha']['number'] = 5;
$session['captcha']['lifetime'] = 3600;
// le code suivant fonctionne :
$session['captcha'] = [
'number' => 5,
'lifetime' => 3600,
];
// le code suivant fonctionne également :
echo $session['captcha']['lifetime'];
```
Vous pouvez utiliser une des solutions de contournement suivantes pour résoudre ce problème :
```php
$session = Yii::$app->session;
// utiliser directement $_SESSION (assurez-vous que Yii::$app->session->open() a été appelée)
$_SESSION['captcha']['number'] = 5;
$_SESSION['captcha']['lifetime'] = 3600;
// obtenir le tableau complet d'abord, le modifier et le sauvegarder
$captcha = $session['captcha'];
$captcha['number'] = 5;
$captcha['lifetime'] = 3600;
$session['captcha'] = $captcha;
// utiliser un ArrayObject au lieu d'un tableau
$session['captcha'] = new \ArrayObject;
...
$session['captcha']['number'] = 5;
$session['captcha']['lifetime'] = 3600;
// stocker les données du tableau par une clé avec un préfixe commun
$session['captcha.number'] = 5;
$session['captcha.lifetime'] = 3600;
```
Pour une meilleure performance et une meilleure lisibilité du code, nous recommandons la dernière solution de contournement. Elle consiste, au lieu de stocker un tableau comme une donnée de session unique, à stocker chacun des éléments du tableau comme une variable de session qui partage le même préfixe de clé avec le reste des éléments de ce tableau.
### Stockage de session personnalisé <span id="custom-session-storage"></span>
La classe par défaut [[yii\web\Session]] stocke les données de session sous forme de fichiers sur le serveur. Yii fournit également des classes de session qui mettent en œuvre des procédés de stockage différents. En voici la liste :
* [[yii\web\DbSession]]: stocke les données de session dans une base de données.
* [[yii\web\CacheSession]]: stocke les données de session dans un cache avec l'aide d'un [composant cache](caching-data.md#cache-components) configuré.
* [[yii\redis\Session]]: stocke les données de session en utilisant le médium de stockage [redis](http://redis.io/) as the storage medium.
* [[yii\mongodb\Session]]: stocke les données de session dans une base de données de documents [MongoDB](http://www.mongodb.org/).
Toutes ces classes de session prennent en charge le même jeu de méthodes d'API. En conséquence, vous pouvez changer de support de stockage sans avoir à modifier le code de votre application qui utilise ces sessions.
> Note: si vous voulez accéder aux données de session via `$_SESSION` quand vous êtes en train d'utiliser une session à stockage personnalisé, vous devez vous assurer que cette session a été préalablement démarrée via [[yii\web\Session::open()]]. Cela est dû au fait que les gestionnaires de stockage des sessions personnalisées sont enregistrés à l'intérieur de cette méthode.
Pour savoir comment configurer et utiliser ces classes de composant, reportez-vous à leur documentation d'API. Ci-dessous, nous présentons un exemple de configuration de [[yii\web\DbSession]] dans la configuration de l'application pour utiliser une base de données en tant que support de stockage d'une session :
```php
return [
'components' => [
'session' => [
'class' => 'yii\web\DbSession',
// 'db' => 'mydb', // l'identifiant du composant d'application de la connexion à la base de données. Valeur par défaut : 'db'.
// 'sessionTable' => 'my_session', // nom de la table 'session' . Valeur par défaut : 'session'.
],
],
];
```
Vous devez aussi créer la base de données suivante pour stocker les données de session :
```sql
CREATE TABLE session
(
id CHAR(40) NOT NULL PRIMARY KEY,
expire INTEGER,
data BLOB
)
```
où 'BLOB' fait référence au type de grand objet binaire (binary large objet — BLOB) de votre système de gestion de base de données (DBMS) préféré. Ci-dessous, vous trouverez les types de BLOB qui peuvent être utilisés par quelques DBMS populaires :
- MySQL: LONGBLOB
- PostgreSQL: BYTEA
- MSSQL: BLOB
> Note: en fonction des réglages de `session.hash_function` dans votre fichier php.ini, vous devez peut-être ajuster la longueur de la colonne `id`. Par exemple, si `session.hash_function=sha256`, vous devez utiliser une longueur de 64 au lieu de 40.
### Donnés flash <span id="flash-data"></span>
Les données flash sont une sorte de données de session spéciale qui, une fois définies dans une requête, ne restent disponibles que durant la requête suivante et sont détruites automatiquement ensuite. Les données flash sont le plus communément utilisées pour mettre en œuvre des messages qui doivent être présentés une seule fois, comme les messages de confirmation affichés après une soumission réussie de formulaire.
Vous pouvez définir des données flash et y accéder via le composant d'application `session`. Par exemple :
```php
$session = Yii::$app->session;
// Request #1
// définit un message flash nommé "commentDeleted"
$session->setFlash('commentDeleted', 'Vous avez réussi la suppression de votre commentaire.');
// Request #2
// affiche le message flash nommé "commentDeleted"
echo $session->getFlash('commentDeleted');
// Request #3
// $result est faux puisque le message flash a été automatiquement supprimé
$result = $session->hasFlash('commentDeleted');
```
Comme les données de session ordinaires, vous pouvez stocker des données arbitraires sous forme de données flash.
Vous pouvez appeler [[yii\web\Session::setFlash()]], cela écrase toute donnée flash préexistante qui a le même nom. Pour ajouter une nouvelle donnée flash à un message existant, vous pouvez utiliser [[yii\web\Session::addFlash()]] à la place. Par exemple :
```php
$session = Yii::$app->session;
// Request #1
// ajoute un message flash nommé "alerts"
$session->addFlash('alerts', 'Vous avez réussi la suppression de votre commentaire');
$session->addFlash('alerts', 'Vous avez réussi l'ajout d'un ami.');
$session->addFlash('alerts', 'Vous êtes promu.');
// Request #2
// $alerts est un tableau de messages flash nommé "alerts"
$alerts = $session->getFlash('alerts');
```
> Note: évitez d'utiliser [[yii\web\Session::setFlash()]] en même temps que [[yii\web\Session::addFlash()]] pour des données flash de même nom. C'est parce que la deuxième méthode transforme automatiquement les données flash en tableau pour pouvoir y ajouter des données. En conséquence, quand vous appelez [[yii\web\Session::getFlash()]], vous pouvez parfois recevoir un tableau ou une chaîne de caractères selon l'ordre dans lequel ces méthodes ont été appelées.
> Tip: pour afficher des messages Flash vous pouvez utiliser l'objet graphique [[yii\bootstrap\Alert|bootstrap Alert]] de la manière suivante :
>
> ```php
> echo Alert::widget([
> 'options' => ['class' => 'alert-info'],
> 'body' => Yii::$app->session->getFlash('postDeleted'),
> ]);
> ```
## Témoins de connexion <span id="cookies"></span>
Yii représente chacun des témoins de connexion sous forme d'objet de classe [[yii\web\Cookie]]. Les objets [[yii\web\Request]] et [[yii\web\Response]] contiennent une collection de témoins de connexion via la propriété nommée `cookies`. La collection de témoins de connexion dans le premier de ces objets est celle soumise dans une requête, tandis que celle du deuxième objet représente les témoins de connexion envoyés à l'utilisateur.
La partie de l'application qui traite la requête et la réponse directement est le contrôleur. Par conséquent, les témoins de connexion doivent être lus et envoyés dans le contrôleur.
### Lecture des témoins de connexion <span id="reading-cookies"></span>
Vous pouvez obtenir les témoins de connexion de la requête courante en utilisant le code suivant :
```php
// obtient la collection de témoins de connexion (yii\web\CookieCollection) du composant "request"
$cookies = Yii::$app->request->cookies;
// obtient la valeur du témoin de connexion "language". Si le témoin de connexion n'existe pas, retourne "en" par défaut.
$language = $cookies->getValue('language', 'en');
// une façon alternative d'obtenir la valeur du témoin de connexion "language"
if (($cookie = $cookies->get('language')) !== null) {
$language = $cookie->value;
}
// vous pouvez aussi utiliser $cookies comme un tableau
if (isset($cookies['language'])) {
$language = $cookies['language']->value;
}
// vérifie si un témoin de connexion "language" existe
if ($cookies->has('language')) ...
if (isset($cookies['language'])) ...
```
### Envoi de témoins de connexion <span id="sending-cookies"></span>
Vous pouvez envoyer des témoins de connexion à l'utilisateur final avec le code suivant :
```php
// obtient la collection de témoins de connexion (yii\web\CookieCollection) du composant "response"
$cookies = Yii::$app->response->cookies;
// ajoute un témoin de connexion à la réponse à envoyer
$cookies->add(new \yii\web\Cookie([
'name' => 'language',
'value' => 'zh-CN',
]));
// supprime un cookie
$cookies->remove('language');
// équivalent à
unset($cookies['language']);
```
En plus des propriétés [[yii\web\Cookie::name|name (nom)]], [[yii\web\Cookie::value|value (valeur)]] montrées dans les exemples ci-dessus, la classe [[yii\web\Cookie]] définit également d'autres propriétés pour représenter complètement toutes les informations de témoin de connexion disponibles, comme les propriétés [[yii\web\Cookie::domain|domain (domaine)]], [[yii\web\Cookie::expire|expire (date d'expiration)]]. Vous pouvez configurer ces propriété selon vos besoins pour préparer un témoin de connexion et ensuite l'ajouter à la collection de témoins de connexion de la réponse.
> Note: pour une meilleure sécurité, la valeur par défaut de la propriété [[yii\web\Cookie::httpOnly]] est définie à `true`. Cela permet de limiter le risque qu'un script client n'accède à un témoin de connexion protégé (si le navigateur le prend en charge). Reportez-vous à l'[article de wiki httpOnly](https://www.owasp.org/index.php/HttpOnly) pour plus de détails.
### Validation des témoins de connexion <span id="cookie-validation"></span>
Lorsque vous lisez ou envoyez des témoins de connexion via les composants `request` et `response` comme expliqué dans les sous-sections qui précèdent, vous appréciez la sécurité additionnelle de validation des témoins de connexion qui protège vos témoins de connexion de la modification côté client. Cela est réalisé en signant chacun des témoins de connexion avec une valeur de hachage qui permet à l'application de dire si un témoin de connexion a été modifié ou pas du côté client. Si c'est le cas, le témoin de connexion n'est PLUS accessible via la [[yii\web\Request::cookies|collection de témoins de connexion]] du composant `request`.
> Note: la validation des témoins de connexion ne protège que contre les effets de la modification des valeurs de témoins de connexion. Néanmoins, si un témoin de connexion ne peut être validé, vous pouvez continuer à y accéder via la variable globale `$_COOKIE`. Ceci est dû au fait que les bibliothèques de tierces parties peuvent manipuler les témoins de connexion d'une façon qui leur est propre, sans forcément impliquer la validation des témoins de connexion.
La validation des témoins de connexion est activée par défaut. Vous pouvez la désactiver en définissant la propriété [[yii\web\Request::enableCookieValidation]] à `false` (faux) mais nous vous recommandons fortement de ne pas le faire.
> Note: les témoins de connexion qui sont lus/écrits directement via `$_COOKIE` et `setcookie()` ne seront PAS validés.
Quand vous utilisez la validation des témoins de connexion, vous devez spécifier une [[yii\web\Request::cookieValidationKey |clé de validation des témoins de connexion]] gui sera utilisée pour générer la valeur de hachage dont nous avons parlé plus haut. Vous pouvez faire ça en configurant le composant `request` dans la configuration de l'application configuration comme indiqué ci-après :
```php
return [
'components' => [
'request' => [
'cookieValidationKey' => 'entrez une clé secrète ici',
],
],
];
```
> Info: la [[yii\web\Request::cookieValidationKey|clé de validation des témoins de connexion (cookieValidationKey)]] est un élément critique de la sécurité de votre application. Elle ne devrait être connue que des personnes à qui vous faites confiance. Ne le stockez pas dans le système de gestion des version.

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

Loading…
Cancel
Save