diff --git a/.gitignore b/.gitignore index fb5029b..1be1354 100644 --- a/.gitignore +++ b/.gitignore @@ -14,12 +14,13 @@ Thumbs.db # composer vendor dir /vendor +# cubrid install dir +/cubrid # composer itself is not needed composer.phar -# composer.lock should not be committed as we always want the latest versions -/composer.lock -# composer.lock in applications is ignored in dev repo, will be committed in checked out app repos + +# composer.lock in applications is ignored since it's automatically created by composer when application is installed /apps/*/composer.lock # Mac DS_Store Files @@ -29,3 +30,7 @@ composer.phar phpunit.phar # local phpunit config /phpunit.xml + +# ignore sub directory for dev installed apps and extensions +/apps +/extensions diff --git a/.scrutinizer.yml b/.scrutinizer.yml index cd15e71..08f5200 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -4,7 +4,7 @@ imports: tools: external_code_coverage: timeout: 2100 # Timeout in seconds. - # disable copy paste detector and simliarity analyzer as they have no real value + # disable copy paste detector and similarity analyzer as they have no real value # and a huge bunch of false-positives php_sim: false php_cpd: false diff --git a/.travis.yml b/.travis.yml index b0bdd26..2bc020b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,60 +4,70 @@ php: - 5.4 - 5.5 - 5.6 + - 7.0 - hhvm - hhvm-nightly +env: + - CUBRID_VERSION=9.3.0/CUBRID-9.3.0.0206 CUBRID_PDO_VERSION=9.3.0.0001 + # run build against hhvm but allow them to fail # http://docs.travis-ci.com/user/build-configuration/#Rows-That-are-Allowed-To-Fail matrix: fast_finish: true allow_failures: - - php: hhvm - php: hhvm-nightly + - php: 7.0 services: - - redis-server - memcached - - elasticsearch - - mongodb + +# faster builds on new travis setup not using sudo +sudo: false + +# cache vendor dirs +cache: + directories: +# - cubrid/9.3.0 + - vendor + - $HOME/.composer/cache # try running against postgres 9.3 addons: postgresql: "9.3" install: - - composer self-update && composer --version + - travis_retry composer self-update && composer --version + - travis_retry composer global require "fxp/composer-asset-plugin:1.0.0" + - export PATH="$HOME/.composer/vendor/bin:$PATH" # core framework: - - composer install --prefer-dist - - tests/unit/data/travis/mongodb-setup.sh + - travis_retry composer install --prefer-dist --no-interaction - tests/unit/data/travis/apc-setup.sh - tests/unit/data/travis/memcache-setup.sh - - tests/unit/data/travis/cubrid-setup.sh -# basic and advanced application: - - tests/unit/data/travis/setup-apps.sh +# - tests/unit/data/travis/cubrid-setup.sh before_script: - - echo 'elasticsearch version ' && curl http://localhost:9200/ + # show some versions and env information + - php -r "echo INTL_ICU_VERSION . \"\n\";" + - mysql --version + - psql --version + + # initialize databases - mysql -e 'CREATE DATABASE yiitest;'; - psql -U postgres -c 'CREATE DATABASE yiitest;'; - - tests/unit/data/travis/sphinx-setup.sh - - mongo yii2test --eval 'db.addUser("travis", "test");' -# basic and advanced application: - - tests/unit/data/travis/init-apps.sh -script: - - vendor/bin/phpunit --verbose --coverage-clover=coverage.clover --exclude-group mssql,oci,wincache,xcache,zenddata - | - if (php --version | grep -i HipHop > /dev/null); then - echo "skipping application tests on HHVM" - else - cd apps/basic && php vendor/bin/codecept run - cd ../advanced/backend && ../vendor/bin/codecept run - cd ../common && ../vendor/bin/codecept run - cd ../frontend && ../vendor/bin/codecept run + if [ $TRAVIS_PHP_VERSION = '5.6' ]; then + PHPUNIT_FLAGS="--coverage-clover=coverage.clover" fi + +script: + - vendor/bin/phpunit --verbose $PHPUNIT_FLAGS --exclude-group mssql,oci,wincache,xcache,zenddata,cubrid + after_script: - - cd ../../.. - - wget https://scrutinizer-ci.com/ocular.phar - - php ocular.phar code-coverage:upload --format=php-clover coverage.clover + - | + if [ $TRAVIS_PHP_VERSION = '5.6' ]; then + travis_retry wget https://scrutinizer-ci.com/ocular.phar + php ocular.phar code-coverage:upload --format=php-clover coverage.clover + fi diff --git a/README.md b/README.md index cc86ad1..eab1cb3 100644 --- a/README.md +++ b/README.md @@ -8,37 +8,22 @@ Yii 2 inherits the main spirit behind Yii for being simple, fast and highly exte Yii 2 requires PHP 5.4 and embraces the best practices and protocols found in modern Web application development. -**Yii 2 is not ready for production use yet.** We may make significant changes without prior notices. -We expect to make the first stable release of Yii 2 in the middle of 2014. - -If you mainly want to learn Yii with no real project development requirement, we highly recommend -you start with Yii 2 as it will be our main focus for the next few years. - -If you have a real project with tight schedule, you should stick to [Yii 1.1](https://github.com/yiisoft/yii) -which is the latest stable release of Yii. - - [![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) -[![Dependency Status](https://www.versioneye.com/php/yiisoft:yii2/dev-master/badge.png)](https://www.versioneye.com/php/yiisoft:yii2/dev-master) +[![Reference Status](https://www.versioneye.com/php/yiisoft:yii2/reference_badge.svg)](https://www.versioneye.com/php/yiisoft:yii2/references) [![Build Status](https://secure.travis-ci.org/yiisoft/yii2.png)](http://travis-ci.org/yiisoft/yii2) -[![HHVM Status](http://hhvm.h4cc.de/badge/yiisoft/yii2-dev.png)](http://hhvm.h4cc.de/package/yiisoft/yii2-dev) +[![Dependency Status](https://www.versioneye.com/php/yiisoft:yii2/dev-master/badge.png)](https://www.versioneye.com/php/yiisoft:yii2/dev-master) +[![HHVM Status](http://hhvm.h4cc.de/badge/yiisoft/yii2-dev.png)](http://hhvm.h4cc.de/package/yiisoft/yii2-dev) [![Code Coverage](https://scrutinizer-ci.com/g/yiisoft/yii2/badges/coverage.png?s=31d80f1036099e9d6a3e4d7738f6b000b3c3d10e)](https://scrutinizer-ci.com/g/yiisoft/yii2/) [![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/yiisoft/yii2/badges/quality-score.png?s=b1074a1ff6d0b214d54fa5ab7abbb90fc092471d)](https://scrutinizer-ci.com/g/yiisoft/yii2/) [![Code Climate](https://codeclimate.com/github/yiisoft/yii2.png)](https://codeclimate.com/github/yiisoft/yii2) -[![Reference Status](https://www.versioneye.com/php/yiisoft:yii2/reference_badge.svg)](https://www.versioneye.com/php/yiisoft:yii2/references) DIRECTORY STRUCTURE ------------------- ``` -apps/ ready-to-use application templates - advanced/ a template suitable for building sophisticated Web applications - basic/ a template suitable for building simple Web applications - benchmark/ an application demonstrating the performance of Yii build/ internally used build tools docs/ documentation -extensions/ extensions framework/ core framework code tests/ tests of the core framework code ``` @@ -53,14 +38,11 @@ The minimum requirement by Yii is that your Web server supports PHP 5.4. DOCUMENTATION ------------- -A draft of the [Definitive Guide](docs/guide/README.md) is available. - -API docs and a rendering of the definitive guide are currently -available under the following urls: +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. -- http://stuff.cebe.cc/yii2docs/ API and Definitive Guide (updated every 15 minutes from the github source) -- http://www.yiiframework.com/doc-2.0/guide-index.html API and Definitive Guide (last updated for the beta release) -- http://stuff.cebe.cc/yii2-guide.pdf The PDF version of the Guide +There is also a [PDF version](http://stuff.cebe.cc/yii2-guide.pdf) of the Definitive Guide +and a [Definitive Guide Mirror](http://stuff.cebe.cc/yii2docs/) which update every 15 minutes. 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. diff --git a/apps/advanced/.gitignore b/apps/advanced/.gitignore deleted file mode 100644 index 346d3b2..0000000 --- a/apps/advanced/.gitignore +++ /dev/null @@ -1,30 +0,0 @@ -# yii console command -/yii - -# phpstorm project files -.idea - -# netbeans project files -nbproject - -# zend studio for eclipse project files -.buildpath -.project -.settings - -# windows thumbnail cache -Thumbs.db - -# composer vendor dir -/vendor - -# composer itself is not needed -composer.phar - -# Mac DS_Store Files -.DS_Store - -# phpunit itself is not needed -phpunit.phar -# local phpunit config -/phpunit.xml diff --git a/apps/advanced/LICENSE.md b/apps/advanced/LICENSE.md deleted file mode 100644 index e98f03d..0000000 --- a/apps/advanced/LICENSE.md +++ /dev/null @@ -1,32 +0,0 @@ -The Yii framework is free software. It is released under the terms of -the following BSD License. - -Copyright © 2008 by Yii Software LLC (http://www.yiisoft.com) -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - * Neither the name of Yii Software LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. diff --git a/apps/advanced/README.md b/apps/advanced/README.md deleted file mode 100644 index 508a414..0000000 --- a/apps/advanced/README.md +++ /dev/null @@ -1,129 +0,0 @@ -Yii 2 Advanced Application Template -=================================== - -Yii 2 Advanced Application Template is a skeleton Yii 2 application best for -developing complex Web applications with multiple tiers. - -The template includes three tiers: front end, back end, and console, each of which -is a separate Yii application. - -The template is designed to work in a team development environment. It supports -deploying the application in different environments. - - -DIRECTORY STRUCTURE -------------------- - -``` -common - config/ contains shared configurations - mail/ contains view files for e-mails - models/ contains model classes used in both backend and frontend - tests/ contains various tests for objects that are common among applications -console - config/ contains console configurations - controllers/ contains console controllers (commands) - migrations/ contains database migrations - models/ contains console-specific model classes - runtime/ contains files generated during runtime - tests/ contains various tests for the console application -backend - assets/ contains application assets such as JavaScript and CSS - config/ contains backend configurations - controllers/ contains Web controller classes - models/ contains backend-specific model classes - runtime/ contains files generated during runtime - tests/ contains various tests for the backend application - views/ contains view files for the Web application - web/ contains the entry script and Web resources -frontend - assets/ contains application assets such as JavaScript and CSS - config/ contains frontend configurations - controllers/ contains Web controller classes - models/ contains frontend-specific model classes - runtime/ contains files generated during runtime - tests/ contains various tests for the frontend application - views/ contains view files for the Web application - web/ contains the entry script and Web resources -vendor/ contains dependent 3rd-party packages -environments/ contains environment-based overrides -``` - - -REQUIREMENTS ------------- - -The minimum requirement by this application template that your Web server supports PHP 5.4.0. - - -INSTALLATION ------------- - -### Install from an Archive File - -Extract the archive file downloaded from [yiiframework.com](http://www.yiiframework.com/download/) to -a directory named `advanced` that is directly under the Web root. - -Then follow the instructions given in "GETTING STARTED". - - -### Install via Composer - -If you do not have [Composer](http://getcomposer.org/), you may install it by following the instructions -at [getcomposer.org](http://getcomposer.org/doc/00-intro.md#installation-nix). - -You can then install the application using the following command: - -~~~ -php composer.phar create-project --prefer-dist --stability=dev yiisoft/yii2-app-advanced advanced -~~~ - - -GETTING STARTED ---------------- - -After you install the application, you have to conduct the following steps to initialize -the installed application. You only need to do these once for all. - -1. Run command `init` to initialize the application with a specific environment. -2. Create a new database and adjust the `components['db']` configuration in `common/config/main-local.php` accordingly. -3. Apply migrations with console command `yii migrate`. This will create tables needed for the application to work. -4. Set document roots of your Web server: - -- for frontend `/path/to/yii-application/frontend/web/` and using the URL `http://frontend/` -- for backend `/path/to/yii-application/backend/web/` and using the URL `http://backend/` - -To login into the application, you need to first sign up, with any of your email address, username and password. -Then, you can login into the application with same email address and password at any time. - -TESTING -------- - -Install additional composer packages: -* `php composer.phar require --dev codeception/codeception:2.0.* codeception/specify:* codeception/verify:* yiisoft/yii2-faker:*` - -This application boilerplate use database in testing, so you should create three databases that are used in tests: -* `yii2_advanced_unit` - database for unit tests; -* `yii2_advanced_functional` - database for functional tests; -* `yii2_advanced_acceptance` - database for acceptance tests. - -To make your database up to date, you can run in needed test folder `yii migrate`, for example -if you are starting from `frontend` tests then you should run `yii migrate` in each suite folder `acceptance`, `functional`, `unit` -it will upgrade your database to the last state according migrations. - -To be able to run acceptance tests you need a running webserver. For this you can use the php builtin server and run it in the directory where your main project folder is located. For example if your application is located in `/www/advanced` all you need to is: -`cd /www` and then `php -S 127.0.0.1:8080` because the default configuration of acceptance tests expects the url of the application to be `/advanced/`. -If you already have a server configured or your application is not located in a folder called `advanced`, you may need to adjust the `test_entry_url` in `backend/codeception.yml` and `frontend/codeception.yml`. - -After that is done you should be able to run your tests, for example to run `frontend` tests do: - -* `cd frontend` -* `../vendor/bin/codecept build` -* `../vendor/bin/codecept run` - -In similar way you can run tests for other application tiers - `backend`, `console`, `common`. - -If you already have run `../vendor/bin/codecept build` for each application, you can run all tests by one command: `vendor/bin/codecept run` - -You also can adjust you application suite configs and `_bootstrap.php` settings to use other urls and files, as it is can be done in `yii2-basic`. -Current template also includes [yii2-faker](https://github.com/yiisoft/yii2/tree/master/extensions/faker) extension, that is correctly setup for each application tier. diff --git a/apps/advanced/backend/assets/AppAsset.php b/apps/advanced/backend/assets/AppAsset.php deleted file mode 100644 index b6c3268..0000000 --- a/apps/advanced/backend/assets/AppAsset.php +++ /dev/null @@ -1,26 +0,0 @@ - - * @since 2.0 - */ -class AppAsset extends AssetBundle -{ - public $basePath = '@webroot'; - public $baseUrl = '@web'; - public $css = ['css/site.css']; - public $js = []; - public $depends = [ - 'yii\web\YiiAsset', - 'yii\bootstrap\BootstrapAsset', - ]; -} diff --git a/apps/advanced/backend/codeception.yml b/apps/advanced/backend/codeception.yml deleted file mode 100644 index 49a978b..0000000 --- a/apps/advanced/backend/codeception.yml +++ /dev/null @@ -1,24 +0,0 @@ -namespace: backend -actor: Tester -paths: - tests: tests - log: tests/_log - data: tests/_data - helpers: tests/_helpers -settings: - bootstrap: _bootstrap.php - suite_class: \PHPUnit_Framework_TestSuite - colors: true - memory_limit: 1024M - log: true -modules: - config: - Db: - dsn: '' - user: '' - password: '' - dump: tests/_data/dump.sql -config: - # the entry script URL (without host info) for functional and acceptance tests - # PLEASE ADJUST IT TO THE ACTUAL ENTRY SCRIPT URL - test_entry_url: /advanced/backend/web/index-test.php diff --git a/apps/advanced/backend/config/.gitignore b/apps/advanced/backend/config/.gitignore deleted file mode 100644 index 20da318..0000000 --- a/apps/advanced/backend/config/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -main-local.php -params-local.php \ No newline at end of file diff --git a/apps/advanced/backend/config/main.php b/apps/advanced/backend/config/main.php deleted file mode 100644 index a0b5fc9..0000000 --- a/apps/advanced/backend/config/main.php +++ /dev/null @@ -1,34 +0,0 @@ - 'app-backend', - 'basePath' => dirname(__DIR__), - 'controllerNamespace' => 'backend\controllers', - 'bootstrap' => ['log'], - 'modules' => [], - 'components' => [ - 'user' => [ - 'identityClass' => 'common\models\User', - 'enableAutoLogin' => true, - ], - 'log' => [ - 'traceLevel' => YII_DEBUG ? 3 : 0, - 'targets' => [ - [ - 'class' => 'yii\log\FileTarget', - 'levels' => ['error', 'warning'], - ], - ], - ], - 'errorHandler' => [ - 'errorAction' => 'site/error', - ], - ], - 'params' => $params, -]; diff --git a/apps/advanced/backend/config/params.php b/apps/advanced/backend/config/params.php deleted file mode 100644 index 7f754b9..0000000 --- a/apps/advanced/backend/config/params.php +++ /dev/null @@ -1,4 +0,0 @@ - 'admin@example.com', -]; diff --git a/apps/advanced/backend/controllers/SiteController.php b/apps/advanced/backend/controllers/SiteController.php deleted file mode 100644 index db3259a..0000000 --- a/apps/advanced/backend/controllers/SiteController.php +++ /dev/null @@ -1,83 +0,0 @@ - [ - 'class' => AccessControl::className(), - 'rules' => [ - [ - 'actions' => ['login', 'error'], - 'allow' => true, - ], - [ - 'actions' => ['logout', 'index'], - 'allow' => true, - 'roles' => ['@'], - ], - ], - ], - 'verbs' => [ - 'class' => VerbFilter::className(), - 'actions' => [ - 'logout' => ['post'], - ], - ], - ]; - } - - /** - * @inheritdoc - */ - public function actions() - { - return [ - 'error' => [ - 'class' => 'yii\web\ErrorAction', - ], - ]; - } - - public function actionIndex() - { - return $this->render('index'); - } - - public function actionLogin() - { - if (!\Yii::$app->user->isGuest) { - return $this->goHome(); - } - - $model = new LoginForm(); - if ($model->load(Yii::$app->request->post()) && $model->login()) { - return $this->goBack(); - } else { - return $this->render('login', [ - 'model' => $model, - ]); - } - } - - public function actionLogout() - { - Yii::$app->user->logout(); - - return $this->goHome(); - } -} diff --git a/apps/advanced/backend/models/.gitkeep b/apps/advanced/backend/models/.gitkeep deleted file mode 100644 index 72e8ffc..0000000 --- a/apps/advanced/backend/models/.gitkeep +++ /dev/null @@ -1 +0,0 @@ -* diff --git a/apps/advanced/backend/runtime/.gitignore b/apps/advanced/backend/runtime/.gitignore deleted file mode 100644 index c96a04f..0000000 --- a/apps/advanced/backend/runtime/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/apps/advanced/backend/tests/.gitignore b/apps/advanced/backend/tests/.gitignore deleted file mode 100644 index c5aa074..0000000 --- a/apps/advanced/backend/tests/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# these files are auto generated by codeception build -/unit/CodeGuy.php -/functional/TestGuy.php -/acceptance/WebGuy.php diff --git a/apps/advanced/backend/tests/_bootstrap.php b/apps/advanced/backend/tests/_bootstrap.php deleted file mode 100644 index bc9d17c..0000000 --- a/apps/advanced/backend/tests/_bootstrap.php +++ /dev/null @@ -1,18 +0,0 @@ - [ - 'mailer' => [ - 'useFileTransport' => true, - ], - 'urlManager' => [ - 'showScriptName' => true, - ], - ], -]; diff --git a/apps/advanced/backend/tests/_console.php b/apps/advanced/backend/tests/_console.php deleted file mode 100644 index b38c84e..0000000 --- a/apps/advanced/backend/tests/_console.php +++ /dev/null @@ -1,19 +0,0 @@ -wantTo('ensure login page works'); - -$loginPage = LoginPage::openBy($I); - -$I->amGoingTo('submit login form with no data'); -$loginPage->login('', ''); -$I->expectTo('see validations errors'); -$I->see('Username cannot be blank.', '.help-block'); -$I->see('Password cannot be blank.', '.help-block'); - -$I->amGoingTo('try to login with wrong credentials'); -$I->expectTo('see validations errors'); -$loginPage->login('admin', 'wrong'); -$I->expectTo('see validations errors'); -$I->see('Incorrect username or password.', '.help-block'); - -$I->amGoingTo('try to login with correct credentials'); -$loginPage->login('erau', 'password_0'); -$I->expectTo('see that user is logged'); -$I->seeLink('Logout (erau)'); -$I->dontSeeLink('Login'); -$I->dontSeeLink('Signup'); -/** Uncomment if using WebDriver - * $I->click('Logout (erau)'); - * $I->dontSeeLink('Logout (erau)'); - * $I->seeLink('Login'); - */ diff --git a/apps/advanced/backend/tests/acceptance/_bootstrap.php b/apps/advanced/backend/tests/acceptance/_bootstrap.php deleted file mode 100644 index 6ce3d17..0000000 --- a/apps/advanced/backend/tests/acceptance/_bootstrap.php +++ /dev/null @@ -1,3 +0,0 @@ - [ - 'db' => [ - 'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_acceptance', - ], - ], - ] -); diff --git a/apps/advanced/backend/tests/acceptance/_console.php b/apps/advanced/backend/tests/acceptance/_console.php deleted file mode 100644 index bae7e44..0000000 --- a/apps/advanced/backend/tests/acceptance/_console.php +++ /dev/null @@ -1,15 +0,0 @@ - [ - 'db' => [ - 'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_acceptance', - ], - ], - ] -); diff --git a/apps/advanced/backend/tests/acceptance/yii b/apps/advanced/backend/tests/acceptance/yii deleted file mode 100644 index a348a9a..0000000 --- a/apps/advanced/backend/tests/acceptance/yii +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env php -run(); -exit($exitCode); diff --git a/apps/advanced/backend/tests/acceptance/yii.bat b/apps/advanced/backend/tests/acceptance/yii.bat deleted file mode 100644 index 5e21e2e..0000000 --- a/apps/advanced/backend/tests/acceptance/yii.bat +++ /dev/null @@ -1,20 +0,0 @@ -@echo off - -rem ------------------------------------------------------------- -rem Yii command line bootstrap script for Windows. -rem -rem @author Qiang Xue -rem @link http://www.yiiframework.com/ -rem @copyright Copyright © 2012 Yii Software LLC -rem @license http://www.yiiframework.com/license/ -rem ------------------------------------------------------------- - -@setlocal - -set YII_PATH=%~dp0 - -if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe - -"%PHP_COMMAND%" "%YII_PATH%yii" %* - -@endlocal diff --git a/apps/advanced/backend/tests/functional.suite.yml b/apps/advanced/backend/tests/functional.suite.yml deleted file mode 100644 index 3c828f5..0000000 --- a/apps/advanced/backend/tests/functional.suite.yml +++ /dev/null @@ -1,17 +0,0 @@ -# Codeception Test Suite Configuration - -# suite for functional (integration) tests. -# emulate web requests and make application process them. -# (tip: better to use with frameworks). - -# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES. -#basic/web/index.php -class_name: TestGuy -modules: - enabled: - - Filesystem - - Yii2 - - common\tests\_helpers\FixtureHelper - config: - Yii2: - configFile: 'tests/functional/_config.php' diff --git a/apps/advanced/backend/tests/functional/LoginCept.php b/apps/advanced/backend/tests/functional/LoginCept.php deleted file mode 100644 index 5bba959..0000000 --- a/apps/advanced/backend/tests/functional/LoginCept.php +++ /dev/null @@ -1,28 +0,0 @@ -wantTo('ensure login page works'); - -$loginPage = LoginPage::openBy($I); - -$I->amGoingTo('submit login form with no data'); -$loginPage->login('', ''); -$I->expectTo('see validations errors'); -$I->see('Username cannot be blank.', '.help-block'); -$I->see('Password cannot be blank.', '.help-block'); - -$I->amGoingTo('try to login with wrong credentials'); -$I->expectTo('see validations errors'); -$loginPage->login('admin', 'wrong'); -$I->expectTo('see validations errors'); -$I->see('Incorrect username or password.', '.help-block'); - -$I->amGoingTo('try to login with correct credentials'); -$loginPage->login('erau', 'password_0'); -$I->expectTo('see that user is logged'); -$I->seeLink('Logout (erau)'); -$I->dontSeeLink('Login'); -$I->dontSeeLink('Signup'); diff --git a/apps/advanced/backend/tests/functional/_bootstrap.php b/apps/advanced/backend/tests/functional/_bootstrap.php deleted file mode 100644 index 6ce3d17..0000000 --- a/apps/advanced/backend/tests/functional/_bootstrap.php +++ /dev/null @@ -1,3 +0,0 @@ - [ - 'db' => [ - 'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_functional', - ], - ], - ] -); diff --git a/apps/advanced/backend/tests/functional/_console.php b/apps/advanced/backend/tests/functional/_console.php deleted file mode 100644 index d76662c..0000000 --- a/apps/advanced/backend/tests/functional/_console.php +++ /dev/null @@ -1,15 +0,0 @@ - [ - 'db' => [ - 'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_functional', - ], - ], - ] -); diff --git a/apps/advanced/backend/tests/functional/yii b/apps/advanced/backend/tests/functional/yii deleted file mode 100644 index a348a9a..0000000 --- a/apps/advanced/backend/tests/functional/yii +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env php -run(); -exit($exitCode); diff --git a/apps/advanced/backend/tests/functional/yii.bat b/apps/advanced/backend/tests/functional/yii.bat deleted file mode 100644 index 5e21e2e..0000000 --- a/apps/advanced/backend/tests/functional/yii.bat +++ /dev/null @@ -1,20 +0,0 @@ -@echo off - -rem ------------------------------------------------------------- -rem Yii command line bootstrap script for Windows. -rem -rem @author Qiang Xue -rem @link http://www.yiiframework.com/ -rem @copyright Copyright © 2012 Yii Software LLC -rem @license http://www.yiiframework.com/license/ -rem ------------------------------------------------------------- - -@setlocal - -set YII_PATH=%~dp0 - -if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe - -"%PHP_COMMAND%" "%YII_PATH%yii" %* - -@endlocal diff --git a/apps/advanced/backend/tests/unit.suite.yml b/apps/advanced/backend/tests/unit.suite.yml deleted file mode 100644 index f0573a8..0000000 --- a/apps/advanced/backend/tests/unit.suite.yml +++ /dev/null @@ -1,6 +0,0 @@ -# Codeception Test Suite Configuration - -# suite for unit (internal) tests. -# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES. - -class_name: CodeGuy diff --git a/apps/advanced/backend/tests/unit/DbTestCase.php b/apps/advanced/backend/tests/unit/DbTestCase.php deleted file mode 100644 index 6c40020..0000000 --- a/apps/advanced/backend/tests/unit/DbTestCase.php +++ /dev/null @@ -1,8 +0,0 @@ - [ - 'db' => [ - 'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_unit', - ], - ], - ] -); diff --git a/apps/advanced/backend/tests/unit/_console.php b/apps/advanced/backend/tests/unit/_console.php deleted file mode 100644 index d7a1791..0000000 --- a/apps/advanced/backend/tests/unit/_console.php +++ /dev/null @@ -1,22 +0,0 @@ - [ - 'db' => [ - 'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_unit', - ], - ], - 'controllerMap' => [ - 'fixture' => [ - 'class' => 'yii\faker\FixtureController', - 'fixtureDataPath' => '@backend/tests/unit/fixtures/data', - 'templatePath' => '@commmon/tests/templates/fixtures' - ], - ], - ] -); diff --git a/apps/advanced/backend/tests/unit/fixtures/data/.gitkeep b/apps/advanced/backend/tests/unit/fixtures/data/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/apps/advanced/backend/tests/unit/yii b/apps/advanced/backend/tests/unit/yii deleted file mode 100644 index a348a9a..0000000 --- a/apps/advanced/backend/tests/unit/yii +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env php -run(); -exit($exitCode); diff --git a/apps/advanced/backend/tests/unit/yii.bat b/apps/advanced/backend/tests/unit/yii.bat deleted file mode 100644 index 5e21e2e..0000000 --- a/apps/advanced/backend/tests/unit/yii.bat +++ /dev/null @@ -1,20 +0,0 @@ -@echo off - -rem ------------------------------------------------------------- -rem Yii command line bootstrap script for Windows. -rem -rem @author Qiang Xue -rem @link http://www.yiiframework.com/ -rem @copyright Copyright © 2012 Yii Software LLC -rem @license http://www.yiiframework.com/license/ -rem ------------------------------------------------------------- - -@setlocal - -set YII_PATH=%~dp0 - -if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe - -"%PHP_COMMAND%" "%YII_PATH%yii" %* - -@endlocal diff --git a/apps/advanced/backend/views/layouts/main.php b/apps/advanced/backend/views/layouts/main.php deleted file mode 100644 index e3f294f..0000000 --- a/apps/advanced/backend/views/layouts/main.php +++ /dev/null @@ -1,71 +0,0 @@ - -beginPage() ?> - - - - - - - <?= Html::encode($this->title) ?> - head() ?> - - - beginBody() ?> -
- 'My Company', - 'brandUrl' => Yii::$app->homeUrl, - 'options' => [ - 'class' => 'navbar-inverse navbar-fixed-top', - ], - ]); - $menuItems = [ - ['label' => 'Home', 'url' => ['/site/index']], - ]; - if (Yii::$app->user->isGuest) { - $menuItems[] = ['label' => 'Login', 'url' => ['/site/login']]; - } else { - $menuItems[] = [ - 'label' => 'Logout (' . Yii::$app->user->identity->username . ')', - 'url' => ['/site/logout'], - 'linkOptions' => ['data-method' => 'post'] - ]; - } - echo Nav::widget([ - 'options' => ['class' => 'navbar-nav navbar-right'], - 'items' => $menuItems, - ]); - NavBar::end(); - ?> - -
- isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [], - ]) ?> - -
-
- -
-
-

© My Company

-

-
-
- - endBody() ?> - - -endPage() ?> diff --git a/apps/advanced/backend/views/site/error.php b/apps/advanced/backend/views/site/error.php deleted file mode 100644 index b9812c4..0000000 --- a/apps/advanced/backend/views/site/error.php +++ /dev/null @@ -1,27 +0,0 @@ -title = $name; -?> -
- -

title) ?>

- -
- -
- -

- The above error occurred while the Web server was processing your request. -

-

- Please contact us if you think this is a server error. Thank you. -

- -
diff --git a/apps/advanced/backend/views/site/index.php b/apps/advanced/backend/views/site/index.php deleted file mode 100644 index 0159bef..0000000 --- a/apps/advanced/backend/views/site/index.php +++ /dev/null @@ -1,52 +0,0 @@ -title = 'My Yii Application'; -?> -
- -
-

Congratulations!

- -

You have successfully created your Yii-powered application.

- -

Get started with Yii

-
- -
- -
-
-

Heading

- -

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et - dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip - ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu - fugiat nulla pariatur.

- -

Yii Documentation »

-
-
-

Heading

- -

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et - dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip - ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu - fugiat nulla pariatur.

- -

Yii Forum »

-
-
-

Heading

- -

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et - dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip - ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu - fugiat nulla pariatur.

- -

Yii Extensions »

-
-
- -
-
diff --git a/apps/advanced/backend/views/site/login.php b/apps/advanced/backend/views/site/login.php deleted file mode 100644 index aad55b8..0000000 --- a/apps/advanced/backend/views/site/login.php +++ /dev/null @@ -1,29 +0,0 @@ -title = 'Login'; -$this->params['breadcrumbs'][] = $this->title; -?> - diff --git a/apps/advanced/backend/web/.gitignore b/apps/advanced/backend/web/.gitignore deleted file mode 100644 index 25c74e6..0000000 --- a/apps/advanced/backend/web/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/index.php -/index-test.php diff --git a/apps/advanced/backend/web/assets/.gitignore b/apps/advanced/backend/web/assets/.gitignore deleted file mode 100644 index c96a04f..0000000 --- a/apps/advanced/backend/web/assets/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/apps/advanced/backend/web/css/site.css b/apps/advanced/backend/web/css/site.css deleted file mode 100644 index 698be70..0000000 --- a/apps/advanced/backend/web/css/site.css +++ /dev/null @@ -1,91 +0,0 @@ -html, -body { - height: 100%; -} - -.wrap { - min-height: 100%; - height: auto; - margin: 0 auto -60px; - padding: 0 0 60px; -} - -.wrap > .container { - padding: 70px 15px 20px; -} - -.footer { - height: 60px; - background-color: #f5f5f5; - border-top: 1px solid #ddd; - padding-top: 20px; -} - -.jumbotron { - text-align: center; - background-color: transparent; -} - -.jumbotron .btn { - font-size: 21px; - padding: 14px 24px; -} - -.not-set { - color: #c55; - font-style: italic; -} - -/* add sorting icons to gridview sort links */ -a.asc:after, a.desc:after { - position: relative; - top: 1px; - display: inline-block; - font-family: 'Glyphicons Halflings'; - font-style: normal; - font-weight: normal; - line-height: 1; - padding-left: 5px; -} - -a.asc:after { - content: /*"\e113"*/ "\e151"; -} - -a.desc:after { - content: /*"\e114"*/ "\e152"; -} - -.sort-numerical a.asc:after { - content: "\e153"; -} - -.sort-numerical a.desc:after { - content: "\e154"; -} - -.sort-ordinal a.asc:after { - content: "\e155"; -} - -.sort-ordinal a.desc:after { - content: "\e156"; -} - -.grid-view th { - white-space: nowrap; -} - -.hint-block { - display: block; - margin-top: 5px; - color: #999; -} - -.error-summary { - color: #a94442; - background: #fdf7f7; - border-left: 3px solid #eed3d7; - padding: 10px 20px; - margin: 0 0 15px 0; -} diff --git a/apps/advanced/backend/web/favicon.ico b/apps/advanced/backend/web/favicon.ico deleted file mode 100644 index 580ed73..0000000 Binary files a/apps/advanced/backend/web/favicon.ico and /dev/null differ diff --git a/apps/advanced/backend/web/robots.txt b/apps/advanced/backend/web/robots.txt deleted file mode 100644 index c6742d8..0000000 --- a/apps/advanced/backend/web/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-Agent: * -Disallow: / diff --git a/apps/advanced/codeception.yml b/apps/advanced/codeception.yml deleted file mode 100644 index c94b9fd..0000000 --- a/apps/advanced/codeception.yml +++ /dev/null @@ -1,11 +0,0 @@ -include: - - common - - console - - backend - - frontend - -paths: - log: tests/_log - -settings: - colors: true diff --git a/apps/advanced/common/codeception.yml b/apps/advanced/common/codeception.yml deleted file mode 100644 index 4ee1523..0000000 --- a/apps/advanced/common/codeception.yml +++ /dev/null @@ -1,20 +0,0 @@ -namespace: common -actor: Tester -paths: - tests: tests - log: tests/_log - data: tests/_data - helpers: tests/_helpers -settings: - bootstrap: _bootstrap.php - suite_class: \PHPUnit_Framework_TestSuite - colors: true - memory_limit: 1024M - log: true -modules: - config: - Db: - dsn: '' - user: '' - password: '' - dump: tests/_data/dump.sql diff --git a/apps/advanced/common/config/.gitignore b/apps/advanced/common/config/.gitignore deleted file mode 100644 index 97c0f01..0000000 --- a/apps/advanced/common/config/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -main-local.php -params-local.php diff --git a/apps/advanced/common/config/aliases.php b/apps/advanced/common/config/aliases.php deleted file mode 100644 index ecc13e5..0000000 --- a/apps/advanced/common/config/aliases.php +++ /dev/null @@ -1,5 +0,0 @@ - dirname(dirname(__DIR__)) . '/vendor', - 'components' => [ - 'cache' => [ - 'class' => 'yii\caching\FileCache', - ], - ], -]; diff --git a/apps/advanced/common/config/params.php b/apps/advanced/common/config/params.php deleted file mode 100644 index 4ec9ba6..0000000 --- a/apps/advanced/common/config/params.php +++ /dev/null @@ -1,6 +0,0 @@ - 'admin@example.com', - 'supportEmail' => 'support@example.com', - 'user.passwordResetTokenExpire' => 3600, -]; diff --git a/apps/advanced/common/mail/layouts/html.php b/apps/advanced/common/mail/layouts/html.php deleted file mode 100644 index bddbc61..0000000 --- a/apps/advanced/common/mail/layouts/html.php +++ /dev/null @@ -1,22 +0,0 @@ - -beginPage() ?> - - - - - <?= Html::encode($this->title) ?> - head() ?> - - - beginBody() ?> - - endBody() ?> - - -endPage() ?> diff --git a/apps/advanced/common/mail/passwordResetToken.php b/apps/advanced/common/mail/passwordResetToken.php deleted file mode 100644 index 4093dc9..0000000 --- a/apps/advanced/common/mail/passwordResetToken.php +++ /dev/null @@ -1,14 +0,0 @@ -urlManager->createAbsoluteUrl(['site/reset-password', 'token' => $user->password_reset_token]); -?> - -Hello username) ?>, - -Follow the link below to reset your password: - - diff --git a/apps/advanced/common/models/LoginForm.php b/apps/advanced/common/models/LoginForm.php deleted file mode 100644 index 80a5f6a..0000000 --- a/apps/advanced/common/models/LoginForm.php +++ /dev/null @@ -1,77 +0,0 @@ -hasErrors()) { - $user = $this->getUser(); - if (!$user || !$user->validatePassword($this->password)) { - $this->addError($attribute, 'Incorrect username or password.'); - } - } - } - - /** - * Logs in a user using the provided username and password. - * - * @return boolean whether the user is logged in successfully - */ - public function login() - { - if ($this->validate()) { - return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0); - } else { - return false; - } - } - - /** - * Finds user by [[username]] - * - * @return User|null - */ - public function getUser() - { - if ($this->_user === false) { - $this->_user = User::findByUsername($this->username); - } - - return $this->_user; - } -} diff --git a/apps/advanced/common/models/User.php b/apps/advanced/common/models/User.php deleted file mode 100644 index 76c0926..0000000 --- a/apps/advanced/common/models/User.php +++ /dev/null @@ -1,180 +0,0 @@ - self::STATUS_ACTIVE], - ['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]], - - ['role', 'default', 'value' => self::ROLE_USER], - ['role', 'in', 'range' => [self::ROLE_USER]], - ]; - } - - /** - * @inheritdoc - */ - public static function findIdentity($id) - { - return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]); - } - - /** - * @inheritdoc - */ - public static function findIdentityByAccessToken($token, $type = null) - { - throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.'); - } - - /** - * Finds user by username - * - * @param string $username - * @return static|null - */ - public static function findByUsername($username) - { - return static::findOne(['username' => $username, 'status' => self::STATUS_ACTIVE]); - } - - /** - * Finds user by password reset token - * - * @param string $token password reset token - * @return static|null - */ - public static function findByPasswordResetToken($token) - { - $expire = Yii::$app->params['user.passwordResetTokenExpire']; - $parts = explode('_', $token); - $timestamp = (int) end($parts); - if ($timestamp + $expire < time()) { - // token expired - return null; - } - - return static::findOne([ - 'password_reset_token' => $token, - 'status' => self::STATUS_ACTIVE, - ]); - } - - /** - * @inheritdoc - */ - public function getId() - { - return $this->getPrimaryKey(); - } - - /** - * @inheritdoc - */ - public function getAuthKey() - { - return $this->auth_key; - } - - /** - * @inheritdoc - */ - public function validateAuthKey($authKey) - { - return $this->getAuthKey() === $authKey; - } - - /** - * Validates password - * - * @param string $password password to validate - * @return boolean if password provided is valid for current user - */ - public function validatePassword($password) - { - return Yii::$app->security->validatePassword($password, $this->password_hash); - } - - /** - * Generates password hash from password and sets it to the model - * - * @param string $password - */ - public function setPassword($password) - { - $this->password_hash = Yii::$app->security->generatePasswordHash($password); - } - - /** - * Generates "remember me" authentication key - */ - public function generateAuthKey() - { - $this->auth_key = Yii::$app->security->generateRandomString(); - } - - /** - * Generates new password reset token - */ - public function generatePasswordResetToken() - { - $this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time(); - } - - /** - * Removes password reset token - */ - public function removePasswordResetToken() - { - $this->password_reset_token = null; - } -} diff --git a/apps/advanced/common/tests/.gitignore b/apps/advanced/common/tests/.gitignore deleted file mode 100644 index c5aa074..0000000 --- a/apps/advanced/common/tests/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# these files are auto generated by codeception build -/unit/CodeGuy.php -/functional/TestGuy.php -/acceptance/WebGuy.php diff --git a/apps/advanced/common/tests/_bootstrap.php b/apps/advanced/common/tests/_bootstrap.php deleted file mode 100644 index 15b36bc..0000000 --- a/apps/advanced/common/tests/_bootstrap.php +++ /dev/null @@ -1,14 +0,0 @@ - [ - 'mailer' => [ - 'useFileTransport' => true, - ], - 'urlManager' => [ - 'showScriptName' => true, - ], - ], -]; diff --git a/apps/advanced/common/tests/_console.php b/apps/advanced/common/tests/_console.php deleted file mode 100644 index b38c84e..0000000 --- a/apps/advanced/common/tests/_console.php +++ /dev/null @@ -1,19 +0,0 @@ -loadFixtures(); - } - - /** - * Method is called after all suite tests run - */ - public function _afterSuite() - { - $this->unloadFixtures(); - } - - /** - * @inheritdoc - */ - public function fixtures() - { - return [ - 'user' => [ - 'class' => UserFixture::className(), - 'dataFile' => '@common/tests/fixtures/data/init_login.php', - ], - ]; - } -} diff --git a/apps/advanced/common/tests/_log/.gitignore b/apps/advanced/common/tests/_log/.gitignore deleted file mode 100644 index d6b7ef3..0000000 --- a/apps/advanced/common/tests/_log/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore diff --git a/apps/advanced/common/tests/_pages/LoginPage.php b/apps/advanced/common/tests/_pages/LoginPage.php deleted file mode 100644 index b0d4c75..0000000 --- a/apps/advanced/common/tests/_pages/LoginPage.php +++ /dev/null @@ -1,21 +0,0 @@ -guy->fillField('input[name="LoginForm[username]"]', $username); - $this->guy->fillField('input[name="LoginForm[password]"]', $password); - $this->guy->click('login-button'); - } -} diff --git a/apps/advanced/common/tests/fixtures/UserFixture.php b/apps/advanced/common/tests/fixtures/UserFixture.php deleted file mode 100644 index 4aea8fd..0000000 --- a/apps/advanced/common/tests/fixtures/UserFixture.php +++ /dev/null @@ -1,10 +0,0 @@ - 'erau', - 'auth_key' => 'tUu1qHcde0diwUol3xeI-18MuHkkprQI', - // password_0 - 'password_hash' => '$2y$13$nJ1WDlBaGcbCdbNC5.5l4.sgy.OMEKCqtDQOdQ2OWpgiKRWYyzzne', - 'password_reset_token' => 'RkD_Jw0_8HEedzLk7MM-ZKEFfYR7VbMr_1392559490', - 'created_at' => '1392559490', - 'updated_at' => '1392559490', - 'email' => 'sfriesen@jenkins.info', - ], -]; diff --git a/apps/advanced/common/tests/templates/fixtures/user.php b/apps/advanced/common/tests/templates/fixtures/user.php deleted file mode 100644 index d3f83b5..0000000 --- a/apps/advanced/common/tests/templates/fixtures/user.php +++ /dev/null @@ -1,17 +0,0 @@ -getSecurity(); - -return [ - 'username' => $faker->userName, - 'email' => $faker->email, - 'auth_key' => $security->generateRandomString(), - 'password_hash' => $security->generatePasswordHash('password_' . $index), - 'password_reset_token' => $security->generateRandomString() . '_' . time(), - 'created_at' => time(), - 'updated_at' => time(), -]; diff --git a/apps/advanced/common/tests/unit.suite.yml b/apps/advanced/common/tests/unit.suite.yml deleted file mode 100644 index f0573a8..0000000 --- a/apps/advanced/common/tests/unit.suite.yml +++ /dev/null @@ -1,6 +0,0 @@ -# Codeception Test Suite Configuration - -# suite for unit (internal) tests. -# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES. - -class_name: CodeGuy diff --git a/apps/advanced/common/tests/unit/DbTestCase.php b/apps/advanced/common/tests/unit/DbTestCase.php deleted file mode 100644 index 942fcd7..0000000 --- a/apps/advanced/common/tests/unit/DbTestCase.php +++ /dev/null @@ -1,8 +0,0 @@ - [ - 'db' => [ - 'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_unit', - ], - ], - 'id' => 'app-common', - 'basePath' => dirname(__DIR__), - ] -); diff --git a/apps/advanced/common/tests/unit/_console.php b/apps/advanced/common/tests/unit/_console.php deleted file mode 100644 index 258c752..0000000 --- a/apps/advanced/common/tests/unit/_console.php +++ /dev/null @@ -1,22 +0,0 @@ - [ - 'db' => [ - 'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_unit', - ], - ], - 'controllerMap' => [ - 'fixture' => [ - 'class' => 'yii\faker\FixtureController', - 'fixtureDataPath' => '@common/tests/unit/fixtures/data', - 'templatePath' => '@common/tests/templates/fixtures' - ], - ], - ] -); diff --git a/apps/advanced/common/tests/unit/fixtures/data/models/user.php b/apps/advanced/common/tests/unit/fixtures/data/models/user.php deleted file mode 100644 index 9c9f50a..0000000 --- a/apps/advanced/common/tests/unit/fixtures/data/models/user.php +++ /dev/null @@ -1,14 +0,0 @@ - 'bayer.hudson', - 'auth_key' => 'HP187Mvq7Mmm3CTU80dLkGmni_FUH_lR', - //password_0 - 'password_hash' => '$2y$13$EjaPFBnZOQsHdGuHI.xvhuDp1fHpo8hKRSk6yshqa9c5EG8s3C3lO', - 'password_reset_token' => 'ExzkCOaYc1L8IOBs4wdTGGbgNiG3Wz1I_1402312317', - 'created_at' => '1402312317', - 'updated_at' => '1402312317', - 'email' => 'nicole.paucek@schultz.info', - ], -]; diff --git a/apps/advanced/common/tests/unit/models/LoginFormTest.php b/apps/advanced/common/tests/unit/models/LoginFormTest.php deleted file mode 100644 index ba83ef4..0000000 --- a/apps/advanced/common/tests/unit/models/LoginFormTest.php +++ /dev/null @@ -1,88 +0,0 @@ - [ - 'user' => [ - 'class' => 'yii\web\User', - 'identityClass' => 'common\models\User', - ], - ], - ]); - } - - protected function tearDown() - { - Yii::$app->user->logout(); - parent::tearDown(); - } - - public function testLoginNoUser() - { - $model = new LoginForm([ - 'username' => 'not_existing_username', - 'password' => 'not_existing_password', - ]); - - $this->specify('user should not be able to login, when there is no identity', function () use ($model) { - expect('model should not login user', $model->login())->false(); - expect('user should not be logged in', Yii::$app->user->isGuest)->true(); - }); - } - - public function testLoginWrongPassword() - { - $model = new LoginForm([ - 'username' => 'bayer.hudson', - 'password' => 'wrong_password', - ]); - - $this->specify('user should not be able to login with wrong password', function () use ($model) { - expect('model should not login user', $model->login())->false(); - expect('error message should be set', $model->errors)->hasKey('password'); - expect('user should not be logged in', Yii::$app->user->isGuest)->true(); - }); - } - - public function testLoginCorrect() - { - - $model = new LoginForm([ - 'username' => 'bayer.hudson', - 'password' => 'password_0', - ]); - - $this->specify('user should be able to login with correct credentials', function () use ($model) { - expect('model should login user', $model->login())->true(); - expect('error message should not be set', $model->errors)->hasntKey('password'); - expect('user should be logged in', Yii::$app->user->isGuest)->false(); - }); - } - - public function fixtures() - { - return [ - 'user' => [ - 'class' => UserFixture::className(), - 'dataFile' => '@common/tests/unit/fixtures/data/models/user.php' - ], - ]; - } - -} diff --git a/apps/advanced/common/tests/unit/yii b/apps/advanced/common/tests/unit/yii deleted file mode 100644 index a348a9a..0000000 --- a/apps/advanced/common/tests/unit/yii +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env php -run(); -exit($exitCode); diff --git a/apps/advanced/common/tests/unit/yii.bat b/apps/advanced/common/tests/unit/yii.bat deleted file mode 100644 index 5e21e2e..0000000 --- a/apps/advanced/common/tests/unit/yii.bat +++ /dev/null @@ -1,20 +0,0 @@ -@echo off - -rem ------------------------------------------------------------- -rem Yii command line bootstrap script for Windows. -rem -rem @author Qiang Xue -rem @link http://www.yiiframework.com/ -rem @copyright Copyright © 2012 Yii Software LLC -rem @license http://www.yiiframework.com/license/ -rem ------------------------------------------------------------- - -@setlocal - -set YII_PATH=%~dp0 - -if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe - -"%PHP_COMMAND%" "%YII_PATH%yii" %* - -@endlocal diff --git a/apps/advanced/composer.json b/apps/advanced/composer.json deleted file mode 100644 index 639396b..0000000 --- a/apps/advanced/composer.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "name": "yiisoft/yii2-app-advanced", - "description": "Yii 2 Advanced Application Template", - "keywords": ["yii2", "framework", "advanced", "application template"], - "homepage": "http://www.yiiframework.com/", - "type": "project", - "license": "BSD-3-Clause", - "support": { - "issues": "https://github.com/yiisoft/yii2/issues?state=open", - "forum": "http://www.yiiframework.com/forum/", - "wiki": "http://www.yiiframework.com/wiki/", - "irc": "irc://irc.freenode.net/yii", - "source": "https://github.com/yiisoft/yii2" - }, - "minimum-stability": "dev", - "require": { - "php": ">=5.4.0", - "yiisoft/yii2": "*", - "yiisoft/yii2-bootstrap": "*", - "yiisoft/yii2-swiftmailer": "*" - }, - "require-dev": { - "yiisoft/yii2-codeception": "*", - "yiisoft/yii2-debug": "*", - "yiisoft/yii2-gii": "*" - }, - "suggest": { - "codeception/codeception": "Codeception, 2.0.* is currently works well with Yii.", - "codeception/specify": "BDD style code blocks for PHPUnit and Codeception", - "codeception/verify": "BDD Assertions for PHPUnit and Codeception", - "yiisoft/yii2-faker": "Fixtures generator for Yii2 based on Faker lib" - }, - "scripts": { - "post-create-project-cmd": [ - "yii\\composer\\Installer::setPermission" - ] - }, - "config": { - "process-timeout": 1800 - }, - "extra": { - "writable": [ - "backend/runtime", - "backend/web/assets", - - "frontend/runtime", - "frontend/web/assets" - ] - } -} diff --git a/apps/advanced/console/codeception.yml b/apps/advanced/console/codeception.yml deleted file mode 100644 index 94a12e3..0000000 --- a/apps/advanced/console/codeception.yml +++ /dev/null @@ -1,20 +0,0 @@ -namespace: console -actor: Tester -paths: - tests: tests - log: tests/_log - data: tests/_data - helpers: tests/_helpers -settings: - bootstrap: _bootstrap.php - suite_class: \PHPUnit_Framework_TestSuite - colors: true - memory_limit: 1024M - log: true -modules: - config: - Db: - dsn: '' - user: '' - password: '' - dump: tests/_data/dump.sql diff --git a/apps/advanced/console/config/.gitignore b/apps/advanced/console/config/.gitignore deleted file mode 100644 index 20da318..0000000 --- a/apps/advanced/console/config/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -main-local.php -params-local.php \ No newline at end of file diff --git a/apps/advanced/console/config/main.php b/apps/advanced/console/config/main.php deleted file mode 100644 index ec60922..0000000 --- a/apps/advanced/console/config/main.php +++ /dev/null @@ -1,26 +0,0 @@ - 'app-console', - 'basePath' => dirname(__DIR__), - 'bootstrap' => ['log'], - 'controllerNamespace' => 'console\controllers', - 'modules' => [], - 'components' => [ - 'log' => [ - 'targets' => [ - [ - 'class' => 'yii\log\FileTarget', - 'levels' => ['error', 'warning'], - ], - ], - ], - ], - 'params' => $params, -]; diff --git a/apps/advanced/console/config/params.php b/apps/advanced/console/config/params.php deleted file mode 100644 index 7f754b9..0000000 --- a/apps/advanced/console/config/params.php +++ /dev/null @@ -1,4 +0,0 @@ - 'admin@example.com', -]; diff --git a/apps/advanced/console/controllers/.gitkeep b/apps/advanced/console/controllers/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/apps/advanced/console/migrations/m130524_201442_init.php b/apps/advanced/console/migrations/m130524_201442_init.php deleted file mode 100644 index 8e6243e..0000000 --- a/apps/advanced/console/migrations/m130524_201442_init.php +++ /dev/null @@ -1,34 +0,0 @@ -db->driverName === 'mysql') { - $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=InnoDB'; - } - - $this->createTable('{{%user}}', [ - 'id' => Schema::TYPE_PK, - 'username' => Schema::TYPE_STRING . ' NOT NULL', - 'auth_key' => Schema::TYPE_STRING . '(32) NOT NULL', - 'password_hash' => Schema::TYPE_STRING . ' NOT NULL', - 'password_reset_token' => Schema::TYPE_STRING, - 'email' => Schema::TYPE_STRING . ' NOT NULL', - 'role' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 10', - - 'status' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 10', - 'created_at' => Schema::TYPE_INTEGER . ' NOT NULL', - 'updated_at' => Schema::TYPE_INTEGER . ' NOT NULL', - ], $tableOptions); - } - - public function down() - { - $this->dropTable('{{%user}}'); - } -} diff --git a/apps/advanced/console/models/.gitkeep b/apps/advanced/console/models/.gitkeep deleted file mode 100644 index 72e8ffc..0000000 --- a/apps/advanced/console/models/.gitkeep +++ /dev/null @@ -1 +0,0 @@ -* diff --git a/apps/advanced/console/runtime/.gitignore b/apps/advanced/console/runtime/.gitignore deleted file mode 100644 index c96a04f..0000000 --- a/apps/advanced/console/runtime/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/apps/advanced/console/tests/.gitignore b/apps/advanced/console/tests/.gitignore deleted file mode 100644 index 65a0d8a..0000000 --- a/apps/advanced/console/tests/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# these files are auto generated by codeception build -/unit/CodeGuy.php diff --git a/apps/advanced/console/tests/_bootstrap.php b/apps/advanced/console/tests/_bootstrap.php deleted file mode 100644 index 15b36bc..0000000 --- a/apps/advanced/console/tests/_bootstrap.php +++ /dev/null @@ -1,14 +0,0 @@ - [ - 'mailer' => [ - 'useFileTransport' => true, - ], - 'urlManager' => [ - 'showScriptName' => true, - ], - ], -]; diff --git a/apps/advanced/console/tests/_console.php b/apps/advanced/console/tests/_console.php deleted file mode 100644 index b38c84e..0000000 --- a/apps/advanced/console/tests/_console.php +++ /dev/null @@ -1,19 +0,0 @@ - [ - 'db' => [ - 'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_unit', - ], - ], - ] -); diff --git a/apps/advanced/console/tests/unit/_console.php b/apps/advanced/console/tests/unit/_console.php deleted file mode 100644 index bbb5fa3..0000000 --- a/apps/advanced/console/tests/unit/_console.php +++ /dev/null @@ -1,22 +0,0 @@ - [ - 'db' => [ - 'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_unit', - ], - ], - 'controllerMap' => [ - 'fixture' => [ - 'class' => 'yii\faker\FixtureController', - 'fixtureDataPath' => '@console/tests/unit/fixtures/data', - 'templatePath' => '@common/tests/templates/fixtures' - ], - ], - ] -); diff --git a/apps/advanced/console/tests/unit/fixtures/data/.gitkeep b/apps/advanced/console/tests/unit/fixtures/data/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/apps/advanced/console/tests/unit/yii b/apps/advanced/console/tests/unit/yii deleted file mode 100644 index a348a9a..0000000 --- a/apps/advanced/console/tests/unit/yii +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env php -run(); -exit($exitCode); diff --git a/apps/advanced/console/tests/unit/yii.bat b/apps/advanced/console/tests/unit/yii.bat deleted file mode 100644 index 5e21e2e..0000000 --- a/apps/advanced/console/tests/unit/yii.bat +++ /dev/null @@ -1,20 +0,0 @@ -@echo off - -rem ------------------------------------------------------------- -rem Yii command line bootstrap script for Windows. -rem -rem @author Qiang Xue -rem @link http://www.yiiframework.com/ -rem @copyright Copyright © 2012 Yii Software LLC -rem @license http://www.yiiframework.com/license/ -rem ------------------------------------------------------------- - -@setlocal - -set YII_PATH=%~dp0 - -if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe - -"%PHP_COMMAND%" "%YII_PATH%yii" %* - -@endlocal diff --git a/apps/advanced/environments/dev/backend/config/main-local.php b/apps/advanced/environments/dev/backend/config/main-local.php deleted file mode 100644 index d9e3809..0000000 --- a/apps/advanced/environments/dev/backend/config/main-local.php +++ /dev/null @@ -1,21 +0,0 @@ - [ - 'request' => [ - // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation - 'cookieValidationKey' => '', - ], - ], -]; - -if (!YII_ENV_TEST) { - // configuration adjustments for 'dev' environment - $config['bootstrap'][] = 'debug'; - $config['modules']['debug'] = 'yii\debug\Module'; - - $config['bootstrap'][] = 'gii'; - $config['modules']['gii'] = 'yii\gii\Module'; -} - -return $config; diff --git a/apps/advanced/environments/dev/backend/config/params-local.php b/apps/advanced/environments/dev/backend/config/params-local.php deleted file mode 100644 index d0b9c34..0000000 --- a/apps/advanced/environments/dev/backend/config/params-local.php +++ /dev/null @@ -1,3 +0,0 @@ -run(); diff --git a/apps/advanced/environments/dev/backend/web/index.php b/apps/advanced/environments/dev/backend/web/index.php deleted file mode 100644 index b4748ba..0000000 --- a/apps/advanced/environments/dev/backend/web/index.php +++ /dev/null @@ -1,17 +0,0 @@ -run(); diff --git a/apps/advanced/environments/dev/common/config/main-local.php b/apps/advanced/environments/dev/common/config/main-local.php deleted file mode 100644 index 43db30e..0000000 --- a/apps/advanced/environments/dev/common/config/main-local.php +++ /dev/null @@ -1,20 +0,0 @@ - [ - 'db' => [ - 'class' => 'yii\db\Connection', - 'dsn' => 'mysql:host=localhost;dbname=yii2advanced', - 'username' => 'root', - 'password' => '', - 'charset' => 'utf8', - ], - 'mailer' => [ - 'class' => 'yii\swiftmailer\Mailer', - 'viewPath' => '@common/mail', - // send all mails to a file by default. You have to set - // 'useFileTransport' to false and configure a transport - // for the mailer to send real emails. - 'useFileTransport' => true, - ], - ], -]; diff --git a/apps/advanced/environments/dev/common/config/params-local.php b/apps/advanced/environments/dev/common/config/params-local.php deleted file mode 100644 index d0b9c34..0000000 --- a/apps/advanced/environments/dev/common/config/params-local.php +++ /dev/null @@ -1,3 +0,0 @@ - [ - 'request' => [ - // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation - 'cookieValidationKey' => '', - ], - ], -]; - -if (!YII_ENV_TEST) { - // configuration adjustments for 'dev' environment - $config['bootstrap'][] = 'debug'; - $config['modules']['debug'] = 'yii\debug\Module'; - - $config['bootstrap'][] = 'gii'; - $config['modules']['gii'] = 'yii\gii\Module'; -} - -return $config; diff --git a/apps/advanced/environments/dev/frontend/config/params-local.php b/apps/advanced/environments/dev/frontend/config/params-local.php deleted file mode 100644 index d0b9c34..0000000 --- a/apps/advanced/environments/dev/frontend/config/params-local.php +++ /dev/null @@ -1,3 +0,0 @@ -run(); diff --git a/apps/advanced/environments/dev/frontend/web/index.php b/apps/advanced/environments/dev/frontend/web/index.php deleted file mode 100644 index b4748ba..0000000 --- a/apps/advanced/environments/dev/frontend/web/index.php +++ /dev/null @@ -1,17 +0,0 @@ -run(); diff --git a/apps/advanced/environments/dev/yii b/apps/advanced/environments/dev/yii deleted file mode 100644 index a282824..0000000 --- a/apps/advanced/environments/dev/yii +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env php -run(); -exit($exitCode); diff --git a/apps/advanced/environments/index.php b/apps/advanced/environments/index.php deleted file mode 100644 index e7ab700..0000000 --- a/apps/advanced/environments/index.php +++ /dev/null @@ -1,58 +0,0 @@ - [ - * 'path' => 'directory storing the local files', - * 'setWritable' => [ - * // list of directories that should be set writable - * ], - * 'setExecutable' => [ - * // list of directories that should be set executable - * ], - * 'setCookieValidationKey' => [ - * // list of config files that need to be inserted with automatically generated cookie validation keys - * ], - * ], - * ]; - * ``` - */ -return [ - 'Development' => [ - 'path' => 'dev', - 'setWritable' => [ - 'backend/runtime', - 'backend/web/assets', - 'frontend/runtime', - 'frontend/web/assets', - ], - 'setExecutable' => [ - 'yii', - ], - 'setCookieValidationKey' => [ - 'backend/config/main-local.php', - 'frontend/config/main-local.php', - ], - ], - 'Production' => [ - 'path' => 'prod', - 'setWritable' => [ - 'backend/runtime', - 'backend/web/assets', - 'frontend/runtime', - 'frontend/web/assets', - ], - 'setExecutable' => [ - 'yii', - ], - 'setCookieValidationKey' => [ - 'backend/config/main-local.php', - 'frontend/config/main-local.php', - ], - ], -]; diff --git a/apps/advanced/environments/prod/backend/config/main-local.php b/apps/advanced/environments/prod/backend/config/main-local.php deleted file mode 100644 index af46ba3..0000000 --- a/apps/advanced/environments/prod/backend/config/main-local.php +++ /dev/null @@ -1,9 +0,0 @@ - [ - 'request' => [ - // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation - 'cookieValidationKey' => '', - ], - ], -]; diff --git a/apps/advanced/environments/prod/backend/config/params-local.php b/apps/advanced/environments/prod/backend/config/params-local.php deleted file mode 100644 index d0b9c34..0000000 --- a/apps/advanced/environments/prod/backend/config/params-local.php +++ /dev/null @@ -1,3 +0,0 @@ -run(); diff --git a/apps/advanced/environments/prod/common/config/main-local.php b/apps/advanced/environments/prod/common/config/main-local.php deleted file mode 100644 index 84c4d9f..0000000 --- a/apps/advanced/environments/prod/common/config/main-local.php +++ /dev/null @@ -1,16 +0,0 @@ - [ - 'db' => [ - 'class' => 'yii\db\Connection', - 'dsn' => 'mysql:host=localhost;dbname=yii2advanced', - 'username' => 'root', - 'password' => '', - 'charset' => 'utf8', - ], - 'mailer' => [ - 'class' => 'yii\swiftmailer\Mailer', - 'viewPath' => '@common/mail', - ], - ], -]; diff --git a/apps/advanced/environments/prod/common/config/params-local.php b/apps/advanced/environments/prod/common/config/params-local.php deleted file mode 100644 index d0b9c34..0000000 --- a/apps/advanced/environments/prod/common/config/params-local.php +++ /dev/null @@ -1,3 +0,0 @@ - [ - 'request' => [ - // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation - 'cookieValidationKey' => '', - ], - ], -]; diff --git a/apps/advanced/environments/prod/frontend/config/params-local.php b/apps/advanced/environments/prod/frontend/config/params-local.php deleted file mode 100644 index d0b9c34..0000000 --- a/apps/advanced/environments/prod/frontend/config/params-local.php +++ /dev/null @@ -1,3 +0,0 @@ -run(); diff --git a/apps/advanced/environments/prod/yii b/apps/advanced/environments/prod/yii deleted file mode 100644 index 7f738bd..0000000 --- a/apps/advanced/environments/prod/yii +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env php -run(); -exit($exitCode); diff --git a/apps/advanced/frontend/assets/AppAsset.php b/apps/advanced/frontend/assets/AppAsset.php deleted file mode 100644 index 995e3dc..0000000 --- a/apps/advanced/frontend/assets/AppAsset.php +++ /dev/null @@ -1,29 +0,0 @@ - - * @since 2.0 - */ -class AppAsset extends AssetBundle -{ - public $basePath = '@webroot'; - public $baseUrl = '@web'; - public $css = [ - 'css/site.css', - ]; - public $js = [ - ]; - public $depends = [ - 'yii\web\YiiAsset', - 'yii\bootstrap\BootstrapAsset', - ]; -} diff --git a/apps/advanced/frontend/codeception.yml b/apps/advanced/frontend/codeception.yml deleted file mode 100644 index 7fa2a38..0000000 --- a/apps/advanced/frontend/codeception.yml +++ /dev/null @@ -1,24 +0,0 @@ -namespace: frontend -actor: Tester -paths: - tests: tests - log: tests/_log - data: tests/_data - helpers: tests/_helpers -settings: - bootstrap: _bootstrap.php - suite_class: \PHPUnit_Framework_TestSuite - colors: true - memory_limit: 1024M - log: true -modules: - config: - Db: - dsn: '' - user: '' - password: '' - dump: tests/_data/dump.sql -config: - # the entry script URL (without host info) for functional and acceptance tests - # PLEASE ADJUST IT TO THE ACTUAL ENTRY SCRIPT URL - test_entry_url: /advanced/frontend/web/index-test.php diff --git a/apps/advanced/frontend/config/.gitignore b/apps/advanced/frontend/config/.gitignore deleted file mode 100644 index 20da318..0000000 --- a/apps/advanced/frontend/config/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -main-local.php -params-local.php \ No newline at end of file diff --git a/apps/advanced/frontend/config/main.php b/apps/advanced/frontend/config/main.php deleted file mode 100644 index 1ed8305..0000000 --- a/apps/advanced/frontend/config/main.php +++ /dev/null @@ -1,33 +0,0 @@ - 'app-frontend', - 'basePath' => dirname(__DIR__), - 'bootstrap' => ['log'], - 'controllerNamespace' => 'frontend\controllers', - 'components' => [ - 'user' => [ - 'identityClass' => 'common\models\User', - 'enableAutoLogin' => true, - ], - 'log' => [ - 'traceLevel' => YII_DEBUG ? 3 : 0, - 'targets' => [ - [ - 'class' => 'yii\log\FileTarget', - 'levels' => ['error', 'warning'], - ], - ], - ], - 'errorHandler' => [ - 'errorAction' => 'site/error', - ], - ], - 'params' => $params, -]; diff --git a/apps/advanced/frontend/config/params.php b/apps/advanced/frontend/config/params.php deleted file mode 100644 index 7f754b9..0000000 --- a/apps/advanced/frontend/config/params.php +++ /dev/null @@ -1,4 +0,0 @@ - 'admin@example.com', -]; diff --git a/apps/advanced/frontend/controllers/SiteController.php b/apps/advanced/frontend/controllers/SiteController.php deleted file mode 100644 index c160a45..0000000 --- a/apps/advanced/frontend/controllers/SiteController.php +++ /dev/null @@ -1,171 +0,0 @@ - [ - 'class' => AccessControl::className(), - 'only' => ['logout', 'signup'], - 'rules' => [ - [ - 'actions' => ['signup'], - 'allow' => true, - 'roles' => ['?'], - ], - [ - 'actions' => ['logout'], - 'allow' => true, - 'roles' => ['@'], - ], - ], - ], - 'verbs' => [ - 'class' => VerbFilter::className(), - 'actions' => [ - 'logout' => ['post'], - ], - ], - ]; - } - - /** - * @inheritdoc - */ - public function actions() - { - return [ - 'error' => [ - 'class' => 'yii\web\ErrorAction', - ], - 'captcha' => [ - 'class' => 'yii\captcha\CaptchaAction', - 'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null, - ], - ]; - } - - public function actionIndex() - { - return $this->render('index'); - } - - public function actionLogin() - { - if (!\Yii::$app->user->isGuest) { - return $this->goHome(); - } - - $model = new LoginForm(); - if ($model->load(Yii::$app->request->post()) && $model->login()) { - return $this->goBack(); - } else { - return $this->render('login', [ - 'model' => $model, - ]); - } - } - - public function actionLogout() - { - Yii::$app->user->logout(); - - return $this->goHome(); - } - - public function actionContact() - { - $model = new ContactForm(); - if ($model->load(Yii::$app->request->post()) && $model->validate()) { - if ($model->sendEmail(Yii::$app->params['adminEmail'])) { - Yii::$app->session->setFlash('success', 'Thank you for contacting us. We will respond to you as soon as possible.'); - } else { - Yii::$app->session->setFlash('error', 'There was an error sending email.'); - } - - return $this->refresh(); - } else { - return $this->render('contact', [ - 'model' => $model, - ]); - } - } - - public function actionAbout() - { - return $this->render('about'); - } - - public function actionSignup() - { - $model = new SignupForm(); - if ($model->load(Yii::$app->request->post())) { - if ($user = $model->signup()) { - if (Yii::$app->getUser()->login($user)) { - return $this->goHome(); - } - } - } - - return $this->render('signup', [ - 'model' => $model, - ]); - } - - public function actionRequestPasswordReset() - { - $model = new PasswordResetRequestForm(); - if ($model->load(Yii::$app->request->post()) && $model->validate()) { - if ($model->sendEmail()) { - Yii::$app->getSession()->setFlash('success', 'Check your email for further instructions.'); - - return $this->goHome(); - } else { - Yii::$app->getSession()->setFlash('error', 'Sorry, we are unable to reset password for email provided.'); - } - } - - return $this->render('requestPasswordResetToken', [ - 'model' => $model, - ]); - } - - public function actionResetPassword($token) - { - try { - $model = new ResetPasswordForm($token); - } catch (InvalidParamException $e) { - throw new BadRequestHttpException($e->getMessage()); - } - - if ($model->load(Yii::$app->request->post()) && $model->validate() && $model->resetPassword()) { - Yii::$app->getSession()->setFlash('success', 'New password was saved.'); - - return $this->goHome(); - } - - return $this->render('resetPassword', [ - 'model' => $model, - ]); - } -} diff --git a/apps/advanced/frontend/models/ContactForm.php b/apps/advanced/frontend/models/ContactForm.php deleted file mode 100644 index 613abb5..0000000 --- a/apps/advanced/frontend/models/ContactForm.php +++ /dev/null @@ -1,59 +0,0 @@ - 'Verification Code', - ]; - } - - /** - * Sends an email to the specified email address using the information collected by this model. - * - * @param string $email the target email address - * @return boolean whether the email was sent - */ - public function sendEmail($email) - { - return Yii::$app->mailer->compose() - ->setTo($email) - ->setFrom([$this->email => $this->name]) - ->setSubject($this->subject) - ->setTextBody($this->body) - ->send(); - } -} diff --git a/apps/advanced/frontend/models/PasswordResetRequestForm.php b/apps/advanced/frontend/models/PasswordResetRequestForm.php deleted file mode 100644 index b89b7bc..0000000 --- a/apps/advanced/frontend/models/PasswordResetRequestForm.php +++ /dev/null @@ -1,57 +0,0 @@ - 'trim'], - ['email', 'required'], - ['email', 'email'], - ['email', 'exist', - 'targetClass' => '\common\models\User', - 'filter' => ['status' => User::STATUS_ACTIVE], - 'message' => 'There is no user with such email.' - ], - ]; - } - - /** - * Sends an email with a link, for resetting the password. - * - * @return boolean whether the email was send - */ - public function sendEmail() - { - /* @var $user User */ - $user = User::findOne([ - 'status' => User::STATUS_ACTIVE, - 'email' => $this->email, - ]); - - if ($user) { - $user->generatePasswordResetToken(); - if ($user->save()) { - return \Yii::$app->mailer->compose('passwordResetToken', ['user' => $user]) - ->setFrom([\Yii::$app->params['supportEmail'] => \Yii::$app->name . ' robot']) - ->setTo($this->email) - ->setSubject('Password reset for ' . \Yii::$app->name) - ->send(); - } - } - - return false; - } -} diff --git a/apps/advanced/frontend/models/ResetPasswordForm.php b/apps/advanced/frontend/models/ResetPasswordForm.php deleted file mode 100644 index 93d1a69..0000000 --- a/apps/advanced/frontend/models/ResetPasswordForm.php +++ /dev/null @@ -1,64 +0,0 @@ -_user = User::findByPasswordResetToken($token); - if (!$this->_user) { - throw new InvalidParamException('Wrong password reset token.'); - } - parent::__construct($config); - } - - /** - * @inheritdoc - */ - public function rules() - { - return [ - ['password', 'required'], - ['password', 'string', 'min' => 6], - ]; - } - - /** - * Resets password. - * - * @return boolean if password was reset. - */ - public function resetPassword() - { - $user = $this->_user; - $user->password = $this->password; - $user->removePasswordResetToken(); - - return $user->save(); - } -} diff --git a/apps/advanced/frontend/models/SignupForm.php b/apps/advanced/frontend/models/SignupForm.php deleted file mode 100644 index 17bcdeb..0000000 --- a/apps/advanced/frontend/models/SignupForm.php +++ /dev/null @@ -1,57 +0,0 @@ - 'trim'], - ['username', 'required'], - ['username', 'unique', 'targetClass' => '\common\models\User', 'message' => 'This username has already been taken.'], - ['username', 'string', 'min' => 2, 'max' => 255], - - ['email', 'filter', 'filter' => 'trim'], - ['email', 'required'], - ['email', 'email'], - ['email', 'unique', 'targetClass' => '\common\models\User', 'message' => 'This email address has already been taken.'], - - ['password', 'required'], - ['password', 'string', 'min' => 6], - ]; - } - - /** - * Signs user up. - * - * @return User|null the saved model or null if saving fails - */ - public function signup() - { - if ($this->validate()) { - $user = new User(); - $user->username = $this->username; - $user->email = $this->email; - $user->setPassword($this->password); - $user->generateAuthKey(); - $user->save(); - return $user; - } - - return null; - } -} diff --git a/apps/advanced/frontend/runtime/.gitignore b/apps/advanced/frontend/runtime/.gitignore deleted file mode 100644 index c96a04f..0000000 --- a/apps/advanced/frontend/runtime/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/apps/advanced/frontend/tests/.gitignore b/apps/advanced/frontend/tests/.gitignore deleted file mode 100644 index c5aa074..0000000 --- a/apps/advanced/frontend/tests/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# these files are auto generated by codeception build -/unit/CodeGuy.php -/functional/TestGuy.php -/acceptance/WebGuy.php diff --git a/apps/advanced/frontend/tests/_bootstrap.php b/apps/advanced/frontend/tests/_bootstrap.php deleted file mode 100644 index bc9d17c..0000000 --- a/apps/advanced/frontend/tests/_bootstrap.php +++ /dev/null @@ -1,18 +0,0 @@ - [ - 'mailer' => [ - 'useFileTransport' => true, - ], - 'urlManager' => [ - 'showScriptName' => true, - ], - ], -]; diff --git a/apps/advanced/frontend/tests/_console.php b/apps/advanced/frontend/tests/_console.php deleted file mode 100644 index b38c84e..0000000 --- a/apps/advanced/frontend/tests/_console.php +++ /dev/null @@ -1,19 +0,0 @@ - $value) { - $inputType = $field === 'body' ? 'textarea' : 'input'; - $this->guy->fillField($inputType . '[name="ContactForm[' . $field . ']"]', $value); - } - $this->guy->click('contact-button'); - } -} diff --git a/apps/advanced/frontend/tests/_pages/SignupPage.php b/apps/advanced/frontend/tests/_pages/SignupPage.php deleted file mode 100644 index 41bd153..0000000 --- a/apps/advanced/frontend/tests/_pages/SignupPage.php +++ /dev/null @@ -1,23 +0,0 @@ - $value) { - $inputType = $field === 'body' ? 'textarea' : 'input'; - $this->guy->fillField($inputType . '[name="SignupForm[' . $field . ']"]', $value); - } - $this->guy->click('signup-button'); - } -} diff --git a/apps/advanced/frontend/tests/acceptance.suite.yml b/apps/advanced/frontend/tests/acceptance.suite.yml deleted file mode 100644 index fa31ffb..0000000 --- a/apps/advanced/frontend/tests/acceptance.suite.yml +++ /dev/null @@ -1,27 +0,0 @@ -# Codeception Test Suite Configuration - -# suite for acceptance tests. -# perform tests in browser using the Selenium-like tools. -# powered by Mink (http://mink.behat.org). -# (tip: that's what your customer will see). -# (tip: test your ajax and javascript by one of Mink drivers). - -# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES. - -class_name: WebGuy -modules: - enabled: - - PhpBrowser - - common\tests\_helpers\FixtureHelper -# you can use WebDriver instead of PhpBrowser to test javascript and ajax. -# This will require you to install selenium. See http://codeception.com/docs/04-AcceptanceTests#Selenium -# "restart" option is used by the WebDriver to start each time per test-file new session and cookies, -# it is useful if you want to login in your app in each test. -# - WebDriver - config: - PhpBrowser: - url: 'http://localhost:8080' -# WebDriver: -# url: 'http://localhost' -# browser: firefox -# restart: true diff --git a/apps/advanced/frontend/tests/acceptance/AboutCept.php b/apps/advanced/frontend/tests/acceptance/AboutCept.php deleted file mode 100644 index e8d17b2..0000000 --- a/apps/advanced/frontend/tests/acceptance/AboutCept.php +++ /dev/null @@ -1,9 +0,0 @@ -wantTo('ensure that about works'); -AboutPage::openBy($I); -$I->see('About', 'h1'); diff --git a/apps/advanced/frontend/tests/acceptance/ContactCept.php b/apps/advanced/frontend/tests/acceptance/ContactCept.php deleted file mode 100644 index 5a36e1d..0000000 --- a/apps/advanced/frontend/tests/acceptance/ContactCept.php +++ /dev/null @@ -1,46 +0,0 @@ -wantTo('ensure that contact works'); - -$contactPage = ContactPage::openBy($I); - -$I->see('Contact', 'h1'); - -$I->amGoingTo('submit contact form with no data'); -$contactPage->submit([]); -$I->expectTo('see validations errors'); -$I->see('Contact', 'h1'); -$I->see('Name cannot be blank', '.help-block'); -$I->see('Email cannot be blank', '.help-block'); -$I->see('Subject cannot be blank', '.help-block'); -$I->see('Body cannot be blank', '.help-block'); -$I->see('The verification code is incorrect', '.help-block'); - -$I->amGoingTo('submit contact form with not correct email'); -$contactPage->submit([ - 'name' => 'tester', - 'email' => 'tester.email', - 'subject' => 'test subject', - 'body' => 'test content', - 'verifyCode' => 'testme', -]); -$I->expectTo('see that email adress is wrong'); -$I->dontSee('Name cannot be blank', '.help-block'); -$I->see('Email is not a valid email address.', '.help-block'); -$I->dontSee('Subject cannot be blank', '.help-block'); -$I->dontSee('Body cannot be blank', '.help-block'); -$I->dontSee('The verification code is incorrect', '.help-block'); - -$I->amGoingTo('submit contact form with correct data'); -$contactPage->submit([ - 'name' => 'tester', - 'email' => 'tester@example.com', - 'subject' => 'test subject', - 'body' => 'test content', - 'verifyCode' => 'testme', -]); -$I->see('Thank you for contacting us. We will respond to you as soon as possible.'); diff --git a/apps/advanced/frontend/tests/acceptance/HomeCept.php b/apps/advanced/frontend/tests/acceptance/HomeCept.php deleted file mode 100644 index 4f5cc19..0000000 --- a/apps/advanced/frontend/tests/acceptance/HomeCept.php +++ /dev/null @@ -1,11 +0,0 @@ -wantTo('ensure that home page works'); -$I->amOnPage(Yii::$app->homeUrl); -$I->see('My Company'); -$I->seeLink('About'); -$I->click('About'); -$I->see('This is the About page.'); diff --git a/apps/advanced/frontend/tests/acceptance/LoginCept.php b/apps/advanced/frontend/tests/acceptance/LoginCept.php deleted file mode 100644 index 3728baf..0000000 --- a/apps/advanced/frontend/tests/acceptance/LoginCept.php +++ /dev/null @@ -1,33 +0,0 @@ -wantTo('ensure login page works'); - -$loginPage = LoginPage::openBy($I); - -$I->amGoingTo('submit login form with no data'); -$loginPage->login('', ''); -$I->expectTo('see validations errors'); -$I->see('Username cannot be blank.', '.help-block'); -$I->see('Password cannot be blank.', '.help-block'); - -$I->amGoingTo('try to login with wrong credentials'); -$I->expectTo('see validations errors'); -$loginPage->login('admin', 'wrong'); -$I->expectTo('see validations errors'); -$I->see('Incorrect username or password.', '.help-block'); - -$I->amGoingTo('try to login with correct credentials'); -$loginPage->login('erau', 'password_0'); -$I->expectTo('see that user is logged'); -$I->seeLink('Logout (erau)'); -$I->dontSeeLink('Login'); -$I->dontSeeLink('Signup'); -/** Uncomment if using WebDriver - * $I->click('Logout (erau)'); - * $I->dontSeeLink('Logout (erau)'); - * $I->seeLink('Login'); - */ diff --git a/apps/advanced/frontend/tests/acceptance/SignupCest.php b/apps/advanced/frontend/tests/acceptance/SignupCest.php deleted file mode 100644 index c086773..0000000 --- a/apps/advanced/frontend/tests/acceptance/SignupCest.php +++ /dev/null @@ -1,82 +0,0 @@ - 'tester.email@example.com', - 'username' => 'tester', - ]); - } - - /** - * This method is called when test fails. - * @param \Codeception\Event\Fail $event - */ - public function _fail($event) - { - } - - /** - * @param \WebGuy $I - * @param \Codeception\Scenario $scenario - */ - public function testUserSignup($I, $scenario) - { - $I->wantTo('ensure that signup works'); - - $signupPage = SignupPage::openBy($I); - $I->see('Signup', 'h1'); - $I->see('Please fill out the following fields to signup:'); - - $I->amGoingTo('submit signup form with no data'); - - $signupPage->submit([]); - - $I->expectTo('see validation errors'); - $I->see('Username cannot be blank.', '.help-block'); - $I->see('Email cannot be blank.', '.help-block'); - $I->see('Password cannot be blank.', '.help-block'); - - $I->amGoingTo('submit signup form with not correct email'); - $signupPage->submit([ - 'username' => 'tester', - 'email' => 'tester.email', - 'password' => 'tester_password', - ]); - - $I->expectTo('see that email address is wrong'); - $I->dontSee('Username cannot be blank.', '.help-block'); - $I->dontSee('Password cannot be blank.', '.help-block'); - $I->see('Email is not a valid email address.', '.help-block'); - - $I->amGoingTo('submit signup form with correct email'); - $signupPage->submit([ - 'username' => 'tester', - 'email' => 'tester.email@example.com', - 'password' => 'tester_password', - ]); - - $I->expectTo('see that user logged in'); - $I->seeLink('Logout (tester)'); - } -} diff --git a/apps/advanced/frontend/tests/acceptance/_bootstrap.php b/apps/advanced/frontend/tests/acceptance/_bootstrap.php deleted file mode 100644 index 6ce3d17..0000000 --- a/apps/advanced/frontend/tests/acceptance/_bootstrap.php +++ /dev/null @@ -1,3 +0,0 @@ - [ - 'db' => [ - 'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_acceptance', - ], - ], - ] -); diff --git a/apps/advanced/frontend/tests/acceptance/_console.php b/apps/advanced/frontend/tests/acceptance/_console.php deleted file mode 100644 index bae7e44..0000000 --- a/apps/advanced/frontend/tests/acceptance/_console.php +++ /dev/null @@ -1,15 +0,0 @@ - [ - 'db' => [ - 'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_acceptance', - ], - ], - ] -); diff --git a/apps/advanced/frontend/tests/acceptance/yii b/apps/advanced/frontend/tests/acceptance/yii deleted file mode 100644 index a348a9a..0000000 --- a/apps/advanced/frontend/tests/acceptance/yii +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env php -run(); -exit($exitCode); diff --git a/apps/advanced/frontend/tests/acceptance/yii.bat b/apps/advanced/frontend/tests/acceptance/yii.bat deleted file mode 100644 index 5e21e2e..0000000 --- a/apps/advanced/frontend/tests/acceptance/yii.bat +++ /dev/null @@ -1,20 +0,0 @@ -@echo off - -rem ------------------------------------------------------------- -rem Yii command line bootstrap script for Windows. -rem -rem @author Qiang Xue -rem @link http://www.yiiframework.com/ -rem @copyright Copyright © 2012 Yii Software LLC -rem @license http://www.yiiframework.com/license/ -rem ------------------------------------------------------------- - -@setlocal - -set YII_PATH=%~dp0 - -if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe - -"%PHP_COMMAND%" "%YII_PATH%yii" %* - -@endlocal diff --git a/apps/advanced/frontend/tests/functional.suite.yml b/apps/advanced/frontend/tests/functional.suite.yml deleted file mode 100644 index 3c828f5..0000000 --- a/apps/advanced/frontend/tests/functional.suite.yml +++ /dev/null @@ -1,17 +0,0 @@ -# Codeception Test Suite Configuration - -# suite for functional (integration) tests. -# emulate web requests and make application process them. -# (tip: better to use with frameworks). - -# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES. -#basic/web/index.php -class_name: TestGuy -modules: - enabled: - - Filesystem - - Yii2 - - common\tests\_helpers\FixtureHelper - config: - Yii2: - configFile: 'tests/functional/_config.php' diff --git a/apps/advanced/frontend/tests/functional/AboutCept.php b/apps/advanced/frontend/tests/functional/AboutCept.php deleted file mode 100644 index f9dd1a5..0000000 --- a/apps/advanced/frontend/tests/functional/AboutCept.php +++ /dev/null @@ -1,9 +0,0 @@ -wantTo('ensure that about works'); -AboutPage::openBy($I); -$I->see('About', 'h1'); diff --git a/apps/advanced/frontend/tests/functional/ContactCept.php b/apps/advanced/frontend/tests/functional/ContactCept.php deleted file mode 100644 index 774428c..0000000 --- a/apps/advanced/frontend/tests/functional/ContactCept.php +++ /dev/null @@ -1,46 +0,0 @@ -wantTo('ensure that contact works'); - -$contactPage = ContactPage::openBy($I); - -$I->see('Contact', 'h1'); - -$I->amGoingTo('submit contact form with no data'); -$contactPage->submit([]); -$I->expectTo('see validations errors'); -$I->see('Contact', 'h1'); -$I->see('Name cannot be blank', '.help-block'); -$I->see('Email cannot be blank', '.help-block'); -$I->see('Subject cannot be blank', '.help-block'); -$I->see('Body cannot be blank', '.help-block'); -$I->see('The verification code is incorrect', '.help-block'); - -$I->amGoingTo('submit contact form with not correct email'); -$contactPage->submit([ - 'name' => 'tester', - 'email' => 'tester.email', - 'subject' => 'test subject', - 'body' => 'test content', - 'verifyCode' => 'testme', -]); -$I->expectTo('see that email adress is wrong'); -$I->dontSee('Name cannot be blank', '.help-block'); -$I->see('Email is not a valid email address.', '.help-block'); -$I->dontSee('Subject cannot be blank', '.help-block'); -$I->dontSee('Body cannot be blank', '.help-block'); -$I->dontSee('The verification code is incorrect', '.help-block'); - -$I->amGoingTo('submit contact form with correct data'); -$contactPage->submit([ - 'name' => 'tester', - 'email' => 'tester@example.com', - 'subject' => 'test subject', - 'body' => 'test content', - 'verifyCode' => 'testme', -]); -$I->see('Thank you for contacting us. We will respond to you as soon as possible.'); diff --git a/apps/advanced/frontend/tests/functional/HomeCept.php b/apps/advanced/frontend/tests/functional/HomeCept.php deleted file mode 100644 index 1bc1d5b..0000000 --- a/apps/advanced/frontend/tests/functional/HomeCept.php +++ /dev/null @@ -1,11 +0,0 @@ -wantTo('ensure that home page works'); -$I->amOnPage(Yii::$app->homeUrl); -$I->see('My Company'); -$I->seeLink('About'); -$I->click('About'); -$I->see('This is the About page.'); diff --git a/apps/advanced/frontend/tests/functional/LoginCept.php b/apps/advanced/frontend/tests/functional/LoginCept.php deleted file mode 100644 index 7e1e1be..0000000 --- a/apps/advanced/frontend/tests/functional/LoginCept.php +++ /dev/null @@ -1,28 +0,0 @@ -wantTo('ensure login page works'); - -$loginPage = LoginPage::openBy($I); - -$I->amGoingTo('submit login form with no data'); -$loginPage->login('', ''); -$I->expectTo('see validations errors'); -$I->see('Username cannot be blank.', '.help-block'); -$I->see('Password cannot be blank.', '.help-block'); - -$I->amGoingTo('try to login with wrong credentials'); -$I->expectTo('see validations errors'); -$loginPage->login('admin', 'wrong'); -$I->expectTo('see validations errors'); -$I->see('Incorrect username or password.', '.help-block'); - -$I->amGoingTo('try to login with correct credentials'); -$loginPage->login('erau', 'password_0'); -$I->expectTo('see that user is logged'); -$I->seeLink('Logout (erau)'); -$I->dontSeeLink('Login'); -$I->dontSeeLink('Signup'); diff --git a/apps/advanced/frontend/tests/functional/SignupCest.php b/apps/advanced/frontend/tests/functional/SignupCest.php deleted file mode 100644 index 5287aee..0000000 --- a/apps/advanced/frontend/tests/functional/SignupCest.php +++ /dev/null @@ -1,90 +0,0 @@ - 'tester.email@example.com', - 'username' => 'tester', - ]); - } - - /** - * This method is called when test fails. - * @param \Codeception\Event\Fail $event - */ - public function _fail($event) - { - - } - - /** - * - * @param \TestGuy $I - * @param \Codeception\Scenario $scenario - */ - public function testUserSignup($I, $scenario) - { - $I->wantTo('ensure that signup works'); - - $signupPage = SignupPage::openBy($I); - $I->see('Signup', 'h1'); - $I->see('Please fill out the following fields to signup:'); - - $I->amGoingTo('submit signup form with no data'); - - $signupPage->submit([]); - - $I->expectTo('see validation errors'); - $I->see('Username cannot be blank.', '.help-block'); - $I->see('Email cannot be blank.', '.help-block'); - $I->see('Password cannot be blank.', '.help-block'); - - $I->amGoingTo('submit signup form with not correct email'); - $signupPage->submit([ - 'username' => 'tester', - 'email' => 'tester.email', - 'password' => 'tester_password', - ]); - - $I->expectTo('see that email address is wrong'); - $I->dontSee('Username cannot be blank.', '.help-block'); - $I->dontSee('Password cannot be blank.', '.help-block'); - $I->see('Email is not a valid email address.', '.help-block'); - - $I->amGoingTo('submit signup form with correct email'); - $signupPage->submit([ - 'username' => 'tester', - 'email' => 'tester.email@example.com', - 'password' => 'tester_password', - ]); - - $I->expectTo('see that user is created'); - $I->seeRecord('common\models\User', [ - 'username' => 'tester', - 'email' => 'tester.email@example.com', - ]); - - $I->expectTo('see that user logged in'); - $I->seeLink('Logout (tester)'); - } -} diff --git a/apps/advanced/frontend/tests/functional/_bootstrap.php b/apps/advanced/frontend/tests/functional/_bootstrap.php deleted file mode 100644 index 6ce3d17..0000000 --- a/apps/advanced/frontend/tests/functional/_bootstrap.php +++ /dev/null @@ -1,3 +0,0 @@ - [ - 'db' => [ - 'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_functional', - ], - ], - ] -); diff --git a/apps/advanced/frontend/tests/functional/_console.php b/apps/advanced/frontend/tests/functional/_console.php deleted file mode 100644 index d76662c..0000000 --- a/apps/advanced/frontend/tests/functional/_console.php +++ /dev/null @@ -1,15 +0,0 @@ - [ - 'db' => [ - 'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_functional', - ], - ], - ] -); diff --git a/apps/advanced/frontend/tests/functional/yii b/apps/advanced/frontend/tests/functional/yii deleted file mode 100644 index a348a9a..0000000 --- a/apps/advanced/frontend/tests/functional/yii +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env php -run(); -exit($exitCode); diff --git a/apps/advanced/frontend/tests/functional/yii.bat b/apps/advanced/frontend/tests/functional/yii.bat deleted file mode 100644 index 5e21e2e..0000000 --- a/apps/advanced/frontend/tests/functional/yii.bat +++ /dev/null @@ -1,20 +0,0 @@ -@echo off - -rem ------------------------------------------------------------- -rem Yii command line bootstrap script for Windows. -rem -rem @author Qiang Xue -rem @link http://www.yiiframework.com/ -rem @copyright Copyright © 2012 Yii Software LLC -rem @license http://www.yiiframework.com/license/ -rem ------------------------------------------------------------- - -@setlocal - -set YII_PATH=%~dp0 - -if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe - -"%PHP_COMMAND%" "%YII_PATH%yii" %* - -@endlocal diff --git a/apps/advanced/frontend/tests/unit.suite.yml b/apps/advanced/frontend/tests/unit.suite.yml deleted file mode 100644 index f0573a8..0000000 --- a/apps/advanced/frontend/tests/unit.suite.yml +++ /dev/null @@ -1,6 +0,0 @@ -# Codeception Test Suite Configuration - -# suite for unit (internal) tests. -# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES. - -class_name: CodeGuy diff --git a/apps/advanced/frontend/tests/unit/DbTestCase.php b/apps/advanced/frontend/tests/unit/DbTestCase.php deleted file mode 100644 index f175a3b..0000000 --- a/apps/advanced/frontend/tests/unit/DbTestCase.php +++ /dev/null @@ -1,8 +0,0 @@ - [ - 'db' => [ - 'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_unit', - ], - ], - ] -); diff --git a/apps/advanced/frontend/tests/unit/_console.php b/apps/advanced/frontend/tests/unit/_console.php deleted file mode 100644 index 2515f1d..0000000 --- a/apps/advanced/frontend/tests/unit/_console.php +++ /dev/null @@ -1,22 +0,0 @@ - [ - 'db' => [ - 'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_unit', - ], - ], - 'controllerMap' => [ - 'fixture' => [ - 'class' => 'yii\faker\FixtureController', - 'fixtureDataPath' => '@frontend/tests/unit/fixtures/data', - 'templatePath' => '@common/tests/templates/fixtures' - ], - ], - ] -); diff --git a/apps/advanced/frontend/tests/unit/fixtures/data/models/user.php b/apps/advanced/frontend/tests/unit/fixtures/data/models/user.php deleted file mode 100644 index 3670e09..0000000 --- a/apps/advanced/frontend/tests/unit/fixtures/data/models/user.php +++ /dev/null @@ -1,23 +0,0 @@ - 'okirlin', - 'auth_key' => 'iwTNae9t34OmnK6l4vT4IeaTk-YWI2Rv', - 'password_hash' => '$2y$13$CXT0Rkle1EMJ/c1l5bylL.EylfmQ39O5JlHJVFpNn618OUS1HwaIi', - 'password_reset_token' => 't5GU9NwpuGYSfb7FEZMAxqtuz2PkEvv_' . time(), - 'created_at' => '1391885313', - 'updated_at' => '1391885313', - 'email' => 'brady.renner@rutherford.com', - ], - [ - 'username' => 'troy.becker', - 'auth_key' => 'EdKfXrx88weFMV0vIxuTMWKgfK2tS3Lp', - 'password_hash' => '$2y$13$g5nv41Px7VBqhS3hVsVN2.MKfgT3jFdkXEsMC4rQJLfaMa7VaJqL2', - 'password_reset_token' => '4BSNyiZNAuxjs5Mty990c47sVrgllIi_' . time(), - 'created_at' => '1391885313', - 'updated_at' => '1391885313', - 'email' => 'nicolas.dianna@hotmail.com', - 'status' => '0', - ], -]; diff --git a/apps/advanced/frontend/tests/unit/models/ContactFormTest.php b/apps/advanced/frontend/tests/unit/models/ContactFormTest.php deleted file mode 100644 index a30824e..0000000 --- a/apps/advanced/frontend/tests/unit/models/ContactFormTest.php +++ /dev/null @@ -1,59 +0,0 @@ -mailer->fileTransportCallback = function ($mailer, $message) { - return 'testing_message.eml'; - }; - } - - protected function tearDown() - { - unlink($this->getMessageFile()); - parent::tearDown(); - } - - public function testContact() - { - $model = new ContactForm(); - - $model->attributes = [ - 'name' => 'Tester', - 'email' => 'tester@example.com', - 'subject' => 'very important letter subject', - 'body' => 'body of current message', - ]; - - $model->sendEmail('admin@example.com'); - - $this->specify('email should be send', function () { - expect('email file should exist', file_exists($this->getMessageFile()))->true(); - }); - - $this->specify('message should contain correct data', function () use ($model) { - $emailMessage = file_get_contents($this->getMessageFile()); - - expect('email should contain user name', $emailMessage)->contains($model->name); - expect('email should contain sender email', $emailMessage)->contains($model->email); - expect('email should contain subject', $emailMessage)->contains($model->subject); - expect('email should contain body', $emailMessage)->contains($model->body); - }); - } - - private function getMessageFile() - { - return Yii::getAlias(Yii::$app->mailer->fileTransportPath) . '/testing_message.eml'; - } -} diff --git a/apps/advanced/frontend/tests/unit/models/PasswordResetRequestFormTest.php b/apps/advanced/frontend/tests/unit/models/PasswordResetRequestFormTest.php deleted file mode 100644 index c83d3e4..0000000 --- a/apps/advanced/frontend/tests/unit/models/PasswordResetRequestFormTest.php +++ /dev/null @@ -1,88 +0,0 @@ -mailer->fileTransportCallback = function ($mailer, $message) { - return 'testing_message.eml'; - }; - } - - protected function tearDown() - { - @unlink($this->getMessageFile()); - - parent::tearDown(); - } - - public function testSendEmailWrongUser() - { - $this->specify('no user with such email, message should not be send', function () { - - $model = new PasswordResetRequestForm(); - $model->email = 'not-existing-email@example.com'; - - expect('email not send', $model->sendEmail())->false(); - - }); - - $this->specify('user is not active, message should not be send', function () { - - $model = new PasswordResetRequestForm(); - $model->email = $this->user[1]['email']; - - expect('email not send', $model->sendEmail())->false(); - - }); - } - - public function testSendEmailCorrectUser() - { - $model = new PasswordResetRequestForm(); - $model->email = $this->user[0]['email']; - $user = User::findOne(['password_reset_token' => $this->user[0]['password_reset_token']]); - - expect('email sent', $model->sendEmail())->true(); - expect('user has valid token', $user->password_reset_token)->notNull(); - - $this->specify('message has correct format', function () use ($model) { - - expect('message file exists', file_exists($this->getMessageFile()))->true(); - - $message = file_get_contents($this->getMessageFile()); - expect('message "from" is correct', $message)->contains(Yii::$app->params['supportEmail']); - expect('message "to" is correct', $message)->contains($model->email); - - }); - } - - public function fixtures() - { - return [ - 'user' => [ - 'class' => UserFixture::className(), - 'dataFile' => '@frontend/tests/unit/fixtures/data/models/user.php' - ], - ]; - } - - private function getMessageFile() - { - return Yii::getAlias(Yii::$app->mailer->fileTransportPath) . '/testing_message.eml'; - } - -} diff --git a/apps/advanced/frontend/tests/unit/models/ResetPasswordFormTest.php b/apps/advanced/frontend/tests/unit/models/ResetPasswordFormTest.php deleted file mode 100644 index 419b424..0000000 --- a/apps/advanced/frontend/tests/unit/models/ResetPasswordFormTest.php +++ /dev/null @@ -1,44 +0,0 @@ -user[0]['password_reset_token']); - expect('password should be resetted', $form->resetPassword())->true(); - } - - public function fixtures() - { - return [ - 'user' => [ - 'class' => UserFixture::className(), - 'dataFile' => '@frontend/tests/unit/fixtures/data/models/user.php' - ], - ]; - } - -} diff --git a/apps/advanced/frontend/tests/unit/models/SignupFormTest.php b/apps/advanced/frontend/tests/unit/models/SignupFormTest.php deleted file mode 100644 index d761421..0000000 --- a/apps/advanced/frontend/tests/unit/models/SignupFormTest.php +++ /dev/null @@ -1,53 +0,0 @@ - 'some_username', - 'email' => 'some_email@example.com', - 'password' => 'some_password', - ]); - - $user = $model->signup(); - - $this->assertInstanceOf('common\models\User', $user, 'user should be valid'); - - expect('username should be correct', $user->username)->equals('some_username'); - expect('email should be correct', $user->email)->equals('some_email@example.com'); - expect('password should be correct', $user->validatePassword('some_password'))->true(); - } - - public function testNotCorrectSignup() - { - $model = new SignupForm([ - 'username' => 'troy.becker', - 'email' => 'nicolas.dianna@hotmail.com', - 'password' => 'some_password', - ]); - - expect('username and email are in use, user should not be created', $model->signup())->null(); - } - - public function fixtures() - { - return [ - 'user' => [ - 'class' => UserFixture::className(), - 'dataFile' => '@frontend/tests/unit/fixtures/data/models/user.php', - ], - ]; - } - -} diff --git a/apps/advanced/frontend/tests/unit/yii b/apps/advanced/frontend/tests/unit/yii deleted file mode 100644 index a348a9a..0000000 --- a/apps/advanced/frontend/tests/unit/yii +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env php -run(); -exit($exitCode); diff --git a/apps/advanced/frontend/tests/unit/yii.bat b/apps/advanced/frontend/tests/unit/yii.bat deleted file mode 100644 index 5e21e2e..0000000 --- a/apps/advanced/frontend/tests/unit/yii.bat +++ /dev/null @@ -1,20 +0,0 @@ -@echo off - -rem ------------------------------------------------------------- -rem Yii command line bootstrap script for Windows. -rem -rem @author Qiang Xue -rem @link http://www.yiiframework.com/ -rem @copyright Copyright © 2012 Yii Software LLC -rem @license http://www.yiiframework.com/license/ -rem ------------------------------------------------------------- - -@setlocal - -set YII_PATH=%~dp0 - -if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe - -"%PHP_COMMAND%" "%YII_PATH%yii" %* - -@endlocal diff --git a/apps/advanced/frontend/views/layouts/main.php b/apps/advanced/frontend/views/layouts/main.php deleted file mode 100644 index d4e68e6..0000000 --- a/apps/advanced/frontend/views/layouts/main.php +++ /dev/null @@ -1,76 +0,0 @@ - -beginPage() ?> - - - - - - - <?= Html::encode($this->title) ?> - head() ?> - - - beginBody() ?> -
- 'My Company', - 'brandUrl' => Yii::$app->homeUrl, - 'options' => [ - 'class' => 'navbar-inverse navbar-fixed-top', - ], - ]); - $menuItems = [ - ['label' => 'Home', 'url' => ['/site/index']], - ['label' => 'About', 'url' => ['/site/about']], - ['label' => 'Contact', 'url' => ['/site/contact']], - ]; - if (Yii::$app->user->isGuest) { - $menuItems[] = ['label' => 'Signup', 'url' => ['/site/signup']]; - $menuItems[] = ['label' => 'Login', 'url' => ['/site/login']]; - } else { - $menuItems[] = [ - 'label' => 'Logout (' . Yii::$app->user->identity->username . ')', - 'url' => ['/site/logout'], - 'linkOptions' => ['data-method' => 'post'] - ]; - } - echo Nav::widget([ - 'options' => ['class' => 'navbar-nav navbar-right'], - 'items' => $menuItems, - ]); - NavBar::end(); - ?> - -
- isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [], - ]) ?> - - -
-
- -
-
-

© My Company

-

-
-
- - endBody() ?> - - -endPage() ?> diff --git a/apps/advanced/frontend/views/site/about.php b/apps/advanced/frontend/views/site/about.php deleted file mode 100644 index 813ed30..0000000 --- a/apps/advanced/frontend/views/site/about.php +++ /dev/null @@ -1,14 +0,0 @@ -title = 'About'; -$this->params['breadcrumbs'][] = $this->title; -?> -
-

title) ?>

- -

This is the About page. You may modify the following file to customize its content:

- - -
diff --git a/apps/advanced/frontend/views/site/contact.php b/apps/advanced/frontend/views/site/contact.php deleted file mode 100644 index b37693c..0000000 --- a/apps/advanced/frontend/views/site/contact.php +++ /dev/null @@ -1,37 +0,0 @@ -title = 'Contact'; -$this->params['breadcrumbs'][] = $this->title; -?> -
-

title) ?>

- -

- If you have business inquiries or other questions, please fill out the following form to contact us. Thank you. -

- -
-
- 'contact-form']); ?> - field($model, 'name') ?> - field($model, 'email') ?> - field($model, 'subject') ?> - field($model, 'body')->textArea(['rows' => 6]) ?> - field($model, 'verifyCode')->widget(Captcha::className(), [ - 'template' => '
{image}
{input}
', - ]) ?> -
- 'btn btn-primary', 'name' => 'contact-button']) ?> -
- -
-
- -
diff --git a/apps/advanced/frontend/views/site/error.php b/apps/advanced/frontend/views/site/error.php deleted file mode 100644 index b9812c4..0000000 --- a/apps/advanced/frontend/views/site/error.php +++ /dev/null @@ -1,27 +0,0 @@ -title = $name; -?> -
- -

title) ?>

- -
- -
- -

- The above error occurred while the Web server was processing your request. -

-

- Please contact us if you think this is a server error. Thank you. -

- -
diff --git a/apps/advanced/frontend/views/site/index.php b/apps/advanced/frontend/views/site/index.php deleted file mode 100644 index a00ee4d..0000000 --- a/apps/advanced/frontend/views/site/index.php +++ /dev/null @@ -1,51 +0,0 @@ -title = 'My Yii Application'; -?> -
- -
-

Congratulations!

- -

You have successfully created your Yii-powered application.

- -

Get started with Yii

-
- -
- -
-
-

Heading

- -

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et - dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip - ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu - fugiat nulla pariatur.

- -

Yii Documentation »

-
-
-

Heading

- -

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et - dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip - ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu - fugiat nulla pariatur.

- -

Yii Forum »

-
-
-

Heading

- -

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et - dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip - ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu - fugiat nulla pariatur.

- -

Yii Extensions »

-
-
- -
-
diff --git a/apps/advanced/frontend/views/site/login.php b/apps/advanced/frontend/views/site/login.php deleted file mode 100644 index 890eddf..0000000 --- a/apps/advanced/frontend/views/site/login.php +++ /dev/null @@ -1,32 +0,0 @@ -title = 'Login'; -$this->params['breadcrumbs'][] = $this->title; -?> - diff --git a/apps/advanced/frontend/views/site/requestPasswordResetToken.php b/apps/advanced/frontend/views/site/requestPasswordResetToken.php deleted file mode 100644 index 13e6901..0000000 --- a/apps/advanced/frontend/views/site/requestPasswordResetToken.php +++ /dev/null @@ -1,27 +0,0 @@ -title = 'Request password reset'; -$this->params['breadcrumbs'][] = $this->title; -?> -
-

title) ?>

- -

Please fill out your email. A link to reset password will be sent there.

- -
-
- 'request-password-reset-form']); ?> - field($model, 'email') ?> -
- 'btn btn-primary']) ?> -
- -
-
-
diff --git a/apps/advanced/frontend/views/site/resetPassword.php b/apps/advanced/frontend/views/site/resetPassword.php deleted file mode 100644 index 4efb28a..0000000 --- a/apps/advanced/frontend/views/site/resetPassword.php +++ /dev/null @@ -1,27 +0,0 @@ -title = 'Reset password'; -$this->params['breadcrumbs'][] = $this->title; -?> -
-

title) ?>

- -

Please choose your new password:

- -
-
- 'reset-password-form']); ?> - field($model, 'password')->passwordInput() ?> -
- 'btn btn-primary']) ?> -
- -
-
-
diff --git a/apps/advanced/frontend/views/site/signup.php b/apps/advanced/frontend/views/site/signup.php deleted file mode 100644 index a0fb685..0000000 --- a/apps/advanced/frontend/views/site/signup.php +++ /dev/null @@ -1,29 +0,0 @@ -title = 'Signup'; -$this->params['breadcrumbs'][] = $this->title; -?> - diff --git a/apps/advanced/frontend/web/.gitignore b/apps/advanced/frontend/web/.gitignore deleted file mode 100644 index 25c74e6..0000000 --- a/apps/advanced/frontend/web/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/index.php -/index-test.php diff --git a/apps/advanced/frontend/web/assets/.gitignore b/apps/advanced/frontend/web/assets/.gitignore deleted file mode 100644 index c96a04f..0000000 --- a/apps/advanced/frontend/web/assets/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/apps/advanced/frontend/web/css/site.css b/apps/advanced/frontend/web/css/site.css deleted file mode 100644 index 698be70..0000000 --- a/apps/advanced/frontend/web/css/site.css +++ /dev/null @@ -1,91 +0,0 @@ -html, -body { - height: 100%; -} - -.wrap { - min-height: 100%; - height: auto; - margin: 0 auto -60px; - padding: 0 0 60px; -} - -.wrap > .container { - padding: 70px 15px 20px; -} - -.footer { - height: 60px; - background-color: #f5f5f5; - border-top: 1px solid #ddd; - padding-top: 20px; -} - -.jumbotron { - text-align: center; - background-color: transparent; -} - -.jumbotron .btn { - font-size: 21px; - padding: 14px 24px; -} - -.not-set { - color: #c55; - font-style: italic; -} - -/* add sorting icons to gridview sort links */ -a.asc:after, a.desc:after { - position: relative; - top: 1px; - display: inline-block; - font-family: 'Glyphicons Halflings'; - font-style: normal; - font-weight: normal; - line-height: 1; - padding-left: 5px; -} - -a.asc:after { - content: /*"\e113"*/ "\e151"; -} - -a.desc:after { - content: /*"\e114"*/ "\e152"; -} - -.sort-numerical a.asc:after { - content: "\e153"; -} - -.sort-numerical a.desc:after { - content: "\e154"; -} - -.sort-ordinal a.asc:after { - content: "\e155"; -} - -.sort-ordinal a.desc:after { - content: "\e156"; -} - -.grid-view th { - white-space: nowrap; -} - -.hint-block { - display: block; - margin-top: 5px; - color: #999; -} - -.error-summary { - color: #a94442; - background: #fdf7f7; - border-left: 3px solid #eed3d7; - padding: 10px 20px; - margin: 0 0 15px 0; -} diff --git a/apps/advanced/frontend/web/favicon.ico b/apps/advanced/frontend/web/favicon.ico deleted file mode 100644 index 580ed73..0000000 Binary files a/apps/advanced/frontend/web/favicon.ico and /dev/null differ diff --git a/apps/advanced/frontend/web/robots.txt b/apps/advanced/frontend/web/robots.txt deleted file mode 100644 index 6f27bb6..0000000 --- a/apps/advanced/frontend/web/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-agent: * -Disallow: \ No newline at end of file diff --git a/apps/advanced/frontend/widgets/Alert.php b/apps/advanced/frontend/widgets/Alert.php deleted file mode 100644 index fa755da..0000000 --- a/apps/advanced/frontend/widgets/Alert.php +++ /dev/null @@ -1,79 +0,0 @@ -getSession()->setFlash('error', 'This is the message'); - * \Yii::$app->getSession()->setFlash('success', 'This is the message'); - * \Yii::$app->getSession()->setFlash('info', 'This is the message'); - * ``` - * - * Multiple messages could be set as follows: - * - * ```php - * \Yii::$app->getSession()->setFlash('error', ['Error 1', 'Error 2']); - * ``` - * - * @author Kartik Visweswaran - * @author Alexander Makarov - */ -class Alert extends \yii\bootstrap\Widget -{ - /** - * @var array the alert types configuration for the flash messages. - * This array is setup as $key => $value, where: - * - $key is the name of the session flash variable - * - $value is the bootstrap alert type (i.e. danger, success, info, warning) - */ - public $alertTypes = [ - 'error' => 'alert-danger', - 'danger' => 'alert-danger', - 'success' => 'alert-success', - 'info' => 'alert-info', - 'warning' => 'alert-warning' - ]; - - /** - * @var array the options for rendering the close button tag. - */ - public $closeButton = []; - - public function init() - { - parent::init(); - - $session = \Yii::$app->getSession(); - $flashes = $session->getAllFlashes(); - $appendCss = isset($this->options['class']) ? ' ' . $this->options['class'] : ''; - - foreach ($flashes as $type => $data) { - if (isset($this->alertTypes[$type])) { - $data = (array) $data; - foreach ($data as $message) { - /* initialize css class for each alert box */ - $this->options['class'] = $this->alertTypes[$type] . $appendCss; - - /* assign unique id to each alert box */ - $this->options['id'] = $this->getId() . '-' . $type; - - echo \yii\bootstrap\Alert::widget([ - 'body' => $message, - 'closeButton' => $this->closeButton, - 'options' => $this->options, - ]); - } - - $session->removeFlash($type); - } - } - } -} diff --git a/apps/advanced/init b/apps/advanced/init deleted file mode 100755 index db9dd7e..0000000 --- a/apps/advanced/init +++ /dev/null @@ -1,195 +0,0 @@ -#!/usr/bin/env php - - * - * @link http://www.yiiframework.com/ - * @copyright Copyright (c) 2008 Yii Software LLC - * @license http://www.yiiframework.com/license/ - */ - -if (!extension_loaded('mcrypt')) { - die('The mcrypt PHP extension is required by Yii2.'); -} - -$params = getParams(); -$root = str_replace('\\', '/', __DIR__); -$envs = require("$root/environments/index.php"); -$envNames = array_keys($envs); - -echo "Yii Application Initialization Tool v1.0\n\n"; - -$envName = null; -if (empty($params['env']) || $params['env'] === '1') { - echo "Which environment do you want the application to be initialized in?\n\n"; - foreach ($envNames as $i => $name) { - echo " [$i] $name\n"; - } - echo "\n Your choice [0-" . (count($envs) - 1) . ', or "q" to quit] '; - $answer = trim(fgets(STDIN)); - - if (!ctype_digit($answer) || !in_array($answer, range(0, count($envs) - 1))) { - echo "\n Quit initialization.\n"; - exit(0); - } - - if (isset($envNames[$answer])) { - $envName = $envNames[$answer]; - } -} else { - $envName = $params['env']; -} - -if (!in_array($envName, $envNames)) { - $envsList = implode(', ', $envNames); - echo "\n $envName is not a valid environment. Try one of the following: $envsList. \n"; - exit(2); -} - -$env = $envs[$envName]; - -if (empty($params['env'])) { - echo "\n Initialize the application under '{$envNames[$answer]}' environment? [yes|no] "; - $answer = trim(fgets(STDIN)); - if (strncasecmp($answer, 'y', 1)) { - echo "\n Quit initialization.\n"; - exit(0); - } -} - -echo "\n Start initialization ...\n\n"; -$files = getFileList("$root/environments/{$env['path']}"); -$all = false; -foreach ($files as $file) { - if (!copyFile($root, "environments/{$env['path']}/$file", $file, $all, $params)) { - break; - } -} - -$callbacks = ['setCookieValidationKey', 'setWritable', 'setExecutable']; -foreach ($callbacks as $callback) { - if (!empty($env[$callback])) { - $callback($root, $env[$callback]); - } -} - -echo "\n ... initialization completed.\n\n"; - -function getFileList($root, $basePath = '') -{ - $files = []; - $handle = opendir($root); - while (($path = readdir($handle)) !== false) { - if ($path === '.svn' || $path === '.' || $path === '..') { - continue; - } - $fullPath = "$root/$path"; - $relativePath = $basePath === '' ? $path : "$basePath/$path"; - if (is_dir($fullPath)) { - $files = array_merge($files, getFileList($fullPath, $relativePath)); - } else { - $files[] = $relativePath; - } - } - closedir($handle); - return $files; -} - -function copyFile($root, $source, $target, &$all, $params) -{ - if (!is_file($root . '/' . $source)) { - echo " skip $target ($source not exist)\n"; - return true; - } - if (is_file($root . '/' . $target)) { - if (file_get_contents($root . '/' . $source) === file_get_contents($root . '/' . $target)) { - echo " unchanged $target\n"; - return true; - } - if ($all) { - echo " overwrite $target\n"; - } else { - echo " exist $target\n"; - echo " ...overwrite? [Yes|No|All|Quit] "; - - - $answer = !empty($params['overwrite']) ? $params['overwrite'] : trim(fgets(STDIN)); - if (!strncasecmp($answer, 'q', 1)) { - return false; - } else { - if (!strncasecmp($answer, 'y', 1)) { - echo " overwrite $target\n"; - } else { - if (!strncasecmp($answer, 'a', 1)) { - echo " overwrite $target\n"; - $all = true; - } else { - echo " skip $target\n"; - return true; - } - } - } - } - file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source)); - return true; - } - echo " generate $target\n"; - @mkdir(dirname($root . '/' . $target), 0777, true); - file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source)); - return true; -} - -function getParams() -{ - $rawParams = []; - if (isset($_SERVER['argv'])) { - $rawParams = $_SERVER['argv']; - array_shift($rawParams); - } - - $params = []; - foreach ($rawParams as $param) { - if (preg_match('/^--(\w+)(=(.*))?$/', $param, $matches)) { - $name = $matches[1]; - $params[$name] = isset($matches[3]) ? $matches[3] : true; - } else { - $params[] = $param; - } - } - return $params; -} - -function setWritable($root, $paths) -{ - foreach ($paths as $writable) { - echo " chmod 0777 $writable\n"; - @chmod("$root/$writable", 0777); - } -} - -function setExecutable($root, $paths) -{ - foreach ($paths as $executable) { - echo " chmod 0755 $executable\n"; - @chmod("$root/$executable", 0755); - } -} - -function setCookieValidationKey($root, $paths) -{ - foreach ($paths as $file) { - echo " generate cookie validation key in $file\n"; - $file = $root . '/' . $file; - $length = 32; - $bytes = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM); - $key = strtr(substr(base64_encode($bytes), 0, $length), '+/=', '_-.'); - $content = preg_replace('/(("|\')cookieValidationKey("|\')\s*=>\s*)(""|\'\')/', "\\1'$key'", file_get_contents($file)); - file_put_contents($file, $content); - } -} diff --git a/apps/advanced/init.bat b/apps/advanced/init.bat deleted file mode 100644 index 4fc52f7..0000000 --- a/apps/advanced/init.bat +++ /dev/null @@ -1,20 +0,0 @@ -@echo off - -rem ------------------------------------------------------------- -rem Yii command line init script for Windows. -rem -rem @author Qiang Xue -rem @link http://www.yiiframework.com/ -rem @copyright Copyright © 2012 Yii Software LLC -rem @license http://www.yiiframework.com/license/ -rem ------------------------------------------------------------- - -@setlocal - -set YII_PATH=%~dp0 - -if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe - -"%PHP_COMMAND%" "%YII_PATH%init" %* - -@endlocal diff --git a/apps/advanced/requirements.php b/apps/advanced/requirements.php deleted file mode 100644 index bc4018f..0000000 --- a/apps/advanced/requirements.php +++ /dev/null @@ -1,102 +0,0 @@ -Error'; - echo '

The path to yii framework seems to be incorrect.

'; - echo '

You need to install Yii framework via composer or adjust the framework path in file ' . basename(__FILE__) . '.

'; - echo '

Please refer to the README on how to install Yii.

'; -} - -require_once($frameworkPath . '/requirements/YiiRequirementChecker.php'); -$requirementsChecker = new YiiRequirementChecker(); - -/** - * Adjust requirements according to your application specifics. - */ -$requirements = array( - // Database : - array( - 'name' => 'PDO extension', - 'mandatory' => true, - 'condition' => extension_loaded('pdo'), - 'by' => 'All DB-related classes', - ), - array( - 'name' => 'PDO SQLite extension', - 'mandatory' => false, - 'condition' => extension_loaded('pdo_sqlite'), - 'by' => 'All DB-related classes', - 'memo' => 'Required for SQLite database.', - ), - array( - 'name' => 'PDO MySQL extension', - 'mandatory' => false, - 'condition' => extension_loaded('pdo_mysql'), - 'by' => 'All DB-related classes', - 'memo' => 'Required for MySQL database.', - ), - array( - 'name' => 'PDO PostgreSQL extension', - 'mandatory' => false, - 'condition' => extension_loaded('pdo_pgsql'), - 'by' => 'All DB-related classes', - 'memo' => 'Required for PostgreSQL database.', - ), - // Cache : - array( - 'name' => 'Memcache extension', - 'mandatory' => false, - 'condition' => extension_loaded('memcache') || extension_loaded('memcached'), - 'by' => 'MemCache', - 'memo' => extension_loaded('memcached') ? 'To use memcached set MemCache::useMemcached to true.' : '' - ), - array( - 'name' => 'APC extension', - 'mandatory' => false, - 'condition' => extension_loaded('apc'), - 'by' => 'ApcCache', - ), - // PHP ini : - 'phpSafeMode' => array( - 'name' => 'PHP safe mode', - 'mandatory' => false, - 'condition' => $requirementsChecker->checkPhpIniOff("safe_mode"), - 'by' => 'File uploading and console command execution', - 'memo' => '"safe_mode" should be disabled at php.ini', - ), - 'phpExposePhp' => array( - 'name' => 'Expose PHP', - 'mandatory' => false, - 'condition' => $requirementsChecker->checkPhpIniOff("expose_php"), - 'by' => 'Security reasons', - 'memo' => '"expose_php" should be disabled at php.ini', - ), - 'phpAllowUrlInclude' => array( - 'name' => 'PHP allow url include', - 'mandatory' => false, - 'condition' => $requirementsChecker->checkPhpIniOff("allow_url_include"), - 'by' => 'Security reasons', - 'memo' => '"allow_url_include" should be disabled at php.ini', - ), - 'phpSmtp' => array( - 'name' => 'PHP mail SMTP', - 'mandatory' => false, - 'condition' => strlen(ini_get('SMTP')) > 0, - 'by' => 'Email sending', - 'memo' => 'PHP mail SMTP server required', - ), -); -$requirementsChecker->checkYii()->check($requirements)->render(); diff --git a/apps/advanced/tests/_log/.gitignore b/apps/advanced/tests/_log/.gitignore deleted file mode 100644 index d6b7ef3..0000000 --- a/apps/advanced/tests/_log/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore diff --git a/apps/advanced/yii.bat b/apps/advanced/yii.bat deleted file mode 100644 index 5e21e2e..0000000 --- a/apps/advanced/yii.bat +++ /dev/null @@ -1,20 +0,0 @@ -@echo off - -rem ------------------------------------------------------------- -rem Yii command line bootstrap script for Windows. -rem -rem @author Qiang Xue -rem @link http://www.yiiframework.com/ -rem @copyright Copyright © 2012 Yii Software LLC -rem @license http://www.yiiframework.com/license/ -rem ------------------------------------------------------------- - -@setlocal - -set YII_PATH=%~dp0 - -if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe - -"%PHP_COMMAND%" "%YII_PATH%yii" %* - -@endlocal diff --git a/apps/basic/.gitignore b/apps/basic/.gitignore deleted file mode 100644 index 45bf7bf..0000000 --- a/apps/basic/.gitignore +++ /dev/null @@ -1,27 +0,0 @@ -# phpstorm project files -.idea - -# netbeans project files -nbproject - -# zend studio for eclipse project files -.buildpath -.project -.settings - -# windows thumbnail cache -Thumbs.db - -# composer vendor dir -/vendor - -# composer itself is not needed -composer.phar - -# Mac DS_Store Files -.DS_Store - -# phpunit itself is not needed -phpunit.phar -# local phpunit config -/phpunit.xml diff --git a/apps/basic/LICENSE.md b/apps/basic/LICENSE.md deleted file mode 100644 index e98f03d..0000000 --- a/apps/basic/LICENSE.md +++ /dev/null @@ -1,32 +0,0 @@ -The Yii framework is free software. It is released under the terms of -the following BSD License. - -Copyright © 2008 by Yii Software LLC (http://www.yiisoft.com) -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - * Neither the name of Yii Software LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. diff --git a/apps/basic/README.md b/apps/basic/README.md deleted file mode 100644 index 452d030..0000000 --- a/apps/basic/README.md +++ /dev/null @@ -1,88 +0,0 @@ -Yii 2 Basic Application Template -================================ - -Yii 2 Basic Application Template is a skeleton Yii 2 application best for -rapidly creating small projects. - -The template contains the basic features including user login/logout and a contact page. -It includes all commonly used configurations that would allow you to focus on adding new -features to your application. - - -DIRECTORY STRUCTURE -------------------- - - assets/ contains assets definition - commands/ contains console commands (controllers) - config/ contains application configurations - controllers/ contains Web controller classes - mail/ contains view files for e-mails - models/ contains model classes - runtime/ contains files generated during runtime - tests/ contains various tests for the basic application - vendor/ contains dependent 3rd-party packages - views/ contains view files for the Web application - web/ contains the entry script and Web resources - - - -REQUIREMENTS ------------- - -The minimum requirement by this application template that your Web server supports PHP 5.4.0. - - -INSTALLATION ------------- - -### Install from an Archive File - -Extract the archive file downloaded from [yiiframework.com](http://www.yiiframework.com/download/) to -a directory named `basic` that is directly under the Web root. - -You can then access the application through the following URL: - -~~~ -http://localhost/basic/web/ -~~~ - - -### Install via Composer - -If you do not have [Composer](http://getcomposer.org/), you may install it by following the instructions -at [getcomposer.org](http://getcomposer.org/doc/00-intro.md#installation-nix). - -You can then install this application template using the following command: - -~~~ -php composer.phar create-project --prefer-dist --stability=dev yiisoft/yii2-app-basic basic -~~~ - -Now you should be able to access the application through the following URL, assuming `basic` is the directory -directly under the Web root. - -~~~ -http://localhost/basic/web/ -~~~ - - -CONFIGURATION -------------- - -### Database - -Edit the file `config/db.php` with real data, for example: - -```php -return [ - 'class' => 'yii\db\Connection', - 'dsn' => 'mysql:host=localhost;dbname=yii2basic', - 'username' => 'root', - 'password' => '1234', - 'charset' => 'utf8', -]; -``` - -**NOTE:** Yii won't create the database for you, this has to be done manually before you can access it. - -Also check and edit the other files in the `config/` directory to customize your application. diff --git a/apps/basic/assets/AppAsset.php b/apps/basic/assets/AppAsset.php deleted file mode 100644 index 0e495a8..0000000 --- a/apps/basic/assets/AppAsset.php +++ /dev/null @@ -1,29 +0,0 @@ - - * @since 2.0 - */ -class AppAsset extends AssetBundle -{ - public $basePath = '@webroot'; - public $baseUrl = '@web'; - public $css = [ - 'css/site.css', - ]; - public $js = [ - ]; - public $depends = [ - 'yii\web\YiiAsset', - 'yii\bootstrap\BootstrapAsset', - ]; -} diff --git a/apps/basic/codeception.yml b/apps/basic/codeception.yml deleted file mode 100644 index 496ebd9..0000000 --- a/apps/basic/codeception.yml +++ /dev/null @@ -1,19 +0,0 @@ -actor: Tester -paths: - tests: tests - log: tests/_log - data: tests/_data - helpers: tests/_helpers -settings: - bootstrap: _bootstrap.php - suite_class: \PHPUnit_Framework_TestSuite - memory_limit: 1024M - log: true - colors: true -modules: - config: - Db: - dsn: '' - user: '' - password: '' - dump: tests/_data/dump.sql diff --git a/apps/basic/commands/HelloController.php b/apps/basic/commands/HelloController.php deleted file mode 100644 index 86ab8b8..0000000 --- a/apps/basic/commands/HelloController.php +++ /dev/null @@ -1,30 +0,0 @@ - - * @since 2.0 - */ -class HelloController extends Controller -{ - /** - * This command echoes what you have entered as the message. - * @param string $message the message to be echoed. - */ - public function actionIndex($message = 'hello world') - { - echo $message . "\n"; - } -} diff --git a/apps/basic/composer.json b/apps/basic/composer.json deleted file mode 100644 index a21128b..0000000 --- a/apps/basic/composer.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "name": "yiisoft/yii2-app-basic", - "description": "Yii 2 Basic Application Template", - "keywords": ["yii2", "framework", "basic", "application template"], - "homepage": "http://www.yiiframework.com/", - "type": "project", - "license": "BSD-3-Clause", - "support": { - "issues": "https://github.com/yiisoft/yii2/issues?state=open", - "forum": "http://www.yiiframework.com/forum/", - "wiki": "http://www.yiiframework.com/wiki/", - "irc": "irc://irc.freenode.net/yii", - "source": "https://github.com/yiisoft/yii2" - }, - "minimum-stability": "dev", - "require": { - "php": ">=5.4.0", - "yiisoft/yii2": "*", - "yiisoft/yii2-bootstrap": "*", - "yiisoft/yii2-swiftmailer": "*" - }, - "require-dev": { - "yiisoft/yii2-codeception": "*", - "yiisoft/yii2-debug": "*", - "yiisoft/yii2-gii": "*" - }, - "suggest": { - "codeception/codeception": "Codeception, 2.0.* is currently works well with Yii.", - "codeception/specify": "BDD style code blocks for PHPUnit and Codeception", - "codeception/verify": "BDD Assertions for PHPUnit and Codeception" - }, - "scripts": { - "post-create-project-cmd": [ - "yii\\composer\\Installer::setPermission", - "yii\\composer\\Installer::generateCookieValidationKey" - ] - }, - "config": { - "process-timeout": 1800 - }, - "extra": { - "writable": [ - "runtime", - "web/assets" - ], - "executable": [ - "yii" - ], - "config": [ - "config/web.php" - ] - } -} diff --git a/apps/basic/config/console.php b/apps/basic/config/console.php deleted file mode 100644 index 85297b3..0000000 --- a/apps/basic/config/console.php +++ /dev/null @@ -1,28 +0,0 @@ - 'basic-console', - 'basePath' => dirname(__DIR__), - 'bootstrap' => ['log'], - 'controllerNamespace' => 'app\commands', - 'components' => [ - 'cache' => [ - 'class' => 'yii\caching\FileCache', - ], - 'log' => [ - 'targets' => [ - [ - 'class' => 'yii\log\FileTarget', - 'levels' => ['error', 'warning'], - ], - ], - ], - 'db' => $db, - ], - 'params' => $params, -]; diff --git a/apps/basic/config/db.php b/apps/basic/config/db.php deleted file mode 100644 index c4c1252..0000000 --- a/apps/basic/config/db.php +++ /dev/null @@ -1,9 +0,0 @@ - 'yii\db\Connection', - 'dsn' => 'mysql:host=localhost;dbname=yii2basic', - 'username' => 'root', - 'password' => '', - 'charset' => 'utf8', -]; diff --git a/apps/basic/config/params.php b/apps/basic/config/params.php deleted file mode 100644 index 6ebf279..0000000 --- a/apps/basic/config/params.php +++ /dev/null @@ -1,5 +0,0 @@ - 'admin@example.com', -]; diff --git a/apps/basic/config/web.php b/apps/basic/config/web.php deleted file mode 100644 index 1632a5a..0000000 --- a/apps/basic/config/web.php +++ /dev/null @@ -1,54 +0,0 @@ - 'basic', - 'basePath' => dirname(__DIR__), - 'bootstrap' => ['log'], - 'components' => [ - 'request' => [ - // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation - 'cookieValidationKey' => '', - ], - 'cache' => [ - 'class' => 'yii\caching\FileCache', - ], - 'user' => [ - 'identityClass' => 'app\models\User', - 'enableAutoLogin' => true, - ], - 'errorHandler' => [ - 'errorAction' => 'site/error', - ], - 'mailer' => [ - 'class' => 'yii\swiftmailer\Mailer', - // send all mails to a file by default. You have to set - // 'useFileTransport' to false and configure a transport - // for the mailer to send real emails. - 'useFileTransport' => true, - ], - 'log' => [ - 'traceLevel' => YII_DEBUG ? 3 : 0, - 'targets' => [ - [ - 'class' => 'yii\log\FileTarget', - 'levels' => ['error', 'warning'], - ], - ], - ], - 'db' => require(__DIR__ . '/db.php'), - ], - 'params' => $params, -]; - -if (YII_ENV_DEV) { - // configuration adjustments for 'dev' environment - $config['bootstrap'][] = 'debug'; - $config['modules']['debug'] = 'yii\debug\Module'; - - $config['bootstrap'][] = 'gii'; - $config['modules']['gii'] = 'yii\gii\Module'; -} - -return $config; diff --git a/apps/basic/controllers/SiteController.php b/apps/basic/controllers/SiteController.php deleted file mode 100644 index f959941..0000000 --- a/apps/basic/controllers/SiteController.php +++ /dev/null @@ -1,96 +0,0 @@ - [ - 'class' => AccessControl::className(), - 'only' => ['logout'], - 'rules' => [ - [ - 'actions' => ['logout'], - 'allow' => true, - 'roles' => ['@'], - ], - ], - ], - 'verbs' => [ - 'class' => VerbFilter::className(), - 'actions' => [ - 'logout' => ['post'], - ], - ], - ]; - } - - public function actions() - { - return [ - 'error' => [ - 'class' => 'yii\web\ErrorAction', - ], - 'captcha' => [ - 'class' => 'yii\captcha\CaptchaAction', - 'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null, - ], - ]; - } - - public function actionIndex() - { - return $this->render('index'); - } - - public function actionLogin() - { - if (!\Yii::$app->user->isGuest) { - return $this->goHome(); - } - - $model = new LoginForm(); - if ($model->load(Yii::$app->request->post()) && $model->login()) { - return $this->goBack(); - } else { - return $this->render('login', [ - 'model' => $model, - ]); - } - } - - public function actionLogout() - { - Yii::$app->user->logout(); - - return $this->goHome(); - } - - public function actionContact() - { - $model = new ContactForm(); - if ($model->load(Yii::$app->request->post()) && $model->contact(Yii::$app->params['adminEmail'])) { - Yii::$app->session->setFlash('contactFormSubmitted'); - - return $this->refresh(); - } else { - return $this->render('contact', [ - 'model' => $model, - ]); - } - } - - public function actionAbout() - { - return $this->render('about'); - } -} diff --git a/apps/basic/mail/layouts/html.php b/apps/basic/mail/layouts/html.php deleted file mode 100644 index bddbc61..0000000 --- a/apps/basic/mail/layouts/html.php +++ /dev/null @@ -1,22 +0,0 @@ - -beginPage() ?> - - - - - <?= Html::encode($this->title) ?> - head() ?> - - - beginBody() ?> - - endBody() ?> - - -endPage() ?> diff --git a/apps/basic/models/ContactForm.php b/apps/basic/models/ContactForm.php deleted file mode 100644 index d4052ee..0000000 --- a/apps/basic/models/ContactForm.php +++ /dev/null @@ -1,64 +0,0 @@ - 'Verification Code', - ]; - } - - /** - * Sends an email to the specified email address using the information collected by this model. - * @param string $email the target email address - * @return boolean whether the model passes validation - */ - public function contact($email) - { - if ($this->validate()) { - Yii::$app->mailer->compose() - ->setTo($email) - ->setFrom([$this->email => $this->name]) - ->setSubject($this->subject) - ->setTextBody($this->body) - ->send(); - - return true; - } else { - return false; - } - } -} diff --git a/apps/basic/models/LoginForm.php b/apps/basic/models/LoginForm.php deleted file mode 100644 index 687d29d..0000000 --- a/apps/basic/models/LoginForm.php +++ /dev/null @@ -1,78 +0,0 @@ -hasErrors()) { - $user = $this->getUser(); - - if (!$user || !$user->validatePassword($this->password)) { - $this->addError($attribute, 'Incorrect username or password.'); - } - } - } - - /** - * Logs in a user using the provided username and password. - * @return boolean whether the user is logged in successfully - */ - public function login() - { - if ($this->validate()) { - return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600*24*30 : 0); - } else { - return false; - } - } - - /** - * Finds user by [[username]] - * - * @return User|null - */ - public function getUser() - { - if ($this->_user === false) { - $this->_user = User::findByUsername($this->username); - } - - return $this->_user; - } -} diff --git a/apps/basic/models/User.php b/apps/basic/models/User.php deleted file mode 100644 index cbfb9fe..0000000 --- a/apps/basic/models/User.php +++ /dev/null @@ -1,103 +0,0 @@ - [ - 'id' => '100', - 'username' => 'admin', - 'password' => 'admin', - 'authKey' => 'test100key', - 'accessToken' => '100-token', - ], - '101' => [ - 'id' => '101', - 'username' => 'demo', - 'password' => 'demo', - 'authKey' => 'test101key', - 'accessToken' => '101-token', - ], - ]; - - /** - * @inheritdoc - */ - public static function findIdentity($id) - { - return isset(self::$users[$id]) ? new static(self::$users[$id]) : null; - } - - /** - * @inheritdoc - */ - public static function findIdentityByAccessToken($token, $type = null) - { - foreach (self::$users as $user) { - if ($user['accessToken'] === $token) { - return new static($user); - } - } - - return null; - } - - /** - * Finds user by username - * - * @param string $username - * @return static|null - */ - public static function findByUsername($username) - { - foreach (self::$users as $user) { - if (strcasecmp($user['username'], $username) === 0) { - return new static($user); - } - } - - return null; - } - - /** - * @inheritdoc - */ - public function getId() - { - return $this->id; - } - - /** - * @inheritdoc - */ - public function getAuthKey() - { - return $this->authKey; - } - - /** - * @inheritdoc - */ - public function validateAuthKey($authKey) - { - return $this->authKey === $authKey; - } - - /** - * Validates password - * - * @param string $password password to validate - * @return boolean if password provided is valid for current user - */ - public function validatePassword($password) - { - return $this->password === $password; - } -} diff --git a/apps/basic/requirements.php b/apps/basic/requirements.php deleted file mode 100644 index a38b936..0000000 --- a/apps/basic/requirements.php +++ /dev/null @@ -1,102 +0,0 @@ -Error'; - echo '

The path to yii framework seems to be incorrect.

'; - echo '

You need to install Yii framework via composer or adjust the framework path in file ' . basename(__FILE__) . '.

'; - echo '

Please refer to the README on how to install Yii.

'; -} - -require_once($frameworkPath . '/requirements/YiiRequirementChecker.php'); -$requirementsChecker = new YiiRequirementChecker(); - -/** - * Adjust requirements according to your application specifics. - */ -$requirements = array( - // Database : - array( - 'name' => 'PDO extension', - 'mandatory' => true, - 'condition' => extension_loaded('pdo'), - 'by' => 'All DB-related classes', - ), - array( - 'name' => 'PDO SQLite extension', - 'mandatory' => false, - 'condition' => extension_loaded('pdo_sqlite'), - 'by' => 'All DB-related classes', - 'memo' => 'Required for SQLite database.', - ), - array( - 'name' => 'PDO MySQL extension', - 'mandatory' => false, - 'condition' => extension_loaded('pdo_mysql'), - 'by' => 'All DB-related classes', - 'memo' => 'Required for MySQL database.', - ), - array( - 'name' => 'PDO PostgreSQL extension', - 'mandatory' => false, - 'condition' => extension_loaded('pdo_pgsql'), - 'by' => 'All DB-related classes', - 'memo' => 'Required for PostgreSQL database.', - ), - // Cache : - array( - 'name' => 'Memcache extension', - 'mandatory' => false, - 'condition' => extension_loaded('memcache') || extension_loaded('memcached'), - 'by' => 'MemCache', - 'memo' => extension_loaded('memcached') ? 'To use memcached set MemCache::useMemcached to true.' : '' - ), - array( - 'name' => 'APC extension', - 'mandatory' => false, - 'condition' => extension_loaded('apc'), - 'by' => 'ApcCache', - ), - // PHP ini : - 'phpSafeMode' => array( - 'name' => 'PHP safe mode', - 'mandatory' => false, - 'condition' => $requirementsChecker->checkPhpIniOff("safe_mode"), - 'by' => 'File uploading and console command execution', - 'memo' => '"safe_mode" should be disabled at php.ini', - ), - 'phpExposePhp' => array( - 'name' => 'Expose PHP', - 'mandatory' => false, - 'condition' => $requirementsChecker->checkPhpIniOff("expose_php"), - 'by' => 'Security reasons', - 'memo' => '"expose_php" should be disabled at php.ini', - ), - 'phpAllowUrlInclude' => array( - 'name' => 'PHP allow url include', - 'mandatory' => false, - 'condition' => $requirementsChecker->checkPhpIniOff("allow_url_include"), - 'by' => 'Security reasons', - 'memo' => '"allow_url_include" should be disabled at php.ini', - ), - 'phpSmtp' => array( - 'name' => 'PHP mail SMTP', - 'mandatory' => false, - 'condition' => strlen(ini_get('SMTP'))>0, - 'by' => 'Email sending', - 'memo' => 'PHP mail SMTP server required', - ), -); -$requirementsChecker->checkYii()->check($requirements)->render(); diff --git a/apps/basic/runtime/.gitignore b/apps/basic/runtime/.gitignore deleted file mode 100644 index c96a04f..0000000 --- a/apps/basic/runtime/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/apps/basic/tests/.gitignore b/apps/basic/tests/.gitignore deleted file mode 100644 index c5aa074..0000000 --- a/apps/basic/tests/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# these files are auto generated by codeception build -/unit/CodeGuy.php -/functional/TestGuy.php -/acceptance/WebGuy.php diff --git a/apps/basic/tests/README.md b/apps/basic/tests/README.md deleted file mode 100644 index e1aed9a..0000000 --- a/apps/basic/tests/README.md +++ /dev/null @@ -1,33 +0,0 @@ -This folder contains various tests for the basic application. -These tests are developed with [Codeception PHP Testing Framework](http://codeception.com/). - -After creating the basic application, follow these steps to prepare for the tests: - -1. Install additional composer packages: - - ``` - php composer.phar require --dev "codeception/codeception: 2.0.*" "codeception/specify: *" "codeception/verify: *" - ``` -2. In the file `_bootstrap.php`, modify the definition of the constant `TEST_ENTRY_URL` so - that it points to the correct entry script URL. -3. Go to the application base directory and build the test suites: - - ``` - vendor/bin/codecept build - ``` - -Now you can run the tests with the following commands: - -``` -# run all available tests -vendor/bin/codecept run -# run acceptance tests -vendor/bin/codecept run acceptance -# run functional tests -vendor/bin/codecept run functional -# run unit tests -vendor/bin/codecept run unit -``` - -Please refer to [Codeception tutorial](http://codeception.com/docs/01-Introduction) for -more details about writing and running acceptance, functional and unit tests. diff --git a/apps/basic/tests/_bootstrap.php b/apps/basic/tests/_bootstrap.php deleted file mode 100644 index 4890b3e..0000000 --- a/apps/basic/tests/_bootstrap.php +++ /dev/null @@ -1,23 +0,0 @@ - [ - 'mailer' => [ - 'useFileTransport' => true, - ], - 'urlManager' => [ - 'showScriptName' => true, - ], - ], -]; diff --git a/apps/basic/tests/_console_bootstrap.php b/apps/basic/tests/_console_bootstrap.php deleted file mode 100644 index 81287f3..0000000 --- a/apps/basic/tests/_console_bootstrap.php +++ /dev/null @@ -1,12 +0,0 @@ - $value) { - $inputType = $field === 'body' ? 'textarea' : 'input'; - $this->guy->fillField($inputType . '[name="ContactForm[' . $field . ']"]', $value); - } - $this->guy->click('contact-button'); - } -} diff --git a/apps/basic/tests/_pages/LoginPage.php b/apps/basic/tests/_pages/LoginPage.php deleted file mode 100644 index c73d729..0000000 --- a/apps/basic/tests/_pages/LoginPage.php +++ /dev/null @@ -1,21 +0,0 @@ -guy->fillField('input[name="LoginForm[username]"]', $username); - $this->guy->fillField('input[name="LoginForm[password]"]', $password); - $this->guy->click('login-button'); - } -} diff --git a/apps/basic/tests/acceptance.suite.yml b/apps/basic/tests/acceptance.suite.yml deleted file mode 100644 index bd10f82..0000000 --- a/apps/basic/tests/acceptance.suite.yml +++ /dev/null @@ -1,26 +0,0 @@ -# Codeception Test Suite Configuration - -# suite for acceptance tests. -# perform tests in browser using the Selenium-like tools. -# powered by Mink (http://mink.behat.org). -# (tip: that's what your customer will see). -# (tip: test your ajax and javascript by one of Mink drivers). - -# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES. - -class_name: WebGuy -modules: - enabled: - - PhpBrowser -# you can use WebDriver instead of PhpBrowser to test javascript and ajax. -# This will require you to install selenium. See http://codeception.com/docs/04-AcceptanceTests#Selenium -# "restart" option is used by the WebDriver to start each time per test-file new session and cookies, -# it is useful if you want to login in your app in each test. -# - WebDriver - config: - PhpBrowser: - url: 'http://localhost:8080' -# WebDriver: -# url: 'http://localhost' -# browser: firefox -# restart: true diff --git a/apps/basic/tests/acceptance/AboutCept.php b/apps/basic/tests/acceptance/AboutCept.php deleted file mode 100644 index deecee7..0000000 --- a/apps/basic/tests/acceptance/AboutCept.php +++ /dev/null @@ -1,8 +0,0 @@ -wantTo('ensure that about works'); -AboutPage::openBy($I); -$I->see('About', 'h1'); diff --git a/apps/basic/tests/acceptance/ContactCept.php b/apps/basic/tests/acceptance/ContactCept.php deleted file mode 100644 index e76ac9b..0000000 --- a/apps/basic/tests/acceptance/ContactCept.php +++ /dev/null @@ -1,49 +0,0 @@ -wantTo('ensure that contact works'); - -$contactPage = ContactPage::openBy($I); - -$I->see('Contact', 'h1'); - -$I->amGoingTo('submit contact form with no data'); -$contactPage->submit([]); -$I->expectTo('see validations errors'); -$I->see('Contact', 'h1'); -$I->see('Name cannot be blank'); -$I->see('Email cannot be blank'); -$I->see('Subject cannot be blank'); -$I->see('Body cannot be blank'); -$I->see('The verification code is incorrect'); - -$I->amGoingTo('submit contact form with not correct email'); -$contactPage->submit([ - 'name' => 'tester', - 'email' => 'tester.email', - 'subject' => 'test subject', - 'body' => 'test content', - 'verifyCode' => 'testme', -]); -$I->expectTo('see that email adress is wrong'); -$I->dontSee('Name cannot be blank', '.help-inline'); -$I->see('Email is not a valid email address.'); -$I->dontSee('Subject cannot be blank', '.help-inline'); -$I->dontSee('Body cannot be blank', '.help-inline'); -$I->dontSee('The verification code is incorrect', '.help-inline'); - -$I->amGoingTo('submit contact form with correct data'); -$contactPage->submit([ - 'name' => 'tester', - 'email' => 'tester@example.com', - 'subject' => 'test subject', - 'body' => 'test content', - 'verifyCode' => 'testme', -]); -if (method_exists($I, 'wait')) { - $I->wait(3); // only for selenium -} -$I->dontSeeElement('#contact-form'); -$I->see('Thank you for contacting us. We will respond to you as soon as possible.'); diff --git a/apps/basic/tests/acceptance/HomeCept.php b/apps/basic/tests/acceptance/HomeCept.php deleted file mode 100644 index 62456f9..0000000 --- a/apps/basic/tests/acceptance/HomeCept.php +++ /dev/null @@ -1,9 +0,0 @@ -wantTo('ensure that home page works'); -$I->amOnPage(Yii::$app->homeUrl); -$I->see('My Company'); -$I->seeLink('About'); -$I->click('About'); -$I->see('This is the About page.'); diff --git a/apps/basic/tests/acceptance/LoginCept.php b/apps/basic/tests/acceptance/LoginCept.php deleted file mode 100644 index c7c9ae3..0000000 --- a/apps/basic/tests/acceptance/LoginCept.php +++ /dev/null @@ -1,32 +0,0 @@ -wantTo('ensure that login works'); - -$loginPage = LoginPage::openBy($I); - -$I->see('Login', 'h1'); - -$I->amGoingTo('try to login with empty credentials'); -$loginPage->login('', ''); -$I->expectTo('see validations errors'); -$I->see('Username cannot be blank.'); -$I->see('Password cannot be blank.'); - -$I->amGoingTo('try to login with wrong credentials'); -$loginPage->login('admin', 'wrong'); -if (method_exists($I, 'wait')) { - $I->wait(3); // only for selenium -} -$I->expectTo('see validations errors'); -$I->see('Incorrect username or password.'); - -$I->amGoingTo('try to login with correct credentials'); -$loginPage->login('admin', 'admin'); -if (method_exists($I, 'wait')) { - $I->wait(3); // only for selenium -} -$I->expectTo('see user info'); -$I->see('Logout (admin)'); diff --git a/apps/basic/tests/acceptance/_bootstrap.php b/apps/basic/tests/acceptance/_bootstrap.php deleted file mode 100644 index 6ce3d17..0000000 --- a/apps/basic/tests/acceptance/_bootstrap.php +++ /dev/null @@ -1,3 +0,0 @@ - [ - 'db' => [ - 'dsn' => 'mysql:host=localhost;dbname=yii2_basic_acceptance', - ], - ], - ] -); diff --git a/apps/basic/tests/acceptance/_console.php b/apps/basic/tests/acceptance/_console.php deleted file mode 100644 index 03cdd1f..0000000 --- a/apps/basic/tests/acceptance/_console.php +++ /dev/null @@ -1,13 +0,0 @@ - [ - 'db' => [ - 'dsn' => 'mysql:host=localhost;dbname=yii2_basic_acceptance', - ], - ], - ] -); diff --git a/apps/basic/tests/acceptance/yii b/apps/basic/tests/acceptance/yii deleted file mode 100644 index e587ba4..0000000 --- a/apps/basic/tests/acceptance/yii +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env php -run(); -exit($exitCode); diff --git a/apps/basic/tests/acceptance/yii.bat b/apps/basic/tests/acceptance/yii.bat deleted file mode 100644 index 5e21e2e..0000000 --- a/apps/basic/tests/acceptance/yii.bat +++ /dev/null @@ -1,20 +0,0 @@ -@echo off - -rem ------------------------------------------------------------- -rem Yii command line bootstrap script for Windows. -rem -rem @author Qiang Xue -rem @link http://www.yiiframework.com/ -rem @copyright Copyright © 2012 Yii Software LLC -rem @license http://www.yiiframework.com/license/ -rem ------------------------------------------------------------- - -@setlocal - -set YII_PATH=%~dp0 - -if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe - -"%PHP_COMMAND%" "%YII_PATH%yii" %* - -@endlocal diff --git a/apps/basic/tests/functional.suite.yml b/apps/basic/tests/functional.suite.yml deleted file mode 100644 index 916ef1a..0000000 --- a/apps/basic/tests/functional.suite.yml +++ /dev/null @@ -1,16 +0,0 @@ -# Codeception Test Suite Configuration - -# suite for functional (integration) tests. -# emulate web requests and make application process them. -# (tip: better to use with frameworks). - -# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES. -#basic/web/index.php -class_name: TestGuy -modules: - enabled: - - Filesystem - - Yii2 - config: - Yii2: - configFile: 'tests/functional/_config.php' diff --git a/apps/basic/tests/functional/AboutCept.php b/apps/basic/tests/functional/AboutCept.php deleted file mode 100644 index 1875c2e..0000000 --- a/apps/basic/tests/functional/AboutCept.php +++ /dev/null @@ -1,8 +0,0 @@ -wantTo('ensure that about works'); -AboutPage::openBy($I); -$I->see('About', 'h1'); diff --git a/apps/basic/tests/functional/ContactCept.php b/apps/basic/tests/functional/ContactCept.php deleted file mode 100644 index 49d7735..0000000 --- a/apps/basic/tests/functional/ContactCept.php +++ /dev/null @@ -1,46 +0,0 @@ -wantTo('ensure that contact works'); - -$contactPage = ContactPage::openBy($I); - -$I->see('Contact', 'h1'); - -$I->amGoingTo('submit contact form with no data'); -$contactPage->submit([]); -$I->expectTo('see validations errors'); -$I->see('Contact', 'h1'); -$I->see('Name cannot be blank'); -$I->see('Email cannot be blank'); -$I->see('Subject cannot be blank'); -$I->see('Body cannot be blank'); -$I->see('The verification code is incorrect'); - -$I->amGoingTo('submit contact form with not correct email'); -$contactPage->submit([ - 'name' => 'tester', - 'email' => 'tester.email', - 'subject' => 'test subject', - 'body' => 'test content', - 'verifyCode' => 'testme', -]); -$I->expectTo('see that email adress is wrong'); -$I->dontSee('Name cannot be blank', '.help-inline'); -$I->see('Email is not a valid email address.'); -$I->dontSee('Subject cannot be blank', '.help-inline'); -$I->dontSee('Body cannot be blank', '.help-inline'); -$I->dontSee('The verification code is incorrect', '.help-inline'); - -$I->amGoingTo('submit contact form with correct data'); -$contactPage->submit([ - 'name' => 'tester', - 'email' => 'tester@example.com', - 'subject' => 'test subject', - 'body' => 'test content', - 'verifyCode' => 'testme', -]); -$I->dontSeeElement('#contact-form'); -$I->see('Thank you for contacting us. We will respond to you as soon as possible.'); diff --git a/apps/basic/tests/functional/HomeCept.php b/apps/basic/tests/functional/HomeCept.php deleted file mode 100644 index 3258ba3..0000000 --- a/apps/basic/tests/functional/HomeCept.php +++ /dev/null @@ -1,9 +0,0 @@ -wantTo('ensure that home page works'); -$I->amOnPage(Yii::$app->homeUrl); -$I->see('My Company'); -$I->seeLink('About'); -$I->click('About'); -$I->see('This is the About page.'); diff --git a/apps/basic/tests/functional/LoginCept.php b/apps/basic/tests/functional/LoginCept.php deleted file mode 100644 index e5285cd..0000000 --- a/apps/basic/tests/functional/LoginCept.php +++ /dev/null @@ -1,26 +0,0 @@ -wantTo('ensure that login works'); - -$loginPage = LoginPage::openBy($I); - -$I->see('Login', 'h1'); - -$I->amGoingTo('try to login with empty credentials'); -$loginPage->login('', ''); -$I->expectTo('see validations errors'); -$I->see('Username cannot be blank.'); -$I->see('Password cannot be blank.'); - -$I->amGoingTo('try to login with wrong credentials'); -$loginPage->login('admin', 'wrong'); -$I->expectTo('see validations errors'); -$I->see('Incorrect username or password.'); - -$I->amGoingTo('try to login with correct credentials'); -$loginPage->login('admin', 'admin'); -$I->expectTo('see user info'); -$I->see('Logout (admin)'); diff --git a/apps/basic/tests/functional/_bootstrap.php b/apps/basic/tests/functional/_bootstrap.php deleted file mode 100644 index 6ce3d17..0000000 --- a/apps/basic/tests/functional/_bootstrap.php +++ /dev/null @@ -1,3 +0,0 @@ - [ - 'db' => [ - 'dsn' => 'mysql:host=localhost;dbname=yii2_basic_functional', - ], - ], - ] -); diff --git a/apps/basic/tests/functional/_console.php b/apps/basic/tests/functional/_console.php deleted file mode 100644 index abeee69..0000000 --- a/apps/basic/tests/functional/_console.php +++ /dev/null @@ -1,13 +0,0 @@ - [ - 'db' => [ - 'dsn' => 'mysql:host=localhost;dbname=yii2_basic_functional', - ], - ], - ] -); diff --git a/apps/basic/tests/functional/yii b/apps/basic/tests/functional/yii deleted file mode 100644 index e587ba4..0000000 --- a/apps/basic/tests/functional/yii +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env php -run(); -exit($exitCode); diff --git a/apps/basic/tests/functional/yii.bat b/apps/basic/tests/functional/yii.bat deleted file mode 100644 index 5e21e2e..0000000 --- a/apps/basic/tests/functional/yii.bat +++ /dev/null @@ -1,20 +0,0 @@ -@echo off - -rem ------------------------------------------------------------- -rem Yii command line bootstrap script for Windows. -rem -rem @author Qiang Xue -rem @link http://www.yiiframework.com/ -rem @copyright Copyright © 2012 Yii Software LLC -rem @license http://www.yiiframework.com/license/ -rem ------------------------------------------------------------- - -@setlocal - -set YII_PATH=%~dp0 - -if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe - -"%PHP_COMMAND%" "%YII_PATH%yii" %* - -@endlocal diff --git a/apps/basic/tests/unit.suite.yml b/apps/basic/tests/unit.suite.yml deleted file mode 100644 index f0573a8..0000000 --- a/apps/basic/tests/unit.suite.yml +++ /dev/null @@ -1,6 +0,0 @@ -# Codeception Test Suite Configuration - -# suite for unit (internal) tests. -# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES. - -class_name: CodeGuy diff --git a/apps/basic/tests/unit/_bootstrap.php b/apps/basic/tests/unit/_bootstrap.php deleted file mode 100644 index 80cc72a..0000000 --- a/apps/basic/tests/unit/_bootstrap.php +++ /dev/null @@ -1,3 +0,0 @@ - [ - 'db' => [ - 'dsn' => 'mysql:host=localhost;dbname=yii2_basic_unit', - ], - ], - ] -); diff --git a/apps/basic/tests/unit/_console.php b/apps/basic/tests/unit/_console.php deleted file mode 100644 index 04272a3..0000000 --- a/apps/basic/tests/unit/_console.php +++ /dev/null @@ -1,13 +0,0 @@ - [ - 'db' => [ - 'dsn' => 'mysql:host=localhost;dbname=yii2_basic_unit', - ], - ], - ] -); diff --git a/apps/basic/tests/unit/fixtures/.gitkeep b/apps/basic/tests/unit/fixtures/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/apps/basic/tests/unit/fixtures/data/.gitkeep b/apps/basic/tests/unit/fixtures/data/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/apps/basic/tests/unit/models/ContactFormTest.php b/apps/basic/tests/unit/models/ContactFormTest.php deleted file mode 100644 index 6e69cec..0000000 --- a/apps/basic/tests/unit/models/ContactFormTest.php +++ /dev/null @@ -1,60 +0,0 @@ -mailer->fileTransportCallback = function ($mailer, $message) { - return 'testing_message.eml'; - }; - } - - protected function tearDown() - { - unlink($this->getMessageFile()); - parent::tearDown(); - } - - public function testContact() - { - $model = $this->getMock('app\models\ContactForm', ['validate']); - $model->expects($this->once())->method('validate')->will($this->returnValue(true)); - - $model->attributes = [ - 'name' => 'Tester', - 'email' => 'tester@example.com', - 'subject' => 'very important letter subject', - 'body' => 'body of current message', - ]; - - $model->contact('admin@example.com'); - - $this->specify('email should be send', function () { - expect('email file should exist', file_exists($this->getMessageFile()))->true(); - }); - - $this->specify('message should contain correct data', function () use ($model) { - $emailMessage = file_get_contents($this->getMessageFile()); - - expect('email should contain user name', $emailMessage)->contains($model->name); - expect('email should contain sender email', $emailMessage)->contains($model->email); - expect('email should contain subject', $emailMessage)->contains($model->subject); - expect('email should contain body', $emailMessage)->contains($model->body); - }); - } - - private function getMessageFile() - { - return Yii::getAlias(Yii::$app->mailer->fileTransportPath) . '/testing_message.eml'; - } - -} diff --git a/apps/basic/tests/unit/models/LoginFormTest.php b/apps/basic/tests/unit/models/LoginFormTest.php deleted file mode 100644 index f2c60f5..0000000 --- a/apps/basic/tests/unit/models/LoginFormTest.php +++ /dev/null @@ -1,61 +0,0 @@ -user->logout(); - parent::tearDown(); - } - - public function testLoginNoUser() - { - $model = new LoginForm([ - 'username' => 'not_existing_username', - 'password' => 'not_existing_password', - ]); - - $this->specify('user should not be able to login, when there is no identity', function () use ($model) { - expect('model should not login user', $model->login())->false(); - expect('user should not be logged in', Yii::$app->user->isGuest)->true(); - }); - } - - public function testLoginWrongPassword() - { - $model = new LoginForm([ - 'username' => 'demo', - 'password' => 'wrong_password', - ]); - - $this->specify('user should not be able to login with wrong password', function () use ($model) { - expect('model should not login user', $model->login())->false(); - expect('error message should be set', $model->errors)->hasKey('password'); - expect('user should not be logged in', Yii::$app->user->isGuest)->true(); - }); - } - - public function testLoginCorrect() - { - $model = new LoginForm([ - 'username' => 'demo', - 'password' => 'demo', - ]); - - $this->specify('user should be able to login with correct credentials', function () use ($model) { - expect('model should login user', $model->login())->true(); - expect('error message should not be set', $model->errors)->hasntKey('password'); - expect('user should be logged in', Yii::$app->user->isGuest)->false(); - }); - } - -} diff --git a/apps/basic/tests/unit/models/UserTest.php b/apps/basic/tests/unit/models/UserTest.php deleted file mode 100644 index 19ab30d..0000000 --- a/apps/basic/tests/unit/models/UserTest.php +++ /dev/null @@ -1,17 +0,0 @@ -loadFixtures(['user']); - } - - // TODO add test methods here -} diff --git a/apps/basic/tests/unit/templates/fixtures/.gitkeep b/apps/basic/tests/unit/templates/fixtures/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/apps/basic/tests/unit/yii b/apps/basic/tests/unit/yii deleted file mode 100644 index e587ba4..0000000 --- a/apps/basic/tests/unit/yii +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env php -run(); -exit($exitCode); diff --git a/apps/basic/tests/unit/yii.bat b/apps/basic/tests/unit/yii.bat deleted file mode 100644 index 5e21e2e..0000000 --- a/apps/basic/tests/unit/yii.bat +++ /dev/null @@ -1,20 +0,0 @@ -@echo off - -rem ------------------------------------------------------------- -rem Yii command line bootstrap script for Windows. -rem -rem @author Qiang Xue -rem @link http://www.yiiframework.com/ -rem @copyright Copyright © 2012 Yii Software LLC -rem @license http://www.yiiframework.com/license/ -rem ------------------------------------------------------------- - -@setlocal - -set YII_PATH=%~dp0 - -if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe - -"%PHP_COMMAND%" "%YII_PATH%yii" %* - -@endlocal diff --git a/apps/basic/views/layouts/main.php b/apps/basic/views/layouts/main.php deleted file mode 100644 index b9dcfb9..0000000 --- a/apps/basic/views/layouts/main.php +++ /dev/null @@ -1,69 +0,0 @@ - -beginPage() ?> - - - - - - - <?= Html::encode($this->title) ?> - head() ?> - - - -beginBody() ?> -
- 'My Company', - 'brandUrl' => Yii::$app->homeUrl, - 'options' => [ - 'class' => 'navbar-inverse navbar-fixed-top', - ], - ]); - echo Nav::widget([ - 'options' => ['class' => 'navbar-nav navbar-right'], - 'items' => [ - ['label' => 'Home', 'url' => ['/site/index']], - ['label' => 'About', 'url' => ['/site/about']], - ['label' => 'Contact', 'url' => ['/site/contact']], - Yii::$app->user->isGuest ? - ['label' => 'Login', 'url' => ['/site/login']] : - ['label' => 'Logout (' . Yii::$app->user->identity->username . ')', - 'url' => ['/site/logout'], - 'linkOptions' => ['data-method' => 'post']], - ], - ]); - NavBar::end(); - ?> - -
- isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [], - ]) ?> - -
-
- -
-
-

© My Company

-

-
-
- -endBody() ?> - - -endPage() ?> diff --git a/apps/basic/views/site/about.php b/apps/basic/views/site/about.php deleted file mode 100644 index 13d85a6..0000000 --- a/apps/basic/views/site/about.php +++ /dev/null @@ -1,16 +0,0 @@ -title = 'About'; -$this->params['breadcrumbs'][] = $this->title; -?> -
-

title) ?>

- -

- This is the About page. You may modify the following file to customize its content: -

- - -
diff --git a/apps/basic/views/site/contact.php b/apps/basic/views/site/contact.php deleted file mode 100644 index fad2d7c..0000000 --- a/apps/basic/views/site/contact.php +++ /dev/null @@ -1,57 +0,0 @@ -title = 'Contact'; -$this->params['breadcrumbs'][] = $this->title; -?> -
-

title) ?>

- - session->hasFlash('contactFormSubmitted')): ?> - -
- Thank you for contacting us. We will respond to you as soon as possible. -
- -

- Note that if you turn on the Yii debugger, you should be able - to view the mail message on the mail panel of the debugger. - mailer->useFileTransport): ?> - Because the application is in development mode, the email is not sent but saved as - a file under mailer->fileTransportPath) ?>. - Please configure the useFileTransport property of the mail - application component to be false to enable email sending. - -

- - - -

- If you have business inquiries or other questions, please fill out the following form to contact us. Thank you. -

- -
-
- 'contact-form']); ?> - field($model, 'name') ?> - field($model, 'email') ?> - field($model, 'subject') ?> - field($model, 'body')->textArea(['rows' => 6]) ?> - field($model, 'verifyCode')->widget(Captcha::className(), [ - 'template' => '
{image}
{input}
', - ]) ?> -
- 'btn btn-primary', 'name' => 'contact-button']) ?> -
- -
-
- - -
diff --git a/apps/basic/views/site/error.php b/apps/basic/views/site/error.php deleted file mode 100644 index b9812c4..0000000 --- a/apps/basic/views/site/error.php +++ /dev/null @@ -1,27 +0,0 @@ -title = $name; -?> -
- -

title) ?>

- -
- -
- -

- The above error occurred while the Web server was processing your request. -

-

- Please contact us if you think this is a server error. Thank you. -

- -
diff --git a/apps/basic/views/site/index.php b/apps/basic/views/site/index.php deleted file mode 100644 index a00ee4d..0000000 --- a/apps/basic/views/site/index.php +++ /dev/null @@ -1,51 +0,0 @@ -title = 'My Yii Application'; -?> -
- -
-

Congratulations!

- -

You have successfully created your Yii-powered application.

- -

Get started with Yii

-
- -
- -
-
-

Heading

- -

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et - dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip - ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu - fugiat nulla pariatur.

- -

Yii Documentation »

-
-
-

Heading

- -

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et - dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip - ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu - fugiat nulla pariatur.

- -

Yii Forum »

-
-
-

Heading

- -

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et - dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip - ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu - fugiat nulla pariatur.

- -

Yii Extensions »

-
-
- -
-
diff --git a/apps/basic/views/site/login.php b/apps/basic/views/site/login.php deleted file mode 100644 index df0c812..0000000 --- a/apps/basic/views/site/login.php +++ /dev/null @@ -1,46 +0,0 @@ -title = 'Login'; -$this->params['breadcrumbs'][] = $this->title; -?> - diff --git a/apps/basic/web/assets/.gitignore b/apps/basic/web/assets/.gitignore deleted file mode 100644 index c96a04f..0000000 --- a/apps/basic/web/assets/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/apps/basic/web/css/site.css b/apps/basic/web/css/site.css deleted file mode 100644 index 698be70..0000000 --- a/apps/basic/web/css/site.css +++ /dev/null @@ -1,91 +0,0 @@ -html, -body { - height: 100%; -} - -.wrap { - min-height: 100%; - height: auto; - margin: 0 auto -60px; - padding: 0 0 60px; -} - -.wrap > .container { - padding: 70px 15px 20px; -} - -.footer { - height: 60px; - background-color: #f5f5f5; - border-top: 1px solid #ddd; - padding-top: 20px; -} - -.jumbotron { - text-align: center; - background-color: transparent; -} - -.jumbotron .btn { - font-size: 21px; - padding: 14px 24px; -} - -.not-set { - color: #c55; - font-style: italic; -} - -/* add sorting icons to gridview sort links */ -a.asc:after, a.desc:after { - position: relative; - top: 1px; - display: inline-block; - font-family: 'Glyphicons Halflings'; - font-style: normal; - font-weight: normal; - line-height: 1; - padding-left: 5px; -} - -a.asc:after { - content: /*"\e113"*/ "\e151"; -} - -a.desc:after { - content: /*"\e114"*/ "\e152"; -} - -.sort-numerical a.asc:after { - content: "\e153"; -} - -.sort-numerical a.desc:after { - content: "\e154"; -} - -.sort-ordinal a.asc:after { - content: "\e155"; -} - -.sort-ordinal a.desc:after { - content: "\e156"; -} - -.grid-view th { - white-space: nowrap; -} - -.hint-block { - display: block; - margin-top: 5px; - color: #999; -} - -.error-summary { - color: #a94442; - background: #fdf7f7; - border-left: 3px solid #eed3d7; - padding: 10px 20px; - margin: 0 0 15px 0; -} diff --git a/apps/basic/web/favicon.ico b/apps/basic/web/favicon.ico deleted file mode 100644 index 580ed73..0000000 Binary files a/apps/basic/web/favicon.ico and /dev/null differ diff --git a/apps/basic/web/index-test.php b/apps/basic/web/index-test.php deleted file mode 100644 index 326608d..0000000 --- a/apps/basic/web/index-test.php +++ /dev/null @@ -1,16 +0,0 @@ -run(); diff --git a/apps/basic/web/index.php b/apps/basic/web/index.php deleted file mode 100644 index d1e070a..0000000 --- a/apps/basic/web/index.php +++ /dev/null @@ -1,12 +0,0 @@ -run(); diff --git a/apps/basic/web/robots.txt b/apps/basic/web/robots.txt deleted file mode 100644 index 6f27bb6..0000000 --- a/apps/basic/web/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-agent: * -Disallow: \ No newline at end of file diff --git a/apps/basic/yii b/apps/basic/yii deleted file mode 100755 index b032ebd..0000000 --- a/apps/basic/yii +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env php -run(); -exit($exitCode); diff --git a/apps/basic/yii.bat b/apps/basic/yii.bat deleted file mode 100644 index 5e21e2e..0000000 --- a/apps/basic/yii.bat +++ /dev/null @@ -1,20 +0,0 @@ -@echo off - -rem ------------------------------------------------------------- -rem Yii command line bootstrap script for Windows. -rem -rem @author Qiang Xue -rem @link http://www.yiiframework.com/ -rem @copyright Copyright © 2012 Yii Software LLC -rem @license http://www.yiiframework.com/license/ -rem ------------------------------------------------------------- - -@setlocal - -set YII_PATH=%~dp0 - -if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe - -"%PHP_COMMAND%" "%YII_PATH%yii" %* - -@endlocal diff --git a/apps/benchmark/LICENSE.md b/apps/benchmark/LICENSE.md deleted file mode 100644 index e98f03d..0000000 --- a/apps/benchmark/LICENSE.md +++ /dev/null @@ -1,32 +0,0 @@ -The Yii framework is free software. It is released under the terms of -the following BSD License. - -Copyright © 2008 by Yii Software LLC (http://www.yiisoft.com) -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - * Neither the name of Yii Software LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. diff --git a/apps/benchmark/README.md b/apps/benchmark/README.md deleted file mode 100644 index 27f598a..0000000 --- a/apps/benchmark/README.md +++ /dev/null @@ -1,58 +0,0 @@ -Yii 2 Benchmark Application -=========================== - -**NOTE** Yii 2 and the relevant applications and extensions are still under heavy -development. We may make significant changes without prior notices. Please do not -use them for production. Please consider using [Yii v1.1](https://github.com/yiisoft/yii) -if you have a project to be deployed for production soon. - - -Yii 2 Benchmark Application is an application built to demonstrate the minimal overhead -introduced by the Yii framework. The application contains a single page which only renders -the "hello world" string. - -The application attempts to simulate the scenario in which you can achieve the best performance -when using Yii. It does so by assuming that both of the main application configuration and the page -content are cached in memory, and the application enables pretty URLs. - - -DIRECTORY STRUCTURE -------------------- - - protected/ contains application source code - controllers/ contains Web controller classes - index.php the entry script - - -REQUIREMENTS ------------- - -The minimum requirement by Yii is that your Web server supports PHP 5.4.0. - - -INSTALLATION ------------- - -If you do not have [Composer](http://getcomposer.org/), you may download it from -[http://getcomposer.org/](http://getcomposer.org/) or run the following command on Linux/Unix/MacOS: - -~~~ -curl -s http://getcomposer.org/installer | php -~~~ - -You can then install the Bootstrap Application using the following command: - -~~~ -php composer.phar create-project --prefer-dist --stability=dev yiisoft/yii2-app-benchmark yii-benchmark -~~~ - -Now you should be able to access the benchmark page using the URL - -~~~ -http://localhost/yii-benchmark/index.php/site/hello -~~~ - -In the above, we assume `yii-benchmark` is directly under the document root of your Web server. - -Note that in order to install some dependencies you must have `php_openssl` extension enabled. - diff --git a/apps/benchmark/composer.json b/apps/benchmark/composer.json deleted file mode 100644 index c8ed589..0000000 --- a/apps/benchmark/composer.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "yiisoft/yii2-app-benchmark", - "description": "Yii 2 Benchmark Application", - "keywords": ["yii2", "framework", "benchmark", "application"], - "homepage": "http://www.yiiframework.com/", - "type": "project", - "license": "BSD-3-Clause", - "support": { - "issues": "https://github.com/yiisoft/yii2/issues?state=open", - "forum": "http://www.yiiframework.com/forum/", - "wiki": "http://www.yiiframework.com/wiki/", - "irc": "irc://irc.freenode.net/yii", - "source": "https://github.com/yiisoft/yii2" - }, - "config": { - "vendor-dir": "protected/vendor" - }, - "minimum-stability": "dev", - "require": { - "php": ">=5.4.0", - "yiisoft/yii2": "*" - } -} diff --git a/apps/benchmark/index.php b/apps/benchmark/index.php deleted file mode 100644 index c278f1d..0000000 --- a/apps/benchmark/index.php +++ /dev/null @@ -1,18 +0,0 @@ - 'benchmark', - 'basePath' => __DIR__ . '/protected', - 'components' => [ - 'urlManager' => [ - 'enablePrettyUrl' => true, - ], - ], -]; - -$application = new yii\web\Application($config); -$application->run(); diff --git a/apps/benchmark/protected/.htaccess b/apps/benchmark/protected/.htaccess deleted file mode 100644 index 8d2f256..0000000 --- a/apps/benchmark/protected/.htaccess +++ /dev/null @@ -1 +0,0 @@ -deny from all diff --git a/apps/benchmark/protected/controllers/SiteController.php b/apps/benchmark/protected/controllers/SiteController.php deleted file mode 100644 index 9b08da8..0000000 --- a/apps/benchmark/protected/controllers/SiteController.php +++ /dev/null @@ -1,15 +0,0 @@ - - * @since 2.0 - */ -class AppController extends Controller -{ - public $defaultAction = 'link'; - - /** - * Properly removes symlinked directory under Windows, MacOS and Linux - * - * @param string $file path to symlink - */ - protected function unlink($file) - { - if (is_dir($file) && DIRECTORY_SEPARATOR === '\\') { - rmdir($file); - } else { - unlink($file); - } - } - - /** - * This command runs the following shell commands in the dev repo root: - * - * - Run `composer update` - * - `rm -rf apps/basic/vendor/yiisoft/yii2` - * - `rm -rf apps/basic/vendor/yiisoft/yii2-*` - * - * And replaces them with symbolic links to the extensions and framework path in the dev repo. - * @param string $app the application name `basic` or `advanced`. - */ - public function actionLink($app) - { - // root of the dev repo - $base = dirname(dirname(__DIR__)); - $appDir = "$base/apps/$app"; - - // cleanup - if (is_link($link = "$appDir/vendor/yiisoft/yii2")) { - $this->stdout("Removing symlink $link.\n"); - $this->unlink($link); - } - $extensions = $this->findDirs("$appDir/vendor/yiisoft"); - foreach($extensions as $ext) { - if (is_link($link = "$appDir/vendor/yiisoft/yii2-$ext")) { - $this->stdout("Removing symlink $link.\n"); - $this->unlink($link); - } - } - - // composer update - chdir($appDir); - passthru('composer update --prefer-dist'); - - // link directories - if (is_dir($link = "$appDir/vendor/yiisoft/yii2")) { - $this->stdout("Removing dir $link.\n"); - FileHelper::removeDirectory($link); - $this->stdout("Creating symlink for $link.\n"); - symlink("$base/framework", $link); - } - $extensions = $this->findDirs("$appDir/vendor/yiisoft"); - foreach($extensions as $ext) { - if (is_dir($link = "$appDir/vendor/yiisoft/yii2-$ext")) { - $this->stdout("Removing dir $link.\n"); - FileHelper::removeDirectory($link); - $this->stdout("Creating symlink for $link.\n"); - symlink("$base/extensions/$ext", $link); - } - } - - $this->stdout("done.\n"); - } - - /** - * Finds linkable applications - * - * @param string $dir directory to search in - * @return array list of applications command can link - */ - protected function findDirs($dir) - { - $list = []; - $handle = @opendir($dir); - if ($handle === false) { - return []; - } - while (($file = readdir($handle)) !== false) { - if ($file === '.' || $file === '..') { - continue; - } - $path = $dir . DIRECTORY_SEPARATOR . $file; - if (is_dir($path) && preg_match('/^yii2-(.*)$/', $file, $matches)) { - $list[] = $matches[1]; - } - } - closedir($handle); - - foreach($list as $i => $e) { - if ($e == 'composer') { // skip composer to not break composer update - unset($list[$i]); - } - } - - return $list; - } -} diff --git a/build/controllers/ClassmapController.php b/build/controllers/ClassmapController.php index e88bdb0..a88e6cd 100644 --- a/build/controllers/ClassmapController.php +++ b/build/controllers/ClassmapController.php @@ -51,6 +51,7 @@ class ClassmapController extends Controller '/Yii.php', '/BaseYii.php', '/console/', + '/requirements/', ], ]; $files = FileHelper::findFiles($root, $options); diff --git a/build/controllers/DevController.php b/build/controllers/DevController.php new file mode 100644 index 0000000..b15b9a9 --- /dev/null +++ b/build/controllers/DevController.php @@ -0,0 +1,320 @@ + + * @since 2.0 + */ +class DevController extends Controller +{ + public $defaultAction = 'all'; + + public $apps = [ + 'basic' => 'git@github.com:yiisoft/yii2-app-basic.git', + 'advanced' => 'git@github.com:yiisoft/yii2-app-advanced.git', + ]; + + public $extensions = [ + 'apidoc' => 'git@github.com:yiisoft/yii2-apidoc.git', + 'authclient' => 'git@github.com:yiisoft/yii2-authclient.git', + 'bootstrap' => 'git@github.com:yiisoft/yii2-bootstrap.git', + 'codeception' => 'git@github.com:yiisoft/yii2-codeception.git', + 'composer' => 'git@github.com:yiisoft/yii2-composer.git', + 'debug' => 'git@github.com:yiisoft/yii2-debug.git', + 'elasticsearch' => 'git@github.com:yiisoft/yii2-elasticsearch.git', + 'faker' => 'git@github.com:yiisoft/yii2-faker.git', + 'gii' => 'git@github.com:yiisoft/yii2-gii.git', + 'imagine' => 'git@github.com:yiisoft/yii2-imagine.git', + 'jui' => 'git@github.com:yiisoft/yii2-jui.git', + 'mongodb' => 'git@github.com:yiisoft/yii2-mongodb.git', + 'redis' => 'git@github.com:yiisoft/yii2-redis.git', + 'smarty' => 'git@github.com:yiisoft/yii2-smarty.git', + 'sphinx' => 'git@github.com:yiisoft/yii2-sphinx.git', + 'swiftmailer' => 'git@github.com:yiisoft/yii2-swiftmailer.git', + 'twig' => 'git@github.com:yiisoft/yii2-twig.git', + ]; + + + /** + * Install all extensions and advanced + basic app + */ + public function actionAll() + { + if (!$this->confirm('Install all applications and all extensions now?')) { + return 1; + } + + foreach($this->extensions as $ext => $repo) { + $ret = $this->actionExt($ext, $repo); + if ($ret !== 0) { + return $ret; + } + } + + foreach($this->apps as $app => $repo) { + $ret = $this->actionApp($app, $repo); + if ($ret !== 0) { + return $ret; + } + } + + return 0; + } + + /** + * Runs a command in all extension and application directories + * + * Can be used to run e.g. `git pull`. + * + * ./build/build dev/run git pull + * + * @param string $command the command to run + */ + public function actionRun($command) + { + $command = implode(' ', func_get_args()); + + // root of the dev repo + $base = dirname(dirname(__DIR__)); + $dirs = $this->listSubDirs("$base/extensions"); + $dirs = array_merge($dirs, $this->listSubDirs("$base/apps")); + asort($dirs); + + foreach($dirs as $dir) { + $displayDir = substr($dir, strlen($base)); + $this->stdout("Running '$command' in $displayDir...\n", Console::BOLD); + passthru($command); + $this->stdout("done.\n", Console::BOLD, Console::FG_GREEN); + } + } + + /** + * This command installs an application template in the `apps` directory and links the framework and extensions + * + * It basically runs the following commands in the dev repo root: + * + * - Run `composer update` + * - `rm -rf apps/basic/vendor/yiisoft/yii2` + * - `rm -rf apps/basic/vendor/yiisoft/yii2-*` + * + * And replaces them with symbolic links to the extensions and framework path in the dev repo. + * + * Extensions required by the application are automatically installed using the `ext` action. + * + * @param string $app the application name e.g. `basic` or `advanced`. + * @param string $repo url of the git repo to clone if it does not already exist. + */ + public function actionApp($app, $repo = null) + { + // root of the dev repo + $base = dirname(dirname(__DIR__)); + $appDir = "$base/apps/$app"; + + if (!file_exists($appDir)) { + if (empty($repo)) { + if (isset($this->apps[$app])) { + $repo = $this->apps[$app]; + } else { + $this->stderr("Repo argument is required for app '$app'.\n", Console::FG_RED); + return 1; + } + } + + $this->stdout("cloning application repo '$app' from '$repo'...\n", Console::BOLD); + passthru('git clone ' . escapeshellarg($repo) . ' ' . $appDir); + $this->stdout("done.\n", Console::BOLD, Console::FG_GREEN); + } + + // cleanup + $this->stdout("cleaning up application '$app' vendor directory...\n", Console::BOLD); + $this->cleanupVendorDir($appDir); + $this->stdout("done.\n", Console::BOLD, Console::FG_GREEN); + + // composer update + $this->stdout("updating composer for app '$app'...\n", Console::BOLD); + chdir($appDir); + passthru('composer update --prefer-dist'); + $this->stdout("done.\n", Console::BOLD, Console::FG_GREEN); + + // link directories + $this->stdout("linking framework and extensions to '$app' app vendor dir...\n", Console::BOLD); + $this->linkFrameworkAndExtensions($appDir, $base); + $this->stdout("done.\n", Console::BOLD, Console::FG_GREEN); + + return 0; + } + + /** + * This command installs an extension in the `extensions` directory and links the framework and other extensions + * + * @param string $extension the application name e.g. `basic` or `advanced`. + * @param string $repo url of the git repo to clone if it does not already exist. + */ + public function actionExt($extension, $repo = null) + { + // root of the dev repo + $base = dirname(dirname(__DIR__)); + $extensionDir = "$base/extensions/$extension"; + + if (!file_exists($extensionDir)) { + if (empty($repo)) { + if (isset($this->extensions[$extension])) { + $repo = $this->extensions[$extension]; + } else { + $this->stderr("Repo argument is required for extension '$extension'.\n", Console::FG_RED); + return 1; + } + } + + $this->stdout("cloning extension repo '$extension' from '$repo'...\n", Console::BOLD); + passthru('git clone ' . escapeshellarg($repo) . ' ' . $extensionDir); + $this->stdout("done.\n", Console::BOLD, Console::FG_GREEN); + } + + // cleanup + $this->stdout("cleaning up extension '$extension' vendor directory...\n", Console::BOLD); + $this->cleanupVendorDir($extensionDir); + $this->stdout("done.\n", Console::BOLD, Console::FG_GREEN); + + // composer update + $this->stdout("updating composer for extension '$extension'...\n", Console::BOLD); + chdir($extensionDir); + passthru('composer update --prefer-dist'); + $this->stdout("done.\n", Console::BOLD, Console::FG_GREEN); + + // link directories + $this->stdout("linking framework and extensions to '$extension' vendor dir...\n", Console::BOLD); + $this->linkFrameworkAndExtensions($extensionDir, $base); + $this->stdout("done.\n", Console::BOLD, Console::FG_GREEN); + + return 0; + } + + + protected function cleanupVendorDir($dir) + { + if (is_link($link = "$dir/vendor/yiisoft/yii2")) { + $this->stdout("Removing symlink $link.\n"); + $this->unlink($link); + } + $extensions = $this->findDirs("$dir/vendor/yiisoft"); + foreach($extensions as $ext) { + if (is_link($link = "$dir/vendor/yiisoft/yii2-$ext")) { + $this->stdout("Removing symlink $link.\n"); + $this->unlink($link); + } + } + } + + protected function linkFrameworkAndExtensions($dir, $base) + { + if (is_dir($link = "$dir/vendor/yiisoft/yii2")) { + $this->stdout("Removing dir $link.\n"); + FileHelper::removeDirectory($link); + $this->stdout("Creating symlink for $link.\n"); + symlink("$base/framework", $link); + } + $extensions = $this->findDirs("$dir/vendor/yiisoft"); + foreach($extensions as $ext) { + if (is_dir($link = "$dir/vendor/yiisoft/yii2-$ext")) { + $this->stdout("Removing dir $link.\n"); + FileHelper::removeDirectory($link); + $this->stdout("Creating symlink for $link.\n"); + if (!file_exists("$base/extensions/$ext")) { + $ret = $this->actionExt($ext); + if ($ret !== 0) { + return $ret; + } + } + symlink("$base/extensions/$ext", $link); + } + } + } + + /** + * Properly removes symlinked directory under Windows, MacOS and Linux + * + * @param string $file path to symlink + */ + protected function unlink($file) + { + if (is_dir($file) && DIRECTORY_SEPARATOR === '\\') { + rmdir($file); + } else { + unlink($file); + } + } + + protected function listSubDirs($dir) + { + $list = []; + $handle = opendir($dir); + if ($handle === false) { + throw new InvalidParamException("Unable to open directory: $dir"); + } + while (($file = readdir($handle)) !== false) { + if ($file === '.' || $file === '..') { + continue; + } + // ignore hidden directories + if ($file[0] === '.') { + continue; + } + if (is_dir("$dir/$file")) { + $list[] = "$dir/$file"; + } + } + closedir($handle); + return $list; + } + + /** + * Finds linkable applications + * + * @param string $dir directory to search in + * @return array list of applications command can link + */ + protected function findDirs($dir) + { + $list = []; + $handle = @opendir($dir); + if ($handle === false) { + return []; + } + while (($file = readdir($handle)) !== false) { + if ($file === '.' || $file === '..') { + continue; + } + $path = $dir . DIRECTORY_SEPARATOR . $file; + if (is_dir($path) && preg_match('/^yii2-(.*)$/', $file, $matches)) { + $list[] = $matches[1]; + } + } + closedir($handle); + + foreach($list as $i => $e) { + if ($e == 'composer') { // skip composer to not break composer update + unset($list[$i]); + } + } + + return $list; + } +} diff --git a/build/controllers/PhpDocController.php b/build/controllers/PhpDocController.php index f085c51..c0b390c 100644 --- a/build/controllers/PhpDocController.php +++ b/build/controllers/PhpDocController.php @@ -103,9 +103,9 @@ class PhpDocController extends Controller /** * @inheritdoc */ - public function options($actionId) + public function options($actionID) { - return array_merge(parent::options($actionId), ['updateFiles']); + return array_merge(parent::options($actionID), ['updateFiles']); } protected function findFiles($root) diff --git a/build/controllers/ReleaseController.php b/build/controllers/ReleaseController.php index ffe19ec..6e5f65f 100644 --- a/build/controllers/ReleaseController.php +++ b/build/controllers/ReleaseController.php @@ -8,6 +8,7 @@ namespace yii\build\controllers; use Yii; +use yii\base\Exception; use yii\console\Controller; /** @@ -30,6 +31,8 @@ class ReleaseController extends Controller */ public function actionPrepare($version) { + $this->resortChangelogs($version); + $this->mergeChangelogs($version); $this->closeChangelogs($version); $this->composerSetStability($version); $this->updateYiiVersion($version); @@ -77,9 +80,95 @@ class ReleaseController extends Controller } } + protected function resortChangelogs($version) + { + foreach($this->getChangelogs() as $file) { + // split the file into relevant parts + list($start, $changelog, $end) = $this->splitChangelog($file, $version); + $changelog = $this->resortChangelog($changelog); + file_put_contents($file, implode("\n", array_merge($start, $changelog, $end))); + } + } + + protected function mergeChangelogs($version) + { + $file = $this->getFrameworkChangelog(); + // split the file into relevant parts + list($start, $changelog, $end) = $this->splitChangelog($file, $version); + + $changelog = $this->resortChangelog($changelog); + + $changelog[] = ''; + $extensions = $this->getExtensionChangelogs(); + asort($extensions); + foreach($extensions as $changelogFile) { + if (!preg_match('~extensions/([a-z]+)/CHANGELOG\\.md~', $changelogFile, $m)) { + throw new Exception("Illegal extension changelog file: " . $changelogFile); + } + list( , $extensionChangelog, ) = $this->splitChangelog($changelogFile, $version); + $name = $m[1]; + $ucname = ucfirst($name); + $changelog[] = "### $ucname Extension (yii2-$name)"; + $changelog = array_merge($changelog, $extensionChangelog); + } + + file_put_contents($file, implode("\n", array_merge($start, $changelog, $end))); + } + + /** + * Extract changelog content for a specific version + */ + protected function splitChangelog($file, $version) + { + $lines = explode("\n", file_get_contents($file)); + + // split the file into relevant parts + $start = []; + $changelog = []; + $end = []; + + $state = 'start'; + foreach($lines as $l => $line) { + // starting from the changelogs headline + if (isset($lines[$l-2]) && strpos($lines[$l-2], $version) !== false && + isset($lines[$l-1]) && strncmp($lines[$l-1], '---', 3) === 0) { + $state = 'changelog'; + } + if ($state === 'changelog' && isset($lines[$l+1]) && strncmp($lines[$l+1], '---', 3) === 0) { + $state = 'end'; + } + ${$state}[] = $line; + } + return [$start, $changelog, $end]; + } + + /** + * Ensure sorting of the changelog lines + */ + protected function resortChangelog($changelog) + { + // cleanup whitespace + foreach($changelog as $i => $line) { + $changelog[$i] = rtrim($line); + } + + // TODO sorting + return $changelog; + } + protected function getChangelogs() { - return array_merge([YII2_PATH . '/CHANGELOG.md'], glob(dirname(YII2_PATH) . '/extensions/*/CHANGELOG.md')); + return array_merge([$this->getFrameworkChangelog()], $this->getExtensionChangelogs()); + } + + protected function getFrameworkChangelog() + { + return YII2_PATH . '/CHANGELOG.md'; + } + + protected function getExtensionChangelogs() + { + return glob(dirname(YII2_PATH) . '/extensions/*/CHANGELOG.md'); } protected function composerSetStability($version) diff --git a/build/controllers/TranslationController.php b/build/controllers/TranslationController.php index d510de4..75a4d7d 100644 --- a/build/controllers/TranslationController.php +++ b/build/controllers/TranslationController.php @@ -128,14 +128,11 @@ class TranslationController extends Controller foreach ($lines as $key => $val) { if (mb_substr($val, 0, 1, 'utf-8') === '@') { $lines[$key] = '' . Html::encode($val) . ''; - } - else if (mb_substr($val, 0, 1, 'utf-8') === '+') { + } elseif (mb_substr($val, 0, 1, 'utf-8') === '+') { $lines[$key] = '' . Html::encode($val) . ''; - } - else if (mb_substr($val, 0, 1, 'utf-8') === '-') { + } elseif (mb_substr($val, 0, 1, 'utf-8') === '-') { $lines[$key] = '' . Html::encode($val) . ''; - } - else { + } else { $lines[$key] = Html::encode($val); } } diff --git a/build/controllers/views/translation/report_html.php b/build/controllers/views/translation/report_html.php index 8a58bfd..c12a4d6 100644 --- a/build/controllers/views/translation/report_html.php +++ b/build/controllers/views/translation/report_html.php @@ -1,5 +1,7 @@ @@ -27,21 +29,21 @@ use yii\helpers\Html; -

+

    -
  • Source:
  • -
  • Translation:
  • +
  • Source:
  • +
  • Translation:
- $result):?> -

- -

+ $result): ?> +

+ +

- -
context->highlightDiff($result['diff'])?>
- + +
context->highlightDiff($result['diff']) ?>
+ \ No newline at end of file diff --git a/composer.json b/composer.json index 21f5992..70f3362 100644 --- a/composer.json +++ b/composer.json @@ -1,128 +1,109 @@ { - "name": "yiisoft/yii2-dev", - "description": "Yii PHP Framework Version 2 - Development Package", - "keywords": ["yii2", "framework"], - "homepage": "http://www.yiiframework.com/", - "type": "yii2-extension", - "license": "BSD-3-Clause", - "authors": [ - { - "name": "Qiang Xue", - "email": "qiang.xue@gmail.com", - "homepage": "http://www.yiiframework.com/", - "role": "Founder and project lead" - }, - { - "name": "Alexander Makarov", - "email": "sam@rmcreative.ru", - "homepage": "http://rmcreative.ru/", - "role": "Core framework development" - }, - { - "name": "Maurizio Domba", - "homepage": "http://mdomba.info/", - "role": "Core framework development" - }, - { - "name": "Carsten Brandt", - "email": "mail@cebe.cc", - "homepage": "http://cebe.cc/", - "role": "Core framework development" - }, - { - "name": "Timur Ruziev", - "email": "resurtm@gmail.com", - "homepage": "http://resurtm.com/", - "role": "Core framework development" - }, - { - "name": "Paul Klimov", - "email": "klimov.paul@gmail.com", - "role": "Core framework development" - } - ], - "support": { - "issues": "https://github.com/yiisoft/yii2/issues?state=open", - "forum": "http://www.yiiframework.com/forum/", - "wiki": "http://www.yiiframework.com/wiki/", - "irc": "irc://irc.freenode.net/yii", - "source": "https://github.com/yiisoft/yii2" - }, - "minimum-stability": "dev", - "replace": { - "yiisoft/yii2-apidoc": "self.version", - "yiisoft/yii2-authclient": "self.version", - "yiisoft/yii2-bootstrap": "self.version", - "yiisoft/yii2-codeception": "self.version", - "yiisoft/yii2-debug": "self.version", - "yiisoft/yii2-elasticsearch": "self.version", - "yiisoft/yii2-faker": "self.version", - "yiisoft/yii2-imagine": "self.version", - "yiisoft/yii2-gii": "self.version", - "yiisoft/yii2-jui": "self.version", - "yiisoft/yii2-mongodb": "self.version", - "yiisoft/yii2-redis": "self.version", - "yiisoft/yii2-smarty": "self.version", - "yiisoft/yii2-swiftmailer": "self.version", - "yiisoft/yii2-sphinx": "self.version", - "yiisoft/yii2-twig": "self.version", - "yiisoft/yii2": "self.version" - }, - "require": { - "php": ">=5.4.0", - "ext-mbstring": "*", - "lib-pcre": "*", - "yiisoft/yii2-composer": "*", - "yiisoft/jquery": "~2.0 | ~1.10", - "yiisoft/jquery-pjax": "*", - "ezyang/htmlpurifier": "4.6.*", - "cebe/markdown": "0.9.*" - }, - "require-dev": { - "phpunit/phpunit": "3.7.*", - "twig/twig": "*", - "smarty/smarty": "*", - "imagine/imagine": "v0.5.0", - "swiftmailer/swiftmailer": "*", - "cebe/indent": "*" - }, - "suggest": { - "phpdocumentor/reflection": "required by yii2-apidoc extension", - "twbs/bootstrap": "required by yii2-bootstrap, yii2-debug, yii2-gii extension", - "ext-curl": "required by yii2-elasticsearch extension", - "ext-mongo": "required by yii2-mongo extension", - "ext-pdo": "required by yii2-sphinx extension", - "ext-pdo_mysql": "required by yii2-sphinx extension", - "fzaninotto/faker": "required by yii2-faker extension", - "imagine/imagine": "required by yii2-imagine extension", - "phpspec/php-diff": "required by yii2-gii extension", - "smarty/smarty": "required by yii2-smarty extension", - "swiftmailer/swiftmailer": "required by yii2-swiftmailer extension", - "twig/twig": "required by yii2-twig extension", - "yiisoft/yii2-coding-standards": "you can use this package to check for code style issues when contributing to yii" - }, - "autoload": { - "psr-4": { - "yii\\": "framework/", - "yii\\apidoc\\": "extensions/apidoc/", - "yii\\authclient\\": "extensions/authclient/", - "yii\\bootstrap\\": "extensions/bootstrap/", - "yii\\codeception\\": "extensions/codeception/", - "yii\\debug\\": "extensions/debug/", - "yii\\elasticsearch\\": "extensions/elasticsearch/", - "yii\\faker\\": "extensions/faker/", - "yii\\gii\\": "extensions/gii/", - "yii\\imagine\\" : "extensions/imagine/", - "yii\\jui\\": "extensions/jui/", - "yii\\mongodb\\": "extensions/mongodb/", - "yii\\redis\\": "extensions/redis/", - "yii\\smarty\\": "extensions/smarty/", - "yii\\swiftmailer\\": "extensions/swiftmailer/", - "yii\\sphinx\\": "extensions/sphinx/", - "yii\\twig\\": "extensions/twig/" - } - }, - "bin": [ - "framework/yii" - ] + "name": "yiisoft/yii2-dev", + "description": "Yii PHP Framework Version 2 - Development Package", + "keywords": [ + "yii2", + "framework" + ], + "homepage": "http://www.yiiframework.com/", + "type": "yii2-extension", + "license": "BSD-3-Clause", + "authors": [ + { + "name": "Qiang Xue", + "email": "qiang.xue@gmail.com", + "homepage": "http://www.yiiframework.com/", + "role": "Founder and project lead" + }, + { + "name": "Alexander Makarov", + "email": "sam@rmcreative.ru", + "homepage": "http://rmcreative.ru/", + "role": "Core framework development" + }, + { + "name": "Maurizio Domba", + "homepage": "http://mdomba.info/", + "role": "Core framework development" + }, + { + "name": "Carsten Brandt", + "email": "mail@cebe.cc", + "homepage": "http://cebe.cc/", + "role": "Core framework development" + }, + { + "name": "Timur Ruziev", + "email": "resurtm@gmail.com", + "homepage": "http://resurtm.com/", + "role": "Core framework development" + }, + { + "name": "Paul Klimov", + "email": "klimov.paul@gmail.com", + "role": "Core framework development" + } + ], + "support": { + "issues": "https://github.com/yiisoft/yii2/issues?state=open", + "forum": "http://www.yiiframework.com/forum/", + "wiki": "http://www.yiiframework.com/wiki/", + "irc": "irc://irc.freenode.net/yii", + "source": "https://github.com/yiisoft/yii2" + }, + "minimum-stability": "dev", + "require": { + "php": ">=5.4.0", + "ext-mbstring": "*", + "lib-pcre": "*", + "ezyang/htmlpurifier": "4.6.*", + "cebe/markdown": "~1.0.0 | ~1.1.0", + "bower-asset/jquery": "2.1.*@stable | 1.11.*@stable", + "bower-asset/jquery.inputmask": "3.1.*", + "bower-asset/punycode": "1.3.*", + "bower-asset/yii2-pjax": "2.0.*", + "bower-asset/bootstrap": "3.3.* | 3.2.* | 3.1.*", + "bower-asset/jquery-ui": "1.11.*@stable", + "bower-asset/typeahead.js": "0.10.*" + }, + "require-dev": { + "phpunit/phpunit": "~4.5", + "twig/twig": "*", + "smarty/smarty": "~3.1", + "imagine/imagine": "0.5.*", + "swiftmailer/swiftmailer": "*", + "fzaninotto/faker": "*", + "cebe/indent": "*" + }, + "suggest": { + "phpdocumentor/reflection": "required by yii2-apidoc extension", + "ext-curl": "required by yii2-elasticsearch extension", + "ext-mongo": "required by yii2-mongo extension", + "ext-pdo": "required by yii2-sphinx extension", + "ext-pdo_mysql": "required by yii2-sphinx extension", + "fzaninotto/faker": "required by yii2-faker extension", + "imagine/imagine": "required by yii2-imagine extension", + "phpspec/php-diff": "required by yii2-gii extension", + "smarty/smarty": "required by yii2-smarty extension", + "swiftmailer/swiftmailer": "required by yii2-swiftmailer extension", + "twig/twig": "required by yii2-twig extension", + "yiisoft/yii2-coding-standards": "you can use this package to check for code style issues when contributing to yii" + }, + "autoload": { + "psr-4": { + "yii\\": "framework/" + } + }, + "bin": [ + "framework/yii" + ], + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + }, + "asset-installer-paths": { + "npm-asset-library": "vendor/npm", + "bower-asset-library": "vendor/bower" + } + } } diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..8cccc8a --- /dev/null +++ b/composer.lock @@ -0,0 +1,1652 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "hash": "6f81c77925e8946ece8cd3a4d536f88c", + "packages": [ + { + "name": "bower-asset/bootstrap", + "version": "v3.3.4", + "source": { + "type": "git", + "url": "https://github.com/twbs/bootstrap.git", + "reference": "a10eb60bc0b07b747fa0c4ebd8821eb7307bd07f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twbs/bootstrap/zipball/a10eb60bc0b07b747fa0c4ebd8821eb7307bd07f", + "reference": "a10eb60bc0b07b747fa0c4ebd8821eb7307bd07f", + "shasum": "" + }, + "require": { + "bower-asset/jquery": ">=1.9.1" + }, + "type": "bower-asset-library", + "extra": { + "bower-asset-main": [ + "less/bootstrap.less", + "dist/css/bootstrap.css", + "dist/js/bootstrap.js", + "dist/fonts/glyphicons-halflings-regular.eot", + "dist/fonts/glyphicons-halflings-regular.svg", + "dist/fonts/glyphicons-halflings-regular.ttf", + "dist/fonts/glyphicons-halflings-regular.woff", + "dist/fonts/glyphicons-halflings-regular.woff2" + ], + "bower-asset-ignore": [ + "/.*", + "_config.yml", + "CNAME", + "composer.json", + "CONTRIBUTING.md", + "docs", + "js/tests", + "test-infra" + ] + }, + "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.", + "keywords": [ + "css", + "framework", + "front-end", + "js", + "less", + "mobile-first", + "responsive", + "web" + ] + }, + { + "name": "bower-asset/jquery", + "version": "2.1.3", + "source": { + "type": "git", + "url": "https://github.com/jquery/jquery.git", + "reference": "8f2a9d9272d6ed7f32d3a484740ab342c02541e0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jquery/jquery/zipball/8f2a9d9272d6ed7f32d3a484740ab342c02541e0", + "reference": "8f2a9d9272d6ed7f32d3a484740ab342c02541e0", + "shasum": "" + }, + "require-dev": { + "bower-asset/qunit": "1.14.0", + "bower-asset/requirejs": "2.1.10", + "bower-asset/sinon": "1.8.1", + "bower-asset/sizzle": "2.1.1-patch2" + }, + "type": "bower-asset-library", + "extra": { + "bower-asset-main": "dist/jquery.js", + "bower-asset-ignore": [ + "**/.*", + "build", + "speed", + "test", + "*.md", + "AUTHORS.txt", + "Gruntfile.js", + "package.json" + ] + }, + "license": [ + "MIT" + ], + "keywords": [ + "javascript", + "jquery", + "library" + ] + }, + { + "name": "bower-asset/jquery-ui", + "version": "1.11.4", + "source": { + "type": "git", + "url": "https://github.com/components/jqueryui.git", + "reference": "c34f8dbf3ba57b3784b93f26119f436c0e8288e1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/components/jqueryui/zipball/c34f8dbf3ba57b3784b93f26119f436c0e8288e1", + "reference": "c34f8dbf3ba57b3784b93f26119f436c0e8288e1", + "shasum": "" + }, + "require": { + "bower-asset/jquery": ">=1.6" + }, + "type": "bower-asset-library", + "extra": { + "bower-asset-main": [ + "jquery-ui.js" + ], + "bower-asset-ignore": [] + } + }, + { + "name": "bower-asset/jquery.inputmask", + "version": "3.1.61", + "source": { + "type": "git", + "url": "https://github.com/RobinHerbots/jquery.inputmask.git", + "reference": "f2c086411d2557fc485c47afb3cecfa6c1de9ee2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/RobinHerbots/jquery.inputmask/zipball/f2c086411d2557fc485c47afb3cecfa6c1de9ee2", + "reference": "f2c086411d2557fc485c47afb3cecfa6c1de9ee2", + "shasum": "" + }, + "require": { + "bower-asset/jquery": ">=1.7" + }, + "type": "bower-asset-library", + "extra": { + "bower-asset-main": [ + "./dist/inputmask/jquery.inputmask.js", + "./dist/inputmask/jquery.inputmask.extensions.js", + "./dist/inputmask/jquery.inputmask.date.extensions.js", + "./dist/inputmask/jquery.inputmask.numeric.extensions.js", + "./dist/inputmask/jquery.inputmask.phone.extensions.js", + "./dist/inputmask/jquery.inputmask.regex.extensions.js" + ], + "bower-asset-ignore": [ + "**/.*", + "qunit/", + "nuget/", + "tools/", + "js/", + "*.md", + "build.properties", + "build.xml", + "jquery.inputmask.jquery.json" + ] + }, + "license": [ + "http://opensource.org/licenses/mit-license.php" + ], + "description": "jquery.inputmask is a jquery plugin which create an input mask.", + "keywords": [ + "form", + "input", + "inputmask", + "jquery", + "mask", + "plugins" + ] + }, + { + "name": "bower-asset/punycode", + "version": "v1.3.2", + "source": { + "type": "git", + "url": "https://github.com/bestiejs/punycode.js.git", + "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bestiejs/punycode.js/zipball/38c8d3131a82567bfef18da09f7f4db68c84f8a3", + "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3", + "shasum": "" + }, + "type": "bower-asset-library", + "extra": { + "bower-asset-main": "punycode.js", + "bower-asset-ignore": [ + "coverage", + "tests", + ".*", + "component.json", + "Gruntfile.js", + "node_modules", + "package.json" + ] + } + }, + { + "name": "bower-asset/typeahead.js", + "version": "v0.10.5", + "source": { + "type": "git", + "url": "https://github.com/twitter/typeahead.js.git", + "reference": "5f198b87d1af845da502ea9df93a5e84801ce742" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twitter/typeahead.js/zipball/5f198b87d1af845da502ea9df93a5e84801ce742", + "reference": "5f198b87d1af845da502ea9df93a5e84801ce742", + "shasum": "" + }, + "require": { + "bower-asset/jquery": ">=1.7" + }, + "require-dev": { + "bower-asset/jasmine-ajax": ">=1.3.1,<1.4", + "bower-asset/jasmine-jquery": ">=1.5.2,<1.6", + "bower-asset/jquery": ">=1.7,<1.8" + }, + "type": "bower-asset-library", + "extra": { + "bower-asset-main": "dist/typeahead.bundle.js" + } + }, + { + "name": "bower-asset/yii2-pjax", + "version": "v2.0.4", + "source": { + "type": "git", + "url": "https://github.com/yiisoft/jquery-pjax.git", + "reference": "3f20897307cca046fca5323b318475ae9dac0ca0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/yiisoft/jquery-pjax/zipball/3f20897307cca046fca5323b318475ae9dac0ca0", + "reference": "3f20897307cca046fca5323b318475ae9dac0ca0", + "shasum": "" + }, + "require": { + "bower-asset/jquery": ">=1.8" + }, + "type": "bower-asset-library", + "extra": { + "bower-asset-main": "./jquery.pjax.js", + "bower-asset-ignore": [ + ".travis.yml", + "Gemfile", + "Gemfile.lock", + "vendor/", + "script/", + "test/" + ] + }, + "license": [ + "MIT" + ] + }, + { + "name": "cebe/markdown", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/cebe/markdown.git", + "reference": "e14d3da8f84eefa3792fd22b5b5ecba9c98d2e18" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cebe/markdown/zipball/e14d3da8f84eefa3792fd22b5b5ecba9c98d2e18", + "reference": "e14d3da8f84eefa3792fd22b5b5ecba9c98d2e18", + "shasum": "" + }, + "require": { + "lib-pcre": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "cebe/indent": "*", + "facebook/xhprof": "*@dev", + "phpunit/phpunit": "4.1.*" + }, + "bin": [ + "bin/markdown" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "cebe\\markdown\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Carsten Brandt", + "email": "mail@cebe.cc", + "homepage": "http://cebe.cc/", + "role": "Creator" + } + ], + "description": "A super fast, highly extensible markdown parser for PHP", + "homepage": "https://github.com/cebe/markdown#readme", + "keywords": [ + "extensible", + "fast", + "gfm", + "markdown", + "markdown-extra" + ], + "time": "2015-03-20 11:07:08" + }, + { + "name": "ezyang/htmlpurifier", + "version": "v4.6.0", + "source": { + "type": "git", + "url": "https://github.com/ezyang/htmlpurifier.git", + "reference": "6f389f0f25b90d0b495308efcfa073981177f0fd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/6f389f0f25b90d0b495308efcfa073981177f0fd", + "reference": "6f389f0f25b90d0b495308efcfa073981177f0fd", + "shasum": "" + }, + "require": { + "php": ">=5.2" + }, + "type": "library", + "autoload": { + "psr-0": { + "HTMLPurifier": "library/" + }, + "files": [ + "library/HTMLPurifier.composer.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL" + ], + "authors": [ + { + "name": "Edward Z. Yang", + "email": "admin@htmlpurifier.org", + "homepage": "http://ezyang.com", + "role": "Developer" + } + ], + "description": "Standards compliant HTML filter written in PHP", + "homepage": "http://htmlpurifier.org/", + "keywords": [ + "html" + ], + "time": "2013-11-30 08:25:19" + } + ], + "packages-dev": [ + { + "name": "cebe/indent", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/cebe/indent.git", + "reference": "c500ed74d30ed2d7e085f9cf07f8092d32d70776" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cebe/indent/zipball/c500ed74d30ed2d7e085f9cf07f8092d32d70776", + "reference": "c500ed74d30ed2d7e085f9cf07f8092d32d70776", + "shasum": "" + }, + "bin": [ + "indent" + ], + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Carsten Brandt", + "email": "mail@cebe.cc", + "homepage": "http://cebe.cc/", + "role": "Core framework development" + } + ], + "description": "a small tool to convert text file indentation", + "time": "2014-05-23 14:40:08" + }, + { + "name": "doctrine/instantiator", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "3d9669e597439e8d205baf315efb757038fb4dea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/3d9669e597439e8d205baf315efb757038fb4dea", + "reference": "3d9669e597439e8d205baf315efb757038fb4dea", + "shasum": "" + }, + "require": { + "php": ">=5.3,<8.0-DEV" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2015-01-16 19:29:51" + }, + { + "name": "fzaninotto/faker", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/fzaninotto/Faker.git", + "reference": "81f8e9439d0041866849c05d334584ea31c7b05e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/81f8e9439d0041866849c05d334584ea31c7b05e", + "reference": "81f8e9439d0041866849c05d334584ea31c7b05e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~1.5" + }, + "suggest": { + "ext-intl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5.x-dev" + } + }, + "autoload": { + "psr-4": { + "Faker\\": "src/Faker/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "François Zaninotto" + } + ], + "description": "Faker is a PHP library that generates fake data for you.", + "keywords": [ + "data", + "faker", + "fixtures" + ], + "time": "2015-03-18 16:46:58" + }, + { + "name": "imagine/imagine", + "version": "0.5.x-dev", + "source": { + "type": "git", + "url": "https://github.com/avalanche123/Imagine.git", + "reference": "343580fceed1f89220481ac98480e92f47d91e6c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/avalanche123/Imagine/zipball/343580fceed1f89220481ac98480e92f47d91e6c", + "reference": "343580fceed1f89220481ac98480e92f47d91e6c", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "sami/sami": "dev-master" + }, + "suggest": { + "ext-gd": "to use the GD implementation", + "ext-gmagick": "to use the Gmagick implementation", + "ext-imagick": "to use the Imagick implementation" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-develop": "0.5-dev" + } + }, + "autoload": { + "psr-0": { + "Imagine": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bulat Shakirzyanov", + "email": "mallluhuct@gmail.com", + "homepage": "http://avalanche123.com" + } + ], + "description": "Image processing for PHP 5.3", + "homepage": "http://imagine.readthedocs.org/", + "keywords": [ + "drawing", + "graphics", + "image manipulation", + "image processing" + ], + "time": "2014-06-13 10:54:04" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "d1da796ba5565789a623052eb9f2cf59d57fec60" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d1da796ba5565789a623052eb9f2cf59d57fec60", + "reference": "d1da796ba5565789a623052eb9f2cf59d57fec60", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "dflydev/markdown": "~1.0", + "erusev/parsedown": "~1.0", + "league/commonmark": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "phpDocumentor": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "mike.vanriel@naenius.com" + } + ], + "time": "2015-02-27 09:28:18" + }, + { + "name": "phpspec/prophecy", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "07606749da971eda75434814a313ed0ce6790f6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/07606749da971eda75434814a313ed0ce6790f6a", + "reference": "07606749da971eda75434814a313ed0ce6790f6a", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "phpdocumentor/reflection-docblock": "~2.0", + "sebastian/comparator": "~1.1" + }, + "require-dev": { + "phpspec/phpspec": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "psr-0": { + "Prophecy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2015-03-20 17:41:29" + }, + { + "name": "phpunit/php-code-coverage", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "4676604b851bfc6fc02bf3394bf350c727bcebf4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/4676604b851bfc6fc02bf3394bf350c727bcebf4", + "reference": "4676604b851bfc6fc02bf3394bf350c727bcebf4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-file-iterator": "~1.3", + "phpunit/php-text-template": "~1.2", + "phpunit/php-token-stream": "~1.3", + "sebastian/environment": "~1.0", + "sebastian/version": "~1.0" + }, + "require-dev": { + "ext-xdebug": ">=2.1.4", + "phpunit/phpunit": "~4" + }, + "suggest": { + "ext-dom": "*", + "ext-xdebug": ">=2.2.1", + "ext-xmlwriter": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2015-03-19 05:49:08" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.3.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb", + "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "File/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2013-10-10 15:34:57" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", + "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "Text/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2014-01-30 17:20:04" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/19689d4354b295ee3d8c54b4f42c3efb69cbc17c", + "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2013-08-02 07:42:54" + }, + { + "name": "phpunit/php-token-stream", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "db32c18eba00b121c145575fcbcd4d4d24e6db74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/db32c18eba00b121c145575fcbcd4d4d24e6db74", + "reference": "db32c18eba00b121c145575fcbcd4d4d24e6db74", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2015-01-17 09:51:32" + }, + { + "name": "phpunit/phpunit", + "version": "4.5.x-dev", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "10f6685ca2cf5d8662b43a225ab853699821690b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/10f6685ca2cf5d8662b43a225ab853699821690b", + "reference": "10f6685ca2cf5d8662b43a225ab853699821690b", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.3.3", + "phpspec/prophecy": "~1.3.1", + "phpunit/php-code-coverage": "~2.0,>=2.0.11", + "phpunit/php-file-iterator": "~1.3.2", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": "~1.0.2", + "phpunit/phpunit-mock-objects": "~2.3", + "sebastian/comparator": "~1.1", + "sebastian/diff": "~1.1", + "sebastian/environment": "~1.2", + "sebastian/exporter": "~1.2", + "sebastian/global-state": "~1.0", + "sebastian/version": "~1.0", + "symfony/yaml": "~2.0" + }, + "suggest": { + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.5.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2015-03-02 06:58:30" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "55484334fb4c306ed24bfc3bdb0874685c29036f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/55484334fb4c306ed24bfc3bdb0874685c29036f", + "reference": "55484334fb4c306ed24bfc3bdb0874685c29036f", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "~1.0,>=1.0.2", + "php": ">=5.3.3", + "phpunit/php-text-template": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "4.4.*@dev" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2015-03-18 09:04:51" + }, + { + "name": "sebastian/comparator", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "1dd8869519a225f7f2b9eb663e225298fade819e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1dd8869519a225f7f2b9eb663e225298fade819e", + "reference": "1dd8869519a225f7f2b9eb663e225298fade819e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/diff": "~1.2", + "sebastian/exporter": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2015-01-29 16:28:08" + }, + { + "name": "sebastian/diff", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "863df9687835c62aa423a22412d26fa2ebde3fd3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/863df9687835c62aa423a22412d26fa2ebde3fd3", + "reference": "863df9687835c62aa423a22412d26fa2ebde3fd3", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "http://www.github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2015-02-22 15:13:53" + }, + { + "name": "sebastian/environment", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "5a8c7d31914337b69923db26c4221b81ff5a196e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5a8c7d31914337b69923db26c4221b81ff5a196e", + "reference": "5a8c7d31914337b69923db26c4221b81ff5a196e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2015-01-01 10:01:08" + }, + { + "name": "sebastian/exporter", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "84839970d05254c73cde183a721c7af13aede943" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/84839970d05254c73cde183a721c7af13aede943", + "reference": "84839970d05254c73cde183a721c7af13aede943", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/recursion-context": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2015-01-27 07:23:06" + }, + { + "name": "sebastian/global-state", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "007c441df427cf0e175372fcbb9d196bce7eb743" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/007c441df427cf0e175372fcbb9d196bce7eb743", + "reference": "007c441df427cf0e175372fcbb9d196bce7eb743", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2015-01-20 04:09:31" + }, + { + "name": "sebastian/recursion-context", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "3989662bbb30a29d20d9faa04a846af79b276252" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/3989662bbb30a29d20d9faa04a846af79b276252", + "reference": "3989662bbb30a29d20d9faa04a846af79b276252", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2015-01-24 09:48:32" + }, + { + "name": "sebastian/version", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "a77d9123f8e809db3fbdea15038c27a95da4058b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/a77d9123f8e809db3fbdea15038c27a95da4058b", + "reference": "a77d9123f8e809db3fbdea15038c27a95da4058b", + "shasum": "" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2014-12-15 14:25:24" + }, + { + "name": "smarty/smarty", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/smarty-php/smarty.git", + "reference": "443ae8c2167add9c7e605f115955816efeb86f1e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/smarty-php/smarty/zipball/443ae8c2167add9c7e605f115955816efeb86f1e", + "reference": "443ae8c2167add9c7e605f115955816efeb86f1e", + "shasum": "" + }, + "require": { + "php": ">=5.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "libs/Smarty.class.php", + "libs/SmartyBC.class.php", + "libs/sysplugins/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0" + ], + "authors": [ + { + "name": "Monte Ohrt", + "email": "monte@ohrt.com" + }, + { + "name": "Uwe Tews", + "email": "uwe.tews@googlemail.com" + }, + { + "name": "Rodney Rehm", + "email": "rodney.rehm@medialize.de" + } + ], + "description": "Smarty - the compiling PHP template engine", + "homepage": "http://www.smarty.net", + "keywords": [ + "templating" + ], + "time": "2015-03-22 23:39:22" + }, + { + "name": "swiftmailer/swiftmailer", + "version": "5.x-dev", + "source": { + "type": "git", + "url": "https://github.com/swiftmailer/swiftmailer.git", + "reference": "048be6f7c19944d604e321347990543bc2bbe10b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/048be6f7c19944d604e321347990543bc2bbe10b", + "reference": "048be6f7c19944d604e321347990543bc2bbe10b", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "mockery/mockery": "~0.9.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.4-dev" + } + }, + "autoload": { + "files": [ + "lib/swift_required.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Corbyn" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Swiftmailer, free feature-rich PHP mailer", + "homepage": "http://swiftmailer.org", + "keywords": [ + "mail", + "mailer" + ], + "time": "2015-03-14 06:07:26" + }, + { + "name": "symfony/yaml", + "version": "2.7.x-dev", + "target-dir": "Symfony/Component/Yaml", + "source": { + "type": "git", + "url": "https://github.com/symfony/Yaml.git", + "reference": "bc2504716cb3f7704dfff5d5dcb88df43282f414" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/bc2504716cb3f7704dfff5d5dcb88df43282f414", + "reference": "bc2504716cb3f7704dfff5d5dcb88df43282f414", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7|~3.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Yaml\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Yaml Component", + "homepage": "http://symfony.com", + "time": "2015-03-22 16:57:18" + }, + { + "name": "twig/twig", + "version": "1.x-dev", + "source": { + "type": "git", + "url": "https://github.com/twigphp/Twig.git", + "reference": "7ee4aec238949225a25f174318dc84167e5f360d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/7ee4aec238949225a25f174318dc84167e5f360d", + "reference": "7ee4aec238949225a25f174318dc84167e5f360d", + "shasum": "" + }, + "require": { + "php": ">=5.2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + } + }, + "autoload": { + "psr-0": { + "Twig_": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Armin Ronacher", + "email": "armin.ronacher@active-4.com", + "role": "Project Founder" + }, + { + "name": "Twig Team", + "homepage": "http://twig.sensiolabs.org/contributors", + "role": "Contributors" + } + ], + "description": "Twig, the flexible, fast, and secure template language for PHP", + "homepage": "http://twig.sensiolabs.org", + "keywords": [ + "templating" + ], + "time": "2015-03-17 17:21:28" + } + ], + "aliases": [], + "minimum-stability": "dev", + "stability-flags": { + "bower-asset/jquery-ui": 0 + }, + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=5.4.0", + "ext-mbstring": "*", + "lib-pcre": "*" + }, + "platform-dev": [] +} diff --git a/docs/documentation_style_guide.md b/docs/documentation_style_guide.md index 99861f5..1444f98 100644 --- a/docs/documentation_style_guide.md +++ b/docs/documentation_style_guide.md @@ -27,6 +27,8 @@ Blocks use the Markdown `> Type: `. There are four block types: * `Info`, general information (an aside); not as strong as a "Note" * `Tip`, pro tips, extras, can be useful but may not be needed by everyone all the time +The sentence after the colon should begin with a capital letter. + ## References * Yii 2.0 or Yii 2 (not Yii2 or Yii2.0) diff --git a/docs/guide-es/README.md b/docs/guide-es/README.md index 413f8df..bef9ef1 100644 --- a/docs/guide-es/README.md +++ b/docs/guide-es/README.md @@ -1,7 +1,7 @@ -Guía Definitiva de Yii 2.0 +Guía Definitiva de Yii 2.0 ========================== -Este tutorial se publica con arreglo a los [Términos de Documentación Yii](http://www.yiiframework.com/doc/terms/). +Este tutorial se publica bajo los [Términos de Documentación Yii](http://www.yiiframework.com/doc/terms/). Todos los derechos reservados. @@ -37,22 +37,22 @@ Estructura de una aplicación * [Controladores](structure-controllers.md) * [Modelos](structure-models.md) * [Vistas](structure-views.md) -* **TBD** [Filtros](structure-filters.md) -* **TBD** [Widgets](structure-widgets.md) -* **TBD** [Módulos](structure-modules.md) -* [Recursos](structure-assets.md) -* **TBD** [Extensiones](structure-extensions.md) +* [Filtros](structure-filters.md) +* [Widgets](structure-widgets.md) +* [Módulos](structure-modules.md) +* [Assets](structure-assets.md) +* [Extensiones](structure-extensions.md) Gestión de las peticiones ------------------------- -* **TBD** [Bootstrapping](runtime-bootstrapping.md) -* **TBD** [Rutas](runtime-routing.md) -* **TBD** [Peticiones](runtime-requests.md) -* **TBD** [Respuestas](runtime-responses.md) -* **TBD** [Sesiones y Cookies](runtime-sessions-cookies.md) -* [Procesamiento y generación de las URL](runtime-url-handling.md) +* [Información general](runtime-overview.md) +* [Bootstrapping](runtime-bootstrapping.md) +* [Routing y Creación de las URL](runtime-routing.md) +* [Peticiones (Requests)](runtime-requests.md) +* [Respuestas (Responses)](runtime-responses.md) +* [Sesiones (Sessions) y Cookies](runtime-sessions-cookies.md) * [Gestión de errores](runtime-handling-errors.md) * [Registro de anotaciones](runtime-logging.md) @@ -72,12 +72,16 @@ Conceptos clave Trabajar con bases de datos ------------------------------ - -* [Objeto de acceso a datos](db-dao.md) - Conexión a una base de datos, consultas básicas, transacciones y manipulación de esquemas -* [Constructor de consultas](db-query-builder.md) - Consulta de la base de datos utilizando una simple capa de abstracción -* [Active Record](db-active-record.md) - ORM Active Record, recuperación y manipulación de registros y definición de relaciones -* [Migraciones](db-migrations.md) - Control de versiones de bases de datos en el entorno de desarrollo en equipo +--------------------------- + +* [Objeto de acceso a datos](db-dao.md) - Conexión a una base de datos, consultas básicas, transacciones y + manipulación de esquemas +* [Constructor de consultas](db-query-builder.md) - Consulta de la base de datos utilizando una simple capa de + abstracción +* **TBD** [Active Record](db-active-record.md) - ORM Active Record, recuperación y manipulación de registros y + definición de relaciones +* **TBD** [Migraciones](db-migrations.md) - Control de versiones de bases de datos en el entorno de desarrollo en + equipo * **TBD** [Sphinx](db-sphinx.md) * **TBD** [Redis](db-redis.md) * **TBD** [MongoDB](db-mongodb.md) @@ -87,9 +91,10 @@ Trabajar con bases de datos Obtener datos de los usuarios ----------------------------- -* [Crear formularios](input-forms.md) -* [Validar datos](input-validation.md) +* **TBD** [Crear formularios](input-forms.md) +* **TBD** [Validar datos](input-validation.md) * **TBD** [Subir archivos](input-file-upload.md) +* **TBD** [Recogida de tabular input](input-tabular-input.md) * **TBD** [Obtener datos para múltiples modelos](input-multiple-models.md) @@ -99,18 +104,19 @@ Visualizar datos * **TBD** [Formato de datos](output-formatting.md) * **TBD** [Paginación](output-pagination.md) * **TBD** [Ordenación](output-sorting.md) -* [Proveedores de datos](output-data-providers.md) -* [Widgets de datos](output-data-widgets.md) -* [Utilización de temas](output-theming.md) +* **TBD** [Proveedores de datos](output-data-providers.md) +* **TBD** [Widgets de datos](output-data-widgets.md) +* **TBD** [Trabajar con scripts de cliente](output-client-scripts.md) +* [Temas](output-theming.md) Seguridad --------- -* [Autenticación](security-authentication.md) -* [Autorización](security-authorization.md) -* [Trabajar con contraseñas](security-passwords.md) -* **TBD** [Auth Clients](security-auth-clients.md) +* **TBD** [Autenticación](security-authentication.md) +* **TBD** [Autorización](security-authorization.md) +* **TBD** [Trabajar con contraseñas](security-passwords.md) +* **TBD** [Autenticar Clientes](security-auth-clients.md) * **TBD** [Buenas prácticas](security-best-practices.md) @@ -124,7 +130,7 @@ Caché * [Caché HTTP](caching-http.md) -Servicios Web RESTful +Servicios Web RESTful --------------------- * [Guía breve](rest-quick-start.md) @@ -141,58 +147,49 @@ Servicios Web RESTful Herramientas de Desarrollo -------------------------- -* [Depurador y Barra de Herramientas de Depuración](tool-debugger.md) -* [Generación de códigos con Gii](tool-gii.md) +* **TBD** [Depurador y Barra de Herramientas de Depuración](tool-debugger.md) +* **TBD** [Generación de códigos con Gii](tool-gii.md) * **TBD** [Generación de documentación de API](tool-api-doc.md) Pruebas ------ -* [Información general](test-overview.md) +* **TBD** [Información general](test-overview.md) +* **TBD** [Configuración del entorno de pruebas](test-environment-setup.md) * **TBD** [Pruebas unitarias](test-unit.md) * **TBD** [Pruebas funcionales](test-functional.md) * **TBD** [Pruebas de aceptación](test-acceptance.md) -* [Fixtures](test-fixtures.md) - - -Extender Yii ------------- - -* [Crear extensiones](extend-creating-extensions.md) -* [Personalizar el código de base](extend-customizing-core.md) -* [Utilizar librerías de terceros](extend-using-libs.md) -* **TBD** [Utilizar Yii en sistemas de terceros](extend-embedding-in-others.md) -* **TBD** [Utilizar las versiones 1.1 y 2.0 de Yii juntas](extend-using-v1-v2.md) -* [Utilizar Composer](extend-using-composer.md) +* **TBD** [Fixtures](test-fixtures.md) Temas especiales ---------------- -* [Plantilla aplicación avanzada](tutorial-advanced-app.md) -* [Creación de una aplicación desde cero](tutorial-start-from-scratch.md) -* [Comandos de consola](tutorial-console.md) -* [Validadores de base](tutorial-core-validators.md) -* [Internacionalización](tutorial-i18n.md) -* [Envío de correos electrónicos](tutorial-mailing.md) -* [Mejora del rendimiento](tutorial-performance-tuning.md) +* **TBD** [Plantilla aplicación avanzada](tutorial-advanced-app.md) +* **TBD** [Creación de una aplicación desde cero](tutorial-start-from-scratch.md) +* **TBD** [Comandos de consola](tutorial-console.md) +* [Validadores del núcleo](tutorial-core-validators.md) +* **TBD** [Internacionalización](tutorial-i18n.md) +* **TBD** [Envío de correos electrónicos](tutorial-mailing.md) +* **TBD** [Mejora del rendimiento](tutorial-performance-tuning.md) * **TBD** [Entorno de alojamiento compartido](tutorial-shared-hosting.md) -* [Motores de plantillas](tutorial-template-engines.md) +* **TBD** [Motores de plantillas](tutorial-template-engines.md) +* **TBD** [Trabajar con Código de Terceros](tutorial-yii-integration.md) Widgets ------- -* GridView: link to demo page -* ListView: link to demo page -* DetailView: link to demo page -* ActiveForm: link to demo page -* Pjax: link to demo page -* Menu: link to demo page -* LinkPager: link to demo page -* LinkSorter: link to demo page -* [Bootstrap Widgets](bootstrap-widgets.md) +* GridView: **TBD** link to demo page +* ListView: **TBD** link to demo page +* DetailView: **TBD** link to demo page +* ActiveForm: **TBD** link to demo page +* Pjax: **TBD** link to demo page +* Menu: **TBD** link to demo page +* LinkPager: **TBD** link to demo page +* LinkSorter: **TBD** link to demo page +* **TBD** [Bootstrap Widgets](bootstrap-widgets.md) * **TBD** [Jquery UI Widgets](jui-widgets.md) @@ -200,8 +197,6 @@ Clases auxiliares ----------------- * [Información general](helper-overview.md) -* **TBD** [ArrayHelper](helper-array.md) -* **TBD** [Html](helper-html.md) -* **TBD** [Url](helper-url.md) -* **TBD** [Security](helper-security.md) - +* [ArrayHelper](helper-array.md) +* [Html](helper-html.md) +* [Url](helper-url.md) diff --git a/docs/guide-es/caching-data.md b/docs/guide-es/caching-data.md index 27f3275..20c8073 100644 --- a/docs/guide-es/caching-data.md +++ b/docs/guide-es/caching-data.md @@ -1,21 +1,17 @@ -Almacenamiento de Datos en Caché +Almacenamiento de Datos en Caché ================================ -El almacenamiento de datos en caché trata del almacenamiento de alguna variable PHP en caché y recuperarla más tarde del -mismo. También es la base de algunas de las características avanzadas de almacenamiento en caché, tales como -[el almacenamiento en caché de consultas a la base de datos](#query-caching) y -[el almacenamiento en caché de contenido](caching-content.md). +El almacenamiento de datos en caché trata del almacenamiento de alguna variable PHP en caché y recuperarla más tarde del mismo. También es la base de algunas de las características avanzadas de almacenamiento en caché, tales como [el almacenamiento en caché de consultas a la base de datos](#query-caching) y [el almacenamiento en caché de contenido](caching-page.md). -El siguiente código muestra el típico patrón de uso para el almacenamiento en caché, donde la variable `$cache` se -refiere al [componente caché](#cache-components): +El siguiente código muestra el típico patrón de uso para el almacenamiento en caché, donde la variable `$cache` se refiere al [componente caché](#cache-components): ```php -// probar de recuerar $data del caché +// intenta recuperar $data de la caché $data = $cache->get($key); if ($data === false) { - // $data no ha sido encontrada en caché, calcularla desde cero + // $data no ha sido encontrada en la caché, calcularla desde cero // guardar $data en caché para así recuperarla la próxima vez $cache->set($key, $data); @@ -25,12 +21,12 @@ if ($data === false) { ``` -## Componentes de Caché +## Componentes de Caché El almacenamiento de datos en caché depende de los llamados *cache components* (componentes de caché) los cuales representan diferentes tipos de almacenamiento en caché, como por ejemplo en memoria, en archivos o en base de datos. -Los Componentes de Caché estan normalmente registrados como componentes de la aplicación para que de esta forma puedan +Los Componentes de Caché están normalmente registrados como [componentes de la aplicación](structure-application-components.md) para que de esta forma puedan ser configurados y accesibles globalmente. El siguiente código muestra cómo configurar el componente de aplicación `cache` para usar [memcached](http://memcached.org/) con dos servidores caché: @@ -58,8 +54,7 @@ Puedes acceder al componente de caché usando la expresión `Yii::$app->cache`. Debido a que todos los componentes de caché soportan el mismo conjunto de APIs, podrías cambiar el componente de caché subyacente por otro diferente mediante su reconfiguración en la configuración de la aplicación sin tener que modificar -el código que utiliza el caché. Por ejemplo, podrías modificar la configuración anterior para usar [[yii\caching\ApcCache|APC cache]]: - +el código que utiliza la caché. Por ejemplo, podrías modificar la configuración anterior para usar [[yii\caching\ApcCache|APC cache]]: ```php 'components' => [ @@ -69,73 +64,50 @@ el código que utiliza el caché. Por ejemplo, podrías modificar la configuraci ], ``` -> Nota: Puedes registrar multiples componentes de aplicación de caché. El componente llamado `cache` es usado por defecto - por muchas caché-dependiente clases (e.g. [[yii\web\UrlManager]]). +> Consejo: Puedes registrar múltiples componentes de aplicación de caché. El componente llamado `cache` es usado por defecto por muchas clases caché-dependiente (ej. [[yii\web\UrlManager]]). -### Almacenamientos de Caché Soportados +### Almacenamientos de Caché Soportados Yii proporciona varios componentes de caché que pueden almacenar datos en diferentes medios. A continuación se muestra un listado con los componentes de caché disponibles: -* [[yii\caching\ApcCache]]: utiliza la extensión de PHP [APC](http://php.net/manual/en/book.apc.php). Esta opción puede - ser considerada como la más rápida de entre todas las disponibles para una aplicación centralizada. (p. ej. un servidor, - no dedicado balance de carga, etc). -* [[yii\caching\DbCache]]: utiliza una tabla de base de datos para almacenar los datos. Por defecto, se creará y usará - como base de datos [SQLite3](http://sqlite.org/) en el directorio runtime. Se puede especificar explicitamente que base - de datos va a ser utilizada configurando la propiedad `db`. -* [[yii\caching\DummyCache]]: dummy cache (caché tonta) que no almacena en caché nada. El propósito de este componente - es simplificar el código necesario para chequear la disponibilidad de caché. Por ejemplo, durante el desarrollo o - si el servidor no tiene soporte de caché actualmente, puede utilizarse este componente de caché. Cuando este disponible - un soporte en caché, puede cambiarse el componente correspondiente. En ambos casos, puede utilizarse el mismo código - `Yii::$app->cache->get($key)` para recuperar un dato sin la preocupación de que `Yii::$app->cache` pueda ser `null`. -* [[yii\caching\FileCache]]: utiliza un fichero estándar para almacenar los datos. Esto es adecuado para almacenar - grandes bloques de datos (como páginas). -* [[yii\caching\MemCache]]: utiliza las extensiones de PHP [memcache](http://php.net/manual/en/book.memcache.php) - y [memcached](http://php.net/manual/en/book.memcached.php). Esta opción puede ser considerada como la más rápida - cuando la caché es manejada en una aplicación distribuida (p. ej. con varios servidores, con balance de carga, etc..) -* [[yii\redis\Cache]]: implementa un componente de caché basado en [Redis](http://redis.io/) que almacenan pares - clave-valor (requiere la versión 2.6.12 de redis). -* [[yii\caching\WinCache]]: utiliza la extensión de PHP [WinCache](http://iis.net/downloads/microsoft/wincache-extension) - ([ver también](http://php.net/manual/en/book.wincache.php)). +* [[yii\caching\ApcCache]]: utiliza la extensión de PHP [APC](http://php.net/manual/es/book.apc.php). Esta opción puede ser considerada como la más rápida de entre todas las disponibles para una aplicación centralizada. (ej. un servidor, no dedicado al balance de carga, etc). +* [[yii\caching\DbCache]]: utiliza una tabla de base de datos para almacenar los datos. Por defecto, se creará y usará como base de datos [SQLite3](http://sqlite.org/) en el directorio runtime. Se puede especificar explícitamente que base de datos va a ser utilizada configurando la propiedad `db`. +* [[yii\caching\DummyCache]]: dummy cache (caché tonta) que no almacena en caché nada. El propósito de este componente es simplificar el código necesario para chequear la disponibilidad de caché. Por ejemplo, durante el desarrollo o si el servidor no tiene soporte de caché actualmente, puede utilizarse este componente de caché. Cuando este disponible un soporte en caché, puede cambiarse el componente correspondiente. En ambos casos, puede utilizarse el mismo código `Yii::$app->cache->get($key)` para recuperar un dato sin la preocupación de que `Yii::$app->cache` pueda ser `null`. +* [[yii\caching\FileCache]]: utiliza un fichero estándar para almacenar los datos. Esto es adecuado para almacenar grandes bloques de datos (como páginas). +* [[yii\caching\MemCache]]: utiliza las extensiones de PHP [memcache](http://php.net/manual/es/book.memcache.php) y [memcached](http://php.net/manual/es/book.memcached.php). Esta opción puede ser considerada como la más rápida cuando la caché es manejada en una aplicación distribuida (ej. con varios servidores, con balance de carga, etc..) +* [[yii\redis\Cache]]: implementa un componente de caché basado en [Redis](http://redis.io/) que almacenan pares clave-valor (requiere la versión 2.6.12 de redis). +* [[yii\caching\WinCache]]: utiliza la extensión de PHP [WinCache](http://iis.net/downloads/microsoft/wincache-extension) ([ver también](http://php.net/manual/es/book.wincache.php)). * [[yii\caching\XCache]]: utiliza la extensión de PHP [XCache](http://xcache.lighttpd.net/). -* [[yii\caching\ZendDataCache]]: utiliza - [Zend Data Cache](http://files.zend.com/help/Zend-Server-6/zend-server.htm#data_cache_component.htm) - como el medio fundamental de caché. +* [[yii\caching\ZendDataCache]]: utiliza [Zend Data Cache](http://files.zend.com/help/Zend-Server-6/zend-server.htm#data_cache_component.htm) como el medio fundamental de caché. + +> Consejo: Puedes utilizar diferentes tipos de almacenamiento de caché en la misma aplicación. Una estrategia común es la de usar almacenamiento de caché en memoria para almacenar datos que son pequeños pero que son utilizados constantemente (ej. datos estadísticos), y utilizar el almacenamiento de caché en archivos o en base de datos para guardar datos que son grandes y utilizados con menor frecuencia (ej. contenido de página). -> Nota: Puedes utililizar diferentes tipos de almacenamiento de caché en la misma aplicación. Una estrategia común es la - de usar almacenamiento de caché en memoria par almacenar datos que son pequeños pero que son utilizados constantemente - (por ejemplo, datos estadísticos), y utilizar el almacenamiento de caché en archivos o en base de datos para guardar - datos que son grandes y utilizados con menor frecuencia (por ejemplo, contenido de página). -## API de Caché +## API de Caché -Todos los componentes de almacenamiento de caché provienen de la misma clase "padre" [[yii\caching\Cache]] y por lo tanto -soportan la siguiente API: +Todos los componentes de almacenamiento de caché provienen de la misma clase "padre" [[yii\caching\Cache]] y por lo tanto soportan la siguiente API: * [[yii\caching\Cache::get()|get()]]: recupera un elemento de datos de la memoria caché con una clave especificada. - Un valor nulo será devuelto si el elemento de datos no ha sido encontrado en la memoria caché o si ha expirado o ha sido - invalidado. + Un valor nulo será devuelto si el elemento de datos no ha sido encontrado en la memoria caché o si ha expirado o ha sido invalidado. * [[yii\caching\Cache::set()|set()]]: almacena un elemento de datos identificado por una clave en la memoria caché. -* [[yii\caching\Cache::add()|add()]]: almacena un elemento de datos identificado por una clave en la memoria caché si la - clave no se encuentra en la memoria caché. +* [[yii\caching\Cache::add()|add()]]: almacena un elemento de datos identificado por una clave en la memoria caché si la clave no se encuentra en la memoria caché. * [[yii\caching\Cache::mget()|mget()]]: recupera varios elementos de datos de la memoria caché con las claves especificadas. -* [[yii\caching\Cache::mset()|mset()]]: almacena múltiples elementos de datos en la memoria caché. Cada elemento se - identifica por una clave. -* [[yii\caching\Cache::madd()|madd()]]: stores multiple data items in cache. Each item is identified by a key. - If a key already exists in the cache, the data item will be skipped. -* [[yii\caching\Cache::exists()|exists()]]: devuelve un valor que indica si la clave especificada se encuentra en la - memoria caché. +* [[yii\caching\Cache::mset()|mset()]]: almacena múltiples elementos de datos en la memoria caché. Cada elemento se identifica por una clave. +* [[yii\caching\Cache::madd()|madd()]]: almacena múltiples elementos de datos en la memoria caché. Cada elemento se identifica con una clave. Si una clave ya existe en la caché, el elemento será omitido. +* [[yii\caching\Cache::exists()|exists()]]: devuelve un valor que indica si la clave especificada se encuentra en la memoria caché. * [[yii\caching\Cache::delete()|delete()]]: elimina un elemento de datos identificado por una clave de la caché. * [[yii\caching\Cache::flush()|flush()]]: elimina todos los elementos de datos de la cache. -Algunos sistemas de almacenamiento de caché, como por ejemplo MemCache, APC, pueden recuperar multiples valores -almacenados en modo de lote (batch), lo que puede reducir considerablemente la sobrecarga que implica la recuperación -de datos almacenados en el caché. Las API [[yii\caching\Cache::mget()|mget()]] y [[yii\caching\Cache::madd()|madd()]] -se proporcionan para utilizar esta característia. En el caso de que el sistema de memoria caché no lo soportara, ésta -sería simulada. +> Nota: No Almacenes el valor boolean `false` en caché directamente porque el método [[yii\caching\Cache::get()|get()]] devuelve +el valor `false` para indicar que el dato no ha sido encontrado en la caché. Puedes poner `false` dentro de un array y cachear +este array para evitar este problema. + +Algunos sistemas de almacenamiento de caché, como por ejemplo MemCache, APC, pueden recuperar múltiples valores almacenados en modo de lote (batch), lo que puede reducir considerablemente la sobrecarga que implica la recuperación de datos almacenados en la caché. Las API [[yii\caching\Cache::mget()|mget()]] y [[yii\caching\Cache::madd()|madd()]] +se proporcionan para utilizar esta característica. En el caso de que el sistema de memoria caché no lo soportara, ésta sería simulada. -Puesto que [[yii\caching\Cache]] implementa `ArrayAccess`, un componente de caché puede ser usado como una matriz (array). +Puesto que [[yii\caching\Cache]] implementa `ArrayAccess`, un componente de caché puede ser usado como un array. El siguiente código muestra unos ejemplos: ```php @@ -144,18 +116,13 @@ $value2 = $cache['var2']; // equivalente a: $value2 = $cache->get('var2'); ``` -### Claves de Caché +### Claves de Caché -Cada elemento de datos almacenado en caché se identifica por una clave. Cuando se almacena un elemento de datos en la -memoria caché, se debe especificar una clave. Más tarde, cuando se recupera el elemento de datos de la memoria caché, -se debe proporcionar la tecla correspondiente. +Cada elemento de datos almacenado en caché se identifica por una clave. Cuando se almacena un elemento de datos en la memoria caché, se debe especificar una clave. Más tarde, cuando se recupera el elemento de datos de la memoria caché, se debe proporcionar la clave correspondiente. -Puedes utilizar una cadena o un valor arbitrario como una clave de caché. Cuando una clave no es una cadena de texto, -ésta será automáticamente serializada en una cadena. +Puedes utilizar una cadena o un valor arbitrario como una clave de caché. Cuando una clave no es una cadena de texto, ésta será automáticamente serializada en una cadena. -Una estrategia común para definir una clave de caché es incluir en ella todos los factores determinantes en términos de -una matriz. Por ejemplo, [[yii\db\Schema]] utiliza la siguiente clave para almacenar en caché la información del esquema -de una tabla de base de datos: +Una estrategia común para definir una clave de caché es incluir en ella todos los factores determinantes en términos de un array. Por ejemplo, [[yii\db\Schema]] utiliza la siguiente clave para almacenar en caché la información del esquema de una tabla de base de datos: ```php [ @@ -166,19 +133,15 @@ de una tabla de base de datos: ]; ``` -Como puedes ver, la clave incluye toda la información necesaria para especificar de una forma exclusiva una tabla de -base de datos. +Como puedes ver, la clave incluye toda la información necesaria para especificar de una forma exclusiva una tabla de base de datos. -Cuando el un mismo almacenamiento en caché es utilizado por diferentes aplicaciones, se debería especificar un prefijo -único para las claves de de caché por cada una de las aplicaciones para así evitar conflictos. Esto puede hacerse -mediante la configuración de la propiedad [[yii\caching\Cache::keyPrefix]]. Por ejemplo, en la configuración de la -aplicación podrías escribir el siguiente código: +Cuando en un mismo almacenamiento en caché es utilizado por diferentes aplicaciones, se debería especificar un prefijo único para las claves de la caché por cada una de las aplicaciones para así evitar conflictos. Esto puede hacerse mediante la configuración de la propiedad [[yii\caching\Cache::keyPrefix]]. Por ejemplo, en la configuración de la aplicación podrías escribir el siguiente código: ```php 'components' => [ 'cache' => [ 'class' => 'yii\caching\ApcCache', - 'keyPrefix' => 'myapp', // un prefixo de clave de caché único + 'keyPrefix' => 'myapp', // un prefijo de clave de caché único ], ], ``` @@ -186,15 +149,9 @@ aplicación podrías escribir el siguiente código: Para garantizar la interoperabilidad, deberían utilizarse sólo caracteres alfanuméricos. -### Caducidad de Caché +### Caducidad de Caché -Un elemento de datos almacenado en la memoria caché permanecerá en ella para siempre, a menos que sea removida de alguna -manera debido a alguna directiva de caché (por ejemplo, el espacio de almacenamiento en caché está lleno y los datos -más antiguos se eliminan). Para cambiar este comportamiento, podrías proporcionar un parámetro de caducidad al llamar -[[yii\caching\Cache::set()|set()]] para guardar el elemento de datos. El parámetro nos indica por cuántos segundos el -elemento se mantendrá válido en memoria caché. Cuando llames [[yii\caching\Cache::get()|get()]] para recuperar el -elemento, si el tiempo de caducidad ha pasado, el método devolverá `false`, indicando que el elemento de datos no ha -sido encontrado en la memoria caché. Por ejemplo, +Un elemento de datos almacenado en la memoria caché permanecerá en ella para siempre, a menos que sea removida de alguna manera debido a alguna directiva de caché (ej. el espacio de almacenamiento en caché está lleno y los datos más antiguos se eliminan). Para cambiar este comportamiento, podrías proporcionar un parámetro de caducidad al llamar [[yii\caching\Cache::set()|set()]] para guardar el elemento de datos. El parámetro nos indica por cuántos segundos el elemento se mantendrá válido en memoria caché. Cuando llames [[yii\caching\Cache::get()|get()]] para recuperar el elemento, si el tiempo de caducidad ha pasado, el método devolverá `false`, indicando que el elemento de datos no ha sido encontrado en la memoria caché. Por ejemplo, ```php // guardar los datos en memoria caché al menos 45 segundos @@ -209,18 +166,11 @@ if ($data === false) { ``` -### Dependecias de Caché +### Dependencias de Caché -Además de configurar el tiempo de expiración, los datos almacenados en caché pueden también ser invalidados conforme -a algunos cambios en las dependencias (cache dependencies). Por ejemplo, [[yii\caching\FileDependency]] representa -la dependencia del tiempo de modificación del archivo. Cuando esta dependencia cambia, significa que el archivo -correspondiente ha cambiado. Como resultado, cualquier contenido anticuado que sea encontrado en el caché debería -ser invalidado y la llamada a [[yii\caching\Cache::get()|get()]] debería devolver `null`. - -Una dependencia es representada como una instancia de [[yii\caching\Dependency]] o su clase hija. Cuando llamas -[[yii\caching\Cache::set()|set()]] para almacenar un elemento de datos en el caché, puedes pasar el objeto de dependencia -asociado. Por ejemplo, +Además de configurar el tiempo de caducidad, los datos almacenados en caché pueden también ser invalidados conforme a algunos cambios en la caché de dependencias. Por ejemplo, [[yii\caching\FileDependency]] representa la dependencia del tiempo de modificación del archivo. Cuando esta dependencia cambia, significa que el archivo correspondiente ha cambiado. Como resultado, cualquier contenido anticuado que sea encontrado en la caché debería ser invalidado y la llamada a [[yii\caching\Cache::get()|get()]] debería retornar falso. +Una dependencia es representada como una instancia de [[yii\caching\Dependency]] o su clase hija. Cuando llamas [[yii\caching\Cache::set()|set()]] para almacenar un elemento de datos en la caché, puedes pasar el objeto de dependencia asociado. Por ejemplo, ```php // Crear una dependencia sobre el tiempo de modificación del archivo example.txt. @@ -230,9 +180,9 @@ $dependency = new \yii\caching\FileDependency(['fileName' => 'example.txt']); // También podría ser invalidada antes si example.txt es modificado. $cache->set($key, $data, 30, $dependency); -// El caché chequeará si los datos han expirado. -// También chequeará si la dependencia ha cambiado. -// Devolerá false si se encuentran algunas de esas condiciones. +// 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. $data = $cache->get($key); ``` @@ -246,53 +196,111 @@ Aquí abajo se muestra un sumario de las dependencias disponibles: con el mismo nombre del grupo a la vez llamando a [[yii\caching\TagDependency::invalidate()]]. -## Consultas en Caché +## Consultas en Caché Las consultas en caché es una característica especial de caché construido sobre el almacenamiento de caché de datos. Se proporciona para almacenar en caché el resultado de consultas a la base de datos. -Las consultas en caché requieren una [[yii\db\Connection|conexión a BD]] y un componente de aplicación -caché válido. El uso básico de las consultas en memoria caché es el siguiente, asumiendo `db` es una instancia [[yii\db\Connection]]: +Las consultas en caché requieren una [[yii\db\Connection|DB connection]] y un componente de aplicación caché válido. El uso básico de las consultas en memoria caché es el siguiente, asumiendo que `db` es una instancia de [[yii\db\Connection]]: + +```php +$result = $db->cache(function ($db) { + + // el resultado de la consulta SQL será servida de la caché + // si el cacheo de consultas está habilitado y el resultado de la consulta se encuentra en la caché + return $db->createCommand('SELECT * FROM customer WHERE id=1')->queryOne(); + +}); +``` + +El cacheo de consultas puede ser usado tanto para [DAO](db-dao.md) como para [ActiveRecord](db-active-record.md): + +```php +$result = Customer::getDb()->cache(function ($db) { + return Customer::find()->where(['id' => 1])->one(); +}); +``` + +> Nota: Algunos DBMS (ej. [MySQL](http://dev.mysql.com/doc/refman/5.1/en/query-cache.html)) también soporta el almacenamiento en caché desde el mismo servidor de la BD. Puedes optar por utilizar cualquiera de los mecanismos de memoria caché. El almacenamiento en caché de consultas previamente descrito tiene la ventaja que de que se puede especificar dependencias de caché de una forma flexible y son potencialmente mucho más eficientes. + + +### Configuraciones + +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]]. +* [[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. + + +### Usos + +Puedes usar [[yii\db\Connection::cache()]] si tienes multiples consultas SQL que necesitas a aprovechar el cacheo de consultas. El uso es de la siguiente manera, ```php -$duration = 60; // guardar en caché el resultado de la consulta por 60 segundos. +$duration = 60; // resultado de la consulta de caché durante 60 segundos. $dependency = ...; // dependencia opcional -$db->beginCache($duration, $dependency); +$result = $db->cache(function ($db) { + + // ... realiza consultas SQL aquí ... -// ...realiza consultas a la BD aquí... + return $result; -$db->endCache(); +}, $duration, $dependency); ``` -Como puedes ver, cualquier consulta SQL entre las llamadas `beginCache()` y `endCache()` serán guardadas en la memoria caché. -Si el resultado de la misma consulta se encuentra vigente en la memoria caché, la consulta se omitirá y el resultado -se servirá de la memoria caché en su lugar. +Cualquier consulta SQL en una función anónima será cacheada durante el tiempo indicado con la dependencia especificada. +Si el resultado de la consulta se encuentra válida en la caché, la consulta se omitirá y el resultado se servirá de la caché en su lugar. Si no especificar el parámetro `$duration`, el valor [[yii\db\Connection::queryCacheDuration|queryCacheDuration]] será usado en su lugar. + +A veces dentro de `cache()`, puedes querer desactivar el cacheo de consultas para algunas consultas especificas. Puedes usar [[yii\db\Connection::noCache()]] en este caso. -El almacenamiento en caché de consultas se puede usar para [DAO](db-dao.md), así como para [ActiveRecord](db-active-record.md). +```php +$result = $db->cache(function ($db) { -> Nota: Algunos DBMS (por ejemplo, [MySQL](http://dev.mysql.com/doc/refman/5.1/en/query-cache.html)) también soporta - el almacenamiento en caché desde el mismo servidor de la BD. Puedes optar por utilizar cualquiera de los mecanismos - de memoria caché. El almacenamiento en caché de consultas previamente descrito tiene la ventaja que de que se puede - especificar dependencias de caché de una forma flexible y son potencialmente mucho más eficientes. + // consultas SQL que usan el cacheo de consultas -### Configuraciones + $db->noCache(function ($db) { -Las consultas en caché tienen dos opciones configurables a traves de [[yii\db\Connection]]: + // consultas SQL que no usan el cacheo de consultas + + }); + + // ... + + return $result; +}); +``` + +Si lo deseas puedes usar el cacheo de consultas para una simple consulta, puedes llamar a [[yii\db\Command::cache()]] cuando construyas el comando. Por ejemplo, + +```php +// usa el cacheo de consultas y asigna la duración de la consulta de caché por 60 segundos +$customer = $db->createCommand('SELECT * FROM customer WHERE id=1')->cache(60)->queryOne(); +``` + +También puedes usar [[yii\db\Command::noCache()]] para desactivar el cacheo de consultas de un simple comando. Por ejemplo, + +```php +$result = $db->cache(function ($db) { + + // consultas SQL que usan cacheo de consultas + + // no usa cacheo de consultas para este comando + $customer = $db->createCommand('SELECT * FROM customer WHERE id=1')->noCache()->queryOne(); + + // ... + + return $result; +}); +``` -* [[yii\db\Connection::queryCacheDuration|queryCacheDuration]]: esto representa el número de segundos que un resultado - de la consulta permanecerá válido en la memoria caché. La duración será sobrescrita si se llama a - [[yii\db\Connection::beginCache()]] con un parámetro explícito de 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 cuando hay un componente de la - aplicación de caché válido. -### Limitaciones +### Limitaciones El almacenamiento en caché de consultas no funciona con los resultados de consulta que contienen controladores de recursos. -Por ejemplo, cuando se utiliza el tipo de columna `BLOB` en algunos DBMS, el resultado de la consulta devolverá un recurso -para manejar los datos de la columna. +Por ejemplo, cuando se utiliza el tipo de columna `BLOB` en algunos DBMS, el resultado de la consulta devolverá un recurso para manejar los datos de la columna. -Algunos sistemas de almacenamiento caché tienen limitación de tamaño. Por ejemplo, memcache limita el tamaño máximo -de cada entrada a 1MB. Por lo tanto, si el tamaño de un resultado de la consulta excede ese límite, el almacenamiento -en caché fallará. +Algunos sistemas de almacenamiento caché tienen limitación de tamaño. Por ejemplo, memcache limita el tamaño máximo de cada entrada a 1MB. Por lo tanto, si el tamaño de un resultado de la consulta excede ese límite, el almacenamiento en caché fallará. diff --git a/docs/guide-es/caching-fragment.md b/docs/guide-es/caching-fragment.md index 1314d34..3d8cd17 100644 --- a/docs/guide-es/caching-fragment.md +++ b/docs/guide-es/caching-fragment.md @@ -1,12 +1,12 @@ Caché de Fragmentos =================== -Caché de Fragmentos se refiere al almacenamiento en caché de un fragmento, o sección, de una página Web. Por ejemplo, si -una página muestra un sumario de la ventas anuales en una tabla, podrías guardar esta tabla en memoria caché para -eliminar el tiempo necesario para generar esta tabla en cada petición (request). El caché de fragmentos está construido -sobre el [caché de datos](caching-data.md). +La Caché de Fragmentos se refiere al almacenamiento en caché de un fragmento, o sección, de una página Web. Por ejemplo, si +una página muestra un sumario de las ventas anuales en una tabla, podrías guardar esta tabla en memoria caché para +eliminar el tiempo necesario para generar esta tabla en cada petición (request). La caché de fragmentos está construido +sobre la [caché de datos](caching-data.md). -Para usar el caché de fragmentos, utiliza el siguiente código en tu [vista](structure-views.md): +Para usar la caché de fragmentos, utiliza el siguiente código en tu [vista (view)](structure-views.md): ```php @@ -18,28 +18,28 @@ if ($this->beginCache($id)) { } ``` -Es decir, encierra la lógica de la generación del contenido entre las llamadas a [[yii\base\View::beginCache()|beginCache()]] y +Es decir, encierra la lógica de la generación del contenido entre las llamadas [[yii\base\View::beginCache()|beginCache()]] y [[yii\base\View::endCache()|endCache()]]. Si el contenido se encuentra en la memoria caché, [[yii\base\View::beginCache()|beginCache()]] mostrará el contenido y devolverá `false`, saltandose así la lógica de generación del contenido. De lo contrario, el -código de generación se ejecutaría y al alcanzar la llamada a [[yii\base\View::endCache()|endCache()]], el contenido +código de generación se ejecutaría y al alcanzar la llamada [[yii\base\View::endCache()|endCache()]], el contenido generado será capturado y almacenado en la memoria caché. -Como en [caché de datos](caching-data.md), un `$id` (clave) único es necesario para identificar un contenido guardado en +Como en la [caché de datos](caching-data.md), un `$id` (clave) único es necesario para identificar un contenido guardado en caché. -## Opciones de Caché +## Opciones de Caché -Puedes especificar opciones adicionales para el caché de fragmentos pasando la matriz (array) de opciones como segundo -parametro del método [[yii\base\View::beginCache()|beginCache()]]. Entre bastidores, esta matriz de opciones se utiliza -para configurar el widget [[yii\widgets\FragmentCache]] que es en realidad el que implementa la funcionalidad de caché +Puedes especificar opciones adicionales para la caché de fragmentos pasando el array de opciones como segundo +parametro del método [[yii\base\View::beginCache()|beginCache()]]. Entre bastidores, este array de opciones se utiliza +para configurar el widget [[yii\widgets\FragmentCache]] que es en realidad el que implementa la funcionalidad de la caché de fragmentos. -### Duración +### Duración -Quizás la opción más utilizada en el caché de fragmentos es [[yii\widgets\FragmentCache::duration|duración]]. Ésta +Quizás la opción más utilizada en la caché de fragmentos es [[yii\widgets\FragmentCache::duration|duración]]. Ésta especifica cuántos segundos el contenido puede permanecer como válido en la memoria caché. El siguiente código almacena -en caché el fragmento de contenido para una hora a lo sumo: +en la caché el fragmento de contenido para una hora a lo sumo: ```php if ($this->beginCache($id, ['duration' => 3600])) { @@ -50,19 +50,18 @@ if ($this->beginCache($id, ['duration' => 3600])) { } ``` -Si la opción no está activada, se tomará el valor por defecto 0, lo que significa que el contenido almacenado en caché -nunca expirará. +Si la opción no está activada, se tomará el valor por defecto 60, lo que significa que el contenido almacenado en caché expirará en 60 segundos. -### Dependencias +### Dependencias -Como en [caché de datos](caching-data.md#cache-dependencies), fragmento de contenido que está siendo almacenado en caché +Como en la [caché de datos](caching-data.md#cache-dependencies), el fragmento de contenido que está siendo almacenado en caché también puede tener dependencias. Por ejemplo, el contenido de un artículo que se muestre depende de si el mensaje se modifica o no. Para especificar una dependencia, activa la opción [[yii\widgets\FragmentCache::dependency|dependencia]] (dependency), -que puede ser un objecto [[yii\caching\Dependency]] o la matriz de configuración para crear un objecto `Dependency`. El -siguiente código especifica que el caché de fragmento depende del cambio del valor de la columna `updated_at`: +que puede ser un objecto [[yii\caching\Dependency]] o un array de configuración para crear un objecto `Dependency`. El +siguiente código especifica que la caché de fragmento depende del cambio del valor de la columna `updated_at`: ```php $dependency = [ @@ -79,16 +78,16 @@ if ($this->beginCache($id, ['dependency' => $dependency])) { ``` -### Variaciones +### Variaciones El contenido almacenado en caché puede variar de acuerdo a ciertos parámetros. Por ejemplo, para una aplicación Web que -soporte multiples idiomas, la misma pieza del código de la vista (View) puede generar el contenido almacenado en caché +soporte multiples idiomas, la misma pieza del código de la vista puede generar el contenido almacenado en caché en diferentes idiomas. Por lo tanto, es posible que desees hacer variaciones del mismo contenido almacenado en caché de acuerdo con la actual selección del idioma en la aplicación. -Para especificar variacioens en la memoria caché, configura la opción [[yii\widgets\FragmentCache::variations|variaciones]] -(variations), la cual debere ser una matriz de valores escalares, cada uno de ellos representando un factor de variación. -Por ejemplo, para hacer que el contenido almacenado en caché varie por lenguaje, podrías usar el siguiente código: +Para especificar variaciones en la memoria caché, configura la opción [[yii\widgets\FragmentCache::variations|variaciones]] +(variations), la cual deberá ser un array de valores escalares, cada uno de ellos representando un factor de variación. +Por ejemplo, para hacer que el contenido almacenado en la caché varíe por lenguaje, podrías usar el siguiente código: ```php if ($this->beginCache($id, ['variations' => [Yii::$app->language]])) { @@ -100,12 +99,12 @@ if ($this->beginCache($id, ['variations' => [Yii::$app->language]])) { ``` -### Alternando el Almacenamiento en Caché +### Alternando el Almacenamiento en Caché -Puede que a veces quieras habilitar el caché de fragmentos únicamente cuando ciertas condiciones se cumplan. Por ejemplo, -para una página que muestra un formulario, tal vez quieras guardarlo en caché cuando es inicialmente solicitado (a +Puede que a veces quieras habilitar la caché de fragmentos únicamente cuando ciertas condiciones se cumplan. Por ejemplo, +para una página que muestra un formulario, tal vez quieras guardarlo en la caché cuando es inicialmente solicitado (a través de una petición GET). Cualquier muestra posterior (a través de una petición POST) del formulario no debería ser -almacenada en caché ya que el formulario puede que contenga entradas del usuario. Para hacerlo, podrias configurar la +almacenada en caché ya que el formulario puede que contenga entradas del usuario. Para hacerlo, podrías configurar la opción de [[yii\widgets\FragmentCache::enabled|activado]] (enabled), de la siguiente manera: ```php @@ -118,7 +117,7 @@ if ($this->beginCache($id, ['enabled' => Yii::$app->request->isGet])) { ``` -## Almacenamiento en Caché Anidado +## Almacenamiento en Caché Anidada El almacenamiento en caché de fragmentos se puede anidar. Es decir, un fragmento de caché puede ser encerrado dentro de otro fragmento que también se almacena en caché. Por ejemplo, los comentarios se almacenan en una caché de fragmento @@ -143,27 +142,27 @@ if ($this->beginCache($id1)) { } ``` -Existen diferentes opciones de configuración de para los cachés anidados. Por ejemplo, las cachés internas y las cachés -externas pueden usar diferentes valores de duración. Aún cuando los datos almacenados en el caché externo sean invalidados, -el caché interno puede todavía proporcionar un fragmento válido. Sin embargo, no podría ser viceversa. Si el caché externo -es evaluado como válido, seguiría proporcionando la misma copia en caché incluso después de que el contenido en el -caché interno haya sido invalidado. Por lo tanto, hay que tener mucho cuidado al configurar el tiempo de duración o las -dependencias de los cachés anidados, de lo contrario los fragmentos internos que ya estén obsoletes se pueden seguir +Existen diferentes opciones de configuración para las cachés anidadas. Por ejemplo, las cachés internas y las cachés +externas pueden usar diferentes valores de duración. Aún cuando los datos almacenados en la caché externa sean invalidados, +la caché interna puede todavía proporcionar un fragmento válido. Sin embargo, al revés no es cierto. Si la caché externa +es evaluada como válida, seguiría proporcionando la misma copia en caché incluso después de que el contenido en la +caché interna haya sido invalidada. Por lo tanto, hay que tener mucho cuidado al configurar el tiempo de duración o las +dependencias de las cachés anidadas, de lo contrario los fragmentos internos que ya estén obsoletos se pueden seguir manteniendo en el fragmento externo. -## Contenido Dinámico +## Contenido Dinámico -Cuando se usa el caché de fragmentos, podrías encontrarte en la situación que un fragmento grande de contenido es -relavitamente estático excepto en uno u otro lugar. Por ejemplo, el cabezal de una página (header) puede que muestre el +Cuando se usa la caché de fragmentos, podrías encontrarte en la situación que un fragmento grande de contenido es +relavitamente estático excepto en uno u otro lugar. Por ejemplo, la cabeza de una página (header) puede que muestre el menú principal junto al nombre del usuario actual. Otro problema es que el contenido que está siendo almacenado en caché -puede que contenga código PHP que debe ser ejecutado en cada petición (request) (por ejemplo, el código para registrar +puede que contenga código PHP que debe ser ejecutado en cada petición (por ejemplo, el código para registrar un paquete de recursos (asset bundle)). En ambos casos, podríamos resolver el problema con lo que llamamos la característica de *contenido dinámico*. -Como *contenido dinámico* entendemos a un fragmento de salida que no debería ser guardado en caché incluso si está +Entendemos *contenido dinámico* como un fragmento de salida que no debería ser guardado en caché incluso si está encerrado dentro de un fragmento de caché. Para hacer el contenido dinámico todo el tiempo, éste ha de ser generado ejecutando -cierto código PHP en cada petición (request), incluso si el contenido está siendo mostrado desde el caché. +cierto código PHP en cada petición, incluso si el contenido está siendo mostrado desde la caché. Puedes llamar a [[yii\base\View::renderDynamic()]] dentro de un fragmento almacenado en caché para insertar código dinámico en el lugar deseado como, por ejemplo, de la siguiente manera, @@ -182,5 +181,5 @@ if ($this->beginCache($id1)) { ``` El método [[yii\base\View::renderDynamic()|renderDynamic()]] toma una pieza de código PHP como su parámetro. El valor -devuelto del código PHP se trata como contenido dinámico. El mismo código PHP será ejecutado en cada petición (request), -sin importar que esté dentro de un fragmento que está siendo servido desde el caché o no. +devuelto del código PHP se trata como contenido dinámico. El mismo código PHP será ejecutado en cada petición, +sin importar que esté dentro de un fragmento que está siendo servido desde la caché o no. diff --git a/docs/guide-es/caching-http.md b/docs/guide-es/caching-http.md index 5439ece..391da78 100644 --- a/docs/guide-es/caching-http.md +++ b/docs/guide-es/caching-http.md @@ -2,11 +2,11 @@ Caché HTTP ========== Además del almacenamiento de caché en el servidor que hemos descrito en secciones anteriores, las aplicaciones Web -pueden hacer uso del caché en el lado del cliente para así ahorrar tiempo y recursos para generar y transmitir el +pueden hacer uso de la caché en el lado del cliente para así ahorrar tiempo y recursos para generar y transmitir el mismo contenido una y otra vez. Para usar la caché del lado del cliente, puedes configurar [[yii\filters\HttpCache]] como un filtro en el controlador -para aquellas acciones cuyo resultado deba estar estar almacenado en la caché en el lado del cliente. [[yii\filters\HttpCache|HttpCache]] +para aquellas acciones cuyo resultado deba estar almacenado en la caché en el lado del cliente. [[yii\filters\HttpCache|HttpCache]] solo funciona en peticiones `GET` y `HEAD`. Puede manejar tres tipos de cabeceras (headers) HTTP relacionadas en este tipo de consultas: @@ -15,7 +15,7 @@ consultas: * [[yii\filters\HttpCache::cacheControlHeader|Cache-Control]] -## La Cabecera `Last-Modified` +## La Cabecera `Last-Modified` La cabecera `Last-Modified` usa un sello de tiempo para indicar si la página ha sido modificada desde que el cliente la almacena en la caché. @@ -59,10 +59,10 @@ regenerar la página, y el navegador usará la versión caché del lado del clie lado del servidor y la transmisión del contenido de la página son ambos omitidos. -## La Cabecera `ETag` +## La Cabecera `ETag` La cabecera "Entity Tag" (o para abreviar `ETag`) usa un hash para representar el contenido de una página. Si la página -ha sido cambiada, el hash también cambiará. Al comprar el hash guardado en el lado del cliente con el hash generado en +ha sido cambiada, el hash también cambiará. Al comparar el hash guardado en el lado del cliente con el hash generado en el servidor, la caché puede determinar si la página ha cambiado y deber ser retransmitida. Puedes configurar la propiedad [[yii\filters\HttpCache::etagSeed]] para activar el envío de la cabecera `ETag`. @@ -97,9 +97,9 @@ public function behaviors() ``` El código anterior establece que la caché HTTP debe ser activada únicamente para la acción `view`. Debería generar una -cabecera HTTP `ETag` basándose en el título y contenido del artículo consultado. Cuando un navegador vista la página +cabecera HTTP `ETag` basándose en el título y contenido del artículo consultado. Cuando un navegador visita la página `view` por primera vez, la página se generará en el servidor y será enviada al navegador; Si el navegador visita la -misma página de nuevo y ha ocurrido un cambio en el título o contenido del artículo, el servidor no volverá a generar +misma página de nuevo y no ha ocurrido un cambio en el título o contenido del artículo, el servidor no volverá a generar la página, y el navegador usará la versión guardada en la caché del lado del cliente. Como resultado, la representación del lado del servidor y la transmisión del contenido de la página son ambos omitidos. @@ -110,11 +110,10 @@ La generación de un ETag que requiera muchos recursos puede echar por tierra el introducir una sobrecarga innecesaria, ya que debe ser re-evaluada en cada solicitud (request). Trata de encontrar una expresión sencilla para invalidar la caché si la página ha sido modificada. -> Nota: En cumplimiento con [RFC 2616, section 13.3.4](http://tools.ietf.org/html/rfc2616#section-13.3.4), - `HttpCache` enviará ambas cabeceras `ETag` y `Last-Modified` si ambas estaán configuradas. En consecuencia, ambas serán - utilizadas para la validación de la caché si han sido enviadas por el cliente. +> Nota: En cumplimiento con [RFC 7232](http://tools.ietf.org/html/rfc7232#section-2.4), + `HttpCache` enviará ambas cabeceras `ETag` y `Last-Modified` si ambas están configuradas. Y si el clientes envía tanto la cabecera `If-None-Match` como la cabecera `If-Modified-Since`, solo la primera será respetada. -## La Cabecera `Cache-Control` +## La Cabecera `Cache-Control` La cabecera `Cache-Control` especifica la directiva general de la caché para páginas. Puedes enviarla configurando la propiedad [[yii\filters\HttpCache::cacheControlHeader]] con el valor de la cabecera. Por defecto, la siguiente cabecera @@ -124,18 +123,18 @@ será enviada: Cache-Control: public, max-age=3600 ``` -## Limitador de la Sesión de Caché +## Limitador de la Sesión de Caché -Cuando una página utiliza la sesión, PHP enviará automaticamente cabeceras HTTP relacionadas con la caché tal y como se +Cuando una página utiliza la sesión, PHP enviará automáticamente cabeceras HTTP relacionadas con la caché tal y como se especifican en `session.cache_limiter` de la configuración INI de PHP. Estas cabeceras pueden interferir o deshabilitar el almacenamiento de caché que desees de `HttpCache`. Para evitar este problema, por defecto `HttpCache` deshabilitará -automaticamente el envío de estas cabeceras. Si deseas modificar este comportamiento, tienes que configurar la propiedad +automáticamente el envío de estas cabeceras. Si deseas modificar este comportamiento, tienes que configurar la propiedad [[yii\filters\HttpCache::sessionCacheLimiter]]. La propiedad puede tomar un valor de cadena, incluyendo `public`, `private`, `private_no_expire`, and `nocache`. Por favor, consulta el manual PHP acerca de [session_cache_limiter()](http://www.php.net/manual/es/function.session-cache-limiter.php) para una mejor explicación sobre esos valores. -## Implicaciones SEO +## Implicaciones SEO Los robots de motores de búsqueda tienden a respetar las cabeceras de caché. Dado que algunos `crawlers` tienen limitado el número de páginas que pueden rastrear por dominios dentro de un cierto período de tiempo, la introducción de cabeceras diff --git a/docs/guide-es/caching-overview.md b/docs/guide-es/caching-overview.md index 89fb862..4a2504f 100644 --- a/docs/guide-es/caching-overview.md +++ b/docs/guide-es/caching-overview.md @@ -11,10 +11,9 @@ de artículos que han sido extraídos de la base de datos; y en el nivel superio almacenar fragmentos o un conjuto de páginas Web, tales como el resultado de la representación de los artículos más recientes. -Caching can occur at different levels and places in a Web application. On the server side, at the lower level, -cache may be used to store basic data, such as a list of most recent article information fetched from database; -and at the higher level, cache may be used to store fragments or whole of Web pages, such as the rendering result -of the most recent articles. En el lado del cliente, el almacenamiento en caché HTTP puede ser utilizado para mantener +El almacenamiento en caché se puede usar en diferentes niveles y lugares en una aplicación web. En el lado del servidor, al más bajo nivel, +la caché puede ser usada para almacenar datos básicos, tales como una una lista de los artículos más recientes obtenidos de una base de datos; +y en el más alto nivel, la caché puede ser usada para almacenar fragmentos o la totalidad de las páginas web, tales como el resultado del renderizado de los artículos más recientes. En el lado del cliente, el almacenamiento en caché HTTP puede ser utilizado para mantener el contenido de la página que ha sido visitada más recientemente en el caché del navegador. Yii soporta los siguientes mecanismos de almacenamiento de caché: diff --git a/docs/guide-es/caching-page.md b/docs/guide-es/caching-page.md index b7dab68..60e064c 100644 --- a/docs/guide-es/caching-page.md +++ b/docs/guide-es/caching-page.md @@ -1,8 +1,8 @@ Caché de Páginas ================ -El caché de páginas se refiere a guardar el contenido de toda una página en el almacenamiento de caché del servidor. -Posteriormente, cuando la misma página sea requerida de nuevo, su contenido será devuelto desde el caché en vez de +La caché de páginas se refiere a guardar el contenido de toda una página en el almacenamiento de caché del servidor. +Posteriormente, cuando la misma página sea requerida de nuevo, su contenido será devuelto desde la caché en vez de volver a generarlo desde cero. El almacenamiento en caché de páginas está soportado por [[yii\filters\PageCache]], un [filtro de acción](structure-filters.md). @@ -33,10 +33,9 @@ contenido de la página debería almacenarse durante un máximo de 60 segundos y aplicación; además, el almacenamiento de la página en caché debería ser invalidado si el número total de artículos ha cambiado. -Como puedes ver, el caché de páginas es muy similar al [caché de fragmentos](caching-fragment.md). Ambos soportan opciones -tales como `duration`, `dependencies`, `variations`, y `enabled`. Su principal diferencia es que el caché de páginas es -implementado como un [filtro de acción](structure-filters.md) mientras que el caché de fragmentos se hace en un [widget](structure-widgets.md). - -Puedes usar el [caché de fragmentos](caching-fragment.md) así como [contenido dinámico](caching-fragment.md#dynamic-content) -junto con el caché de páginas. +Como puedes ver, la caché de páginas es muy similar a la [caché de fragmentos](caching-fragment.md). Ambos soportan opciones +tales como `duration`, `dependencies`, `variations`, y `enabled`. Su principal diferencia es que la caché de páginas está +implementado como un [filtro de acción](structure-filters.md) mientras que la caché de fragmentos se hace en un [widget](structure-widgets.md). +Puedes usar la [caché de fragmentos](caching-fragment.md) así como el [contenido dinámico](caching-fragment.md#dynamic-content) +junto con la caché de páginas. diff --git a/docs/guide-es/concept-aliases.md b/docs/guide-es/concept-aliases.md index 0e42141..ecaee1a 100644 --- a/docs/guide-es/concept-aliases.md +++ b/docs/guide-es/concept-aliases.md @@ -6,7 +6,7 @@ en tu código. Un alias debe comenzar con un cáracter `@` para que así pueda s Por ejemplo, el alias `@yii` representa la ruta de instalación de la librería Yii, mientras que `@web` representa la URL base la aplicación que actualmente se está ejecutando. -Definiendo Alias +Definiendo Alias ---------------- Puedes llamar a [[Yii::setAlias()]] para definir un alias para una determinada ruta de archivo o URL. Por ejemplo, @@ -48,7 +48,7 @@ return [ ``` -Resolución de Alias +Resolución de Alias ------------------- Puedes llamar [[Yii::getAlias()]] para resolver un alias de raíz en la ruta o URL que representa. El mismo método puede @@ -80,7 +80,7 @@ Yii::getAlias('@foo/bar/file.php'); // muestra: /path2/bar/file.php Si `@foo/bar` no está definido como un alias de raíz, la última declaración mostraría `/path/to/foo/bar/file.php`. -Usando Alias +Usando Alias ------------ Los alias son utilizados en muchos lugares en Yii sin necesidad de llamar [[Yii::getAlias()]] para convertirlos en rutas/URLs. @@ -97,29 +97,31 @@ $cache = new FileCache([ Por favor, presta atención a la documentación API para ver si una propiedad o el parámetro de un método soporta alias. -Alias Predefinidos + +Alias Predefinidos ------------------ Yii predefine un conjunto de alias para aliviar la necesidad de hacer referencia a rutas de archivo o URLs que son utilizadas regularmente. La siguiente es la lista de alias predefinidos por Yii: -- `@yii`: el directorio donde el archivo `BaseYii.php` se encuentra (también llamado el directorio de la libreria). +- `@yii`: el directorio donde el archivo `BaseYii.php` se encuentra (también llamado el directorio del framework). - `@app`: la [[yii\base\Application::basePath|ruta base]] de la aplicación que se está ejecutando actualmente. -- `@runtime`: la [[yii\base\Application::runtimePath|ruta de ejecución]] (carpeta `runtime) de la aplicación que se ` - está ejecutando actualmente. -- `@vendor`: el [[yii\base\Application::vendorPath|directorio vendor de Composer]. +- `@runtime`: la [[yii\base\Application::runtimePath|ruta de ejecución]] de la aplicación en ejecución. Por defecto `@app/runtime`. - `@webroot`: el directorio raíz Web de la aplicación Web se está ejecutando actualmente. -- `@web`: la URL base de la aplicación web se ejecuta actualmente. +- `@web`: la URL base de la aplicación web se ejecuta actualmente. Tiene el mismo valor que [[yii\web\Request::baseUrl]]. +- `@vendor`: el [[yii\base\Application::vendorPath|directorio vendor de Composer]. Por defecto `@app/vendor`. +- `@bower`, el directorio raíz que contiene [paquetes bower](http://bower.io/). Por defecto `@vendor/bower`. +- `@npm`, el directorio raíz que contiene [paquetes npm](https://www.npmjs.org/). Por defecto `@vendor/npm`. El alias `@yii` se define cuando incluyes el archivo `Yii.php` en tu [script de entrada](structure-entry-scripts.md), mientras que el resto de los alias están definidos en el constructor de la aplicación cuando se aplica la [configuración](concept-configurations.md) de la aplicación. -Alias en Extensiones +Alias en Extensiones -------------------- -Un alias se define automaticamente por cada [extension](structure-extensions.md) que ha sido instalada a través de Composer. +Un alias se define automaticamente por cada [extensión](structure-extensions.md) que ha sido instalada a través de Composer. El alias es nombrado tras el `namespace` de raíz de la extensión instalada tal y como está declarada en su archivo `composer.json`, y representa el directorio raíz de la extensión. Por ejemplo, si instalas la extensión `yiisoft/yii2-jui`, tendrás automaticamente definido el alias `@yii/jui` durante la etapa [bootstrapping](runtime-bootstrapping.md) de la aplicación: diff --git a/docs/guide-es/concept-autoloading.md b/docs/guide-es/concept-autoloading.md index 90f439c..900ad25 100644 --- a/docs/guide-es/concept-autoloading.md +++ b/docs/guide-es/concept-autoloading.md @@ -1,7 +1,7 @@ Autocarga de clases =================== -Yii depende del [mecanismo de autocarga de clases](http://www.php.net/manual/en/language.oop5.autoload.php) para localizar +Yii depende del [mecanismo de autocarga de clases](http://www.php.net/manual/es/language.oop5.autoload.php) para localizar e incluir los archivos de las clases requiridas. Proporciona un cargador de clases de alto rendimiento que cumple con el [estandard PSR-4](https://github.com/php-fig/fig-standards/blob/master/proposed/psr-4-autoloader/psr-4-autoloader.md). El cargador se instala cuando incluyes el archivo `Yii.php`. @@ -10,7 +10,7 @@ El cargador se instala cuando incluyes el archivo `Yii.php`. ten en cuenta que el contenido que describimos aquí también se aplica a la autocarga de interfaces y rasgos (Traits). -Usando el Autocargador de Yii +Usando el Autocargador de Yii ----------------------------- Para utilizar el cargador automático de clases de Yii, deberías seguir dos reglas básicas cuando desarrolles y nombres tus @@ -28,7 +28,7 @@ Por ejemplo, si el nombre de una clase es `foo\bar\MyClass`, el [alias](concept- archivo de la clase sería `@foo/bar/MyClass.php`. Para que este sea capaz de ser resuelto como una ruta de archivo, ya sea `@foo` o `@foo/bar` debe ser un [alias de raíz](concept-aliases.md#defining-aliases) (root alias). -Cuando utilizas la [Plantilla de Aplicación Básica](start-basic.md), puede que pongas tus clases bajo el nivel superior +Cuando utilizas la [Plantilla de Aplicación Básica](start-installation.md), puede que pongas tus clases bajo el nivel superior de espacio de nombres `app` para que de esta manera pueda ser automáticamente cargado por Yii sin tener la necesidad de definir un nuevo alias. Esto es porque `@app` es un [alias predefinido](concept-aliases.md#predefined-aliases), y el nombre de una clase tal como `app\components\MyClass` puede ser resuelto en el archivo de la clase `AppBasePath/components/MyClass.php`, @@ -40,7 +40,7 @@ poner las clases `front-end` bajo el espacio de nombres `frontend` mientras que `backend`. Esto permitirá que estas clases sean automaticamente cargadas por el autocargador de Yii. -Mapa de Clases +Mapa de Clases -------------- El autocargador de clases de Yii soporta el *mapa de clases*, que mapea nombres de clases to sus correpondientes rutas de @@ -59,7 +59,7 @@ clases en el proceso [bootstrapping](runtime-bootstrapping.md) de la aplicación antes de que tus clases sean usadas. -Usando otros Autocargadores +Usando otros Autocargadores --------------------------- Debido a que Yii incluye Composer como un gestor de dependencias y extensions, es recomendado que también instales el @@ -69,7 +69,7 @@ instalarlos. Cuando se utiliza el cargador de clases automático de Yii conjuntamente con otros autocargadores, deberías incluir el archivo `Yii.php` *después* de que todos los demás autocargadores se hayan instalado. Esto hará que el autocargador de Yii sea el primero en responder a cualquier petición de carga automática de clases. Por ejemplo, el siguiente código ha -sido extraido del [script de entrada](structure-entry-scripts.md) de la [Plantilla de Aplicación Básica](start-basic.md). +sido extraido del [script de entrada](structure-entry-scripts.md) de la [Plantilla de Aplicación Básica](start-installation.md). La primera línea instala el autocargador de Composer, mientras que la segunda línea instala el autocargador de Yii. ```php @@ -85,7 +85,7 @@ ser autocargables. incluirlo en tu [script de entrada](structure-entry-scripts.md). -Carga Automática de Clases de Extensiones +Carga Automática de Clases de Extensiones ----------------------------------------- El autocargador de Yii es capaz de autocargar clases de [extensiones](structure-extensions.md). El único requirimiento es diff --git a/docs/guide-es/concept-behaviors.md b/docs/guide-es/concept-behaviors.md index 4a6ff48..fbbbf16 100644 --- a/docs/guide-es/concept-behaviors.md +++ b/docs/guide-es/concept-behaviors.md @@ -10,58 +10,99 @@ comportamiento puede responder a [eventos](concept-events.md) disparados por el o adaptar a la ejecución normal del código del componente. -Usando comportamientos ----------------------- +Definiendo comportamientos +-------------------------- -Para poder utilizar un comportamiento, primero tienes que unirlo a un [[yii\base\Component|componente]]. Describiremos cómo -puedes vincular un comportamiento en la próxima sub-sección. +Para definir un comportamiento, se debe crear una clase que exiende [[yii\base\Behavior]], o se extiende una clase hija. Por ejemplo: -Una vez que el comportamiento ha sido vinculado a un componente, su uso es sencillo. +```php +namespace app\components; -Puedes usar a una variable *pública* o a una [propiedad](concept-properties.md) definida por un `getter` y/o un `setter` -del comportamiento a través del componente con el que se ha vinculado, como por ejemplo, +use yii\base\Behavior; -```php -// "prop1" es una propiedad definida en la clase comportamiento -echo $component->prop1; -$component->prop1 = $value; -``` +class MyBehavior extends Behavior +{ + public $prop1; -También puedes llamar métodos *públicos* del comportamiento de una forma similar, + private $_prop2; -```php -// bar() es un método público definido dentro de la clase comportamiento -$component->bar(); + public function getProp2() + { + return $this->_prop2; + } + + public function setProp2($value) + { + $this->_prop2 = $value; + } + + public function foo() + { + // ... + } +} ``` +El código anterior define la clase de comportamiento (behavior) app\components\MyBehavior`, con dos propiedades -- +`prop1` y `prop2`--y un método `foo()`. Tenga en cuenta que la propiedad `prop2` +se define a través de la getter `getProp2()` y el setter `setProp2()`. Este caso es porque [[yii\base\Behavior]] extiende [[yii\base\Object]] y por lo tanto se apoya en la definición de [propiedades](concept-properties.md) via getters y setters. -Como puedes ver, aunque `$component` no tiene definida `prop1` y `bar()`, pueden ser usadas como si fueran parte -definida del componente. +Debido a que esta clase es un comportamiento, cuando está unido a un componente, el componente también tienen la propiedad `prop1` y `prop2` y el método `foo()`. -Si dos comportamientos definen la misma propiedad o método y ambos están vinculados con el mismo componente, el -comportamiento que ha sido vinculado primero tendrá preferencia cuando se esté accediendo a la propiedad o método. +> Consejo: Dentro de un comportamiento, puede acceder al componente que el comportamiento está unido a través de la propiedad [[yii\base\Behavior::owner]]. -Un comportamiento puede estar asociado con un nombre cuando se une a un componente. Si este es el caso, es posible -acceder al objeto de comportamiento mediante el nombre, como se muestra a continuación, + +Gestión de eventos de componentes +--------------------------------- + +Si un comportamiento necesita responder a los acontecimientos desencadenados por el componente al que está unido, se debe reemplazar el método [[yii\base\Behavior::events()]]. Por ejemplo: ```php -$behavior = $component->getBehavior('myBehavior'); +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) + { + // ... + } +} ``` -También puedes acceder a todos los comportamientos vinculados al componente: +El método [[yii\base\Behavior::events()|events()]] debe devolver una lista de eventos y sus correspondientes controladores. +El ejemplo anterior declara que el evento [[yii\db\ActiveRecord::EVENT_BEFORE_VALIDATE|EVENT_BEFORE_VALIDATE]] existe y esta exists y define su controlador, `beforeValidate()`. Al especificar un controlador de eventos, puede utilizar uno de los siguientes formatos: + +* una cadena que se refiere al nombre de un método de la clase del comportamiento, como el ejemplo anterior +* un arreglo de objeto o nombre de clase, y un nombre de método como una cadena (sin paréntesis), ej., `[$object, 'methodName']`; +* una función anónima + +La firma de un controlador de eventos debe ser la siguiente, donde `$ event` refiere al parámetro de evento. Por favor, consulte la sección [Eventos](concept-events.md) para más detalles sobre los eventos. ```php -$behaviors = $component->getBehaviors(); +function ($event) { +} ``` -Vinculando Comportamientos +Vinculando Comportamientos -------------------------- Puedes vincular un comportamiento a un [[yii\base\Component|componente]] ya sea estática o dinámicamente. La primera forma es la más comúnmente utilizada en la práctica. -Para unir un comportamiento estáticamente, reemplaza el método [[yii\base\Component::behaviors()|behaviors()]] de la -clase componente que se está conectando. Por ejemplo, +Para unir un comportamiento estáticamente, reemplaza el método [[yii\base\Component::behaviors()|behaviors()]] dde la clase de componente a la que se une el comportamiento. El método [[yii\base\Component::behaviors()|behaviors()]] debe devolver una lista de comportamiento [configuraciones](concept-configurations.md). +Cada configuración de comportamiento puede ser un nombre de clase de comportamiento o un arreglo de configuración: ```php namespace app\models; @@ -74,20 +115,20 @@ class User extends ActiveRecord public function behaviors() { return [ - // comportamiento anónimo, sólo el nombre de la clase del comportamiento + // anonymous behavior, behavior class name only MyBehavior::className(), - // comportamiento nombrado, sólo el nombre de la clase del comportamiento + // named behavior, behavior class name only 'myBehavior2' => MyBehavior::className(), - // comportamiento anónimo, matriz de configuración + // anonymous behavior, configuration array [ 'class' => MyBehavior::className(), 'prop1' => 'value1', 'prop2' => 'value2', ], - // comportamiento nombrado, matriz de configuración + // named behavior, configuration array 'myBehavior4' => [ 'class' => MyBehavior::className(), 'prop1' => 'value1', @@ -98,17 +139,13 @@ class User extends ActiveRecord } ``` -El método [[yii\base\Component::behaviors()|behaviors()]] tiene que devolver la lista de los comportamientos -[configuraciones](concept-configurations.md). -Cada configuración de un comportamiento puede ser el nombre de la clase o una matriz de configuración. - Puedes asociciar un nombre a un comportamiento especificándolo en la clave de la matriz correspondiente a la configuración del comportamiento. En este caso, el comportamiento puede ser llamado un *comportamiento nombrado* (named behavior). En el ejemplo anterior, hay dos tipos de comportamientos nombrados: `myBehavior2` y `myBehavior4`. Si un comportamiento no está asociado con un nombre, se le llama *comportamiento anónimo* (anonymous behavior). Para vincular un comportamiento dinámicamente, llama al método [[yii\base\Component::attachBehavior()]] desde el componente al -que se le va a unir el comportamiento. Por ejemplo, +que se le va a unir el comportamiento: ```php use app\components\MyBehavior; @@ -126,19 +163,16 @@ $component->attachBehavior('myBehavior3', [ 'prop2' => 'value2', ]); ``` - -You may attach multiple behaviors at once by using the [[yii\base\Component::attachBehaviors()]] method. -For example, +Puede vincular múltiples comportamientos a la vez mediante el uso del método [[yii\base\Component::attachBehaviors()]]. Por ejemplo, ```php $component->attachBehaviors([ - 'myBehavior1' => new MyBehavior, // a named behavior - MyBehavior::className(), // an anonymous behavior + 'myBehavior1' => new MyBehavior, // un comportamiento nombrado + MyBehavior::className(), // un comportamiento anónimo ]); ``` -También puedes asociar comportamientos a traves de [configuraciones](concept-configurations.md) compor el siguiente -ejemplo. Para más detalles, por favor visita la sección [Configuraciones](concept-configurations.md#configuration-format). +También puedes asociar comportamientos a traves de [configuraciones](concept-configurations.md) como el siguiente: ```php [ @@ -152,121 +186,73 @@ ejemplo. Para más detalles, por favor visita la sección [Configuraciones](conc ] ``` +Para más detalles, por favor visita la sección [Configuraciones](concept-configurations.md#configuration-format). -Desasociar Comportamientos --------------------------- -Para desasociar un comportamiento, puedes llamar el método [[yii\base\Component::detachBehavior()]] con el nombre con el -que se le asoció: +Usando comportamientos +---------------------- -```php -$component->detachBehavior('myBehavior1'); -``` +Para poder utilizar un comportamiento, primero tienes que unirlo a un [[yii\base\Component|componente]] según las instrucciones anteriores. Una vez que un comportamiento ha sido vinculado a un componente, su uso es sencillo. -También puedes desvincular *todos* los comportamientos: +Puedes usar a una variable *pública* o a una [propiedad](concept-properties.md) definida por un `getter` y/o un `setter` +del comportamiento a través del componente con el que se ha vinculado: ```php -$component->detachBehaviors(); +// "prop1" es una propiedad definida en la clase comportamiento +echo $component->prop1; +$component->prop1 = $value; ``` - -Definiendo Comportamientos --------------------------- - -Para definir un comportamiento, crea una clase extendendiéndola de [[yii\base\Behavior]] o una de sus clases "hija". Por ejemplo, +También puedes llamar métodos *públicos* del comportamiento de una forma similar: ```php -namespace app\components; - -use yii\base\Model; -use yii\base\Behavior; - -class MyBehavior extends Behavior -{ - public $prop1; +// foo() es un método público definido dentro de la clase comportamiento +$component->foo(); +``` - private $_prop2; +Como puedes ver, aunque `$component` no tiene definida `prop1` y `bar()`, que se pueden utilizar como si son parte +de la definición de componentes debido al comportamiento vinculado. - public function getProp2() - { - return $this->_prop2; - } +Si dos comportamientos definen la misma propiedad o método y ambos están vinculados con el mismo componente, el +comportamiento que ha sido vinculado *primero* tendrá preferencia cuando se esté accediendo a la propiedad o método. - public function setProp2($value) - { - $this->_prop2 = $value; - } +Un comportamiento puede estar asociado con un nombre cuando se une a un componente. Si este es el caso, es posible +acceder al objeto de comportamiento mediante el nombre, como se muestra a continuación, - public function foo() - { - // ... - } -} +```php +$behavior = $component->getBehavior('myBehavior'); ``` -El código anterior define la clase del comportamiento `app\components\MyBehavior` que provee dos propiedades `prop1` y -`prop2`, y un método `foo()` al componente con el que está asociado. - -The above code defines the behavior class `app\components\MyBehavior` which will provide two properties -`prop1` and `prop2`, and one method `foo()` to the component it is attached to. Fíjese que la propiedad `prop2` esta -definida a través del getter `getProp2()` y el setter `setProp2()`. Esto es debido a que [[yii\base\Object]] es una -clase "ancestro" (o padre) de [[yii\base\Behavior]], la cual soporta la definición de [propiedades](concept-properties.md) por -getters/setters. - -En un comportamiento, puedes acceder al componente al que está vinculado a través de la propiedad [[yii\base\Behavior::owner]]. - -Si un omportamiento necesita responder a los eventos que han sido disparados desde el componente al qu están asociados, -debería sobreescribir el método [[yii\base\Behavior::events()]]. Por ejemplo, +También puedes acceder a todos los comportamientos vinculados al componente: ```php -namespace app\components; +$behaviors = $component->getBehaviors(); +``` -use yii\db\ActiveRecord; -use yii\base\Behavior; -class MyBehavior extends Behavior -{ - // ... +Desasociar Comportamientos +-------------------------- - public function events() - { - return [ - ActiveRecord::EVENT_BEFORE_VALIDATE => 'beforeValidate', - ]; - } +Para desasociar un comportamiento, puedes llamar el método [[yii\base\Component::detachBehavior()]] con el nombre con el +que se le asoció: - public function beforeValidate($event) - { - // ... - } -} +```php +$component->detachBehavior('myBehavior1'); ``` -El método [[yii\base\Behavior::events()|events()]] tiene que devolver un listado de eventos y sus correspondientes -controladores (handlers). El código anterior declara el evento [[yii\db\ActiveRecord::EVENT_BEFORE_VALIDATE|EVENT_BEFORE_VALIDATE]] -con su controlador `beforeValidate()`. Cuando se especifica un controlador de evento, pudes utilizar uno de los siguientes -formatos: - -* una cadena que se refiere al nombre de un método de la clase comportamiento, como el ejemplo anterior; -* una matriz con un objeto o nombre de la clase, y el nombre de un método, por ejemplo, `[$object, 'nombreMétodo']`; -* una función anónima. - -El formato de un controlador de eventos tendría que ser como se describe a continuación, donde `$event` se refiere al -parámetro `evento`. Por favor, visita la sección [Eventos](concept-events.md) para obtener más información acerca de -eventos. +También puedes desvincular *todos* los comportamientos: ```php -function ($event) { -} +$component->detachBehaviors(); ``` -Utilizando `TimestampBehavior` +Utilizando `TimestampBehavior` ----------------------------- -Para terminar, vamos a echar un vistazo a [[yii\behaviors\TimestampBehavior]] - un comportamiento que soporta de forma -automática la actualización de atributos `timestamp` (sellos de tiempo) de un [[yii\db\ActiveRecord|Registro Activo]] -(Active Record) cuando éste está siendo guardado. +Para terminar, vamos a echar un vistazo a [[yii\behaviors\TimestampBehavior]]. Este comportamiento soporta de forma +automática la actualización de atributos timestamp de un modelo [[yii\db\ActiveRecord|Registro Activo]] +(Active Record) en cualquier momento donde se guarda el modelo (ej., en la inserción o actualización). Primero, vincula este comportamiento a la clase [[yii\db\ActiveRecord|Active Record]] que desees utilizar. @@ -300,7 +286,7 @@ La configuración del comportamiento anterior especifica que * cuando el registro está siendo insertado, el comportamiento debe asignar el sello de tiempo actual a los atributos `created_at` y `updated_at`; * cuando el registro está siendo actualizado, el comportamiento debe asignar el sello de tiempo actual al atributo - `updated_at. + `updated_at`. Ahora si tienes un objeto `User` e intentas guardarlo, descubrirás que sus campos `created_at` y `updated_at` están automáticamente actualizados con el sello de tiempo actual: @@ -313,26 +299,25 @@ echo $user->created_at; // muestra el sello tiempo actual (timestamp) ``` El comportamiento [[yii\behaviors\TimestampBehavior|TimestampBehavior]] también ofrece un método muy útil llamado -[[yii\behaviors\TimestampBehavior::touch()|touch()]], que asigna el sello de tiempo actual a un atributo especificado y -lo guarda automáticamente en la base de datos: +[[yii\behaviors\TimestampBehavior::touch()|touch()]], que asigna el sello de tiempo actual a un atributo especificado y lo guarda automáticamente en la base de datos: ```php $user->touch('login_time'); ``` -Comparación con Traits +Comparación con Traits ---------------------- Mientras que los comportamientos son similares a [traits](http://www.php.net/traits) en cuanto que ambos "inyectan" sus métodos y propiedades a la clase primaria, son diferentes en muchos aspectos. Tal y como se describe abajo, los dos -tienen sus ventajas y desventajas. Son much mejor descritos como complementos y no como reemplazos entre sí. +tienen sus ventajas y desventajas. Son más como complementos el uno al otro en lugar de alternativas. -### Las Ventajas de los Comportamientos +### Razones para utilizar comportamientos -Las clases de comportamientos (Behaviors), como todas las clases, soportan herencias. Traits, por otro lado, pueden ser -considerados como un copia-y-pega de PHP. Los Traits no soportan la herencia de clases. +Las clases de comportamientos, como todas las clases, soportan herencias. Traits, por otro lado, pueden ser +considerados como un copia-y-pega de PHP. Ellos no soportan la herencia de clases. Los comportamientos pueden ser asociados y desasociados a un componente dinámicamente sin necesidad de que la clase del componente sea modificada. Para usar un trait, debes modificar la clase que la usa. @@ -343,14 +328,13 @@ Los comportamientos pueden personalizar la ejecución de un componente al respon Cuando hay un conflicto de nombre entre los diferentes comportamientos vinculados a un mismo componente, el conflicto es automáticamente resuelto respetando al que ha sido asociado primero. -El conflicto de nombres en traits requiere que manualmente sean resueltos cambiando el nombre de las propiedades o métodos -afectados. +El conflicto de nombres en traits requiere que manualmente sean resueltos cambiando el nombre de las propiedades o métodos afectados. -### Las Ventajas de los Traits +### Razones para utilizar los Traits Los Traits son mucho más eficientes que los comportamientos debido a que los últimos son objetos que consumen tiempo y memoria. -Los IDEs (Programas de desarrollo) trabajan mucho mejor con traits ya que forman parte del lenguaje PHP. +Los IDEs (Programas de desarrollo) son más amigables con traits ya que son una construcción del lenguaje nativo. diff --git a/docs/guide-es/concept-components.md b/docs/guide-es/concept-components.md index 78003cd..b00ca26 100644 --- a/docs/guide-es/concept-components.md +++ b/docs/guide-es/concept-components.md @@ -1,17 +1,14 @@ -Componentes +Componentes =========== -Los componentes son los principales bloques de construcción de las aplicaciones Yii. Los componentes son instancias de -[[yii\base\Component]] o de una clase extendida. Las tres características principales que los componentes proporcionan +Los componentes son los principales bloques de construcción de las aplicaciones Yii. Los componentes son instancias de [[yii\base\Component]] o de una clase extendida. Las tres características principales que los componentes proporcionan a las otras clases son: * [Propiedades](concept-properties.md) * [Eventos](concept-events.md) * [Comportamientos](concept-behaviors.md) -Por separado y combinadas, estas características hacen que las clases Yii sean mucho mas personalizables y sean mucho -más fáciles de usar. Por ejemplo, el incluido [[yii\jui\DatePicker|widget de selección de fecha]], un componente de la -interfaz de usuario, puede ser utilizado en una [vista](structure-view.md) para generar un selector de fechas interactivo: +Por separado y combinadas, estas características hacen que las clases Yii sean mucho mas personalizables y sean mucho más fáciles de usar. Por ejemplo, el incluido [[yii\jui\DatePicker|widget de selección de fecha]], un componente de la interfaz de usuario, puede ser utilizado en una [vista](structure-view.md) para generar un DatePicker interactivo: ```php use yii\jui\DatePicker; @@ -25,22 +22,16 @@ echo DatePicker::widget([ ]); ``` -Las propiedades del widget son facilmente modificables porque la clase se extiende de [[yii\base\Component]]. +Las propiedades del widget son fácilmente modificables porque la clase se extiende de [[yii\base\Component]]. -Mientras que los componentes son muy potentes, son un poco más pesados que los objetos normales, debido al hecho de que -necesitan más memoria y tiempo de CPU para poder soportar [eventos](concept-events.md) y [comportamientos](concept-behaviors.md) en particular. -Si tus componentes no necesitan estas dos características, deberías considerar extender tu componente directamente de -[[yii\base\Object]] en vez de [[yii\base\Component]]. De esta manera harás que tus componentes sean mucho más eficientes que -que objetos PHP normales, pero con el añadido soporte para [propiedades](concept-properties.md). +Mientras que los componentes son muy potentes, son un poco más pesados que los objetos normales, debido al hecho de que necesitan más memoria y tiempo de CPU para poder soportar [eventos](concept-events.md) y [comportamientos](concept-behaviors.md) en particular. +Si tus componentes no necesitan estas dos características, deberías considerar extender tu componente directamente de [[yii\base\Object]] en vez de [[yii\base\Component]]. De esta manera harás que tus componentes sean mucho más eficientes que objetos PHP normales, pero con el añadido soporte para [propiedades](concept-properties.md). -Cuando extiendes tu clase de [[yii\base\Component]] o [[yii\base\Object]], se recomienda que sigas las siguientes -convenciones: +Cuando extiendes tu clase de [[yii\base\Component]] o [[yii\base\Object]], se recomienda que sigas las siguientes convenciones: -- Si sobrescribes el constructor, especifica un parámetro `$config` como el *último* parámetro del constructor, y después - pasa este parámetro al constructor de la clase "padre". -- Siempre llama al constructor del "padre" al *final* de su propio constructor. -- Si sobrescribes el método [[yii\base\Object::init()]], asegúrate de que llamas a la implementación de la clase "padre" - *al principio* de tu método `init`. +- Si sobrescribes el constructor, especifica un parámetro `$config` como el *último* parámetro del constructor, y después pasa este parámetro al constructor padre. +- Siempre llama al constructor padre al *final* de su propio constructor. +- Si sobrescribes el método [[yii\base\Object::init()]], asegúrese de llamar la implementación padre de `init` * al principio * de su método` init`. Por ejemplo: @@ -65,7 +56,7 @@ class MyClass extends Object { parent::init(); - // ... inicialización despues de la configuración esta siendo aplicada + // ... inicialización después de la configuración esta siendo aplicada } } ``` @@ -82,19 +73,14 @@ $component = \Yii::createObject([ ], [1, 2]); ``` -> Información: Mientras que el enfoque de llamar [[Yii::createObject()]] parece mucho más complicado, es mucho más potente - debido al hecho de que se implementa en la parte superior de un [contenedor de inyección de dependencia](concept-di-container.md). +> Información: Mientras que el enfoque de llamar [[Yii::createObject()]] parece mucho más complicado, es mucho más potente debido al hecho de que se implementa en la parte superior de un [contenedor de inyección de dependencia](concept-di-container.md). La clase [[yii\base\Object]] hace cumplir el siguiente ciclo de vida del objeto: 1. Pre-inicialización en el constructor. Puedes establecer los valores predeterminados de propiedades aquí. -2. Configuración del objeto a través de `$config`. La configuración puede sobrescribir los valores prdeterminados dentro - del constructor. -3. Post-inicialización dentro de [[yii\base\Object::init()|init()]]. Puedes sobrescribir este método para realizar - comprobaciones de validez y normalización de las propiedades. -4. LLamadas a métodos del objeto. +2. Configuración del objeto a través de `$config`. La configuración puede sobrescribir los valores prdeterminados dentro del constructor. +3. Post-inicialización dentro de [[yii\base\Object::init()|init()]]. Puedes sobrescribir este método para realizar comprobaciones de validez y normalización de las propiedades. +4. Llamadas a métodos del objeto. - -Los tres primeros pasos ocurren dentro del constructor del objeto. Esto significa que una vez obtengas la instancia de -un objeto, ésta ha sido inicializada para que puedas utilizarla adecuadamente. +Los tres primeros pasos ocurren dentro del constructor del objeto. Esto significa que una vez obtengas la instancia de un objeto, ésta ha sido inicializada para que puedas utilizarla adecuadamente. diff --git a/docs/guide-es/concept-configurations.md b/docs/guide-es/concept-configurations.md new file mode 100644 index 0000000..a59447f --- /dev/null +++ b/docs/guide-es/concept-configurations.md @@ -0,0 +1,229 @@ +Configuración +============== + +Las configuraciones se utilizan ampliamente en Yii al crear nuevos objetos o inicializar los objetos existentes. Las configuraciones por lo general incluyen el nombre de la clase del objeto que se está creando, y una lista de los valores iniciales que deberían ser asignadas a las del [propiedades](concept-properties.md) objeto. Las configuraciones también pueden incluir una lista de manipuladores que deban imponerse a del objeto [eventos](concept-events.md) y/o una lista de [comportamientos](concept-behaviors.md) que también ha de atribuirse al objeto. + +A continuación, una configuración que se utiliza para crear e inicializar una conexión a base de datos: + +```php +$config = [ + 'class' => 'yii\db\Connection', + 'dsn' => 'mysql:host=127.0.0.1;dbname=demo', + 'username' => 'root', + 'password' => '', + 'charset' => 'utf8', +]; + +$db = Yii::createObject($config); +``` +El método [[Yii::createObject()]] toma una matriz de configuración como su argumento, y crea un objeto intanciando la clase llamada en la configuración. Cuando se crea una instancia del objeto, el resto de la configuración se utilizará para inicializar las propiedades del objeto, controladores de eventos y comportamientos. + +Si usted ya tiene un objeto, puede usar [[Yii::configure()]] para inicializar las propiedades del objeto con una matriz de configuración: + +```php +Yii::configure($object, $config); +``` + +Tenga en cuenta que en este caso, la matriz de configuración no debe contener un elemento `class`. + +## Formato de Configuración + +El formato de una configuración se puede describir formalmente como: + +```php +[ + 'class' => 'ClassName', + 'propertyName' => 'propertyValue', + 'on eventName' => $eventHandler, + 'as behaviorName' => $behaviorConfig, +] +``` + +donde + +* El elemento `class` especifica un nombre de clase completo para el objeto que se está creando. +* Los elementos `propertyName` especifica los valores iniciales de la propiedad con nombre. Las claves son los nombres de las propiedades y los valores son los valores iniciales correspondientes. Sólo los miembros de variables públicas y [propiedades](concept-properties.md) definidas por getters/setters se pueden configurar. +* Los elementos `on eventName` especifican qué manipuladores deberán adjuntarse al del objeto [eventos](concept-events.md). Observe que las claves de matriz se forman prefijando nombres de eventos con `on`. Por favor, consulte la sección [Eventos](concept-events.md) para los formatos de controlador de eventos compatibles. +* Los elementos `as behaviorName` especifican qué [comportamientos](concept-behaviors.md) deben adjuntarse al objeto. Observe que las claves de matriz se forman prefijando nombres de comportamiento con `as`; el valor, `$behaviorConfig`, representa la configuración para la creación de un comportamiento, como una configuración normal descrita aquí. + +A continuación se muestra un ejemplo de una configuración con los valores de propiedad iniciales, controladores de eventos y comportamientos: + +```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 ... + ], +] +``` + + +## Usando Configuraciones + +Las configuraciones se utilizan en muchos lugares en Yii. Al comienzo de esta sección, hemos demostrado cómo crear un objeto según una configuración mediante el uso de [[Yii::CreateObject()]]. En este apartado, vamos a describir configuraciones de aplicaciones y configuraciones widget - dos principales usos de configuraciones. + + +### Configuraciones de aplicación + +Configuración para una [aplicación](structure-applications.md) es probablemente una de las configuraciones más complejas. Esto se debe a que la clase [[yii\web\Application|aplicación]] tiene un montón de propiedades y eventos configurables. Más importante aún, su propiedad [[yii\web\Application::components|componentes]] que puede recibir una gran variedad de configuraciones para crear componentes que se registran a través de la aplicación. Lo siguiente es un resumen del archivo de configuración de la aplicación para la [plantilla básica de la aplicación](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 configuración no tiene una clave `class`. Esto es porque se utiliza como sigue en un [script de entrada](structure-entry-scripts.md), donde ya se le da el nombre de la clase, + +```php +(new yii\web\Application($config))->run(); +``` + +Para más detalles sobre la configuración de la propiedad `components` de una aplicación se puede encontrar en la sección [Aplicación](structure-applications.md) y la sección [Localizador de Servicio](concept-service-locator.md). + + +### Configuración Widget + +Cuando se utiliza [widgets](structure-widgets.md), a menudo es necesario utilizar las configuraciones para personalizar las propiedades de widgets. Tanto los metodos [[yii\base\Widget::widget()]] y [[yii\base\Widget::begin()]] pueden usarse para crear un widget. Toman un arreglo de configuración, como el siguiente, + +```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], + ], +]); +``` + +El código anterior crea un widget `Menu` e inicializa su propiedad `activeItems` en falsa. La propiedad `items` también se configura con elementos de menú que se muestran. + +Tenga en cuenta que debido a que el nombre de la clase ya está dado, la matriz de configuración no deben tener la clave `class`. + + +## Archivos de Configuración + +Cuando una configuración es muy compleja, una práctica común es almacenarla en uno o múltiples archivos PHP, conocidos como *archivos de configuración*. Un archivo de configuración devuelve un array de PHP que representa la configuración. Por ejemplo, es posible mantener una configuración de la aplicación en un archivo llamado `web.php`, como el siguiente, + +```php +return [ + 'id' => 'basic', + 'basePath' => dirname(__DIR__), + 'extensions' => require(__DIR__ . '/../vendor/yiisoft/extensions.php'), + 'components' => require(__DIR__ . '/components.php'), +]; +``` + +Debido a que la configuración `componentes` es compleja también, se guarda en un archivo separado llamado `components.php` y "requerir" este archivo en `web.php` como se muestra arriba. El contenido de `components.php` es el siguiente, + +```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', + ], +]; +``` + +Para obtener una configuración almacenada en un archivo de configuración, simplemente "requerir" este, como el siguiente: + +```php +$config = require('path/to/web.php'); +(new yii\web\Application($config))->run(); +``` + + +## Configuraciones por Defecto + +El método [[Yii::createObject()]] es implementado en base a [contenedor de inyección de dependencia](concept-di-container.md). Le permite especificar un conjunto de los llamados *configuraciones predeterminadas* que se aplicarán a todos los casos de las clases especificadas cuando se crean utilizando [[Yii::createObject()]]. Las configuraciones por defecto se puede especificar llamando `Yii::$container->set()` en el código [bootstrapping](runtime-bootstrapping.md). + +Por ejemplo, si desea personalizar [[yii\widgets\LinkPager]] para que TODO enlace de búsqueda muestre como máximo 5 botones de página (el valor por defecto es 10), puede utilizar el siguiente código para lograr este objetivo, + +```php +\Yii::$container->set('yii\widgets\LinkPager', [ + 'maxButtonCount' => 5, +]); +``` + +Sin utilizar las configuraciones predeterminadas, usted tendría que configurar `maxButtonCount` en cada lugar en el que utiliza enlace paginador. + +## Constantes de Entorno + +Las configuraciones a menudo varían de acuerdo al entorno en que se ejecuta una aplicación. Por ejemplo, en el entorno de desarrollo, es posible que desee utilizar una base de datos llamada `mydb_dev`, mientras que en servidor de producción es posible que desee utilizar la base de datos `mydb_prod`. Para facilitar la conmutación de entornos, Yii proporciona una constante llamado `YII_ENV` que se puede definir en el [script de entrada](structure-entry-scripts.md) de su aplicación. Por ejemplo, + +```php +defined('YII_ENV') or define('YII_ENV', 'dev'); +``` + +Usted puede definir `YII_ENV` como uno de los valores siguientes: + +- `prod`: entorno de producción. La constante `YII_ENV_PROD` evaluará como verdadero. +Este es el valor por defecto de `YII_ENV` si no esta definida. +- `dev`: entorno de desarrollo. La constante `YII_ENV_DEV` evaluará como verdadero. +- `test`: entorno de pruebas. La constante `YII_ENV_TEST` evaluará como verdadero. + +Con estas constantes de entorno, puede especificar sus configuraciones condicionales basado en el entorno actual. Por ejemplo, la configuración de la aplicación puede contener el siguiente código para permitir que el [depurador y barra de herramientas de depuración](tool-debugger.md) en el entorno de desarrollo. + +```php +$config = [...]; + +if (YII_ENV_DEV) { + // configuration adjustments for 'dev' environment + $config['bootstrap'][] = 'debug'; + $config['modules']['debug'] = 'yii\debug\Module'; +} + +return $config; +``` diff --git a/docs/guide-es/concept-di-container.md b/docs/guide-es/concept-di-container.md new file mode 100644 index 0000000..80eea95 --- /dev/null +++ b/docs/guide-es/concept-di-container.md @@ -0,0 +1,324 @@ +Contenedor de Inyección de Dependencias +======================================= + +Un contenedor de Inyección de Dependencias (ID), es un objeto que sabe como instancias y configurar objetos y sus +objetos dependientes. El [articulo de Martin](http://martinfowler.com/articles/injection.html) contiene una buena +explicación de porque son útiles los contenedores de ID. A continuación explicaremos como usar el contenedor de ID que +proporciona Yii. + +Inyección de Dependencias +------------------------- + +Yii proporciona la función de contenedor de ID mediante la clase [[yii\di\Container]]. Soporta los siguientes tipos +de ID: + +* Inyección de constructores; +* Inyección de setters y propiedades; +* Inyección de [llamadas de retorno PHP](http://php.net/manual/es/language.types.callable.php); + +### Inyección de Constructores + +El contenedor de ID soporta inyección de constructores con la ayuda de los indicios (hint) de tipo para los parámetros del +constructor. Los indicios de tipo le proporcionan información al contenedor para saber cuáles son las clases o +interfaces dependientes al usarse para crear un nuevo objeto. El contenedor intentara obtener las instancias de las +clases o interfaces dependientes y las inyectará dentro del nuevo objeto mediante el constructor. Por ejemplo, + +```php +class Foo +{ + public function __construct(Bar $bar) + { + } +} + +$foo = $container->get('Foo'); +// que es equivalente a: +$bar = new Bar; +$foo = new Foo($bar); +``` + +### Inyección de Setters y Propiedades + +La inyección de setters y propiedades se admite a través de [configuraciones](concept-configurations.md). Cuando se +registra una dependencia o se crea un nuevo objeto, se puede proporcionar una configuración que usará el contenedor +para inyectar las dependencias a través de sus correspondientes setters y propiedades. Por ejemplo, + +```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'), +]); +``` + +### Inyección de Llamadas de retorno PHP + +En este caso, el contenedor usará una llamada de retorno PHP registrada para construir una nueva instancia de una +clase. La llamada de retorno se responsabiliza de que dependencias debe inyectar al nuevo objeto creado. Por ejemplo, + +```php +$container->set('Foo', function () { + return new Foo(new Bar); +}); + +$foo = $container->get('Foo'); +``` + +Registro de dependencias +------------------------ + +Se puede usar [[yii\di\Container::set()]] para registrar dependencias. El registro requiere un nombre de dependencia +así como una definición de dependencia. Un nombre de dependencia puede ser un nombre de clase, un nombre de interfaz, +o un nombre de alias; y una definición de dependencia puede ser un nombre de clase, un array de configuración, o una +llamada de retorno PHP. + +```php +$container = new \yii\di\Container; + +// registra un nombre de clase como tal. Puede se omitido. +$container->set('yii\db\Connection'); + +// registra una interfaz +// Cuando una clase depende de una interfaz, la clase correspondiente +// se instanciará como un objeto dependiente +$container->set('yii\mail\MailInterface', 'yii\swiftmailer\Mailer'); + +// registra un nombre de alias. Se puede usar $container->get('foo') +// para crear una instancia de Connection +$container->set('foo', 'yii\db\Connection'); + +// registrar una clase con configuración. La configuración +// se aplicara cuando la clase se instancie por get() +$container->set('yii\db\Connection', [ + 'dsn' => 'mysql:host=127.0.0.1;dbname=demo', + 'username' => 'root', + 'password' => '', + 'charset' => 'utf8', +]); + +// registra un nombre de alias con configuración de clase +// En este caso, se requiere un elemento "clase" para especificar la clase +$container->set('db', [ + 'class' => 'yii\db\Connection', + 'dsn' => 'mysql:host=127.0.0.1;dbname=demo', + 'username' => 'root', + 'password' => '', + 'charset' => 'utf8', +]); + +// registra una llamada de retorno de PHP +// La llamada de retorno sera ejecutada cada vez que se ejecute $container->get('db') +$container->set('db', function ($container, $params, $config) { + return new \yii\db\Connection($config); +}); + +// registra un componente instancia +// $container->get('pageCache') devolverá la misma instancia cada vez que se ejecute +$container->set('pageCache', new FileCache); +``` + +> Consejo: Si un nombre de dependencia es el mismo que la definición de dependencia, no es necesario registrarlo con + el contenedor de ID. + +Una dependencia registrada mediante `set()` generará una instancia cada vez que se necesite la dependencia. Se puede +usar [[yii\di\Container::setSingleton()]] para registrar una dependencia que genere una única instancia: + +```php +$container->setSingleton('yii\db\Connection', [ + 'dsn' => 'mysql:host=127.0.0.1;dbname=demo', + 'username' => 'root', + 'password' => '', + 'charset' => 'utf8', +]); +``` + +Resolución de Dependencias +-------------------------- + +Una ves se hayan registrado las dependencias, se puede usar el contenedor de ID para crear nuevos objetos, y el +contenedor resolverá automáticamente las dependencias instanciándolas e inyectándolas dentro de los nuevos objetos +creados. La resolución de dependencias es recursiva, esto significa que si una dependencia tiene otras dependencias, +estas dependencias también se resolverán automáticamente. + +Se puede usar [[yii\di\Container::get()]] para crear nuevos objetos. El método obtiene el nombre de dependencia, que +puede ser un nombre de clase, un nombre de interfaz o un nombre de alias. El nombre de dependencia puede estar +registrado o no mediante `set()` o `setSingleton()`. Se puede proporcionar opcionalmente un listado de los parámetros +del constructor de clase y una [configuración](concept-configurations.md) para configurar los nuevos objetos creados. +Por ejemplo, + +```php +// "db" ha sido registrado anteriormente como nombre de alias +$db = $container->get('db'); + +// equivalente a: $engine = new \app\components\SearchEngine($apiKey, ['type' => 1]); +$engine = $container->get('app\components\SearchEngine', [$apiKey], ['type' => 1]); +``` + +Por detrás, el contenedor de ID efectúa mucho más trabajo la creación de un nuevo objeto. El contenedor primero +inspeccionará la clase constructora para encontrar los nombres de clase o interfaces dependientes y después +automáticamente resolverá estas dependencias recursivamente. + +El siguiente código muestra un ejemplo más sofisticado. La clase `UserLister` depende del un objeto que implementa la +interfaz `UserFinderInterface`; la clase `UserFinder` implementa la interfaz y depende del objeto `Connection`. Todas +estas dependencias se declaran a través de insinuaciones (hinting) de los parámetros del constructor de clase. Con el +registro de dependencia de propiedades, el contenedor de ID puede resolver las dependencias automáticamente y crear +una nueva instancia de `UserLister` con una simple llamada a `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'); + +// que es equivalente a: + +$db = new \yii\db\Connection(['dsn' => '...']); +$finder = new UserFinder($db); +$lister = new UserLister($finder); +``` + +Uso Practico +------------ + +Yii crea un contenedor de ID cuando se incluye el archivo `Yii.php` en el +[script de entrada](structure-entry-scripts.md) de la aplicación. Cuando se llama a [[Yii::createObject()]] el método +realmente llama al contenedor del método [[yii\di\Container::get()|get()]] para crear un nuevo objeto. Como se ha +comentado anteriormente, el contenedor de ID resolverá automáticamente las dependencias (si las hay) y las inyectará +dentro del nuevo objeto creado. Debido a que Yii utiliza [[Yii::createObject()]] en la mayor parte del núcleo (core) +para crear nuevo objetos, podemos personalizar los objetos globalmente para que puedan tratar con [[Yii::$container]]. + +Por ejemplo, se puede personalizar globalmenete el numero predeterminado de números de botones de paginación de +[[yii\widgets\LinkPager]]: + +```php +\Yii::$container->set('yii\widgets\LinkPager', ['maxButtonCount' => 5]); +``` + +Ahora si se usa el widget en una vista con el siguiente código, la propiedad `maxButtonCount` será inicializada con +valor 5 en lugar de 10 que es el valor predeterminado definido en la clase. + +```php +echo \yii\widgets\LinkPager::widget(); +``` + +Se puede sobrescribir el valor establecido mediante el contenedor de ID, como a continuación: + +```php +echo \yii\widgets\LinkPager::widget(['maxButtonCount' => 20]); +``` + +Otro ejemplo es aprovechar la ventaja de la inyección automática de constructores de contenedores de ID. Asumiendo que +la clase controlador depende de otros objetos, tales como un servicio de reservas de hotel. Se puede declarar una +dependencia a través de un parámetro del constructor y permitir al contenedor de ID resolverla por nosotros. + +```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 se accede al controlador desde el navegador, veremos un error advirtiendo que `BookingInterface` no puede ser +instanciada. Esto se debe a que necesitamos indicar al contenedor de ID como tratar con esta dependencia: + +```php +\Yii::$container->set('app\components\BookingInterface', 'app\components\BookingService'); +``` + +Ahora si se accede al contenedor nuevamente, se creará una instancia de `app\components\BookingService` y se inyectará +a como tercer parámetro al constructor del controlador. + +Cuando Registrar Dependencias +----------------------------- + +El registro de dependencias debe hacerse lo antes posible debido a que las dependencias se necesitan cuando se crean +nuevos objetos. A continuación se listan practicas recomendadas: + +* Siendo desarrolladores de una aplicación, podemos registrar dependencias en el + [script de entrada](structure-entry-scripts.md) o en un script incluido en el script de entrada. +* Siendo desarrolladores de una [extension](structure-extensions.md) redistribuible, podemos registrar dependencias en + la clase de boostraping de la extensión. + +Resumen +------- + +Tanto la inyección de dependencias como el [localizador de servicios](concept-service-locator.md) son patrones de +diseño populares que permiten construir software con acoplamiento flexible y más fácil de testear. Se recomienda +encarecida la lectura del articulo de [Martin](http://martinfowler.com/articles/injection.html) para obtener una mejor +comprensión de la inyección de dependencias y de la localización de servicios. + +Yii implementa su propio [localizador de servicios](concept-service-locator.md) por encima del contenedor de ID. +Cuando un localizador de servicios intenta crear una nueva instancia de objeto, se desviará la llamada al contenedor +de ID. Este último resolverá las dependencias automáticamente como se ha descrito anteriormente. diff --git a/docs/guide-es/concept-events.md b/docs/guide-es/concept-events.md new file mode 100644 index 0000000..741cc5d --- /dev/null +++ b/docs/guide-es/concept-events.md @@ -0,0 +1,292 @@ +Eventos +======= + +Los eventos permiten inyectar código dentro de otro código existente en ciertos puntos de ejecución. Se pueden adjuntar +código personalizado a un evento, cuando se lance (triggered), el código se ejecutará automáticamente. Por ejemplo, un +objeto mailer puede lanzar el evento `messageSent` cuando se envía un mensaje correctamente. Si se quiere rastrear +el correcto envío del mensaje, se puede, simplemente, añadir un código de seguimiento al evento `messageSent`. + +Yii introduce una clase base [[yii\base\Component]] para soportar eventos. Si una clase necesita lanzar un evento, +este debe extender a [[yii\base\Component]] o a una clase hija. + +Gestor de Eventos +----------------- + +Un gestor de eventos es una +[llamada de retorno PHP (PHP callback)](http://php.net/manual/es/language.types.callable.php) que se ejecuta cuando se +lanza el evento al que corresponde. Se puede usar cualquier llamada de retorno de las enumeradas a continuación: + +- una función de PHP global especificada como una cadena de texto (sin paréntesis), ej. `'trim'`; +- un método de objeto especificado como un array de un objeto y un nombre de método como una cadena de texto + (sin paréntesis), ej. `[$object, 'methodNAme']`; +- un método de clase estático especificado como un array de un nombre de clase y un método como una cadena de texto + (sin paréntesis), ej. `[$class, 'methodName']`; +- una función anónima, ej. `function ($event) { ... }`. + +La firma de un gestor de eventos es: + +```php +function ($event) { + // $event es un objeto de yii\base\Event o de una clase hija +} +``` + +Un gestor de eventos puede obtener la siguiente información acerca de un evento ya sucedido mediante el parámetro +`$event`: + +- [[yii\base\Event::name|nombre del evento]] +- [[yii\base\Event::sender|evento enviando]]: el objeto desde el que se ha ejecutado `trigger()` +- [[yii\base\Event::data|custom data]]: los datos que se proporcionan al adjuntar el gestor de eventos + (se explicará más adelante) + + +Añadir Gestores de Eventos +-------------------------- + +Se puede añadir un gestor a un evento llamando al método [[yii\base\Component::on()]]. Por ejemplo: + +```php +$foo = new Foo; + +// este gestor es una función global +$foo->on(Foo::EVENT_HELLO, 'function_name'); + +// este gestor es un método de objeto +$foo->on(Foo::EVENT_HELLO, [$object, 'methodName']); + +// este gestor es un método de clase estática +$foo->on(Foo::EVENT_HELLO, ['app\components\Bar', 'methodName']); + +// este gestor es una función anónima +$foo->on(Foo::EVENT_HELLO, function ($event) { + // event handling logic +}); +``` + +También se pueden adjuntar gestores de eventos mediante [configuraciones](concept-configurations.md). Se pueden +encontrar más de talles en la sección [Configuraciones](concept-configurations.md#configuration-format). + +Cuando se adjunta un gestor de eventos, se pueden proporcionar datos adicionales como tercer parámetro de +[[yii\base\Component::on()]]. El gestor podrá acceder a los datos cuando se lance el evento y se ejecute el gestor. +Por ejemplo: + +```php +// El siguiente código muestra "abc" cuando se lanza el evento +// ya que $event->data contiene los datos enviados en el tercer parámetro de "on" +$foo->on(Foo::EVENT_HELLO, 'function_name', 'abc'); + +function function_name($event) { + echo $event->data; +} +``` + +Ordenación de Gestores de Eventos +--------------------------------- + +Se puede adjuntar uno o más gestores a un único evento. Cuando se lanza un evento, se ejecutarán los gestores adjuntos +en el orden que se hayan añadido al evento. Si un gestor necesita parar la invocación de los gestores que le siguen, +se puede establecer la propiedad [[yii\base\Event::handled]] del parámetro `$event` para que sea `true`: + +```php +$foo->on(Foo::EVENT_HELLO, function ($event) { + $event->handled = true; +}); +``` + +De forma predeterminada, cada nuevo gestor añadido se pone a la cola de la lista de gestores del evento. Por lo tanto, +el gestor se ejecutará en el último lugar cuando se lance el evento. Para insertar un nuevo gestor al principio de la +cola de gestores para que sea ejecutado primero, se debe llamar a [[yii\base\Component::on()]], pasando al cuarto +parámetro `$append` el valor false: + +```php +$foo->on(Foo::EVENT_HELLO, function ($event) { + // ... +}, $data, false); +``` + +Lanzamiento de Eventos +---------------------- + +Los eventos se lanzan llamando al método [[yii\base\Component::trigger()]]. El método requiere un *nombre de evento*, +y de forma opcional un objeto de evento que describa los parámetros que se enviarán a los gestores de eventos. Por +ejemplo: + +```php +namespace app\components; + +use yii\base\Component; +use yii\base\Event; + +class Foo extends Component +{ + const EVENT_HELLO = 'hello'; + + public function bar() + { + $this->trigger(self::EVENT_HELLO); + } +} +``` + +Con el código anterior, cada llamada a `bar()` lanzará un evento llamado `hello` + +> Consejo: Se recomienda usar las constantes de clase para representar nombres de eventos. En el anterior ejemplo, la + constante `EVENT_HELLO` representa el evento `hello`. Este enfoque proporciona tres beneficios. Primero, previene + errores tipográficos. Segundo, puede hacer que los IDEs reconozcan los eventos en las funciones de auto-completado. + Tercero, se puede ver que eventos soporta una clase simplemente revisando la declaración de constantes. + +A veces cuando se lanza un evento se puede querer pasar información adicional al gestor de eventos. Por ejemplo, un +mailer puede querer enviar la información del mensaje para que los gestores del evento `messageSent` para que los +gestores puedan saber las particularidades del mensaje enviado. Para hacerlo, se puede proporcionar un objeto de tipo +evento como segundo parámetro al método [[yii\base\Component::trigger()]]. El objeto de tipo evento debe ser una +instancia de la clase [[yii\base\Event]] o de su clase hija. Por ejemplo: + +```php +namespace app\components; + +use yii\base\Component; +use yii\base\Event; + +class MessageEvent extends Event +{ + public $message; +} + +class Mailer extends Component +{ + const EVENT_MESSAGE_SENT = 'messageSent'; + + public function send($message) + { + // ...enviando $message... + + $event = new MessageEvent; + $event->message = $message; + $this->trigger(self::EVENT_MESSAGE_SENT, $event); + } +} +``` + +Cuando se lanza el método [[yii\base\Component::trigger()]], se ejecutarán todos los gestores adjuntos al evento. + +Desadjuntar Gestores de Evento +------------------------------ + +Para desadjuntar un gestor de un evento, se puede ejecutar el método [[yii\base\Component::off()]]. Por ejemplo: + +```php +// el gestor es una función global +$foo->off(Foo::EVENT_HELLO, 'function_name'); + +// el gestor es un método de objeto +$foo->off(Foo::EVENT_HELLO, [$object, 'methodName']); + +// el gestor es un método estático de clase +$foo->off(Foo::EVENT_HELLO, ['app\components\Bar', 'methodName']); + +// el gestor es una función anónima +$foo->off(Foo::EVENT_HELLO, $anonymousFunction); +``` + +Tenga en cuenta que en general no se debe intentar desadjuntar las funciones anónimas a no ser que se almacene donde +se ha adjuntado al evento. En el anterior ejemplo, se asume que la función anónima se almacena como variable +`$anonymousFunction`. + +Para desadjuntar TODOS los gestores de un evento, se puede llamar [[yii\base\Component::off()]] sin el segundo +parámetro: + +```php +$foo->off(Foo::EVENT_HELLO); +``` + +Nivel de Clase (Class-Level) Gestores de Eventos +------------------------------------------------ + +En las subsecciones anteriores se ha descrito como adjuntar un gestor a un evento a *nivel de instancia*. A veces, se +puede querer que un gestor responda todos los eventos de *todos* las instancias de una clase en lugar de una instancia +especifica. En lugar de adjuntar un gestor de eventos a una instancia, se puede adjuntar un gestor a *nivel de clase* +llamando al método estático [[yii\base\Event::on()]]. + +Por ejemplo, un objeto de tipo [Active Record](db-active-record.md) lanzará un evento +[[yii\db\BaseActiveRecord::EVENT_AFTER_INSERT|EVENT_AFTER_INSERT]] cada vez que inserte un nuevo registro en la base +de datos. Para poder registrar las inserciones efectuadas por *todos* los objetos +[Active Record](db-active-record.md), se puede usar el siguiente código: + +```php +use Yii; +use yii\base\Event; +use yii\db\ActiveRecord; + +Event::on(ActiveRecord::className(), ActiveRecord::EVENT_AFTER_INSERT, function ($event) { + Yii::trace(get_class($event->sender) . ' is inserted'); +}); +``` + +Se invocará al gestor de eventos cada vez que una instancia de [[yii\db\ActiveRecord|ActiveRecord]], o de uno de sus +clases hijas, lance un evento de tipo [[yii\db\BaseActiveRecord::EVENT_AFTER_INSERT|EVENT_AFTER_INSERT]]. Se puede +obtener el objeto que ha lanzado el evento mediante `$event->sender` en el gestor. + +Cuando un objeto lanza un evento, primero llamará los gestores a nivel de instancia, y a continuación los gestores a +nivel de clase. + +Se puede lanzar un evento de tipo *nivel de clase* llamando al método estático [[yii\base\Event::trigger()]]. Un +evento de nivel de clase no se asocia a un objeto en particular. Como resultado, esto provocará solamente la +invocación de los gestores de eventos a nivel de clase. + +```php +use yii\base\Event; + +Event::on(Foo::className(), Foo::EVENT_HELLO, function ($event) { + echo $event->sender; // displays "app\models\Foo" +}); + +Event::trigger(Foo::className(), Foo::EVENT_HELLO); +``` + +Tenga en cuenta que en este caso, el `$event->sender` hace referencia al nombre de la clase que lanza el evento en +lugar de a la instancia del objeto. + +> Nota: Debido a que los gestores a nivel de clase responderán a los eventos lanzados por cualquier instancia de la +clase, o cualquier clase hija, se debe usar con cuidado, especialmente en las clases de bajo nivel (low-level), tales +como [[yii\base\Object]]. + +Para desadjuntar un gestor de eventos a nivel de clase, se tiene que llamar a [[yii\base\Event::off()]]. Por ejemplo: + +```php +// desadjunta $handler +Event::off(Foo::className(), Foo::EVENT_HELLO, $handler); + +// desadjunta todos los gestores de Foo::EVENT_HELLO +Event::off(Foo::className(), Foo::EVENT_HELLO); +``` + +Eventos Globales +---------------- + +Yii soporta los llamados *eventos globales*, que en realidad es un truco basado en el gestor de eventos descrito +anteriormente. El evento global requiere un Singleton globalmente accesible, tal como la instancia de +[aplicación](structure-applications.md) en si misma. + +Para crear un evento global, un evento remitente (event sender) llama al método `trigger()` del Singleton para lanzar +el evento, en lugar de llamar al propio método `trigger()` del remitente. De forma similar, los gestores de eventos se +adjuntan al evento del Singleton. Por ejemplo: + +```php +use Yii; +use yii\base\Event; +use app\components\Foo; + +Yii::$app->on('bar', function ($event) { + echo get_class($event->sender); // muestra "app\components\Foo" +}); + +Yii::$app->trigger('bar', new Event(['sender' => new Foo])); +``` + +Un beneficio de usar eventos globales es que no se necesita un objeto cuando se adjuntan gestores a un evento para que +sean lanzados por el objeto. En su lugar, los gestores adjuntos y el lanzamiento de eventos se efectúan en el +Singleton (ej. la instancia de la aplicación). + +Sin embargo, debido a que los `namespaces` de los eventos globales son compartidos por todas partes, se les deben +asignar nombres bien pensados, como puede ser la introducción de algún `namespace` +(ej. "frontend.mail.sent", "backend.mail.sent"). diff --git a/docs/guide-es/concept-properties.md b/docs/guide-es/concept-properties.md new file mode 100644 index 0000000..82ba186 --- /dev/null +++ b/docs/guide-es/concept-properties.md @@ -0,0 +1,88 @@ +Propiedades +=========== + +En PHP, las variables miembro de clases también llamadas *propiedades*, son parte de la definición de la clase, y se +usan para representar el estado de una instancia de la clase (ej. para diferenciar una instancia de clase de otra). +A la práctica, a menudo, se puede querer gestionar la lectura o escritura de las propiedades de algunos momentos. Por +ejemplo, se puede querer eliminar los espacios en blanco (trim) de una cadena de texto cada vez que esta se asigne a +una propiedad de tipo `label`. Se *podría* usar el siguiente código para realizar esta tarea: + +```php +$object->label = trim($label); +``` + +La desventaja del código anterior es que se tendría que ejecutar `trim()` en todas las partes del código que pudieran +establecer la propiedad `label`. Si en el futuro, la propiedad `label` tiene que seguir otro funcionamiento, como por +ejemplo que la primera letra tiene que estar en mayúsculas, se tendrán que modificar todas las secciones de código que +asignen el valor a la propiedad `label`. La repetición de código conlleva a bugs, y es una practica que se tiene que +evitar en la medida de lo posible. + +Para solventar este problema, Yii introduce la clase base llamada [[yii\base\Object]] que da soporte a la definición +de propiedades basada en los métodos de clase *getter* y *setter*. Si una clase necesita más funcionalidad, debe +extender a la clase [[yii\base\Object]] o a alguna de sus hijas. + +> Información: Casi todas las clases del núcleo (core) en el framework Yii extienden a [[yii\base\Object]] o a una de + sus clases hijas. Esto significa que siempre que se encuentre un getter o un setter en una clase del núcleo, se + puede utilizar como una propiedad. + +Un método getter es un método cuyo nombre empieza por la palabra `get`: un metodo setter empieza por `set`. El nombre +añadido detrás del prefijo `get` o `set` define el nombre de la propiedad. Por ejemplo, un getter `getLabel()` y/o un +setter `setLabel()` definen la propiedad `label`, como se muestra a continuación: + +```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); + } +} +``` + +(Para ser claros, los métodos getter y setter crean la propiedad `label`, que en este caso hace una referencia interna +al nombre de atributo privado `_label`.) + +Las propiedades definidas por los getter y los setters se pueden usar como variables de clase miembro. La principal +diferencia radica en que cuando esta propiedad se lea, se ejecutará su correspondiente método getter; cuando se asigne +un valor a la propiedad, se ejecutará el correspondiente método setter. Por ejemplo: + +```php +// equivalente a $label = $object->getLabel(); +$label = $object->label; + +// equivalente a $object->setLabel('abc'); +$object->label = 'abc'; +``` + +Una propiedad definida por un getter sin un setter es de tipo *sólo lectura*. Si se intenta asignar un valor a esta +propiedad se producirá una excepción de tipo [[yii\base\InvalidCallException|InvalidCallException]]. Del mismo modo +que una propiedad definida con un setter pero sin getter será de tipo *sólo escritura*, cualquier intento de lectura +de esta propiedad producirá una excepción. No es común tener variables de tipo sólo escritura. + +Hay varias reglas especiales y limitaciones en las propiedades definidas mediante getters y setters: + +* Los nombres de estas propiedades son *case-insensitive*. Por ejemplo, `$object->label` y `$object->Label` son la + misma. Esto se debe a que los nombres de los métodos en PHP son case-insensitive. +* Si el nombre de una propiedad de este tipo es igual al de una variable miembro de la clase, la segunda tendrá + prioridad. Por ejemplo, si la anterior clase `Foo` tiene la variable miembro `label`, entonces la asignación + `$object->label = 'abc'` afectará a la *variable miembro* 'label'; no se ejecutará el método setter `setLabel()`. +* Estas variables no soportan la visibilidad. No hay diferencia en definir los métodos getter o setter en una + propiedad public, protected, o private. +* Las propiedades sólo se pueden definir por getters y setters *no estáticos*. Los métodos estáticos no se tratarán de + la misma manera. + +Volviendo de nuevo al problema descrito al principio de la guía, en lugar de ejecutar `trim()` cada vez que se asigne +un valor a `label`, ahora `trim()` sólo necesita ser invocado dentro del setter `setLabel()`. I si se tiene que añadir +un nuevo requerimiento, para que `label` empiece con una letra mayúscula, se puede modificar rápidamente el método ` +setLabel()` sin tener que modificar más secciones de código. El cambio afectará a cada asignación de `label`. \ No newline at end of file diff --git a/docs/guide-es/concept-service-locator.md b/docs/guide-es/concept-service-locator.md new file mode 100644 index 0000000..8a74ef2 --- /dev/null +++ b/docs/guide-es/concept-service-locator.md @@ -0,0 +1,71 @@ +Localizador de Servicios +======================== + +Un localizador de servicios es un objeto que sabe cómo proporcionar todo tipo de servicios (o componentes) que puede necesitar una aplicación. Dentro de un localizador de servicios, existe en cada componente como una única instancia, únicamente identificado por un ID. Se utiliza el ID para recuperar un componente desde el localizador de servicios. + +En Yii, un localizador de servicio es simplemente una instancia de [[yii\di\ServiceLocator]], o de una clase hija. + +El localizador de servicio más utilizado en Yii es el objeto *aplicación*, que se puede acceder a través de `\Yii::$app`. Los servicios que prestá son llamadas *componentes de la aplicación*, como los componentes `request`, `response`, and `urlManager`. Usted puede configurar estos componentes, o incluso cambiarlos por sus propias implementaciones fácilmente a través de la funcionalidad proporcionada por el localizador de servicios. + +Además del objeto de aplicación, cada objeto módulo es también un localizador de servicios. + +Para utilizar un localizador de servicios, el primer paso es registrar los componentes de la misma. Un componente se puede registrar a través de [[yii\di\ServiceLocator::set()]]. El código siguiente muestra diferentes maneras de registrarse componentes: + +```php +use yii\di\ServiceLocator; +use yii\caching\FileCache; + +$locator = new ServiceLocator; + +// register "cache" using a class name that can be used to create a component +$locator->set('cache', 'yii\caching\ApcCache'); + +// register "db" using a configuration array that can be used to create a component +$locator->set('db', [ + 'class' => 'yii\db\Connection', + 'dsn' => 'mysql:host=localhost;dbname=demo', + 'username' => 'root', + 'password' => '', +]); + +// register "search" using an anonymous function that builds a component +$locator->set('search', function () { + return new app\components\SolrService; +}); + +// register "pageCache" using a component +$locator->set('pageCache', new FileCache); +``` + +Una vez que el componente se ha registrado, usted puede acceder a él utilizando su ID, en una de las dos formas siguientes: + +```php +$cache = $locator->get('cache'); +// or alternatively +$cache = $locator->cache; +``` + +Como puede observarse, [[yii\di\ServiceLocator]] le permite acceder a un componente como una propiedad utilizando el ID de componente. Cuando acceda a un componente, por primera vez, [[yii\di\ServiceLocator]] utilizará la información de registro de componente para crear una nueva instancia del componente y devolverlo. Más tarde, si se accede de nuevo al componente, el localizador de servicio devolverá la misma instancia. + +Usted puede utilizar [[yii\di\ServiceLocator::has()]] para comprobar si un ID de componente ya ha sido registrada. +Si llama [[yii\di\ServiceLocator::get()]] con una identificación válida, se produce una excepción. + +Debido a que los localizadores de servicios a menudo se crean con [configuraciones](concept-configurations.md), se proporciona una propiedad que puede escribir el nombre [[yii\di\ServiceLocator::setComponents()|components]]. Esto le permite configurar y registrar varios componentes a la vez. El siguiente código muestra un arreglo de configuración que se puede utilizar para configurar una aplicación, al mismo tiempo que el registro de la "db", "cache" y "buscar" componentes: + +```php +return [ + // ... + 'components' => [ + 'db' => [ + 'class' => 'yii\db\Connection', + 'dsn' => 'mysql:host=localhost;dbname=demo', + 'username' => 'root', + 'password' => '', + ], + 'cache' => 'yii\caching\ApcCache', + 'search' => function () { + return new app\components\SolrService; + }, + ], +]; +``` diff --git a/docs/guide-es/db-dao.md b/docs/guide-es/db-dao.md new file mode 100644 index 0000000..40e1cf7 --- /dev/null +++ b/docs/guide-es/db-dao.md @@ -0,0 +1,636 @@ +Objetos de Acceso a Bases de Datos +================================== + +Construido sobre [PDO](http://php.net/manual/es/book.pdo.php), Yii DAO (Objetos de Acceso a Bases de Datos) proporciona una +API orientada a objetos para el acceso a bases de datos relacionales. Es el fundamento para otros métodos de acceso a bases de datos +más avanzados, incluyendo el [constructor de consultas](db-query-builder.md) y [active record](db-active-record.md). + +Al utilizar Yii DAO, principalmente vas a tratar con SQLs planos y arrays PHP. Como resultado, esta es la manera más eficiente +de acceder a las bases de datos. Sin embargo, como la sintaxis puede variar para las diferentes bases de datos, utilizando +Yii DAO también significa que tienes que tienes que tomar un esfuerzo adicional para crear una aplicación de database-agnostic. + +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/) +- [CUBRID](http://www.cubrid.org/): versión 9.3 o superior. +- [Oracle](http://www.oracle.com/us/products/database/overview/index.html) +- [MSSQL](https://www.microsoft.com/en-us/sqlserver/default.aspx): versión 2008 o superior. + +## Creando Conexiones DB + +Para acceder a una base de datos, primero necesitas conectarte a tu bases de datos mediante la creación +de una instancia de [yii\db\Connection]]: + +```php +$db = new yii\db\Connection([ + 'dsn' => 'mysql:host=localhost;dbname=example', + 'username' => 'root', + 'password' => '', + 'charset' => 'utf8', +]); +``` + +Debido a una conexión DB a menudo necesita ser accedido en diferentes lugares, una práctica común es +configurarlo en términos de un [componente de aplicación](structure-application-components.md) como +se muestra a continuación: + +```php +return [ + // ... + 'components' => [ + // ... + 'db' => [ + 'class' => 'yii\db\Connection', + 'dsn' => 'mysql:host=localhost;dbname=example', + 'username' => 'root', + 'password' => '', + 'charset' => 'utf8', + ], + ], + // ... +]; +``` + +Puedes acceder a la conexión DB mediante la expresión `Yii::$app->db`. + +> Consejo: Puedes configurar múltiples componentes de aplicación DB si tu aplicación necesita acceder a múltiples bases de datos. + +Cuando configuras una conexión DB, deberías siempre especificar el Nombre de Origen de Datos (DSN) mediante la +propiedad [[yii\db\Connection::dsn|dsn]]. El formato del DSN varia para cada diferente base de datos. Por favor consulte el +[manual de PHP](http://www.php.net/manual/es/function.PDO-construct.php) para más detalles. Abajo están algunos ejemplos: + +* MySQL, MariaDB: `mysql:host=localhost;dbname=mydatabase` +* SQLite: `sqlite:/path/to/database/file` +* PostgreSQL: `pgsql:host=localhost;port=5432;dbname=mydatabase` +* CUBRID: `cubrid:dbname=demodb;host=localhost;port=33000` +* MS SQL Server (mediante sqlsrv driver): `sqlsrv:Server=localhost;Database=mydatabase` +* MS SQL Server (mediante dblib driver): `dblib:host=localhost;dbname=mydatabase` +* MS SQL Server (mediante mssql driver): `mssql:host=localhost;dbname=mydatabase` +* Oracle: `oci:dbname=//localhost:1521/mydatabase` + +Nota que si estás conectándote con una base de datos mediante ODBC, deberías configurar la propiedad [[yii\db\Connection::driverName]] +para que Yii pueda conocer el tipo de base de datos actual. Por ejemplo, + +```php +'db' => [ + 'class' => 'yii\db\Connection', + 'driverName' => 'mysql', + 'dsn' => 'odbc:Driver={MySQL};Server=localhost;Database=test', + 'username' => 'root', + 'password' => '', +], +``` + +Además de la propiedad [[yii\db\Connection::dsn|dsn]], a menudo es necesario configurar el [[yii\db\Connection::username|username]] +y [[yii\db\Connection::password|password]]. Por favor consulta [[yii\db\Connection]] para ver la lista completa de propiedades configurables. + +> Información: Cuando se crea una instancia de conexión DB, la conexión actual a la base de datos no se establece hasta que + ejecutes el primer SQL o llames explícitamente al método [[yii\db\Connection::open()|open()]]. + + +## Ejecutando Consultas SQL + +Una vez tienes instanciada una conexión a la base de datos, se pueden ejecutar consultas SQL tomando +los siguientes pasos: + +1. Crea un [[yii\db\Command]] con SQL plano; +2. Vincula parámetros (opcional); +3. Llama a uno de los métodos de ejecución SQL con [[yii\db\Command]]. + +El siguiente ejemplo muestra varias maneras de obtener datos de una base de datos: + +```php +$db = new yii\db\Connection(...); + +// retorna un conjunto de filas. Cada fila es un array asociativo de columnas de nombres y valores. +// un array vacío es retornado si no hay resultados +$posts = $db->createCommand('SELECT * FROM post') + ->queryAll(); + +// retorna una sola fila (la primera fila) +// false es retornado si no hay resultados +$post = $db->createCommand('SELECT * FROM post WHERE id=1') + ->queryOne(); + +// retorna una sola columna (la primera columna) +// un array vacío es retornado si no hay resultados +$titles = $db->createCommand('SELECT title FROM post') + ->queryColumn(); + +// retorna un escalar +// false es retornado si no hay resultados +$count = $db->createCommand('SELECT COUNT(*) FROM post') + ->queryScalar(); +``` + +> Nota: Para preservar la precisión, los datos obtenidos de las bases de datos son todos representados como cadenas, incluso si el tipo de columna correspondiente +a la base de datos es numérico. + +> Consejo: Si necesitas ejecutar una consulta SQL inmediatamente después de establecer una conexión (ej., para establecer una zona horaria o un conjunto de caracteres), +> puedes hacerlo con el evento [[yii\db\Connection::EVENT_AFTER_OPEN]]. Por ejemplo, +> +```php +return [ + // ... + 'components' => [ + // ... + 'db' => [ + 'class' => 'yii\db\Connection', + // ... + 'on afterOpen' => function($event) { + // $event->sender se refiere a la conexión DB + $event->sender->createCommand("SET time_zone = 'UTC'")->execute(); + } + ], + ], + // ... +]; +``` + + +### Parámetros Vinculados (Binding Parameters) + +Cuando creamos un comando DB para un SQL con parámetros, nosotros deberíamos casi siempre aprovechar el uso de los parámetros vinculados +para prevenir los ataques de inyección de SQL. Por ejemplo, + +```php +$post = $db->createCommand('SELECT * FROM post WHERE id=:id AND status=:status') + ->bindValue(':id', $_GET['id']) + ->bindValue(':status', 1) + ->queryOne(); +``` + +En la sentencia SQL, puedes incrustar uno o múltiples parámetros placeholders (ej. `:id` en el ejemplo anterior). Un parámetro +placeholder debería ser una cadena que empiece con dos puntos. A continuación puedes llamar a uno de los siguientes métodos para +unir los valores de los parámetros vinculados: + +* [[yii\db\Command::bindValue()|bindValue()]]: une un solo parámetro +* [[yii\db\Command::bindValues()|bindValues()]]: une múltiples parámetros en una sola llamada +* [[yii\db\Command::bindParam()|bindParam()]]: similar a [[yii\db\Command::bindValue()|bindValue()]] pero también + soporta las referencias de parámetros vinculados. + +El siguiente ejemplo muestra formas alternativas de vincular parámetros: + +```php +$params = [':id' => $_GET['id'], ':status' => 1]; + +$post = $db->createCommand('SELECT * FROM post WHERE id=:id AND status=:status') + ->bindValues($params) + ->queryOne(); + +$post = $db->createCommand('SELECT * FROM post WHERE id=:id AND status=:status', $params) + ->queryOne(); +``` + +La vinculación parámetros es implementada mediante [sentencias preparadas (prepared statements)](http://php.net/manual/es/mysqli.quickstart.prepared-statements.php). +Además de prevenir ataques de inyección de SQL, también puede mejorar el rendimiento preparando una sola vez una sentencia SQL y ejecutándola múltiples veces con diferentes +parámetros. Por ejemplo, + +```php +$command = $db->createCommand('SELECT * FROM post WHERE id=:id'); + +$post1 = $command->bindValue(':id', 1)->queryOne(); +$post2 = $command->bindValue(':id', 2)->queryOne(); +``` + +Porque [[yii\db\Command::bindParam()|bindParam()]] soporta parámetros vinculados por referencias, el código de arriba también +puede ser escrito como lo siguiente: + +```php +$command = $db->createCommand('SELECT * FROM post WHERE id=:id') + ->bindParam(':id', $id); + +$id = 1; +$post1 = $command->queryOne(); + +$id = 2; +$post2 = $command->queryOne(); +``` + +Observe que vincula el placeholder a la variable `$id` antes de la ejecución, y entonces cambia el valor de esa variable +antes de cada subsiguiente ejecución (esto se hace a menudo con bucles). Ejecutando consultas de esta manera puede ser +bastante más eficiente que ejecutar una nueva consulta para cada valor diferente del parámetro. + + +### Ejecutando Consultas Non-SELECT + +El método `queryXyz()` introducidos en las secciones previas todos tratan con consultas SELECT los cuales recogen los +datos de la base de datos. Para las consultas que no devuelven datos, deberías llamar a el método [[yii\db\Command::execute()]] +en su lugar. Por ejemplo, + +```php +$db->createCommand('UPDATE post SET status=1 WHERE id=1') + ->execute(); +``` + +El método [[yii\db\Command::execute()]] retorna el número de filas afectadas por la ejecución SQL. + +Para consultas INSERT, UPDATE y DELETE, en vez de escribir SQLs planos, puedes llamar a [[yii\db\Command::insert()|insert()]], +[[yii\db\Command::update()|update()]], [[yii\db\Command::delete()|delete()]], respectivamente, construyen los correspondientes +SQLs. Estos métodos entrecomillan adecuadamente las tablas y los nombres de columnas y los valores de los parámetros vinculados. +Por ejemplo, + +```php +// INSERT (table name, column values) +$db->createCommand()->insert('user', [ + 'name' => 'Sam', + 'age' => 30, +])->execute(); + +// UPDATE (table name, column values, condition) +$db->createCommand()->update('user', ['status' => 1], 'age > 30')->execute(); + +// DELETE (table name, condition) +$db->createCommand()->delete('user', 'status = 0')->execute(); +``` + +Puedes también llamar a [[yii\db\Command::batchInsert()|batchInsert()]] para insertar múltiples filas de una sola vez, +que es mucho más eficiente que insertar una fila de cada vez: + +```php +// table name, column names, column values +$db->createCommand()->batchInsert('user', ['name', 'age'], [ + ['Tom', 30], + ['Jane', 20], + ['Linda', 25], +])->execute(); +``` + + +## Entrecomillado de Tablas y Nombres de Columna + +Al escribir código de database-agnostic, entrecomillar correctamente los nombres de las tablas y las columnas es a menudo +un dolor de cabeza porque las diferentes bases de datos tienen diferentes reglas para entrecomillar los nombres. Para +solventar este problema, puedes usar la siguiente sintaxis de entrecomillado introducido por Yii: + +* `[[column name]]`: encierra con dobles corchetes el nombre de una columna que debe ser entrecomillado; +* `{{table name}}`: encierra con dobles llaves el nombre de una tabla que debe ser entrecomillado. + +Yii DAO automáticamente convertirá tales construcciones en un SQL con los correspondientes entrecomillados de los nombres de las columnas o tablas. +Por ejemplo, + +```php +// ejecuta esta SQL para MySQL: SELECT COUNT(`id`) FROM `employee` +$count = $db->createCommand("SELECT COUNT([[id]]) FROM {{employee}}") + ->queryScalar(); +``` + + +### Usadno Prefijos de Tabla + +Si la mayoría de tus tablas de BD utilizan algún prefijo común en sus tablas, puedes usar la función de prefijo de tabla soportado +por Yii DAO. + +Primero, especifica el prefijo de tabla mediante la propiedad [[yii\db\Connection::tablePrefix]]: + +```php +return [ + // ... + 'components' => [ + // ... + 'db' => [ + // ... + 'tablePrefix' => 'tbl_', + ], + ], +]; +``` + +Luego en tu código, siempre que lo necesites para hacer referencia a una tabla cuyo nombre tiene un prefijo, utiliza la sintaxis +`{{%table name}}`. El carácter porcentaje se sustituye con el prefijo de la tabla que has especificado en la configuración de +la conexión DB. Por ejemplo, + +```php +// ejecuta esta SQL para MySQL: SELECT COUNT(`id`) FROM `tbl_employee` +$count = $db->createCommand("SELECT COUNT([[id]]) FROM {{%employee}}") + ->queryScalar(); +``` + + +## Realización de Transacciones + +Cuando se ejecutan múltiples consultas relacionadas en una secuencia, puede que se tengan que envolver en una +transacción para asegurar la integridad de los datos y la consistencia de tu base de datos. Si cualquiera de las consultas +falla, la base de datos debe ser revertida al estado anterior como si ninguna de estas consultas se haya ejecutado. + +El siguiente código muestra una manera típica de usar transacciones: + +```php +$db->transaction(function($db) { + $db->createCommand($sql1)->execute(); + $db->createCommand($sql2)->execute(); + // ... ejecutando otras sentencias SQL +}); +``` + +El código de arriba es equivalente a lo siguiente: + +```php +$transaction = $db->beginTransaction(); + +try { + $db->createCommand($sql1)->execute(); + $db->createCommand($sql2)->execute(); + // ... ejecutando otras sentencias SQL + + $transaction->commit(); + +} catch(\Exception $e) { + + $transaction->rollBack(); + + throw $e; +} +``` + +Al llamar al método [[yii\db\Connection::beginTransaction()|beginTransaction()]], se inicia una nueva transacción. +La transacción se representa como un objeto [[yii\db\Transaction]] almacenado en la variable `$transaction`. Luego, +las consultas que se ejecutan están encerrados en un bloque `try...catch...`. Si todas las consultas son ejecutadas satisfactoriamente, +el método [[yii\db\Transaction::commit()|commit()]] es llamado para confirmar la transacción. De lo contrario, una excepción +se disparará y se capturará, y el método [[yii\db\Transaction::rollBack()|rollBack()]] es llamado para revertir +los cambios hechos por las consultas antes de que fallara la consulta en la transacción. + + +### Especificando los Niveles de Aislamiento + +Yii también soporta la configuración de [niveles de aislamiento] para tus transacciones. Por defecto, cuando comienza una nueva transacción, +utilizará el nivel de aislamiento definido por tu sistema de base de datos. Se puede sobrescribir el nivel de aislamiento por defecto de la +siguiente manera, + +```php +$isolationLevel = \yii\db\Transaction::REPEATABLE_READ; + +$db->transaction(function ($db) { + .... +}, $isolationLevel); + +// or alternatively + +$transaction = $db->beginTransaction($isolationLevel); +``` + +Yii proporciona cuatro constantes para los niveles de aislamiento más comunes: + +- [[\yii\db\Transaction::READ_UNCOMMITTED]] - el nivel más bajo, pueden ocurrir lecturas Dirty, lecturas + Non-repeatable y Phantoms. +- [[\yii\db\Transaction::READ_COMMITTED]] - evita lecturas Dirty. +- [[\yii\db\Transaction::REPEATABLE_READ]] - evita lecturas Dirty y lecturas Non-repeatable. +- [[\yii\db\Transaction::SERIALIZABLE]] - el nivel más fuerte, evita todos los problemas nombrados anteriormente. + +Además de usar las constantes de arriba para especificar los niveles de aislamiento, puedes también usar cadenas con +una sintaxis valida soportada por el DBMS que estés usando. Por ejemplo, en PostgreSQL, puedes utilizar `SERIALIZABLE READ ONLY DEFERRABLE`. + +Tenga en cuenta que algunos DBMS permiten configuraciones de niveles de aislamiento solo a nivel de conexión. Las transacciones subsiguientes +recibirá el mismo nivel de aislamiento , incluso si no se especifica ninguna. Al utilizar esta característica +es posible que necesites ajustar el nivel de aislamiento para todas las transacciones de forma explícitamente para evitar conflictos +en las configuraciones. +En el momento de escribir esto, solo MSSQL y SQLite serán afectadas. + +> Nota: SQLite solo soporta dos niveles de aislamiento, por lo que solo se puede usar `READ UNCOMMITTED` y +`SERIALIZABLE`. El uso de otros niveles causará el lanzamiento de una excepción. + +> Nota: PostgreSQL no permite configurar el nivel de aislamiento antes que la transacción empiece por lo que no se + puede especificar el nivel de aislamiento directamente cuando empieza la transacción. Se tiene que llamar a + [[yii\db\Transaction::setIsolationLevel()]] después de que la transacción haya empezado. + +[isolation levels]: http://en.wikipedia.org/wiki/Isolation_%28database_systems%29#Isolation_levels + + +### Transacciones Anidadas + +Si tu DBMS soporta Savepoint, puedes anidar múltiples transacciones como a continuación: + +```php +$db->transaction(function ($db) { + // outer transaction + + $db->transaction(function ($db) { + // inner transaction + }); +}); +``` + +O alternativamente, + +```php +$outerTransaction = $db->beginTransaction(); +try { + $db->createCommand($sql1)->execute(); + + $innerTransaction = $db->beginTransaction(); + try { + $db->createCommand($sql2)->execute(); + $innerTransaction->commit(); + } catch (Exception $e) { + $innerTransaction->rollBack(); + } + + $outerTransaction->commit(); +} catch (Exception $e) { + $outerTransaction->rollBack(); +} +``` + + +## Replicación y División Lectura-Escritura + +Muchos DBMS soportan [replicación de bases de datos](http://en.wikipedia.org/wiki/Replication_(computing)#Database_replication) para tener +una mejor disponibilidad de la base de datos y un mejor tiempo de respuesta del servidor. Con la replicación de bases +de datos, los datos están replicados en los llamados *servidores maestros* (master servers) y *servidores esclavos* +(slave servers). Todas las escrituras y actualizaciones deben hacerse en el servidor maestro, mientras que las lecturas +se efectuarán en los servidores esclavos. + +Para aprovechar las ventajas de la replicación de la base de datos y lograr una división de lecuta-escritura, se puede configurar +el componente [[yii\db\Connection]] como se muestra a continuación: + +```php +[ + 'class' => 'yii\db\Connection', + + // configuración para el maestro + 'dsn' => 'dsn for master server', + 'username' => 'master', + 'password' => '', + + // configuración para los esclavos + 'slaveConfig' => [ + 'username' => 'slave', + 'password' => '', + 'attributes' => [ + // utiliza un tiempo de espera de conexión más pequeña + PDO::ATTR_TIMEOUT => 10, + ], + ], + + // listado de configuraciones de esclavos + '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 configuración anterior especifica una configuración con un único maestro y múltiples esclavos. Uno de los esclavos +se conectará y se usará para ejecutar consultas de lectura, mientras que el maestro se usará para realizar consultas de +escritura. De este modo la división de lectura-escritura se logra automáticamente con esta configuración, Por ejemplo, + +```php +// crea una instancia de Connection usando la configuración anterior +$db = Yii::createObject($config); + +// consulta contra uno de los esclavos +$rows = $db->createCommand('SELECT * FROM user LIMIT 10')->queryAll(); + +// consulta contra el maestro +$db->createCommand("UPDATE user SET username='demo' WHERE id=1")->execute(); +``` + +> Información: Las consultas realizadas llamando a [[yii\db\Command::execute()]] se consideran consultas de escritura, + mientras que todas las demás se ejecutan mediante alguno de los métodos "query" de [[yii\db\Command]] son consultas + de lectura. Se puede obtener la conexión de esclavo activa mediante `$db->slave`. + +El componente `Connection` soporta el balanceo de carga y la conmutación de errores entre esclavos. Cuando se realiza +una consulta de lectura por primera vez, el componente `Connection` elegirá un esclavo aleatorio e intentará realizar +una conexión a este. Si el esclavo se encuentra "muerto", se intentará con otro. Si no está disponible ningún esclavo, se conectará al maestro. Configurando una [[yii\db\Connection::serverStatusCache|server status cache]], se recordarán los servidores +"muertos" por lo que no se intentará volver a conectar a ellos durante +[[yii\db\Connection::serverRetryInterval|certain period of time]]. + +> Información: En la configuración anterior, se especifica un tiempo de espera (timeout) de conexión de 10 segundos + para cada esclavo. Esto significa que si no se puede conectar a un esclavo en 10 segundos, este será considerado + como "muerto". Se puede ajustar el parámetro basado en el entorno actual. + +También se pueden configurar múltiples maestros con múltiples esclavos. Por ejemplo, + +```php +[ + 'class' => 'yii\db\Connection', + + // configuracion habitual para los maestros + 'masterConfig' => [ + 'username' => 'master', + 'password' => '', + 'attributes' => [ + // utilizar un tiempo de espera de conexión más pequeña + PDO::ATTR_TIMEOUT => 10, + ], + ], + + // listado de configuraciones de maestros + 'masters' => [ + ['dsn' => 'dsn for master server 1'], + ['dsn' => 'dsn for master server 2'], + ], + + // configuración habitual para esclavos + 'slaveConfig' => [ + 'username' => 'slave', + 'password' => '', + 'attributes' => [ + // utilizar un tiempo de espera de conexión más pequeña + PDO::ATTR_TIMEOUT => 10, + ], + ], + + // listado de configuración de esclavos + '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 configuración anterior especifica dos maestros y cuatro esclavos. El componente `Connection` también da soporte al +balanceo de carga y la conmutación de errores entre maestros igual que hace con los esclavos. La diferencia es que +cuando no se encuentra ningún maestro disponible se lanza una excepción. + +> Nota: cuando se usa la propiedad [[yii\db\Connection::masters|masters]] para configurar uno o múltiples maestros, se + ignorarán todas las otras propiedades que especifiquen una conexión de base de datos + (ej. `dsn`, `username`, `password`), junto con el mismo objeto `Connection`. + +Por defecto. las transacciones usan la conexión del maestro. Y dentro de una transacción, todas las operaciones de DB usarán +la conexión del maestro. Por ejemplo, + +```php +// la transacción empieza con la conexión al maestro +$transaction = $db->beginTransaction(); + +try { + // las dos consultas se ejecutan contra el maestro + $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 se quiere empezar la transacción con una conexión a un esclavo, se debe hacer explícitamente como se muestra a +continuación: + +```php +$transaction = $db->slave->beginTransaction(); +``` + +A veces, se puede querer forzar el uso de una conexión maestra para realizar una consulta de lectura. Se puede lograr +usando el método `useMaster()`: + +```php +$rows = $db->useMaster(function ($db) { + return $db->createCommand('SELECT * FROM user LIMIT 10')->queryAll(); +}); +``` + +También se puede utilizar directamente estableciendo `$db->enableSlaves` a `false` para que se redirijan todas las +consultas a la conexión del maestro. + +## Trabajando con Esquemas de Bases de Datos + +Yii DAO proporciona todo un conjunto de métodos que permites manipular el esquema de tu base de datos, tal como +crear nuevas tablas, borrar una columna de una tabla, etc. Estos métodos son listados a continuación: + +* [[yii\db\Command::createTable()|createTable()]]: crea una tabla +* [[yii\db\Command::renameTable()|renameTable()]]: renombra una tabla +* [[yii\db\Command::dropTable()|dropTable()]]: remueve una tabla +* [[yii\db\Command::truncateTable()|truncateTable()]]: remueve todas las filas de una tabla +* [[yii\db\Command::addColumn()|addColumn()]]: añade una columna +* [[yii\db\Command::renameColumn()|renameColumn()]]: renombra una columna +* [[yii\db\Command::dropColumn()|dropColumn()]]: remueve una columna +* [[yii\db\Command::alterColumn()|alterColumn()]]: altera una columna +* [[yii\db\Command::addPrimaryKey()|addPrimaryKey()]]: añade una clave primaria +* [[yii\db\Command::dropPrimaryKey()|dropPrimaryKey()]]: remueve una clave primaria +* [[yii\db\Command::addForeignKey()|addForeignKey()]]: añade una clave ajena +* [[yii\db\Command::dropForeignKey()|dropForeignKey()]]: remueve una clave ajena +* [[yii\db\Command::createIndex()|createIndex()]]: crea un indice +* [[yii\db\Command::dropIndex()|dropIndex()]]: remueve un indice + +Estos métodos puedes ser usados como se muestra a continuación: + +```php +// CREATE TABLE +$db->createCommand()->createTable('post', [ + 'id' => 'pk', + 'title' => 'string', + 'text' => 'text', +]); +``` + +También puedes recuperar la información de definición de una tabla a través +del método [[yii\db\Connection::getTableSchema()|getTableSchema()]] de una conexión DB. Por ejemplo, + +```php +$table = $db->getTableSchema('post'); +``` + +El método retorna un objeto [[yii\db\TableSchema]] que contiene la información sobre las columnas de las tablas, +claves primarias, claves ajenas, etc. Toda esta información principalmente es utilizada por el +[constructor de consultas](db-query-builder.md) y [active record](db-active-record.md) para ayudar a +escribir código database-agnostic. diff --git a/docs/guide-es/db-query-builder.md b/docs/guide-es/db-query-builder.md new file mode 100644 index 0000000..a7670ff --- /dev/null +++ b/docs/guide-es/db-query-builder.md @@ -0,0 +1,470 @@ +Constructor de Consultas +======================== + +> Nota: Esta sección está en desarrollo. + +Yii proporciona una capa de acceso básico a bases de datos como se describe en la sección +[Objetos de Acceso a Bases de Datos](db-dao.md). La capa de acceso a bases de datos proporciona un método de bajo +nivel (low-level) para interaccionar con la base de datos. Aunque a veces puede ser útil la escritura de sentencias +SQLs puras, en otras situaciones puede ser pesado y propenso a errores. Otra manera de tratar con bases de datos puede +ser el uso de Constructores de Consultas (Query Builder). El Constructor de Consultas proporciona un medio orientado a +objetos para generar las consultas que se ejecutarán. + +Un uso típico de Constructor de Consultas puede ser el siguiente: + +```php +$rows = (new \yii\db\Query()) + ->select('id, name') + ->from('user') + ->limit(10) + ->all(); + +// que es equivalente al siguiente código: + +$query = (new \yii\db\Query()) + ->select('id, name') + ->from('user') + ->limit(10); + +// Crear un comando. Se puede obtener la consulta SQL actual utilizando $command->sql +$command = $query->createCommand(); + +// Ejecutar el comando: +$rows = $command->queryAll(); +``` + +Métodos de Consulta +------------------- + +Como se puede observar, primero se debe tratar con [[yii\db\Query]]. En realidad, `Query` sólo se encarga de +representar diversa información de la consulta. La lógica para generar la consulta se efectúa mediante +[[yii\db\QueryBuilder]] cuando se llama al método `createCommand()`, y la ejecución de la consulta la efectúa +[[yii\db\Command]]. + +Se ha establecido, por convenio, que [[yii\db\Query]] proporcione un conjunto de métodos de consulta comunes que +construirán la consulta, la ejecutarán, y devolverán el resultado. Por ejemplo: + +- [[yii\db\Query::all()|all()]]: construye la consulta, la ejecuta y devuelve todos los resultados en formato de array. +- [[yii\db\Query::one()|one()]]: devuelve la primera fila del resultado. +- [[yii\db\Query::column()|column()]]: devuelve la primera columna del resultado. +- [[yii\db\Query::scalar()|scalar()]]: devuelve la primera columna en la primera fila del resultado. +- [[yii\db\Query::exists()|exists()]]: devuelve un valor indicando si la el resultado devuelve algo. +- [[yii\db\Query::count()|count()]]: devuelve el resultado de la consulta `COUNT`. Otros métodos similares incluidos + son `sum($q)`, `average($q)`, `max($q)`, `min($q)`, que soportan las llamadas funciones de agregación. El parámetro + `$q` es obligatorio en estos métodos y puede ser el nombre de la columna o expresión. + +Construcción de Consultas +------------------------- + +A continuación se explicará como construir una sentencia SQL que incluya varias clausulas. Para simplificarlo, usamos +`$query` para representar el objeto [[yii\db\Query]]: + +### `SELECT` + +Para formar una consulta `SELECT` básica, se necesita especificar que columnas y de que tablas se seleccionarán: + +```php +$query->select('id, name') + ->from('user'); +``` + +Las opciones de select se pueden especificar como una cadena de texto (string) separada por comas o como un array. La +sintaxis del array es especialmente útil cuando se forma la selección dinámicamente. + +```php +$query->select(['id', 'name']) + ->from('user'); +``` + +> Información: Se debe usar siempre el formato array si la clausula `SELECT` contiene expresiones SQL. Esto se debe a + que una expresión SQL como `CONCAT(first_name, last_name) AS full_name` puede contener comas. Si se junta con otra + cadena de texto de otra columna, puede ser que la expresión se divida en varias partes por comas, esto puede + conllevar a errores. + +Cuando se especifican columnas, se pueden incluir los prefijos de las tablas o alias de columnas, ej. `user.id`, +`user.id AS user_id`. Si se usa un array para especificar las columnas, también se pueden usar las claves del array +para especificar los alias de columna, ej. `['user_id' => 'user.id', 'user_name' => 'user.name']`. + +A partir de la versión 2.0.1, también se pueden seleccionar subconsultas como columnas. Por ejemplo: + +```php +$subQuery = (new Query)->select('COUNT(*)')->from('user'); +$query = (new Query)->select(['id', 'count' => $subQuery])->from('post'); +// $query representa la siguiente sentencia SQL: +// SELECT `id`, (SELECT COUNT(*) FROM `user`) AS `count` FROM `post` +``` + +Para seleccionar filas distintas, se puede llamar a `distinct()`, como se muestra a continuación: + +```php +$query->select('user_id')->distinct()->from('post'); +``` + +### `FROM` + +Para especificar de que tabla(s) se quieren seleccionar los datos, se llama a `from()`: + +```php +$query->select('*')->from('user'); +``` + +Se pueden especificar múltiples tablas usando una cadena de texto separado por comas o un array. Los nombres de tablas +pueden contener prefijos de esquema (ej. `'public.user'`) y/o alias de tablas (ej. `'user u'). El método +entrecomillara automáticamente los nombres de tablas a menos que contengan algún paréntesis (que significa que se +proporciona la tabla como una subconsulta o una expresión de BD). Por ejemplo: + +```php +$query->select('u.*, p.*')->from(['user u', 'post p']); +``` + +Cuando se especifican las tablas como un array, también se pueden usar las claves de los arrays como alias de tablas +(si una tabla no necesita alias, no se usa una clave en formato texto). Por ejemplo: + +```php +$query->select('u.*, p.*')->from(['u' => 'user', 'p' => 'post']); +``` + +Se puede especificar una subconsulta usando un objeto `Query`. En este caso, la clave del array correspondiente se +usará como alias para la subconsulta. + +```php +$subQuery = (new Query())->select('id')->from('user')->where('status=1'); +$query->select('*')->from(['u' => $subQuery]); +``` + +### `WHERE` + +Habitualmente se seleccionan los datos basándose en ciertos criterios. El Constructor de Consultas tiene algunos +métodos útiles para especificarlos, el más poderoso de estos es `where`, y se puede usar de múltiples formas. + +La manera más simple para aplicar una condición es usar una cadena de texto: + +```php +$query->where('status=:status', [':status' => $status]); +``` + +Cuando se usan cadenas de texto, hay que asegurarse que se unen los parámetros de la consulta, no crear una consulta +mediante concatenación de cadenas de texto. El enfoque anterior es seguro, el que se muestra a continuación, no lo es: + +```php +$query->where("status=$status"); // Peligroso! +``` + +En lugar de enlazar los valores de estado inmediatamente, se puede hacer usando `params` o `addParams`: + +```php +$query->where('status=:status'); +$query->addParams([':status' => $status]); +``` + +Se pueden establecer múltiples condiciones en `where` usando el *formato hash*. + +```php +$query->where([ + 'status' => 10, + 'type' => 2, + 'id' => [4, 8, 15, 16, 23, 42], +]); +``` + +El código generará la el siguiente SQL: + +```sql +WHERE (`status` = 10) AND (`type` = 2) AND (`id` IN (4, 8, 15, 16, 23, 42)) +``` + +El valor NULO es un valor especial en las bases de datos, y el Constructor de Consultas lo gestiona inteligentemente. +Este código: + +```php +$query->where(['status' => null]); +``` + +da como resultado la siguiente cláusula WHERE: + +```sql +WHERE (`status` IS NULL) +``` + +También se pueden crear subconsultas con objetos de tipo `Query` como en el siguiente ejemplo: + +```php +$userQuery = (new Query)->select('id')->from('user'); +$query->where(['id' => $userQuery]); +``` + +que generará el siguiente código SQL: + +```sql +WHERE `id` IN (SELECT `id` FROM `user`) +``` + +Otra manera de usar el método es el formato de operando que es `[operator, operand1, operand2, ...]`. + +El operando puede ser uno de los siguientes (ver también [[yii\db\QueryInterface::where()]]): + +- `and`: los operandos deben concatenerase usando `AND`. por ejemplo, `['and', 'id=1', 'id=2']` generará + `id=1 AND id=2`. Si el operando es un array, se convertirá en una cadena de texto usando las reglas aquí descritas. + Por ejemplo, `['and', 'type=1', ['or', 'id=1', 'id=2']]` generará `type=1 AND (id=1 OR id=2)`. El método no + ejecutará ningún filtrado ni entrecomillado. + +- `or`: similar al operando `and` exceptuando que los operando son concatenados usando `OR`. + +- `between`: el operando 1 debe ser el nombre de columna, y los operandos 2 y 3 deben ser los valores iniciales y + finales del rango en el que se encuentra la columna. Por ejemplo, `['between', 'id', 1, 10]` generará + `id BETWEEN 1 AND 10`. + +- `not between`: similar a `between` exceptuando que `BETWEEN` se reemplaza por `NOT BETWEEN` en la condición + generada. + +- `in`: el operando 1 debe ser una columna o una expresión de BD. El operando 2 puede ser un array o un objeto de tipo + `Query`. Generará una condición `IN`. Si el operando 2 es un array, representará el rango de valores que puede + albergar la columna o la expresión de BD; Si el operando 2 es un objeto de tipo `Query`, se generará una subconsulta + y se usará como rango de la columna o de la expresión de BD. Por ejemplo, `['in', 'id', [1, 2, 3]]` generará + `id IN (1, 2, 3)`. El método entrecomillará adecuadamente el nombre de columna y filtrará los valores del rango. El + operando `in` también soporta columnas compuestas. En este caso, el operando 1 debe se un array de columnas, + mientras que el operando 2 debe ser un array de arrays o un objeto de tipo `Query` que represente el rango de las + columnas. + +- `not in`: similar que el operando `in` exceptuando que `IN` se reemplaza por `NOT IN` en la condición generada. + +- `like`: el operando 1 debe ser una columna o una expresión de BD, y el operando 2 debe ser una cadena de texto o un + array que represente los valores a los que tienen que asemejarse la columna o la expresión de BD.Por ejemplo, + `['like', 'name', 'tester']` generará `name LIKE '%tester%'`. Cuando se da el valor rango como un array, se + generarán múltiples predicados `LIKE` y se concatenaran usando `AND`. Por ejemplo, + `['like', 'name', ['test', 'sample']]` generará `name LIKE '%test%' AND name LIKE '%sample%'`. También se puede + proporcionar un tercer operando opcional para especificar como deben filtrarse los caracteres especiales en los + valores. El operando debe se un array que mapeen los caracteres especiales a sus caracteres filtrados asociados. Si + no se proporciona este operando, se aplicará el mapeo de filtrado predeterminado. Se puede usar `false` o un array + vacío para indicar que los valores ya están filtrados y no se necesita aplicar ningún filtro. Hay que tener en + cuenta que cuando se usa un el mapeo de filtrado (o no se especifica el tercer operando), los valores se encerraran + automáticamente entre un par de caracteres de porcentaje. + +> Nota: Cuando se usa PostgreSQL también se puede usar +[`ilike`](http://www.postgresql.org/docs/8.3/static/functions-matching.html#FUNCTIONS-LIKE) en lugar de `like` para +filtrar resultados insensibles a mayúsculas (case-insensitive). + +- `or like`: similar al operando `like` exceptuando que se usa `OR` para concatenar los predicados `LIKE` cuando haya + un segundo operando en un array. + +- `not like`: similar al operando `like` exceptuando que se usa `LIKE` en lugar de `NOT LIKE` en las condiciones + generadas. + +- `or not like`: similar al operando `not like` exceptuando que se usa `OR` para concatenar los predicados `NOT LIKE`. + +- `exists`: requiere un operando que debe ser una instancia de [[yii\db\Query]] que represente la subconsulta. Esto + generará una expresión `EXISTS (sub-query)`. + +- `not exists`: similar al operando `exists` y genera una expresión `NOT EXISTS (sub-query)`. + +Adicionalmente se puede especificar cualquier cosa como operando: + +```php +$query->select('id') + ->from('user') + ->where(['>=', 'id', 10]); +``` + +Cuyo resultado será: + +```sql +SELECT id FROM user WHERE id >= 10; +``` + +Si se construyen partes de una condición dinámicamente, es muy convenientes usar `andWhere()` y `orWhere()`: + +```php +$status = 10; +$search = 'yii'; + +$query->where(['status' => $status]); +if (!empty($search)) { + $query->andWhere(['like', 'title', $search]); +} +``` + +En el caso que `$search` no este vacío, se generará el siguiente código SQL: + +```sql +WHERE (`status` = 10) AND (`title` LIKE '%yii%') +``` + +#### Construcción de Condiciones de Filtro + +Cuando se generan condiciones de filtro basadas en datos recibidos de usuarios (inputs), a menudo se quieren gestionar +de forma especial las "datos vacíos" para ignorarlos en los filtros. Por ejemplo, teniendo un formulario HTML que +obtiene el nombre de usuario y la dirección de correo electrónico. Si el usuario solo rellena el campo de nombre de +usuario, se puede querer generar una consulta para saber si el nombre de usuario recibido es valido. Se puede usar +`filterWhere()` para conseguirlo: + +```php +// $username y $email son campos de formulario rellenados por usuarios +$query->filterWhere([ + 'username' => $username, + 'email' => $email, +]); +``` + +El método `filterWhere()` es muy similar al método `where()`. La principal diferencia es que el `filterWhere()` +eliminará los valores vacíos de las condiciones proporcionadas. Por lo tanto si `$email` es "vació", la consulta +resultante será `...WHERE username=:username`; y si tanto `$username` como `$email` son "vacías", la consulta no +tendrá `WHERE`. + +Decimos que un valor es *vacío* si es nulo, una cadena de texto vacía, una cadena de texto que consista en espacios en +blanco o un array vacío. + +También se pueden usar `andFilterWhere()` y `orFilterWhere()` para añadir más condiciones de filtro. + +### `ORDER BY` + +Se pueden usar `orderBy` y `addOrderBy` para ordenar resultados: + +```php +$query->orderBy([ + 'id' => SORT_ASC, + 'name' => SORT_DESC, +]); +``` + +Aquí estamos ordenando por `id` ascendente y después por `name` descendente. + +### `GROUP BY` and `HAVING` + +Para añadir `GROUP BY` al SQL generado se puede usar el siguiente código: + +```php +$query->groupBy('id, status'); +``` + +Si se quieren añadir otro campo después de usar `groupBy`: + +```php +$query->addGroupBy(['created_at', 'updated_at']); +``` + +Para añadir la condición `HAVING` se pueden usar los métodos `having` y `andHaving` y `orHaving`. Los parámetros para +ellos son similares a los del grupo de métodos `where`: + +```php +$query->having(['status' => $status]); +``` + +### `LIMIT` and `OFFSET` + +Para limitar el resultado a 10 filas se puede usar `limit`: + +```php +$query->limit(10); +``` + +Para saltarse las 100 primeras filas, se puede usar: + +```php +$query->offset(100); +``` + +### `JOIN` + +Las clausulas `JOIN` se generan en el Constructor de Consultas usando el método join aplicable: + +- `innerJoin()` +- `leftJoin()` +- `rightJoin()` + +Este left join selecciona los datos desde dos tablas relacionadas en una consulta: + +```php +$query->select(['user.name AS author', 'post.title as title']) + ->from('user') + ->leftJoin('post', 'post.user_id = user.id'); +``` + +En el código, el primer parámetro del método `leftjoin` especifica la tabla a la que aplicar el join. El segundo +parámetro, define la condición del join. + +Si la aplicación de bases de datos soporta otros tipos de joins, se pueden usar mediante el método `join` genérico: + +```php +$query->join('FULL OUTER JOIN', 'post', 'post.user_id = user.id'); +``` + +El primer argumento es el tipo de join a realizar. El segundo es la tabla a la que aplicar el join, y el tercero es la condición: + +Como en `FROM`, también se pueden efectuar joins con subconsultas. Para hacerlo, se debe especificar la subconsulta +como un array que tiene que contener un elemento. El valor del array tiene que ser un objeto de tipo `Query` que +represente la subconsulta, mientras que la clave del array es el alias de la subconsulta. Por ejemplo: + +```php +$query->leftJoin(['u' => $subQuery], 'u.id=author_id'); +``` + +### `UNION` + +En SQL `UNION` agrega resultados de una consulta a otra consulta. Las columnas devueltas por ambas consultas deben +coincidir. En Yii para construirla, primero se pueden formar dos objetos de tipo query y después usar el método +`union`: + +```php +$query = new Query(); +$query->select("id, category_id as type, name")->from('post')->limit(10); + +$anotherQuery = new Query(); +$anotherQuery->select('id, type, name')->from('user')->limit(10); + +$query->union($anotherQuery); +``` + +Consulta por Lotes +--------------- + +Cuando se trabaja con grandes cantidades de datos, los métodos como [[yii\db\Query::all()]] no son adecuados ya que +requieren la carga de todos los datos en memoria. Para mantener los requerimientos de memoria reducidos, Yii +proporciona soporte a las llamadas consultas por lotes (batch query). Una consulta por lotes usa un cursor de datos y +recupera los datos en bloques. + +Las consultas por lotes se pueden usar del siguiente modo: + +```php +use yii\db\Query; + +$query = (new Query()) + ->from('user') + ->orderBy('id'); + +foreach ($query->batch() as $users) { + // $users is an array of 100 or fewer rows from the user table +} + +// o si se quieren iterar las filas una a una +foreach ($query->each() as $user) { + // $user representa uno fila de datos de la tabla user +} +``` + +Los métodos [[yii\db\Query::batch()]] y [[yii\db\Query::each()]] devuelven un objeto [[yii\db\BatchQueryResult]] que +implementa una interfaz `Iterator` y así se puede usar en el constructor `foreach`. Durante la primera iteración, se +efectúa una consulta SQL a la base de datos. Desde entonces, los datos se recuperan por lotes en las iteraciones. El +tamaño predeterminado de los lotes es 100, que significa que se recuperan 100 filas de datos en cada lote. Se puede +modificar el tamaño de los lotes pasando pasando un primer parámetro a los métodos `batch()` o `each()`. + +En comparación con [[yii\db\Query::all()]], las consultas por lotes sólo cargan 100 filas de datos en memoria cada +vez. Si el procesan los datos y después se descartan inmediatamente, las consultas por lotes, pueden ayudar a mantener +el uso de memora bajo un limite. + +Si se especifica que el resultado de la consulta tiene que ser indexado por alguna columna mediante +[[yii\db\Query::indexBy()]], las consultas por lotes seguirán manteniendo el indice adecuado. Por ejemplo, + +```php +use yii\db\Query; + +$query = (new Query()) + ->from('user') + ->indexBy('username'); + +foreach ($query->batch() as $users) { + // $users esta indexado en la columna "username" +} + +foreach ($query->each() as $username => $user) { +} +``` \ No newline at end of file diff --git a/docs/guide-es/helper-array.md b/docs/guide-es/helper-array.md new file mode 100644 index 0000000..0bfb01c --- /dev/null +++ b/docs/guide-es/helper-array.md @@ -0,0 +1,304 @@ +ArrayHelper +=========== + +Adicionalmente al [rico conjunto de funciones para arrays de PHP](http://php.net/manual/es/book.array.php) Yii array helper proporciona +métodos estáticos adicionales permitiendo trabajar con arrays de manera más eficiente. + + +## Devolviendo Valores + +Recuperar valores de un array, un objeto o una estructura compleja usando PHP estándar es bastante +repetitivo. Tienes que comprobar primero si una clave existe con `isset`, después devolver el valor si existe, si no, +devolver un valor por defecto: + +```php +class User +{ + public $name = 'Alex'; +} + +$array = [ + 'foo' => [ + 'bar' => new User(), + ] +]; + +$value = isset($array['foo']['bar']->name) ? $array['foo']['bar']->name : null; +``` + +Yii proviene de un método muy conveniente para hacerlo: + +```php +$value = ArrayHelper::getValue($array, 'foo.bar.name'); +``` + +El primer argumento del método es de donde vamos a obtener el valor. El segundo argumento especifica como devolver el dato. Puede ser +de la siguiente manera: + +- Nombre de la clave del array o de la propiedad del objeto para recuperar el valor. +- Conjunto de puntos separados por las claves del array o los nombres de las propiedades del objeto. Esto se ha usado en el ejemplo anterior. +- Un callback que devuelve un valor. + +El callback se debería usar de la siguiente manera: + +```php +$fullName = ArrayHelper::getValue($user, function ($user, $defaultValue) { + return $user->firstName . ' ' . $user->lastName; +}); +``` + +El tercer argumento opcional es el valor por defecto el cual es `null` si no se especifica. Podría ser utilizado de la siguiente manera: + +```php +$username = ArrayHelper::getValue($comment, 'user.username', 'Unknown'); +``` + +En caso de que quieras coger un valor y luego removerlo inmediatamente del array puedes usar el método `remove`: + +```php +$array = ['type' => 'A', 'options' => [1, 2]]; +$type = ArrayHelper::remove($array, 'type'); +``` + +Después de ejecutar el código el `$array` contendrá `['options' => [1, 2]]` y `$type` debe ser `A`. Tenga en cuenta que a diferencia del método +`getValue`, `remove` solo soporta nombres clave simples. + + +## Comprobando la Existencia de Claves + +`ArrayHelper::keyExists` funciona de la misma manera que [array_key_exists](http://php.net/manual/es/function.array-key-exists.php) +excepto que también soporta case-insensitive para la comparación de claves. Por ejemplo, + +```php +$data1 = [ + 'userName' => 'Alex', +]; + +$data2 = [ + 'username' => 'Carsten', +]; + +if (!ArrayHelper::keyExists('username', $data1, false) || !ArrayHelper::keyExists('username', $data2, false)) { + echo "Please provide username."; +} +``` + +## Recuperando Columnas + +A menudo necesitas obtener unos valores de una columna de las filas de datos u objetos de un array. Un ejemplo común es obtener una lista de IDs. + +```php +$data = [ + ['id' => '123', 'data' => 'abc'], + ['id' => '345', 'data' => 'def'], +]; +$ids = ArrayHelper::getColumn($array, 'id'); +``` + +El resultado será `['123', '345']`. + +Si se requieren transformaciones adicionales o la manera de obtener el valor es complejo, se podría especificar como segundo argumento +una función anónima : + +```php +$result = ArrayHelper::getColumn($array, function ($element) { + return $element['id']; +}); +``` + + +## Re-indexar Arrays + +Con el fin de indexar un array según una clave especificada, se puede usar el método `index`. La entrada del array debe ser +multidimensional o un array de objetos. La clave puede ser un nombre clave del sub-array, un nombre de una propiedad del objeto, o +una función anónima que retorne el valor de la clave dado el elemento del array. + +Si el valor de la clave es null, el correspondiente elemento del array será desechado y no se pondrá en el resultado. Por ejemplo, + +```php +$array = [ + ['id' => '123', 'data' => 'abc'], + ['id' => '345', 'data' => 'def'], +]; +$result = ArrayHelper::index($array, 'id'); +// el resultado es: +// [ +// '123' => ['id' => '123', 'data' => 'abc'], +// '345' => ['id' => '345', 'data' => 'def'], +// ] + +// usando función anónima +$result = ArrayHelper::index($array, function ($element) { + return $element['id']; +}); +``` + + +## Construyendo Mapas (Maps) + +Con el fin de construir un mapa (pareja clave-valor) de un array multidimensional o un array de objetos puedes usar el método `map`. +Los parámetros `$from` y `$to` especifican los nombres de las claves o los nombres de las propiedades que serán configuradas en el mapa. Opcionalmente, se puede +agrupar en el mapa de acuerdo al campo de agrupamiento `$group`. Por ejemplo, + +```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'); +// el resultado es: +// [ +// '123' => 'aaa', +// '124' => 'bbb', +// '345' => 'ccc', +// ] + +$result = ArrayHelper::map($array, 'id', 'name', 'class'); +// el resultado es: +// [ +// 'x' => [ +// '123' => 'aaa', +// '124' => 'bbb', +// ], +// 'y' => [ +// '345' => 'ccc', +// ], +// ] +``` + + +## Ordenamiento Multidimensional + +El método `multisort` ayuda a ordenar un array de objetos o arrays anidados por una o varias claves. Por ejemplo, + +```php +$data = [ + ['age' => 30, 'name' => 'Alexander'], + ['age' => 30, 'name' => 'Brian'], + ['age' => 19, 'name' => 'Barney'], +]; +ArrayHelper::multisort($data, ['age', 'name'], [SORT_ASC, SORT_DESC]); +``` + +Después del ordenado obtendremos lo siguiente en `$data`: + +```php +[ + ['age' => 19, 'name' => 'Barney'], + ['age' => 30, 'name' => 'Brian'], + ['age' => 30, 'name' => 'Alexander'], +]; +``` + +El segundo argumento que especifica las claves para ordenar puede ser una cadena si se trata de una clave, un array en caso de que tenga múltiples claves +o una función anónima como la siguiente + +```php +ArrayHelper::multisort($data, function($item) { + return isset($item['age']) ? ['age', 'name'] : 'name'; +}); +``` + +El tercer argumento es la dirección. En caso de ordenar por una clave podría ser `SORT_ASC` o +`SORT_DESC`. Si ordenas por múltiples valores puedes ordenar cada valor diferentemente proporcionando un array de +direcciones de ordenación. + +El último argumento es un PHP sort flag que toma los mismos valores que los pasados a +PHP [sort()](http://php.net/manual/es/function.sort.php). + + +## Detectando Tipos de Array + +Es muy útil saber si un array es indexado o asociativo. He aquí un ejemplo: + +```php +// sin claves especificadas +$indexed = ['Qiang', 'Paul']; +echo ArrayHelper::isIndexed($indexed); + +// todas las claves son strings +$associative = ['framework' => 'Yii', 'version' => '2.0']; +echo ArrayHelper::isAssociative($associative); +``` + + +## Codificación y Decodificación de Valores HTML + +Con el fin de codificar o decodificar caracteres especiales en un array de strings con entidades HTML puedes usar lo siguiente: + +```php +$encoded = ArrayHelper::htmlEncode($data); +$decoded = ArrayHelper::htmlDecode($data); +``` + +Solo los valores se codifican por defecto. Pasando como segundo argumento `false` puedes codificar un array de claves también. +La codificación utilizará el charset de la aplicación y podría ser cambiado pasandole un tercer argumento. + + +## Fusionando Arrays + +```php + /** + * Merges two or more arrays into one recursively. + * If each array has an element with the same string key value, the latter + * will overwrite the former (different from array_merge_recursive). + * Recursive merging will be conducted if both arrays have an element of array + * type and are having the same key. + * For integer-keyed elements, the elements from the latter array will + * be appended to the former array. + * @param array $a array to be merged to + * @param array $b array to be merged from. You can specify additional + * arrays via third argument, fourth argument etc. + * @return array the merged array (the original arrays are not changed.) + */ + public static function merge($a, $b) +``` + + +## Convirtiendo Objetos a Arrays + +A menudo necesitas convertir un objeto o un array de objetos a un array. El caso más común es convertir los modelos de +active record con el fin de servir los arrays de datos vía API REST o utilizarlos de otra manera. El siguiente código +se podría utilizar para hacerlo: + +```php +$posts = Post::find()->limit(10)->all(); +$data = ArrayHelper::toArray($post, [ + 'app\models\Post' => [ + 'id', + 'title', + // el nombre de la clave del resultado del array => nombre de la propiedad + 'createTime' => 'created_at', + // el nombre de la clave del resultado del array => función anónima + 'length' => function ($post) { + return strlen($post->content); + }, + ], +]); +``` + +El primer argumento contiene el dato que queremos convertir. En nuestro caso queremos convertir un modelo AR `Post`. + +El segundo argumento es el mapeo de conversión por clase. Estamos configurando un mapeo para el modelo `Post`. +Cada array de mapeo contiene un conjunto de mapeos. Cada mapeo podría ser: + +- Un campo nombre para incluir como está. +- Un par clave-valor del array deseado con un nombre clave y el nombre de la columna del modelo que tomará el valor. +- Un par clave-valor del array deseado con un nombre clave y una función anónima que retorne el valor. + +El resultado de la conversión anterior será: + + +```php +[ + 'id' => 123, + 'title' => 'test', + 'createTime' => '2013-01-01 12:00AM', + 'length' => 301, +] +``` + +Es posible proporcionar una manera predeterminada de convertir un objeto a un array para una clase especifica +mediante la implementación de la interfaz [[yii\base\Arrayable|Arrayable]] en esa clase. diff --git a/docs/guide-es/helper-html.md b/docs/guide-es/helper-html.md new file mode 100644 index 0000000..e2cf2bb --- /dev/null +++ b/docs/guide-es/helper-html.md @@ -0,0 +1,377 @@ +Clase auxiliar Html (Html helper) +================================= + +Todas las aplicaciones web generan grandes cantidades de marcado HTML (HTML markup). Si el marcado es estático, se +puede realizar de forma efectiva +[mezclando PHP y HTML en un mismo archivo](http://php.net/manual/es/language.basic-syntax.phpmode.php) pero cuando se +generan dinámicamente empieza a complicarse su gestión sin ayuda extra. Yii ofrece esta ayuda en forma de una clase auxiliar Html +que proporciona un conjunto de métodos estáticos para gestionar las etiquetas HTML más comúnmente usadas, sus opciones y contenidos. + +> Nota: Si el marcado es casi estático, es preferible usar HTML directamente. No es necesario encapsularlo todo con +llamadas a la clase auxiliar Html. + +## Lo fundamental + + +Teniendo en cuenta que la construcción de HTML dinámico mediante la concatenación de cadenas de texto se complica +rápidamente, Yii proporciona un conjunto de métodos para manipular las opciones de etiquetas y la construcción de las +mismas basadas en estas opciones. + +### Generación de etiquetas + +El código de generación de etiquetas es similar al siguiente: + +```php +name), ['class' => 'username']) ?> +``` + +El primer argumento es el nombre de la etiqueta. El segundo es el contenido que se ubicará entre la etiqueta de +apertura y la de cierre. Hay que tener en cuenta que estamos usando `Html::encode`. Esto es debido a que el contenido +no se codifica automáticamente para permitir usar HTML cuando se necesite. La tercera opción es un array de opciones +HTML o, en otras palabras, los atributos de las etiquetas. En este array la clave representa el nombre del atributo +como podría ser `class`, `href` o `target` y el valor es su valor. + +El código anterior generará el siguiente HTML: + +```html +

samdark

+``` + +Si se necesita solo la apertura o el cierre de una etiqueta, se pueden usar los métodos `Html::beginTag()` y +`Html::endTag()`. + +Las opciones se usan en muchos métodos de la clase auxiliar Html y en varios widgets. En todos estos casos hay cierta +gestión adicional que se debe conocer: + +- Si un valor es `null`, el correspondiente atributo no se renderizará. +- Los atributos cuyos valores son de tipo booleano serán tratados como + [atributos booleanos](http://www.w3.org/TR/html5/infrastructure.html#boolean-attributes). +- Los valores de los atributos se codificarán en HTML usando [[yii\helpers\Html::encode()|Html::encode()]]. +- El atributo "data" puede recibir un array. En este caso, se "expandirá" y se renderizará una lista de atributos + `data` ej. `'data' => ['id' => 1, 'name' => 'yii']` se convierte en `data-id="1" data-name="yii"`. +- El atributo "data" puede recibir un JSON. Se gestionará de la misma manera que un array ej. + `'data' => ['params' => ['id' => 1, 'name' => 'yii'], 'status' => 'ok']` se convierte en + `data-params='{"id":1,"name":"yii"}' data-status="ok"`. + +### Formación de clases y estilos dinámicamente + +Cuando se construyen opciones para etiquetas HTML, a menudo nos encontramos con valores predeterminados que hay que +modificar. Para añadir o eliminar clases CSS se puede usar el siguiente ejemplo: + +```php +$options = ['class' => 'btn btn-default']; + +if ($type === 'success') { + Html::removeCssClass($options, 'btn-default'); + Html::addCssClass($options, 'btn-success'); +} + +echo Html::tag('div', 'Pwede na', $options); + +// cuando $type sea 'success' se renderizará +//
Pwede na
+``` + +Para hacer lo mismo con los estilos para el atributo `style`: + +```php +$options = ['style' => ['width' => '100px', 'height' => '100px']]; + +// devuelve style="width: 100px; height: 200px; position: absolute;" +Html::addCssStyle($options, 'height: 200px; positon: absolute;'); + +// devuelve style="position: absolute;" +Html::removeCssStyle($options, ['width', 'height']); +``` + +Cuando se usa [[yii\helpers\Html::addCssStyle()|addCssStyle()]] se puede especificar si un array de pares clave-valor +corresponde a nombres y valores de la propiedad CSS correspondiente o a una cadena de texto como por ejemplo +`width: 100px; height: 200px;`. Estos formatos se pueden "hacer" y "deshacer" usando +[[yii\helpers\Html::cssStyleFromArray()|cssStyleFromArray()]] y +[[yii\helpers\Html::cssStyleToArray()|cssStyleToArray()]]. El método +[[yii\helpers\Html::removeCssStyle()|removeCssStyle()]] acepta un array de propiedades que se eliminarán. Si sólo se +eliminara una propiedad, se puede especificar como una cadena de texto. + +## Codificación y Decodificación del contenido + + +Para que el contenido se muestre correctamente y de forma segura con caracteres especiales HTML el contenido debe ser +codificado. En PHP esto se hace con [htmlspecialchars](http://www.php.net/manual/es/function.htmlspecialchars.php) y +[htmlspecialchars_decode](http://www.php.net/manual/es/function.htmlspecialchars-decode.php). El problema con el uso +de estos métodos directamente es que se tiene que especificar la codificación y opciones extra cada vez. Ya que las +opciones siempre son las mismas y la codificación debe coincidir con la de la aplicación para prevenir problemas de +seguridad, Yii proporciona dos métodos simples y compactos: + +```php +$userName = Html::encode($user->name); +echo $userName; + +$decodedUserName = Html::decode($userName); +``` + +## Formularios + + +El trato con el marcado de formularios es una tarea repetitiva y propensa a errores. Por esto hay un grupo de métodos +para ayudar a gestionarlos. + +> Nota: hay que considerar la opción de usar [[yii\widgets\ActiveForm|ActiveForm]] en caso de que se gestionen +formularios que requieran validaciones. + +### Creando formularios + +Se puede abrir un formulario con el método [[yii\helpers\Html::beginForm()|beginForm()]] como se muestra a +continuación: + +```php + $id], 'post', ['enctype' => 'multipart/form-data']) ?> +``` + +El primer argumento es la URL a la que se enviarán los datos del formulario. Se puede especificar en formato de ruta +de Yii con los parámetros aceptados por [[yii\helpers\Url::to()|Url::to()]]. El segundo es el método que se usará. +`post` es el método predeterminado. El tercero es un array de opciones para la etiqueta `form`. En este caso cambiamos +el método de codificación del formulario de `data` en una petición POST a `multipart/form-data`. Esto se requiere +cuando se quieren subir archivos. + +El cierre de la etiqueta `form` es simple: + +```php + +``` + +### Botones + +Para generar botones se puede usar el siguiente código: + +```php + 'teaser']) ?> + 'submit']) ?> + 'reset']) ?> +``` + +El primer argumento para los tres métodos es el título del botón y el segundo son las opciones. El título no está +codificado pero si se usan datos recibidos por el usuario, deben codificarse mediante +[[yii\helpers\Html::encode()|Html::encode()]]. + +### Inputs + +Hay dos grupos en los métodos input. Unos empiezan con `active` y se llaman inputs activos y los otros no empiezan +así. Los inputs activos obtienen datos del modelo y del atributo especificado y los datos de los inputs normales se +especifica directamente. + +Los métodos más genéricos son: + +```php +type, input name, input value, options +name, ['class' => $username]) ?> + +type, model, model attribute name, options + $username]) ?> +``` + +Si se conoce el tipo de input de antemano, es conveniente usar los atajos de los métodos: + +- [[yii\helpers\Html::buttonInput()]] +- [[yii\helpers\Html::submitInput()]] +- [[yii\helpers\Html::resetInput()]] +- [[yii\helpers\Html::textInput()]], [[yii\helpers\Html::activeTextInput()]] +- [[yii\helpers\Html::hiddenInput()]], [[yii\helpers\Html::activeHiddenInput()]] +- [[yii\helpers\Html::passwordInput()]] / [[yii\helpers\Html::activePasswordInput()]] +- [[yii\helpers\Html::fileInput()]], [[yii\helpers\Html::activeFileInput()]] +- [[yii\helpers\Html::textarea()]], [[yii\helpers\Html::activeTextarea()]] + +Los botones de opción (Radios) y las casillas de verificación (checkboxes) se especifican de forma un poco diferente: + +```php + 'I agree']); + 'agreement']) + + 'I agree']); + 'agreement']) +``` + +Las listas desplegables (dropdown list) se pueden renderizar como se muestra a continuación: + +```php + + + + + +``` + +El primer argumento es el nombre del input, el segundo es el valor seleccionado actualmente y el tercero es el array +de pares clave-valor donde la clave es la lista de valores y el valor del array es la lista a mostrar. + +Si se quiere habilitar la selección múltiple, se puede usar la lista seleccionable (checkbox list): + +```php + + +``` + +Si no, se puede usar la lista de opciones (radio list): + +```php + + +``` + +### Etiquetas y Errores + +De forma parecida que en los inputs hay dos métodos para generar etiquetas. El activo que obtiene los datos del modelo y +el no-activo que acepta los datos directamente: + +```php + 'label username']) ?> + 'label username']) +``` + +Para mostrar los errores del formulario de un modelo o modelos a modo de resumen puedes usar: + +```php + 'errors']) ?> +``` + +Para mostrar un error individual: + +```php + 'error']) ?> +``` + +### Input Names y Values + +Existen métodos para obtener names, IDs y values para los campos de entrada (inputs) basados en el modelo. Estos se +usan principalmente internamente pero a veces pueden resultar prácticos: + +```php +// Post[title] +echo Html::getInputName($post, 'title'); + +// post-title +echo Html::getInputId($post, 'title'); + +// mi primer post +echo Html::getAttributeValue($post, 'title'); + +// $post->authors[0] +echo Html::getAttributeValue($post, '[0]authors[0]'); +``` + +En el ejemplo anterior, el primer argumento es el modelo y el segundo es un atributo de expresión. En su forma más +simple es su nombre de atributo pero podría ser un nombre de atributo prefijado y/o añadido como sufijo con los +indices de un array, esto se usa principalmente para mostrar inputs en formatos de tablas: + +- `[0]content` se usa en campos de entrada de datos en formato de tablas para representar el atributo "content" para + el primer modelo del input en formato de tabla; +- `dates[0]` representa el primer elemento del array del atributo "dates"; +- `[0]dates[0]` representa el primer elemento del array del atributo "dates" para el primer modelo en formato de tabla. + +Para obtener el nombre de atributo sin sufijos o prefijos se puede usar el siguiente código: + +```php +// dates +echo Html::getAttributeName('dates[0]'); +``` + +## Estilos y scripts + + +Existen dos métodos para generar etiquetas que envuelvan estilos y scripts incrustados (embebbed): + +```php + + +Genera + + + + true]); + +Genera + + +``` + +Si se quiere enlazar un estilo externo desde un archivo CSS: + +```php + 'IE 5']) ?> + +genera + + +``` + +El primer argumento es la URL. El segundo es un array de opciones. Adicionalmente, para regular las opciones se puede +especificar: + +- `condition` para envolver `` por lo que el sólo se + incluirá si el navegador no soporta JavaScript o si lo ha deshabilitado el usuario. + +Para enlazar un archivo JavaScript: + +```php + +``` + +Es igual que con las CSS, el primer argumento especifica el enlace al fichero que se quiere incluir. Las opciones se +pueden pasar como segundo argumento. En las opciones se puede especificar `condition` del mismo modo que se puede usar +para `cssFile`. + +## Enlaces + + +Existe un método para generar hipervínculos a conveniencia: + +```php + $id], ['class' => 'profile-link']) ?> +``` + +El primer argumento es el título. No está codificado por lo que si se usan datos enviados por el usuario se tienen que +codificar usando `Html::encode()`. El segundo argumento es el que se introducirá en `href` de la etiqueta ` +``` + +## Imagenes + + +Para generar una etiqueta de tipo imagen se puede usar el siguiente ejemplo: + +```php + 'My logo']) ?> + +genera + +My logo +``` + +Aparte de los [alias](concept-aliases.md) el primer argumento puede aceptar rutas, parámetros y URLs. Del mismo modo +que [Url::to()](helper-url.md). + +## Listas + + +Las listas desordenadas se puede generar como se muestra a continuación: + +```php + function($item, $index) { + return Html::tag( + 'li', + $this->render('post', ['item' => $item]), + ['class' => 'post'] + ); +}]) ?> +``` + +Para generar listas ordenadas se puede usar `Html::ol()` en su lugar. diff --git a/docs/guide-es/helper-overview.md b/docs/guide-es/helper-overview.md new file mode 100644 index 0000000..3bf4354 --- /dev/null +++ b/docs/guide-es/helper-overview.md @@ -0,0 +1,79 @@ +Helpers +======= + +> Nota: Esta sección está en desarrollo. + +Yii ofrece muchas clases que ayudan a simplificar las tareas comunes de codificación, como manipulación de string o array, +generación de código HTML, y más. Estas clases helper están organizadas bajo el namespace `yii\helpers` y +son todo clases estáticas (lo que significa que sólo contienen propiedades y métodos estáticos y no deben ser instanciadas). + +Puedes usar una clase helper directamente llamando a uno de sus métodos estáticos, como a continuación: + +```php +use yii\helpers\Html; + +echo Html::encode('Test > test'); +``` + +> Nota: Para soportar la [personalización de clases helper](#customizing-helper-classes), Yii separa cada clase helper del núcleo + en dos clases: una clase base (ej. `BaseArrayHelper`) y una clase concreta (ej. `ArrayHelper`). + Cuando uses un helper, deberías sólo usar la versión concreta y nunca usar la clase base. + + +Clases Helper del núcleo +------------------------ + +Las siguientes clases helper del núcleo son proporcionadas en los releases de Yii: + +- [ArrayHelper](helper-array.md) +- Console +- FileHelper +- [Html](helper-html.md) +- HtmlPurifier +- Image +- Inflector +- Json +- Markdown +- Security +- StringHelper +- [Url](helper-url.md) +- VarDumper + + +Personalizando Las Clases Helper +-------------------------------- + +Para personalizar una clase helper del núcleo (ej. [[yii\helpers\ArrayHelper]]), deberías crear una nueva clase extendiendo +de los helpers correspondientes a la clase base (ej. [[yii\helpers\BaseArrayHelper]]), incluyendo su namespace. Esta clase +será creada para remplazar la implementación original del framework. + +El siguiente ejemplo muestra como personalizar el método [[yii\helpers\ArrayHelper::merge()|merge()]] de la clase +[[yii\helpers\ArrayHelper]]: + +```php + 42]); +``` + +Se puede especificar la ruta como una cadena de texto, ej. `site/index`. También se puede usar un array si se +quieren especificar parámetros para la URL que se esta generando. El formato del array debe ser: + +```php +// genera: /index.php?r=site/index¶m1=value1¶m2=value2 +['site/index', 'param1' => 'value1', 'param2' => 'value2'] +``` + +Si se quiere crear una URL con un enlace, se puede usar el formato de array con el parámetro `#`. Por ejemplo, + +```php +// genera: /index.php?r=site/index¶m1=value1#name +['site/index', 'param1' => 'value1', '#' => 'name'] +``` + +Una ruta puede ser absoluta o relativa. Una ruta absoluta tiene una barra al principio (ej. `/site/index`), +mientras que una ruta relativa no la tiene (ej. `site/index` o `index`). Una ruta relativa se convertirá en una +ruta absoluta siguiendo las siguientes normas: + +- Si la ruta es una cadena vacía, se usará la [[\yii\web\Controller::route|route]] actual; +- Si la ruta no contiene barras (ej. `index`), se considerará que es el ID de una acción del controlador actual y + se antepondrá con [[\yii\web\Controller::uniqueId]]; +- Si la ruta no tiene barra inicial (ej. `site/index`), se considerará que es una ruta relativa del modulo actual y + se le antepondrá el [[\yii\base\Module::uniqueId|uniqueId]] del modulo. + +A continuación se muestran varios ejemplos del uso de este método: + +```php +// /index?r=site/index +echo Url::toRoute('site/index'); + +// /index?r=site/index&src=ref1#name +echo Url::toRoute(['site/index', 'src' => 'ref1', '#' => 'name']); + +// http://www.example.com/index.php?r=site/index +echo Url::toRoute('site/index', true); + +// https://www.example.com/index.php?r=site/index +echo Url::toRoute('site/index', 'https'); +``` + +El otro método `Url::to()` es muy similar a [[toRoute()]]. La única diferencia es que este método requiere que la ruta +especificada sea un array. Si se pasa una cadena de texto, se tratara como una URL. + +El primer argumento puede ser: + +- un array: se llamará a [[toRoute()]] para generar la URL. Por ejemplo: `['site/index']`, + `['post/index', 'page' => 2]`. Se puede revisar [[toRoute()]] para obtener más detalles acerca de como especificar + una ruta. +- una cadena que empiece por `@`: se tratará como un alias, y se devolverá la cadena correspondiente asociada a este + alias. +- una cadena vacía: se devolverá la URL de la petición actual; +- una cadena de texto: se devolverá sin alteraciones. + +Cuando se especifique `$schema` (tanto una cadena de text como `true`), se devolverá una URL con información del host +(obtenida mediante [[\yii\web\UrlManager::hostInfo]]). Si `$url` ya es una URL absoluta, su esquema se reemplazará con +el especificado. + +A continuación se muestran algunos ejemplos de uso: + +```php +// /index?r=site/index +echo Url::to(['site/index']); + +// /index?r=site/index&src=ref1#name +echo Url::to(['site/index', 'src' => 'ref1', '#' => 'name']); + +// la URL solicitada actualmente +echo Url::to(); + +// /images/logo.gif +echo Url::to('@web/images/logo.gif'); + +// images/logo.gif +echo Url::to('images/logo.gif'); + +// http://www.example.com/images/logo.gif +echo Url::to('@web/images/logo.gif', true); + +// https://www.example.com/images/logo.gif +echo Url::to('@web/images/logo.gif', 'https'); +``` + +Recordar la URL para utilizarla más adelante +-------------------------------------------- + +Hay casos en que se necesita recordar la URL y después usarla durante el procesamiento de una de las peticiones +secuenciales. Se puede logar de la siguiente manera: + +```php +// Recuerda la URL actual +Url::remember(); + +// Recuerda la URL especificada. Revisar Url::to() para ver formatos de argumentos. +Url::remember(['product/view', 'id' => 42]); + +// Recuerda la URL especificada con un nombre asignado +Url::remember(['product/view', 'id' => 42], 'product'); +``` + +En la siguiente petición se puede obtener la URL memorizada de la siguiente manera: + +```php +$url = Url::previous(); +$productUrl = Url::previous('product'); +``` + +Reconocer la relatividad de URLs +-------------------------------- + +Para descubrir si una URL es relativa, es decir, que no contenga información del host, se puede utilizar el siguiente +código: + +```php +$isRelative = Url::isRelative('test/it'); +``` diff --git a/docs/guide-es/images/application-lifecycle.png b/docs/guide-es/images/application-lifecycle.png deleted file mode 100644 index 1a47ee9..0000000 Binary files a/docs/guide-es/images/application-lifecycle.png and /dev/null differ diff --git a/docs/guide-es/images/application-structure.graphml b/docs/guide-es/images/application-structure.graphml new file mode 100644 index 0000000..dde7359 --- /dev/null +++ b/docs/guide-es/images/application-structure.graphml @@ -0,0 +1,429 @@ + + + + + + + + + + + + + + + + + + + + + + + componente +de +aplicación + + + + + + + + + + + + + + + + + script de entrada + + + + + + + + + + + + + + + + + aplicación + + + + + + + + + + + + + + + + + controlador + + + + + + + + + + + + + + + + + filtro + + + + + + + + + + + + + + + + + módulo + + + + + + + + + + + + + + + + + vista + + + + + + + + + + + + + + + + + modelo + + + + + + + + + + + + + + + + + widget + + + + + + + + + + + + + + + + + recursos + + + + + + + + + + + + + + + + + 1:1 + + + + + + + + + + + + + + + + + + 0..* + + + + + + + + + + + + + + + + + + 0..* + + + + + + + + + + + + + + + + + + 1..* + + + + + + + + + + + + + + + + + + 0..* + + + + + + + + + + + + + + + + + + + + 0..* + + + + + + + + + + + + + + + + + + 0..* + + + + + + + + + + + + + + + + + + 0..* + + + + + + + + + + + + + + + + + + 0..* + + + + + + + + + + + + + + + + + + 0..* + + + + + + + + + + + + + + + + + + 0..* + + + + + + + + + + + + + + + + + + 0..* + + + + + + + + + + + + + + + + + + 0..* + + + + + + + + + + + + + + + + diff --git a/docs/guide-es/images/application-structure.png b/docs/guide-es/images/application-structure.png index d3a5549..4d120c2 100644 Binary files a/docs/guide-es/images/application-structure.png and b/docs/guide-es/images/application-structure.png differ diff --git a/docs/guide-es/images/request-lifecycle.graphml b/docs/guide-es/images/request-lifecycle.graphml new file mode 100644 index 0000000..533eaf0 --- /dev/null +++ b/docs/guide-es/images/request-lifecycle.graphml @@ -0,0 +1,834 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + usuario + + + + + + + + + + + + + + + + + + + + modelo + + + + + + + + + + + + + + + + + base de datos + + + + + + + + + + + + + + + + + + + + + + + + + + + + vista + + + + + + + + + + + + + + + + + + + + controlador + + + + + + + + + + Folder 1 + + + + + + + + + + + + + + + + crear acción + + + + + + + + + + + + + + + + + ejecutar filtros + + + + + + + + + + + + + + + + + + + + acción + + + + + + + + + + Folder 3 + + + + + + + + + + + + + + + + cargar modelo + + + + + + + + + + + + + + + + + renderizar vista + + + + + + + + + + + + + + + + + + + + + respuesta + + + + + + + + + + + + + + + + + petición + + + + + + + + + + + + + + + + + + + + aplicación + + + + + + + + + + Folder 2 + + + + + + + + + + + + + + + + resolver ruta + + + + + + + + + + + + + + + + + crear controlador + + + + + + + + + + + + + + + + + + + + + + script de entrada + + + + + + + + + + Folder 4 + + + + + + + + + + + + + + + + cargar configuración de aplicación + + + + + + + + + + + + + + + + + ejecutar aplicación + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 11 + + + + + + + + + + + + + + + + + + 3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + + + + + + + + + + + + + + + 4 + + + + + + + + + + + + + + + + + + 9 + + + + + + + + + + + + + + + + + + 10 + + + + + + + + + + + + + + + + + + 2 + + + + + + + + + + + + + + + + + + 8 + + + + + + + + + + + + + + + + + + + + 6 + + + + + + + + + + + + + + + + + + 5 + + + + + + + + + + + + + + + + + + 7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <?xml version="1.0" encoding="utf-8"?> +<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + width="57px" height="66px" viewBox="0 0 57 66" enable-background="new 0 0 57 66" xml:space="preserve"> +<g> + + <linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="26.3799" y1="-2276.8809" x2="27.6209" y2="-2306.6792" gradientTransform="matrix(1 0 0 -1 0.2803 -2252.9199)"> + <stop offset="0.2711" style="stop-color:#FFAB4F"/> + <stop offset="1" style="stop-color:#FFD28F"/> + </linearGradient> + <path fill="url(#SVGID_1_)" stroke="#ED9135" stroke-miterlimit="10" d="M49.529,51.225c-4.396-4.396-10.951-5.884-12.063-6.109 + V37.8H19.278c0,0,0.038,6.903,0,6.868c0,0-6.874,0.997-12.308,6.432C1.378,56.691,0.5,62.77,0.5,62.77 + c0,1.938,1.575,3.492,3.523,3.492h48.51c1.947,0,3.521-1.558,3.521-3.492C56.055,62.768,54.211,55.906,49.529,51.225z"/> + <path id="body_13_" fill="#ECECEC" stroke="#9B9B9B" stroke-miterlimit="10" d="M0.5,62.768c0,1.938,1.575,3.494,3.523,3.494h48.51 + c1.947,0,3.521-1.559,3.521-3.494c0,0-1.844-6.861-6.525-11.543c-4.815-4.813-11.244-6.146-11.244-6.146 + c-1.771,1.655-5.61,3.802-10.063,3.802c-4.453,0-8.292-2.146-10.063-3.802c0,0-5.755,0.586-11.189,6.021 + C1.378,56.689,0.5,62.768,0.5,62.768z"/> + <path fill="#2068A3" stroke="#2068A3" d="M28.106,33.487c-8.112,0-12.688,4.312-12.688,10.437c0,7.422,12.688,10.438,12.688,10.438 + s14.688-3.016,14.688-10.438C42.793,38.75,36.215,33.487,28.106,33.487z M26.288,53.051c0,0-7.135-2.093-8.805-7.201 + c-0.222-0.682,0.147-1.156,0.795-1.521V37.8h20.188v6.663c0.235,0.352,1.109,0.737,1.229,1.387 + C40.445,49.917,26.288,53.051,26.288,53.051z"/> + + <radialGradient id="SVGID_2_" cx="14.2417" cy="9.1006" r="53.247" gradientTransform="matrix(1 0 0 -1 0.04 65.1543)" gradientUnits="userSpaceOnUse"> + <stop offset="0" style="stop-color:#74AEEE"/> + <stop offset="1" style="stop-color:#2068A3"/> + </radialGradient> + <path fill="url(#SVGID_2_)" stroke="#2068A3" stroke-miterlimit="10" d="M49.529,51.225c-2.239-2.24-5.041-3.724-7.396-4.67 + c-2.854,5.51-14.022,7.807-14.022,7.807s-10.472-2.484-12.387-8.514c-2.439,0.771-5.787,2.287-8.749,5.25 + c-5.592,5.592-6.47,11.67-6.47,11.67c0,1.938,1.575,3.492,3.523,3.492h48.51c1.947,0,3.521-1.558,3.521-3.492 + C56.055,62.768,54.211,55.906,49.529,51.225z"/> + <path fill="#5491CF" stroke="#2068A3" d="M13.404,44.173c1.15-1.81,2.039-3.832,3.332-5.397c-0.514,1.027-1.669,4.084-1.669,5.148 + c0,5.186,10.366,9.079,14.688,10.438c-3.472,1.627-9.134-1.498-11.335-2.36c-3.601-1.419-4.071-3.063-5.89-4.854 + C12.523,47.135,12.878,45,13.404,44.173z"/> + <path fill="#5491CF" stroke="#2068A3" d="M45.777,43.924c-1.317-1.568-5.11-9.424-6.604-6.617c0.516,1.025,3.617,3.693,3.617,6.617 + c0,5.186-10.27,8.576-16.698,9.145c1.429,4.938,11.372,1.293,13.804-0.313c3.563-2.354,4.563-5.133,7.854-3.705 + C47.754,49.045,48.006,46.574,45.777,43.924z"/> + <path fill="none" stroke="#2068A3" stroke-linecap="round" d="M30.777,54.167c0.357,0.836-0.153,1.983-0.352,2.813 + c-0.256,1.084-0.072,2.104,0.102,3.186c0.164,1.02,0.156,2.107,0.25,3.167c0.082,0.916,0.482,1.849,0.357,2.75"/> + <path fill="none" stroke="#2068A3" stroke-linecap="round" d="M23.695,53.417c-0.508,0.584-0.476,2.209-0.398,3 + c0.116,1.183,0.456,2.099,0.333,3.333c-0.192,1.943,0.154,4.479-0.436,6.333"/> + + <radialGradient id="face_x5F_white_1_" cx="27.623" cy="-2278.646" r="23.425" fx="23.0534" fy="-2281.1357" gradientTransform="matrix(1 0 0 -1 0.2803 -2252.9199)" gradientUnits="userSpaceOnUse"> + <stop offset="0" style="stop-color:#FFD28F"/> + <stop offset="1" style="stop-color:#FFAB4F"/> + </radialGradient> + <path id="face_x5F_white_3_" fill="url(#face_x5F_white_1_)" stroke="#ED9135" stroke-miterlimit="10" d="M43.676,23.357 + c0.086,10.2-6.738,18.52-15.25,18.586c-8.5,0.068-15.464-8.146-15.55-18.344C12.794,13.4,19.618,5.079,28.123,5.012 + C36.627,4.945,43.59,13.158,43.676,23.357z"/> + + <linearGradient id="face_highlight_1_" gradientUnits="userSpaceOnUse" x1="5761.7578" y1="11330.6484" x2="5785.3872" y2="11424.0977" gradientTransform="matrix(0.275 0 0 0.2733 -1558.9874 -3088.4209)"> + <stop offset="0" style="stop-color:#FFFFFF;stop-opacity:0.24"/> + <stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.16"/> + </linearGradient> + <path id="face_highlight_3_" fill="url(#face_highlight_1_)" d="M27.958,6.333c-6.035,0.047-10.747,4.493-12.787,10.386 + c-0.664,1.919-0.294,4.043,0.98,5.629c2.73,3.398,5.729,6.283,9.461,8.088c3.137,1.518,7.535,2.385,11.893,1.247 + c2.274-0.592,3.988-2.459,4.375-4.766c0.187-1.094,0.293-2.289,0.283-3.553C42.083,13.952,36.271,6.268,27.958,6.333z"/> + <path id="Hair_Young_Brown_1_" fill="#CC9869" stroke="#99724F" stroke-linecap="round" stroke-linejoin="round" d="M20.278,13.25 + c3.417,4.333,9.333,6.917,9.333,6.917l-1.417-3.5c0,0,7.094,4.691,8.083,4.333c0.968-0.2-1.082-3.807-1.082-3.807 + s3.138,1.795,4.854,3.969c1.803,2.28,4.285,3.504,4.285,3.504S47.027,2.719,27.289,2.744C8.278,2.709,12.058,27.678,12.058,27.678 + L14.695,17c0,0,0.914,5.757,1.399,4.875C17.861,15.211,18.861,11.5,20.278,13.25z"/> + <path fill="#4B4B4B" stroke="#4B4B4B" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M28.105,2 + C22.464,2,20.2,4.246,18.13,5.533C29.753,2.865,41.152,10.375,44.46,20.5C44.459,16.875,44.459,2,28.105,2z"/> + <path fill="#9B9B9B" stroke="#4B4B4B" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M11.151,17.751 + C12.878,8.25,18.686,6.309,25.273,7.127C31.295,7.875,36.93,10.491,44.459,20.5C37.777,7.125,20.278-3.375,9.903,3.921 + C5.569,6.97,4.903,13.375,11.151,17.751z"/> +</g> +</svg> + + <?xml version="1.0" encoding="utf-8"?> +<svg version="1.1" + xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" + x="0px" y="0px" width="41px" height="48px" viewBox="-0.875 -0.887 41 48" enable-background="new -0.875 -0.887 41 48" + xml:space="preserve"> +<defs> +</defs> +<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="642.8008" y1="-979.1445" x2="682.0508" y2="-979.1445" gradientTransform="matrix(1 0 0 -1 -642.8008 -939.4756)"> + <stop offset="0" style="stop-color:#3C89C9"/> + <stop offset="0.1482" style="stop-color:#60A6DD"/> + <stop offset="0.3113" style="stop-color:#81C1F0"/> + <stop offset="0.4476" style="stop-color:#95D1FB"/> + <stop offset="0.5394" style="stop-color:#9CD7FF"/> + <stop offset="0.636" style="stop-color:#98D4FD"/> + <stop offset="0.7293" style="stop-color:#8DCAF6"/> + <stop offset="0.8214" style="stop-color:#79BBEB"/> + <stop offset="0.912" style="stop-color:#5EA5DC"/> + <stop offset="1" style="stop-color:#3C89C9"/> +</linearGradient> +<path fill="url(#SVGID_1_)" d="M19.625,36.763C8.787,36.763,0,34.888,0,32.575v10c0,2.313,8.787,4.188,19.625,4.188 + c10.839,0,19.625-1.875,19.625-4.188v-10C39.25,34.888,30.464,36.763,19.625,36.763z"/> +<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="642.8008" y1="-973.1445" x2="682.0508" y2="-973.1445" gradientTransform="matrix(1 0 0 -1 -642.8008 -939.4756)"> + <stop offset="0" style="stop-color:#9CD7FF"/> + <stop offset="0.0039" style="stop-color:#9DD7FF"/> + <stop offset="0.2273" style="stop-color:#BDE5FF"/> + <stop offset="0.4138" style="stop-color:#D1EEFF"/> + <stop offset="0.5394" style="stop-color:#D9F1FF"/> + <stop offset="0.6155" style="stop-color:#D5EFFE"/> + <stop offset="0.6891" style="stop-color:#C9E7FA"/> + <stop offset="0.7617" style="stop-color:#B6DAF3"/> + <stop offset="0.8337" style="stop-color:#9AC8EA"/> + <stop offset="0.9052" style="stop-color:#77B0DD"/> + <stop offset="0.9754" style="stop-color:#4D94CF"/> + <stop offset="1" style="stop-color:#3C89C9"/> +</linearGradient> +<path fill="url(#SVGID_2_)" d="M19.625,36.763c10.839,0,19.625-1.875,19.625-4.188l-1.229-2c0,2.168-8.235,3.927-18.396,3.927 + c-9.481,0-17.396-1.959-18.396-3.927l-1.229,2C0,34.888,8.787,36.763,19.625,36.763z"/> +<path fill="#3C89C9" d="M19.625,26.468c10.16,0,19.625,2.775,19.625,2.775c-0.375,2.721-5.367,5.438-19.554,5.438 + c-12.125,0-18.467-2.484-19.541-4.918C-0.127,29.125,9.465,26.468,19.625,26.468z"/> +<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="642.8008" y1="-965.6948" x2="682.0508" y2="-965.6948" gradientTransform="matrix(1 0 0 -1 -642.8008 -939.4756)"> + <stop offset="0" style="stop-color:#3C89C9"/> + <stop offset="0.1482" style="stop-color:#60A6DD"/> + <stop offset="0.3113" style="stop-color:#81C1F0"/> + <stop offset="0.4476" style="stop-color:#95D1FB"/> + <stop offset="0.5394" style="stop-color:#9CD7FF"/> + <stop offset="0.636" style="stop-color:#98D4FD"/> + <stop offset="0.7293" style="stop-color:#8DCAF6"/> + <stop offset="0.8214" style="stop-color:#79BBEB"/> + <stop offset="0.912" style="stop-color:#5EA5DC"/> + <stop offset="1" style="stop-color:#3C89C9"/> +</linearGradient> +<path fill="url(#SVGID_3_)" d="M19.625,23.313C8.787,23.313,0,21.438,0,19.125v10c0,2.313,8.787,4.188,19.625,4.188 + c10.839,0,19.625-1.875,19.625-4.188v-10C39.25,21.438,30.464,23.313,19.625,23.313z"/> +<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="642.8008" y1="-959.6948" x2="682.0508" y2="-959.6948" gradientTransform="matrix(1 0 0 -1 -642.8008 -939.4756)"> + <stop offset="0" style="stop-color:#9CD7FF"/> + <stop offset="0.0039" style="stop-color:#9DD7FF"/> + <stop offset="0.2273" style="stop-color:#BDE5FF"/> + <stop offset="0.4138" style="stop-color:#D1EEFF"/> + <stop offset="0.5394" style="stop-color:#D9F1FF"/> + <stop offset="0.6155" style="stop-color:#D5EFFE"/> + <stop offset="0.6891" style="stop-color:#C9E7FA"/> + <stop offset="0.7617" style="stop-color:#B6DAF3"/> + <stop offset="0.8337" style="stop-color:#9AC8EA"/> + <stop offset="0.9052" style="stop-color:#77B0DD"/> + <stop offset="0.9754" style="stop-color:#4D94CF"/> + <stop offset="1" style="stop-color:#3C89C9"/> +</linearGradient> +<path fill="url(#SVGID_4_)" d="M19.625,23.313c10.839,0,19.625-1.875,19.625-4.188l-1.229-2c0,2.168-8.235,3.926-18.396,3.926 + c-9.481,0-17.396-1.959-18.396-3.926l-1.229,2C0,21.438,8.787,23.313,19.625,23.313z"/> +<path fill="#3C89C9" d="M19.476,13.019c10.161,0,19.625,2.775,19.625,2.775c-0.375,2.721-5.367,5.438-19.555,5.438 + c-12.125,0-18.467-2.485-19.541-4.918C-0.277,15.674,9.316,13.019,19.476,13.019z"/> +<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="642.8008" y1="-952.4946" x2="682.0508" y2="-952.4946" gradientTransform="matrix(1 0 0 -1 -642.8008 -939.4756)"> + <stop offset="0" style="stop-color:#3C89C9"/> + <stop offset="0.1482" style="stop-color:#60A6DD"/> + <stop offset="0.3113" style="stop-color:#81C1F0"/> + <stop offset="0.4476" style="stop-color:#95D1FB"/> + <stop offset="0.5394" style="stop-color:#9CD7FF"/> + <stop offset="0.636" style="stop-color:#98D4FD"/> + <stop offset="0.7293" style="stop-color:#8DCAF6"/> + <stop offset="0.8214" style="stop-color:#79BBEB"/> + <stop offset="0.912" style="stop-color:#5EA5DC"/> + <stop offset="1" style="stop-color:#3C89C9"/> +</linearGradient> +<path fill="url(#SVGID_5_)" d="M19.625,10.113C8.787,10.113,0,8.238,0,5.925v10c0,2.313,8.787,4.188,19.625,4.188 + c10.839,0,19.625-1.875,19.625-4.188v-10C39.25,8.238,30.464,10.113,19.625,10.113z"/> +<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="642.8008" y1="-946.4946" x2="682.0508" y2="-946.4946" gradientTransform="matrix(1 0 0 -1 -642.8008 -939.4756)"> + <stop offset="0" style="stop-color:#9CD7FF"/> + <stop offset="0.0039" style="stop-color:#9DD7FF"/> + <stop offset="0.2273" style="stop-color:#BDE5FF"/> + <stop offset="0.4138" style="stop-color:#D1EEFF"/> + <stop offset="0.5394" style="stop-color:#D9F1FF"/> + <stop offset="0.6155" style="stop-color:#D5EFFE"/> + <stop offset="0.6891" style="stop-color:#C9E7FA"/> + <stop offset="0.7617" style="stop-color:#B6DAF3"/> + <stop offset="0.8337" style="stop-color:#9AC8EA"/> + <stop offset="0.9052" style="stop-color:#77B0DD"/> + <stop offset="0.9754" style="stop-color:#4D94CF"/> + <stop offset="1" style="stop-color:#3C89C9"/> +</linearGradient> +<path fill="url(#SVGID_6_)" d="M19.625,10.113c10.839,0,19.625-1.875,19.625-4.188l-1.229-2c0,2.168-8.235,3.926-18.396,3.926 + c-9.481,0-17.396-1.959-18.396-3.926L0,5.925C0,8.238,8.787,10.113,19.625,10.113z"/> +<linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="644.0293" y1="-943.4014" x2="680.8223" y2="-943.4014" gradientTransform="matrix(1 0 0 -1 -642.8008 -939.4756)"> + <stop offset="0" style="stop-color:#9CD7FF"/> + <stop offset="1" style="stop-color:#3C89C9"/> +</linearGradient> +<ellipse fill="url(#SVGID_7_)" cx="19.625" cy="3.926" rx="18.396" ry="3.926"/> +<path opacity="0.24" fill="#FFFFFF" enable-background="new " d="M31.04,45.982c0,0-4.354,0.664-7.29,0.781 + c-3.125,0.125-8.952,0-8.952,0l-2.384-10.292l0.044-2.108l-1.251-1.154L9.789,23.024l-0.082-0.119L9.5,20.529l-1.65-1.254 + L5.329,8.793c0,0,4.213,0.903,7.234,1.07s8.375,0.25,8.375,0.25l3,9.875l-0.25,1.313l1.063,2.168l2.312,9.645l-0.521,1.416 + l1.46,1.834L31.04,45.982z"/> +</svg> + + + + diff --git a/docs/guide-es/images/request-lifecycle.png b/docs/guide-es/images/request-lifecycle.png new file mode 100644 index 0000000..554d64b Binary files /dev/null and b/docs/guide-es/images/request-lifecycle.png differ diff --git a/docs/guide-es/images/start-gii-crud-preview.png b/docs/guide-es/images/start-gii-crud-preview.png new file mode 100644 index 0000000..85c2355 Binary files /dev/null and b/docs/guide-es/images/start-gii-crud-preview.png differ diff --git a/docs/guide-es/images/start-gii-crud.png b/docs/guide-es/images/start-gii-crud.png index a3aa21b..77c1ada 100644 Binary files a/docs/guide-es/images/start-gii-crud.png and b/docs/guide-es/images/start-gii-crud.png differ diff --git a/docs/guide-es/intro-upgrade-from-v1.md b/docs/guide-es/intro-upgrade-from-v1.md index 0a995a7..bcb4df3 100644 --- a/docs/guide-es/intro-upgrade-from-v1.md +++ b/docs/guide-es/intro-upgrade-from-v1.md @@ -6,7 +6,7 @@ en su segunda versión. Como resultado, actualizar desde la versión 1.1 no es tan trivial como actualizar entre versiones menores. En esta guía encontrarás las diferencias más grandes entre estas dos versiones. -Si no has utilizado Yii 1.1 antes, puedes saltar con seguridad esta sección e ir directamente a "[Comenzando con Yii](start-installation.md)". +Si no has utilizado Yii 1.1 antes, puedes saltarte con seguridad esta sección e ir directamente a "[Comenzando con Yii](start-installation.md)". Es importante anotar que Yii 2.0 introduce más características de las que van a ser cubiertas en este resumen. Es altamente recomendado que leas a través de toda la guía definitiva para aprender acerca de todas ellas. Hay muchas posibilidades de que algo que hayas desarrollado anteriormente para extender Yii, sea ahora parte del núcleo de la librería. @@ -17,8 +17,8 @@ Instalación Yii 2.0 adopta íntegramente [Composer](https://getcomposer.org/), el administrador de paquetes de facto de PHP. Tanto la instalación del núcleo del framework como las extensiones se manejan a través de Composer. Por favor consulta -la sección [Comenzando con la Aplicación Básica](start-basic.md) para aprender a instalar Yii 2.0. Si quieres crear extensiones -o transformar extensiones de Yii 1.1 para que sean compatibles con Yii 2.0, consulta la sección [Creando Extensiones](extend-creating-extensions.md) de la guía. +la sección [Comenzando con la Aplicación Básica](start-installation.md) para aprender a instalar Yii 2.0. Si quieres crear extensiones +o transformar extensiones de Yii 1.1 para que sean compatibles con Yii 2.0, consulta la sección [Creando Extensiones](structure-extensions.md#creating-extensions) de la guía. Requerimientos de PHP @@ -30,13 +30,13 @@ Abajo hay un resumen de los mayores cambios en relación a PHP: - [Namespaces](http://php.net/manual/es/language.namespaces.php). - [Funciones anónimas](http://php.net/manual/es/functions.anonymous.php). -- Sintáxis cortas de Arrays `[...elementos...]` es utilizado en vez de `array(...elementos...)`. +- La sintaxis corta de Arrays `[...elementos...]` es utilizada en vez de `array(...elementos...)`. - Etiquetas cortas de `echo`. Ahora en las vistas se usa `on($eventName, $handler); Hay muchas mejoras en lo que respecta a eventos. Para más detalles, consulta la sección [Eventos](concept-events.md). -Path Alias ----------- +Alias +----- -Yii 2.0 extiende el uso de path alias tanto para archivos/directorios como URLs. Yii 2.0 ahora requiere que cada +Yii 2.0 extiende el uso de alias tanto para archivos/directorios como URLs. Yii 2.0 ahora requiere que cada alias comience con el carácter `@`, para diferenciarlos de rutas o URLs normales. -Por ejemplo, el alias `@yii` corresponde al directorio donde Yii se encuentra instalado. Los path alias +Por ejemplo, el alias `@yii` corresponde al directorio donde Yii se encuentra instalado. Los alias están soportados en la mayor parte del núcleo. Por ejemplo, [[yii\caching\FileCache::cachePath]] puede tomar tanto una ruta de directorios normal como un alias. -Un path alias está relacionado de cerca con un namespace. Se recomienda definir un path alias +Un alias está estrechamente relacionado con un namespace de la clase. Se recomienda definir un alias por cada namespace raíz, y así poder utilizar el autolader de Yii sin otra configuración. Por ejemplo, debido a que `@yii` se refiere al directorio de instalación, una clase como `yii\web\Request` puede ser auto-cargada. Si estás utilizando una librería de terceros, -como Zend Framework, puedes definir un path alias `@Zend` que se refiera al directorio de instalación +como Zend Framework, puedes definir un alias `@Zend` que se refiera al directorio de instalación de ese framework. Una vez realizado esto, Yii será capaz de auto-cargar cualquier clase de Zend Framework también. -Se puede encontrar más detalles del tema en la sección [Path Alias](concept-aliases.md). +Se puede encontrar más detalles del tema en la sección [Alias](concept-aliases.md). Vistas ------ -El cambio más significativo con respecto a las vistas en Yii 2 es que la variable especial `$this` (dentro de una vista) +El cambio más significativo con respecto a las vistas en Yii 2 es que la variable especial `$this` dentro de una vista ya no se refiere al controlador o widget actual. En vez de eso, `$this` ahora se refiere al objeto de la *vista*, un concepto nuevo introducido en Yii 2.0. -El objeto *vista* es del tipo [[yii\web\View]], que representa la parte de las vistas en el patrón MVC. -of the MVC pattern. Si quieres acceder al controlador o al widget correspondiente desde la propia vista, +El objeto *vista* es del tipo [[yii\web\View]], que representa la parte de las vistas en el patrón MVC. Si +quieres acceder al controlador o al widget correspondiente desde la propia vista, puedes utilizar `$this->context`. Para renderizar una vista parcial (partial) dentro de otra vista, se utiliza `$this->render()`, no `$this->renderPartial()`. @@ -179,10 +179,10 @@ Modelos ------- Yii 2.0 utiliza [[yii\base\Model]] como modelo base, algo similar a `CModel` en 1.1. -La clase `CFormModel` ha sido descartada por completo. Ahora, en Yii 2 debes extender [[yii\base\Model]] para crear clases de modelos. +La clase `CFormModel` ha sido descartada por completo. Ahora, en Yii 2 debes extender de [[yii\base\Model]] para crear clases de modelos basados en formularios. Yii 2.0 introduce un nuevo método llamado [[yii\base\Model::scenarios()|scenarios()]] para declarar escenarios soportados, -y para indicar bajo qué escenario un atributo necesita ser validado, puede ser considerado seguro o no, etc. Por ejemplo: +y para indicar bajo que escenario un atributo necesita ser validado, puede ser considerado seguro o no, etc. Por ejemplo: ```php public function scenarios() @@ -204,7 +204,7 @@ Ten en cuenta que dada la introducción de [[yii\base\Model::scenarios()|scenari En la mayoría de los casos, no necesitas sobrescribir [[yii\base\Model::scenarios()|scenarios()]] si el método [[yii\base\Model::rules()|rules()]] especifica completamente los escenarios que existirán, y si no hay necesidad de declarar atributos inseguros (`unsafe`). -Para aprender más detalles de modelos, consulta la sección [Modelos](basic-models.md). +Para aprender más detalles de modelos, consulta la sección [Modelos](structure-models.md). Controladores @@ -228,7 +228,7 @@ public function actionView($id) } ``` -Por favor, consulta la sección [Controllers](structure-controllers.md) para más detalles acerca de los controladores. +Por favor, consulta la sección [Controladores](structure-controllers.md) para más detalles acerca de los controladores. Widgets @@ -236,7 +236,7 @@ Widgets Yii 2.0 utiliza [[yii\base\Widget]] como clase base de los widgets, similar a `CWidget` en Yii 1.1. -Para obtener mejor soporte del framework en IDEs, Yii 2.0 introduce una nueva sintáxis para utilizar widgets. +Para obtener mejor soporte del framework en IDEs, Yii 2.0 introduce una nueva sintaxis para utilizar widgets. Los métodos estáticos [[yii\base\Widget::begin()|begin()]], [[yii\base\Widget::end()|end()]], y [[yii\base\Widget::widget()|widget()]] fueron incorporados, y deben utilizarse así: @@ -259,19 +259,19 @@ ActiveForm::end(); Consulta la sección [Widgets](structure-widgets.md) para más detalles. -Themes +Temas ------ -Los themes funcionan completamente diferente en Yii 2.0. Ahora están basados en un mecanismo de mapeo de rutas, -que mapea la ruta de un archivo vista de origen a uno con un theme aplicado. Por ejemplo, si el path map de un theme es -`['/web/views' => '/web/themes/basic']`, entonces la versión con el theme aplicado del archivo -`/web/views/site/index.php` será `/web/themes/basic/site/index.php`. Por esta razón, ahora los themes pueden ser -aplicados a cualquier archivo de vista, incluso una vista renderizada fuera del contexto de un controlador o widget. +Los temas funcionan completamente diferente en Yii 2.0. Ahora están basados en un mecanismo de mapeo de rutas, +que mapea la ruta de un archivo de la vista de origen a uno con un tema aplicado. Por ejemplo, si el mapeo de ruta de un tema es +`['/web/views' => '/web/themes/basic']`, entonces la versión con el tema aplicado del archivo +`/web/views/site/index.php` será `/web/themes/basic/site/index.php`. Por esta razón, ahora los temas pueden ser +aplicados a cualquier archivo de la vista, incluso una vista renderizada fuera del contexto de un controlador o widget. Además, el componente `CThemeManager` ya no existe. En cambio, `theme` es una propiedad configurable del componente `view` de la aplicación. -Consulta la sección [Utilizando Themes](tutorial-theming.md) para más detalles. +Consulta la sección [Temas](output-theming.md) para más detalles. Aplicaciones de Consola @@ -304,7 +304,7 @@ Por favor, consulta la sección [Internacionalización](tutorial-i18n.md) para m Filtros de Acciones ------------------- -En Yii 2.0, los filtros de acciones son implementados a través de comportamientos (behaviors). Para definir un +Los filtros de acciones son implementados a través de comportamientos. Para definir un nuevo filtro personalizado, se debe extender de [[yii\base\ActionFilter]]. Para utilizar el filtro, conecta la clase del filtro al controlador como un comportamiento. Por ejemplo, para utilizar el filtro [[yii\filters\AccessControl]], deberías tener el siguiente código en el controlador: @@ -331,13 +331,13 @@ Assets Yii 2.0 introduce un nuevo concepto llamado *asset bundle* que reemplaza el concepto de script package encontrado en Yii 1.1. -Un asset bundle es una colección de assets (ej. archivos JavaScript, archivos CSS, imágenes, etc.) dentro de un directorio. -Cada asset bundle está representada por una clase que extiende de [[yii\web\AssetBundle]]. +Un asset bundle es una colección de archivos assets (ej. archivos JavaScript, archivos CSS, imágenes, etc.) dentro de un directorio. +Cada asset bundle está representado por una clase que extiende de [[yii\web\AssetBundle]]. Al registrar un asset bundle a través de [[yii\web\AssetBundle::register()]], haces que los assets de dicho bundle sean accesibles vía Web. A diferencia de Yii 1, la página que registra el bundle contendrá automáticamente las referencias a los archivos JavaScript y CSS especificados en el bundle. -Por favor, consulta la sección [Manejando Assets](output-assets.md) para más detalles. +Por favor, consulta la sección [Manejando Assets](structure-assets.md) para más detalles. Helpers @@ -356,10 +356,10 @@ Por favor, consulta la sección [Información General de Helpers](helper-overvie Formularios ----------- -Yii 2.0 introduce el concepto de *campo* (field) para construir formularios utilizando [[yii\widgets\ActiveForm]]. Un campo (field) +Yii 2.0 introduce el concepto de *campo* (field) para construir formularios utilizando [[yii\widgets\ActiveForm]]. Un campo es un contenedor que consiste en una etiqueta, un input, un mensaje de error y/o texto de ayuda. Un campo es representado como un objeto [[yii\widgets\ActiveField|ActiveField]]. -Utilizando estos campos, puedes crear formularios más claramente que antes: +Utilizando estos campos, puedes crear formularios más legibles que antes: ```php @@ -374,12 +374,12 @@ Utilizando estos campos, puedes crear formularios más claramente que antes: Por favor, consulta la sección [Creando Formularios](input-forms.md) para más detalles. -Query Builder -------------- +Constructor de Consultas +------------------------ En Yii 1.1, la generación de consultas a la base de datos estaba dividida en varias clases, incluyendo `CDbCommand`, `CDbCriteria`, y `CDbCommandBuilder`. Yii 2.0 representa una consulta a la base de datos en términos de un objeto [[yii\db\Query|Query]] -que puede ser convertido en una declaración SQL con la ayuda de [[yii\db\QueryBuilder|QueryBuilder]] detrás de escena. +que puede ser convertido en una declaración SQL con la ayuda de [[yii\db\QueryBuilder|QueryBuilder]] detrás de la escena. Por ejemplo: ```php @@ -395,7 +395,7 @@ $rows = $command->queryAll(); Lo mejor de todo, dichos métodos de generación de consultas pueden ser también utilizados mientras se trabaja con [Active Record](db-active-record.md). -Consulta la sección [Query Builder](db-query-builder.md) para más detalles. +Consulta la sección [Constructor de Consultas](db-query-builder.md) para más detalles. Active Record @@ -409,7 +409,7 @@ y por lo tanto hereda todos los métodos de generación de consultas. Para comenzar a generar una consulta, llamas al método [[yii\db\ActiveRecord::find()]]: ```php -// Para traer todos los clientes *activos* y ordenarlos por su ID: +// Recibe todos los clientes *activos* y ordenados por su ID: $customers = Customer::find() ->where(['status' => $active]) ->orderBy('id') @@ -431,27 +431,27 @@ class Customer extends \yii\db\ActiveRecord ``` Ahora puedes utilizar `$customer->orders` para acceder a las órdenes de la tabla relacionada. También puedes utilizar el siguiente -código para realizar una consulta 'al-vuelo' relacionada con una condición personalizada: +código para realizar una consulta relacional 'al-vuelo' con una condición personalizada: ```php $orders = $customer->getOrders()->andWhere('status=1')->all(); ``` -Cuando se utiliza la carga temprana de la relación, Yii 2.0 lo hace diferente de 1.1. En particular, en 1.1 una declaración JOIN +Cuando se utiliza la carga temprana (eager loading) de la relación, Yii 2.0 lo hace diferente de 1.1. En particular, en 1.1 una declaración JOIN sería creada para seleccionar tanto los registros de la tabla primaria como los relacionados. En Yii 2.0, dos declaraciones SQL son ejecutadas -sin utilizar un JOIN: la primera traer todos los modelos primarios, mientras que la segunda trae los registros relacionados +sin utilizar un JOIN: la primera trae todos los modelos primarios, mientras que la segunda trae los registros relacionados utilizando como condición la clave primaria de los primarios. En vez de devolver objetos [[yii\db\ActiveRecord|ActiveRecord]], puedes conectar el método [[yii\db\ActiveQuery::asArray()|asArray()]] mientras generas una consulta que devuelve un gran número de registros. Esto causará que el resultado de la consulta sea devuelto como -matrices (arrays), lo que puede reducir significativamente la necesidad de tiempo de CPU y memoria si el número de registros es grande. +arrays, lo que puede reducir significativamente la necesidad de tiempo de CPU y memoria si el número de registros es grande. Por ejemplo: ```php $customers = Customer::find()->asArray()->all(); ``` -Otro cambio es que ya no puedes definir valores por defecto a los atributos a través de propiedades publicas. +Otro cambio es que ya no puedes definir valores por defecto a los atributos a través de propiedades públicas. Si lo necesitaras, debes definirlo en el método `init` de la clase del registro en cuestión. ```php @@ -469,21 +469,51 @@ Hay muchos otros cambios y mejoras con respecto a ActiveRecord. Por favor, consu la sección [Active Record](db-active-record.md) para más detalles. +Active Record Behaviors +----------------------- + +En 2.0, hemos eliminado la clase del comportamiento base `CActiveRecordBehavior`. Si desea crear un comportamiento Active Record, usted tendrá que extender directamente de `yii\base\Behavior`. Si la clase de comportamiento debe responder a algunos eventos propios, usted tiene que sobrescribir los métodos `events()` como se muestra a continuación, + +```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 e IdentityInterface ------------------------ La clase `CWebUser` de 1.1 es reemplazada por [[yii\web\User]], y la clase `CUserIdentity` ha dejado de existir. -En cambio, ahora debes implementar [[yii\web\IdentityInterface]] lo que es mucho más directo para usar. -El template de Aplicación Avanzada provee un ejemplo así. +En cambio, ahora debes implementar [[yii\web\IdentityInterface]] el cual es mucho más directo de usar. +La plantilla de Aplicación Avanzada provee un ejemplo así. -Consulta las secciones [Autenticación](security-authentication.md), [Autorización](security-authorization.md), y [Template de Aplicación Avanzanda](tutorial-advanced-app.md) para más detalles. +Consulta las secciones [Autenticación](security-authentication.md), [Autorización](security-authorization.md), y [Plantilla de Aplicación Avanzada](tutorial-advanced-app.md) para más detalles. Manejo de URLs -------------- El manejo de URLs en Yii 2 es similar al de 1.1. Una mejora mayor es que el manejador actual ahora soporta parámetros opcionales. -Por ejemplo, si tienes una regla declarada como a continuación, entonces coincidirá tanto con `post/popular` como `post/1/popular`. +Por ejemplo, si tienes una regla declarada como a continuación, entonces coincidirá tanto con `post/popular` como con `post/1/popular`. En 1.1, tendrías que haber creado dos reglas diferentes para obtener el mismo resultado ```php @@ -494,11 +524,11 @@ En 1.1, tendrías que haber creado dos reglas diferentes para obtener el mismo r ] ``` -Por favor, consulta la sección [Documentación del Manejo de URLs](url.md) para más detalles. +Por favor, consulta la sección [Documentación del Manejo de URLs](runtime-routing.md) para más detalles. Utilizando Yii 1.1 y 2.x juntos ------------------------------- Si tienes código en Yii 1.1 que quisieras utilizar junto con Yii 2.0, por favor consulta -la sección [Using Yii 1.1 and 2.0 Together](extend-using-v1-v2.md). +la sección [Utilizando Yii 1.1 y 2.0 juntos](tutorial-yii-integration.md). diff --git a/docs/guide-es/intro-yii.md b/docs/guide-es/intro-yii.md index 453eb4b..f4e8c9c 100644 --- a/docs/guide-es/intro-yii.md +++ b/docs/guide-es/intro-yii.md @@ -1,50 +1,52 @@ ¿Qué es Yii? ============ -Yii es un marco de programación del lenguaje PHP de alto rendimiento, basado en componentes para desarrollar aplicaciones web -modernas en poco tiempo. El nombre Yii significa "simple y evolutivo" en chino; también se puede considerar como un acrónimo +Yii es un framework de PHP de alto rendimiento, basado en componentes para desarrollar aplicaciones web +modernas en poco tiempo. El nombre Yii significa "simple y evolutivo" en chino. También se puede considerar como un acrónimo de _**Yes It Is**_ (que en inglés significa _**Sí, eso es**_)! ¿En qué es mejor Yii? ----------------------- -Yii es un marco genérico de programación web, lo que significa que se puede utilizar para desarrollar todo tipo de aplicaciones web en PHP. -Debido a su arquitectura basada en componentes y a su sofisticada compatibilidad de caché, es especialmente apropiado para el desarrollo -de aplicaciones de gran envergadura, como portales, foros, sistemas de gestión de contenidos (CMS), proyectos de comercio electrónico, +Yii es un framework genérico de programación web, lo que significa que se puede utilizar para desarrollar todo tipo de aplicaciones web en PHP. +Debido a su arquitectura basada en componentes y a su sofisticada compatibilidad de caché, es especialmente apropiado para el desarrollo +de aplicaciones de gran envergadura, como portales, foros, sistemas de gestión de contenidos (CMS), proyectos de comercio electrónico, servicios web compatibles con la arquitectura REST y muchas más. -¿Cómo se compara Yii con otros marcos? +¿Cómo se compara Yii con otros frameworks? -------------------------------------- -- Como la mayoría de los marcos de PHP, Yii implementa el patrón de diseño MVC (Modelo-Vista-Controlador) y promueve la organización de código basada en este patrón. +Si estás familiarizado con otros framework, puedes apreciar como se compara Yii con ellos: + +- Como la mayoría de los framework de PHP, Yii implementa el patrón de diseño MVC (Modelo-Vista-Controlador) y promueve la organización de código basada en este patrón. - La filosofía de Yii consiste en escribir el código de manera simple y elegante, sin sobrediseñar nunca por el mero hecho de seguir un patrón de diseño determinado. -- Yii es un marco completo que provee muchas características probadas y listas para usar, como los constructores de consultas y la clase ActiveRecord para las bases de datos relacionales y NoSQL, la compatibilidad con la arquitectura REST para desarrollar API, la compatibilidad de caché en varios niveles y muchas más. -- Yii es extremadamente extensible; se puede personalizar o reemplazar prácticamente cualquier pieza de código de base, como se puede también aprovechar su sólida arquitectura de extensiones para utilizar o desarrollar extensiones distribuibles. +- Yii es un framework completo que provee muchas características probadas y listas para usar, como los constructores de consultas y la clase ActiveRecord para las bases de datos relacionales y NoSQL, la compatibilidad con la arquitectura REST para desarrollar API, la compatibilidad de caché en varios niveles y muchas más. +- Yii es extremadamente extensible. Puedes personalizar o reemplazar prácticamente cualquier pieza de código de base, como se puede también aprovechar su sólida arquitectura de extensiones para utilizar o desarrollar extensiones distribuibles. - El alto rendimiento es siempre la meta principal de Yii. -Detrás de Yii hay un [sólido equipo de desarrollo][], así como una gran comunidad en la que numerosos profesionales contribuyen constantemente a su desarrollo. -El equipo de desarrollo de Yii se mantiene atento a las últimas tendencias de desarrollo web, así como a las mejores prácticas y características de otros marcos y proyectos. -Las buenas prácticas más relevantes de otros proyectos se incorporan regularmente a la base del marco y se exponen a través de interfaces simples y elegantes. +Yii no es un proyecto de un sola persona, detrás de Yii hay un [sólido equipo de desarrollo][], así como una gran comunidad en la que numerosos profesionales contribuyen constantemente a su desarrollo. +El equipo de desarrollo de Yii se mantiene atento a las últimas tendencias de desarrollo web, así como a las mejores prácticas y características de otros frameworks y proyectos. +Las buenas prácticas y características más relevantes de otros proyectos se incorporan regularmente a la base del framework y se exponen a través de interfaces simples y elegantes. [sólido equipo de desarrollo]: http://www.yiiframework.com/about/ Versiones de Yii ---------------- -Actualmente existen dos versiones principales de Yii: la versión 1.1 y la versión 2.0. Para la versión 1.1, que es de la generación anterior, actualmente solo se ofrece mantenimiento. -La versión 2.0 está completamente reescrita y adopta las últimas tecnologías y protocolos, incluidos Composer, PSR, espacio de nombres, rasgos, etc. -Esta versión representa la última generación del marco y su desarrollo recibirá nuestro principal esfuerzo en los próximos años. -Esta guía está basada principalmente en la versión 2.0 del marco. +Actualmente existen dos versiones principales de Yii: la versión 1.1 y la versión 2.0. Para la versión 1.1, que es de la generación anterior, actualmente solo se ofrece mantenimiento. +La versión 2.0 está completamente reescrita y adopta las últimas tecnologías y protocolos, incluidos Composer, PSR, namespaces, traits, etc. +La versión 2.0 representa la actual generación del framework y su desarrollo recibirá el principal esfuerzo en los próximos años. +Esta guía está basada principalmente en la versión 2.0. del framework. Requisitos ----------- -Yii 2.0 requiere PHP 5.4.0 o una versión posterior. Se pueden encontrar requisitos más detallados de características individuales -ejecutando el programa de comprobación incluido en cada lanzamiento de Yii. +Yii 2.0 requiere PHP 5.4.0 o una versión posterior. Se pueden encontrar requisitos más detallados de características individuales +ejecutando el script de comprobación incluido en cada release de Yii. -Para utilizar Yii se requieren conocimientos básicos de programación orientada a objetos (POO), porque el marco Yii se basa íntegramente en esta tecnología. -Yii 2.0 hace uso también de las últimas características de PHP, como [espacios de nombres](http://www.php.net/manual/en/language.namespaces.php) -y [rasgos](http://www.php.net/manual/en/language.oop5.traits.php). Comprender estos conceptos ayuda a entender Yii 2.0. +Para utilizar Yii se requieren conocimientos básicos de programación orientada a objetos (POO), porque el framework Yii se basa íntegramente en esta tecnología. +Yii 2.0 hace uso también de las últimas características de PHP, como [namespaces](http://www.php.net/manual/es/language.namespaces.php) +y [traits](http://www.php.net/manual/es/language.oop5.traits.php). Comprender estos conceptos te ayudará a entender mejor Yii 2.0. diff --git a/docs/guide-es/output-theming.md b/docs/guide-es/output-theming.md new file mode 100644 index 0000000..18a7d45 --- /dev/null +++ b/docs/guide-es/output-theming.md @@ -0,0 +1,99 @@ +Temas +===== + +> Nota: Esta sección está en desarrollo. + +Un tema (theme) es un directorio de archivos y de vistas (views) y layouts. Cada archivo de este directorio +sobrescribe el archivo correspondiente de una aplicación cuando se renderiza. Una única aplicación puede usar +múltiples temas para que pueden proporcionar experiencias totalmente diferentes. Solo se puede haber un único tema +activo. + +> Nota: Los temas no están destinados a ser redistribuidos ya que están demasiado ligados a la aplicación. Si se + quiere redistribuir una apariencia personalizada, se puede considerar la opción de + [asset bundles](structure-assets.md) de archivos CSS y Javascript. + +Configuración de un Tema +------------------------ + +La configuración de un tema se especifica a través del componente `view` de la aplicación. Para establecer que un tema +trabaje con vistas de aplicación básicas, la configuración de la aplicación debe contener lo siguiente: + +```php +'components' => [ + 'view' => [ + 'theme' => [ + 'pathMap' => ['@app/views' => '@app/themes/basic'], + 'baseUrl' => '@web/themes/basic', + ], + ], +], +``` + +En el ejemplo anterior, el `pathMap` define un mapa (map) de las rutas a las que se aplicará el tema mientras que +`baseUrl` define la URL base para los recursos a los que hacen referencia los archivos del tema. + +En nuestro caso `pathMap` es `['@app/views' => '@app/themes/basic']`. Esto significa que cada vista de `@app/views` +primero se buscará en `@app/themes/basic` y si existe, se usará la vista del directorio del tema en lugar de la vista +original. + +Por ejemplo, con la configuración anterior, la versión del tema para la vista `@app/views/site/index.php` será +`@app/themes/basic/site/index.php`. Básicamente se reemplaza `@app/views` en `@app/views/site/index.php` por +`@app/themes/basic`. + +### Temas para Módulos + +Para utilizar temas en los módulos, el `pathMap` debe ser similar al siguiente: + +```php +'components' => [ + 'view' => [ + 'theme' => [ + 'pathMap' => [ + '@app/views' => '@app/themes/basic', + '@app/modules' => '@app/themes/basic/modules', // <-- !!! + ], + ], + ], +], +``` + +Esto permite aplicar el tema a `@app/modules/blog/views/comment/index.php` con la vista +`@app/themes/basic/modules/blog/views/comment/index.php`. + +### Temas para Widgets + +Para utilizar un tema en una vista que se encuentre en `@app/widgets/currency/views/index.php`, se debe aplicar la +siguiente configuración para el componente vista, tema: + +```php +'components' => [ + 'view' => [ + 'theme' => [ + 'pathMap' => ['@app/widgets' => '@app/themes/basic/widgets'], + ], + ], +], +``` + +Con la configuración anterior, se puede crear una versión de la vista `@app/widgets/currency/index.php` para que se +aplique el tema en `@app/themes/basic/widgets/currency/index.php`. + +Uso de Multiples Rutas +---------------------- + +Es posible mapear una única ruta a múltiples rutas de temas. Por ejemplo: + +```php +'pathMap' => [ + '@app/views' => [ + '@app/themes/christmas', + '@app/themes/basic', + ], +] +``` + +En este caso, primero se buscara la vista en `@app/themes/christmas/site/index.php`, si no se encuentra, se intentará +en `@app/themes/basic/site/index.php`. Si la vista no se encuentra en ninguna de rutas especificadas, se usará la +vista de aplicación. + +Esta capacidad es especialmente útil si se quieren sobrescribir algunas rutas temporal o condicionalmente. \ No newline at end of file diff --git a/docs/guide-es/rest-authentication.md b/docs/guide-es/rest-authentication.md new file mode 100644 index 0000000..d97036e --- /dev/null +++ b/docs/guide-es/rest-authentication.md @@ -0,0 +1,121 @@ +Autenticación +============= + +A diferencia de las aplicaciones Web, las API RESTful son usualmente sin estado (stateless), lo que permite que las sesiones o las cookies no sean usadas. +Por lo tanto, cada petición debe llevar alguna suerte de credenciales de autenticación, porque la autenticación del usuario no puede ser mantenida por las sesiones o las cookies. +Una práctica común es enviar una pieza (token) secreta de acceso con cada petición para autenticar al usuario. Dado que una pieza de autenticación +puede ser usada para identificar y autenticar solamente a un usuario, **el API de peticiones tiene que ser siempre enviado vía HTTPS para prevenir ataques que intervengan en la transmisión "man-in-the-middle" (MitM) **. + +Hay muchas maneras de enviar una token (pieza) de acceso: + +* [Autorización Básica HTTP](http://en.wikipedia.org/wiki/Basic_access_authentication): la pieza de acceso + es enviada como nombre de usuario. Esto sólo debe de ser usado cuando la pieza de acceso puede ser guardada + de forma segura en la parte del API del consumidor. Por ejemplo, el API del consumidor es un programa ejecutándose en un servidor. +* Parámetro de la consulta: la pieza de acceso es enviada como un parámetro de la consulta en la URL de la API, p.e., + `https://example.com/users?access-token=xxxxxxxx`. Debido que muchos servidores dejan los parámetros de consulta en los logs del servidor, + esta aproximación suele ser usada principalmente para servir peticiones `JSONP` + que no usen las cabeceras HTTP para enviar piezas de acceso. +* [OAuth 2](http://oauth.net/2/): la pieza de acceso es obtenida por el consumidor por medio de una autorización del servidor + y enviada al API del servidor según el protocolo OAuth 2 [tokens HTTP del portador] (http://tools.ietf.org/html/rfc6750). + +Yii soporta todos los métodos anteriores de autenticación. Puedes crear nuevos métodos de autenticación de una forma fácil. + +Para activar la autenticación para tus APIs, sigue los pasos siguientes: + +1. Configura el componente `user` de la aplicación: + - Define la propiedad [[yii\web\User::enableSession|enableSession]] como `false`. + - Define la propiedad [[yii\web\User::loginUrl|loginUrl]] como `null` para mostrar un error HTTP 403 en vez de redireccionar a la pantalla de login. +2. Especifica cuál método de autenticación planeas usar configurando el comportamiento (behavior) `authenticator` en tus + clases de controladores REST. +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. +Si embargo, la autenticación será realizada para cada petición, lo que se consigue en los pasos 2 y 3. + +> Tip: Puedes configurar [[yii\web\User::enableSession|enableSession]] del componente de la aplicación `user` en la configuración + de las aplicaciones si estás desarrollando APIs RESTful en términos de un aplicación. Si desarrollas un módulo de las APIs RESTful, + puedes poner la siguiente línea en el método del módulo `init()`, tal y como sigue: +> ```php +public function init() +{ + parent::init(); + \Yii::$app->user->enableSession = false; +} +``` + +Por ejemplo, para usar HTTP Basic Auth, puedes configurar el comportamiento `authenticator` como sigue, + +```php +use yii\filters\auth\HttpBasicAuth; + +public function behaviors() +{ + $behaviors = parent::behaviors(); + $behaviors['authenticator'] = [ + 'class' => HttpBasicAuth::className(), + ]; + return $behaviors; +} +``` + +Si quieres implementar los tres métodos de autenticación explicados antes, puedes usar `CompositeAuth` de la siguiente manera, + +```php +use yii\filters\auth\CompositeAuth; +use yii\filters\auth\HttpBasicAuth; +use yii\filters\auth\HttpBearerAuth; +use yii\filters\auth\QueryParamAuth; + +public function behaviors() +{ + $behaviors = parent::behaviors(); + $behaviors['authenticator'] = [ + 'class' => CompositeAuth::className(), + 'authMethods' => [ + HttpBasicAuth::className(), + HttpBearerAuth::className(), + QueryParamAuth::className(), + ], + ]; + return $behaviors; +} +``` + +Cada elemento en `authMethods` debe de ser el nombre de una clase de método de autenticación o un array de configuración. + + +La implementación de `findIdentityByAccessToken()` es específico de la aplicación. Por ejemplo, en escenarios simples +cuando cada usuario sólo puede tener un token de acceso, puedes almacenar este token en la columna `access_token` +en la tabla de usuario. El método debe de ser inmediatamente implementado en la clase `User` como sigue, + +```php +use yii\db\ActiveRecord; +use yii\web\IdentityInterface; + +class User extends ActiveRecord implements IdentityInterface +{ + public static function findIdentityByAccessToken($token, $type = null) + { + return static::findOne(['access_token' => $token]); + } +} +``` + +Después que la autenticación es activada, tal y como se describe arriba, para cada petición de la API, el controlador solicitado +puede intentar autenticar al usuario en su evento `beforeAction()`. + +Si la autenticación tiene éxito, el controlador realizará otras comprobaciones (como son límite del ratio, autorización) +y entonces ejecutar la acción. La identidad del usuario autenticado puede ser recuperada via `Yii::$app->user->identity`. + +Si la autenticación falla, una respuesta con estado HTTP 401 será devuelta junto con otras cabeceras apropiadas (tal como la cabecera para autenticación básica HTTP `WWW-Authenticate`). + + +## Autorización + +Después de que un usuario se ha autenticado, probablementer querrás comprobar si él o ella tiene los permisos para realizar +la acción solicitada. Este proceso es llamado *autorización (authorization)* y está cubierto en detalle en la [Sección de Autorización](security-authorization.md). + +Si tus controladores extienden de [[yii\rest\ActiveController]], puedes sobreescribir +el método [[yii\rest\Controller::checkAccess()|checkAccess()]] para realizar la comprobación de la autorización. +El método será llamado por las acciones contenidas en [[yii\rest\ActiveController]]. diff --git a/docs/guide-es/rest-controllers.md b/docs/guide-es/rest-controllers.md new file mode 100644 index 0000000..1177cda --- /dev/null +++ b/docs/guide-es/rest-controllers.md @@ -0,0 +1,152 @@ +Controladores +============= + +Después de crear las clases de recursos y especificar cómo debe ser el formato de datos de recursos, el siguiente paso +es crear acciones del controlador para exponer los recursos a los usuarios finales a través de las APIs RESTful. + +Yii ofrece dos clases controlador base para simplificar tu trabajo de crear acciones REST: +[[yii\rest\Controller]] y [[yii\rest\ActiveController]]. La diferencia entre estos dos controladores +es que este último proporciona un conjunto predeterminado de acciones que están específicamente diseñado para trabajar con +los recursos representados como [Active Record](db-active-record.md). Así que si estás utilizando [Active Record](db-active-record.md) +y te sientes cómodo con las acciones integradas provistas, podrías considerar extender tus controladores +de [[yii\rest\ActiveController]], lo que te permitirá crear potentes APIs RESTful con un mínimo de código. + +Ambos [[yii\rest\Controller]] y [[yii\rest\ActiveController]] proporcionan las siguientes características, +algunas de las cuales se describen en detalle en las siguientes secciones: + +* Método de Validación HTTP; +* [Negociación de contenido y formato de datos](rest-response-formatting.md); +* [Autenticación](rest-authentication.md); +* [Límite de Rango](rest-rate-limiting.md). + +[[yii\rest\ActiveController]] además provee de las siguientes características: + +* Un conjunto de acciones comunes necesarias: `index`, `view`, `create`, `update`, `delete`, `options`; +* La autorización del usuario de acuerdo a la acción y recurso solicitado. + + +## Creando Clases de Controlador + +Al crear una nueva clase de controlador, una convención para nombrar la clase del controlador es utilizar +el nombre del tipo de recurso en singular. Por ejemplo, para servir información de usuario, +el controlador puede ser nombrado como `UserController`. + +Crear una nueva acción es similar a crear una acción para una aplicación Web. La única diferencia +es que en lugar de renderizar el resultado utilizando una vista llamando al método `render()`, para las acciones REST +regresas directamente los datos. El [[yii\rest\Controller::serializer|serializer]] y el +[[yii\web\Response|response object]] se encargarán de la conversión de los datos originales +al formato solicitado. Por ejemplo, + +```php +public function actionView($id) +{ + return User::findOne($id); +} +``` + + +## Filtros + +La mayoría de las características API REST son proporcionadas por [[yii\rest\Controller]] son implementadas en los términos de [filtros](structure-filters.md). +En particular, los siguientes filtros se ejecutarán en el orden en que aparecen: + +* [[yii\filters\ContentNegotiator|contentNegotiator]]: soporta la negociación de contenido, que se explica en + la sección [Formateo de respuestas](rest-response-formatting.md); +* [[yii\filters\VerbFilter|verbFilter]]: soporta métodos de validación HTTP; +* [[yii\filters\AuthMethod|authenticator]]: soporta la autenticación de usuarios, que se explica en + la sección [Autenticación](rest-authentication.md); +* [[yii\filters\RateLimiter|rateLimiter]]: soporta la limitación de rango, que se explica en + la sección [Límite de Rango](rest-rate-limiting.md). + +Estos filtros se declaran nombrándolos en el método [[yii\rest\Controller::behaviors()|behaviors()]]. +Puede sobrescribir este método para configurar filtros individuales, desactivar algunos de ellos, o añadir los tuyos. +Por ejemplo, si sólo deseas utilizar la autenticación básica HTTP, puede escribir el siguiente código: + +```php +use yii\filters\auth\HttpBasicAuth; + +public function behaviors() +{ + $behaviors = parent::behaviors(); + $behaviors['authenticator'] = [ + 'class' => HttpBasicAuth::className(), + ]; + return $behaviors; +} +``` + + +## Extendiendo `ActiveController` + +Si tu clase controlador extiende de [[yii\rest\ActiveController]], debe establecer +su propiedad [[yii\rest\ActiveController::modelClass||modelClass]] con el nombre de la clase del recurso +que planeas servir a través de este controlador. La clase debe extender de [[yii\db\ActiveRecord]]. + + +### Personalizando Acciones + +Por defecto, [[yii\rest\ActiveController]] provee de las siguientes acciones: + +* [[yii\rest\IndexAction|index]]: listar recursos página por página; +* [[yii\rest\ViewAction|view]]: devolver el detalle de un recurso específico; +* [[yii\rest\CreateAction|create]]: crear un nuevo recurso; +* [[yii\rest\UpdateAction|update]]: actualizar un recurso existente; +* [[yii\rest\DeleteAction|delete]]: eliminar un recurso específico; +* [[yii\rest\OptionsAction|options]]: devolver los métodos HTTP soportados. + +Todas esta acciones se declaran a través de método [[yii\rest\ActiveController::actions()|actions()]]. +Puedes configurar estas acciones o desactivar alguna de ellas sobrescribiendo el método `actions()`, como se muestra a continuación, + +```php +public function actions() +{ + $actions = parent::actions(); + + // disable the "delete" and "create" actions + unset($actions['delete'], $actions['create']); + + // customize the data provider preparation with the "prepareDataProvider()" method + $actions['index']['prepareDataProvider'] = [$this, 'prepareDataProvider']; + + return $actions; +} + +public function prepareDataProvider() +{ + // prepare and return a data provider for the "index" action +} +``` + +Por favor, consulta las referencias de clases de acciones individuales para aprender las opciones de configuración disponibles para cada una. + + +### Realizando Comprobación de Acceso + +Al exponer los recursos a través de RESTful APIs, a menudo es necesario comprobar si el usuario actual tiene permiso +para acceder y manipular el/los recurso solicitado/s. Con [[yii\rest\ActiveController]], esto puede lograrse +sobrescribiendo el método [[yii\rest\ActiveController::checkAccess()|checkAccess()]] como a continuación, + +```php +/** + * Checks the privilege of the current user. + * + * This method should be overridden to check whether the current user has the privilege + * to run the specified action against the specified data model. + * 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 array $params additional parameters + * @throws ForbiddenHttpException if the user does not have access + */ +public function checkAccess($action, $model = null, $params = []) +{ + // check if the user can access $action and $model + // throw ForbiddenHttpException if access should be denied +} +``` + +El método `checkAccess()` será llamado por defecto en las acciones predeterminadas de [[yii\rest\ActiveController]]. Si creas +nuevas acciones y también deseas llevar a cabo la comprobación de acceso, debe llamar a este método de forma explícita en las nuevas acciones. + +> Consejo: Puedes implementar `checkAccess()` mediante el uso del [Componente Role-Based Access Control (RBAC)](security-authorization.md). diff --git a/docs/guide-es/rest-error-handling.md b/docs/guide-es/rest-error-handling.md new file mode 100644 index 0000000..092a6ab --- /dev/null +++ b/docs/guide-es/rest-error-handling.md @@ -0,0 +1,91 @@ +Manejo de errores +================= + +Cuando se maneja una petición de API RESTful, si ocurre un error en la petición del usuario o si algo inesperado +ocurre en el servidor, simplemente puedes lanzar una excepción para notificar al usuario que algo erróneo ocurrió. +Si puedes identificar la causa del error (p.e., el recurso solicitado no existe), debes considerar lanzar una excepción +con el código HTTP de estado apropiado (p.e., [[yii\web\NotFoundHttpException]] representa un código de estado 404). +Yii enviará la respuesta a continuación con el correspondiente código de estado HTTP y el texto. Yii puede incluir también +la representación serializada de la excepción en el cuerpo de la respuesta. Por ejemplo: + +``` +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": "El recurso solicitado no ha sido encontrado.", + "code": 0, + "status": 404 +} +``` + +La siguiente lista sumariza los códigos de estado HTTP que son usados por el framework REST: + +* `200`: OK. Todo ha funcionado como se esperaba. +* `201`: El recurso ha creado con éxito en respuesta a la petición `POST`. La cabecera de situación `Location` contiene la URL apuntando al nuevo recurso creado. +* `204`: La petición ha sido manejada con éxito y el cuerpo de la respuesta no tiene contenido (como una petición `DELETE`). +* `304`: El recurso no ha sido modificado. Puede usar la versión en caché. +* `400`: Petición errónea. Esto puede estar causado por varias acciones de el usuario, como proveer un JSON no válido en el cuerpo de la petición, proveyendo parámetros de acción no válidos, etc. +* `401`: Autenticación fallida. +* `403`: El usuario autenticado no tiene permitido acceder a la API final. +* `404`: El recurso pedido no existe. +* `405`: Método no permitido. Por favor comprueba la cabecera `Allow` por los métodos HTTP permitidos. +* `415`: Tipo de medio no soportado. El tipo de contenido pedido o el número de versión no es válido. +* `422`: La validación de datos ha fallado (en respuesta a una petición `POST` , por ejemplo). Por favor, comprobad en el cuerpo de la respuesta el mensaje detallado. +* `429`: Demasiadas peticiones. La petición ha sido rechazada debido a un limitación de rango. +* `500`: Error interno del servidor. Esto puede estar causado por errores internos del programa. + + +## Personalizando la Respuesta al Error + +A veces puedes querer personalizar el formato de la respuesta del error por defecto . Por ejemplo, en lugar de depender +del uso de diferentes estados HTTP para indicar los diferentes errores, puedes querer usar siempre el estado HTTP 200 +y encapsular el código de estado HTTP real como parte de una estructura JSON en la respuesta, como se muestra a continuación, + +``` +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 + } +} +``` + +Para lograr este objetivo, puedes responder al evento `beforeSend` del componente `response` en la configuración de la aplicación: + +```php +return [ + // ... + 'components' => [ + 'response' => [ + 'class' => 'yii\web\Response', + 'on beforeSend' => function ($event) { + $response = $event->sender; + if ($response->data !== null && !empty(Yii::$app->request->get['suppress_response_code'])) { + $response->data = [ + 'success' => $response->isSuccessful, + 'data' => $response->data, + ]; + $response->statusCode = 200; + } + }, + ], + ], +]; +``` + +El anterior código reformateará la respuesta (sea exitosa o fallida) como se explicó cuando +`suppress_response_code` es pasado como un parámetro `GET`. diff --git a/docs/guide-es/rest-quick-start.md b/docs/guide-es/rest-quick-start.md new file mode 100644 index 0000000..836292f --- /dev/null +++ b/docs/guide-es/rest-quick-start.md @@ -0,0 +1,203 @@ +Guía Breve +========== + +Yii ofrece todo un conjunto de herramientas para simplificar la tarea de implementar un +servicio web APIs RESTful. +En particular, Yii soporta las siguientes características sobre APIs RESTful; + +* Prototipado rápido con soporte para APIs comunes para [Active Record](db-active-record.md); +* Formato de respuesta de negocio (soporta JSON y XML por defecto); +* Personalización de objetos serializados con soporte para campos de salida seleccionables; +* Formateo apropiado de colecciones de datos y validación de errores; +* Soporte para [HATEOAS](http://en.wikipedia.org/wiki/HATEOAS); +* Eficiente enrutamiento con una adecuada comprobación del verbo(verb) HTTP; +* Incorporado soporte para las `OPTIONS` y `HEAD` verbos; +* Autenticación y autorización; +* Cacheo de datos y cacheo HTTP; +* Limitación de rango; + + +A continuación, utilizamos un ejemplo para ilustrar como se puede construir un conjunto de APIs RESTful con un esfuerzo mínimo de codificación. + +Supongamos que deseas exponer los datos de los usuarios vía APIs RESTful. Los datos de usuario son almacenados en la tabla DB `user`, +y ya tienes creado la clase [[yii\db\ActiveRecord|ActiveRecord]] `app\models\User` para acceder a los datos del usuario. + + +## Creando un controlador + +Primero, crea una clase controladora `app\controllers\UserController` como la siguiente, + +```php +namespace app\controllers; + +use yii\rest\ActiveController; + +class UserController extends ActiveController +{ + public $modelClass = 'app\models\User'; +} +``` + +La clase controladora extiende de [[yii\rest\ActiveController]]. Especificado por [[yii\rest\ActiveController::modelClass|modelClass]] +como `app\models\User`, el controlador sabe que modelo puede ser usado para recoger y manipular sus datos. + + +## Configurando las reglas de las URL + +A continuación, modifica la configuración del componente `urlManager` en la configuración de tu aplicación: + +```php +'urlManager' => [ + 'enablePrettyUrl' => true, + 'enableStrictParsing' => true, + 'showScriptName' => false, + 'rules' => [ + ['class' => 'yii\rest\UrlRule', 'controller' => 'user'], + ], +] +``` + +La configuración anterior principalmente añade una regla URL para el controlador `user` de manera +que los datos de user pueden ser accedidos y manipulados con URLs amigables y verbos HTTP significativos. + + +## Habilitando entradas JSON + +Para permitir que la API acepte datos de entrada con formato JSON, configura la propiedad [[yii\web\Request::$parsers|parsers]] +del componente de aplicación `request` para usar [[yii\web\JsonParser]] para entradas JSON: + +```php +'request' => [ + 'parsers' => [ + 'application/json' => 'yii\web\JsonParser', + ] +] +``` + +> Consejo: La configuración anterior es opcional. Sin la configuración anterior, la API sólo reconocería + `application/x-www-form-urlencoded` y `multipart/form-data` como formatos de entrada. + + +## Probándolo + +Con la mínima cantidad de esfuerzo, tienes ya finalizado tu tarea de crear las APIs RESTful +para acceder a los datos de user. Las APIs que tienes creado incluyen: + +* `GET /users`: una lista de todos los usuarios página por página; +* `HEAD /users`: muestra la información general de la lista de usuarios; +* `POST /users`: crea un nuevo usuario; +* `GET /users/123`: devuelve los detalles del usuario 123; +* `HEAD /users/123`: muestra la información general del usuario 123; +* `PATCH /users/123` y `PUT /users/123`: actualiza el usuario 123; +* `DELETE /users/123`: elimina el usuario 123; +* `OPTIONS /users`: muestra los verbos compatibles respecto al punto final `/users`; +* `OPTIONS /users/123`: muestra los verbos compatibles respecto al punto final `/users/123`. + +> Información: Yii automáticamente pluraliza los nombres de los controladores para usarlo en los puntos finales. +> Puedes configurar esto usando la propiedad [[yii\rest\UrlRule::$pluralize]]. + +Puedes acceder a tus APIs con el comando `curl` de la siguiente manera, + +``` +$ curl -i -H "Accept:application/json" "http://localhost/users" + +HTTP/1.1 200 OK +... +X-Pagination-Total-Count: 1000 +X-Pagination-Page-Count: 50 +X-Pagination-Current-Page: 1 +X-Pagination-Per-Page: 20 +Link: ; rel=self, + ; rel=next, + ; rel=last +Transfer-Encoding: chunked +Content-Type: application/json; charset=UTF-8 + +[ + { + "id": 1, + ... + }, + { + "id": 2, + ... + }, + ... +] +``` + +Intenta cambiar el tipo de contenido aceptado para ser `application/xml`, y verá que el resultado +se devuelve en formato XML: + +``` +$ curl -i -H "Accept:application/xml" "http://localhost/users" + +HTTP/1.1 200 OK +... +X-Pagination-Total-Count: 1000 +X-Pagination-Page-Count: 50 +X-Pagination-Current-Page: 1 +X-Pagination-Per-Page: 20 +Link: ; rel=self, + ; rel=next, + ; rel=last +Transfer-Encoding: chunked +Content-Type: application/xml + + + + + 1 + ... + + + 2 + ... + + ... + +``` + +El siguiente comando creará un nuevo usuario mediante el envío de una petición POST con los datos del usuario en formato JSON: + +``` +$ curl -i -H "Accept:application/json" -H "Content-Type:application/json" -XPOST "http://localhost/users" -d '{"username": "example", "email": "user@example.com"}' + +HTTP/1.1 201 Created +... +Location: http://localhost/users/1 +Content-Length: 99 +Content-Type: application/json; charset=UTF-8 + +{"id":1,"username":"example","email":"user@example.com","created_at":1414674789,"updated_at":1414674789} +``` + +> Consejo: También puedes acceder a tus APIs a través del navegador web introduciendo la URL `http://localhost/users`. + Sin embargo, es posible que necesites algunos plugins para el navegador para enviar cabeceras especificas en la petición. + +Como se puede ver, en las cabeceras de la respuesta, hay información sobre la cuenta total, número de páginas, etc. +También hay enlaces que permiten navegar por otras páginas de datos. Por ejemplo, `http://localhost/users?page=2` +le daría la página siguiente de los datos de usuario. + +Utilizando los parámetros `fields` y `expand`, puedes también especificar que campos deberían ser incluidos en el resultado. +Por ejemplo, la URL `http://localhost/users?fields=id,email` sólo devolverá los campos `id` y `email`. + + +> Información: Puedes haber notado que el resultado de `http://localhost/users` incluye algunos campos sensibles, +> tal como `password_hash`, `auth_key`. Seguramente no quieras que éstos aparecieran en el resultado de tu API. +> Puedes y deberías filtrar estos campos como se describe en la sección [Response Formatting](rest-response-formatting.md). + + +## Resumen + +Utilizando el framework Yii API RESTful, implementa un punto final API en términos de una acción de un controlador, y utiliza +un controlador para organizar las acciones que implementan los puntos finales para un sólo tipo de recurso. + +Los recursos son representados como modelos de datos que extienden de la clase [[yii\base\Model]]. +Si estás trabajando con bases de datos (relacionales o NoSQL), es recomendable utilizar [[yii\db\ActiveRecord|ActiveRecord]] +para representar los recursos. + +Puedes utilizar [[yii\rest\UrlRule]] para simplificar el enrutamiento de los puntos finales de tu API. + +Aunque no es obligatorio, es recomendable que desarrolles tus APIs RESTful como una aplicación separada, diferente de +tu WEB front end y tu back end para facilitar el mantenimiento. diff --git a/docs/guide-es/rest-rate-limiting.md b/docs/guide-es/rest-rate-limiting.md new file mode 100644 index 0000000..23ca26b --- /dev/null +++ b/docs/guide-es/rest-rate-limiting.md @@ -0,0 +1,44 @@ +Limitando el rango (rate) +========================= + +Para prevenir el abuso, puedes considerar añadir un *límitación del rango (rate limiting)* para tus APIs. Por ejemplo, +puedes querer limitar el uso del API de cada usuario a un máximo de 100 llamadas al API dentro de un periodo de 10 minutos. +Si se reciben demasiadas peticiones de un usuario dentro del periodo de tiempo declarado, deveríá devolverse una respuesta con código de estado 429 (que significa "Demasiadas peticiones"). + +Para activar la limitación de rango, la clase [[yii\web\User::identityClass|user identity class]] debe implementar [[yii\filters\RateLimitInterface]]. +Este interface requiere la implementación de tres métodos: + +* `getRateLimit()`: devuelve el número máximo de peticiones permitidas y el periodo de tiempo (p.e., `[100, 600]` significa que como mucho puede haber 100 llamadas al API dentro de 600 segundos). +* `loadAllowance()`: devuelve el número de peticiones que quedan permitidas y el tiempo (fecha/hora) UNIX + con el último límite del rango que ha sido comprobado. +* `saveAllowance()`: guarda ambos, el número restante de peticiones permitidas y el tiempo actual (fecha/hora) UNIX . + +Puedes usar dos columnas en la tabla de usuario para guardar la información de lo permitido y la fecha/hora (timestamp). Con ambas definidas, +entonces `loadAllowance()` y `saveAllowance()` pueden ser utilizados para leer y guardar los valores de las dos columnas correspondientes al actual usuario autenticado. +Para mejorar el desempeño, también puedes considerar almacenar esas piezas de información en caché o almacenamiento NoSQL. + +Una vez que la clase de identidad implementa la interfaz requerida, Yii utilizará automáticamente [[yii\filters\RateLimiter]] +configurado como un filtro de acción para que [[yii\rest\Controller]] compruebe el límite de rango. El limitador de rango +lanzará una excepeción [[yii\web\TooManyRequestsHttpException]] cuando el límite del rango sea excedido. + +Puedes configurar el limitador de rango +en tu clase controlador REST como sigue: + +```php +public function behaviors() +{ + $behaviors = parent::behaviors(); + $behaviors['rateLimiter']['enableRateLimitHeaders'] = false; + return $behaviors; +} +``` + +Cuando se activa el límite de rango, por defecto todas las respuestas serán enviadas con la siguiente cabecera HTTP conteniendo +información sobre el límite actual de rango: + +* `X-Rate-Limit-Limit`, el máximo número de peticiones permitidas en un periodo de tiempo +* `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, +tal y como en el anterior ejemplo. diff --git a/docs/guide-es/rest-resources.md b/docs/guide-es/rest-resources.md new file mode 100644 index 0000000..3d8979e --- /dev/null +++ b/docs/guide-es/rest-resources.md @@ -0,0 +1,190 @@ +Recursos +========= + +Las APIs RESTful lo son todos para acceder y manipular *recursos (resources)*. Puedes observar los recursos en el paradigma MVC en [Modelos (models)](structure-models.md) . + +Mientras que no hay restricción a cómo representar un recurso, en YII usualmente, puedes representar recursos como objetos de la clase [[yii\base\Model]] o sus clases hijas (p.e. [[yii\db\ActiveRecord]]), por las siguientes razones: + +* [[yii\base\Model]] implementa el interface [[yii\base\Arrayable]] , el cual te permite personalizar como exponer los datos de los recursos a travès de las APIs RESTful. +* [[yii\base\Model]] soporta [Validación de entrada (input validation)](input-validation.md), lo cual es muy usado en las APIs RESTful para soportar la entrada de datos. +* [[yii\db\ActiveRecord]] provee un poderoso soporte para el acceso a datos en bases de datos y su manipulación, lo que lo le hace servir perfectamente si sus recursos de datos están en bases de datos. + +En esta sección, vamos principalmente a describir como la clase con recursos que extiende de [[yii\base\Model]] (o sus clases hijas) puede especificar qué datos puede ser devueltos vía las APIs RESTful. Si la clase de los recursos no extiende de [[yii\base\Model]], entonces todas las variables públicas miembro serán devueltas. + + +## Campos (fields) + +Cuando incluimos un recurso en una respuesta de la API RESTful, el recurso necesita ser serializado en una cadena. +Yii divide este proceso en dos pasos. Primero, el recurso es convertido en un array por [[yii\rest\Serializer]]. +Segundo, el array es serializado en una cadena en el formato requerido (p.e. JSON, XML) por [[yii\web\ResponseFormatterInterface|response formatters]]. El primer paso es en el que debes de concentrarte principalmente cuando desarrolles una clase de un recurso. + +Sobreescribiendo [[yii\base\Model::fields()|fields()]] y/o [[yii\base\Model::extraFields()|extraFields()]], +puedes especificar qué datos, llamados *fields*, en el recursos, pueden ser colocados en el array que le representa. +La diferencia entre estos dos métodos es que el primero especifica el conjunto de campos por defecto que deben ser incluidos en el array que los representa, mientras que el último especifica campos adicionales que deben de ser incluidos en el array si una petición del usuario final para ellos vía el parámetro de consulta `expand`. Por ejemplo, + +``` +// devuelve todos los campos declarados en fields() +http://localhost/users + +// sólo devuelve los campos id y email, provistos por su declaración en fields() +http://localhost/users?fields=id,email + +// devuelve todos los campos en fields() y el campo profile siempre y cuando esté declarado en extraFields() +http://localhost/users?expand=profile + +// sólo devuelve los campos id, email y profile, siempre y cuando ellos estén declarados en fields() y extraFields() +http://localhost/users?fields=id,email&expand=profile +``` + + +### Sobreescribiendo `fields()` + +Por defecto, [[yii\base\Model::fields()]] devuelve todos los atributos de los modelos como si fueran campos, mientras [[yii\db\ActiveRecord::fields()]] sólo devuelve los atributos que tengan datos en la base de datos. + +Puedes sobreescribir `fields()` para añadir, quitar, renombrar o redefinir campos. El valor de retorno de `fields()` ha de estar en un array. Las claves del array son los nombres de los campos y los valores del array son las correspondientes definiciones de los campos que pueden ser tanto nombres de propiedades/atributos o funciones anónimas que devuelven los correspondientes valores del los campos. En el caso especial de que el nombre de un campo sea el mismo que su definición puedes omitir la clave en el array. Por ejemplo, + +```php +// explícitamente lista cada campo, siendo mejor usarlo cuando quieras asegurarte que los cambios +// en una tabla de la base de datos o en un atributo del modelo no provoque el cambio de tu campo (para mantener la compatibilidad anterior). +public function fields() +{ + return [ + // el nombre de campo es el mismo nombre del atributo + 'id', + // el nombre del campo es "email", su atributo se denomina "email_address" + 'email' => 'email_address', + // el nombre del campo es "name", su valor es definido está definido por una función anónima de retrollamada (callback) + 'name' => function () { + return $this->first_name . ' ' . $this->last_name; + }, + ]; +} + +// el ignorar algunos campos, es mejor usarlo cuando heredas de una implementación padre +// y pones en la lista negra (blacklist) algunos campos sensibles +public function fields() +{ + $fields = parent::fields(); + + // quita los campos con información sensible + unset($fields['auth_key'], $fields['password_hash'], $fields['password_reset_token']); + + return $fields; +} +``` + +> Atención: Dado que, por defecto, todos los atributos de un modelo pueden ser incluidos en la devolución del API, debes +> examinar tus datos para estar seguro de que no contiene información sensible. Si se da este tipo de información, +> debes sobreescribir `fields()` para filtrarlos. En el ejemplo anterior, escogemos +> quitar `auth_key`, `password_hash` y `password_reset_token`. + + +### Sobreescribiendo `extraFields()` + +Por defecto, [[yii\base\Model::extraFields()]] no devuelve nada, mientras que [[yii\db\ActiveRecord::extraFields()]] devuelve los nombres de las relaciones que tienen datos (populated) obtenidos de la base de datos. + +El formato de devolución de los datos de `extraFields()` es el mismo que el de `fields()`. Usualmente, `extraFields()` es principalmente usado para especificar campos cuyos valores sean objetos. Por ejemplo, dado la siguiente declaración de campo, + +```php +public function fields() +{ + return ['id', 'email']; +} + +public function extraFields() +{ + return ['profile']; +} +``` + +la petición `http://localhost/users?fields=id,email&expand=profile` puede devolver los siguientes datos en formato JSON : + +```php +[ + { + "id": 100, + "email": "100@example.com", + "profile": { + "id": 100, + "age": 30, + } + }, + ... +] +``` + + +## Enlaces (Links) + +[HATEOAS](http://en.wikipedia.org/wiki/HATEOAS), es una abreviación de Hipermedia es el Motor del Estado de la Aplicación (Hypermedia as the Engine of Application State), promueve que las APIs RESTfull devuelvan información que permita a los clientes descubrir las acciones que soportan los recursos devueltos. El sentido de HATEOAS es devolver un conjunto de hiperenlaces con relación a la información, cuando los datos de los recursos son servidos por las APIs. + +Las clases con recursos pueden soportar HATEOAS implementando el interfaz [[yii\web\Linkable]] . El interfaz contiene sólo un método [[yii\web\Linkable::getLinks()|getLinks()]] el cual debe de de devolver una lista de [[yii\web\Link|links]]. +Típicamente, debes devolver al menos un enlace `self` representando la URL al mismo recurso objeto. Por ejemplo, + +```php +use yii\db\ActiveRecord; +use yii\web\Link; +use yii\web\Linkable; +use yii\helpers\Url; + +class User extends ActiveRecord implements Linkable +{ + public function getLinks() + { + return [ + Link::REL_SELF => Url::to(['user/view', 'id' => $this->id], true), + ]; + } +} +``` + +Cuando un objeto `User` es devuelto en una respuesta, puede contener un elemento `_links` representando los enlaces relacionados con el usuario, por ejemplo, + +``` +{ + "id": 100, + "email": "user@example.com", + // ... + "_links" => { + "self": { + "href": "https://example.com/users/100" + } + } +} +``` + + +## Colecciones + +Los objetos de los recursos pueden ser agrupados en *collections*. Cada colección contiene una lista de recursos objeto del mismo tipo. + +Las colecciones pueden ser representadas como arrays pero, es usualmente más deseable representarlas como [proveedores de datos (data providers)](output-data-providers.md). Esto es así porque los proveedores de datos soportan paginación y ordenación de los recursos, lo cual es comunmente necesario en las colecciones devueltas con las APIs RESTful. Por ejemplo, la siguiente acción devuelve un proveedor de datos sobre los recursos post: + +```php +namespace app\controllers; + +use yii\rest\Controller; +use yii\data\ActiveDataProvider; +use app\models\Post; + +class PostController extends Controller +{ + public function actionIndex() + { + return new ActiveDataProvider([ + 'query' => Post::find(), + ]); + } +} +``` + +Cuando un proveedor de datos está enviando una respuesta con el API RESTful, [[yii\rest\Serializer]] llevará la actual página de los recursos y los serializa como un array de recursos objeto. Adicionalmente, [[yii\rest\Serializer]] +puede incluir también la información de paginación a través de las cabeceras HTTP siguientes: + +* `X-Pagination-Total-Count`: Número total de recursos; +* `X-Pagination-Page-Count`: Número de páginas; +* `X-Pagination-Current-Page`: Página actual (iniciando en 1); +* `X-Pagination-Per-Page`: Número de recursos por página; +* `Link`: Un conjunto de enlaces de navegación permitiendo al cliente recorrer los recursos página a página. + +Un ejemplo se puede ver en la sección [Inicio rápido (Quick Start)](rest-quick-start.md#trying-it-out). diff --git a/docs/guide-es/rest-response-formatting.md b/docs/guide-es/rest-response-formatting.md new file mode 100644 index 0000000..2b8826a --- /dev/null +++ b/docs/guide-es/rest-response-formatting.md @@ -0,0 +1,156 @@ +Formato de Respuesta +==================== + +Cuando se maneja una petición al API RESTful, una aplicación realiza usualmente los siguientes pasos que están relacionados +con el formato de la respuesta: + +1. Determinar varios factores que pueden afectar al formato de la respuesta, como son el tipo de medio, lenguaje, versión, etc. + Este proceso es también conocido como [negociación de contenido (content negotiation)](http://en.wikipedia.org/wiki/Content_negotiation). +2. La conversión de objetos recurso en arrays, como está descrito en la sección [Recursos (Resources)](rest-resources.md). + Esto es realizado por la clase [[yii\rest\Serializer]]. +3. La conversión de arrays en cadenas con el formato determinado por el paso de negociación de contenido. Esto es + realizado por los [[yii\web\ResponseFormatterInterface|response formatters]] registrados con el + componente de la aplicación [[yii\web\Response::formatters|response]]. + + +## Negociación de contenido (Content Negotiation) + +Yii soporta la negociación de contenido a través del filtro [[yii\filters\ContentNegotiator]]. La clase de controlador base +del API RESTful [[yii\rest\Controller]] está equipada con este filtro bajo el nombre `contentNegotiator`. +El filtro provee tanto un formato de respuesta de negociación como una negociación de lenguaje. Por ejemplo, si la petición API RESTful +contiene la siguiente cabecera, + +``` +Accept: application/json; q=1.0, */*; q=0.1 +``` + +puede obtener una respuesta en formato JSON, como a continuación: + +``` +$ curl -i -H "Accept: application/json; q=1.0, */*; q=0.1" "http://localhost/users" + +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 +X-Powered-By: PHP/5.4.20 +X-Pagination-Total-Count: 1000 +X-Pagination-Page-Count: 50 +X-Pagination-Current-Page: 1 +X-Pagination-Per-Page: 20 +Link: ; rel=self, + ; rel=next, + ; rel=last +Transfer-Encoding: chunked +Content-Type: application/json; charset=UTF-8 + +[ + { + "id": 1, + ... + }, + { + "id": 2, + ... + }, + ... +] +``` + +Detrás de escena, antes de que sea ejecutada una acción del controlador del API RESTful, el filtro [[yii\filters\ContentNegotiator]] +comprobará la cabecera HTTP `Accept` de la petición y definirá el [[yii\web\Response::format|response format]] +como `'json'`. Después de que la acción sea ejecutada y devuelva el objeto recurso o la colección resultante, +[[yii\rest\Serializer]] convertirá el resultado en un array. Y finalmente, [[yii\web\JsonResponseFormatter]] +serializará el array en una cadena JSON incluyéndola en el cuerpo de la respuesta. + +Por defecto, el API RESTful soporta tanto el formato JSON como el XML. Para soportar un nuevo formato, debes configurar +la propiedad [[yii\filters\ContentNegotiator::formats|formats]] del filtro `contentNegotiator` tal y como sigue, +en las clases del controlador del API: + +```php +use yii\web\Response; + +public function behaviors() +{ + $behaviors = parent::behaviors(); + $behaviors['contentNegotiator']['formats']['text/html'] = Response::FORMAT_HTML; + return $behaviors; +} +``` + +Las claves de la propiedad `formats` son los tipos MIME soportados, mientras que los valores son los nombres de formato de respuesta correspondientes, +los cuales deben ser soportados en [[yii\web\Response::formatters]]. + + +## Serialización de Datos + +Como hemos descrito antes, [[yii\rest\Serializer]] es la pieza central responsable de convertir +objetos recurso o colecciones en arrays. Reconoce objetos tanto implementando [[yii\base\ArrayableInterface]] +como [[yii\data\DataProviderInterface]]. El primer formateador es implementado principalmente para objetos recursos, +mientras que el segundo para recursos collección. + +Puedes configurar el serializador definiendo la propiedad [[yii\rest\Controller::serializer]] con un array de configuración. +Por ejemplo, a veces puedes querer ayudar a simplificar el trabajo de desarrollo del cliente incluyendo información de la paginación +directamente en el cuerpo de la respuesta. Para hacer esto, configura la propiedad [[yii\rest\Serializer::collectionEnvelope]] +como sigue: + +```php +use yii\rest\ActiveController; + +class UserController extends ActiveController +{ + public $modelClass = 'app\models\User'; + public $serializer = [ + 'class' => 'yii\rest\Serializer', + 'collectionEnvelope' => 'items', + ]; +} +``` + +Puedes obtener la respuesta que sigue para la petición `http://localhost/users`: + +``` +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 +X-Powered-By: PHP/5.4.20 +X-Pagination-Total-Count: 1000 +X-Pagination-Page-Count: 50 +X-Pagination-Current-Page: 1 +X-Pagination-Per-Page: 20 +Link: ; rel=self, + ; rel=next, + ; rel=last +Transfer-Encoding: chunked +Content-Type: application/json; charset=UTF-8 + +{ + "items": [ + { + "id": 1, + ... + }, + { + "id": 2, + ... + }, + ... + ], + "_links": { + "self": { + "href": "http://localhost/users?page=1" + }, + "next": { + "href": "http://localhost/users?page=2" + }, + "last": { + "href": "http://localhost/users?page=50" + } + }, + "_meta": { + "totalCount": 1000, + "pageCount": 50, + "currentPage": 1, + "perPage": 20 + } +} +``` diff --git a/docs/guide-es/rest-routing.md b/docs/guide-es/rest-routing.md new file mode 100644 index 0000000..74d9dc9 --- /dev/null +++ b/docs/guide-es/rest-routing.md @@ -0,0 +1,92 @@ +Enrutamiento +============ + +Con las clases de controlador y recurso preparadas, puedes acceder a los recursos usando una URL como +`http://localhost/index.php?r=user/create`, parecida a la que usas con aplicaciones Web normales. + +En la práctica, querrás usualmente usar URLs limpias y obtener ventajas de los verbos HTTP. +Por ejemplo, una petición `POST /users` significaría acceder a la acción `user/create`. +Esto puede realizarse fácilmente configurando el componente de la aplicación `urlManager` +como sigue: + +```php +'urlManager' => [ + 'enablePrettyUrl' => true, + 'enableStrictParsing' => true, + 'showScriptName' => false, + 'rules' => [ + ['class' => 'yii\rest\UrlRule', 'controller' => 'user'], + ], +] +``` + +En comparación con la gestión de URL en las aplicaciones Web, lo principalmente nuevo de lo anterior es el uso de +[[yii\rest\UrlRule]] para el enrutamiento de las peticiones con el API RESTful. Esta clase especial de regla URL creará +un conjunto completo de reglas URL hijas para soportar el enrutamiento y creación de URL para el/los controlador/es especificados. +Por ejemplo, el código anterior es equivalente a las siguientes reglas: + +```php +[ + 'PUT,PATCH users/' => 'user/update', + 'DELETE users/' => 'user/delete', + 'GET,HEAD users/' => 'user/view', + 'POST users' => 'user/create', + 'GET,HEAD users' => 'user/index', + 'users/' => 'user/options', + 'users' => 'user/options', +] +``` + +Y los siguientes puntos finales del API son mantenidos por esta regla: + +* `GET /users`: lista de todos los usuarios página a página; +* `HEAD /users`: muestra ĺa información resumén del usuario listado; +* `POST /users`: crea un nuevo usuario; +* `GET /users/123`: devuelve los detalles del usuario 123; +* `HEAD /users/123`: muestra la información resúmen del usuario 123; +* `PATCH /users/123` y `PUT /users/123`: actualizan al usuario 123; +* `DELETE /users/123`: borra el usuario 123; +* `OPTIONS /users`: muestra los verbos soportados de acuerdo al punto final `/users`; +* `OPTIONS /users/123`: muestra los verbos soportados de acuerdo al punto final `/users/123`. + +Puedes configurar las opciones `only` y `except` para explícitamente listar cuáles acciones a soportar o cuáles +deshabilitar, respectivamente. Por ejemplo, + +```php +[ + 'class' => 'yii\rest\UrlRule', + 'controller' => 'user', + 'except' => ['delete', 'create', 'update'], +], +``` + +También puedes configurar las propiedades `patterns` o `extraPatterns` para redifinir patrones existentes o añadir nuevos soportados por esta regla. +Por ejemplo, para soportar una nueva acción `search` por el punto final `GET /users/search`, configura la opción `extraPatterns` como sigue, + +```php +[ + 'class' => 'yii\rest\UrlRule', + 'controller' => 'user', + 'extraPatterns' => [ + 'GET search' => 'search', + ], +] +``` + +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. + +> 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`. + +En caso de que la pluralización automática no encaje en tus requerimientos, puedes además configurar la propiedad +[[yii\rest\UrlRule::controller]] para especificar exlpícitamente cómo mapear un nombre utilizado en un punto final URL +a un ID de controlador. Por ejemplo, el siguiente código mapea el nombre `u` al ID del controlador `user`. + +```php +[ + 'class' => 'yii\rest\UrlRule', + 'controller' => ['u' => 'user'], +] +``` diff --git a/docs/guide-es/rest-versioning.md b/docs/guide-es/rest-versioning.md new file mode 100644 index 0000000..49ea108 --- /dev/null +++ b/docs/guide-es/rest-versioning.md @@ -0,0 +1,111 @@ +Versionado +========== + +Una buena API ha de ser *versionada*: los cambios y las nuevas características son implementadas en las nuevas versiones del API, en vez de estar continuamente modificando sólo una versión. Al contrario que en las aplicaciones Web, en las cuales tienes total control del código de ambas partes lado del cliente y lado del servidor, +las APIs están destinadas a ser usadas por los clientes fuera de tu control. Por esta razón, compatibilidad hacia atrás (BC Backward compatibility) +de las APIs ha de ser mantenida siempre que sea posible. Si es necesario un cambio que puede romper la BC, debes de introducirla en la nueva versión del API, e incrementar el número de versión. Los clientes que la usan pueden continuar usando la antigua versión de trabajo del API; los nuevos y actualizados clientes pueden obtener la nueva funcionalidad de la nueva versión del API. + +> Tip: referirse a [Semántica del versionado](http://semver.org/) +para más información en el diseño del número de versión del API. + +Una manera común de implementar el versionado de la API es embeber el número de versión en las URLs de la API. +Por ejemplo, `http://example.com/v1/users` se refiere al punto final `/users` de la versión 1 de la API. + +Otro método de versionado de la API, +la cual está ganando predominancia recientemente, es poner el número de versión en las cabeceras de la petición HTTP. Esto se suele hacer típicamente a través la cabecera `Accept`: + +``` +// vía parámetros +Accept: application/json; version=v1 +// vía de el tipo de contenido del proveedor +Accept: application/vnd.company.myapp-v1+json +``` + +Ambos métodos tienen sus pros y sus contras, y hay gran cantidad de debates sobre cada uno. Debajo puedes ver una estrategia +práctica para el versionado de la API que es una mezcla de estos dos métodos: + +* Pon cada versión superior de la implementación de la API en un módulo separado cuyo ID es el número de la versión mayor (p.e. `v1`, `v2`). + Naturalmente, las URLs de la API contendrán números de versión mayores. +* Dentro de cada versión mayor (y por lo tanto, dentro del correspondiente módulo), usa la cabecera de HTTP `Accept` + para determinar el número de la versión menor y escribe código condicional para responder a la menor versión como corresponde. + +Para cada módulo sirviendo una versión mayor, el módulo debe incluir las clases de recursos y y controladores +que especifican la versión. Para separar mejor la responsabilidad del código, puedes conservar un conjunto común de +clases base de recursos y controladores, y hacer subclases de ellas en cada versión individual del módulo. Dentro de las subclases, +impementa el código concreto como por ejemplo `Model::fields()`. + +Tu código puede estar organizado como lo que sigue: + +``` +api/ + common/ + controllers/ + UserController.php + PostController.php + models/ + User.php + Post.php + modules/ + v1/ + controllers/ + UserController.php + PostController.php + models/ + User.php + Post.php + v2/ + controllers/ + UserController.php + PostController.php + models/ + User.php + Post.php +``` + +La configuración de tu aplicación puede tener este aspecto: + +```php +return [ + 'modules' => [ + 'v1' => [ + 'basePath' => '@app/modules/v1', + 'controllerNamespace' => 'app\modules\v1\controllers', + ], + 'v2' => [ + 'basePath' => '@app/modules/v2', + 'controllerNamespace' => 'app\modules\v2\controllers', + ], + ], + 'components' => [ + 'urlManager' => [ + 'enablePrettyUrl' => true, + 'enableStrictParsing' => true, + 'showScriptName' => false, + 'rules' => [ + ['class' => 'yii\rest\UrlRule', 'controller' => ['v1/user', 'v1/post']], + ['class' => 'yii\rest\UrlRule', 'controller' => ['v2/user', 'v2/post']], + ], + ], + ], +]; +``` + +Como consecuencia del código anterior, `http://example.com/v1/users` devolverá la lista de usuarios en la versión 1, mientras +`http://example.com/v2/users` devolverá la versión 2 de los usuarios. + +Gracias a los módulos, el código de las diferentes principales versiones puede ser aislado. Pero los módulos hacen posible +reutilizar el código a través de los módulos vía clases base comunes y otros recursos compartidos. + +Para tratar con versiones menores, puedes tomar ventaja de la característica de negociación de contenido +provista por el comportamiento (behavior) [[yii\filters\ContentNegotiator|contentNegotiator]]. El comportamiento `contentNegotiator` +definirá la propiedad [[yii\web\Response::acceptParams]] cuando determina qué tipo +de contenido soportar. + +Por ejemplo, si una petición es enviada con la cabecera HTTP `Accept: application/json; version=v1`, +después de la negociación de contenido, [[yii\web\Response::acceptParams]] contendrá el valor `['version' => 'v1']`. + +Basado en la información de versión contenida en `acceptParams`, puedes escribir código condicional en lugares +como acciones, clases de recursos, serializadores, etc. para proveer la funcionalidad apropiada. + +Dado que por definición las versiones menores requireren mantener la compatibilidad hacia atrás, con suerte no tendrás demasiadas +comprobaciones de versión en tu código. De otra manera, probablemente puede ocurrir que necesites crear una versión mayor. diff --git a/docs/guide-es/runtime-bootstrapping.md b/docs/guide-es/runtime-bootstrapping.md new file mode 100644 index 0000000..966f4b0 --- /dev/null +++ b/docs/guide-es/runtime-bootstrapping.md @@ -0,0 +1,24 @@ +Bootstrapping +============= + +El Bootstrapping hace referencia al proceso de preparar el entorno antes de que una aplicación se inicie para resolver y procesar una petición entrante. El se ejecuta en dos lugares: el [script de entrada](structure-entry-scripts.md) y la [aplicación](structure-applications.md). + +En el [script de entrada](structure-entry-scripts.md), se registran los cargadores automáticos de clase para diferentes librerías. Esto incluye el cargador automático de Composer a través de su fichero ‘autoload.php’ y del cargador automático de Yii a través del fichero de clase ‘Yii’. El script de entrada después carga la [configuración](concept-configurations.md) de la aplicación y crea una instancia de la [aplicación](structure-applications.md). + +El constructor de la aplicación, ejecuta el siguiente trabajo de bootstrapping: + +Llama a [[yii\base\Application::preInit()|preInit()]], que configura algunas propiedades de alta prioridad de la aplicación, como [[yii\base\Application::basePath|basePath]]. +Registra el [[yii\base\Application::errorHandler|error handler]]. +Inicializa las propiedades de aplicación usando la configuración de la aplicación dada. +Llama a [[yii\base\Application::init()|init()]] que a su vez llama a [[yii\base\Application::bootstrap()|bootstrap()]] para ejecutar componentes de bootstrapping. +Incluye el archivo de manifiesto de extensiones ‘vendor/yiisoft/extensions.php’ +Crea y ejecuta [componentes de bootstrap](structure-extensions.md#bootstrapping-classes) declarados por las extensiones. +Crea y ejecuta [componentes de aplicación](structure-application-components.md) y/o [módulos](structure-modules.md) que se declaran en la [propiedad bootstrap](structure-applications.md#bootstrap) de la aplicación. + +Debido a que el trabajo de bootstrapping se tiene que ejecutar antes de gestionar *todas* las peticiones, es muy importante mantener este proceso ligero y optimizado lo máximo que sea posible. + +Intenta no registrar demasiados componentes de bootstrapping. Un componente de bootstrapping sólo es necesario si tiene que interaccionar en todo el ciclo de vida de la gestión de la petición. Por ejemplo, si un modulo necesita registrar reglas de análisis de URL adicionales, se debe incluirse en la [propiedad bootstrap](structure-applications.md#bootstrap) para que la nueva regla de URL tenga efecto antes de que sea utilizada para resolver peticiones. + +En modo de producción, hay que habilitar la cache bytecode, así como [APC](http://php.net/manual/es/book.apc.php), para minimizar el tiempo necesario para incluir y analizar archivos PHP. + +Algunas grandes aplicaciones tienen [configuraciones](concept-configurations.md) de aplicación muy complejas que están dividida en muchos archivos de configuración más pequeños. diff --git a/docs/guide-es/runtime-handling-errors.md b/docs/guide-es/runtime-handling-errors.md new file mode 100644 index 0000000..e7cfb15 --- /dev/null +++ b/docs/guide-es/runtime-handling-errors.md @@ -0,0 +1,222 @@ +Gestión de Errores +================== + +Yii incluye un [[yii\web\ErrorHandler|error handler]] que permite una gestión de errores mucho más práctica que +anteriormente. En particular, el gestor de errores de Yii hace lo siguiente para mejorar la gestión de errores: + +* Todos los errores no fatales (ej. advertencias (warning), avisos (notices)) se convierten en excepciones + capturables. +* Las excepciones y los errores fatales de PHP se muestran con una pila de llamadas (call stack) de información + detallada y lineas de código fuente. +* Soporta el uso de [acciones de controlador](structure-controllers.md#actions) dedicadas para mostrar errores. +* Soporta diferentes formatos de respuesta (response) de errores. + +El [[yii\web\ErrorHandler|error handler]] esta habilitado de forma predeterminada. Se puede deshabilitar definiendo la +constante `YII_ENABLE_ERROR_HANDLER` con valor false en el +[script de entrada (entry script)](structure-entry-scripts.md) de la aplicación. + +## Uso del Gestor de Errores + +El [[yii\web\ErrorHandler|error handler]] se registra como un +[componente de aplicación](structure-application-components.md) llamado `errorHandler`. Se puede configurar en la +configuración de la aplicación como en el siguiente ejemplo: + +```php +return [ + 'components' => [ + 'errorHandler' => [ + 'maxSourceLines' => 20, + ], + ], +]; +``` + +Con la anterior configuración, el numero del lineas de código fuente que se mostrará en las páginas de excepciones +será como máximo de 20. + +Como se ha mencionado, el gestor de errores convierte todos los errores de PHP no fatales en excepciones capturables. +Esto significa que se puede usar el siguiente código para tratar los errores PHP: + +```php +use Yii; +use yii\base\ErrorException; + +try { + 10/0; +} catch (ErrorException $e) { + Yii::warning("Division by zero."); +} + +// la ejecución continua ... +``` + +Si se quiere mostrar una página de error que muestra al usuario que su petición no es válida o no es la esperada, se +puede simplemente lanzar una excepción de tipo [[yii\web\HttpException|HTTP exception]], como podría ser +[[yii\web\NotFoundHttpException]]. El gestor de errores establecerá correctamente el código de estado HTTP de la +respuesta y usará la vista de error apropiada para mostrar el mensaje. + +```php +use yii\web\NotFoundHttpException; + +throw new NotFoundHttpException(); +``` + +## Personalizar la Visualización de Errores + +El [[yii\web\ErrorHandler|error handler]] ajusta la visualización del error conforme al valor de la constante +`YII_DEBUG`. Cuando `YII_DEBUG` es `true` (es decir, en modo depuración (debug)), el gestor de errores mostrara las +excepciones con una pila detallada de información y con lineas de código fuente para ayudar a depurar. Y cuando la +variable `YII_DEBUG` es `false`, solo se mostrará el mensaje de error para prevenir la revelación de información +sensible de la aplicación. + +> Información: Si una excepción es descendiente de [[yii\base\UserException]], no se mostrará la pila de llamadas + independientemente del valor de `YII_DEBUG`. Esto es debido a que se considera que estas excepciones se deben a + errores cometidos por los usuarios y los desarrolladores no necesitan corregirlas. + +De forma predeterminada, el [[yii\web\ErrorHandler|error handler]] muestra los errores usando dos +[vistas](structure-views.md): + +* `@yii/views/errorHandler/error.php`: se usa cuando deben mostrarse los errores SIN la información de la pila de + llamadas. Cuando `YII_DEBUG` es falos, este es el único error que se mostrara. +* `@yii/views/errorHandler/exception.php`: se usa cuando los errores deben mostrarse CON la información de la pila de + llamadas. + +Se pueden configurar las propiedades [[yii\web\ErrorHandler::errorView|errorView]] y +[[yii\web\ErrorHandler::exceptionView|exceptionView]] el gestor de errores para usar nuestros propias vistas para +personalizar la visualización de los errores. + +### Uso de Acciones de Error + +Una mejor manera de personalizar la visualización de errores es usar un [acción](structure-controllers.md) de error +dedicada. Para hacerlo, primero se debe configurar la propiedad [[yii\web\ErrorHandler::errorAction|errorAction]] del +componente `errorHandler` como en el siguiente ejemplo: + +```php +return [ + 'components' => [ + 'errorHandler' => [ + 'errorAction' => 'site/error', + ], + ] +]; +``` + +La propiedad [[yii\web\ErrorHandler::errorAction|errorAction]] vincula una [ruta](structure-controllers.md#routes) a +una acción. La configuración anterior declara que cuando un error tiene que mostrarse sin la pila de información de +llamadas, se debe ejecutar la acción `site/error`. + +Se puede crear una acción `site/error` como se hace a continuación, + +```php +namespace app\controllers; + +use Yii; +use yii\web\Controller; + +class SiteController extends Controller +{ + public function actions() + { + return [ + 'error' => [ + 'class' => 'yii\web\ErrorAction', + ], + ]; + } +} +``` + +El código anterior define la acción `error` usando la clase [[yii\web\ErrorAction]] que renderiza un error usando la +vista llamada `error`. + +Además, usando [[yii\web\ErrorAction]], también se puede definir la acción `error` usando un método de acción como en +el siguiente ejemplo, + +```php +public function actionError() +{ + $exception = Yii::$app->errorHandler->exception; + if ($exception !== null) { + return $this->render('error', ['exception' => $exception]); + } +} +``` + +Ahora se debe crear un archivo de vista ubicado en `views/sites/error.php`. En este archivo de vista, se puede acceder +a las siguientes variables si se define el error como un [[yii\web\ErrorAction]]: + +* `name`: el nombre del error; +* `message`: el mensaje del error; +* `exception`: el objeto de excepción a través del cual se puede obtener más información útil, tal como el código de + estado HTTP, el código de error, la pila de llamadas del error, etc. + +> Información: Tanto la [plantilla de aplicación básica](start-installation.md) como la + [plantilla de aplicación avanzada](tutorial-advanced-app.md), ya incorporan la acción de error y la vista de error. + +### Personalizar el Formato de Respuesta de Error + +El gestor de errores muestra los errores de siguiente la configuración del formato de las +[respuestas](runtime-responses.md). Si el [[yii\web\Response::format response format]] es `html`, se usará la vista de +error o excepción para mostrar los errores tal y como se ha descrito en la anterior subsección. Para otros tipos de +formatos de respuesta, el gestor de errores asignara la representación del array de la excepción a la propiedad +[[yii\web\Response::data]] que posteriormente podrá convertirse al formato deseado. Por ejemplo, si el formato de +respuesta es `json`, obtendremos la siguiente respuesta: + +``` +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 +} +``` + +Se puede personalizar el formato de respuestas de error respondiendo al evento `beforeSend` del componente `response` +en la configuración de la aplicación: + +```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; + } + }, + ], + ], +]; +``` + +El código anterior reformateará la respuesta de error como en el siguiente ejemplo: + +``` +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 + } +} +``` \ No newline at end of file diff --git a/docs/guide-es/runtime-logging.md b/docs/guide-es/runtime-logging.md new file mode 100644 index 0000000..505caf0 --- /dev/null +++ b/docs/guide-es/runtime-logging.md @@ -0,0 +1,398 @@ +Registro de anotaciones +======================= + +Yii proporciona un poderoso framework dedicado al registro de anotaciones (logging) que es altamente personalizable y +extensible. Usando este framework se pueden guardar fácilmente anotaciones (logs) de varios tipos de mensajes, +filtrarlos, y unificarlos en diferentes destinos que pueden ser archivos, bases de datos o emails. + + +Usar el framework de registro de anotaciones de Yii involucra los siguientes pasos: + +* Registrar [mensajes de las anotaciones](#log-messages) en distintos lugares del código; +* Configurar los [destinos de las anotaciones](#log-targets) en la configuración de la aplicación para filtrar y + exportar los mensajes de las anotaciones; +* Examinar los mensajes filtrados de los las anotaciones exportadas para diferentes destinos + (ej. [Yii debugger](tool-debugger.md)). + +En esta sección, se describirán principalmente los dos primeros pasos. + +## Anotación de Messages + +Registrar mensajes de anotación es tan simple como llamar a uno de los siguientes métodos de registro de anotaciones. + +* [[Yii::trace()]]: registra un mensaje para trazar el funcionamiento de una sección de código. Se usa principalmente + para tareas de desarrollo. +* [[Yii::info()]]: registra un mensaje que transmite información útil. +* [[Yii::warning()]]: registra un mensaje de advertencia que indica que ha sucedido algo inesperado. +* [[Yii::error()]]: registra un error fatal que debe ser investigado tan pronto como sea posible. + +Estos métodos registran mensajes de varios *niveles de severidad* y *categorías*. Comparten el mismo registro de +función `function ($message, $category = 'application')`, donde `$message` representa el mensaje del registro que +tiene que ser registrado, mientras que `$category` es la categoría del registro de mensaje. El código del siguiente +ejemplo registra la huella del mensaje para la categoría `application`: + +```php +Yii::trace('start calculating average revenue'); +``` + +> Información: Los mensajes de registro pueden ser tanto cadenas de texto como datos complejos, como arrays u objetos. + Es responsabilidad de los [destinos de registros](#log-targets) tratar los mensajes de registro de manera apropiada. + De forma predeterminada, si un mensaje de registro no es una cadena de texto, se exporta como si fuera un string + llamando a [[yii\helpers\VarDumper::export()]]. + +Para organizar mejor y filtrar los mensajes de registro, se recomienda especificar una categoría apropiada para cada +mensaje de registro. Se puede elegir un sistema de nombres jerárquicos por categorías que facilite a los +[destino de registros](#log-targets) el filtrado de mensajes basándose en categorías. Una manera simple pero +efectiva de organizarlos es usar la constante predefinida (magic constant) de PHP `__METHOD__` como nombre de +categoría. Además este es el enfoque que se usa en el código del núcleo (core) del framework Yii. Por ejemplo, + +```php +Yii::trace('start calculating average revenue', __METHOD__); +``` + +La constante `__METHOD__` equivale al nombre del método (con el prefijo del nombre completo del nombre de clase) donde +se encuentra la constante. Por ejemplo, es igual a la cadena `'app\controllers\RevenueController::calculate'` si la +linea anterior de código se llamara dentro de este método. + +> Información: Los métodos de registro de anotaciones descritos anteriormente en realidad son accesos directos al + método [[yii\log\Logger::log()|log()]] del [[yii\log\Logger|logger object]] que es un singleton accesible a través + de la expresión `Yii::getLogger()`. Cuando se hayan registrado suficientes mensajes o cuando la aplicación haya + finalizado, el objeto de registro llamará [[yii\log\Dispatcher|message dispatcher]] para enviar los mensajes de + registro registrados a los [destiinos de registros](#log-targets). + +## Destino de Registros + +Un destino de registro es una instancia de la clase [[yii\log\Target]] o de una clase hija. Este filtra los +mensajes de registro por sus niveles de severidad y sus categorías y después los exporta a algún medio. Por ejemplo, +un [[yii\log\DbTarget|database target]] exporta los mensajes de registro filtrados a una tabla de base de datos, +mientras que un [[yii\log\EmailTarget|email target]] exporta los mensajes de registro a una dirección de correo +electrónico específica. + +Se pueden registrar múltiples destinos de registros en una aplicación configurándolos en la +[aplicación de componente](structure-application-components.md) `log` dentro de la configuración de aplicación, como +en el siguiente ejemplo: + +```php +return [ + // el componente log tiene que cargarse durante el proceso de bootstrapping + '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', + ], + ], + ], + ], + ], +]; +``` + +> Nota: El componente `log` debe cargarse durante el proceso de [bootstrapping](runtime-bootstrapping.md) para que +pueda enviar los mensajes de registro a los destinos inmediatamente. Este es el motivo por el que se lista en el +array `bootstrap` como se muestra más arriba. + +En el anterior código, se registran dos destinos de registros en la propiedad [[yii\log\Dispatcher::targets]] + +* el primer destino gestiona los errores y las advertencias y las guarda en una tabla de la base de datos; +* el segundo destino gestiona mensajes los mensajes de error de las categorías cuyos nombres empiecen por + `yii\db\` y los envía por email a las direcciones `admin@example.com` y `developer@example.com`. + +Yii incluye los siguientes destinos. En la API de documentación se pueden referencias a estas clases e +información de configuración y uso. + +* [[yii\log\DbTarget]]: almacena los mensajes de registro en una tabla de la base de datos. +* [[yii\log\EmailTarget]]: envía los mensajes de registro a direcciones de correo preestablecidas. +* [[yii\log\FileTarget]]: guarda los menajes de registro en archivos. +* [[yii\log\SyslogTarget]]: guarda los mensajes de registro en el syslog llamando a la función PHP `syslog()`. + +A continuación, se describirá las características más comunes de todos los destinos de registros. + +### Filtrado de Mensajes + +Se pueden configurar las propiedades [[yii\log\Target::levels|levels]] y [[yii\log\Target::categories|categories]] +para cada destino de registros, con estas se especifican los niveles de severidad y las categorías de mensajes que +deberán procesar sus destinos. + +La propiedad [[yii\log\Target::levels|levels]] es un array que consta de uno o varios de los siguientes valores: + +* `error`: correspondiente a los mensajes registrados por [[Yii::error()]]. +* `warning`: correspondiente a los mensajes registrados por [[Yii::warning()]]. +* `info`: correspondiente a los mensajes registrados por [[Yii::info()]]. +* `trace`: correspondiente a los mensajes registrados por [[Yii::trace()]]. +* `profile`: correspondiente a los mensajes registrados por [[Yii::beginProfile()]] y [[Yii::endProfile()]], que se + explicará más detalladamente en la subsección [Perfiles](#performance-profiling). + +Si no se especifica la propiedad [[yii\log\Target::levels|levels]], significa que el destino procesará los +mensajes de *cualquier* nivel de severidad. + +La propiedad [[yii\log\Target::categories|categories]] es un array que consta de categorías de mensaje o patrones. El +destino sólo procesará mensajes de las categorías que se puedan encontrar o si coinciden con algún patrón listado +en el array. Un patrón de categoría es un nombre de categoría al que se le añade un asterisco `*` al final. Un nombre +de categoría coincide con un patrón si empieza por el mismo prefijo que el patrón. Por ejemplo, +`yii\db\Command::execute` y `yii\db\Command::query` que se usan como nombres de categoría para los mensajes +registrados en la clase [[yii\db\Command]], coinciden con el patrón `yii\db\*`. + +Si no se especifica la propiedad [[yii\log\Target::categories|categories]], significa que el destino procesará +los mensajes de *todas* las categorías. + +Además añadiendo las categorías en listas blancas (whitelisting) mediante la propiedad +[[yii\log\Target::categories|categories]], también se pueden añadir ciertas categorías en listas negras (blacklist) +configurando la propiedad [[yii\log\Target::except|except]]. Si se encuentra la categoría de un mensaje o coincide +algún patrón con esta propiedad, NO será procesada por el destino. + +La siguiente configuración de destinos especifica que el destino solo debe procesar los mensajes de error y +de advertencia de las categorías que coincidan con alguno de los siguientes patrones `yii\db\*` o +`yii\web\HttpException:*`, pero no con `yii\web\HttpException:404`. + +```php +[ + 'class' => 'yii\log\FileTarget', + 'levels' => ['error', 'warning'], + 'categories' => [ + 'yii\db\*', + 'yii\web\HttpException:*', + ], + 'except' => [ + 'yii\web\HttpException:404', + ], +] +``` + +> Información: Cuando se captura una excepción de tipo HTTP por el [gestor de errores](runtime-handling-errors.md), se + registrará un mensaje de error con el nombre de categoría con formato `yii\web\HttpException:ErrorCode`. Por + ejemplo, la excepción [[yii\web\NotFoundHttpException]] causará un mensaje de error del tipo + `yii\web\HttpException:404`. + +### Formato de los Mensajes + +Los destinos exportan los mensajes de registro filtrados en cierto formato. Por ejemplo, is se instala un +destino de registros de la calse [[yii\log\FileTarget]], encontraremos un registro similar en el archivo de +registro `runtime/log/app.log`: + +``` +2014-10-04 18:10:15 [::1][][-][trace][yii\base\Module::getModule] Loading module: debug +``` + +De forma predeterminada los mensajes de registro se formatearan por [[yii\log\Target::formatMessage()]] como en el +siguiente ejemplo: + +``` +Timestamp [IP address][User ID][Session ID][Severity Level][Category] Message Text +``` + +Se puede personalizar el formato configurando la propiedad [[yii\log\Target::prefix]] que es un PHP ejecutable y +devuelve un prefijo de mensaje personalizado. Por ejemplo, el siguiente código configura un destino de registro +anteponiendo a cada mensaje de registro el ID de usuario (se eliminan la dirección IP y el ID por razones de +privacidad). + +```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]"; + } +] +``` + +Además de prefijos de mensaje, destinos de registros también añaden alguna información de contexto en cada lote +de mensajes de registro. De forma predeterminada, se incluyen los valores de las siguientes variables globales de +PHP: `$_GET`, `$_POST`, `$_FILES`, `$_COOKIE`, `$_SESSION` y `$_SERVER`. Se puede ajustar el comportamiento +configurando la propiedad [[yii\log\Target::logVars]] con los nombres de las variables globales que se quieran incluir +con el destino del registro. Por ejemplo, la siguiente configuración de destino de registros especifica que +sólo se añadirá al mensaje de registro el valor de la variable `$_SERVER`. + +```php +[ + 'class' => 'yii\log\FileTarget', + 'logVars' => ['_SERVER'], +] +``` + +Se puede configurar `logVars` para que sea un array vacío para deshabilitar totalmente la inclusión de información de +contexto. O si se desea implementar un método propio de proporcionar información de contexto se puede sobrescribir el +método [[yii\log\Target::getContextMessage()]]. + +### Nivel de Seguimiento de Mensajes + +Durante el desarrollo, a veces se quiere visualizar de donde proviene cada mensaje de registro. Se puede lograr +configurando la propiedad [[yii\log\Dispatcher::traceLevel|traceLevel]] del componente `log` como en el siguiente +ejemplo: + +```php +return [ + 'bootstrap' => ['log'], + 'components' => [ + 'log' => [ + 'traceLevel' => YII_DEBUG ? 3 : 0, + 'targets' => [...], + ], + ], +]; +``` + +La configuración de aplicación anterior establece el [[yii\log\Dispatcher::traceLevel|traceLevel]] para que sea 3 si +`YII_DEBUG` esta habilitado y 0 si esta deshabilitado. Esto significa que si `YII_DEBUG` esta habilitado, a cada +mensaje de registro se le añadirán como mucho 3 niveles de la pila de llamadas del mensaje que se este registrando; y +si `YII_DEBUG` está deshabilitado, no se incluirá información de la pila de llamadas. + +> Información: Obtener información de la pila de llamadas no es trivial. Por lo tanto, sólo se debe usar esta + característica durante el desarrollo o cuando se depura la aplicación. + +### Liberación (Flushing) y Exportación de Mensajes + +Como se ha comentado anteriormente, los mensajes de registro se mantienen en un array por el +[[yii\log\Logger|logger object]]. Para limitar el consumo de memoria de este array, el componente encargado del +registro de mensajes enviará los mensajes registrados a los [destinos de registros](#log-targets) cada vez que el +array acumule un cierto número de mensajes de registro. Se puede personalizar el número configurando la propiedad +[[yii\log\Dispatcher::flushInterval|flushInterval]] del componente `log`: + +```php +return [ + 'bootstrap' => ['log'], + 'components' => [ + 'log' => [ + 'flushInterval' => 100, // el valor predeterminado es 1000 + 'targets' => [...], + ], + ], +]; +``` + +> Información: También se produce la liberación de mensajes cuando la aplicación finaliza, esto asegura que los + destinos de los registros reciban los mensajes de registro. + +Cuando el [[yii\log\Logger|logger object]] libera los mensajes de registro enviándolos a los +[destinos de registros](#log-targets), estos no se exportan inmediatamente. La exportación de mensajes solo se +produce cuando un destino de registros acumula un cierto número de mensajes filtrados. Se puede personalizar este +número configurando la propiedad [[yii\log\Target::exportInterval|exportInterval]] de un +[destinos de registros](#log-targets) individual, como se muestra a continuación, + +```php +[ + 'class' => 'yii\log\FileTarget', + 'exportInterval' => 100, // el valor predeterminado es 1000 +] +``` + +Debido al nivel de configuración de la liberación y exportación de mensajes, de forma predeterminada cuando se llama a +`Yii::trace()` o cualquier otro método de registro de mensajes, NO veremos el registro de mensaje inmediatamente en +los destinos de registros. Esto podría ser un problema para algunas aplicaciones de consola de ejecución +prolongada (long-running). Para hacer que los mensajes de registro aparezcan inmediatamente en los destinos de +registro se deben establecer [[yii\log\Dispatcher::flushInterval|flushInterval]] y +[[yii\log\Target::exportInterval|exportInterval]] para que tengan valor 1 como se muestra a continuación: + +```php +return [ + 'bootstrap' => ['log'], + 'components' => [ + 'log' => [ + 'flushInterval' => 1, + 'targets' => [ + [ + 'class' => 'yii\log\FileTarget', + 'exportInterval' => 1, + ], + ], + ], + ], +]; +``` + +> Nota: El uso frecuente de liberación y exportación puede degradar el rendimiento de la aplicación. + +### Conmutación de Destinos de Registros + +Se puede habilitar o deshabilitar un destino de registro configuración su propiedad +[[yii\log\Target::enabled|enabled]]. Esto se puede llevar a cabo a mediante la configuración del destino de +registros o con la siguiente declaración PHP de código: + +```php +Yii::$app->log->targets['file']->enabled = false; +``` + +El código anterior requiere que se asocie un destino como `file`, como se muestra a continuación usando las +claves de texto en el array `targets`: + +```php +return [ + 'bootstrap' => ['log'], + 'components' => [ + 'log' => [ + 'targets' => [ + 'file' => [ + 'class' => 'yii\log\FileTarget', + ], + 'db' => [ + 'class' => 'yii\log\DbTarget', + ], + ], + ], + ], +]; +``` + +### Creación de Nuevos Destinos + +La creación de nuevas clases de destinos de registro es muy simple. Se necesita implementar el método +[[yii\log\Target::export()]] enviando el contenido del array [[yii\log\Target::messages]] al medio designado. Se puede +llamar al método [[yii\log\Target::formatMessage()]] para formatear los mensajes. Se pueden encontrar más detalles de +destinos de registros en las clases incluidas en la distribución de Yii. + +## Perfilado de Rendimiento + +El Perfilado de rendimiento es un tipo especial de registro de mensajes que se usa para medir el tiempo que tardan en +ejecutarse ciertos bloques de código y encontrar donde están los cuellos de botella de rendimiento. Por ejemplo, la +clase [[yii\db\Command]] utiliza el perfilado de rendimiento para encontrar conocer el tiempo que tarda cada consulta +a la base de datos. + +Para usar el perfilado de rendimiento, primero debemos identificar los bloques de código que tienen que ser +perfilados, para poder enmarcar su contenido como en el siguiente ejemplo: + +```php +\Yii::beginProfile('myBenchmark'); + +... Empieza el perfilado del bloque de código ... + +\Yii::endProfile('myBenchmark'); +``` + +Donde `myBenchmark` representa un token único para identificar el bloque de código. Después cuando se examine el +resulte del perfilado, se podrá usar este token para encontrar el tiempo que ha necesitado el correspondiente bloque +de código. + +Es importante asegurarse de que los pares de `beginProfile` y `endProfile` estén bien anidados. Por ejemplo, + +```php +\Yii::beginProfile('block1'); + + // código que será perfilado + + \Yii::beginProfile('block2'); + // más código para perfilar + \Yii::endProfile('block2'); + +\Yii::endProfile('block1'); +``` + +Si nos dejamos el `\Yii::endProfile('block1')` o lo intercambiamos `\Yii::endProfile('block1')` con +`\Yii::endProfile('block2')`, el perfilado de rendimiento no funcionará. + +Se registra un mensaje de registro con el nivel de severidad `profile` para cada bloque de código que se haya +perfilado. Se puede configurar el [destino del registro](#log-targets) para reunir todos los mensajes y exportarlos. +El [depurador de Yii](tool-debugger.md) incluye un panel de perfilado de rendimiento que muestra los resultados de +perfilado. \ No newline at end of file diff --git a/docs/guide-es/runtime-overview.md b/docs/guide-es/runtime-overview.md new file mode 100644 index 0000000..7e9780b --- /dev/null +++ b/docs/guide-es/runtime-overview.md @@ -0,0 +1,24 @@ +Información General +=============== + +Cada vez que una aplicación Yii gestiona una petición, se somete a un flujo de trabajo similar. + +1. Un usuario hace una petición al [script de entrada](structure-entry-scripts.md) ‘web/index.php’. +2. El script de entrada carga la [configuración](concept-configurations.md) y crea una instancia de la + [aplicación](structure-applications.md) para gestionar la petición. +3. La aplicación resuelve la [ruta](runtime-routing.md) solicitada con la ayuda del componente + [petición](runtime-requests.md) de la aplicación. +4. La aplicación crea una instancia del [controlador](structure-controllers.md) para gestionar la petición. +5. El controlador crea una instancia de la [acción](structure-controllers.md) y ejecuta los filtros para la acción. +6. Si algún filtro falla, se cancela la acción. +7. Si pasa todos los filtros, se ejecuta la acción. +8. La acción carga un modelo de datos, posiblemente de la base de datos. +9. La acción renderiza una vista, proporcionándole el modelo de datos. +10. El resultado renderizado se devuelve al componente [respuesta](runtime-responses.md) de la aplicación. +11. El componente respuesta envía el resultado renderizado al navegador del usuario. + +El siguiente diagrama muestra como una aplicación gestiona una petición. + +![Request Lifecycle](images/request-lifecycle.png) + +En esta sección, se describirá en detalle cómo funcionan algunos de estos pasos. diff --git a/docs/guide-es/runtime-requests.md b/docs/guide-es/runtime-requests.md new file mode 100644 index 0000000..3179577 --- /dev/null +++ b/docs/guide-es/runtime-requests.md @@ -0,0 +1,141 @@ +Peticiones +========== + +Las peticiones (requests) hechas a una aplicación son representadas como objetos [[yii\web\Request]] que proporcionan +información como parámetros de la petición, cabeceras HTTP, cookies, etc. Dada una petición, se puede acceder al +objeto request correspondiente a través del [componente de aplicación](structure-application-components.md) `request` +que, por defecto, es una instancia de [[yii\web\Request]]. En esta sección se describirá como hacer uso de este +componente en las aplicaciones. + +## Parámetros de Request + +Para obtener los parámetros de la petición, se puede llamar a los métodos [[yii\web\Request::get()|get()]] y +[[yii\web\Request::post()|post()]] del componente `request`. Estos devuelven los valores de `$_GET` y `$_POST`, +respectivamente. Por ejemplo: + +```php +$request = Yii::$app->request; + +$get = $request->get(); +// equivalente a: $get = $_GET; + +$id = $request->get('id'); +// equivalente a: $id = isset($_GET['id']) ? $_GET['id'] : null; + +$id = $request->get('id', 1); +// equivalente a: $id = isset($_GET['id']) ? $_GET['id'] : 1; + +$post = $request->post(); +// equivalente a: $post = $_POST; + +$name = $request->post('name'); +// equivalente a: $name = isset($_POST['name']) ? $_POST['name'] : null; + +$name = $request->post('name', ''); +// equivalente a: $name = isset($_POST['name']) ? $_POST['name'] : ''; +``` + +> Información: En lugar de acceder directamente a `$_GET` y `$_POST` para obtener los parámetros de la petición, es + recomendable que se obtengan mediante el componente `request` como en el ejemplo anterior. Esto facilitará la + creación de tests ya que se puede simular una componente de request con datos de peticiones personalizados. + +Cuando se implementan [APIs RESTful](rest-quick-start.md), a menudo se necesita obtener parámetros enviados desde el +formulario a través de PUT, PATCH u otros [métodos de request](runtime-requests.md#request-methods). Se pueden obtener +estos parámetros llamando a los métodos [[yii\web\Request::getBodyParam()]]. Por ejemplo: + +```php +$request = Yii::$app->request; + +// devuelve todos los parámetros +$params = $request->bodyParams; + +// devuelve el parámetro "id" +$param = $request->getBodyParam('id'); +``` + +> Información: A diferencia de los parámetros `GET`, los parámetros enviados desde el formulario a través de `POST`, + `PUT`, `PATCH`, etc. se envían en el cuerpo de la petición. El componente `request` convierte los parámetros cuando + se acceda a él a través de los métodos descritos anteriormente. Se puede personalizar la manera en como los + parámetros se convierten configurando la propiedad [[yii\web\Request::parsers]]. + +## Métodos de Request + +Se puede obtener el método HTTP usado por la petición actual a través de la expresión `Yii::$app->request->method`. Se +proporcionan un conjunto de propiedades booleanas para comprobar si el método actual es de un cierto tipo. Por ejemplo: + +```php +$request = Yii::$app->request; + +if ($request->isAjax) { // la request es una request AJAX } +if ($request->isGet) { // el método de la request es GET } +if ($request->isPost) { // el método de la request es POST } +if ($request->isPut) { // el método de la request es PUT } +``` + +## URLs de Request + +El componente `request` proporciona muchas maneras de inspeccionar la URL solicitada actualmente. + +Asumiendo que la URL que se está solicitando es `http://example.com/admin/index.php/product?id=100`, se pueden obtener +varias partes de la URL explicadas en los siguientes puntos: + +* [[yii\web\Request::url|url]]: devuelve `/admin/index.php/product?id=100`, que es la URL sin la parte de información + del host. +* [[yii\web\Request::absoluteUrl|absoluteUrl]]: devuelve `http://example.com/admin/index.php/product?id=100`, que es + la URL entera, incluyendo la parte de información del host. +* [[yii\web\Request::hostInfo|hostInfo]]: devuelve `http://example.com`, que es la parte de información del host + dentro de la URL. +* [[yii\web\Request::pathInfo|pathInfo]]: devuelve `/product`, que es la parte posterior al script de entrada y + anterior al interrogante (query string) +* [[yii\web\Request::queryString|queryString]]: devuelve `id=100`, que es la parte posterior al interrogante. +* [[yii\web\Request::baseUrl|baseUrl]]: devuelve `/admin`, que es la parte posterior a la información del host y + anterior al nombre de script de entrada. +* [[yii\web\Request::scriptUrl|scriptUrl]]: devuelve `/admin/index.php`, que es la URL sin la información del la ruta + ni la query string. +* [[yii\web\Request::serverName|serverName]]: devuelve `example.com`, que es el nombre del host dentro de la URL. +* [[yii\web\Request::serverPort|serverPort]]: devuelve 80, que es el puerto que usa el servidor web. + +## Cabeceras HTTP + +Se pueden obtener la información de las cabeceras HTTP a través de [[yii\web\HeaderCollection|header collection]] +devueltas por la propiedad [[yii\web\Request::headers]]. Por ejemplo: + +```php +// $headers es un objeto de yii\web\HeaderCollection +$headers = Yii::$app->request->headers; + +// devuelve el valor Accept de la cabecera +$accept = $headers->get('Accept'); + +if ($headers->has('User-Agent')) { // la cabecera contiene un User-Agent } +``` + +El componente `request` también proporciona soporte para acceder rápidamente a las cabeceras usadas más comúnmente, +incluyendo: + +* [[yii\web\Request::userAgent|userAgent]]: devuelve el valor de la cabecera `User-Agen`. +* [[yii\web\Request::contentType|contentType]]: devuelve el valor de la cabecera `Content-Type` que indica el tipo + MIME de los datos del cuerpo de la petición. +* [[yii\web\Request::acceptableContentTypes|acceptableContentTypes]]: devuelve los tipos de contenido MIME aceptado + por los usuarios, ordenados por puntuación de calidad. Los que tienen mejor puntuación, se devolverán primero. +* [[yii\web\Request::acceptableLanguages|acceptableLanguages]]: devuelve los idiomas aceptados por el usuario. Los + idiomas devueltos son ordenados según su orden de preferencia. El primer elemento representa el idioma preferido. + +Si la aplicación soporta múltiples idiomas y se quiere mostrar las páginas en el idioma preferido por el usuario, se +puede usar el método de negociación de idioma [[yii\web\Request::getPreferredLanguage()]]. Este método obtiene una +lista de idiomas soportados por la aplicación, comparados con +[[yii\web\Request::acceptableLanguages|acceptableLanguages]], y devuelve el idioma más apropiado. + +> Consejo: También se puede usar el filtro [[yii\filters\ContentNegotiator|ContentNegotiator]] para determinar +diatónicamente el content type y el idioma que debe usarse en la respuesta. El filtro implementa la negociación de +contenido en la parte superior de las propiedades y métodos descritos anteriormente. + +## Información del cliente + +Se puede obtener el nombre del host y la dirección IP de la máquina cliente a través de +[[yii\web\Request::userHost|userHost]] y [[yii\web\Request::userIP|userIP]], respectivamente. Por ejemplo: + +```php +$userHost = Yii::$app->request->userHost; +$userIP = Yii::$app->request->userIP; +``` \ No newline at end of file diff --git a/docs/guide-es/runtime-responses.md b/docs/guide-es/runtime-responses.md new file mode 100644 index 0000000..8b16966 --- /dev/null +++ b/docs/guide-es/runtime-responses.md @@ -0,0 +1,265 @@ +Respuestas +========== + +Cuando una aplicación finaliza la gestión de una [petición (request)](runtime-requests.md), genera un objeto +[[yii\web\Response|response]] y lo envía al usuario final. El objeto response contiene información tal como el código +de estado (status code) HTTP, las cabeceras (headers) HTTP y el cuerpo (body). El objetivo final del desarrollo de una +aplicación Web es esencialmente construir objetos response para varias peticiones. + +En la mayoría de casos principalmente se debe tratar con +[componentes de aplicación](structure-application-components.md) de tipo `response` que, por defecto, son una +instancia de [[yii\web\Response]]. Sin embargo, Yii permite crear sus propios objetos `response` y enviarlos al +usuario final tal y como se explica a continuación. + +En esta sección, se describirá como generar y enviar respuestas a usuarios finales. + +## Códigos de Estado + +Una de las primeras cosas que debería hacerse cuando se genera una respuesta es indicar si la petición se ha +gestionado correctamente. Esto se indica asignando la propiedad [[yii\web\Response::statusCode]] a la que se le puede +asignar cualquier valor válido dentro de los +[códigos de estado HTTP](http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html). Por ejemplo, para indicar que la +petición se ha gestionado correctamente, se puede asignar el código de estado a 200, como en el siguiente ejemplo: + +```php +Yii::$app->response->statusCode = 200; +``` + +Sin embargo, en la mayoría de casos nos es necesario asignar explícitamente el código de estado. Esto se debe a que el +valor por defecto de [[yii\web\Response::statusCode]] es 200. Y si se quiere indicar que la petición ha fallado, se +puede lanzar una excepción HTTP apropiada como en el siguiente ejemplo: + +```php +throw new \yii\web\NotFoundHttpException; +``` + +Cuando el [error handler](runtime-handling-errors.md) captura una excepción, obtendrá el código de estado de la +excepción y lo asignará a la respuesta. En el caso anterior, la excepción [[yii\web\NotFoundHttpException]] está +asociada al estado HTTP 404. En Yii existen las siguientes excepciones predefinidas. + +* [[yii\web\BadRequestHttpException]]: código de estado 400. +* [[yii\web\ConflictHttpException]]: código de estado 409. +* [[yii\web\ForbiddenHttpException]]: código de estado 403. +* [[yii\web\GoneHttpException]]: código de estado 410. +* [[yii\web\MethodNotAllowedHttpException]]: código de estado 405. +* [[yii\web\NotAcceptableHttpException]]: código de estado 406. +* [[yii\web\NotFoundHttpException]]: código de estado 404. +* [[yii\web\ServerErrorHttpException]]: código de estado 500. +* [[yii\web\TooManyRequestsHttpException]]: código de estado 429. +* [[yii\web\UnauthorizedHttpException]]: código de estado 401. +* [[yii\web\UnsupportedMediaTypeHttpException]]: código de estado 415. + +Si la excepción que se quiere lanzar no se encuentra en la lista anterior, se puede crear una extendiendo +[[yii\web\HttpException]], o directamente lanzando un código de estado, por ejemplo: + +```php +throw new \yii\web\HttpException(402); +``` + +## Cabeceras HTTP + +Se puede enviar cabeceras HTTP modificando el [[yii\web\Response::headers|header collection]] en el componente +`response`. Por ejemplo: + +```php +$headers = Yii::$app->response->headers; + +// añade una cabecera Pragma. Las cabeceras Pragma existentes NO se sobrescribirán. +$headers->add('Pragma', 'no-cache'); + +// asigna una cabecera Pragma. Cualquier cabecera Pragma existente será descartada. +$headers->set('Pragma', 'no-cache'); + +// Elimina las cabeceras Pragma y devuelve los valores de las eliminadas en un array +$values = $headers->remove('Pragma'); +``` + +> Información: Los nombres de las cabeceras case insensitive, es decir, no discriminan entre mayúsculas y minúsculas. +Además, las nuevas cabeceras registradas no se enviarán al usuario hasta que se llame al método +[[yii\web\Response::send()]]. + +## Cuerpo de la Respuesta + +La mayoría de las respuestas deben tener un cuerpo que contenga el contenido que se quiere mostrar a los usuarios +finales. + +Si ya se tiene un texto de cuerpo con formato, se puede asignar a la propiedad [[yii\web\Response::content]] del +response. Por ejemplo: + +```php +Yii::$app->response->content = 'hello world!'; +``` + +Si se tiene que dar formato a los datos antes de enviarlo al usuario final, se deben asignar las propiedades +[[yii\web\Response::format|format]] y [[yii\web\Response::data|data]]. La propiedad [[yii\web\Response::format|format]] + especifica que formato debe tener [[yii\web\Response::data|data]]. Por ejemplo: + +```php +$response = Yii::$app->response; +$response->format = \yii\web\Response::FORMAT_JSON; +$response->data = ['message' => 'hello world']; +``` + +Yii soporta a los siguientes formatos de forma predeterminada, cada uno de ellos implementado por una clase +[[yii\web\ResponseFormatterInterface|formatter]]. Se pueden personalizar los formatos o añadir nuevos sobrescribiendo +la propiedad [[yii\web\Response::formatters]]. + +* [[yii\web\Response::FORMAT_HTML|HTML]]: implementado por [[yii\web\HtmlResponseFormatter]]. +* [[yii\web\Response::FORMAT_XML|XML]]: implementado por [[yii\web\XmlResponseFormatter]]. +* [[yii\web\Response::FORMAT_JSON|JSON]]: implementado por [[yii\web\JsonResponseFormatter]]. +* [[yii\web\Response::FORMAT_JSONP|JSONP]]: implementado por [[yii\web\JsonResponseFormatter]]. + +Mientras el cuerpo de la respuesta puede ser mostrado de forma explicita como se muestra a en el anterior ejemplo, en +la mayoría de casos se puede asignar implícitamente por el valor de retorno de los métodos de +[acción](structure-controllers.md). El siguiente, es un ejemplo de uso común: + +```php +public function actionIndex() +{ + return $this->render('index'); +} +``` + +La acción `index` anterior, devuelve el resultado renderizado de la vista `index`. El valor devuelto será recogido por +el componente `response`, se le aplicará formato y se enviará al usuario final. + +Por defecto, el formato de respuesta es [[yii\web\Response::FORMAT_HTML|HTML]], sólo se debe devolver un string en un +método de acción. Si se quiere usar un formato de respuesta diferente, se debe asignar antes de devolver los datos. +Por ejemplo: + +```php +public function actionInfo() +{ + \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; + return [ + 'message' => 'hello world', + 'code' => 100, + ]; +} +``` + +Como se ha mencionado, además de usar el componente de aplicación `response` predeterminado, también se pueden crear +objetos response propios y enviarlos a los usuarios finales. Se puede hacer retornando un objeto en el método de +acción, como en el siguiente ejemplo: + +```php +public function actionInfo() +{ + return \Yii::createObject([ + 'class' => 'yii\web\Response', + 'format' => \yii\web\Response::FORMAT_JSON, + 'data' => [ + 'message' => 'hello world', + 'code' => 100, + ], + ]); +} +``` + +> Nota: Si se crea un objeto response propio, no se podrán aprovechar las configuraciones asignadas para el componente +`response` en la configuración de la aplicación. Sin embargo, se puede usar la +[inyección de dependencias](concept-di-container.md) para aplicar la configuración común al nuevo objeto response. + +## Redirección del Navegador + +La redirección del navegador se basa en el envío de la cabecera HTTP `Location`. Debido a que esta característica se +usa comúnmente, Yii proporciona soporte especial para ello. + +Se puede redirigir el navegador a una URL llamando al método [[yii\web\Response::redirect()]]. El método asigna la +cabecera de `Location` apropiada con la URL proporcionada y devuelve el objeto response él mismo. En un método de +acción, se puede acceder a él mediante el acceso directo [[yii\web\Controller::redirect()]] como en el siguiente +ejemplo: + +```php +public function actionOld() +{ + return $this->redirect('http://example.com/new', 301); +} +``` + +En el ejemplo anterior, el método de acción devuelve el resultado del método `redirect()`. Como se ha explicado antes, +el objeto response devuelto por el método de acción se usará como respuesta enviándola al usuario final. + +En otros sitios que no sean los métodos de acción, se puede llamar a [[yii\web\Response::redirect()]] directamente +seguido por una llamada al método [[yii\web\Response::send()]] para asegurar que no habrá contenido extra en la +respuesta. + +```php +\Yii::$app->response->redirect('http://example.com/new', 301)->send(); +``` + +> Información: De forma predeterminada, el método [[yii\web\Response::redirect()]] asigna el estado de respuesta al +código de estado 302 que indica al navegador que recurso solicitado está *temporalmente* alojado en una URI diferente. +Se puede enviar un código de estado 301 para expresar que el recurso se ha movido de forma *permanente*. + +Cuando la petición actual es de una petición AJAX, el hecho de enviar una cabecera `Location` no causará una +redirección del navegador automática. Para resolver este problema, el método [[yii\web\Response::redirect()]] asigna +una cabecera `X-Redirect` con el valor de la URL de redirección. En el lado del cliente se puede escribir código +JavaScript para leer la esta cabecera y redireccionar el navegador como corresponda. + +> Información: Yii contiene el archivo JavaScript `yii.js` que proporciona un conjunto de utilidades comunes de +JavaScript, incluyendo la redirección de navegador basada en la cabecera `X-Redirect`. Por tanto, si se usa este +fichero JavaScript (registrándolo *asset bundle* [[yii\web\YiiAsset]]), no se necesitará escribir nada más para tener +soporte en redirecciones AJAX. + +## Enviar Archivos + +Igual que con la redirección, el envío de archivos es otra característica que se basa en cabeceras HTTP especificas. +Yii proporciona un conjunto de métodos para dar soporte a varias necesidades del envío de ficheros. Todos ellos +incorporan soporte para el rango de cabeceras HTTP. + +* [[yii\web\Response::sendFile()]]: envía un fichero existente al cliente. +* [[yii\web\Response::sendContentAsFile()]]: envía un string al cliente como si fuera un archivo. +* [[yii\web\Response::sendStreamAsFile()]]: envía un *file stream* existente al cliente como si fuera un archivo. + +Estos métodos tienen la misma firma de método con el objeto response como valor de retorno. Si el archivo que se envía +es muy grande, se debe considerar usar [[yii\web\Response::sendStreamAsFile()]] porque es más efectivo en términos de +memoria. El siguiente ejemplo muestra como enviar un archivo en una acción de controlador. + +```php +public function actionDownload() +{ + return \Yii::$app->response->sendFile('ruta/del/fichero.txt'); +} +``` + +Si se llama al método de envío de ficheros fuera de un método de acción, también se debe llamar al método +[[yii\web\Response::send()]] después para asegurar que no se añada contenido extra a la respuesta. + +```php +\Yii::$app->response->sendFile('ruta/del/fichero.txt')->send(); +``` + +Algunos servidores Web tienen un soporte especial para enviar ficheros llamado *X-Sendfile*. La idea es redireccionar +la petición para un fichero a un servidor Web que servirá el fichero directamente. Como resultado, la aplicación Web +puede terminar antes mientras el servidor Web envía el fichero. Para usar esta funcionalidad, se puede llamar a +[[yii\web\Response::xSendFile()]]. La siguiente lista resume como habilitar la característica `X-Sendfile` para +algunos servidores Web populares. + +- 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) + +## Enviar la Respuesta + +El contenido en una respuesta no se envía al usuario hasta que se llama al método [[yii\web\Response::send()]]. De +forma predeterminada, se llama a este método automáticamente al final de [[yii\base\Application::run()]]. Sin embargo, +se puede llamar explícitamente a este método forzando el envío de la respuesta inmediatamente. + +El método [[yii\web\Response::send()]] sigue los siguientes pasos para enviar una respuesta: + +1. Lanza el evento [[yii\web\Response::EVENT_BEFORE_SEND]]. +2. Llama a [[yii\web\Response::prepare()]] para convertir el [[yii\web\Response::data|response data]] en + [[yii\web\Response::content|response content]]. +3. Lanza el evento [[yii\web\Response::EVENT_AFTER_PREPARE]]. +4. Llama a [[yii\web\Response::sendHeaders()]] para enviar las cabeceras HTTP registradas. +5. Llama a [[yii\web\Response::sendContent()]] para enviar el contenido del cuerpo de la respuesta. +6. Lanza el evento [[yii\web\Response::EVENT_AFTER_SEND]]. + +Después de llamar a [[yii\web\Response::send()]] por primera vez, cualquier llamada a este método será ignorada. Esto +significa que una vez se envíe una respuesta, no se le podrá añadir más contenido. + +Como se puede observar, el método [[yii\web\Response::send()]] lanza varios eventos útiles. Al responder a estos +eventos, es posible ajustar o decorar la respuesta. \ No newline at end of file diff --git a/docs/guide-es/runtime-routing.md b/docs/guide-es/runtime-routing.md new file mode 100644 index 0000000..45c61ab --- /dev/null +++ b/docs/guide-es/runtime-routing.md @@ -0,0 +1,660 @@ +Enrutamiento y Creación de URLS +=============================== + +Cuando una aplicación Yii empieza a procesar una URL solicitada, lo primero que hace es convertir la URL en una +[ruta](structure-controllers.md#routes). Luego se usa la ruta para instanciar la +[acción de controlador](structure-controllers.md) correspondiente para gestionar la petición. A este proceso se +le llama *enrutamiento*. + +El proceso inverso se llama *creación de URLs*, y crea una URL a partir de una ruta dada y unos parámetros de consulta (query) asociados. Cuando posteriormente se solicita la URL creada, el proceso de enrutamiento puede resolverla y +convertirla en la ruta original con los parámetros asociados. + +La principal pieza encargada del enrutamiento y de la creación de URLs es [[yii\web\UrlManager|URL manager]], que se +registra como el componente de aplicación `urlManager`. El [[yii\web\UrlManager|URL manager]] proporciona el método +[[yii\web\UrlManager::parseRequest()|parseRequest()]] para convertir una petición entrante en una ruta y sus +parámetros asociados y el método [yii\web\UrlManager::createUrl()|createUrl()]] para crear una URL a partir de una +ruta dada y sus parámetros asociados. + +Configurando el componente `urlManager` en la configuración de la aplicación, se puede dotar a la aplicación de +reconocimiento arbitrario de formatos de URL sin modificar el código de la aplicación existente. Por ejemplo, se +puede usar el siguiente código para crear una URL para la acción `post/view`: + +``` php +use yii\helpers\Url; + +// Url::to() llama a UrlManager::createUrl() para crear una URL +$url = Url::to(['post/view', 'id' => 100]); +``` + +Dependiendo de la configuración de `urlManager`, la URL generada puede asemejarse a alguno de los siguientes (u otro) +formato. Y si la URL creada se solicita posteriormente, se seguirá convirtiendo en la ruta original y los valores de +los parámetros. + +``` +/index.php?r=post/view&id=100 +/index.php/post/100 +/posts/100 +``` + + +## Formatos de URL + +El [[yii\web\UrlManager|URL manager]] soporta dos formatos de URL: el formato predeterminado de URL y el formato URL +amigable (pretty URL). + +El formato de URL predeterminado utiliza un parámetro de consulta llamado `r` para representar la ruta y los +parámetros normales de la petición para representar los parámetros asociados con la ruta. Por ejemplo, la URL +`/index.php?r=post/view&id=100` representa la ruta `post/view` y 100 es el valor del parámetro `id` de la consulta. +El formato predeterminado de URL no requiere ningún tipo de configuración para [[yii\web\UrlManager|URL manager]] y +funciona en cualquier configuración de servidor Web. + +El formato de URL amigable utiliza la ruta adicional a continuación del nombre del script de entrada (entry script) +para representar la ruta y los parámetros de consulta. Por ejemplo, La ruta en la URL `/index.php/post/100` es +`/post/100` que puede representar la ruta `post/view` y el parámetro de consulta `id` 100 con una +[[yii\web\UrlManager::rules|URL rule]] apropiada. Para poder utilizar el formato de URL amigable, se tendrán que +diseñar una serie de [[yii\web\UrlManager::rules|URL rules]] de acuerdo con el requerimiento actual acerca de como +deben mostrarse las URLs. + +Se puede cambiar entre los dos formatos de URL conmutando la propiedad +[[yii\web\UrlManager::enablePrettyUrl|enablePrettyUrl]] del [[yii\web\UrlManager|URL manager]] sin cambiar ningún +otro código de aplicación. + +## Enrutamiento + +El Enrutamiento involucra dos pasos. El primero, la petición (request) entrante se convierte en una ruta y sus +parámetros de consulta asociados. En el segundo paso, se crea la correspondiente +[acción de controlador](structure-controllers.md) para la ruta convertida para que gestione la petición. + +Cuando se usa el formato predefinido de URL, convertir una petición en una ruta es tan simple como obtener los valores +del parámetro de consulta `GET` llamado `r`. + +Cuando se usa el formato de URL amigable, el [[yii\web\UrlManager|URL manager]] examinará las +[[yii\web\UrlManager::rules|URL rules]] registradas para encontrar alguna que pueda convertir la petición en una ruta. +Si no se encuentra tal regla, se lanzará una excepción de tipo [[yii\web\NotFoundHttpException]]. + +Una vez que la petición se ha convertido en una ruta, es el momento de crear la acción de controlador identificada +por la ruta. La ruta se desglosa en múltiples partes a partir de las barras que contenga. Por ejemplo, `site/index` +será desglosado en `site` e `index`. Cada parte is un ID que puede hacer referencia a un modulo, un controlador o una +acción. Empezando por la primera parte de la ruta, la aplicación, sigue los siguientes pasos para generar +(si los hay), controladores y acciones: + +1. Establece la aplicación como el modulo actual. +2. Comprueba si el [[yii\base\Module::controllerMap|controller map]] del modulo actual contiene un ID actual. Si lo + tiene, se creará un objeto controlador de acuerdo con la configuración del controlador encontrado en el mapa, y + se seguirá el Paso 5 para gestionar la parte restante de la ruta. +3. Comprueba si el ID hace referencia a un modulo listado en la propiedad [[yii\base\Module::modules|modules]] del + módulo actual. Si está listado, se crea un modulo de acuerdo con la configuración encontrada en el listado de + módulos, y se seguirá el Paso 2 para gestionar la siguiente parte de la ruta bajo el contexto de la creación de un + nuevo módulo. +4. Trata el ID como si se tratara de un ID de controlador y crea un objeto controlador. Sigue el siguiente paso con la parte restante de la ruta. +5. El controlador busca el ID en su [[yii\base\Controller::actions()|action map]]. Si lo encuentra, crea una acción de acuerdo con la configuración encontrada en el mapa. De otra forma, el controlador intenta crear una acción en linea definida por un método de acción correspondiente al ID actual. + +Si ocurre algún error entre alguno de los pasos anteriores, se lanzará una excepción de tipo +[[yii\web\NotFoundHttpException]], indicando el fallo de proceso de enrutamiento. + +### Ruta Predeterminada + +Cuando una petición se convierte en una ruta vacía, se usa la llamada *ruta predeterminada*. Por defecto, la ruta +predeterminada es `site/index`, que hace referencia a la acción `index` del controlador `site`. Se puede personalizar +configurando la propiedad [[yii\web\Application::defaultRoute|defaultRoute]] de la aplicación en la configuración de +aplicación como en el siguiente ejemplo: + +```php +[ + // ... + 'defaultRoute' => 'main/index', +]; +``` + + +### Ruta `catchAll` + +A veces, se puede querer poner la aplicación Web en modo de mantenimiento temporalmente y mostrar la misma pagina de +información para todas las peticiones. Hay varias maneras de lograr este objetivo. Pero una de las maneras más simples +es configurando la propiedad [[yii\web\Application::catchAll]] como en el siguiente ejemplo de configuración de +aplicación: + +```php +[ + // ... + 'catchAll' => ['site/offline'], +]; +``` + +Con la anterior configuración, se usar la acción `site/offline` para gestionar todas las peticiones entrantes. + +La propiedad `catchAll` debe tener un array cuyo primer elemento especifique una ruta, y el resto de elementos +(pares nombre-valor) especifiquen los parámetros [ligados a la acción](structure-controllers.md#action-parameters). + +## Creación de URLs + +Yii proporciona un método auxiliar (helper method) [[yii\helpers\Url::to()]] para crear varios tipos de URLs a partir +de las rutas dadas y sus parámetros de consulta asociados. Por ejemplo, + +```php +use yii\helpers\Url; + +// crea una URL para la ruta: /index.php?r=post/index +echo Url::to(['post/index']); + +// crea una URL para la ruta con parámetros: /index.php?r=post/view&id=100 +echo Url::to(['post/view', 'id' => 100]); + +// crea una URL interna: /index.php?r=post/view&id=100#contentecho +Url::to(['post/view', 'id' => 100, '#' => 'content']); + +// crea una URL absoluta: http://www.example.com/index.php?r=post/index +echo Url::to(['post/index'], true); + +// crea una URL absoluta usando el esquema https: https://www.example.com/index.php?r=post/index +echo Url::to(['post/index'], 'https'); +``` + +Hay que tener en cuenta que en el anterior ejemplo, asumimos que se está usando el formato de URL predeterminado. +Si habilita el formato de URL amigable, las URLs creadas serán diferentes, de acuerdo con las +[[yii\web\UrlManager::rules|URL rules] que se usen. + +La ruta que se pasa al método [[yii\helpers\Url::to()]] es context sensitive. Esto quiere decir que puede ser una ruta +*relativa* o una ruta *absoluta* que serán tipificadas de acuerdo con las siguientes reglas: + +- Si una ruta es una cadena vacía, se usará la [yii\web\Controller::route|route]] solicitada actualmente. +- Si la ruta no contiene ninguna barra `/`, se considerará que se trata de un ID de acción del controlador actual y se + le antepondrá el valor [[\yii\web\Controller::uniqueId|uniqueId]] del controlador actual. +- Si la ruta no tiene barra inicial, se considerará que se trata de una ruta relativa al modulo actual y se le + antepondrá el valor [[\yii\base\Module::uniqueId|uniqueId]] del modulo actual. + +Por ejemplo, asumiendo que el modulo actual es `admin` y el controlador actual es `post`, + +```php +use yii\helpers\Url; + +// la ruta solicitada: /index.php?r=admin/post/index +echo Url::to(['']); + +// una ruta relativa solo con ID de acción: /index.php?r=admin/post/index +echo Url::to(['index']); + +// una ruta relativa: /index.php?r=admin/post/index +echo Url::to(['post/index']); + +// una ruta absoluta: /index.php?r=post/index +echo Url::to(['/post/index']); +``` + +El método [[yii\helpers\Url::to()]] se implementa llamando a los métodos +[[yii\web\UrlManager::createUrl()|createUrl()]] y [[yii\web\UrlManager::createAbsoluteUrl()|createAbsoluteUrl()]] del +[[yii\web\UrlManager|URL manager]]. En las próximas sub-secciones, explicaremos como configurar el +[[yii\web\UrlManager|URL manager]] para personalizar el formato de las URLs generadas. + +El método [[yii\helpers\Url::to()]] también soporta la creación de URLs NO relacionadas con rutas particulares. +En lugar de pasar un array como su primer paramento, se debe pasar una cadena de texto. Por ejemplo, + +```php +use yii\helpers\Url; + +// la URL solicitada actualmente: /index.php?r=admin/post/index +echo Url::to(); + +// una URL con alias: http://example.comYii::setAlias('@example', 'http://example.com/'); +echo Url::to('@example'); + +// una URL absoluta: http://example.com/images/logo.gif +echo Url::to('/images/logo.gif', true);``` +``` + +Además del método `to()`, la clase auxiliar [[yii\helpers\Url]] también proporciona algunos otros métodos de creación +de URLs. Por ejemplo, + +```php +use yii\helpers\Url; + +// URL de la página inicial: /index.php?r=site/index +echo Url::home(); + +// la URL base, útil si la aplicación se desarrolla en una sub-carpeta de la carpeta raíz (root) Web +echo Url::base(); + +// la URL canónica de la actual URL solicitada// visitar https://en.wikipedia.org/wiki/Canonical_link_element +echo Url::canonical(); + +// recuerda la actual URL solicitada y la recupera más tarde requestsUrl::remember(); +echo Url::previous(); +``` + + +## Uso de URLs Amigables + +Para utilizar URLs amigables, hay que configurar el componente `ulrManager` en la configuración de la aplicación como +en el siguiente ejemplo: + +```php +[ + 'components' => [ + 'urlManager' => [ + 'enablePrettyUrl' => true, + 'showScriptName' => false, + 'enableStrictParsing' => true, + 'rules' => [ + // ... + ], + ], + ], +] +``` + +La propiedad [[yii\web\UrlManager::enablePrettyUrl|enablePrettyUrl]] es obligatoria ya que alterna el formato de URL +amigable. El resto de propiedades son opcionales. Sin embargo, la anterior configuración es la más común. + +* [[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`. +* [[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 + [[yii\web\NotFoundHttpException]]. Si la conversión estricta esta deshabilitada, cuando ninguna de las + [[yii\web\UrlManager::rules|rules]] coincida con la URL solicitada, la parte de información de la URL se tratará + como si fuera la ruta solicitada. +* [[yii\web\UrlManager::rules|rules]]: esta propiedad contiene una lista de las reglas que especifican como convertir + y crear URLs. Esta es la propiedad principal con la que se debe trabajar para crear URLs que satisfagan el formato + de un requerimiento particular de la aplicación. + +> Nota: Para ocultar el nombre del script de entrada en las URLs generadas, además de establecer el + [[yii\web\UrlManager::showScriptName|showScriptName]] a falso, puede ser necesaria la configuración del servidor Web + para que identifique correctamente que script PHP debe ejecutarse cuando se solicita una URL que no lo especifique. + Si se usa el servidor Web Apache, se puede utilizar la configuración recomendada descrita en la sección de + [Instalación](start-installation.md#recommended-apache-configuration). + + +### Reglas de URL + +Una regla de URL es una instancia de [[yii\web\UrlRule]] o de una clase hija. Cada URL consiste en un patrón utilizado +para cotejar la parte de información de ruta de las URLs, una ruta, y algunos parámetros de consulta. Una URL puede +usarse para convertir una petición si su patrón coincide con la URL solicitada y una regla de URL pude usarse para +crear una URL si su ruta y sus nombres de parámetros coinciden con los que se hayan dado. + +Cuando el formato de URL amigables está habilitado, el [[yii\web\UrlManager|URL manager]] utiliza las reglas de URL +declaradas en su propiedad [[yii\web\UrlManager::rules|rules]] para convertir las peticiones entrantes y crear URLs. +En particular, para convertir una petición entrante, el [[yii\web\UrlManager|URL manager]] examina las reglas en el +orden que se han declarado y busca la *primera* regla que coincida con la URL solicitada. La regla que coincide es la +que se usa para convertir la URL en una ruta y sus parámetros asociados. De igual modo, para crear una URL, el +[[yii\web\UrlManager|URL manager]] busca la primera regla que coincida con la ruta dad y los parámetros y la utiliza +para crear una URL. + +Se pueden configurar las [[yii\web\UrlManager::rules]] como un array con claves, siendo los patrones y las reglas sus +correspondientes rutas. Cada pareja patrón-ruta construye una regla de URL. Por ejemplo, la siguiente configuración de +configuración de [[yii\web\UrlManager::rules|rules]] declara dos reglas de URL. La primera regla coincide con una URL +`posts` y la mapea a la ruta `post/index`. La segunda regla coincide con una URL que coincida con la expresión regular +`post/(\d+)` y la mapea a la ruta `post/view` y el parámetro llamado `id`. + +```php +[ + 'posts' => 'post/index', + 'post/' => 'post/view', +] +``` + +> Información; El patrón en una regla se usa para encontrar coincidencias en la parte de información de la URL. + Por ejemplo, la parte de información de la ruta `/index.php/post/100?source=ad` es `post/100` + (la primera barra y la ultima son ignoradas) que coincide con el patrón `post/(\d+)`. + +Entre la declaración de reglas de URL como pares de patrón-ruta, también se pueden declarar como arrays de +configuración. Cada array de configuración se usa para configurar un único objeto de tipo regla de URL. Este proceso +se necesita a menudo cuando se quieren configurar otras propiedades de la regla de URL. Por ejemplo, + +```php +[ + // ... otras reglas de URL ... + + [ + 'pattern' => 'posts', + 'route' => 'post/index', + 'suffix' => '.json', + ], +] +``` + +De forma predeterminada si no se especifica la opción `class` en la configuración de una regla, se utilizará la clase +predeterminada [[yii\web\UrlRule]]. + + +### Parameters Asociativos + +Una regla de URL puede asociarse a una determinado grupo de parámetros de consulta que se hayan sido especificados en +el patrón con el formato ``, donde `ParamName` especifica el nombre del parámetro y `RegExp` es una +expresión regular opcional que se usa para encontrar los valores de los parámetros. Si no se especifica `RegExp` +significa que el parámetro debe ser una cadena de texto sin ninguna barra. + +> Nota: Solo se pueden especificar expresiones regulares para los parámetros. La parte restante del patrón se + considera texto plano. + +Cuando se usa una regla para convertir una URL, esta rellenara los parámetros asociados con los valores que coincidan +con las partes correspondientes de la URL, y estos parámetros serán accesibles posteriormente mediante `$_GET` por el +componente de aplicación `request`. Cuando se usa una regla para crear una URL, esta obtendrá los valores de los +parámetros proporcionados y los insertara donde se hayan declarado los parámetros. + +Vamos a utilizar algunos ejemplos para ilustrar como funcionan los parámetros asociativos. Asumiendo que hemos +declarado las siguientes tres URLs: + +```php +[ + 'posts' => 'post/index', + 'post/' => 'post/view', + 'posts//' => 'post/index', +] +``` + +Cuando se usen las reglas para convertir URLs: + +- `/index.php/posts` se convierte en la ruta `post/index` usando la primera regla; +- `/index.php/posts/2014/php` se convierte en la ruta `post/index`, el parámetro `year` cuyo valor es 2014 y el + parámetro `category` cuyo valor es `php` usando la tercera regla; +- `/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 + información `posts/php`. + +Y cuando las se usen las reglas para crear URLs: + +- `Url::to(['post/index'])` genera `/index.php/posts` usando la primera regla; +- `Url::to(['post/index', 'year' => 2014, 'category' => 'php'])` genera `/index.php/posts/2014/php` usando la tercera + regla; +- `Url::to(['post/view', 'id' => 100])` genera `/index.php/post/100` usando la segunda regla; +- `Url::to(['post/view', 'id' => 100, 'source' => 'ad'])` genera `/index.php/post/100?source=ad` usando la segunda + regla. Debido a que el parámetro `source` no se especifica en la regla, se añade como un parámetro de consulta en + la URL generada. +- `Url::to(['post/index', 'category' => 'php'])` genera `/index.php/post/index?category=php` no usa ninguna de las + reglas. Hay que tener en cuenta que si no se aplica ninguna de las reglas, la URL se genera simplemente añadiendo + la parte de información de la ruta y todos los parámetros como parte de la consulta. + + +### Parametrización de Rutas + +Se pueden incrustar nombres de parámetros en la ruta de una regla de URL. Esto permite a la regla de URL poder ser +usada para que coincida con varias rutas. Por ejemplo, la siguiente regla incrusta los parámetros `controller` y +`action` en las rutas. + +```php +[ + '//' => '/', + '/' => '/view', + 's' => '/index', +] +``` + +Para convertir una URL `index.php/comment/100/create`, se aplicará la primera regla, que establece el parámetro +`controller` a `comment` y el parámetro `action` a `create`. Por lo tanto la ruta `/` se resuelve +como `comment/create`. + +Del mismo modo, para crear una URL para una ruta `comment/index`, se aplicará la tercera regla, que crea una URL +`/index.php/comments`. + +> Información: Mediante la parametrización de rutas es posible reducir el numero de reglas de URL e incrementar + significativamente el rendimiento del [[yii\web\UrlManager|URL manager]]. + +De forma predeterminada, todos los parámetros declarados en una regla son requeridos. Si una URL solicitada no +contiene un parámetro en particular, o si se esta creando una URL sin un parámetro en particular, la regla no se +aplicará. Para establecer algunos parámetros como opcionales, se puede configurar la propiedad de +[[yii\web\UrlRule::defaults|defaults]] de una regla. Los parámetros listados en esta propiedad son opcionales y se +usarán los parámetros especificados cuando estos no se proporcionen. + +En la siguiente declaración de reglas, los parámetros `page` y `tag` son opcionales y cuando no se proporcionen, se +usarán los valores 1 y cadena vacía respectivamente. + +```php +[ + // ... otras reglas ... + [ + 'pattern' => 'posts//', + 'route' => 'post/index', + 'defaults' => ['page' => 1, 'tag' => ''], + ], +] +``` + +La regla anterior puede usarse para convertir o crear cualquiera de las siguientes URLs: + +* `/index.php/posts`: `page` es 1, `tag` es ''. +* `/index.php/posts/2`: `page` es 2, `tag` es ''. +* `/index.php/posts/2/news`: `page` es 2, `tag` es `'news'`. +* `/index.php/posts/news`: `page` es 1, `tag` es `'news'`. + +Sin usar ningún parámetro opcional, se tendrían que crear 4 reglas para lograr el mismo resultado. + + +### Reglas con Nombres de Servidor + +Es posible incluir nombres de servidores Web en los parámetros de las URLs. Esto es practico principalmente cuando una +aplicación debe tener distintos comportamientos paro diferentes nombres de servidores Web. Por ejemplo, las siguientes +reglas convertirán la URL `http://admin.example.com/login` en la ruta `admin/user/login` y +`http://www.example.com/login` en `site/login`. + +```php +[ + 'http://admin.example.com/login' => 'admin/user/login', + 'http://www.example.com/login' => 'site/login', +] +``` + +También se pueden incrustar parámetros en los nombres de servidor para extraer información dinámica de ellas. Por +ejemplo, la siguiente regla convertirá la URL `http://en.example.com/posts` en la ruta `post/index` y el parámetro +`language=en`. + +```php +[ + 'http://.example.com/posts' => 'post/index', +] +``` + +> Nota: Las reglas con nombres de servidor NO deben incluir el subdirectorio del script de entrada (entry script) en + sus patrones. Por ejemplo, is la aplicación se encuentra en `http://www.example.com/sandbox/blog`, entonces se debe + usar el patrón `http://www.example.com/posts` en lugar de `http://www.example.com/sandbox/blog/posts`. Esto + permitirá que la aplicación se pueda desarrollar en cualquier directorio sin la necesidad de cambiar el código de la + aplicación. + +### Sufijos de URL + +Se puede querer añadir sufijos a las URLs para varios propósitos. Por ejemplo, se puede añadir `.html`a las URLs para +que parezcan URLs para paginas HTML estáticas; también se puede querer añadir `.json` a las URLs para indicar el tipo +de contenido que se espera encontrar en una respuesta (response). Se puede lograr este objetivo configurando la +propiedad [[yii\web\UrlManager::suffix]] como en el siguiente ejemplo de configuración de aplicación: + +```php +[ + 'components' => [ + 'urlManager' => [ + 'enablePrettyUrl' => true, + 'showScriptName' => false, + 'enableStrictParsing' => true, + 'suffix' => '.html', + 'rules' => [ + // ... + ], + ], + ], +] +``` + +La configuración anterior permitirá al [[yii\web\UrlManager|URL manager]] reconocer las URLs solicitadas y a su vez +crear URLs con el sufijo `.html`. + +> Consejo: Se puede establecer `/` como el prefijo de URL para que las URLs finalicen con una barra. + +> Nota: Cuando se configura un sufijo de URL, si una URL solicitada no tiene el sufijo, se considerará como una URL + desconocida. Esta es una practica recomendada para SEO (optimización en motores de búsqueda). + +A veces, se pueden querer usar sufijos diferentes para URLs diferentes. Esto se puede conseguir configurando la +propiedad [[yii\web\UrlRule::suffix|suffix]] de una regla de URL individual. Cuando una regla de URL tiene la +propiedad establecida, anulará el sufijo estableciendo a nivel de [[yii\web\UrlManager|URL manager]]. Por ejemplo, la +siguiente configuración contiene una regla de URL personalizada que usa el sufijo `.json` en lugar del sufijo global +`.html`. + +```php +[ + 'components' => [ + 'urlManager' => [ + 'enablePrettyUrl' => true, + 'showScriptName' => false, + 'enableStrictParsing' => true, + 'suffix' => '.html', + 'rules' => [ + // ... + [ + 'pattern' => 'posts', + 'route' => 'post/index', + 'suffix' => '.json', + ], + ], + ], + ], +] +``` + + +### Métodos HTTP + +Cuando se implementan APIs RESTful, normalmente se necesita que ciertas URLs se conviertan en otras de acuerdo con el +método HTTP que se esté usando. Esto se puede hacer fácilmente prefijando los métodos HTTP soportados como los +patrones de las reglas. Si una regla soporta múltiples métodos HTTP, hay que separar los nombres de los métodos con +comas. Por ejemplo, la siguiente regla usa el mismo patrón `post/` para dar soporte a diferentes métodos HTTP. +Una petición para `PUT post/100` se convertirá en `post/create`, mientras que una petición `GET post/100` se +convertirá en `post/view`. + +```php +[ + 'PUT,POST post/' => 'post/create', + 'DELETE post/' => 'post/delete', + 'post/' => 'post/view', +] +``` + +> Nota: Si una regla de URL contiene algún método HTTP en su patrón, la regla solo se usará para aplicar conversiones. + Se omitirá cuando se llame a [[yii\web\UrlManager|URL manager]] para crear URLs. + +> Consejo: Para simplificar el enrutamiento en APIs RESTful, Yii proporciona una clase de reglas de URL + [[yii\rest\UrlRule]] especial que es bastante eficiente y soporta ciertas características como pluralización de IDs + de controladores. Para conocer más detalles, se puede visitar la sección [Enrutamiento](rest-routing.md) acerca de + el desarrollo de APIs RESTful. + + +### Personalización de Reglas + +En los anteriores ejemplos, las reglas de URL se han declarado principalmente en términos de pares de patrón-ruta. +Este es un método de acceso directo que se usa a menudo. En algunos escenarios, se puede querer personalizar la regla +de URL configurando sus otras propiedades, tales como [[yii\web\UrlRule::suffix]]. Esto se puede hacer usando una +array completo de configuración para especificar una regla. El siguiente ejemplo se ha extraído de la subsección +[Sufijos de URL](#url-suffixes). + +```php +[ + // ... otras reglas de URL ... + + [ + 'pattern' => 'posts', + 'route' => 'post/index', + 'suffix' => '.json', + ], +] +``` + +> Información: De forma predeterminada si no se especifica una opción `class` para una configuración de regla, se + usará la clase predeterminada [[yii\web\UrlRule]]. + + +### Adición de Reglas Dinámicamente + +Las reglas de URL se pueden añadir dinámicamente en el [[yii\web\UrlManager|URL manager]]. A menudo se necesita por +[módulos](structure-modules.md) redistribubles que se encargan de gestionar sus propias reglas de URL. Para que las +reglas añadidas dinámicamente tenga efecto durante el proceso de enrutamiento, se deben añadir durante la etapa +[bootstrapping](runtime-bootstrapping.md). Para los módulos, esto significa que deben implementar +[[yii\base\BootstrapInterface]] y añadir las reglas en el método +[[yii\base\BootstrapInterface::bootstrap()|bootstrap()]] como en el siguiente ejemplo: + +```php +public function bootstrap($app) +{ + $app->getUrlManager()->addRules([ + // declaraciones de reglas aquí + ], false); +} +``` + +Hay que tener en cuenta se deben añadir estos módulos en [[yii\web\Application::bootstrap]] para que puedan participar +en el proceso de [bootstrapping](runtime-bootstrapping.md) + +### Creación de Clases de Reglas + +A pesar del hecho de que de forma predeterminada la clase [[yii\web\UrlRule]] lo suficientemente flexible para la +mayoría de proyectos, hay situaciones en las que se tiene que crear una clase de reglas propia. Por ejemplo, en un +sitio Web de un concesionario de coches, se puede querer dar soporte a las URL con el siguiente formato +`/Manufacturer/Model`, donde tanto `Manufacturer` como `Model` tengan que coincidir con algún dato almacenado una +tabla de la base de datos. De forma predeterminada, la clase regla no puede gestionar estas reglas ya que se base en +patrones estáticos declarados. + +Podemos crear la siguiente clase de reglas de URL para solucionar el problema. + +```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; // no se aplica esta regla + } + + public function parseRequest($manager, $request) + { + $pathInfo = $request->getPathInfo(); + if (preg_match('%^(\w+)(/(\w+))?$%', $pathInfo, $matches)) { + // comprueba $matches[1] y $matches[3] para ver + // si coincide con un *manufacturer* y un *model* en la base de datos + // Si coinciden, establece $params['manufacturer'] y/o $params['model'] + // y devuelve ['car/index', $params] + } + return false; // no se aplica la regla + } +} +``` + +Y usa la nueva clase de regla en la configuración de [[yii\web\UrlManager::rules]]: + +```php +[ + // ... otras reglas ... + + [ + 'class' => 'app\components\CarUrlRule', + // ... configura otras propiedades ... + ], +] +``` + +## Consideración del Rendimiento + +Cuando se desarrolla una aplicación Web compleja, es importante optimizar las reglas de URL para que tarden el mínimo +tiempo posible en convertir las peticiones y crear URLs. + +Usando rutas parametrizadas se puede reducir el numero de reglas de URL que a su vez significa una mejor en el +rendimiento. + +Cuando se convierten o crean URLs, el [[yii\web\UrlManager|URL manager]] examina las reglas de URL en el orden en que +han sido declaradas. Por lo tanto, se debe tener en cuenta el orden de las reglas de URL y anteponer las reglas más +especificas y/o las que se usen más a menudo. + +Si algunas URLs comparten el mismo prefijo en sus patrones o rutas, se puede considerar usar [[yii\web\GroupUrlRule]] +ya que puede ser más eficiente al ser examinado por [[yii\web\UrlManager|URL manager]] como un grupo. Este suele ser +el caso cuando una aplicación se compone por módulos, y cada uno tiene su propio conjunto de reglas con un ID de +módulo para sus prefijos más comunes. diff --git a/docs/guide-es/runtime-sessions-cookies.md b/docs/guide-es/runtime-sessions-cookies.md new file mode 100644 index 0000000..400801b --- /dev/null +++ b/docs/guide-es/runtime-sessions-cookies.md @@ -0,0 +1,291 @@ +Sesiones (Sessions) y Cookies +============================= + +Las sesiones y las cookies permiten la persistencia de datos a través de múltiples peticiones de usuario. En PHP plano, debes acceder a ellos a través de las variables globales `$_SESSION` y `$_COOKIE`, respectivamente. Yii encapsula las sesiones y las cookies como objetos y por lo tanto te permite acceder a ellos de manera orientada a objetos con estupendas mejoras adicionales. + + +## Sesiones + +Como las [peticiones](runtime-requests.md) y las [respuestas](runtime-responses.md), puedes acceder a las sesiones vía el [componente de la aplicación](structure-application-components.md) `session` el cual es una instancia de [[yii\web\Session]], por defecto. + + +### Abriendo y cerrando sesiones + +Para abrir y cerrar una sesión, puedes hacer lo siguiente: + +```php +$session = Yii::$app->session; + +// comprueba si una sesión está ya abierta +if ($session->isActive) ... + +// abre una sesión +$session->open(); + +// cierra una sesión +$session->close(); + +// destruye todos los datos registrados por la sesión. +$session->destroy(); +``` + +Puedes llamar a [[yii\web\Session::open()|open()]] y [[yii\web\Session::close()|close()]] múltiples veces sin causar errores. Esto ocurre porque internamente los métodos verificarán primero si la sesión está ya abierta. + + +### Accediendo a los datos de sesión + +Para acceder a los datos almacenados en sesión, puedes hacer lo siguiente: + +```php +$session = Yii::$app->session; + +// devuelve una variable de sesión. Los siguientes usos son equivalentes: +$language = $session->get('language'); +$language = $session['language']; +$language = isset($_SESSION['language']) ? $_SESSION['language'] : null; + +// inicializa una variable de sesión. Los siguientes usos son equivalentes: +$session->set('language', 'en-US'); +$session['language'] = 'en-US'; +$_SESSION['language'] = 'en-US'; + +// remueve la variable de sesión. Los siguientes usos son equivalentes: +$session->remove('language'); +unset($session['language']); +unset($_SESSION['language']); + +// comprueba si una variable de sesión existe. Los siguientes usos son equivalentes: +if ($session->has('language')) ... +if (isset($session['language'])) ... +if (isset($_SESSION['language'])) ... + +// recorre todas las variables de sesión. Los siguientes usos son equivalentes: +foreach ($session as $name => $value) ... +foreach ($_SESSION as $name => $value) ... +``` + +> Información: Cuando accedas a los datos de sesión a través del componente `session`, una sesión será automáticamente abierta si no lo estaba antes. Esto es diferente accediendo a los datos de sesión a través de `$_SESSION`, el cual requiere llamar explícitamente a `session_start()`. + +Cuando trabajas con datos de sesiones que son arrays, el componte `session` tiene una limitación que te previene directamente de modificar un elemento del array. Por ejemplo, + +```php +$session = Yii::$app->session; + +// el siguiente código no funciona +$session['captcha']['number'] = 5; +$session['captcha']['lifetime'] = 3600; + +// el siguiente código funciona: +$session['captcha'] = [ + 'number' => 5, + 'lifetime' => 3600, +]; + +// el siguiente código también funciona: +echo $session['captcha']['lifetime']; +``` + +Puedes usar las siguientes soluciones para arreglar este problema: + +```php +$session = Yii::$app->session; + +// directamente usando $_SESSION (asegura te de que Yii::$app->session->open() ha sido llamado) +$_SESSION['captcha']['number'] = 5; +$_SESSION['captcha']['lifetime'] = 3600; + +// devuelve el valor del array, lo modifica y a continuación lo guarda +$captcha = $session['captcha']; +$captcha['number'] = 5; +$captcha['lifetime'] = 3600; +$session['captcha'] = $captcha; + +// usa un ArrayObject en vez de un array +$session['captcha'] = new \ArrayObject; +... +$session['captcha']['number'] = 5; +$session['captcha']['lifetime'] = 3600; + +// almacena los datos en un array con un prefijo común para las claves +$session['captcha.number'] = 5; +$session['captcha.lifetime'] = 3600; +``` + +Para un mejor rendimiento y legibilidad del código, recomendamos la última solución. Es decir, en vez de almacenar un array como una única variable de sesión, almacena cada elemento del array como una variable de sesión que comparta el mismo prefijo clave con otros elementos del array. + + +### Personalizar el almacenamiento de sesión + +Por defecto la clase [[yii\web\Session]] almacena los datos de sesión como ficheros en el servidor. Yii también provee de las siguientes clases de sesión que implementan diferentes almacenamientos de sesión: + +* [[yii\web\DbSession]]: almacena los datos de sesión en una tabla en la base de datos. +* [[yii\web\CacheSession]]: almacena los datos de sesión en una caché con la ayuda de la configuración del [componente caché](caching-data.md#cache-components). +* [[yii\redis\Session]]: almacena los datos de sesión usando [redis](http://redis.io/) como medio de almacenamiento. +* [[yii\mongodb\Session]]: almacena los datos de sesión en [MongoDB](http://www.mongodb.org/). + +Todas estas clases de sesión soportan los mismos métodos de la API. Como consecuencia, puedes cambiar el uso de diferentes almacenamientos de sesión sin la necesidad de modificar el código de tu aplicación que usa sesiones. + +> Nota: si quieres acceder a los datos de sesión vía `$_SESSION` mientras estás usando un almacenamiento de sesión personalizado, debes asegurar te que la sesión está ya empezada por [[yii\web\Session::open()]]. Esto ocurre porque los manipuladores de almacenamiento de sesión personalizado son registrados sin este método. + +Para aprender como configurar y usar estas clases de componentes, por favor consulte la documentación de la API. Abajo está un ejemplo que muestra como configurar [[yii\web\DbSession]] en la configuración de la aplicación para usar una tabla en la base de datos como almacenamiento de sesión: + +```php +return [ + 'components' => [ + 'session' => [ + 'class' => 'yii\web\DbSession', + // 'db' => 'mydb', // el identificador del componente de aplicación DB connection. Por defecto'db'. + // 'sessionTable' => 'my_session', // nombre de la tabla de sesión. Por defecto 'session'. + ], + ], +]; +``` + +También es necesario crear la siguiente tabla de la base de datos para almacenar los datos de sesión: + +```sql +CREATE TABLE session +( + id CHAR(40) NOT NULL PRIMARY KEY, + expire INTEGER, + data BLOB +) +``` + +donde 'BLOB' se refiere al BLOB-type de tu DBMS preferida. Abajo está el tipo BLOB que puedes usar para algunos DBMS populares: + +- MySQL: LONGBLOB +- PostgreSQL: BYTEA +- MSSQL: BLOB + +> Nota: De acuerdo con la configuración de php.ini `session.hash_function`, puedes necesitar ajustar el tamaño de la columna `id`. Por ejemplo, si `session.hash_function=sha256`, deberías usar el tamaño 64 en vez de 40. + + +### Flash Data + +Flash data es una clase especial de datos de sesión que, una vez se inicialice en la primera petición, estará sólo disponible durante la siguiente petición y automáticamente se borrará después. Flash data es comúnmente usado para implementar mensajes que deberían ser mostrados una vez a usuarios finales, tal como mostrar un mensaje de confirmación después de que un usuario envíe un formulario con éxito. + +Puedes inicializar y acceder a flash data a través del componente de aplicación `session`. Por ejemplo, + +```php +$session = Yii::$app->session; + +// Petición #1 +// inicializa el mensaje flash nombrado como "postDeleted" +$session->setFlash('postDeleted', 'You have successfully deleted your post.'); + +// Petición #2 +// muestra el mensaje flash nombrado "postDeleted" +echo $session->getFlash('postDeleted'); + +// Petición #3 +// $result será false ya que el mensaje flash ha sido borrado automáticamente +$result = $session->hasFlash('postDeleted'); +``` + +Al igual que los datos de sesión regulares, puede almacenar datos arbitrarios como flash data. + +Cuando llamas a [yii\web\Session::setFlash()]], sobrescribirá cualquier Flash data que tenga el mismo nombre. +Para añadir un nuevo flash data a el/los existes con el mismo nombre, puedes llamar a [[yii\web\Session::addFlash()]]. +Por ejemplo: + +```php +$session = Yii::$app->session; + +// Petición #1 +// añade un pequeño mensaje flash bajo el nombre de "alerts" +$session->addFlash('alerts', 'You have successfully deleted your post.'); +$session->addFlash('alerts', 'You have successfully added a new friend.'); +$session->addFlash('alerts', 'You are promoted.'); + +// Petición #2 +// $alerts es un array de mensajes flash bajo el nombre de "alerts" +$alerts = $session->getFlash('alerts'); +``` + +> Nota: Intenta no usar a la vez [[yii\web\Session::setFlash()]] con [[yii\web\Session::addFlash()]] para flash data + del mismo nombre. Esto ocurre porque el último método elimina el flash data dentro del array así que puedes añadir un nuevo flash data con el mismo nombre. Como resultado, cuando llamas a [[yii\web\Session::getFlash()]], puedes encontrarte algunas veces que te está devolviendo un array mientras que otras veces te está devolviendo un string, esto depende del orden que invoques a estos dos métodos. + + +## Cookies + +Yii representa cada cookie como un objeto de [[yii\web\Cookie]]. Tanto [[yii\web\Request]] como [[yii\web\Response]] +mantienen una colección de cookies vía la propiedad de llamada `cookies`. La colección de cookie en la antigua representación son enviadas en una petición, mientras la colección de cookie en esta última representa las cookies que van a ser enviadas al usuario. + + +### Leyendo Cookies + +Puedes recuperar las cookies en la petición actual usando el siguiente código: + +```php +// devuelve la colección de cookie (yii\web\CookieCollection) del componente "request" +$cookies = Yii::$app->request->cookies; + +// devuelve el valor "language" de la cookie. Si la cookie no existe, retorna "en" como valor por defecto. +$language = $cookies->getValue('language', 'en'); + +// una manera alternativa de devolver el valor "language" de la cookie +if (($cookie = $cookies->get('language')) !== null) { + $language = $cookie->value; +} + +// puedes también usar $cookies como un array +if (isset($cookies['language'])) { + $language = $cookies['language']->value; +} + +// comprueba si hay una cookie con el valor "language" +if ($cookies->has('language')) ... +if (isset($cookies['language'])) ... +``` + + +### Enviando Cookies + +Puedes enviar cookies a usuarios finales usando el siguiente código: + +```php +// devuelve la colección de cookie (yii\web\CookieCollection) del componente "response" +$cookies = Yii::$app->response->cookies; + +// añade una nueva cookie a la respuesta que se enviará +$cookies->add(new \yii\web\Cookie([ + 'name' => 'language', + 'value' => 'zh-CN', +])); + +// remueve una cookie +$cookies->remove('language'); +// equivalente a lo siguiente +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. + +> Nota: 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 + +Cuando estás leyendo y enviando cookies a través de los componentes `request` y `response` como mostramos en las dos últimas subsecciones, cuentas con el añadido de seguridad de la validación de cookies el cual protege las cookies de ser modificadas en el lado del cliente. Esto se consigue con la firma de cada cookie con una cadena hash, el cual permite a la aplicación saber si una cookie ha sido modificada en el lado del cliente o no. Si es así, la cookie no será accesible a través de [[yii\web\Request::cookies|cookie collection]] del componente `request`. + +> Información: 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. + +> Nota: Las cookies que son directamente leídas/enviadas vía `$_COOKIE` y `setcookie()` no serán validadas. + +Cuando estás usando la validación de cookie, puedes especificar una [[yii\web\Request::cookieValidationKey]] el cual se usará para generar los strings hash mencionados anteriormente. Puedes hacerlo mediante la configuración del componente `request` en la configuración de la aplicación: + +```php +return [ + 'components' => [ + 'request' => [ + 'cookieValidationKey' => 'fill in a secret key here', + ], + ], +]; +``` + +> Información: [[yii\web\Request::cookieValidationKey|cookieValidationKey]] es crítico para la seguridad de tu aplicación. + Sólo debería ser conocido por personas de confianza. No lo guardes en sistemas de control de versiones. diff --git a/docs/guide-es/start-databases.md b/docs/guide-es/start-databases.md index a9f6a28..fb9f496 100644 --- a/docs/guide-es/start-databases.md +++ b/docs/guide-es/start-databases.md @@ -18,7 +18,7 @@ En particular, deberás ser capaz de crear una base de datos y saber ejecutar co base de datos. -Preparando una Base de Datos +Preparando una Base de Datos ---------------------------- Para empezar, crea una base de datos llamada `yii2basic` de la cual tomarás los datos en la aplicación. @@ -50,7 +50,7 @@ Al final, tendrás una base de datos llamada `yii2basic`, y dentro de esta, una registros en ella. -Configurando una conexión a la Base de Datos +Configurando una conexión a la Base de Datos -------------------------------------------- Asegúrate de tener instalado la extensión de PHP [PDO](http://www.php.net/manual/es/book.pdo.php) y el driver @@ -83,7 +83,7 @@ La conexión a la base de datos realizada anteriormente puede ser accedida media Para más información, consulta la sección [Configuraciones](concept-configurations.md). -Creando un Active Record +Creando un Active Record ------------------------ Para representar y extraer datos de la tabla `country`, crea una clase [Active Record](db-active-record.md) @@ -131,7 +131,7 @@ Puedes encontrar información más detallada acerca de [Active Record](db-active puedes utilizar un método de acceso de bajo nivel llamado [Data Access Objects](db-dao.md). -Creando una Acción +Creando una Acción ------------------ Para mostrar el país a los usuarios, necesitas crear una acción. En vez de hacerlo en el controlador `site` @@ -188,7 +188,7 @@ Al final, la acción `index` renderiza una vista llamada `index` y le pasa los d de paginación relacionada. -Creando una Vista +Creando una Vista ----------------- Bajo el directorio `views`, crea primero un sub-directorio llamado `country`. Este será usado para contener @@ -220,7 +220,7 @@ El widget `LinkPager` muestra una lista de botones que representan las páginas de ellas mostrará los datos de países de la página correspondiente. -Probándolo +Probándolo ---------- Para ver cómo funciona, utiliza a la siguiente URL en tu navegador: @@ -252,7 +252,7 @@ Entre bastidores, [[yii\data\Pagination|Pagination]] está realizando su magia. siguientes cinco países para mostrar. -Resumen +Resumen ------- En esta sección has aprendido cómo trabajar con una base de datos. También has aprendido cómo traer y mostrar diff --git a/docs/guide-es/start-forms.md b/docs/guide-es/start-forms.md index 6788fc4..2516677 100644 --- a/docs/guide-es/start-forms.md +++ b/docs/guide-es/start-forms.md @@ -15,7 +15,7 @@ A través de este tutorial, aprenderás * Cómo construir un formulario HTML en una [vista](structure-views.md). -Creando un Modelo +Creando un Modelo ----------------- Para representar los datos ingresados por un usuario, crea una clase modelo `EntryForm` cómo se muestra abajo y @@ -60,7 +60,7 @@ de los datos se mostrará en la propiedad [[yii\base\Model::hasErrors|hasErrors] [[yii\base\Model::getErrors|errors]] puedes aprender cuales son los errores de validación que tiene el modelo. -Creando una Acción +Creando una Acción ------------------ Luego, crea una acción `entry` en el controlador `site`, como lo hiciste en la sección anterior. @@ -112,7 +112,7 @@ mostrada, y mostrará el formulario HTML junto con los mensajes de error de vali En el código de arriba, el componente `request` es utilizado para acceder los datos `$_POST`. -Creando Vistas +Creando Vistas -------------- Finalmente, crea dos vistas llamadas `entry-confirm` y `entry` que sean mostradas por la acción `entry`, @@ -160,7 +160,7 @@ y el segundo del dato "email". Después de los campos de input, el método [[yii es llamado para general el botón de submit (enviar). -Probándolo +Probándolo ---------- Para ver cómo funciona, utiliza tu navegador para ir al siguiente URL: @@ -182,7 +182,7 @@ mostrando los datos que acabas de ingresar. -### Magia Explicada +### Magia Explicada Te estarás preguntando cómo funciona toda esa automatización del formulario HTML, porque parece casi mágico que pueda mostrar una etiqueta para cada campo de input y mostrar los mensajes de error si no ingresas los datos correctamente @@ -208,7 +208,7 @@ el siguiente código: código de tus vistas en widgets reutilizables para simplificar el desarrollo de las vistas en un futuro. -Resumen +Resumen ------- En esta sección, has tocado cada parte del patrón de diseño MVC. Ahora has aprendido diff --git a/docs/guide-es/start-gii.md b/docs/guide-es/start-gii.md index 4a67d8e..709acc0 100644 --- a/docs/guide-es/start-gii.md +++ b/docs/guide-es/start-gii.md @@ -13,7 +13,7 @@ A lo largo de este tutorial, aprenderás * Cómo personalizar el código generado por Gii. -Comenzando con Gii +Comenzando con Gii ------------------ [Gii](tool-gii.md) está provisto por Yii en forma de [módulo](structure-modules.md). Puedes habilitar Gii @@ -47,7 +47,7 @@ http://hostname/index.php?r=gii ![Gii](images/start-gii.png) -Generando una Clase Active Record +Generando una Clase Active Record --------------------------------- Para poder generar una clase Active Record con Gii, selecciona "Model Generator" (haciendo click en el vínculo que existe en la página inicial del modulo Gii). Después, completa el formulario de la siguiente manera, @@ -71,7 +71,7 @@ Después, verás una página de confirmación indicando que el código ha sido g ha sido sobrescrito con el nuevo código generado. -Generando código de ABM (CRUD en inglés) +Generando código de ABM (CRUD en inglés) ---------------------------------------- En computación, CRUD es el acrónimo de Crear, Obtener, Actualizar y Borrar (del inglés: Create, Read, Update y Delete) @@ -90,7 +90,7 @@ Si has creado previamente los archivos `controllers/CountryController.php` y `views/country/index.php` (en la sección sobre bases de datos de esta guía), asegúrate de seleccionar el checkbox "overwrite" para reemplazarlos. (Las versiones anteriores no disponían de un soporte ABM (CRUD) completo.) -Probándolo +Probándolo ---------- Para ver cómo funciona, accede desde tu navegador a la siguiente URL: @@ -122,7 +122,7 @@ o por si desearas personalizarlos: sección [Gii](tool-gii.md). -Resumen +Resumen ------- En esta sección, has aprendido a utilizar Gii para generar el código que implementa completamente las características diff --git a/docs/guide-es/start-hello.md b/docs/guide-es/start-hello.md index 7432f2d..76ff1da 100644 --- a/docs/guide-es/start-hello.md +++ b/docs/guide-es/start-hello.md @@ -15,7 +15,7 @@ A lo largo de este tutorial, aprenderás tres cosas: 3. Cómo una aplicación envía peticiones a las [acciones](structure-controllers.md#creating-actions). -Creando una Acción +Creando una Acción ------------------ Para la tarea "Hola", crearás una [acción](structure-controllers.md#creating-actions) `say` que lee @@ -70,7 +70,7 @@ El resultado es devuelto al método de la acción. Ese resultado será recibido navegador (como parte de una página HTML completa). -Creando una Vista +Creando una Vista ----------------- Las [vistas](structure-views.md) son scripts que escribes para generar una respuesta de contenido. @@ -95,13 +95,13 @@ De hecho, la vista `say` es sólo un script PHP que es ejecutado por el método El contenido impreso por el script de la vista será regresado a la aplicación como la respuesta del resultado. La aplicación a cambio mostrará el resultado al usuario final. -Probándolo +Probándolo ---------- Después de crear la acción y la vista, puedes acceder a la nueva página abriendo el siguiente URL: ``` -http://hostname/index.php?r=site/say&mensaje=Hello+World +http://hostname/index.php?r=site/say&message=Hello+World ``` ![Hello World](images/start-hello-world.png) @@ -127,7 +127,7 @@ el método `SiteController::actionSay()` será llamado para manejar el requerimi al nombre de clase del controlador `PostComentarioController`. -Resumen +Resumen ------- En esta sección, has tocado las partes del controlador y la vista del patrón de diseño MVC. diff --git a/docs/guide-es/start-installation.md b/docs/guide-es/start-installation.md index e9f146d..beaa9cb 100644 --- a/docs/guide-es/start-installation.md +++ b/docs/guide-es/start-installation.md @@ -7,7 +7,7 @@ Es preferible usar la primera forma, ya que te permite instalar [extensiones](st > Nota: A diferencia de Yii 1, la instalación estándar de Yii 2 resulta en la descarga e instalación tanto del framework como del esqueleto de la aplicación. -Instalando a través de Composer +Instalando a través de Composer ------------------------------- Si aún no tienes Composer instalado, puedes hacerlo siguiendo las instrucciones que se encuentran en @@ -21,8 +21,12 @@ En Windows, tendrás que descargar y ejecutar [Composer-Setup.exe](https://getco Por favor, consulta la [Documentación de Composer](https://getcomposer.org/doc/) si encuentras algún problema o deseas obtener un conocimiento más profundo sobre su utilización. -Teniendo Composer instalado, puedes instalar Yii ejecutando el siguiente comando en un directorio accesible vía Web: +Si ya tienes composer instalado asegurate que esté actualizado ejecutando `composer self-update` +Teniendo Composer instalado, puedes instalar Yii ejecutando los siguientes comandos en un directorio accesible vía Web: +Nota: es posible que en al ejecutar el primer comando te pida tu username + + composer global require "fxp/composer-asset-plugin:1.0.0" composer create-project --prefer-dist yiisoft/yii2-app-basic basic El comando anterior instala Yii dentro del directorio `basic`. @@ -35,7 +39,7 @@ El comando anterior instala Yii dentro del directorio `basic`. > Ten en cuenta que la versión de desarrollo de Yii no debería ser usada para producción ya que podría romper el funcionamiento actual de la aplicación. -Instalando desde un Archivo Comprimido +Instalando desde un Archivo Comprimido -------------------------------------- Instalar Yii desde un archivo comprimido involucra dos pasos: @@ -44,7 +48,7 @@ Instalar Yii desde un archivo comprimido involucra dos pasos: 2. Descomprimirlo en un directorio accesible vía Web. -Otras Opciones de Instalación +Otras Opciones de Instalación ----------------------------- Las instrucciones anteriores muestran cómo instalar Yii, lo que también crea una aplicación Web lista para ser usada. @@ -58,7 +62,7 @@ Pero también hay otras opciones de instalación disponibles: deberías considerar instalar el [Template de Aplicación Avanzada](tutorial-advanced-app.md). -Verificando las Instalación +Verificando las Instalación --------------------------- Después de la instalación, puedes acceder a la aplicación instalada a través de la siguiente URL: @@ -88,7 +92,7 @@ También deberías instalar la [Extensión de PHP PDO](http://www.php.net/manual (como `pdo_mysql` para bases de datos MySQL), si tu aplicación lo necesitara. -Configurando Servidores Web +Configurando Servidores Web --------------------------- > Información: Puedes saltear esta sección por ahora si sólo estás probando Yii sin intención de poner la aplicación en un servidor de producción. @@ -111,7 +115,7 @@ la configuración del servidor Web, aún puedes ajustar la estructura de la apli la sección [Entorno de Hosting Compartido](tutorial-shared-hosting.md) para más detalles. -### Configuración Recomendada de Apache +### Configuración Recomendada de Apache Utiliza la siguiente configuración del archivo `httpd.conf` de Apache dentro de la configuración del virtual host. Ten en cuenta que deberás reemplazar `path/to/basic/web` con la ruta real a `basic/web`. @@ -134,7 +138,7 @@ DocumentRoot "path/to/basic/web" ``` -### Configuración Recomendada de Nginx +### Configuración Recomendada de Nginx Deberías haber instalado PHP como un [FPM SAPI](http://php.net/install.fpm) para utilizar [Nginx](http://wiki.nginx.org/). Utiliza la siguiente configuración de Nginx, reemplazando `path/to/basic/web` con la ruta real a `basic/web` y `mysite.local` con el diff --git a/docs/guide-es/start-workflow.md b/docs/guide-es/start-workflow.md index 4f1e5c4..d2c952c 100644 --- a/docs/guide-es/start-workflow.md +++ b/docs/guide-es/start-workflow.md @@ -12,7 +12,7 @@ y cómo la aplicación maneja los requests en general. Dependiendo de tus necesidades, por favor ajusta dichas URLs. -Funcionalidad +Funcionalidad ------------- La aplicación básica contiene 4 páginas: @@ -32,7 +32,7 @@ Esta es la útil [herramienta de depuración](tool-debugger.md) provista por Yii tal como los mensajes de log, response status, las consultas ejecutadas a la base de datos, y más. -Estructura de la aplicación +Estructura de la aplicación --------------------------- Los archivos y directorios más importantes en tu aplicación son (asumiendo que la raíz de la aplicación es `basic`): @@ -74,12 +74,12 @@ y la envía al resto de los elementos MVC. Los [widgets](structure-widgets.md) s para ayudar a construir elementos de interfáz complejos y dinámicos. -Ciclo de Vida de una Petición (Request) +Ciclo de Vida de una Petición (Request) --------------------------------------- El siguiente diagrama muestra cómo una aplicación maneja una petición. -![Ciclo de Vida de un Request](images/application-lifecycle.png) +![Ciclo de Vida de un Request](images/request-lifecycle.png) 1. Un usuario realiza una petición al [script de entrada](structure-entry-scripts.md) `web/index.php`. 2. El script de entrada carga la [configuración](concept-configurations.md) de la aplicación y crea diff --git a/docs/guide-es/structure-application-components.md b/docs/guide-es/structure-application-components.md index fd43963..c264587 100644 --- a/docs/guide-es/structure-application-components.md +++ b/docs/guide-es/structure-application-components.md @@ -48,7 +48,7 @@ Por ejemplo: y utilizarlo únicamente cuando sea necesario. -## Componentes del Núcleo de la Aplicación +## Componentes del Núcleo de la Aplicación Yii define un grupo de componentes del *núcleo* con IDs fijos y configuraciones por defecto. Por ejemplo, el componente [[yii\web\Application::request|request]] es utilizado para recolectar información acerca diff --git a/docs/guide-es/structure-applications.md b/docs/guide-es/structure-applications.md index 024fee8..81dc946 100644 --- a/docs/guide-es/structure-applications.md +++ b/docs/guide-es/structure-applications.md @@ -14,7 +14,7 @@ Hay dos tipos de aplicaciones: [[yii\web\Application|aplicaciones Web]] y Web requests mientras que la última maneja requests (peticiones) de la línea de comandos. -## Configuraciones de las Aplicaciones +## Configuraciones de las Aplicaciones Cuando un [script de entrada](structure-entry-scripts.md) crea una aplicación, cargará una [configuración](concept-configurations.md) y la aplicará a la aplicación, como se muestra a continuación: @@ -36,7 +36,7 @@ suelen ser complejas, son usualmente guardadas en [archivos de configuración](c como en el archivo `web.php` del ejemplo anterior. -## Propiedades de la Aplicación +## Propiedades de la Aplicación Hay muchas propiedades importantes en la aplicación que deberían configurarse en en la configuración de la aplicación. Estas propiedades suelen describir el entorno en el cual la aplicación está corriendo. @@ -44,20 +44,20 @@ Por ejemplo, las aplicaciones necesitan saber cómo cargar [controladores](struc dónde guardar archivos temporales, etc. A continuación, resumiremos esas propiedades. -### Propiedades Requeridas +### Propiedades Requeridas En cualquier aplicación, debes configurar al menos dos propiedades: [[yii\base\Application::id|id]] y [[yii\base\Application::basePath|basePath]]. -#### [[yii\base\Application::id|id]] +#### [[yii\base\Application::id|id]] La propiedad [[yii\base\Application::id|id]] especifica un ID único que diferencia una aplicación de otras. Es mayormente utilizada a nivel programación. A pesar de que no es un requerimiento, para una mejor interoperabilidad, se recomienda utilizar sólo caracteres alfanuméricos. -#### [[yii\base\Application::basePath|basePath]] +#### [[yii\base\Application::basePath|basePath]] La propiedad [[yii\base\Application::basePath|basePath]] especifica el directorio raíz de una aplicación. Es el directorio que alberga todos los archivos protegidos de un sistema. Bajo este directorio, @@ -73,13 +73,13 @@ La propiedad [[yii\base\Application::basePath|basePath]] es utilizada a menudo d Rutas derivadas pueden ser entonces creadas a partir de este alias (ej. `@app/runtime` para referirse al directorio `runtime`). -### Propiedades Importantes +### Propiedades Importantes Las propiedades descritas en esta subsección a menudo necesita ser configurada porque difieren entre las diferentes aplicaciones. -#### [[yii\base\Application::aliases|aliases]] +#### [[yii\base\Application::aliases|aliases]] Esta propiedad te permite definir un grupo de [alias](concept-aliases.md) en términos de un array (matriz). Las claves del array son los nombres de los alias, y los valores su correspondiente definición. @@ -98,7 +98,7 @@ Esta propiedad está provista de tal manera que puedas definir alias en término en vez de llamadas al método [[Yii::setAlias()]]. -#### [[yii\base\Application::bootstrap|bootstrap]] +#### [[yii\base\Application::bootstrap|bootstrap]] Esta es una propiedad importante. Te permite definir un array de los componentes que deben ejecutarse durante el [[yii\base\Application::bootstrap()|proceso de `bootstrapping`]] de la aplicación. @@ -154,7 +154,7 @@ if (YII_ENV_DEV) { por cada request, se necesita correr el mismo grupo de componentes. Por lo tanto, utiliza componentes `bootstrap` con criterio. -#### [[yii\web\Application::catchAll|catchAll]] +#### [[yii\web\Application::catchAll|catchAll]] Esta propiedad está solamente soportada por [[yii\web\Application|aplicaciones Web]]. Especifica la [acción de controlador](structure-controllers.md) que debería manejar todos los requests (peticiones) del usuario. @@ -176,7 +176,7 @@ Por ejemplo: ``` -#### [[yii\base\Application::components|components]] +#### [[yii\base\Application::components|components]] Esta es la propiedad más importante. Te permite registrar una lista de componentes llamados [componentes de aplicación](#structure-application-components.md) que puedes utilizar en otras partes de tu aplicación. Por ejemplo: @@ -204,7 +204,7 @@ la expresión `\Yii::$app->ComponentID`. Por favor, lee la sección [Componentes de la Aplicación](structure-application-components.md) para mayor detalle. -#### [[yii\base\Application::controllerMap|controllerMap]] +#### [[yii\base\Application::controllerMap|controllerMap]] Esta propiedad te permite mapear un ID de controlador a una clase de controlador arbitraria. Por defecto, Yii mapea ID de controladores a clases de controladores basado en una [convención](#controllerNamespace) (ej. el ID `post` será mapeado @@ -230,7 +230,7 @@ Las claves de este array representan los ID de los controladores, mientras que l los nombres de clase de dichos controladores o una [configuración](concept-configurations.md). -#### [[yii\base\Application::controllerNamespace|controllerNamespace]] +#### [[yii\base\Application::controllerNamespace|controllerNamespace]] Esta propiedad especifica el `namespace` bajo el cual las clases de los controladores deben ser ubicados. Por defecto es `app\controllers`. Si el ID es `post`, por convención el controlador correspondiente (sin @@ -246,7 +246,7 @@ un error "Page Not Found" ("Página no Encontrada") cuando accedas a la aplicaci En caso de que quieras romper con la convención cómo se comenta arriba, puedes configurar la propiedad [controllerMap](#controllerMap). -#### [[yii\base\Application::language|language]] +#### [[yii\base\Application::language|language]] Esta propiedad especifica el idioma en el cual la aplicación debería mostrar el contenido a los usuarios. El valor por defecto de esta propiedad es `en`, referido a English. Deberías configurar esta propiedad @@ -263,7 +263,7 @@ Por ejemplo, `en` se refiere a English, mientras que `en-US` se refiere a Englis Se pueden encontrar más detalles de este aspecto en la sección [Internacionalización](tutorial-i18n.md). -#### [[yii\base\Application::modules|modules]] +#### [[yii\base\Application::modules|modules]] Esta propiedad especifica los [módulos](structure-modules.md) que contiene la aplicación. @@ -288,7 +288,7 @@ los IDs de los módulos. Por ejemplo: Por favor consulta la sección [Módulos](structure-modules.md) para más detalles. -#### [[yii\base\Application::name|name]] +#### [[yii\base\Application::name|name]] Esta propiedad especifica el nombre de la aplicación que será mostrado a los usuarios. Al contrario de [[yii\base\Application::id|id]], que debe tomar un valor único, el valor de esta propiedad existe principalmente @@ -297,7 +297,7 @@ para propósito de visualización y no tiene porqué ser única. No siempre necesitas configurar esta propiedad si en tu aplicación no va a ser utilizada. -#### [[yii\base\Application::params|params]] +#### [[yii\base\Application::params|params]] Esta propiedad especifica un array con parámetros accesibles desde cualquier lugar de tu aplicación. En vez de usar números y cadenas fijas por todos lados en tu código, es una buena práctica definirlos como @@ -323,7 +323,7 @@ Más adelante, si decides cambiar el tamaño de las miniaturas, sólo necesitas sin necesidad de tocar el código que lo utiliza. -#### [[yii\base\Application::sourceLanguage|sourceLanguage]] +#### [[yii\base\Application::sourceLanguage|sourceLanguage]] Esta propiedad especifica el idioma en el cual la aplicación está escrita. El valor por defecto es `'en-US'`, referido a English (United States). Deberías configurar esta propiedad si el contenido de texto en tu código no está en inglés. @@ -334,7 +334,7 @@ Por ejemplo, `en` se refiere a English, mientras que `en-US` se refiere a Englis Puedes encontrar más detalles de esta propiedad en la sección [Internacionalización](tutorial-i18n.md). -#### [[yii\base\Application::timeZone|timeZone]] +#### [[yii\base\Application::timeZone|timeZone]] Esta propiedad es provista como una forma alternativa de definir el `time zone` de PHP por defecto en tiempo de ejecución. Configurando esta propiedad, escencialmente estás llamando a la función de PHP [date_default_timezone_set()](http://php.net/manual/es/function.date-default-timezone-set.php). @@ -347,25 +347,25 @@ Por ejemplo: ``` -#### [[yii\base\Application::version|version]] +#### [[yii\base\Application::version|version]] Esta propiedad especifica la versión de la aplicación. Es por defecto `'1.0'`. No hay total necesidad de configurarla si tu no la usarás en tu código. -### Propiedades Útiles +### Propiedades Útiles Las propiedades especificadas en esta sub-sección no son configuradas normalmente ya que sus valores por defecto estipulan convenciones comunes. De cualquier modo, aún puedes configurarlas en caso de que quieras romper con la convención. -#### [[yii\base\Application::charset|charset]] +#### [[yii\base\Application::charset|charset]] Esta propiedad especifica el `charset` que la aplicación utiliza. El valor por defecto es `'UTF-8'`, que debería ser mantenido tal cual para la mayoría de las aplicaciones a menos que estés trabajando con sistemas legados que utilizan muchos datos no-unicode. -#### [[yii\base\Application::defaultRoute|defaultRoute]] +#### [[yii\base\Application::defaultRoute|defaultRoute]] Esta propiedad especifica la [ruta](runtime-routing.md) que una aplicación debería utilizar si el `request` no especifica una. La ruta puede consistir el ID de un sub-módulo, el ID de un controlador, y/o el ID de una acción. @@ -381,7 +381,7 @@ Para [yii\console\Application|aplicaciones de consola], el valor por defecto es sin proveer ningún argumento, mostrará la información de ayuda. -#### [[yii\base\Application::extensions|extensions]] +#### [[yii\base\Application::extensions|extensions]] Esta propiedad especifica la lista de [extensiones](structure-extensions.md) que se encuentran instaladas y son utilizadas por la aplicación. @@ -416,7 +416,7 @@ un elemento `bootstrap` puede ser especificado con un nombre de clase o un array Una extensión también puede definir algunos [alias](concept-aliases.md). -#### [[yii\base\Application::layout|layout]] +#### [[yii\base\Application::layout|layout]] Esta propiedad especifica el valor del `layout` por defecto que será utilizado al renderizar una [vista](structure-views.md). El valor por defecto es `'main'`, y se refiere al archivo `main.php` bajo el [`layout path`](#layoutPath) definido. @@ -427,7 +427,7 @@ Puedes configurar esta propiedad con el valor `false` si quieres desactivar el ` caso muy raro. -#### [[yii\base\Application::layoutPath|layoutPath]] +#### [[yii\base\Application::layoutPath|layoutPath]] Esta propiedad especifica el lugar por defecto donde deben buscarse los archivos `layout`. El valor por defecto es el sub-directorio `layouts` bajo el [`view path`](#viewPath). Si el [`view path`](#viewPath) usa su valor por defecto, @@ -436,7 +436,7 @@ el `layout path` puede ser representado con el alias `@app/views/layouts`. Puedes configurarlo como un directorio o utilizar un [alias](concept-aliases.md). -#### [[yii\base\Application::runtimePath|runtimePath]] +#### [[yii\base\Application::runtimePath|runtimePath]] Esta propiedad especifica dónde serán guardados los archivos temporales, como archivos de log y de cache, pueden ser generados. El valor por defecto de esta propiedad es el alias `@app/runtime`. @@ -448,13 +448,13 @@ de ser accedido por usuarios finales, ya que los archivos generados pueden tener Para simplificar el acceso a este directorio, Yii trae predefinido el alias `@runtime` para él. -#### [[yii\base\Application::viewPath|viewPath]] +#### [[yii\base\Application::viewPath|viewPath]] Esta propiedad especifica dónde están ubicados los archivos de la vista. El valor por defecto de esta propiedad está representado por el alias `@app/views`. Puedes configurarlo como un directorio o utilizar un [alias](concept-aliases.md). -#### [[yii\base\Application::vendorPath|vendorPath]] +#### [[yii\base\Application::vendorPath|vendorPath]] Esta propiedad especifica el directorio `vendor` que maneja [Composer](http://getcomposer.org). Contiene todas las librerías de terceros utilizadas por tu aplicación, incluyendo el núcleo de Yii. Su valor por defecto @@ -466,14 +466,14 @@ asegúrate de ajustar la configuración de Composer en concordancia. Para simplificar el acceso a esta ruta, Yii trae predefinido el alias `@vendor`. -#### [[yii\console\Application::enableCoreCommands|enableCoreCommands]] +#### [[yii\console\Application::enableCoreCommands|enableCoreCommands]] Esta propiedad está sólo soportada por [[yii\console\Application|aplicaciones de consola]]. Especifica si los comandos de consola incluidos en Yii deberían estar habilitados o no. Por defecto está definido como `true`. -## Eventos de la Aplicación +## Eventos de la Aplicación Una aplicación dispara varios eventos durante su ciclo de vida al manejar un `request`. Puedes conectar manejadores a dichos eventos en la configuración de la aplicación como se muestra a continuación: @@ -497,7 +497,7 @@ después de que la instancia de la aplicación es creada. Por ejemplo: }); ``` -### [[yii\base\Application::EVENT_BEFORE_REQUEST|EVENT_BEFORE_REQUEST]] +### [[yii\base\Application::EVENT_BEFORE_REQUEST|EVENT_BEFORE_REQUEST]] Este evento es disparado *before* (antes) de que la aplicación maneje el `request`. El nombre del evento es `beforeRequest`. @@ -507,7 +507,7 @@ Por ejemplo, en el manejador del evento, podrías definir dinámicamente la prop basada en algunos parámetros. -### [[yii\base\Application::EVENT_BEFORE_REQUEST|EVENT_AFTER_REQUEST]] +### [[yii\base\Application::EVENT_BEFORE_REQUEST|EVENT_AFTER_REQUEST]] Este evento es disparado *after* (después) de que una aplicación finaliza el manejo de un `request` pero *before* (antes) de enviar el `response` (respuesta). El nombre del evento es `afterRequest`. @@ -519,7 +519,7 @@ Ten en cuenta que el componente [[yii\web\Response|response]] también dispara a a los usuarios finales. Estos eventos son disparados *after* (después) de este evento. -### [[yii\base\Application::EVENT_BEFORE_REQUEST|EVENT_BEFORE_ACTION]] +### [[yii\base\Application::EVENT_BEFORE_REQUEST|EVENT_BEFORE_ACTION]] Este evento es disparado *before* (antes) de ejecutar cualquier [acción de controlador](structure-controllers.md). El nombre de este evento es `beforeAction`. @@ -545,7 +545,7 @@ seguidos por módulos (si los hubiera), y finalmente controladores. Si un maneja como `false`, todos los eventos siguientes NO serán disparados. -### [[yii\base\Application::EVENT_BEFORE_REQUEST|EVENT_AFTER_ACTION]] +### [[yii\base\Application::EVENT_BEFORE_REQUEST|EVENT_AFTER_ACTION]] Este evento es disparado *after* (después) de ejecutar cualquier [acción de controlador](structure-controllers.md). El nombre de este evento es `afterAction`. @@ -571,7 +571,7 @@ que los de `beforeAction`. Esto quiere decir que los controladores son los prime seguido por módulos (si los hubiera), y finalmente aplicaciones. -## Ciclo de Vida de una Aplicación +## Ciclo de Vida de una Aplicación Cuando un [script de entrada](structure-entry-scripts.md) está siendo ejecutado para manejar un `request`, una aplicación experimenta el siguiente ciclo de vida: diff --git a/docs/guide-es/structure-assets.md b/docs/guide-es/structure-assets.md new file mode 100644 index 0000000..8f3ea95 --- /dev/null +++ b/docs/guide-es/structure-assets.md @@ -0,0 +1,645 @@ +Assets +====== + +Un asset en Yii es un archivo al que se puede hacer referencia en una página Web. Puede ser un archivo CSS, un archivo +JavaScript, una imagen o un archivo de video, etc. Los assets se encuentran en los directorios públicos de la web y se +sirven directamente por los servidores Web. + +A menudo es preferible gestionar los assets mediante programación. Por ejemplo, cuando se usa el widget +[[yii\jui\DatePicker]] en una página, éste incluirá automáticamente los archivos CSS y JavaScript requeridos, en vez +de tener que buscar los archivos e incluirlos manualmente. Y cuando se actualice el widget a una nueva versión, ésta +usará de forma automática la nueva versión de los archivos asset. +En este tutorial, se describirá la poderosa capacidad que proporciona la gestión de assets en Yii. + +## Asset Bundles + +Yii gestiona los assets en unidades de *asset bundle*. Un asset bundle es simplemente un conjunto de assets +localizados en un directorio. Cuando se registra un asset bundle en una [vista](structure-views.md), éste incluirá los +archivos CSS y JavaScript del bundle en la página Web renderizada. + +## Definición de Asset Bundles + +Los asset bundles son descritos como clases PHP que extienden a [[yii\web\AssetBundle]]. El nombre del bundle es +simplemente su correspondiente nombre de la classe PHP que debe ser [autocargable](concept-autoloading.md). En una +clase asset bundle, lo más habitual es especificar donde se encuentran los archivos asset, que archivos CSS y +JavaScript contiene el bundle, y como depende este bundle de otros bundles. + +El siguiente código define el asset bundle principal que se usa en +[la plantilla de aplicación básica](start-installation.md): + +```php + + +Según la localización de los assets, se pueden clasificar como: + +* assets fuente (source assets): los assets se encuentran junto con el código fuente PHP, al que no se puede acceder + directamente a través de la Web. Para usar los assets fuente en una página, deben ser copiados en un directorio + público y transformados en los llamados assets publicados. El proceso se llama *publicación de assets* que será + descrito a continuación. +* assets publicados (published assets): los archivos assets se encuentran en el directorio Web y son accesibles vía Web. +* assets externos (external assets): los archivos assets se encuentran en un servidor Web diferente al de la aplicación. + +Cuando se define una clase asset bundle, si se especifica la propiedad [[yii\web\AssetBundle::sourcePath|sourcePath]], +significa que cualquier asset listado que use rutas relativas será considerado como un asset fuente. Si no se +especifica la propiedad, significa que los assets son assets publicados (se deben especificar +[[yii\web\AssetBundle::basePath|basePath]] y +[[yii\web\AssetBundle::baseUrl|baseUrl]] para hacerle saber a Yii dónde se encuentran.) + +Se recomienda ubicar los assets que correspondan a la aplicación en un directorio Web para evitar publicaciones de +assets innecesarias. Por esto en el anterior ejemplo `AppAsset` especifica [[yii\web\AssetBundle::basePath|basePath]] +en vez de [[yii\web\AssetBundle::sourcePath|sourcePath]]. + +Para las [extensiones](structure-extensions.md), por el hecho de que sus assets se encuentran junto con el código +fuente, en directorios que no son accesibles para la Web, se tiene que especificar la propiedad +[[yii\web\AssetBundle::sourcePath|sourcePath]] cuando se definan clases asset bundle para ellas. + +> Nota: No se debe usar `@webroot/assets` como [yii\web\AssetBundle::sourcePath|source path]]. Este directorio se usa + por defecto por el [[yii\web\AssetManager|asset manager]] para guardar los archivos asset publicados temporalmente y + pueden ser eliminados. + +### Dependencias de los Asset + +Cuando se incluyen múltiples archivos CSS o JavaScript en una página Web, tienen que cumplir ciertas órdenes para +evitar problemas de sobrescritura. Por ejemplo, si se usa un widget jQuery UI en una página Web, tenemos que +asegurarnos de que el archivo JavaScript jQuery se incluya antes que el archivo JavaScript jQuery UI. A esto se le +llama ordenar las dependencias entre archivos. + +Las dependencias de los assets se especifican principalmente a través de la propiedad [[yii\AssetBundle::depends]]. +En el ejemplo `AppAsset`, el asset bundle depende de otros dos asset bundles [[yii\web\YiiAsset]] y +[[yii\bootstrap\BootstrapAsset]], que significa que los archivos CSS y JavaScript en `AppAsset` se incluirán *después* +que los archivos de los dos bundles dependientes. + +Las dependencias son transitivas. Esto significa, que si un bundle A depende de un bundle B que depende de C, A +dependerá de C, también. + +### Opciones de los Assets + +Se pueden especificar las propiedades [[yii\web\AssetBundle::cssOptions|cssOptions]] y +[[yii\web\AssetBundle::jsOptions|jsOptions]] para personalizar la forma en que los archivos CSS y JavaScript serán +incluidos en una página. Los valores de estas propiedades serán enviadas a los métodos +[[yii\web\View::registerCssFile()]] y [[yii\web\View::registerJsFile()]], respectivamente cuando las +[vistas](structure-views.md) los llamen para incluir los archivos CSS y JavaScript. + +> Nota: Las opciones que se especifican en una clase bundle se aplican a *todos* los archivos CSS/JavaScript de un + bundle. Si se quiere usar diferentes opciones para diferentes archivos, se deben crear assets bundles separados y + usar un conjunto de opciones para cada bundle. + +Por ejemplo, para incluir una archivo CSS condicionalmente para navegadores que como IE9 o anteriores, se puede usar la + siguiente opción: + +```php +public $cssOptions = ['condition' => 'lte IE9']; +``` + +Esto provoca que un archivo CSS dentro de un bundle sea incluido usando los siguientes tags HTML: + +```html + +``` + +Para envolver el tag del enlace con `