Commit f5e5ffa3 by Agrumas

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

parents c5a564f0 4e5079ab
......@@ -5,11 +5,11 @@ Thank you for choosing Yii 2 - a modern PHP framework designed for professional
Yii 2 is a complete rewrite of its previous version Yii 1.1 which is one of the most popular PHP frameworks.
Yii 2 inherits the main spirit behind Yii for being simple, fast and highly extensible.
Yii 2 requires PHP 5.4 and embraces best practices and protocols found in modern Web application development.
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 early 2014.
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.
......@@ -28,15 +28,17 @@ which is the latest stable release of Yii.
DIRECTORY STRUCTURE
-------------------
apps/ ready-to-use application templates
```
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
build/ internally used build tools
docs/ documentation
extensions/ extensions
framework/ core framework code
tests/ tests of the core framework code
```
REQUIREMENTS
......@@ -48,13 +50,12 @@ The minimum requirement by Yii is that your Web server supports PHP 5.4.
DOCUMENTATION
-------------
A draft of the [Definitive Guide](docs/guide/index.md) is available.
A draft of the [Definitive Guide](docs/guide/README.md) is available.
API docs and a rendering of the definitive guide are currently
available at http://stuff.cebe.cc/yii2docs/ (updated four times per hour).
We will make guide and API docs available on yiiframework.com with the beta release.
available at http://stuff.cebe.cc/yii2docs/ (updated four times per hour) and at http://www.yiiframework.com/doc-2.0/guide-index.html.
For 1.1 users, you may refer to [Upgrading from Yii 1.1](docs/guide/upgrade-from-v1.md)
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.
......
......@@ -29,26 +29,6 @@ class User extends ActiveRecord implements IdentityInterface
const ROLE_USER = 10;
/**
* Creates a new user
*
* @param array $attributes the attributes given by field => value
* @return static|null the newly created model, or null on failure
*/
public static function create($attributes)
{
/** @var User $user */
$user = new static();
$user->setAttributes($attributes);
$user->setPassword($attributes['password']);
$user->generateAuthKey();
if ($user->save()) {
return $user;
} else {
return null;
}
}
/**
* @inheritdoc
*/
public function behaviors()
......@@ -67,6 +47,20 @@ class User extends ActiveRecord implements IdentityInterface
/**
* @inheritdoc
*/
public function rules()
{
return [
['status', 'default', 'value' => self::STATUS_ACTIVE],
['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]],
['role', 'default', 'value' => self::ROLE_USER],
['role', 'in', 'range' => [self::ROLE_USER]],
];
}
/**
* @inheritdoc
*/
public static function findIdentity($id)
{
return static::findOne($id);
......@@ -181,28 +175,4 @@ class User extends ActiveRecord implements IdentityInterface
{
$this->password_reset_token = null;
}
/**
* @inheritdoc
*/
public function rules()
{
return [
['status', 'default', 'value' => self::STATUS_ACTIVE],
['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]],
['role', 'default', 'value' => self::ROLE_USER],
['role', 'in', 'range' => [self::ROLE_USER]],
['username', 'filter', 'filter' => 'trim'],
['username', 'required'],
['username', 'unique'],
['username', 'string', 'min' => 2, 'max' => 255],
['email', 'filter', 'filter' => 'trim'],
['email', 'required'],
['email', 'email'],
['email', 'unique'],
];
}
}
......@@ -43,9 +43,6 @@
"backend/runtime",
"backend/web/assets",
"console/runtime",
"console/migrations",
"frontend/runtime",
"frontend/web/assets"
]
......
......@@ -20,7 +20,10 @@ return [
'Development' => [
'path' => 'dev',
'writable' => [
// handled by composer.json already
'backend/runtime',
'backend/web/assets',
'frontend/runtime',
'frontend/web/assets',
],
'executable' => [
'yii',
......@@ -29,7 +32,10 @@ return [
'Production' => [
'path' => 'prod',
'writable' => [
// handled by composer.json already
'backend/runtime',
'backend/web/assets',
'frontend/runtime',
'frontend/web/assets',
],
'executable' => [
'yii',
......
......@@ -120,8 +120,7 @@ class SiteController extends Controller
{
$model = new SignupForm();
if ($model->load(Yii::$app->request->post())) {
$user = $model->signup();
if ($user) {
if ($user = $model->signup()) {
if (Yii::$app->getUser()->login($user)) {
return $this->goHome();
}
......
......@@ -43,7 +43,13 @@ class SignupForm extends Model
public function signup()
{
if ($this->validate()) {
return User::create($this->attributes);
$user = new User();
$user->username = $this->username;
$user->email = $this->email;
$user->setPassword($this->password);
$user->generateAuthKey();
$user->save();
return $user;
}
return null;
......
......@@ -5,7 +5,7 @@
*
* In order to run in non-interactive mode:
*
* init --env=dev --overwrite=n
* init --env=Development --overwrite=n
*
* @author Alexander Makarov <sam@rmcreative.ru>
*
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\build\controllers;
use Yii;
use yii\base\InvalidParamException;
use yii\console\Controller;
use yii\helpers\Console;
use yii\helpers\FileHelper;
/**
* AppController will link the yii2 dev installation to the containted applications vendor dirs
* to help working on yii using the application to test it.
*
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
class AppController extends Controller
{
public $defaultAction = 'link';
/**
* 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");
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");
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");
}
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;
}
}
......@@ -22,13 +22,13 @@ use yii\helpers\FileHelper;
class PhpDocController extends Controller
{
public $defaultAction = 'property';
/**
* @var boolean whether to update class docs directly. Setting this to false will just output docs
* for copy and paste.
*/
public $updateFiles = true;
/**
* Generates `@property` annotations in class files from getters and setters
*
......@@ -125,6 +125,7 @@ class PhpDocController extends Controller
'/build/',
'/docs/',
'/extensions/apidoc/helpers/PrettyPrinter.php',
'/extensions/apidoc/helpers/ApiIndexer.php',
'/extensions/codeception/TestCase.php',
'/extensions/codeception/DbTestCase.php',
'/extensions/composer/',
......@@ -133,6 +134,7 @@ class PhpDocController extends Controller
'/extensions/twig/TwigSimpleFileLoader.php',
'/framework/BaseYii.php',
'/framework/Yii.php',
'assets/',
'tests/',
'vendor/',
];
......@@ -414,11 +416,11 @@ class PhpDocController extends Controller
$gets = $this->match(
'#\* @return (?<type>[\w\\|\\\\\\[\\]]+)(?: (?<comment>(?:(?!\*/|\* @).)+?)(?:(?!\*/).)+|[\s\n]*)\*/' .
'[\s\n]{2,}public function (?<kind>get)(?<name>\w+)\((?:,? ?\$\w+ ?= ?[^,]+)*\)#',
$class['content']);
$class['content'], true);
$sets = $this->match(
'#\* @param (?<type>[\w\\|\\\\\\[\\]]+) \$\w+(?: (?<comment>(?:(?!\*/|\* @).)+?)(?:(?!\*/).)+|[\s\n]*)\*/' .
'[\s\n]{2,}public function (?<kind>set)(?<name>\w+)\(\$\w+(?:, ?\$\w+ ?= ?[^,]+)*\)#',
$class['content']);
$class['content'], true);
// check for @property annotations in getter and setter
$properties = $this->match(
'#\* @(?<kind>property) (?<type>[\w\\|\\\\\\[\\]]+)(?: (?<comment>(?:(?!\*/|\* @).)+?)(?:(?!\*/).)+|[\s\n]*)\*/' .
......@@ -498,15 +500,24 @@ class PhpDocController extends Controller
return [$className, $phpdoc];
}
protected function match($pattern, $subject)
protected function match($pattern, $subject, $split = false)
{
$sets = [];
preg_match_all($pattern . 'suU', $subject, $sets, PREG_SET_ORDER);
foreach ($sets as &$set)
// split subject by double newlines because regex sometimes has problems with matching
// in the complete set of methods
// example: yii\di\ServiceLocator setComponents() is not recognized in the whole but in
// a part of the class.
$parts = $split ? explode("\n\n", $subject) : [$subject];
foreach($parts as $part) {
preg_match_all($pattern . 'suU', $part, $matches, PREG_SET_ORDER);
foreach ($matches as &$set) {
foreach ($set as $i => $match)
if (is_numeric($i) /*&& $i != 0*/)
unset($set[$i]);
$sets[] = $set;
}
}
return $sets;
}
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\build\controllers;
use DirectoryIterator;
use Yii;
use yii\console\Controller;
use yii\helpers\Html;
/**
* TranslationController handles tasks related to framework translations.
*
* build translation ../docs/guide" "../docs/guide_ru" --title="Russian guide translation report" > report_guide_ru.html
*
* @author Alexander Makarov <sam@rmcreative.ru>
*/
class TranslationController extends Controller
{
public $defaultAction = 'report';
/**
* Creates a report about documentation updates since last update of same named translations.
*
* @param string $sourcePath the directory where the original documentation files are
* @param string $translationPath the directory where the translated documentation files are
* @param string $title custom title to use for report
* @return string
*/
public function actionReport($sourcePath, $translationPath, $title = 'Translation report')
{
$sourcePath = trim($sourcePath, '/\\');
$translationPath = trim($translationPath, '/\\');
$results = [];
$dir = new DirectoryIterator($sourcePath);
foreach ($dir as $fileinfo) {
/** @var DirectoryIterator $fileinfo */
if (!$fileinfo->isDot() && !$fileinfo->isDir()) {
$translatedFilePath = $translationPath . '/' . $fileinfo->getFilename();
$sourceFilePath = $sourcePath . '/' . $fileinfo->getFilename();
$errors = $this->checkFiles($translatedFilePath);
$diff = empty($errors) ? $this->getDiff($translatedFilePath, $sourceFilePath) : '';
if(!empty($diff)) {
$errors[] = 'Translation outdated.';
}
$result = [
'errors' => $errors,
'diff' => $diff,
];
$results[$fileinfo->getFilename()] = $result;
}
}
// checking if there are obsolete translation files
$dir = new DirectoryIterator($translationPath);
foreach ($dir as $fileinfo) {
/** @var \DirectoryIterator $fileinfo */
if (!$fileinfo->isDot() && !$fileinfo->isDir()) {
$translatedFilePath = $translationPath . '/' . $fileinfo->getFilename();
$errors = $this->checkFiles(null, $translatedFilePath);
if(!empty($errors)) {
$results[$fileinfo->getFilename()]['errors'] = $errors;
}
}
}
echo $this->renderFile(__DIR__ . '/views/translation/report_html.php', [
'results' => $results,
'sourcePath' => $sourcePath,
'translationPath' => $translationPath,
'title' => $title,
]);
}
/**
* Checks for files existence
*
* @param string $translatedFilePath
* @param string $sourceFilePath
* @return array errors
*/
protected function checkFiles($translatedFilePath = null, $sourceFilePath = null)
{
$errors = [];
if ($translatedFilePath !== null && !file_exists($translatedFilePath)) {
$errors[] = 'Translation does not exist.';
}
if ($sourceFilePath !== null && !file_exists($sourceFilePath)) {
$errors[] = 'Source does not exist.';
}
return $errors;
}
/**
* Getting DIFF from git
*
* @param string $translatedFilePath path pointing to translated file
* @param string $sourceFilePath path pointing to original file
* @return string DIFF
*/
protected function getDiff($translatedFilePath, $sourceFilePath)
{
$lastTranslationHash = shell_exec('git log -1 --format=format:"%H" -- ' . $translatedFilePath);
return shell_exec('git diff ' . $lastTranslationHash.'..HEAD -- ' . $sourceFilePath);
}
/**
* Adds all necessary HTML tags and classes to diff output
*
* @param string $diff DIFF
* @return string highlighted DIFF
*/
protected function highlightDiff($diff)
{
$lines = explode("\n", $diff);
foreach ($lines as $key => $val) {
if (mb_substr($val, 0, 1, 'utf-8') === '@') {
$lines[$key] = '<span class="info">' . Html::encode($val) . '</span>';
}
else if (mb_substr($val, 0, 1, 'utf-8') === '+') {
$lines[$key] = '<ins>' . Html::encode($val) . '</ins>';
}
else if (mb_substr($val, 0, 1, 'utf-8') === '-') {
$lines[$key] = '<del>' . Html::encode($val) . '</del>';
}
else {
$lines[$key] = Html::encode($val);
}
}
return implode("\n", $lines);
}
}
<?php
use yii\helpers\Html;
?><!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Translation report</title>
<style>
.diff ins {
background: #cfc;
text-decoration: none;
}
.diff del {
background: #ffe6cc;
text-decoration: none;
}
.ok {
color: #99cc32;
}
.errors {
color: #cc5129;
}
</style>
</head>
<body>
<h1><?php echo Html::encode($title)?></h1>
<ul>
<li><strong>Source:</strong> <?php echo Html::encode($sourcePath)?></li>
<li><strong>Translation:</strong> <?php echo Html::encode($translationPath)?></li>
</ul>
<?php foreach($results as $name => $result):?>
<h2 class="<?php echo empty($result['errors']) ? 'ok' : 'errors'?>"><?php echo $name?></h2>
<?php foreach($result['errors'] as $error):?>
<p><?php echo Html::encode($error)?></p>
<?php endforeach ?>
<?php if(!empty($result['diff'])):?>
<code class="diff"><pre><?php echo $this->highlightDiff($result['diff'])?></pre></code>
<?php endif?>
<?php endforeach ?>
</body>
</html>
\ No newline at end of file
This folder contains official Yii 2 guides documentation.
The Definitive Guide to Yii 2.0
===============================
To add new guide, take the following steps:
This tutorial is released under the [Terms of Yii Documentation](http://www.yiiframework.com/doc/terms/).
All Rights Reserved.
2014 (c) Yii Software LLC.
Introduction
------------
* [About Yii](intro-yii.md)
* [Upgrading from Version 1.1](intro-upgrade-from-v1.md)
Getting Started
---------------
* [Preparing Your Environment](start-environment.md)
* [Creating Your First Yii Application](start-basic.md)
* [Application Structure](start-structure.md)
* [Request Lifecycle](start-lifecycle.md)
* **TBD** [Next Steps](start-next-steps.md)
Application Structure
---------------------
* **TBD** [Entry Scripts](structure-entry-scripts.md)
* **TBD** [Applications](structure-applications.md)
* [Controllers and Actions](structure-controllers.md)
* [Views](structure-views.md)
* [Models](structure-models.md)
* **TBD** [Widgets](structure-widgets.md)
* **TBD** [Modules](structure-modules.md)
* **TBD** [Extensions](structure-extensions.md)
Handling Requests
-----------------
* **TBD** [Bootstrapping](runtime-bootstrapping.md)
* **TBD** [Routing](runtime-routing.md)
* **TBD** [Requests](runtime-requests.md)
* **TBD** [Responses](runtime-responses.md)
* **TBD** [Sessions and Cookies](runtime-sessions-cookies.md)
* [URL Parsing and Generation](runtime-url-handling.md)
* **TBD** [Filtering](runtime-filtering.md)
Key Concepts
------------
* [Components](concept-components.md)
* [Properties](concept-properties.md)
* [Events](concept-events.md)
* [Behaviors](concept-behaviors.md)
* [Configurations](concept-configurations.md)
* [Aliases](concept-aliases.md)
* [Class Autoloading](concept-autoloading.md)
* [Service Locator](concept-service-locator.md)
* [Dependency Injection Container](concept-di-container.md)
Working with Databases
----------------------
* [Data Access Objects](db-dao.md) - Connecting to a database, basic queries, transactions and schema manipulation
* [Query Builder](db-query-builder.md) - Querying the database using a simple abstraction layer
* [Active Record](db-active-record.md) - The active record ORM, retrieving and manipulating records and defining relations
* [Migrations](db-migrations.md) - Version control your databases in a team development environment
* **TBD** [Sphinx](db-sphinx.md)
* **TBD** [Redis](db-redis.md)
* **TBD** [MongoDB](db-mongodb.md)
* **TBD** [ElasticSearch](db-elastic-search.md)
Getting User Inputs
-------------------
* [Creating Forms](input-forms.md)
* [Input Validation](input-validation.md)
* **TBD** [Uploading Files](input-file-uploading.md)
* **TBD** [Inputs for Multiple Models](input-multiple-models.md)
Presenting Data
---------------
* **TBD** [Data Formatting](output-formatting.md)
* **TBD** [Pagination](output-pagination.md)
* **TBD** [Sorting](output-sorting.md)
* [Data Providers](output-data-providers.md)
* [Data Widgets](output-data-widgets.md)
* [Managing Assets](output-assets.md)
Security
--------
* [Authentication](security-authentication.md)
* [Authorization](security-authorization.md)
* [Working with Passwords](security-passwords.md)
* **TBD** [Auth Clients](security-auth-clients.md)
* **TBD** [Best Practices](security-best-practices.md)
Caching
-------
* [Overview](caching-overview.md)
* **TBD** [Data Caching](caching-data.md)
* **TBD** [Fragment and Page Caching](caching-fragment.md)
* **TBD** [HTTP Caching](caching-http.md)
RESTful Web Services
--------------------
* [Quick Start](rest-quick-start.md)
* **TBD** [Resources](rest-resources.md)
* **TBD** [Routing](rest-routing.md)
* **TBD** [Data Formatting](rest-data-formatting.md)
* **TBD** [Authentication](rest-authentication.md)
* **TBD** [Rate Limiting](rest-rate-limiting.md)
* **TBD** [Versioning](rest-versioning.md)
* **TBD** [Caching](rest-caching.md)
* **TBD** [Error Handling](rest-error-handling.md)
* **TBD** [Testing](rest-testing.md)
Development Tools
-----------------
* [Debug Toolbar and Debugger](tool-debugger.md)
* [Generating Code using Gii](tool-gii.md)
* **TBD** [Generating API Documentation](tool-api-doc.md)
Testing
-------
* [Overview](test-overview.md)
* **TBD** [Unit Tests](test-unit.md)
* **TBD** [Functional Tests](test-functional.md)
* **TBD** [Acceptance Tests](test-acceptance.md)
* [Fixtures](test-fixtures.md)
Extending Yii
-------------
* [Creating Extensions](extend-creating-extensions.md)
* [Customizing Core Code](extend-customizing-core.md)
* [Using 3rd-Party Libraries](extend-using-libs.md)
* **TBD** [Using Yii in 3rd-Party Systems](extend-embedding-in-others.md)
* **TBD** [Using Yii 1.1 and 2.0 Together](extend-using-v1-v2.md)
* [Using Composer](extend-using-composer.md)
Special Topics
--------------
* [Advanced Application Template](tutorial-advanced-app.md)
* [Building Application from Scratch](tutorial-start-from-scratch.md)
* [Console Commands](tutorial-console.md)
* [Handling Errors](tutorial-handling-errors.md)
* [Internationalization](tutorial-i18n.md)
* [Logging](tutorial-logging.md)
* **TBD** [Mailing](tutorial-mailing.md)
* [Performance Tuning](tutorial-performance-tuning.md)
* [Template Engines](tutorial-template-engines.md)
* [Theming](tutorial-theming.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)
* **TBD** [Jquery UI Widgets](jui-widgets.md)
Helpers
-------
* [Overview](helper-overview.md)
* **TBD** [ArrayHelper](helper-array.md)
* **TBD** [Html](helper-html.md)
* **TBD** [Url](helper-url.md)
* **TBD** [Security](helper-security.md)
1. Create `guide-name` and put there relevant documentation;
2. If guide has more then one word in name, then it should be with dashes, like: `console-fixture.md`, `module-debug.md`;
3. If your guide is about console commands, than its name should follow convention: `console-{command}.md`;
4. If your guide is about module usages, than its name should follow convention: `module-{moduleName}.md`.
5. If your guide is about widget usages, than its name should follow convention: `widget-{moduleName}.md`.
Basic concepts of Yii
=====================
Component and Object
--------------------
Classes of the Yii framework usually extend from one of the two base classes [[yii\base\Object]] or [[yii\base\Component]].
These classes provide useful features that are added automatically to all classes extending from them.
The [[yii\base\Object|Object]] class provides the [configuration and property feature](../api/base/Object.md).
The [[yii\base\Component|Component]] class extends from [[yii\base\Object|Object]] and adds
[event handling](events.md) and [behaviors](behaviors.md).
[[yii\base\Object|Object]] is usually used for classes that represent basic data structures while
[[yii\base\Component|Component]] is used for application components and other classes that implement higher logic.
Object Configuration
--------------------
The [[yii\base\Object|Object]] class introduces a uniform way of configuring objects. Any descendant class
of [[yii\base\Object|Object]] should declare its constructor (if needed) in the following way so that
it can be properly configured:
```php
class MyClass extends \yii\base\Object
{
public function __construct($param1, $param2, $config = [])
{
// ... initialization before configuration is applied
parent::__construct($config);
}
public function init()
{
parent::init();
// ... initialization after configuration is applied
}
}
```
In the above example, the last parameter of the constructor must take a configuration array
which contains name-value pairs that will be used to initialize the object's properties at the end of the constructor.
You can override the `init()` method to do initialization work after the configuration is applied.
By following this convention, you will be able to create and configure new objects
using a configuration array like the following:
```php
$object = Yii::createObject([
'class' => 'MyClass',
'property1' => 'abc',
'property2' => 'cde',
], [$param1, $param2]);
```
Path Aliases
------------
Yii 2.0 expands the usage of path aliases to both file/directory paths and URLs. An alias
must start with an `@` symbol so that it can be differentiated from file/directory paths and URLs.
For example, the alias `@yii` refers to the Yii installation directory while `@web` contains the base URL for the currently running web application. Path aliases are supported in most places in the Yii core code. For example, `FileCache::cachePath` can accept both a path alias and a normal directory path.
Path aliases are also closely related to class namespaces. It is recommended that a path
alias should be defined for each root namespace so that Yii's class autoloader can be used without
any further configuration. For example, because `@yii` refers to the Yii installation directory,
a class like `yii\web\Request` can be autoloaded by Yii. If you use a third party library
such as Zend Framework, you may define a path alias `@Zend` which refers to its installation
directory and Yii will be able to autoload any class in this library.
The following aliases are predefined by the core framework:
- `@yii` - framework directory.
- `@app` - base path of currently running application.
- `@runtime` - runtime directory.
- `@vendor` - Composer vendor directory.
- `@webroot` - web root directory of currently running web application.
- `@web` - base URL of currently running web application.
Autoloading
-----------
All classes, interfaces and traits are loaded automatically at the moment they are used. There's no need to use `include` or `require`. It is true for Composer-loaded packages as well as Yii extensions.
Yii's autoloader works according to [PSR-4](https://github.com/php-fig/fig-standards/blob/master/proposed/psr-4-autoloader/psr-4-autoloader.md).
That means namespaces, classes, interfaces and traits must correspond to file system paths and file names accordinly, except for root namespace paths that are defined by an alias.
For example, if the standard alias `@app` refers to `/var/www/example.com/` then `\app\models\User` will be loaded from `/var/www/example.com/models/User.php`.
Custom aliases may be added using the following code:
```php
Yii::setAlias('@shared', realpath('~/src/shared'));
```
Additional autoloaders may be registered using PHP's standard `spl_autoload_register`.
Helper classes
--------------
Helper classes typically contain static methods only and are used as follows:
```php
use \yii\helpers\Html;
echo Html::encode('Test > test');
```
There are several classes provided by framework:
- ArrayHelper
- Console
- FileHelper
- Html
- HtmlPurifier
- Image
- Inflector
- Json
- Markdown
- Security
- StringHelper
- Url
- VarDumper
Behaviors
=========
A behavior (also knows as *mixin*) can be used to enhance the functionality of an existing component without modifying the component's
code. In particular, a behavior can "inject" its public methods and properties into the component, making them directly accessible
via the component itself. A behavior can also respond to events triggered in the component, thus intercepting the normal
code execution. Unlike [PHP's traits](http://www.php.net/traits), behaviors can be attached to classes at runtime.
Using behaviors
---------------
A behavior can be attached to any class that extends from [[yii\base\Component]] either from code or via application
config.
### Attaching behaviors via `behaviors` method
In order to attach a behavior to a class you can implement the `behaviors` method of the component.
As an example, Yii provides the [[yii\behaviors\TimestampBehavior]] behavior for automatically updating timestamp
fields when saving an [[yii\db\ActiveRecord|Active Record]] model:
```php
use yii\behaviors\TimestampBehavior;
class User extends ActiveRecord
{
// ...
public function behaviors()
{
return [
'timestamp' => [
'class' => TimestampBehavior::className(),
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => ['created_at', 'updated_at'],
ActiveRecord::EVENT_BEFORE_UPDATE => 'updated_at',
],
],
];
}
}
```
In the above, the name `timestamp` can be used to reference the behavior through the component. For example, `$user->timestamp`
gives the attached timestamp behavior instance. The corresponding array is the configuration used to create the
[[yii\behaviors\TimestampBehavior|TimestampBehavior]] object.
Besides responding to the insertion and update events of ActiveRecord, `TimestampBehavior` also provides a method `touch()`
that can assign the current timestamp to a specified attribute. As aforementioned, you can access this method directly
through the component, like the following:
```php
$user->touch('login_time');
```
If you do not need to access a behavior object, or the behavior does not need customization, you can also
use the following simplified format when specifying the behavior,
```php
use yii\behaviors\TimestampBehavior;
class User extends ActiveRecord
{
// ...
public function behaviors()
{
return [
TimestampBehavior::className(),
// or the following if you want to access the behavior object
// 'timestamp' => TimestampBehavior::className(),
];
}
}
```
### Attaching behaviors dynamically
Another way to attach a behavior to a component is calling `attachBehavior` method like the followig:
```php
$component = new MyComponent();
$component->attachBehavior();
```
### Attaching behaviors from config
One can attach a behavior to a component when configuring it with a configuration array. The syntax is like the
following:
```php
return [
// ...
'components' => [
'myComponent' => [
// ...
'as tree' => [
'class' => 'Tree',
'root' => 0,
],
],
],
];
```
In the config above `as tree` stands for attaching a behavior named `tree`, and the array will be passed to [[\Yii::createObject()]]
to create the behavior object.
Creating your own behaviors
---------------------------
To create your own behavior, you must define a class that extends [[yii\base\Behavior]].
```php
namespace app\components;
use yii\base\Behavior;
class MyBehavior extends Behavior
{
}
```
To make it customizable, like [[yii\behaviors\TimestampBehavior]], add public properties:
```php
namespace app\components;
use yii\base\Behavior;
class MyBehavior extends Behavior
{
public $attr;
}
```
Now, when the behavior is used, you can set the attribute to which you'd want the behavior to be applied:
```php
namespace app\models;
use yii\db\ActiveRecord;
class User extends ActiveRecord
{
// ...
public function behaviors()
{
return [
'mybehavior' => [
'class' => 'app\components\MyBehavior',
'attr' => 'member_type'
],
];
}
}
```
Behaviors are normally written to take action when certain events occur. Below we're implementing `events` method
to assign event handlers:
```php
namespace app\components;
use yii\base\Behavior;
use yii\db\ActiveRecord;
class MyBehavior extends Behavior
{
public $attr;
public function events()
{
return [
ActiveRecord::EVENT_BEFORE_INSERT => 'beforeInsert',
ActiveRecord::EVENT_BEFORE_UPDATE => 'beforeUpdate',
];
}
public function beforeInsert() {
$model = $this->owner;
// Use $model->$attr
}
public function beforeUpdate() {
$model = $this->owner;
// Use $model->$attr
}
}
```
Bootstrap widgets
Bootstrap Widgets
=================
Out of the box, Yii includes support for the [Bootstrap 3](http://getbootstrap.com/) markup and components framework (also known as "Twitter Bootstrap"). Bootstrap is an excellent, responsive framework that can greatly speed up the client-side of your development process.
> Note: This chapter is under development.
Out of the box, Yii includes support for the [Bootstrap 3](http://getbootstrap.com/) markup and components framework
(also known as "Twitter Bootstrap"). Bootstrap is an excellent, responsive framework that can greatly speed up the
client-side of your development process.
The core of Bootstrap is represented by two parts:
......
Caching
=======
> Note: This chapter is under development.
Caching is a cheap and effective way to improve the performance of a web application. By storing relatively
static data in cache and serving it from cache when requested, the application saves the time required to generate the data from scratch. Caching is one of the best ways to improve the performance of your application, almost mandatory on any large-scale site.
......
Aliases
=======
Aliases are used to represent file paths or URLs to avoid hard-coding absolute paths or URLs in your code.
An alias must start with a `@` character so that it can be differentiated from file paths and URLs.
For example, the alias `@yii` represents the installation path of the Yii framework, while `@web` represents
the base URL for the currently running Web application.
<a name="defining-aliases"></a>
Defining Aliases
----------------
You can call [[Yii::setAlias()]] to define an alias for a given file path or URL. For example,
```php
// an alias of file path
Yii::setAlias('@foo', '/path/to/foo');
// an alias of URL
Yii::setAlias('@bar', 'http://www.example.com');
```
> Note: A file path or URL being aliased may NOT necessarily refer to an existing file or resource.
Given an alias, you may derive a new alias (without the need of calling [[Yii::setAlias()]]) by appending
a slash `/` followed with one or several path segments. We call the aliases defined via [[Yii::setAlias()]]
*root aliases*, while the aliases derived from them *derived aliases*. For example, `@foo` is a root alias,
while `@foo/bar/file.php` is a derived alias.
You can define an alias using another alias (either root alias or derived alias is fine):
```php
Yii::setAlias('@foobar', '@foo/bar');
```
Root aliases are usually defined during the [bootstrapping](runtime-bootstrapping.md) stage.
For example, you may call [[Yii::setAlias()]] in the [entry script](structure-entry-scripts.md).
For convenience, [Application](structure-applications.md) provides a writable property named `aliases`
that you can configure in the application [configuration](concept-configurations.md), like the following,
```php
return [
// ...
'aliases' => [
'@foo' => '/path/to/foo',
'@bar' => 'http://www.example.com',
],
];
```
<a name="resolving-aliases"></a>
Resolving Aliases
-----------------
You can call [[Yii::getAlias()]] to resolve a root alias into the file path or URL it is representing.
The same method can also resolve a derived alias into the corresponding file path or URL. For example,
```php
echo Yii::getAlias('@foo'); // displays: /path/to/foo
echo Yii::getAlias('@bar'); // displays: http://www.example.com
echo Yii::getAlias('@foo/bar/file.php'); // displays: /path/to/foo/bar/file.php
```
The path/URL represented by a derived alias is determined by replacing the root alias part with its corresponding
path/URL in the derived alias.
> Note: The [[Yii::getAlias()]] method does not check whether the resulting path/URL refers to an existing file or resource.
A root alias may also contain slash `/` characters. The [[Yii::getAlias()]] method
is intelligent enough to tell which part of an alias is a root alias and thus correctly determines
the corresponding file path or URL. For example,
```php
Yii::setAlias('@foo', '/path/to/foo');
Yii::setAlias('@foo/bar', '/path2/bar');
Yii::getAlias('@foo/test/file.php'); // displays: /path/to/foo/test/file.php
Yii::getAlias('@foo/bar/file.php'); // displays: /path2/bar/file.php
```
If `@foo/bar` is not defined as a root alias, the last statement would display `/path/to/foo/bar/file.php`.
<a name="using-aliases"></a>
Using Aliases
-------------
Aliases are recognized in many places in Yii without the need of calling [[Yii::getAlias()]] to convert
them into paths/URLs. For example, [[yii\caching\FileCache::cachePath]] can accept both a file path
and an alias representing a file path, thanks to the `@` prefix which allows it to differentiate a file path
from an alias.
```php
use yii\caching\FileCache;
$cache = new FileCache([
'cachePath' => '@runtime/cache',
]);
```
Please pay attention to the API documentation to see if a property or method parameter supports aliases.
<a name="predefined-aliases"></a>
Predefined Aliases
------------------
Yii predefines a set of aliases to ease the need of referencing commonly used file paths and URLs.
The following is the list of the predefined aliases:
- `@yii`: the directory where the `BaseYii.php` file is located (also called the framework directory).
- `@app`: the [[yii\base\Application::basePath|base path]] of the currently running application.
- `@runtime`: the [[yii\base\Application::runtimePath|runtime path]] of the currently running application.
- `@vendor`: the Composer vendor directory.
- `@webroot`: the Web root directory of the currently running Web application.
- `@web`: the base URL of the currently running Web application.
The `@yii` alias is defined when you include the `Yii.php` file in your [entry script](structure-entry-scripts.md),
while the rest of the aliases are defined in the application constructor when applying the application
[configuration](concept-configurations.md).
<a name="extension-aliases"></a>
Extension Aliases
-----------------
An alias is automatically defined for each [extension](structure-extensions.md) that is installed via Composer.
The alias is named after the root namespace of the extension as declared in its `composer.json` file, and it
represents the root directory of the package. For example, if you install the `yiisoft/yii2-jui` extension,
you will automatically have the alias `@yii/jui` defined during the [bootstrapping](runtime-bootstrapping.md) stage:
```php
Yii::setAlias('@yii/jui', 'VendorPath/yiisoft/yii2-jui');
```
Class Autoloading
=================
Yii relies on the [class autoloading mechanism](http://www.php.net/manual/en/language.oop5.autoload.php)
to locate and include required class files. It provides a high-performance class autoloader that is compliant to the
[PSR-4 standard](https://github.com/php-fig/fig-standards/blob/master/proposed/psr-4-autoloader/psr-4-autoloader.md).
The autoloader is installed when you include the `Yii.php` file.
> Note: For simplicity of description, in this chapter we will only talk about autoloading of classes. However, keep in
mind that the content we are describing here applies to autoloading of interfaces and traits as well.
<a name="using-yii-autoloader"></a>
Using the Yii Autoloader
------------------------
To make use of the Yii class autoloader, you should follow two simple rules when creating and naming your classes:
* Each class must be under some namespace (e.g. `foo\bar\MyClass`).
* Each class must be saved in an individual file whose path is determined by the following algorithm:
```php
// $className is a fully qualified class name with the leading backslash
$classFile = Yii::getAlias('@' . str_replace('\\', '/', $className) . '.php');
```
For example, if a class name is `foo\bar\MyClass`, the [alias](concept-aliases.md) for the corresponding class file path
would be `@foo/bar/MyClass.php`. In order for this alias to be able to be resolved into a file path,
either `@foo` or `@foo/bar` must be a [root alias](concept-aliases.md#defining-aliases).
When you are using the [Basic Application Template](start-basic.md), you may put your classes under the top-level
namespace `app` so that they can be autoloaded by Yii without the need of defining a new alias. This is because
`@app` is a [predefined alias](concept-aliases.md#predefined-aliases), and a class name like `app\components\MyClass`
can be resolved into the class file `AppBasePath/components/MyClass.php`, according to the algorithm we just described.
In the [Advanced Application Template](tutorial-advanced-app.md), each tier has its own root alias. For example,
the front-end tier has a root alias `@frontend` while the back-end tier `@backend`. As a result, you may
put the front-end classes under the namespace `frontend` while the back-end classes under `backend`. This will
allow these classes to be autoloaded by the Yii autoloader.
<a name="class-map"></a>
Class Map
---------
The Yii class autoloader supports the *class map* feature which maps class names to the corresponding class file paths.
When the autoloader is loading a class, it will first check if the class is found in the map. If so, the corresponding
file path will be included directly without further check. This makes class autoloading super fast. In fact,
all core Yii classes are being autoloaded this way.
You may add a class to the class map `Yii::$classMap` as follows,
```php
Yii::$classMap['foo\bar\MyClass'] = 'path/to/MyClass.php';
```
[Aliases](concept-aliases.md) can be used to specify class file paths. You should set the class map in the
[bootstrapping](runtime-bootstrapping.md) process so that the map is ready before your classes are used.
<a name="using-other-autoloaders"></a>
Using Other Autoloaders
-----------------------
Because Yii embraces Composer as a package dependency manager, it is recommended that you also install
the Composer autoloader. If you are using some 3rd-party libraries that have their autoloaders, you should
also install them.
When you are using the Yii autoloader together with other autoloaders, you should include the `Yii.php` file
*after* all other autoloaders are installed. This will make the Yii autoloader to be the first one responding to
any class autoloading request. For example, the following code is extracted from
the [entry script](structure-entry-scripts.md) of the [Basic Application Template](start-basic.md). The first
line installs the Composer autoloader, while the second line installs the Yii autoloader.
```php
require(__DIR__ . '/../vendor/autoload.php');
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
```
You may use the Composer autoloader alone without the Yii autoloader. However, by doing so, the performance
of your class autoloading may be degraded, and you must follow the rules set by Composer in order for your classes
to be autoloadable.
> Info: If you do not want to use the Yii autoloader, you must create your own version of the `Yii.php` file
and include it in your [entry script](structure-entry-scripts.md).
<a name="autoloading-extension-classes"></a>
Autoloading Extension Classes
-----------------------------
The Yii autoloader is capable of autoloading [extension](structure-extensions.md) classes. The sole requirement
is that an extension specifies the `autoload` section correctly in its `composer.json` file. Please refer to the
[Composer documentation](https://getcomposer.org/doc/04-schema.md#autoload) for more details about specifying `autoload`.
In case you do not use the Yii autoloader, the Composer autoloader can still autoload extension classes for you.
Components
==========
Components are the main building blocks in Yii applications. Components are instances of [[yii\base\Component]]
or it child class. They support features such as [properties](concept-properties.md), [events](concept-events.md) and
[behaviors](concept-behaviors.md), which makes them more customizable and easier to use. For example, you may use
the included [[yii\jui\DatePicker|date picker widget]], a user interface component, in a [view](structure-view.md)
to generate an interactive date picker:
```php
use yii\jui\DatePicker;
echo DatePicker::widget([
'language' => 'ru',
'name' => 'country',
'clientOptions' => [
'dateFormat' => 'yy-mm-dd',
],
]);
```
While components are very powerful, they are a bit heavier compared to normal objects, due to the fact that
it takes extra memory and CPU time in order to support [events](concept-events.md) and [behaviors](concept-behaviors.md).
If your components do not need these two features, you may consider extending your component class from
[[yii\base\Object]] instead of [[yii\base\Component]], which will make your components as efficient as normal objects,
but with the extra support for [properties](concept-properties.md).
When extending your class from [[yii\base\Component]] or [[yii\base\Object]], it is recommended that you follow
these conventions:
- If you override the constructor, specify a `$config` parameter as its *last* parameter and pass this parameter
to the parent constructor.
- Call parent constructor at the end of the constructor.
- If you override the [[yii\base\Object::init()]] method, make sure you call the parent implementation.
For example,
```php
namespace yii\components\MyClass;
use yii\base\Object;
class MyClass extends Object
{
public $prop1;
public $prop2;
public function __construct($param1, $param2, $config = [])
{
// ... initialization before configuration is applied
parent::__construct($config);
}
public function init()
{
parent::init();
// ... initialization after configuration is applied
}
}
```
This will make your components [configurable](concept-configurations.md) when they are being created. For example,
```php
$component = new MyClass(1, 2, ['prop1' => 3, 'prop2' => 4]);
// alternatively
$component = \Yii::createObject([
'class' => MyClass::className(),
'prop1' => 3,
'prop2' => 4,
], [1, 2]);
```
> Info: While the call of [[Yii::createObject()]] looks more complicated, it is more powerful due to
the fact that it is implemented on top of a [dependency injection container](concept-di-container.md).
The [[yii\base\Object]] class enforces the following object lifecycle:
1. Pre-initialization within constructor. You can set default property values here.
2. Configuring object with `$config`. The configuration may overwrite the default values set above.
3. Post-initialization within [[yii\base\Object::init()|init()]]. You may override this method
and do sanity check and normalization of the properties.
4. Object method calls.
The first three steps all happen within the object constructor. This means, once you get an object instance,
it has already been initialized to a proper state that you can work on.
Service Locator and Dependency Injection
========================================
Dependency Injection Container
==============================
Both service locator and dependency injection are popular design patterns that allow building software
in a loosely-coupled fashion. Yii uses service locator and dependency injection extensively,
......@@ -8,90 +8,6 @@ and support to help you write code more consciously. We also highly recommend yo
[Martin's article](http://martinfowler.com/articles/injection.html) to get a deeper understanding of
service locator and dependency injection.
Service Locator
---------------
A service locator is an object that knows how to provide all sorts of services (or components) that an application
might need. Within a service locator, each component has only a single instance which is uniquely identified by an ID.
You use the ID to retrieve a component from the service locator. In Yii, a service locator is simply an instance
of [[yii\di\ServiceLocator]] or its child class.
The most commonly used service locator in Yii is the *application* object which can be accessed through
`\Yii::$app`. The services it provides are called *application components*, such as `request`, `response`,
`urlManager`. You may configure these components or replace them with your own implementations easily
through functionality provided the service locator.
Besides the application object, each module object is also a service locator.
To use a service locator, the first step is to register components. A component can be registered
via [[yii\di\ServiceLocator::set()]]. The following code shows different ways of registering components:
```php
$locator = new \yii\di\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 "db" using an anonymous function that builds a component
$locator->set('search', function () {
return new app\components\SolrService;
});
```
Once a component is registered, you can access it using its ID in one of the following two ways:
```php
$cache = $locator->get('cache');
// or alternatively
$cache = $locator->cache;
```
As shown above, [[yii\di\ServiceLocator]] allows you to access a component like a property using the component ID.
When you access a component for the first time, [[yii\di\ServiceLocator]] will use the component registration
information to create a new instance of the component and return it. Later if the component is accessed again,
the service locator will return the same instance.
You may use [[yii\di\ServiceLocator::has()]] to check if a component ID has already been registered.
If you call [[yii\di\ServiceLocator::get()]] with an invalid ID, an exception will be thrown.
Because service locators are often being configured using configuration arrays, a method named
[[yii\di\ServiceLocator::setComponents()]] is provided to allow registering components in configuration arrays.
The method is a setter which defines a writable property `components` that can be configured.
The following code shows a configuration array that can be used to configure an application and register
the "db", "cache" and "search" components:
```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;
},
],
];
```
Dependency Injection
--------------------
A dependency injection (DI) container is an object that knows how to instantiate and configure objects and
all their dependent objects. [Martin's article](http://martinfowler.com/articles/injection.html) has well
explained why DI container is useful. Here we will mainly explain the usage of the DI container provided by Yii.
......
Properties
==========
In PHP, class member variables are also called *properties*. They are part of a class definition and are used
to represent the state of a class instance. In practice, you may often want to do some special handling when
a property is being read or modified. For example, you may want to trim a string when it is being assigned
to a `label` property. You could use the following code to achieve this task:
```php
$object->label = trim($label);
```
The drawback of the above code is that you have to call `trim()` everywhere whenever you modify the `label`
property. And if in future, the `label` property has a new requirement, such as the first letter must be turned
into upper case, you would have to modify all those places - a practice you want to avoid as much as possible.
To solve this problem, Yii introduces a base class called [[yii\base\Object]] to support defining properties
based on *getter* and *setter* class methods. If a class needs such a support, it should extend from
[[yii\base\Object]] or its child class.
> Info: Nearly every core class in the Yii framework extends from [[yii\base\Object]] or its child class.
This means whenever you see a getter or setter in a core class, you can use it like a property.
A getter method is a method whose name starts with the word `get`, while a setter method starts with `set`.
The name after the `get` or `set` prefix defines the name of a property. For example, a getter `getLabel()` and/or
a setter `setLabel()` defines a property named `label`, as shown in the following code:
```php
namespace app\components;
use yii\base\Object;
class Foo extend Object
{
private $_label;
public function getLabel()
{
return $this->_label;
}
public function setLabel($value)
{
$this->_label = trim($value);
}
}
```
Properties defined by getters/setters can be used like class member variables. The main difference is that
when such a property is being read, the corresponding getter method will be called; and when the property is
being assigned, the corresponding setter method will be called. For example,
```php
// equivalent to $label = $object->getLabel();
$label = $object->label;
// equivalent to $object->setLabel('abc');
$object->label = 'abc';
```
A property defined by a getter without a setter is *read only*. Trying to assign a value to such a property will cause
an [[yii\base\InvalidCallException|InvalidCallException]]. Similarly, a property defined by a setter without a getter
is *write only*, and trying to read such a property will also cause an exception. It is not common to have write-only
properties.
There are several special rules or limitations of the properties defined based on getters and setters.
* The names of such properties are *case-insensitive*. For example, `$object->label` and `$object->Label` are the same.
This is because PHP method names are case-insensitive.
* If the name of such a property is the same as a class member variable, the latter will take precedence.
For example, if the above `Foo` class has a member variable `label`, then the assignment `$object->label = 'abc'`
will happen to the member variable instead of the setter `setLabel()`.
* The properties do not support visibility. It makes no difference for the visibility of a property
if the defining getter or setter method is public, protected or private.
* The properties can only be defined by *non-static* getters and/or setters. Static methods do not count.
Back to the problem we described at the very beginning, instead of calling `trim()` everywhere, we are calling it
only within the setter `setLabel()`. And if a new requirement comes that the first letter of the label should
be turned into upper case, we just need to modify the `setLabel()` method without touching any other code.
Service Locator
===============
> Note: This chapter needs cleanup.
Both service locator and dependency injection are popular design patterns that allow building software
in a loosely-coupled fashion. Yii uses service locator and dependency injection extensively,
even though you may not be aware of them. In this tutorial, we will explore their implementation
and support to help you write code more consciously. We also highly recommend you to read
[Martin's article](http://martinfowler.com/articles/injection.html) to get a deeper understanding of
service locator and dependency injection.
A service locator is an object that knows how to provide all sorts of services (or components) that an application
might need. Within a service locator, each component has only a single instance which is uniquely identified by an ID.
You use the ID to retrieve a component from the service locator. In Yii, a service locator is simply an instance
of [[yii\di\ServiceLocator]] or its child class.
The most commonly used service locator in Yii is the *application* object which can be accessed through
`\Yii::$app`. The services it provides are called *application components*, such as `request`, `response`,
`urlManager`. You may configure these components or replace them with your own implementations easily
through functionality provided the service locator.
Besides the application object, each module object is also a service locator.
To use a service locator, the first step is to register components. A component can be registered
via [[yii\di\ServiceLocator::set()]]. The following code shows different ways of registering components:
```php
$locator = new \yii\di\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 "db" using an anonymous function that builds a component
$locator->set('search', function () {
return new app\components\SolrService;
});
```
Once a component is registered, you can access it using its ID in one of the following two ways:
```php
$cache = $locator->get('cache');
// or alternatively
$cache = $locator->cache;
```
As shown above, [[yii\di\ServiceLocator]] allows you to access a component like a property using the component ID.
When you access a component for the first time, [[yii\di\ServiceLocator]] will use the component registration
information to create a new instance of the component and return it. Later if the component is accessed again,
the service locator will return the same instance.
You may use [[yii\di\ServiceLocator::has()]] to check if a component ID has already been registered.
If you call [[yii\di\ServiceLocator::get()]] with an invalid ID, an exception will be thrown.
Because service locators are often being configured using configuration arrays, a method named
[[yii\di\ServiceLocator::setComponents()]] is provided to allow registering components in configuration arrays.
The method is a setter which defines a writable property `components` that can be configured.
The following code shows a configuration array that can be used to configure an application and register
the "db", "cache" and "search" components:
```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;
},
],
];
```
Configuration
=============
Yii applications rely upon components to perform most of the common tasks, such as connecting to a database, routing browser
requests, and handling sessions. How these stock components behave can be adjusted by *configuring* your Yii application.
The majority of components have sensible default settings, so it's unlikely that you'll do a lot of configuration. Still, there are some mandatory configuration settings that you will have to establish, such as the database connection.
How an application is configured depends upon the application template in use, but there are some general principles that apply in every Yii case.
Configuring options in the bootstrap file
-----------------------------------------
For each application in Yii there is at least one bootstrap file: a PHP script through which all requests are handled. For web applications, the bootstrap file is typically `index.php`; for
console applications, the bootstrap file is `yii`. Both bootstrap files perform nearly the same job:
1. Setting common constants.
2. Including the Yii framework itself.
3. Including [Composer autoloader](http://getcomposer.org/doc/01-basic-usage.md#autoloading).
4. Reading the configuration file into `$config`.
5. Creating a new application instance, configured via `$config`, and running that instance.
Like any resource in your Yii application, the bootstrap file can be edited to fit your needs. A typical change is to the value of `YII_DEBUG`. This constant should be `true` during development, but always `false` on production sites.
The default bootstrap structure sets `YII_DEBUG` to `false` if not defined:
```php
defined('YII_DEBUG') or define('YII_DEBUG', false);
```
During development, you can change this to `true`:
```php
define('YII_DEBUG', true); // Development only
defined('YII_DEBUG') or define('YII_DEBUG', false);
```
Configuring the application instance
------------------------------------
An application instance is configured when it's created in the bootstrap file. The configuration is typically
stored in a PHP file stored in the `/config` application directory. The file has this structure to begin:
```php
<?php
return [
'id' => 'applicationId',
'basePath' => dirname(__DIR__),
'components' => [
// configuration of application components goes here...
],
'params' => require(__DIR__ . '/params.php'),
];
```
The configuration is a large array of key-value pairs. In the above, the array keys are the names of application properties. Depending upon the application type, you can configure the properties of
either [[yii\web\Application]] or [[yii\console\Application]] classes. Both classes extend [[yii\base\Application]].
Note that you can configure not only public class properties, but any property accessible via a setter. For example, to
configure the runtime path, you can use a key named `runtimePath`. There's no such property in the application class, but
since the class has a corresponding setter named `setRuntimePath`, `runtimePath` becomes configurable.
The ability to configure properties via setters is available to any class that extends from [[yii\base\Object]], which is nearly every class in the Yii framework.
Configuring application components
----------------------------------
The majority of the Yii functionality comes from application components. These components are attached to the application instance via the instance's `components` property:
```php
<?php
return [
'id' => 'applicationId',
'basePath' => dirname(__DIR__),
'components' => [
'cache' => ['class' => 'yii\caching\FileCache'],
'user' => ['identityClass' => 'app\models\User'],
'errorHandler' => ['errorAction' => 'site/error'],
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
],
],
],
],
// ...
];
```
In the above code, four components are configured: `cache`, `user`, `errorHandler`, `log`. Each entry's key is a component ID. The values are subarrays used to configure that component. The component ID is also used to access the component anywhere within the application, using code like `\Yii::$app->myComponent`.
The configuration array has one special key named `class` that identifies the component's base class. The rest of the keys and values are used
to configure component properties in the same way as top-level keys are used to configure the application's properties.
Each application has a predefined set of components. To configure one of these, the `class` key can be omitted to use the default Yii class for that component. You can check the `coreComponents()` method of the application you are using
to get a list of component IDs and corresponding classes.
Note that Yii is smart enough to only configure the component when it's actually being used: for example, if you configure the `cache` component in your configuration file but never use the `cache` component in your code, no instance of that component will be created and no time is wasted configuring it.
Setting component defaults class-wide
------------------------------------
For each component you can specify class-wide defaults. For example, if you want to change the class used for all `LinkPager`
widgets without specifying the class for every widget usage, you can do the following:
```php
\Yii::$container->set('yii\widgets\LinkPager', [
'options' => [
'class' => 'pagination',
],
]);
```
The code above should be executed once before `LinkPager` widget is used. It can be done in `index.php`, the application
configuration file, or anywhere else.
Managing Fixtures
=================
// todo: this tutorial may be merged into test-fixture.md
Fixtures are important part of testing. Their main purpose is to populate you with data that needed by testing
different cases. With this data using your tests becoming more efficient and useful.
Yii supports fixtures via the `yii fixture` command line tool. This tool supports:
* Loading fixtures to different storage such as: RDBMS, NoSQL, etc;
* Unloading fixtures in different ways (usually it is clearing storage);
* Auto-generating fixtures and populating it with random data.
Fixtures format
---------------
Fixtures are objects with different methods and configurations, refer to official [documentation](https://github.com/yiisoft/yii2/blob/master/docs/guide/test-fixture.md) on them.
Lets assume we have fixtures data to load:
```
#users.php file under fixtures data path, by default @tests\unit\fixtures\data
return [
[
'name' => 'Chase',
'login' => 'lmayert',
'email' => 'strosin.vernice@jerde.com',
'auth_key' => 'K3nF70it7tzNsHddEiq0BZ0i-OU8S3xV',
'password' => '$2y$13$WSyE5hHsG1rWN2jV8LRHzubilrCLI5Ev/iK0r3jRuwQEs2ldRu.a2',
],
[
'name' => 'Celestine',
'login' => 'napoleon69',
'email' => 'aileen.barton@heaneyschumm.com',
'auth_key' => 'dZlXsVnIDgIzFgX4EduAqkEPuphhOh9q',
'password' => '$2y$13$kkgpvJ8lnjKo8RuoR30ay.RjDf15bMcHIF7Vz1zz/6viYG5xJExU6',
],
];
```
If we are using fixture that loads data into database then these rows will be applied to `users` table. If we are using nosql fixtures, for example `mongodb`
fixture, then this data will be applied to `users` mongodb collection. In order to learn about implementing various loading strategies and more, refer to official [documentation](https://github.com/yiisoft/yii2/blob/master/docs/guide/test-fixture.md).
Above fixture example was auto-generated by `yii2-faker` extension, read more about it in these [section](#auto-generating-fixtures).
Fixture classes name should not be plural.
Loading fixtures
----------------
Fixture classes should be suffixed by `Fixture` class. By default fixtures will be searched under `tests\unit\fixtures` namespace, you can
change this behavior with config or command options.
To load fixture, run the following command:
```
yii fixture/load <fixture_name>
```
The required `fixture_name` parameter specifies a fixture name which data will be loaded. You can load several fixtures at once.
Below are correct formats of this command:
```
// load `users` fixture
yii fixture/load User
// same as above, because default action of "fixture" command is "load"
yii fixture User
// load several fixtures. Note that there should not be any whitespace between ",", it should be one string.
yii fixture User,UserProfile
// load all fixtures
yii fixture/load all
// same as above
yii fixture all
// load fixtures, but for other database connection.
yii fixture User --db='customDbConnectionId'
// load fixtures, but search them in different namespace. By default namespace is: tests\unit\fixtures.
yii fixture User --namespace='alias\my\custom\namespace'
// load global fixture `some\name\space\CustomFixture` before other fixtures will be loaded.
// By default this option is set to `InitDbFixture` to disable/enable integrity checks. You can specify several
// global fixtures separated by comma.
yii fixture User --globalFixtures='some\name\space\Custom'
```
Unloading fixtures
------------------
To unload fixture, run the following command:
```
// unload Users fixture, by default it will clear fixture storage (for example "users" table, or "users" collection if this is mongodb fixture).
yii fixture/unload User
// Unload several fixtures. Note that there should not be any whitespace between ",", it should be one string.
yii fixture/unload User,UserProfile
// unload all fixtures
yii fixture/unload all
```
Same command options like: `db`, `namespace`, `globalFixtures` also can be applied to this command.
Configure Command Globally
--------------------------
While command line options allow us to configure the migration command
on-the-fly, sometimes we may want to configure the command once for all. For example you can configure
different migration path as follows:
```
'controllerMap' => [
'fixture' => [
'class' => 'yii\console\controllers\FixtureController',
'db' => 'customDbConnectionId',
'namespace' => 'myalias\some\custom\namespace',
'globalFixtures' => [
'some\name\space\Foo',
'other\name\space\Bar'
],
],
]
```
Auto-generating fixtures
------------------------
Yii also can auto-generate fixtures for you based on some template. You can generate your fixtures with different data on different languages and formats.
These feature is done by [Faker](https://github.com/fzaninotto/Faker) library and `yii2-faker` extension.
See extension [guide](https://github.com/yiisoft/yii2/tree/master/extensions/faker) for more docs.
Data Sources and Widgets
========================
One of the most powerful features of Yii is how it works with data. In Yii, you may easily output data directly in view files, which is a good approach
for the Web site's frontend. But when it comes to backend data components and widgets, Yii's ability to access data is a real timesaver.
Typically, you would take the following steps when working with one of these data components:
1. Configure the [data provider](data-providers.md). It may get its data from an array, an SQL command, an ActiveRecord query, etc.
2. Pass the data provider to a widget, such as a [list view](data-widgets.md#listview) or [grid view](data-grid.md).
3. Customize the widget to reflect the presentational style that you are after.
That's it. After doing these simple steps you will have a powerful interfaces, such as a full featured data grid that supports pagination, sorting, and
filtering, ideal for the admin part of your project.
Data widgets
============
GridView
--------
The [[yii\grid\GridView]] widget is a powerful tool to create a data grid that provides pagination, sorting
and filtering of the data out of the box. See the [data grid section](data-grid.md) for more details.
ListView
--------
DetailView
----------
DetailView displays the detail of a single data [[yii\widgets\DetailView::$model|model]].
It is best used for displaying a model in a regular format (e.g. each model attribute is displayed as a row in a table).
The model can be either an instance of [[\yii\base\Model]] or an associative array.
DetailView uses the [[yii\widgets\DetailView::$attributes]] property to determines which model attributes should be displayed and how they
should be formatted.
A typical usage of DetailView is as follows:
```php
echo DetailView::widget([
'model' => $model,
'attributes' => [
'title', // title attribute (in plain text)
'description:html', // description attribute in HTML
[ // the owner name of the model
'label' => 'Owner',
'value' => $model->owner->name,
],
],
]);
```
Active Record
=============
> Note: This chapter is under development.
[Active Record](http://en.wikipedia.org/wiki/Active_record_pattern) provides an object-oriented interface
for accessing data stored in a database. An Active Record class is associated with a database table,
an Active Record instance corresponds to a row of that table, and an attribute of an Active Record
......@@ -95,7 +97,7 @@ Connecting to Database
----------------------
Active Record uses a [[yii\db\Connection|DB connection]] to exchange data with database. By default,
it uses the `db` application component as the connection. As explained in [Database basics](database-basics.md),
it uses the `db` application component as the connection. As explained in [Database basics](db-dao.md),
you may configure the `db` component in the application configuration file like follows,
```php
......@@ -209,7 +211,7 @@ $customers = Customer::find()
### Retrieving Data in Batches
In [Query Builder](query-builder.md), we have explained that you may use *batch query* to keep your memory
In [Query Builder](db-query-builder.md), we have explained that you may use *batch query* to keep your memory
usage under a limit when querying a large amount of data from database. You may use the same technique
in Active Record. For example,
......@@ -267,6 +269,9 @@ $customer->save(); // equivalent to $customer->update();
$customer = Customer::findOne($id);
$customer->delete();
// to delete several customers
Customer::deleteAll('age > :age AND gender = :gender', [':age' => 20, ':gender' => 'M']);
// to increment the age of ALL customers by 1
Customer::updateAllCounters(['age' => 1]);
```
......@@ -281,7 +286,7 @@ Customer::updateAllCounters(['age' => 1]);
### Data Input and Validation
Because Active Record extends from [[yii\base\Model]], it supports the same data input and validation features
as described in [Model](model.md). For example, you may declare validation rules by overwriting the
as described in [Model](structure-models.md). For example, you may declare validation rules by overwriting the
[[yii\base\Model::rules()|rules()]] method; you may massively assign user input data to an Active Record instance;
and you may call [[yii\base\Model::validate()|validate()]] to trigger data validation.
......@@ -326,7 +331,7 @@ Active Record Life Cycles
It is important to understand the life cycles of Active Record when it is used to manipulate data in database.
These life cycles are typically associated with corresponding events which allow you to inject code
to intercept or respond to these events. They are especially useful for developing Active Record [behaviors](behaviors.md).
to intercept or respond to these events. They are especially useful for developing Active Record [behaviors](concept-behaviors.md).
When instantiating a new Active Record instance, we will have the following life cycles:
......@@ -1048,5 +1053,5 @@ TODO
See also
--------
- [Model](model.md)
- [Model](structure-models.md)
- [[yii\db\ActiveRecord]]
Database basics
===============
> Note: This chapter is under development.
Yii has a database access layer built on top of PHP's [PDO](http://www.php.net/manual/en/book.pdo.php). It provides
uniform API and solves some inconsistencies between different DBMS. By default Yii supports the following DBMS:
......
Database Migration
==================
> Note: This chapter is under development.
Like source code, the structure of a database evolves as a database-driven application is developed and maintained. For example, during development, a new table may be added; Or, after the application goes live, it may be discovered that an additional index is required. It is important to keep track of these structural database changes (called **migration**), just as changes to the source code is tracked using version control. If the source code and the database become out of sync, bugs will occur, or the whole application might break. For this reason, Yii provides a database migration
tool that can keep track of database migration history, apply new migrations, or revert existing ones.
......@@ -107,6 +109,10 @@ See documentation of [[yii\db\QueryBuilder::getColumnType()]] for more details a
of available types. You may also use the constants defined in [[yii\db\Schema]] to
define column types.
> Note: You can add constraints and other custom table options at the end of the table description by
> specifying them as simple string. For example in the above migration, after `content` attribute definition
> you can write `'CONSTRAINT ...'` or other custom options.
Transactional Migrations
------------------------
......
Query Builder and Query
=======================
> Note: This chapter is under development.
Yii provides a basic database access layer as described in the [Database basics](database-basics.md) section.
The database access layer provides a low-level way to interact with the database. While useful in some situations,
it can be tedious and error-prone to write raw SQLs. An alternative approach is to use the Query Builder.
......@@ -109,7 +111,7 @@ When the tables are specified as an array, you may also use the array keys as th
(if a table does not need alias, do not use a string key). For example,
```php
$query->select('u.*, p.*')->from(['u' => 'user u', 'p' => 'post']);
$query->select('u.*, p.*')->from(['u' => 'user', 'p' => 'post']);
```
You may specify a sub-query using a `Query` object. In this case, the corresponding array key will be used
......@@ -195,12 +197,16 @@ Operator can be one of the following:
it will be converted into a string using the rules described here. For example,
`['and', 'type=1', ['or', 'id=1', 'id=2']]` will generate `type=1 AND (id=1 OR id=2)`.
The method will NOT do any quoting or escaping.
- `or`: similar to the `and` operator except that the operands are concatenated using `OR`.
- `between`: operand 1 should be the column name, and operand 2 and 3 should be the
starting and ending values of the range that the column is in.
For example, `['between', 'id', 1, 10]` will generate `id BETWEEN 1 AND 10`.
- `not between`: similar to `between` except the `BETWEEN` is replaced with `NOT BETWEEN`
in the generated condition.
- `in`: operand 1 should be a column or DB expression. Operand 2 can be either an array or a `Query` object.
It will generate an `IN` condition. If Operand 2 is an array, it will represent the range of the values
that the column or DB expression should be; If Operand 2 is a `Query` object, a sub-query will be generated
......@@ -209,7 +215,9 @@ Operator can be one of the following:
The method will properly quote the column name and escape values in the range.
The `in` operator also supports composite columns. In this case, operand 1 should be an array of the columns,
while operand 2 should be an array of arrays or a `Query` object representing the range of the columns.
- `not in`: similar to the `in` operator except that `IN` is replaced with `NOT IN` in the generated condition.
- `like`: operand 1 should be a column or DB expression, and operand 2 be a string or an array representing
the values that the column or DB expression should be like.
For example, `['like', 'name', 'tester']` will generate `name LIKE '%tester%'`.
......@@ -222,14 +230,22 @@ Operator can be one of the following:
You may use `false` or an empty array to indicate the values are already escaped and no escape
should be applied. Note that when using an escape mapping (or the third operand is not provided),
the values will be automatically enclosed within a pair of percentage characters.
> Note: When using PostgreSQL you may also use [`ilike`](http://www.postgresql.org/docs/8.3/static/functions-matching.html#FUNCTIONS-LIKE)
> instead of `like` for case-insensitive matching.
- `or like`: similar to the `like` operator except that `OR` is used to concatenate the `LIKE`
predicates when operand 2 is an array.
- `not like`: similar to the `like` operator except that `LIKE` is replaced with `NOT LIKE`
in the generated condition.
- `or not like`: similar to the `not like` operator except that `OR` is used to concatenate
the `NOT LIKE` predicates.
- `exists`: requires one operand which must be an instance of [[yii\db\Query]] representing the sub-query.
It will build a `EXISTS (sub-query)` expression.
- `not exists`: similar to the `exists` operator and builds a `NOT EXISTS (sub-query)` expression.
If you are building parts of condition dynamically it's very convenient to use `andWhere()` and `orWhere()`:
......
Events
======
Event is a way to "inject" custom code into existing code at certain places. For example, a comment object can trigger
an "add" event when the user adds a comment. We can write custom code and attach it to this event so that when the event
is triggered (i.e. comment will be added), our custom code will be executed.
Events are very useful both to make your components flexible and to hook into framework and extensions workflow.
Triggering events
-----------------
Any component can trigger events using `trigger` method:
```php
$this->trigger('myEvent');
// or
$event = new CreateUserEvent(); // extended from yii\base\Event
$event->userName = 'Alexander';
$this->trigger('createUserEvent', $event);
```
Event name should be unique within the class it is defined at. Event names are *case-sensitive*. It is a good practice
to define event names using class constants:
```php
class Mailer extends Component
{
const EVENT_SEND_EMAIL = 'sendEmail';
public function send()
{
// ...
$this->trigger(self::EVENT_SEND_EMAIL);
}
}
```
Attaching event handlers
------------------------
One or multiple PHP callbacks, called *event handlers*, can be attached to an event. When an event is raised, the event
handlers will be invoked automatically in the order they were attached.
There are two main methods of attaching event handlers. It can be done either via code or via application config.
> Tip: In order to get up to date list of framework and extension events search code for `->trigger`.
### Attaching event handlers via code
You can assign event handlers using `on` method of the component instance. The method's first argument is the name of
the event to watch for; the second is the handler to be called when that event occurs:
```php
$component->on($eventName, $handler);
```
The handler must be a valid PHP callback. This could be represented as:
- The name of a global function.
- An array consisting of a model name and method name.
- An array consisting of an object and a method name.
- An anonymous function.
```php
// Global function:
$component->on($eventName, 'functionName');
// Model and method names:
$component->on($eventName, ['Modelname', 'functionName']);
// Object and method name:
$component->on($eventName, [$obj, 'functionName']);
// Anonymous function:
$component->on($eventName, function ($event) {
// Use $event.
});
```
As shown in the anonymous function example, the event handling function must be defined so that it takes one argument.
This will be an [[yii\base\Event]] object.
In order to pass extra data supply it via third argument:
```php
$component->on($eventName, function ($event) {
// the extra data can be accessed via $event->data
}, $extraData);
```
### Attaching event handlers via config
It is possible to use application config to attach event hanelers:
```php
return [
// ...
'components' => [
'db' => [
// ...
'on afterOpen' => function ($event) {
// do something right after connected to database
}
],
],
];
```
Removing Event Handlers
-----------------------
The correspondoing `off` method removes an event handler:
```php
$component->off($eventName);
```
Yii supports the ability to associate multiple handlers with the same event. When using `off` as in the above,
every handler is removed. To remove only a specific handler, provide that as the second argument to `off`:
```php
$component->off($eventName, $handler);
```
The `$handler` should be presented in the `off` method in the same way as was presented in `on` in order to remove it.
Global Events
-------------
You can use "global" events instead of per-component ones. To trigger a global event use an application instance instead
of specific component:
```php
Yii::$app->trigger($eventName);
```
In order to attach a handler to it use the following:
```php
Yii::$app->on($eventName, $handler);
```
Class Events
------------
It is possible to attach event handlers to all instances of a class instead of individual instances. To do so, use
the static `Event::on` method:
```php
Event::on(ActiveRecord::className(), ActiveRecord::EVENT_AFTER_INSERT, function ($event) {
Yii::trace(get_class($event->sender) . ' is inserted.');
});
```
The code above defines a handler that will be triggered for every Active Record object's `EVENT_AFTER_INSERT` event.
Extending Yii
=============
> Note: This chapter is under development.
The Yii framework was designed to be easily extendable. Additional features can be added to your project and then reused, either by yourself on other projects or by sharing your work as a formal Yii extension.
Code style
......
Helper Classes
==============
> Note: This chapter is under development.
Yii provides many classes that help simplify common coding tasks, such as string or array manipulations,
HTML code generation, and so forth. These helper classes are organized under the `yii\helpers` namespace and
are all static classes (meaning they contain only static properties and methods and should not be instantiated).
......
Composer
========
> Note: This chapter is under development.
Yii2 uses Composer as its dependency management tool. Composer is a PHP utility that can automatically handle the installation of needed libraries and
extensions, thereby keeping those third-party resources up to date while absolving you of the need to manually manage the project's dependencies.
......
Using 3rd-Party Libraries
=========================
> Note: This chapter is under development.
Yii is carefully designed so that third-party libraries can be
easily integrated to further extend Yii's functionalities.
......
Helpers
=======
> Note: This chapter is under development.
Helper classes typically contain static methods only and are used as follows:
```php
use \yii\helpers\Html;
echo Html::encode('Test > test');
```
There are several classes provided by framework:
- ArrayHelper
- Console
- FileHelper
- Html
- HtmlPurifier
- Image
- Inflector
- Json
- Markdown
- Security
- StringHelper
- Url
- VarDumper
The Definitive Guide to Yii 2.0
===============================
This tutorial is released under the [Terms of Yii Documentation](http://www.yiiframework.com/doc/terms/).
All Rights Reserved.
2014 (c) Yii Software LLC.
Introduction
------------
- [Overview](overview.md) - What is Yii and what is it good for?
Getting started
---------------
- [Upgrading from 1.1 to 2.0](upgrade-from-v1.md)
- [Installation](installation.md) - How to download Yii and configure the Webserver?
- [Configuration](configuration.md) - Configuration of a Yii application
- [Basic Application Template](apps-basic.md) - A template to start a basic frontend application.
- [Advanced Application Template](apps-advanced.md) - The basis for more advanced applications.
- [Creating your own Application structure](apps-own.md) - Learn how to start from scratch.
Base concepts
-------------
- [Basic concepts of Yii](basics.md) - The Object and Component class, Path aliases and autoloading
- [MVC](mvc.md) - Implementation of MVC in Yii and a typical MVC application flow
- [Model](model.md) - The Yii Model provides Attributes, Scenarios and data Validation
- [View](view.md) - Rendering Views applying layouts, using Widgets and asset management
- [Controller](controller.md) - controller actions, routing and action filters
- [Event Handling](events.md) - The Yii event handling mechanism
- [Behaviors](behaviors.md)
Database
--------
- [Basics](database-basics.md) - Connecting to a database, basic queries, transactions and schema manipulation
- [Query Builder](query-builder.md) - Querying the database using a simple abstraction layer
- [ActiveRecord](active-record.md) - The active record ORM, retrieving and manipulating records and defining relations
- [Database Migration](console-migrate.md) - Versioning your database with database migration
Developers Toolbox
------------------
- [Helper Classes](helpers.md)
- [Automatic Code Generation](gii.md)
- [Debug toolbar and debugger](module-debug.md)
- [Error Handling](error.md)
- [Logging](logging.md)
Extensions and 3rd party libraries
----------------------------------
- [Composer](composer.md) - How to manage applications dependencies via composer
- [Extending Yii](extensions.md)
- [Template engines](template.md) - Using template engines such as Smarty or Twig
- [Using Yii together with 3rd-Party Systems](using-3rd-party-libraries.md) - Using Yii in 3rd-Party Systems and using Yii 1 and 2 together
Security and access control
---------------------------
- [Authentication](authentication.md) - Identifying Users
- [Authorization](authorization.md) - Access control and RBAC
- [Security](security.md) - Hashing and verifying passwords, encryption
- [Views security](view.md#security) - how to prevent XSS
Data providers, lists and grids
-------------------------------
- [Overview](data-overview.md)
- [Data providers](data-providers.md)
- [Data widgets](data-widgets.md)
- [Grid](data-grid.md)
Advanced Topics
---------------
- [Asset Management](assets.md)
- [Working with forms](form.md)
- [Implementing RESTful Web Service APIs](rest.md)
- [Bootstrap widgets](bootstrap-widgets.md) - Using [twitter bootstrap](http://getbootstrap.com/)
- [Theming](theming.md)
- [Caching](caching.md) - Caching data, page fragments and http requests
- [Internationalization](i18n.md) - Message translation and formatting
- [URL Management](url.md) - routing, customized urls and SEO
- [Console Application](console.md)
- [Performance Tuning](performance.md)
- [Testing](testing.md)
- [Managing Test Fixtures](test-fixture.md)
- [Service Locator and Dependency Injection](di.md)
References
----------
- [Model validation reference](validation.md)
- [Official Composer documentation](http://getcomposer.org)
Working with forms
==================
> Note: This chapter is under development.
The primary way of using forms in Yii is through [[yii\widgets\ActiveForm]]. This approach should be preferred when
the form is based upon a model. Additionally, there are some useful methods in [[yii\helpers\Html]] that are typically
used for adding buttons and help text to any form.
......@@ -57,7 +59,7 @@ class LoginForm extends Model
}
```
The controller will pass an instance of that model to the view, wherein the Active Form widget is used:
The controller will pass an instance of that model to the view, wherein the [[yii\widgets\ActiveForm|ActiveForm]] widget is used:
```php
use yii\helpers\Html;
......@@ -98,25 +100,24 @@ To customize the output, you can chain additional methods to this call:
```
This will create all the `<label>`, `<input>` and other tags according to the template defined by the form field.
To add these tags yourself you can use the `Html` helper class. The following is equivalent to the code above:
```php
<?= Html::activeLabel($model, 'password') ?>
<?= Html::activePasswordInput($model, 'password') ?>
<?= Html::error($model, 'password') ?>
To add these tags yourself you can use the `Html` helper class.
or
If you want to use one of HTML5 fields you may specify input type directly like the following:
<?= Html::activeLabel($model, 'username', ['label' => 'name']) ?>
<?= Html::activeTextInput($model, 'username') ?>
<div class="hint-block">Please enter your name</div>
<?= Html::error($model, 'username') ?>
```php
<?= $form->field($model, 'email')->input('email') ?>
```
If you want to use one of HTML5 fields you may specify input type directly like the following:
Specifying the attribute of the model can be done in more sophisticated ways. For example when an attribute may
take an array value when uploading multiple files or selecting multiple items you may specify it by appending `[]`
to the attribute name:
```php
<?= $form->field($model, 'email')->input('email') ?>
// allow multiple files to be uploaded:
echo $form->field($model, 'uploadFile[]')->fileInput('multiple'=>'multiple');
// allow multiple items to be checked:
echo $form->field($model, 'items[]')->checkboxList(['a' => 'Item A', 'b' => 'Item B', 'c' => 'Item C']);
```
> **Tip**: in order to style required fields with asterisk you can use the following CSS:
......
Model validation reference
==========================
> Note: This chapter is under development.
As a model both represents data and defines the business rules to which that data must adhere, comprehending data validation is key to using Yii. In order to learn model validation basics, please refer to [Model, Validation subsection](model.md#Validation).
This guide describes all of Yii's validators and their parameters.
......
What is Yii
===========
Yii is a high performance, component-based PHP framework for rapidly developing modern Web applications.
The name Yii (pronounced `Yee` or `[ji:]`) means simple and evolutionary in Chinese. It can also
be considered as the acronym for **Yes It Is**!
What is Yii Best for?
---------------------
Yii is a generic Web programming framework, meaning that it can be used for developing all kinds
of Web applications based on PHP. Because of its component-based architecture and sophisticated caching
support, it is especially suitable for developing large-scale applications such as portals, forums, content
management systems (CMS), e-commerce projects, RESTful Web services, and so on.
How does Yii Compare with Other Frameworks?
-------------------------------------------
- Like most PHP frameworks, Yii implements the MVC (Model-View-Controller) design pattern and promotes code
organization based on this pattern.
- Yii takes the philosophy that code should be written in a simple yet elegant way. It will never try to
over-design things mainly for the purpose of following some design pattern.
- Yii is a full-stack framework providing many proven and ready-to-use features, such as query builders
and ActiveRecord supporting relational and NoSQL databases, RESTful API development support, multi-tier
caching support, etc.
- Yii is extremely extensible. You can customize or replace nearly every piece of core code. You can also
take advantage of its solid extension architecture, use or develop redistributable extensions.
- High performance is always a primary goal of Yii.
Yii is not a one-man show, it is backed up by a [strong core developer team][] as well as a large community
with many professionals who are constantly contributing to the development of Yii. The Yii developer team
is keeping a close eye on the latest trends of Web development and the best practices and features
found in other frameworks and projects. They are being carefully incorporated into the core framework and exposed
via simple and elegant interfaces.
[strong core developer team]: http://www.yiiframework.com/about/
Yii Versions
------------
Yii has two major versions available currently: 1.1 and 2.0. Version 1.1 is the old generation and is
currently under maintenance mode. Version 2.0 is a complete rewrite of Yii by adopting the latest
technologies and protocols, such as Composer, PSR, namespaces, traits, etc. Version 2.0 represents the latest
generation of the framework and will receive our main development efforts in the next few years.
This guide is mainly about version 2.0.
Requirements and Prerequisites
------------------------------
Yii 2.0 requires PHP 5.4.0 or above. You may find out more detailed requirements for individual features
by running the requirement checker included in every release.
Using Yii requires basic knowledge about object-oriented programming (OOP), as Yii is a pure OOP-based framework.
Yii 2.0 also makes use of the latest features of PHP, such as [namespaces](http://www.php.net/manual/en/language.namespaces.php),
[traits](http://www.php.net/manual/en/language.oop5.traits.php). Understanding these concepts will help
you pick up Yii 2.0 more easily.
Managing assets
===============
> Note: This chapter is under development.
An asset in Yii is a file that is included into the page. It could be CSS, JavaScript or
any other file. The framework provides many ways to work with assets from basics such as adding `<script src="...">` tags
for a file which is covered by the [View section](view.md), to advanced usage such as publishing files that are not
......
Data providers
==============
> Note: This chapter is under development.
Data provider abstracts data set via [[yii\data\DataProviderInterface]] and handles pagination and sorting.
It can be used by [grids](data-grid.md), [lists and other data widgets](data-widgets.md).
......
Data grid
=========
Data widgets
============
> Note: This chapter is under development.
ListView
--------
DetailView
----------
DetailView displays the detail of a single data [[yii\widgets\DetailView::$model|model]].
It is best used for displaying a model in a regular format (e.g. each model attribute is displayed as a row in a table).
The model can be either an instance of [[\yii\base\Model]] or an associative array.
DetailView uses the [[yii\widgets\DetailView::$attributes]] property to determines which model attributes should be displayed and how they
should be formatted.
A typical usage of DetailView is as follows:
```php
echo DetailView::widget([
'model' => $model,
'attributes' => [
'title', // title attribute (in plain text)
'description:html', // description attribute in HTML
[ // the owner name of the model
'label' => 'Owner',
'value' => $model->owner->name,
],
],
]);
```
GridView
--------
Data grid or GridView is one of the most powerful Yii widgets. It is extremely useful if you need to quickly build admin
section of the system. It takes data from [data provider](data-providers.md) and renders each row using a set of columns
......@@ -32,8 +70,7 @@ echo GridView::widget([
The above code first creates a data provider and then uses GridView to display every attribute in every row taken from
data provider. The displayed table is equiped with sorting and pagination functionality.
Grid columns
------------
### Grid columns
Yii grid consists of a number of columns. Depending on column type and settings these are able to present data differently.
......@@ -141,8 +178,8 @@ In the code above `$url` is the URL that the column creates for the button, and
rendered for the current row.
- `urlCreator` is a callback that creates a button URL using the specified model information. The signature of
the callback should be the same as that of [[yii\grid\ActionColumn\createUrl()]]. If this property is not set,
button URLs will be created using [[yii\grid\ActionColumn\createUrl()]].
the callback should be the same as that of [[yii\grid\ActionColumn::createUrl()]]. If this property is not set,
button URLs will be created using [[yii\grid\ActionColumn::createUrl()]].
#### Checkbox column
......@@ -324,3 +361,4 @@ In `search()` you then just add another filter condition with `$query->andFilter
> Info: For more information on `joinWith` and the queries performed in the background, check the
> [active record docs on eager and lazy loading](active-record.md#lazy-and-eager-loading).
What is Yii
===========
Yii is a high-performance, component-based PHP framework for rapidly developing large-scale Web applications. Yii enables maximum reusability in Web
programming and can significantly accelerate your Web application development
process. The name Yii (pronounced `Yee` or `[ji:]`) is an acronym for
**Yes It Is!**.
Requirements
------------
To run a Yii-powered Web application, you need a Web server that supports
PHP 5.4.0 or greater.
For developers who want to use Yii, understanding object-oriented
programming (OOP) is very helpful, as Yii is a pure OOP framework.
Yii 2.0 also makes use of the latest features of PHP, including [namespaces](http://www.php.net/manual/en/language.namespaces.php),
so you should be familiar with how those work, too.
What is Yii Best for?
---------------------
Yii is a generic Web programming framework that can be used for developing
virtually any type of Web application. Because it is light weight and
equipped with sophisticated caching mechanisms, Yii is especially suited
to high-traffic applications such as portals, forums, content
management systems (CMS), e-commerce projects, and so on.
How does Yii Compare with Other Frameworks?
-------------------------------------------
- Like most PHP frameworks, Yii uses the MVC (Model-View-Controller) design approach.
- Yii is a full-stack framework providing many solutions and components, such as logging, session management, caching, etc.
- Yii strikes a good balance between simplicity and being feature-rich.
- Syntax and overall development usability are taken seriously by the Yii development team.
- Performance is one of the key goals for the Yii framework.
- The Yii development team is constantly watching what other Web frameworks are doing to consider what best practices and
features should be incorporated into Yii. The initial Yii release was heavily influenced by Ruby on Rails.
Still, no framework or feature is being blindly copied into Yii; all decisions are based upon what's best
for Web developers and in keeping with Yii's philosophy.
Implementing RESTful Web Service APIs
=====================================
> Note: This chapter is under development.
Yii provides a whole set of tools to greatly simplify the task of implementing RESTful Web Service APIs.
In particular, Yii provides support for the following aspects regarding RESTful APIs:
......@@ -830,7 +832,7 @@ API Versioning
Your APIs should be versioned. Unlike Web applications which you have full control on both client side and server side
code, for APIs you usually do not have control of the client code that consumes the APIs. Therefore, backward
compatibility (BC) of the APIs should be maintained whenever possible, and if some BC-breaking changes must be
introduced to the APIs, you should bump up the version number. You may refer to [Symantic Versioning](http://semver.org/)
introduced to the APIs, you should bump up the version number. You may refer to [Semantic Versioning](http://semver.org/)
for more information about designing the version numbers of your APIs.
Regarding how to implement API versioning, a common practice is to embed the version number in the API URLs.
......
URL Management
==============
> Note: This chapter is under development.
The concept of URL management in Yii is fairly simple. URL management is based on the premise that the application uses
internal routes and parameters everywhere. The framework itself will then translate routes into URLs, and vice versa, according to the URL manager's configuration. This approach allows you to change site-wide URLs merely by
editing a single configuration file, without ever touching the application code.
......@@ -249,7 +251,7 @@ return [
### Handling REST requests
TBD:
- RESTful routing: [[yii\filters\VerbFilter]], [[yii\filters\UrlManager::$rules]]
- RESTful routing: [[yii\filters\VerbFilter]], [[yii\web\UrlManager::$rules]]
- Json API:
- response: [[yii\web\Response::format]]
- request: [[yii\web\Request::$parsers]], [[yii\web\JsonParser]]
......
Authentication
==============
> Note: This chapter is under development.
Authentication is the act of verifying who a user is, and is the basis of the login process. Typically, authentication uses the combination of an identifier--a username or email address--and a password. The user submits these values through a form, and the application then compares the submitted information against that previously stored (e.g., upon registration).
In Yii, this entire process is performed semi-automatically, leaving the developer to merely implement [[yii\web\IdentityInterface]], the most important class in the authentication system. Typically, implementation of `IdentityInterface` is accomplished using the `User` model.
......
Authorization
=============
> Note: This chapter is under development.
Authorization is the process of verifying that a user has enough permission to do something. Yii provides two authorization
methods: Access Control Filter (ACF) and Role-Based Access Control (RBAC).
......@@ -94,7 +96,7 @@ Two special roles are recognized, and they are checked via [[yii\web\User::isGue
Using other role names requires RBAC (to be described in the next section), and [[yii\web\User::can()]] will be called.
If this option is empty or not set, it means this rule applies to all roles.
* [[yii\filters\AccessRule::ips|ips]]: specifies which [[yii\web\Request::Request::userIP|client IP addresses]] this rule matches.
* [[yii\filters\AccessRule::ips|ips]]: specifies which [[yii\web\Request::userIP|client IP addresses]] this rule matches.
An IP address can contain the wildcard `*` at the end so that it matches IP addresses with the same prefix.
For example, '192.168.*' matches all IP addresses in the segment '192.168.'. If this option is empty or not set,
it means this rule applies to all IP addresses.
......@@ -162,14 +164,14 @@ To facilitate our description next, we will first introduce some basic RBAC conc
### Basic Concepts
A role represents a collection of *permissions* (e.g. viewing reports, creating reports). A role may be assigned
A role represents a collection of *permissions* (e.g. creating posts, updating posts). A role may be assigned
to one or multiple users. To check if a user has a specified permission, we may check if the user is assigned
with a role that contains that permission.
Associated with each role or permission, there may be a *rule*. A rule represents a piece of code that will be
executed during access check to determine if the corresponding role or permission applies to the current user.
For example, the "update report" permission may have a rule that checks if the current user is the report creator.
During access checking, if the user is NOT the report creator, he/she will be considered not having the "update report" permission.
For example, the "update post" permission may have a rule that checks if the current user is the post creator.
During access checking, if the user is NOT the post creator, he/she will be considered not having the "update post" permission.
Both roles and permissions can be organized in a hierarchy. In particular, a role may consist of other roles or permissions;
and a permission may consist of other permissions. Yii implements a *partial order* hierarchy which includes the
......@@ -230,26 +232,15 @@ class RbacController extends Controller
// add "createPost" permission
$createPost = $auth->createPermission('createPost');
$createPost->description = 'create a post';
$createPost->description = 'Create a post';
$auth->add($createPost);
// add "readPost" permission
$readPost = $auth->createPermission('readPost');
$readPost->description = 'read a post';
$auth->add($readPost);
// add "updatePost" permission
$updatePost = $auth->createPermission('updatePost');
$updatePost->description = 'update post';
$updatePost->description = 'Update post';
$auth->add($updatePost);
// add "reader" role and give this role the "readPost" permission
$reader = $auth->createRole('reader');
$auth->add($reader);
$auth->addChild($reader, $readPost);
// add "author" role and give this role the "createPost" permission
// as well as the permissions of the "reader" role
$author = $auth->createRole('author');
$auth->add($author);
$auth->addChild($author, $createPost);
......@@ -262,38 +253,44 @@ class RbacController extends Controller
$auth->addChild($admin, $updatePost);
$auth->addChild($admin, $author);
// Assign roles to users. 10, 14 and 26 are IDs returned by IdentityInterface::getId()
// Assign roles to users. 1 and 2 are IDs returned by IdentityInterface::getId()
// usually implemented in your User model.
$auth->assign($reader, 10);
$auth->assign($author, 14);
$auth->assign($admin, 26);
$auth->assign($author, 2);
$auth->assign($admin, 1);
}
}
```
After executing the command we'll get the following hierarchy:
![Simple RBAC hierarchy](images/rbac-hierarchy-1.png "Simple RBAC hierarchy")
Author can create post, admin can update post and do everything author can.
If your application allows user signup you need to assign roles to these new users once. For example, in order for all
signed up users to become authors you in advanced application template you need to modify `common\models\User::create()`
signed up users to become authors you in advanced application template you need to modify `frontend\models\SignupForm::signup()`
as follows:
```php
public static function create($attributes)
public function signup()
{
/** @var User $user */
$user = new static();
$user->setAttributes($attributes);
$user->setPassword($attributes['password']);
if ($this->validate()) {
$user = new User();
$user->username = $this->username;
$user->email = $this->email;
$user->setPassword($this->password);
$user->generateAuthKey();
if ($user->save()) {
$user->save(false);
// the following three lines were added:
$auth = Yii::$app->authManager;
$adminRole = $auth->getRole('author');
$auth->assign($adminRole, $user->getId());
$authorRole = $auth->getRole('author');
$auth->assign($authorRole, $user->getId());
return $user;
} else {
return null;
}
return null;
}
```
......@@ -308,8 +305,9 @@ For applications that require complex access control with dynamically updated au
### Using Rules
As aforementioned, rules add additional constraint to roles and permissions. A rule is a class extending
from [[yii\rbac\Rule]]. It must implement the [[yii\rbac\Rule::execute()|execute()]] method. Below is
an example:
from [[yii\rbac\Rule]]. It must implement the [[yii\rbac\Rule::execute()|execute()]] method. In the hierarchy we've
created previously author cannot edit his own post. Let's fix it. First we need a rule to verify that the use is post
author:
```php
namespace app\rbac;
......@@ -336,8 +334,8 @@ class AuthorRule extends Rule
}
```
The rule above checks if the `post` is created by `$user`. It can be used in the following
to create a special permission `updateOwnPost`:
The rule above checks if the `post` is created by `$user`. We'll create a special permission `updateOwnPost` in the
command we've used previously:
```php
// add the rule
......@@ -346,14 +344,20 @@ $auth->add($rule);
// add the "updateOwnPost" permission and associate the rule with it.
$updateOwnPost = $this->auth->createPermission('updateOwnPost');
$updateOwnPost->description = 'update own post';
$updateOwnPost->description = 'Update own post';
$updateOwnPost->ruleName = $rule->name;
$auth->add($updateOwnPost);
// "updateOwnPost" will be used from "updatePost"
$auth->addChild($updateOwnPost, $updatePost);
// allow "author" to update their own posts
$auth->addChild($author, $updateOwnPost);
```
Now we've got the following hierarchy:
![RBAC hierarchy with a rule](images/rbac-hierarchy-2.png "RBAC hierarchy with a rule")
### Access Check
......@@ -367,7 +371,11 @@ if (\Yii::$app->user->can('createPost')) {
}
```
To check the `updateOwnPost` permission, an extra parameter is required by the `AuthorRule` described before.
If the current user is Jane with ID=1 we're starting at `createPost` and trying to get to `Jane`:
![Access check](images/rbac-access-check-1.png "Access check")
In order to check if user can update post we need to pass an extra parameter that is required by the `AuthorRule` described before:
```php
if (\Yii::$app->user->can('updatePost', ['post' => $post])) {
......@@ -375,6 +383,18 @@ if (\Yii::$app->user->can('updatePost', ['post' => $post])) {
}
```
Here's what happens if current user is John:
![Access check](images/rbac-access-check-2.png "Access check")
We're starting with the `updatePost` and going through `updateOwnPost`. In order to pass it `AuthorRule` should return
`true` from its `execute` method. The method receives its `$params` from `can` method call so the value is
`['post' => $post]`. If everything is OK we're getting to `author` that is assigned to John.
In case of Jane it is a bit simpler since she's an admin:
![Access check](images/rbac-access-check-3.png "Access check")
### Using Default Roles
......@@ -396,6 +416,7 @@ You can create set up the RBAC data as follows,
```php
namespace app\rbac;
use Yii;
use yii\rbac\Rule;
/**
......@@ -407,15 +428,16 @@ class UserGroupRule extends Rule
public function execute($user, $item, $params)
{
$group = \Yii::$app->user->identity->group;
if (!Yii::$app->user->isGuest) {
$group = Yii::$app->user->identity->group;
if ($item->name === 'admin') {
return $group == 1;
} elseif ($item->name === 'author') {
return $group == 1 || $group == 2;
} else {
return false;
}
}
return false;
}
}
$rule = new \app\rbac\UserGroupRule;
......
Security
========
> Note: This chapter is under development.
Good security is vital to the health and success of any application. Unfortunately, many developers cut corners when it comes to security, either due to a lack of understanding or because implementation is too much of a hurdle. To make your Yii powered application as secure as possible, Yii has included several excellent and easy to use security features.
......
Basic application template
==========================
> Note: This chapter is under development.
The basic Yii application template is a perfect fit for small projects or when you're just learning the framework.
The basic application template includes four pages: a homepage, an about page, a contact page, and a login page.
......
Installation
============
> Note: This chapter is under development.
There are two ways you can install the Yii framework:
* Via [Composer](http://getcomposer.org/) (recommended)
* Download an application template containing all site requirements, including the Yii framework itself
* By downloading an application template containing all of the site requirements, including the Yii framework itself
Installing via Composer
-----------------------
The recommended way to install Yii is to use the [Composer](http://getcomposer.org/) package manager. If you do not already
have Composer installed, you may download it from [http://getcomposer.org/](http://getcomposer.org/) or run the following command:
have Composer installed, you may download it from [http://getcomposer.org/](http://getcomposer.org/), or run the following command to download and install it:
```
curl -s http://getcomposer.org/installer | php
```
We strongly recommend a global composer installation.
(It is strongly recommended to perform a [global Composer installation](https://getcomposer.org/doc/00-intro.md#globally)).
For problems or more information, see the official Composer guide:
For problems with, or more information on, installing Composer, see the official Composer guide:
* [Linux](http://getcomposer.org/doc/00-intro.md#installation-nix)
* [Windows](http://getcomposer.org/doc/00-intro.md#installation-windows)
With Composer installed, you can create a new Yii site using one of Yii's ready-to-use application templates.
Based on your needs, choosing the right template can help bootstrap your project.
With Composer installed, you can create a new Yii site using one of Yii's ready-to-use application templates. Based on your needs, choosing the right template can help bootstrap your project.
Currently, there are two application templates available:
Currently, there are two Yii application templates available:
- The [Basic Application Template](https://github.com/yiisoft/yii2-app-basic) - just a basic frontend application template.
- The [Advanced Application Template](https://github.com/yiisoft/yii2-app-advanced) - consisting of a frontend, a backend,
console resources, common (shared code), and support for environments.
- [Basic Application Template](https://github.com/yiisoft/yii2-app-basic), a basic frontend application template
- [Advanced Application Template](https://github.com/yiisoft/yii2-app-advanced), consisting of a frontend, a backend, console resources, common (shared code), and support for environments
For installation instructions for these templates, see the above linked pages.
To read more about the ideas behind these application templates and proposed usage,
For template installation instructions, see the above linked pages.
To read more about the ideas behind these application templates and the proposed usage,
refer to the [basic application template](apps-basic.md) and [advanced application template](apps-advanced.md) documents.
If you do not want to use a template and want to start from scratch you'll find information in the document about
[creating your own application structure](apps-own.md). This is only recommended for advanced users.
If you do not want to use a template, rather starting from scratch, you'll find information in the [creating your own application structure](apps-own.md) document. This approach is only recommended for advanced users.
Installing from zip
......@@ -49,55 +48,48 @@ Installation from a zip file involves two steps:
1. Downloading an application template from [yiiframework.com](http://www.yiiframework.com/download/).
2. Unpacking the downloaded file.
If you only want the Yii Framework files you can download a ZIP file directly from [github](https://github.com/yiisoft/yii2-framework/releases).
If you only want the Yii Framework files you can download a zip file directly from [github](https://github.com/yiisoft/yii2-framework/releases).
To create your application you might want to follow the steps described in [creating your own application structure](apps-own.md).
This is only recommended for advanced users.
> Tip: The Yii framework itself does not need to be installed under a web-accessible directory.
A Yii application has one entry script which is usually the only file that absolutely must be
> Tip: The Yii framework itself does not need to be installed under a web-accessible directory (in fact, it should not be).
A Yii application has one entry script, which is usually the only file that absolutely must be
exposed to web users (i.e., placed within the web directory). Other PHP scripts, including those
part of the Yii Framework, should be protected from web access to prevent possible exploitation by hackers.
in the Yii Framework, should be protected from web access to prevent possible exploitation by hackers.
Requirements
------------
Yii 2 requires PHP 5.4.0 or higher. Yii has been tested with the [Apache HTTP server](http://httpd.apache.org/) and
[Nginx HTTP server](http://nginx.org/) on both Windows and Linux.
Yii may also be usable on other web servers and platforms, provided that PHP 5.4 or higher is present.
After installing Yii, you may want to verify that your server satisfies
Yii's requirements. You can do so by running the requirement checker
script in a web browser or from the command line.
If you have installed a Yii application template via zip or composer you'll find a `requirements.php` file in the
If you have installed a Yii application template via the downloaded zip file or Composer, you'll find a `requirements.php` file in the
base directory of your application.
In order to run this script on the command line use the following command:
In order to run this script on the command line use the following command (after navigating to the directory where `requirements.php` can be found):
```
php requirements.php
```
In order to run this script in your browser, you should ensure it is accessable by the webserver and
In order to run this script in your browser, you must make sure it's within a web directory, and then
access `http://hostname/path/to/yii-app/requirements.php` in your browser.
If you are using Linux you can create a soft link to make it accessable, using the following command:
```
ln -s requirements.php ../requirements.php
```
For the advanded app the `requirements.php` is two levels up so you have to use `ln -s requirements.php ../../requirements.php`.
Yii 2 requires PHP 5.4.0 or higher. Yii has been tested with the [Apache HTTP server](http://httpd.apache.org/) and
[Nginx HTTP server](http://nginx.org/) on Windows and Linux.
Yii may also be usable on other web servers and platforms, provided that PHP 5.4 or higher is supported.
Recommended Apache Configuration
--------------------------------
Yii is ready to work with a default Apache web server configuration. As a security measure, Yii comes with `.htaccess`
files in the Yii framework folder to deny access to those restricted resources.
files in the Yii framework folder to deny access to the application's restricted resources.
By default, requests for pages in a Yii-based site go through the bootstrap file, usually named `index.php`, and placed
in the application's `web` directory. The result will be URLs in the format `http://hostname/index.php/controller/action/param/value`.
in the application's home directory. The result will be URLs in the format `http://hostname/index.php/controller/action/param/value`.
To hide the bootstrap file in your URLs, add `mod_rewrite` instructions to the `.htaccess` file in your web document root
(or add the instructions to the virtual host configuration in Apache's `httpd.conf` file, `Directory` section for your webroot).
......@@ -106,10 +98,10 @@ The applicable instructions are:
~~~
RewriteEngine on
# If a directory or a file exists, use it directly
# If a directory or a file exists, use the request directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Otherwise forward it to index.php
# Otherwise forward the request to index.php
RewriteRule . index.php
~~~
......
MVC Overview
============
Request Lifecycle
=================
Yii implements the model-view-controller (MVC) design pattern, which is
widely adopted in Web and other application programming. MVC aims to separate business logic from
user interface considerations, allowing developers to more easily change one component of an application without affecting, or even touching, another.
In MVC, the *model* represents both the
information (the data) and the business rules to which the data must adhere. The *view* contains elements
of the user interface, such as text, images, and form elements. The *controller* manages
the communication between the model and the view, acting as an agent that handles actions and requests.
Besides implementing the MVC design pattern, Yii also introduces a *front-controller*, called
*application*. The front-controller encapsulates the *execution context* for the processing of a request. This means that the front-controller collects information about a user request, and
then dispatches it to an appropriate controller for the actual handling of that request. In other words, the front-controller is the primary application manager, handling all requests and delegating action accordingly.
The following diagram shows the static structure of a Yii application:
![Static structure of Yii application](images/structure.png)
A Typical Workflow
------------------
> Note: This chapter is under development.
The following diagram shows a typical workflow of a Yii application handling a user request:
......
Application Structure
=====================
> Note: This chapter is under development.
Yii implements the model-view-controller (MVC) design pattern, which is
widely adopted in Web and other application programming. MVC aims to separate business logic from
user interface considerations, allowing developers to more easily change one component of an application without affecting, or even touching, another.
In MVC, the *model* represents both the
information (the data) and the business rules to which the data must adhere. The *view* contains elements
of the user interface, such as text, images, and form elements. The *controller* manages
the communication between the model and the view, acting as an agent that handles actions and requests.
Besides implementing the MVC design pattern, Yii also introduces a *front-controller*, called
*application*. The front-controller encapsulates the *execution context* for the processing of a request. This means that the front-controller collects information about a user request, and
then dispatches it to an appropriate controller for the actual handling of that request. In other words, the front-controller is the primary application manager, handling all requests and delegating action accordingly.
The following diagram shows the static structure of a Yii application:
![Static structure of Yii application](images/structure.png)
Controller
==========
> Note: This chapter is under development.
Controller is one of the key parts of the application. It determines how to handle incoming request and creates a response.
Most often a controller takes HTTP request data and returns HTML, JSON or XML as a response.
......
Entry Scripts
=============
> Note: This chapter is under development.
Configuring options in the bootstrap file
-----------------------------------------
For each application in Yii there is at least one bootstrap file: a PHP script through which all requests are handled. For web applications, the bootstrap file is typically `index.php`; for
console applications, the bootstrap file is `yii`. Both bootstrap files perform nearly the same job:
1. Setting common constants.
2. Including the Yii framework itself.
3. Including [Composer autoloader](http://getcomposer.org/doc/01-basic-usage.md#autoloading).
4. Reading the configuration file into `$config`.
5. Creating a new application instance, configured via `$config`, and running that instance.
Like any resource in your Yii application, the bootstrap file can be edited to fit your needs. A typical change is to the value of `YII_DEBUG`. This constant should be `true` during development, but always `false` on production sites.
The default bootstrap structure sets `YII_DEBUG` to `false` if not defined:
```php
defined('YII_DEBUG') or define('YII_DEBUG', false);
```
During development, you can change this to `true`:
```php
define('YII_DEBUG', true); // Development only
defined('YII_DEBUG') or define('YII_DEBUG', false);
```
Model
=====
> Note: This chapter is under development.
In keeping with the MVC approach, a model in Yii is intended for storing or temporarily representing application data, as well as defining the busines rules by which the data must abide.
Yii models have the following basic features:
......
View
====
> Note: This chapter is under development.
The view component is an important part of MVC. The view acts as the interface to the application, making it responsible
for presenting data to end users, displaying forms, and so forth.
......
Fixtures
========
> Note: This chapter is under development.
Fixtures are important part of testing. Their main purpose is to set up the environment in a fixed/known state
so that your tests are repeatable and run in an expected way. Yii provides a fixture framework that allows
you to define your fixtures precisely and use them easily.
......@@ -225,3 +227,138 @@ of running unit tests related with DB:
- Unload fixtures.
3. Repeat Step 2 until all tests finish.
**To be cleaned up below**
Managing Fixtures
=================
// todo: this tutorial may be merged into test-fixture.md
Fixtures are important part of testing. Their main purpose is to populate you with data that needed by testing
different cases. With this data using your tests becoming more efficient and useful.
Yii supports fixtures via the `yii fixture` command line tool. This tool supports:
* Loading fixtures to different storage such as: RDBMS, NoSQL, etc;
* Unloading fixtures in different ways (usually it is clearing storage);
* Auto-generating fixtures and populating it with random data.
Fixtures format
---------------
Fixtures are objects with different methods and configurations, refer to official [documentation](https://github.com/yiisoft/yii2/blob/master/docs/guide/test-fixture.md) on them.
Lets assume we have fixtures data to load:
```
#users.php file under fixtures data path, by default @tests\unit\fixtures\data
return [
[
'name' => 'Chase',
'login' => 'lmayert',
'email' => 'strosin.vernice@jerde.com',
'auth_key' => 'K3nF70it7tzNsHddEiq0BZ0i-OU8S3xV',
'password' => '$2y$13$WSyE5hHsG1rWN2jV8LRHzubilrCLI5Ev/iK0r3jRuwQEs2ldRu.a2',
],
[
'name' => 'Celestine',
'login' => 'napoleon69',
'email' => 'aileen.barton@heaneyschumm.com',
'auth_key' => 'dZlXsVnIDgIzFgX4EduAqkEPuphhOh9q',
'password' => '$2y$13$kkgpvJ8lnjKo8RuoR30ay.RjDf15bMcHIF7Vz1zz/6viYG5xJExU6',
],
];
```
If we are using fixture that loads data into database then these rows will be applied to `users` table. If we are using nosql fixtures, for example `mongodb`
fixture, then this data will be applied to `users` mongodb collection. In order to learn about implementing various loading strategies and more, refer to official [documentation](https://github.com/yiisoft/yii2/blob/master/docs/guide/test-fixture.md).
Above fixture example was auto-generated by `yii2-faker` extension, read more about it in these [section](#auto-generating-fixtures).
Fixture classes name should not be plural.
Loading fixtures
----------------
Fixture classes should be suffixed by `Fixture` class. By default fixtures will be searched under `tests\unit\fixtures` namespace, you can
change this behavior with config or command options.
To load fixture, run the following command:
```
yii fixture/load <fixture_name>
```
The required `fixture_name` parameter specifies a fixture name which data will be loaded. You can load several fixtures at once.
Below are correct formats of this command:
```
// load `users` fixture
yii fixture/load User
// same as above, because default action of "fixture" command is "load"
yii fixture User
// load several fixtures. Note that there should not be any whitespace between ",", it should be one string.
yii fixture User,UserProfile
// load all fixtures
yii fixture/load all
// same as above
yii fixture all
// load fixtures, but for other database connection.
yii fixture User --db='customDbConnectionId'
// load fixtures, but search them in different namespace. By default namespace is: tests\unit\fixtures.
yii fixture User --namespace='alias\my\custom\namespace'
// load global fixture `some\name\space\CustomFixture` before other fixtures will be loaded.
// By default this option is set to `InitDbFixture` to disable/enable integrity checks. You can specify several
// global fixtures separated by comma.
yii fixture User --globalFixtures='some\name\space\Custom'
```
Unloading fixtures
------------------
To unload fixture, run the following command:
```
// unload Users fixture, by default it will clear fixture storage (for example "users" table, or "users" collection if this is mongodb fixture).
yii fixture/unload User
// Unload several fixtures. Note that there should not be any whitespace between ",", it should be one string.
yii fixture/unload User,UserProfile
// unload all fixtures
yii fixture/unload all
```
Same command options like: `db`, `namespace`, `globalFixtures` also can be applied to this command.
Configure Command Globally
--------------------------
While command line options allow us to configure the migration command
on-the-fly, sometimes we may want to configure the command once for all. For example you can configure
different migration path as follows:
```
'controllerMap' => [
'fixture' => [
'class' => 'yii\console\controllers\FixtureController',
'db' => 'customDbConnectionId',
'namespace' => 'myalias\some\custom\namespace',
'globalFixtures' => [
'some\name\space\Foo',
'other\name\space\Bar'
],
],
]
```
Auto-generating fixtures
------------------------
Yii also can auto-generate fixtures for you based on some template. You can generate your fixtures with different data on different languages and formats.
These feature is done by [Faker](https://github.com/fzaninotto/Faker) library and `yii2-faker` extension.
See extension [guide](https://github.com/yiisoft/yii2/tree/master/extensions/faker) for more docs.
The Definitive Guide to Yii 2.0
===============================
This tutorial is released under [the Terms of Yii Documentation](http://www.yiiframework.com/doc/terms/).
All Rights Reserved.
&copy; 2014 Yii Software LLC.
Debug toolbar and debugger
==========================
> Note: This chapter is under development.
Yii2 includes a handy toolbar, and built-in debugger, for faster development and debugging of your applications. The toolbar displays information
about the currently opened page, while the debugger can be used to analyze data you've previously collected (i.e., to confirm the values of variables).
......
The Gii code generation tool
============================
> Note: This chapter is under development.
Yii includes a handy tool, named Gii, that provides rapid prototyping by generating commonly used code snippets
as well as complete CRUD controllers.
......
Advanced application template
=============================
This template is for large projects developed in teams where backend is divided from frontend, application is deployed
> Note: This chapter is under development.
This template is for large projects developed in teams where the backend is divided from the frontend, application is deployed
to multiple servers etc. This application template also goes a bit further regarding features and provides essential
database, signup and password restore out of the box.
......@@ -14,7 +16,7 @@ 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
curl -sS http://getcomposer.org/installer | php
~~~
You can then install the application using the following command:
......@@ -33,9 +35,13 @@ the installed application. You only need to do these once for all.
```
php /path/to/yii-application/init
```
Otherwise, in production execute `init` in non-interactive mode.
```
php /path/to/yii-application/init --env=prod overwrite=n
```
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`.
4. Set document roots of your Web server:
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/`
......@@ -68,16 +74,20 @@ Root directory contains a set of files.
Predefined path aliases
-----------------------
- @yii - framework directory.
- @app - base path of currently running application.
- @common - common directory.
- @frontend - frontend web application directory.
- @backend - backend web application directory.
- @console - console directory.
- @runtime - runtime directory of currently running web application.
- @vendor - Composer vendor directory.
- @web - base URL of currently running web application.
- @webroot - web root directory of currently running web application.
- `@yii` - framework directory.
- `@app` - base path of currently running application.
- `@common` - common directory.
- `@frontend` - frontend web application directory.
- `@backend` - backend web application directory.
- `@console` - console directory.
- `@runtime` - runtime directory of currently running web application.
- `@vendor` - Composer vendor directory.
- `@web` - base URL of currently running web application.
- `@webroot` - web root directory of currently running web application.
The aliases specific to the directory structure of the advanced application
(`@common`, `@frontend`, `@backend`, and `@console`) are defined in `common/config/aliases.php`.
Applications
------------
......@@ -88,29 +98,29 @@ cron jobs and low-level server management. Also it's used during application dep
There's also a `common` directory that contains files used by more than one application. For example, `User` model.
frontend and backend are both web applications and both contain `web` directory. That's the webroot you should point your
webserver to.
frontend and backend are both web applications and both contain the `web` directory. That's the webroot you should point your
web server to.
Each application has its own namespace and alias corresponding to its name. Same applies to common directory.
Configuration and environments
------------------------------
There are multiple problems with straightforward approach to configuration:
There are multiple problems with a typical approach to configuration:
- Each team member has its own configuration options. Committing such config will affect other team members.
- Production database password and API keys should not end up in repository.
- There are multiple servers: development, testing, production. Each should have its own configuration.
- Production database password and API keys should not end up in the repository.
- There are multiple server environments: development, testing, production. Each should have its own configuration.
- Defining all configuration options for each case is very repetitive and takes too much time to maintain.
In order to solve these issues Yii introduces environments concept that is very simple. Each environment is represented
by a set of files under `environments` directory. `init` command is used to switch between these. What it really does is
just copying everything from environment directory over the root directory where all applications are.
In order to solve these issues Yii introduces a simple environments concept. Each environment is represented
by a set of files under the `environments` directory. The `init` command is used to switch between these. What it really does is
copy everything from the environment directory over to the root directory where all applications are.
Typically environment contains application bootstrap files such as `index.php` and config files suffixed with
`-local.php`. These are added to `.gitignore` and never added to source code repository.
In order to avoid duplication configurations are overriding each other. For example, frontend reads configuration in the
In order to avoid duplication configurations are overriding each other. For example, the frontend reads configuration in the
following order:
- `common/config/main.php`
......@@ -134,7 +144,7 @@ Here's the full scheme:
Configuring Composer
--------------------
After application template is installed it's a good idea to adjust default `composer.json` that can be found in the root
After the application template is installed it's a good idea to adjust default `composer.json` that can be found in the root
directory:
```json
......@@ -184,7 +194,7 @@ directory:
First we're updating basic information. Change `name`, `description`, `keywords`, `homepage` and `support` to match
your project.
Now the interesting part. You can add more packages your application needs to `require` section.
Now the interesting part. You can add more packages your application needs to the `require` section.
All these packages are coming from [packagist.org](https://packagist.org/) so feel free to browse the website for useful code.
After your `composer.json` is changed you can run `php composer.phar update --prefer-dist`, wait till packages are downloaded and
......@@ -193,8 +203,8 @@ installed and then just use them. Autoloading of classes will be handled automat
Creating links from backend to frontend
---------------------------------------
Often it's required to create links from backend application to frontend application. Since frontend application may
contain its own URL manager rules you need to duplicate that for backend application by naming it differently:
Often it's required to create links from the backend application to the frontend application. Since the frontend application may
contain its own URL manager rules you need to duplicate that for the backend application by naming it differently:
```php
return [
......@@ -210,7 +220,7 @@ return [
];
```
After it is done, you can get URL pointing to frontend like the following:
After it is done, you can get an URL pointing to frontend like the following:
```php
echo Yii::$app->urlManagerFrontend->createUrl(...);
......
Console applications
====================
Yii has full featured support of console. Console application structure in Yii is very similar to web application. It
consists of one or more [[yii\console\Controller]] (often referred to as commands). Each has one or more actions.
> Note: This chapter is under development.
Yii has full featured support for console applications, whose structure is very similar to a Yii web application. A console application
consists of one or more [[yii\console\Controller]] classes, which are often referred to as "commands" in the console environment. Each controller can also have one or more actions, just like web controllers.
Usage
-----
You can execute controller action using the following syntax:
You execute a console controller action using the following syntax:
```
yii <route> [--option1=value1 --option2=value2 ... argument1 argument2 ...]
```
For example, [[yii\console\controllers\MigrateController::actionCreate()|MigrateController::actionCreate()]]
For example, the [[yii\console\controllers\MigrateController::actionCreate()|MigrateController::actionCreate()]]
with [[yii\console\controllers\MigrateController::$migrationTable|MigrateController::$migrationTable]] set can
be called from command line like the following:
be called from command line like so:
```
yii migrate/create --migrationTable=my_migration
```
In the above `yii` is console application entry script described below.
In the above `yii` is the console application entry script described below.
Entry script
------------
Console application entry script is typically called `yii`, located in your application root directory and contains
The console application entry script is equivalent to the `index.php` bootstrap file used for the web application. The console entry script is typically called `yii`, and located in your application's root directory. The contents of the console application entry script contains
code like the following:
```php
......@@ -34,10 +36,6 @@ code like the following:
<?php
/**
* Yii console bootstrap file.
*
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
defined('YII_DEBUG') or define('YII_DEBUG', true);
......@@ -57,24 +55,23 @@ exit($exitCode);
```
This script is a part of your application so you're free to adjust it. The `YII_DEBUG` constant can be set `false` if you do
not want to see stack trace on error and want to improve overall performance. In both basic and advanced application
templates it is enabled to provide more developer-friendly environment.
This script will be created as part of your application; you're free to edit it to suit your needs. The `YII_DEBUG` constant can be set `false` if you do
not want to see a stack trace on error, and/or if you want to improve the overall performance. In both basic and advanced application
templates, the console application entry script has debugging enabled to provide a more developer-friendly environment.
Configuration
-------------
As can be seen in the code above, console application uses its own config files named `console.php`. In this file,
you should specify how to configure various application components and properties.
As can be seen in the code above, the console application uses its own configuration file, named `console.php`. In this file
you should configure various application components and properties for the console application in particular.
If your Web application and the console application share a lot of configurations, you may consider moving the common
part into a separate file, and include this file in both of the application configurations, just as what is done
in the "advanced" application template.
If your web application and the console application share a lot of configuration parameters and values, you may consider moving the common
parts into a separate file, and including this file in both of the application configurations (web and console). You can see an example of this in the "advanced" application template.
Sometimes, you may want to run a console command using an application configuration that is different from the one
specified in the entry script. For example, you may want to use the `yii migrate` command to upgrade your
test databases which are configured in each individual test suite. To do so, simply specify the custom application configuration
file via the `appconfig` option, like the following,
test databases, which are configured in each individual test suite. To do change the configuration dynamically, simply specify a custom application configuration
file via the `appconfig` option when executing the command:
```
yii <route> --appconfig=path/to/config.php ...
......@@ -87,33 +84,32 @@ Creating your own console commands
### Console Controller and Action
A console command is defined as a controller class extending from [[yii\console\Controller]]. In the controller class,
you define one or several actions that correspond to the sub-commands of the command. Within each action, you write code
to implement certain tasks for that particular sub-command.
you define one or more actions that correspond to sub-commands of the controller. Within each action, you write code that implements the appropriate tasks for that particular sub-command.
When running a command, you need to specify the route to the corresponding controller action. For example,
the route `migrate/create` specifies the sub-command corresponding to the
When running a command, you need to specify the route to the controller action. For example,
the route `migrate/create` invokes the sub-command that corresponds to the
[[yii\console\controllers\MigrateController::actionCreate()|MigrateController::actionCreate()]] action method.
If a route does not contain an action ID, the default action will be executed.
If a route offered during execution does not contain an action ID, the default action will be executed (as with a web controller).
### Options
By overriding the [[yii\console\Controller::options()]] method, you can specify options that are available
to a console command (controller/actionID). The method should return a list of public property names of the controller class.
to a console command (controller/actionID). The method should return a list of the controller class's public properties.
When running a command, you may specify the value of an option using the syntax `--OptionName=OptionValue`.
This will assign `OptionValue` to the `OptionName` property of the controller class.
If the default value of an option is of array type, then if you set this option while running the command,
the option value will be converted into an array by splitting the input string by commas.
If the default value of an option is of an array type and you set this option while running the command,
the option value will be converted into an array by splitting the input string on any commas.
### Arguments
Besides options, a command can also receive arguments. The arguments will be passed as the parameters to the action
method corresponding to the requested sub-command. The first argument corresponds to the first parameter, the second
corresponds to the second, and so on. If there are not enough arguments are provided, the corresponding parameters
may take the declared default values, or if they do not have default value the command will exit with an error.
corresponds to the second, and so on. If not enough arguments are provided when the command is called, the corresponding parameters
will take the declared default values, if defined. If no default value is set, and no value is provided at runtime, the command will exit with an error.
You may use `array` type hint to indicate that an argument should be treated as an array. The array will be generated
by splitting the input string by commas.
You may use the `array` type hint to indicate that an argument should be treated as an array. The array will be generated
by splitting the input string on commas.
The follow examples show how to declare arguments:
......@@ -136,13 +132,12 @@ class ExampleController extends \yii\console\Controller
### Exit Code
Using exit codes is the best practice of console application development. If a command returns `0` it means
everything is OK. If it is a number greater than zero, we have an error and the number returned is the error
code that may be interpreted to find out details about the error.
For example `1` could stand generally for an unknown error and all codes above are declared for specific cases
such as input errors, missing files, and so forth.
Using exit codes is a best practice for console application development. Conventionally, a command returns `0` to indicate that
everything is OK. If the command returns a number greater than zero, that's considered to be indicative of an error. The number returned will be the error
code, potentially usable to find out details about the error.
For example `1` could stand generally for an unknown error and all codes above would be reserved for specific cases: input errors, missing files, and so forth.
To have your console command return with an exit code you simply return an integer in the controller action
To have your console command return an exit code, simply return an integer in the controller action
method:
```php
......
Error Handling
==============
> Note: This chapter is under development.
Error handling in Yii is different than handling errors in plain PHP. First of all, Yii will convert all non-fatal errors
to *exceptions*:
......
Internationalization
====================
> Note: This chapter is under development.
Internationalization (I18N) refers to the process of designing a software application so that it can be adapted to
various languages and regions without engineering changes. For Web applications, this is of particular importance
because the potential users may be worldwide.
......
Logging
=======
> Note: This chapter is under development.
Yii provides flexible and extensible logger that is able to handle messages according to severity level or their type.
You may filter messages by multiple criteria and forward them to files, email, debugger etc.
......
Performance Tuning
==================
> Note: This chapter is under development.
The performance of your web application is based upon two parts. First is the framework performance
and the second is the application itself. Yii has a pretty low performance impact
on your application out of the box and can be fine-tuned further for production
......
Creating your own Application structure
=======================================
> Note: This chapter is under development.
While [basic](apps-basic.md) and [advanced](apps-advanced.md) application templates are great for most of your needs
you may want to create your own application template to start your projects with.
......
Using template engines
======================
> Note: This chapter is under development.
By default, Yii uses PHP as its template language, but you can configure Yii to support other rendering engines, such as
[Twig](http://twig.sensiolabs.org/) or [Smarty](http://www.smarty.net/).
......@@ -37,7 +39,7 @@ your `composer.json` file to include them, too:
"yiisoft/yii2-smarty": "*",
"yiisoft/yii2-twig": "*",
```
That code would be added to the `require` section of `composer.json`. After making that change and saving the file, you can install the extensions by running `composer update --preder-dist` in the command-line.
That code would be added to the `require` section of `composer.json`. After making that change and saving the file, you can install the extensions by running `composer update --prefer-dist` in the command-line.
Twig
----
......@@ -50,15 +52,35 @@ or `$this->renderPartial()` controller calls:
echo $this->render('renderer.twig', ['username' => 'Alex']);
```
### Additional functions
### Additional syntax
Yii adds some extra syntax constructs additionally to standard Twig ones.
###
{{registerAssetBundle('AppAsset')}} - Registers asset bundle of a given name
Yii adds the following construct to the standard Twig syntax:
### Forms
```
{% set form = form_begin({ ... }) %}
{{ form.field(...) }}
{% form.end() %}
```
#### Getting URL for a route
There are two functions you can use for URLs:
```php
<a href="{{ path('blog/view', {'alias' : post.alias}) }}">{{ post.title }}</a>
<a href="{{ url('blog/view', {'alias' : post.alias}) }}">{{ post.title }}</a>
```
Internally, the `path()` function calls Yii's `Url::to()` method.
`path` generates relative URL while `url` generates absolute one. Internally both are using [[\yii\helpers\Url]].
### Additional variables
......
Theming
=======
> Note: This chapter is under development.
A theme is a directory of view and layout files. Each file of the theme overrides corresponding file of an application
when rendered. A single application may use multiple themes and each may provide totally different experience. At any
time only one theme can be active.
......
Yii2 class loader
=================
Yii 2 class loader is PSR-4 compliant. That means it can handle most of the PHP
libraries and frameworks out there.
In order to autoload a library you need to set a root alias for it.
PEAR-style libraries
--------------------
```php
\Yii::setAlias('@Twig', '@app/vendors/Twig');
```
References
----------
- BaseYii::autoload
Automation
==========
There are some tasks that are done automatically when working on Yii:
- Generation of the classmap `classes.php` located under the framework root directory.
Run `./build/build classmap` to generate it.
- Generation of the `@property` annotations in class files that describe properties introduced by getters and setters.
Run `./build/build php-doc/property` to update them.
- Fixing of code style and other minor issues in phpdoc comments.
Run `./build/build php-doc/fix` to run the command.
Check the changes before you commit them as there may be unwanted changes because the command is not perfect.
You may use `git add -p` to review the changes.
Working with Database
=====================
Architecture
------------
### Data Access Object (DAO)
* Connection
* Command
* DataReader
* Transaction
### Schema
* TableSchema
* ColumnSchema
### Query Builder
* Query
* QueryBuilder
### ActiveRecord
* ActiveRecord
* ActiveQuery
\ No newline at end of file
......@@ -33,3 +33,41 @@ If you're not core developer or want to use your own fork for pull requests:
maintainer is the same for all extensions you require via composer.
Please refer to [Git workflow for Yii 2 contributors](git-workflow.md) for details about creating pull requests.
An Alternative way
------------------
1. Clone your fork of yii2 `git clone git@github.com:<yourname>/yii2`.
2. Change into the repo folder `cd yii2`.
3. run `./build/build app/link basic` to install composer dependecies for the basic app.
This command will install foreign composer packages as normal but will link the yii2 repo to
the currently checked out repo, so you have one instance of all the code installed.
4. Do the same for the advanced app if needed: `./build/build app/link advanced`
This command will also be used to update dependecies, it runs `composer update` internally.
5. Now you have a working playground for hacking on Yii 2.
You may also add the yii2 upstream repo to pull the latest changes:
```
git remote add upstream https://github.com/yiisoft/yii2.git
```
### Unit tests
To run the unit tests you have to install composer packages for the dev-repo.
Run `composer update` in the repo root directory to get the latest packages.
You can now execute unit tests by running `./vendor/bin/phpunit`.
You may limit the tests to a group of tests you are working on e.g. to run only tests for the validators and redis
`./vendor/bin/phpunit --group=validators,redis`.
### Extensions
To work on extensions you have to install them in the application you want to try them in.
Just add them to the `composer.json` as you would normally do e.g. add `"yiisoft/yii2-redis": "*"` to the
`require` section of the basic app.
Running `./build/build app/link basic` will install the extension and its dependecies and create
a symlink to `extensions/redis` so you are not working the composer vendor dir but the yii2 repo directly.
......@@ -24,16 +24,16 @@ Change to the directory where you cloned Yii, normally, "yii2". Then enter the f
git remote add upstream git://github.com/yiisoft/yii2.git
```
### 3. Make sure there is an issue created for the thing you are working on.
### 3. Make sure there is an issue created for the thing you are working on if it requires signifcant effort to fix
All new features and bug fixes should have an associated issue to provide a single point of reference for discussion
and documentation. Take a few minutes to look through the existing issue list for one that matches the contribution you
intend to make. If you find one already on the issue list, then please leave a comment on that issue indicating you
intend to work on that item. If you do not find an existing issue matching what you intend to work on, please open a
new issue for your item. This will allow the team to review your suggestion, and provide appropriate feedback along
new issue for your item or create a pull request directly if it is straightforward fix. This will allow the team to review your suggestion, and provide appropriate feedback along
the way.
> For small changes or documentation issues, you don't need to create an issue, a pull request is enough in this case.
> For small changes or documentation issues or straightforward fixes, you don't need to create an issue, a pull request is enough in this case.
### 4. Fetch the latest code from the main Yii branch
......
......@@ -27,3 +27,17 @@ In the translation file each array element represents the translation (value) of
the message is considered as not translated. Messages that no longer need translation will have their translations
enclosed between a pair of '@@' marks. Message string can be used with plural forms format. Check [i18n section
of the guide](../guide/i18n.md) for details.
Documentation
-------------
Put documentation translations under `docs/<original>-<language>` where `<original>` is the original documentation name
such as `guide` or `internals` and `<language>` is the language code of the language docs are translated to. For the
Russian guide translation it is `docs/guide-ru`.
After initial work is done you can get what's changed since last translation of the file using a special command from
`build` directory:
```
build translation ../docs/guide" "../docs/guide-ru" --title="Russian guide translation report" > report-guide-ru.html
```
......@@ -83,9 +83,6 @@ class GuideController extends BaseController
*/
protected function findFiles($path, $except = [])
{
if (empty($except)) {
$except = ['README.md'];
}
$path = FileHelper::normalizePath($path);
$options = [
'only' => ['*.md'],
......
......@@ -23,7 +23,8 @@
"yiisoft/yii2-bootstrap": "*",
"phpdocumentor/reflection": ">=1.0.3",
"phpdocumentor/reflection-docblock": ">2.0.1",
"nikic/php-parser": "0.9.*"
"nikic/php-parser": "0.9.*",
"cebe/js-search": "*"
},
"autoload": {
"psr-4": { "yii\\apidoc\\": "" }
......
<?php
/**
*
*
* @author Carsten Brandt <mail@cebe.cc>
*/
namespace yii\apidoc\helpers;
use cebe\jssearch\Indexer;
use cebe\jssearch\tokenizer\StandardTokenizer;
use cebe\jssearch\TokenizerInterface;
use yii\helpers\StringHelper;
class ApiIndexer extends Indexer
{
protected function generateFileInfo($file, $contents, $basePath, $baseUrl)
{
// create file entry
if (preg_match('~<h1>(.*?)</h1>~s', $contents, $matches)) {
$title = str_replace('&para;', '', strip_tags($matches[1]));
} elseif (preg_match('~<title>(.*?)</title>~s', $contents, $matches)) {
$title = strip_tags($matches[1]);
} else {
$title = '<i>No title</i>';
}
if (preg_match('~<div id="classDescription">\s*<strong>(.*?)</strong>~s', $contents, $matches)) {
$description = strip_tags($matches[1]);
} elseif (preg_match('~<p>(.*?)</p>~s', $contents, $matches)) {
$description = strip_tags($matches[1]);
if (mb_strlen($description) > 1000) { // TODO truncate by words
$description = mb_substr($description, 0, 1000) . '...';
}
} else {
$description = '';
}
return [
'u' => $baseUrl . str_replace('\\', '/', substr($file, strlen(rtrim($basePath, '\\/')))),
't' => $title,
'd' => $description,
];
}
/**
* @return TokenizerInterface
*/
public function getTokenizer()
{
$tokenizer = parent::getTokenizer();
if ($tokenizer instanceof StandardTokenizer) {
// yii is part of every doc and makes weird search results
$tokenizer->stopWords[] = 'yii';
$tokenizer->stopWords = array_unique($tokenizer->stopWords);
}
return $tokenizer;
}
}
\ No newline at end of file
......@@ -192,7 +192,6 @@ class Context extends Component
return $this->inheritMethodRecursive($method, $parent);
}
}
return $method;
}
......@@ -209,7 +208,7 @@ class Context extends Component
if ($method->isStatic) {
continue;
}
if (!strncmp($name, 'get', 3) && $this->paramsOptional($method)) {
if (!strncmp($name, 'get', 3) && strlen($name) > 3 && $this->paramsOptional($method)) {
$propertyName = '$' . lcfirst(substr($method->name, 3));
if (isset($class->properties[$propertyName])) {
$property = $class->properties[$propertyName];
......@@ -238,7 +237,7 @@ class Context extends Component
]);
}
}
if (!strncmp($name, 'set', 3) && $this->paramsOptional($method, 1)) {
if (!strncmp($name, 'set', 3) && strlen($name) > 3 && $this->paramsOptional($method, 1)) {
$propertyName = '$' . lcfirst(substr($method->name, 3));
if (isset($class->properties[$propertyName])) {
$property = $class->properties[$propertyName];
......@@ -282,7 +281,6 @@ class Context extends Component
return false;
}
}
return true;
}
......@@ -297,7 +295,6 @@ class Context extends Component
return $param;
}
}
return null;
}
......@@ -320,7 +317,6 @@ class Context extends Component
return true;
}
}
return false;
}
}
......@@ -8,7 +8,9 @@
namespace yii\apidoc\templates\bootstrap;
use Yii;
use yii\apidoc\helpers\ApiIndexer;
use yii\helpers\Console;
use yii\helpers\FileHelper;
/**
*
......@@ -76,6 +78,16 @@ class ApiRenderer extends \yii\apidoc\templates\html\ApiRenderer
if ($this->controller !== null) {
$this->controller->stdout('done.' . PHP_EOL, Console::FG_GREEN);
$this->controller->stdout('generating search index...');
}
$indexer = new ApiIndexer();
$indexer->indexFiles(FileHelper::findFiles($targetDir, ['only' => ['*.html']]), $targetDir);
$js = $indexer->exportJs();
file_put_contents($targetDir . '/jssearch.index.js', $js);
if ($this->controller !== null) {
$this->controller->stdout('done.' . PHP_EOL, Console::FG_GREEN);
}
}
......
......@@ -8,6 +8,9 @@
namespace yii\apidoc\templates\bootstrap;
use Yii;
use yii\apidoc\helpers\ApiIndexer;
use yii\helpers\Console;
use yii\helpers\FileHelper;
/**
*
......@@ -38,5 +41,18 @@ class GuideRenderer extends \yii\apidoc\templates\html\GuideRenderer
}
parent::render($files, $targetDir);
if ($this->controller !== null) {
$this->controller->stdout('generating search index...');
}
$indexer = new ApiIndexer();
$indexer->indexFiles(FileHelper::findFiles($targetDir, ['only' => ['*.html']]), $targetDir);
$js = $indexer->exportJs();
file_put_contents($targetDir . '/jssearch.index.js', $js);
if ($this->controller !== null) {
$this->controller->stdout('done.' . PHP_EOL, Console::FG_GREEN);
}
}
}
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\apidoc\templates\bootstrap\assets;
use yii\web\View;
/**
* The asset bundle for the offline template.
*
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
class JsSearchAsset extends \yii\web\AssetBundle
{
public $sourcePath = '@vendor/cebe/js-search';
public $js = [
'jssearch.js',
];
public $depends = [
'yii\web\JqueryAsset',
];
public $jsOptions = [
'position' => View::POS_HEAD,
];
}
......@@ -109,3 +109,73 @@ table.summary-table .col-defined { width: 15%; }
color: #bbb;
text-decoration: none;
}
#search-resultbox {
position: fixed;
left: 25%;
right: 25%;
bottom: 0;
top: 50px;
z-index: 1000;
border-radius: 0;
/* reset all due to android browser issues http://caniuse.com/#search=border-radius */
border-top-left-radius: 0;
border-top-right-radius: 0;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
#search-results {
margin: 0;
padding: 0;
list-style: none;
overflow: auto;
max-height: 100%;
}
#search-results li, #search-results li a {
margin: 0;
padding: 0;
display: block;
min-height: 50px;
width: 100%;
color: #333333;
}
#search-results li a .title, #search-results li .no-results {
padding: 10px 20px 5px 20px;
display: block;
text-decoration: none;
font-weight: bold;
font-size: 120%;
}
#search-results li a .description {
padding: 5px 20px 10px 20px;
display: block;
text-decoration: none;
font-weight: normal;
font-size: 90%;
border-bottom: solid 1px #dddddd;
}
#search-results li a:hover, #search-results li a.selected {
background: #44B5F6;
text-decoration: none;
}
.navbar-form {
width: 50%;
max-width: 350px;
}
.navbar-form div, .navbar-form .form-control {
width: 100%;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment