Google News
logo
Yii framework Interview Questions
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 thought of as an acronym for Yes It Is!
Yii is a generic Web programming framework, meaning that it can be used for developing all kinds of Web applications using 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.
If you're already familiar with another framework, you may appreciate knowing how Yii compares :
 
* Like most PHP frameworks, Yii implements the MVC (Model-View-Controller) architectural pattern and promotes code organization based on that pattern.

* Yii takes the philosophy that code should be written in a simple yet elegant way. Yii will never try to over-design things mainly for the purpose of strictly following some design pattern.

* Yii is a full-stack framework providing many proven and ready-to-use features: query builders and ActiveRecord for both relational and NoSQL databases; RESTful API development support; multi-tier caching support; and more.

* Yii is extremely extensible. You can customize or replace nearly every piece of the core's code. You can also take advantage of Yii's solid extension architecture to 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 of professionals constantly contributing to Yii's development. The Yii developer team keeps a close eye on the latest Web development trends and on the best practices and features found in other frameworks and projects. The most relevant best practices and features found elsewhere are regularly incorporated into the core framework and exposed via simple and elegant interfaces.
Yii 2.0 requires PHP 5.4.0 or above and runs best with the latest version of PHP 7. You can find more detailed requirements for individual features by running the requirement checker included in every Yii release.
 
Using Yii requires basic knowledge of 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 and traits. Understanding these concepts will help you more easily pick up Yii 2.0.
Yii is so much faster because it is using the lazy loading technique extensively. For example, it does not include a class file until the class is used for the first time. And it does not create an object until the object is accessed for the first time. Other frameworks suffer from the performance hit because they enable functionality (e.g., DB connection, user session) no matter if it is used or not during a request.
The Yii 2.0 Framework helps to create modern web applications quickly and make sure they perform well. Yii 2.0 framework is :
 
* Easy to Install
* Utilizes Modern Technologies
* Highly Extensible
* Encourages Testing
* Simplifies Security
* Shorten Development Time
* Easy to Tune for Better Performance
Yii framework has the following main features, such as :
 
* Model-View-Controller (MVC) design pattern
* Database Access Objects (DAO), Query Builder, Active Record, and DB Migration
* Form input and validation
* AJAX-enabled widgets
* Yii provides a skinning and theming mechanism
* Web Service available for Apps like android
* Internationalization and localization translation for multilingual
* Caching to speed up the application
* Error handling and logging for tracking
It provides cross-site scripting (XSS), cross-site request forgery (CSRF) protection.
* PHPUnit and Selenium for testing
* Automatic code generation help us to fast development
* Authentication and authorization
* Friendly with third-party code
* Extension library
The following things are newly added in Yii version 2.0 :
 
* The Yii 2.0 framework supports PSR-4 class autoloading, simpler namespaces, faster loading, and improved usability for developers.
* The Yii 2.0 framework added performance and security improvements.
* The Yii 2.0 framework added RESTful API integration.
* The Yii 2.0 framework added improvement on URL handling and processing.
* Now Yii 2.0 framework, Translations of core messages available in 26 languages.
Yii applications are organized according to the model-view-controller (MVC) architectural pattern. Models represent data, business logic and rules; views are output representation of models; and controllers take input and convert it to commands for models and views.
 
Besides MVC, Yii applications also have the following entities :
 
entry scripts : they are PHP scripts that are directly accessible by end users. They are responsible for starting a request handling cycle.

applications : they are globally accessible objects that manage application components and coordinate them to fulfill requests.

application components : they are objects registered with applications and provide various services for fulfilling requests.

modules : they are self-contained packages that contain complete MVC by themselves. An application can be organized in terms of multiple modules.

filters : they represent code that need to be invoked before and after the actual handling of each request by controllers.

widgets : they are objects that can be embedded in views. They may contain controller logic and can be reused in different views.

The following diagram shows the static structure of an application:
YII Application Structure
Entry scripts are the first step in the application bootstrapping process. An application (either Web application or console application) has a single entry script. End users make requests to entry scripts which instantiate application instances and forward the requests to them.
 
Entry scripts for Web applications must be stored under Web accessible directories so that they can be accessed by end users. They are often named as index.php, but can also use any other names, provided Web servers can locate them.
 
Entry scripts for console applications are usually stored under the base path of applications and are named as yii (with the .php suffix). They should be made executable so that users can run console applications through the command ./yii <route> [arguments] [options].
 
Entry scripts mainly do the following work :
 
* Define global constants;
* Register Composer autoloader;
* Include the Yii class file;
* Load application configuration;
* Create and configure an application instance;
* Call yii\base\Application::run() to process the incoming request.

Web Applications : The following is the code in the entry script for the Basic Web Project Template.
<?php

defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');

// register Composer autoloader
require __DIR__ . '/../vendor/autoload.php';

// include Yii class file
require __DIR__ . '/../vendor/yiisoft/yii2/Yii.php';

// load application configuration
$config = require __DIR__ . '/../config/web.php';

// create, configure and run application
(new yii\web\Application($config))->run();
Console Applications : Similarly, the following is the code for the entry script of a console application:
#!/usr/bin/env php
<?php
/**
 * Yii console bootstrap file.
 *
 * @link https://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license https://www.yiiframework.com/license/
 */

defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');

// register Composer autoloader
require __DIR__ . '/vendor/autoload.php';

// include Yii class file
require __DIR__ . '/vendor/yiisoft/yii2/Yii.php';

// load application configuration
$config = require __DIR__ . '/config/console.php';

$application = new yii\console\Application($config);
$exitCode = $application->run();
exit($exitCode);
Defining Constants : Entry scripts are the best place for defining global constants. Yii supports the following three constants:
 
YII_DEBUG : specifies whether the application is running in debug mode. When in debug mode, an application will keep more log information, and will reveal detailed error call stacks if exceptions are thrown. For this reason, debug mode should be used mainly during development. The default value of YII_DEBUG is false.

YII_ENV : specifies which environment the application is running in. This will be described in more detail in the Configurations section. The default value of YII_ENV is 'prod', meaning the application is running in production environment.

YII_ENABLE_ERROR_HANDLER : specifies whether to enable the error handler provided by Yii. The default value of this constant is true.

When defining a constant, we often use the code like the following:
defined('YII_DEBUG') or define('YII_DEBUG', true);
which is equivalent to the following code:
if (!defined('YII_DEBUG')) {
    define('YII_DEBUG', true);
}
Clearly the former is more succinct and easier to understand.
 
Constant definitions should be done at the very beginning of an entry script so that they can take effect when other PHP files are being included.
Here are the following core components of Yii, such as:
 
db:- database connection.

assetManager : manage the publishing of private asset files

authManager : manage role-based access control

cache : manage to cache functionality

clientScript : manage javascript and CSS

coreMessages : provides translated core messages

errorHandler : manage errors handling.

themeManager : Manage themes

urlManager : URL parsing and creation functionality

statePersister : a mechanism for persisting global state

session : Session management

securityManager : Security Management
Yii framework requires the following things, such as :
 
* PHP 5.4 or above
* mbstring extension
* PCRE-support
You can install Yii2 by running these commands via composer :
composer global require "fxp/composer-asset-plugin:^1.3.1"  
composer create-project --prefer-dist yiisoft/yii2-app-basic basic  
Controllers are the glue that binds models, views, and other components together into a runnable application. Controllers are responsible for dealing directly with end-user requests. Therefore,
 
* Controllers may access $_GET, $_POST, and other PHP variables representing user requests.

* It may create model instances and manage their life cycles. Note that the actual implementation of saving a model should be located in the model instead of the controller.

* It should avoid containing embedded SQL statements, which are better kept in models.

* It should avoid containing any HTML or any other presentational markup, which is better kept in views.
Applications are objects that govern the overall structure and lifecycle of Yii application systems. Each Yii application system contains a single application object which is created in the entry script and is globally accessible through the expression \Yii::$app.
 
Info: Depending on the context, when we say "an application", it can mean either an application object or an application system.
 
There are two types of applications : Web applications and console applications. As the names indicate, the former mainly handles Web requests, while the latter handles console command requests.
 
Application Configurations : When an entry script creates an application, it will load a configuration and apply it to the application, as follows:
require __DIR__ . '/../vendor/autoload.php';
require __DIR__ . '/../vendor/yiisoft/yii2/Yii.php';

// load application configuration
$config = require __DIR__ . '/../config/web.php';

// instantiate and configure the application
(new yii\web\Application($config))->run();
Like normal configurations, application configurations specify how to initialize properties of application objects. Because application configurations are often very complex, they usually are kept in configuration files, like the web.php file in the above example.
Applications are service locators. They host a set of the so-called application components that provide different services for processing requests. For example, the urlManager component is responsible for routing Web requests to appropriate controllers; the db component provides DB-related services; and so on.
 
Each application component has an ID that uniquely identifies itself among other application components in the same application. You can access an application component through the expression:
\Yii::$app->componentID
For example, you can use \Yii::$app->db to get the DB connection, and \Yii::$app->cache to get the primary cache registered with the application.
 
An application component is created the first time it is accessed through the above expression. Any further accesses will return the same component instance.
 
Application components can be any objects. You can register them by configuring the yii\base\Application::$components property in application configurations.

For example :
[
    'components' => [
        // register "cache" component using a class name
        'cache' => 'yii\caching\ApcCache',

        // register "db" component using a configuration array
        'db' => [
            'class' => 'yii\db\Connection',
            'dsn' => 'mysql:host=localhost;dbname=demo',
            'username' => 'root',
            'password' => '',
        ],

        // register "search" component using an anonymous function
        'search' => function () {
            return new app\components\SolrService;
        },
    ],
]
Models are part of the MVC architecture. They are objects representing business data, rules and logic.
 
You can create model classes by extending yii\base\Model or its child classes. The base class yii\base\Model supports many useful features:
 
Attributes : represent the business data and can be accessed like normal object properties or array elements;

Attribute labels : specify the display labels for attributes;

Massive assignment : supports populating multiple attributes in a single step;

Validation rules : ensures input data based on the declared validation rules;

Data Exporting : allows model data to be exported in terms of arrays with customizable formats.

The Model class is also the base class for more advanced models, such as Active Record. Please refer to the relevant documentation for more details about these advanced models.
Views are responsible for presenting models in the format that end users desire. In general,
 
* Views should mainly contain presentational code, such as HTML and simple PHP code to traverse, format, and render data.

* It should avoid containing code that performs explicit DB queries. Such code is better placed in models.

* This is the controller's job. It should avoid direct access to $_GET, $_POST, or other similar variables representing the end-user request. The view should be focused on the display and layout of the data provided to it by the controller or model, but not attempting to access request variables or the database directly.

* It may access properties and methods of controllers and models directly. However, It should be done only for presentation.
Helpers are static classes in Yii that simplify common coding tasks, such as string or array manipulations, HTML code generation, etc. In Yii, all helpers are kept under the yii\helpers namespace.
 
You use a helper class in Yii by directly calling one of its static methods, as the following :
use yii\helpers\Html;  
echo Html::encode('Test > test'); 
Filters are objects that run before and/or after controller actions. For example, an access control filter may run before actions to ensure that they are allowed to be accessed by particular end users; a content compression filter may run after actions to compress the response content before sending them out to end users.
 
A filter may consist of a pre-filter (filtering logic applied before actions) and/or a post-filter (logic applied after actions).
Formatter is a Yii application component that is used format view data in readable format for users. By default, the formatter is implemented by yii\i18n\Formatter, which provides a set of methods to format data as date/time, numbers, currencies, and other commonly used formats. You can use the formatter as the following,
$formatter = \Yii::$app->formatter;  
  
// output: January 1, 2021  
echo $formatter->asDate('2021-01-01', 'long');  
   
// output: 12.50%  
echo $formatter->asPercent(0.125, 2);  
   
// output: jtp@example.com  
echo $formatter->asEmail('jtp@example.com');   
  
// output: Yes  
echo $formatter->asBoolean(true);   
// it also handles display of null values:  
  
// output: (not set)  
echo $formatter->asDate(null);
Active Record provides an object-oriented interface for accessing and manipulating data stored in databases. 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 instance represents the value of a particular column in that row.
 
Instead of writing raw SQL statements, you would access Active Record attributes and call Active Record methods to access and manipulate the data stored in database tables.
To create a new action filter, extend from yii\base\ActionFilter and override the beforeAction() and/or afterAction() methods. The former will be executed before an action runs while the latter after an action runs. The return value of beforeAction() determines whether an action should be executed or not. If it is false, the filters after this one will be skipped and the action will not be executed.
 
The following example shows a filter that logs the action execution time :
namespace app\components;

use Yii;
use yii\base\ActionFilter;

class ActionTimeFilter extends ActionFilter
{
    private $_startTime;

    public function beforeAction($action)
    {
        $this->_startTime = microtime(true);
        return parent::beforeAction($action);
    }

    public function afterAction($action, $result)
    {
        $time = microtime(true) - $this->_startTime;
        Yii::debug("Action '{$action->uniqueId}' spent $time second.");
        return parent::afterAction($action, $result);
    }
}
Widgets are reusable building blocks used in views to create complex and configurable user interface elements in an object-oriented fashion. For example, a date picker widget may generate a fancy date picker that allows users to pick a date as their input. All you need to do is just to insert the code in a view like the following :
<?php
use yii\jui\DatePicker;
?>
<?= DatePicker::widget(['name' => 'date']) ?>
There are a good number of widgets bundled with Yii, such as active form, menu, jQuery UI widgets, Twitter Bootstrap widgets. In the following, we will introduce the basic knowledge about widgets. Please refer to the class API documentation if you want to learn about the usage of a particular widget.
 
Using Widgets : Widgets are primarily used in views. You can call the yii\base\Widget::widget() method to use a widget in a view. The method takes a configuration array for initializing the widget and returns the rendering result of the widget. For example, the following code inserts a date picker widget which is configured to use the Russian language and keep the input in the from_date attribute of $model.
<?php
use yii\jui\DatePicker;
?>
<?= DatePicker::widget([
    'model' => $model,
    'attribute' => 'from_date',
    'language' => 'ru',
    'dateFormat' => 'php:Y-m-d',
]) ?>
Some widgets can take a block of content which should be enclosed between the invocation of yii\base\Widget::begin() and yii\base\Widget::end(). For example, the following code uses the yii\widgets\ActiveForm widget to generate a login form. The widget will generate the opening and closing <form> tags at the place where begin() and end() are called, respectively. Anything in between will be rendered as is.
<?php
use yii\widgets\ActiveForm;
use yii\helpers\Html;
?>

<?php $form = ActiveForm::begin(['id' => 'login-form']); ?>

    <?= $form->field($model, 'username') ?>

    <?= $form->field($model, 'password')->passwordInput() ?>

    <div class="form-group">
        <?= Html::submitButton('Login') ?>
    </div>

<?php ActiveForm::end(); ?>
 
Note that unlike yii\base\Widget::widget() which returns the rendering result of a widget, the method yii\base\Widget::begin() returns an instance of the widget which you can use to build the widget content.
 
 
Configuring global defaults : Global defaults for a widget type could be configured via DI container :
\Yii::$container->set('yii\widgets\LinkPager', ['maxButtonCount' => 5]);
Gii is a web-based code-generator module provided by the Yii framework. It helps to create and generate fully customized forms, models, CRUD for databases, and more.
 
We can enable Gii by configuring it in the modules property of the application. Depending upon how we created our application. You may find the following code is already provided in the config/web.php configuration file :
$config = [ ... ];  
  
if (YII_ENV_DEV) {  
    $config['bootstrap'][] = 'gii';  
    $config['modules']['gii'] = [  
        'class' => 'yii\gii\Module',  
    ];  
} ​
 
Yii has the following benefits over other frameworks of PHP :
 
* The Yii framework is a generic Web programming framework used for developing all kinds of Web applications quickly using PHP. It is also very suitable for developing large-scale applications.
* The primary goal of the Yii or Yii 2.0 framework is - high performance.
* The Yii framework is a full-stack framework and ready-to-use features for both the relational and NoSQL databases.
* The Yii framework implements the MVC (Model-View-Controller) architectural pattern.
* The Yii framework is extremely extensible.
* The Yii framework contains the Larger Community, and it also purchased an unlimited license to the beautiful web-based rich text editor and Redactor.
index.php is the first file that loaded when we run an application using the Yii application. It will create a new object of new yii\web\Application and start the application.
require(__DIR__ . '/../vendor/autoload.php');  
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');  
  
// load application configuration  
$config = require(__DIR__ . '/../config/web.php');  
  
// instantiate and configure the application  
(new yii\web\Application($config))->run(); ​
 
In the latest version of Yii Framework uses a simple standard to set names.
 
* You can define the table prefix when using Gii. In your case, you need to set it to tbl_. Then it should generate UserController instead of TblUserController.

* The Yii Framework employs a class naming convention whereby the names of the classes directly map to the directories in which they are stored. The root-level directory of the Yii Framework is the "framework/" directory, under which all classes are stored hierarchically.

* Class names may only contain alphanumeric characters. Numbers are permitted in class names but are discouraged. A dot (.) is only permitted in place of the path separator.

Routes that refer respectively to module, controller, and the action requested take the following format:
 
ModuleID/ControllerID/ActionID
 
* The ModuleID is optional. The ModuleID must be specified in the module's configuration property under the same name.

* The ControllerID and ActionID should contain only English characters in lowercase, digits, underscores, dashes, and forward slashes.

* URL Conventions: By default, Yii recognizes URLs with the following format :
http://hostname/index.php?r=ControllerID/ActionID ​

The r refers to the route.

Yii CModel is the base class that provides the common features needed by data model objects. CModel defines the basic framework for data models that need to be validated. All Models in Yii extend CModel class.
The Request Life Cycle in the Yii2 framework explains in the following stages :
Life Cycle in YII Framework
 
1. Pre-initialize the application with CApplication::preinit();
2. Set up the error handling;
3. Register core application components;
4. Load application configuration;
5. Initialize the application with CApplication::init()
* Register application behaviors;
* Load static application components;
6. Raise an onBeginRequest event;
7. Process the user request.
* Collect information about the request;
* Create a controller;
* Run the controller;
8. Raise an onEndRequest event;
Extensions are redistributable software packages specifically designed to be used in Yii applications and provide ready-to-use features. For example, the yiisoft/yii2-debug extension adds a handy debug toolbar at the bottom of every page in your application to help you more easily grasp how the pages are generated. You can use extensions to accelerate your development process. You can also package your code as extensions to share with other people your great work.
 
Info : We use the term "extension" to refer to Yii-specific software packages. For general purpose software packages that can be used without Yii, we will refer to them using the term "package" or "library".
 
Using Extensions : To use an extension, you need to install it first. Most extensions are distributed as Composer packages which can be installed by taking the following two simple steps:
 
modify the composer.json file of your application and specify which extensions (Composer packages) you want to install.
run composer install to install the specified extensions.
 
By default, Composer installs packages registered on Packagist - the biggest repository for open source Composer packages. You can look for extensions on Packagist. You may also create your own repository and configure Composer to use it. This is useful if you are developing private extensions that you want to share within your projects only.
 
Extensions installed by Composer are stored in the BasePath/vendor directory, where BasePath refers to the application's base path. Because Composer is a dependency manager, when it installs a package, it will also install all its dependent packages.
 
For example, to install the yiisoft/yii2-imagine extension, modify your composer.json like the following :
{
    // ...

    "require": {
        // ... other dependencies

        "yiisoft/yii2-imagine": "*"
    }
}
After the installation, you should see the directory yiisoft/yii2-imagine under BasePath/vendor. You should also see another directory imagine/imagine which contains the installed dependent package.
 
Info : The yiisoft/yii2-imagine is a core extension developed and maintained by the Yii developer team. All core extensions are hosted on Packagist and named like yiisoft/yii2-xyz, where xyz varies for different extensions.
 
Now you can use the installed extensions like they are part of your application. The following example shows how you can use the yii\imagine\Image class provided by the yiisoft/yii2-imagine extension:
use Yii;
use yii\imagine\Image;

// generate a thumbnail image
Image::thumbnail('@webroot/img/test-image.jpg', 120, 120)
    ->save(Yii::getAlias('@runtime/thumb-test-image.jpg'), ['quality' => 50]);
YiiBase is a helper class that serves functionalities of a common framework. It would be best if you did not use YiiBase directly. Instead, have to use its child class where we can customize the methods of YiiBase.
After creating a model class file, we shall generate the code that implements the CRUD operations for user data. We choose the Crud Generator in Gii. In the model class field, we enter 'User'. In the Controller ID field, we enter 'user' in lower case. Then press the preview button followed by the Generate button. Now we are done with the CRUD code generation.
To create a module, access the gii url, and there you can create a module. After creating a module, you need to add it to the main configuration file of your Yii application.
localhost/your-app/index.php?r=gii // utl to access gii  
 ....  
   'modules' =>  array(  
                'module-name',  
                 'other-module',  
                  'user' =>  array(  
                        'activeAfterRegister' =>  false,  
                ),  
  .....  
The following core helper classes are :
 
* ArrayHelper
* Console
* FileHelper
* FormatConverter
* Html
* HtmlPurifier
* Imagine
* Inflector
* Json
* Markdown
* StringHelper
* Url
* VarDumper
To customize a core helper class, we should create a new class extending from the helper base class. For example :
< ?php  
namespace yii\helpers;  
  
class ArrayHelper extends BaseArrayHelper  
{  
    public static function merge($x, $y)  
    {  
        // your custom implementation  
    }  
}​
 
You can set or change the default controller in Yii by using the default yii2 advanced template that redirects to URL :
 
1) Add below code on backend main/config.php user component :
'components' => [  
        'user' => [  
            'identityClass' => 'common\models\User',  
            'enableAutoLogin' => true,  
        'loginUrl' => [ 'yourcontroller/youraction' ],  
        ],  
2) Yii2 advanced template default controller is controllers/siteController. You can change it to your module or controller name by putting the below configuration in main/config.php :
'defaultRoute' => 'yourcontroller',
In Yii, CFormModel represents a data model that collects HTML form inputs. The data collected by CFormModel are stored in memory only instead of a database. Therefore to collect user inputs, you may extend CFormModel and define the attributes whose values are collected from user inputs.
To set session variables, you will need to apply a global PHP $_SESSION variable. Whereas to access the data stored in a session, you can do the following :
$session = Yii::$app->session;              // get a session variable.
Sessions and cookies allow data to be persisted across multiple user requests. In plain PHP you may access them through the global variables $_SESSION and $_COOKIE, respectively. Yii encapsulates sessions and cookies as objects and thus allows you to access them in an object-oriented fashion with additional useful enhancements.
 
Sessions : Like requests and responses, you can get access to sessions via the session application component which is an instance of yii\web\Session, by default.
 
Opening and Closing Sessions : To open and close a session, you can do the following:
$session = Yii::$app->session;

// check if a session is already open
if ($session->isActive) ...

// open a session
$session->open();

// close a session
$session->close();

// destroys all data registered to a session.
$session->destroy();

 

Cookies : Yii represents each cookie as an object of yii\web\Cookie. Both yii\web\Request and yii\web\Response maintain a collection of cookies via the property named cookies. The cookie collection in the former represents the cookies submitted in a request, while the cookie collection in the latter represents the cookies that are to be sent to the user.

 

The part of the application dealing with request and response directly is controller. Therefore, cookies should be read and sent in controller.

 

Reading Cookies : You can get the cookies in the current request using the following code:

// get the cookie collection (yii\web\CookieCollection) from the "request" component

$cookies = Yii::$app->request->cookies;



// get the "language" cookie value. If the cookie does not exist, return "en" as the default value.

$language = $cookies->getValue('language', 'en');



// an alternative way of getting the "language" cookie value

if (($cookie = $cookies->get('language')) !== null) {

    $language = $cookie->value;

}



// you may also use $cookies like an array

if (isset($cookies['language'])) {

    $language = $cookies['language']->value;

}



// check if there is a "language" cookie

if ($cookies->has('language')) ...

if (isset($cookies['language'])) ...


Sending Cookies : 
You can send cookies to end users using the following code : 

// get the cookie collection (yii\web\CookieCollection) from the "response" component

$cookies = Yii::$app->response->cookies;



// add a new cookie to the response to be sent

$cookies->add(new \yii\web\Cookie([

    'name' => 'language',

    'value' => 'zh-CN',

]));



// remove a cookie

$cookies->remove('language');

// equivalent to the following

unset($cookies['language']);
Yii includes a built-in error handler which makes error handling a much more pleasant experience than before. In particular, the Yii error handler does the following to improve error handling :
 
* All non-fatal PHP errors (e.g. warnings, notices) are converted into catchable exceptions.
* Exceptions and fatal PHP errors are displayed with detailed call stack information and source code lines in debug mode.
* Supports using a dedicated controller action to display errors.
* Supports different error response formats.

The error handler is enabled by default. You may disable it by defining the constant YII_ENABLE_ERROR_HANDLER to be false in the entry script of your application.
 
Using Error Handler : The error handler is registered as an application component named errorHandler. You may configure it in the application configuration like the following :
return [
    'components' => [
        'errorHandler' => [
            'maxSourceLines' => 20,
        ],
    ],
];
With the above configuration, the number of source code lines to be displayed in exception pages will be up to 20.
 
As aforementioned, the error handler turns all non-fatal PHP errors into catchable exceptions. This means you can use the following code to deal with PHP errors :
use Yii;
use yii\base\ErrorException;

try {
    10/0;
} catch (ErrorException $e) {
    Yii::warning("Division by zero.");
}
// execution continues...
 
If you want to show an error page telling the user that his request is invalid or unexpected, you may simply throw an HTTP exception, such as yii\web\NotFoundHttpException. The error handler will correctly set the HTTP status code of the response and use an appropriate error view to display the error message.
use yii\web\NotFoundHttpException;

throw new NotFoundHttpException();
Yii provides a powerful logging framework that is highly customizable and extensible. Using this framework, you can easily log various types of messages, filter them, and gather them at different targets, such as files, databases, emails.
 
Using the Yii logging framework involves the following steps :
 
* Record log messages at various places in your code;
* Configure log targets in the application configuration to filter and export log messages;
* Examine the filtered logged messages exported by different targets (e.g. the Yii debugger).

In this section, we will mainly describe the first two steps.
 
Log Messages : Recording log messages is as simple as calling one of the following logging methods :
 
Yii::debug() : record a message to trace how a piece of code runs. This is mainly for development use.
Yii::info() : record a message that conveys some useful information.
Yii::warning() : record a warning message that indicates something unexpected has happened.
Yii::error() : record a fatal error that should be investigated as soon as possible.

These logging methods record log messages at various severity levels and categories. They share the same function signature function ($message, $category = 'application'), where $message stands for the log message to be recorded, while $category is the category of the log message. The code in the following example records a trace message under the default category application:
Yii::debug('start calculating average revenue');
Info : Log messages can be strings as well as complex data, such as arrays or objects. It is the responsibility of log targets to properly deal with log messages. By default, if a log message is not a string, it will be exported as a string by calling yii\helpers\VarDumper::export().
 
To better organize and filter log messages, it is recommended that you specify an appropriate category for each log message. You may choose a hierarchical naming scheme for categories, which will make it easier for log targets to filter messages based on their categories. A simple yet effective naming scheme is to use the PHP magic constant __METHOD__ for the category names. This is also the approach used in the core Yii framework code. For example : 
Yii::debug('start calculating average revenue', __METHOD__);
The __METHOD__ constant evaluates as the name of the method (prefixed with the fully qualified class name) where the constant appears. For example, it is equal to the string 'app\controllers\RevenueController::calculate' if the above line of code is called within this method.
 
Info : The logging methods described above are actually shortcuts to the log() method of the logger object which is a singleton accessible through the expression Yii::getLogger(). When enough messages are logged or when the application ends, the logger object will call a message dispatcher to send recorded log messages to the registered log targets.
 
Log Targets : A log target is an instance of the yii\log\Target class or its child class. It filters the log messages by their severity levels and categories and then exports them to some medium. For example, a database target exports the filtered log messages to a database table, while an email target exports the log messages to specified email addresses.
 
You can register multiple log targets in an application by configuring them through the log application component in the application configuration, like the following :
return [
    // the "log" component must be loaded during bootstrapping time
    'bootstrap' => ['log'],
    // the "log" component process messages with timestamp. Set PHP timezone to create correct timestamp
    'timeZone' => 'America/Los_Angeles',
    'components' => [
        'log' => [
            'targets' => [
                [
                    'class' => 'yii\log\DbTarget',
                    'levels' => ['error', 'warning'],
                ],
                [
                    'class' => 'yii\log\EmailTarget',
                    'levels' => ['error'],
                    'categories' => ['yii\db\*'],
                    'message' => [
                       'from' => ['log@example.com'],
                       'to' => ['admin@example.com', 'developer@example.com'],
                       'subject' => 'Database errors at example.com',
                    ],
                ],
            ],
        ],
    ],
];
Note : The log component must be loaded during bootstrapping time so that it can dispatch log messages to targets promptly. That is why it is listed in the bootstrap array as shown above.
 
In the above code, two log targets are registered in the yii\log\Dispatcher::$targets property :
 
the first target selects error and warning messages and saves them in a database table;

the second target selects error messages under the categories whose names start with yii\db\, and sends them in an email to both admin@example.com and developer@example.com.

Yii comes with the following built-in log targets. Please refer to the API documentation about these classes to learn how to configure and use them.
 
yii\log\DbTarget : stores log messages in a database table.
yii\log\EmailTarget : sends log messages to pre-specified email addresses.
yii\log\FileTarget : saves log messages in files.
yii\log\SyslogTarget : saves log messages to syslog by calling the PHP function syslog().
The difference between Yii & Yii2 is explained as :
Yii Yii2
Yii requires PHP 5.2. Yii 2.0 requires PHP 5.4.0 or higher, which makes use of the latest features of PHP.
In Yii, prefix C was used, and the classes were in global namespaces. In Yii2, prefix C is not used in namespaces. And classes based on the directory structure.
Yii uses the On-event method, where custom event names are not allowed to use. In Yii 2.0, any name can be used for the event with a handler attached to it, and event handling can be done using J-query.
Yii uses PHP as the primary template language. Yii 2.0 is equipped with PHP and two more template engines- TWIG and SMARTY.
Yii relies on the class autoloading mechanism to locate and include all required class files. It provides a high-performance class autoloader that is compliant with the PSR-4 standard. The autoloader is installed when you include the Yii.php file.
 
Note : For simplicity of description, in this section 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.
 
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 a namespace (e.g. foo\bar\MyClass)
* Each class must be saved in an individual file whose path is determined by the following algorithm:
// $className is a fully qualified class name without the leading backslash
$classFile = Yii::getAlias('@' . str_replace('\\', '/', $className) . '.php');
For example, if a class name and namespace is foo\bar\MyClass, the alias for the corresponding class file path would be @foo/bar/MyClass.php. In order for this alias to be resolvable into a file path, either @foo or @foo/bar must be a root alias.
 
When using the Basic Project Template, 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, and a class name like app\components\MyClass can be resolved into the class file AppBasePath/components/MyClass.php, according to the algorithm just described.
 
In the Advanced Project Template, each tier has its own root alias. For example, the front-end tier has a root alias @frontend, while the back-end tier root alias is @backend. As a result, you may put the front-end classes under the namespace frontend while the back-end classes are under backend. This will allow these classes to be autoloaded by the Yii autoloader.
 
To add a custom namespace to the autoloader you need to define an alias for the base directory of the namespace using Yii::setAlias(). For example to load classes in the foo namespace that are located in the path/to/foo directory you will call Yii::setAlias('@foo', 'path/to/foo').
 
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 checks. This makes class autoloading super fast. In fact, all core Yii classes are autoloaded this way.
 
You may add a class to the class map, stored in Yii::$classMap, using :
Yii::$classMap['foo\bar\MyClass'] = 'path/to/MyClass.php';
Aliases can be used to specify class file paths. You should set the class map in the bootstrapping process so that the map is ready before your classes are used.
 
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 3rd-party libraries that have their own autoloaders, you should also install those.
 
When 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 the first one responding to any class autoloading request. For example, the following code is extracted from the entry script of the Basic Project Template. The first line installs the Composer autoloader, while the second line installs the Yii autoloader:
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.
 
Autoloading Extension Classes : The Yii autoloader is capable of autoloading extension classes. The sole requirement is that an extension specifies the autoload section correctly in its composer.json file. Please refer to the Composer documentation 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.
A dependency injection (DI) container is an object that knows how to instantiate and configure objects and all their dependent objects. Martin Fowler's article has well explained why DI container is useful. Here we will mainly explain the usage of the DI container provided by Yii.
 
Dependency Injection : Yii provides the DI container feature through the class yii\di\Container. It supports the following kinds of dependency injection:
 
* Constructor injection;
* Method injection;
* Setter and property injection;
* PHP callable injection;
The DI container supports constructor injection with the help of type hints for constructor parameters. The type hints tell the container which classes or interfaces are dependent when it is used to create a new object. The container will try to get the instances of the dependent classes or interfaces and then inject them into the new object through the constructor.

For example :
class Foo
{
    public function __construct(Bar $bar)
    {
    }
}

$foo = $container->get('Foo');
// which is equivalent to the following:
$bar = new Bar;
$foo = new Foo($bar);
Usually the dependencies of a class are passed to the constructor and are available inside of the class during the whole lifecycle. With Method Injection it is possible to provide a dependency that is only needed by a single method of the class and passing it to the constructor may not be possible or may cause too much overhead in the majority of use cases.
 
A class method can be defined like the doSomething() method in the following example:
class MyClass extends \yii\base\Component
{
    public function __construct(/*Some lightweight dependencies here*/, $config = [])
    {
        // ...
    }

    public function doSomething($param1, \my\heavy\Dependency $something)
    {
        // do something with $something
    }
}
You may call that method either by passing an instance of \my\heavy\Dependency yourself or using yii\di\Container::invoke() like the following:
$obj = new MyClass(/*...*/);
Yii::$container->invoke([$obj, 'doSomething'], ['param1' => 42]); // $something will be provided by the DI container
Setter and property injection is supported through configurations. When registering a dependency or when creating a new object, you can provide a configuration which will be used by the container to inject the dependencies through the corresponding setters or properties.

For example :
use yii\base\BaseObject;

class Foo extends BaseObject
{
    public $bar;

    private $_qux;

    public function getQux()
    {
        return $this->_qux;
    }

    public function setQux(Qux $qux)
    {
        $this->_qux = $qux;
    }
}

$container->get('Foo', [], [
    'bar' => $container->get('Bar'),
    'qux' => $container->get('Qux'),
]);
In this case, the container will use a registered PHP callable to build new instances of a class. Each time when yii\di\Container::get() is called, the corresponding callable will be invoked. The callable is responsible to resolve the dependencies and inject them appropriately to the newly created objects. For example :
$container->set('Foo', function ($container, $params, $config) {
    $foo = new Foo(new Bar);
    // ... other initializations ...
    return $foo;
});

$foo = $container->get('Foo');
To hide the complex logic for building a new object, you may use a static class method as callable. For example :
class FooBuilder
{
    public static function build($container, $params, $config)
    {
        $foo = new Foo(new Bar);
        // ... other initializations ...
        return $foo;
    }
}

$container->set('Foo', ['app\helper\FooBuilder', 'build']);

$foo = $container->get('Foo');
 
By doing so, the person who wants to configure the Foo class no longer needs to be aware of how it is built.
You can use yii\di\Container::set() to register dependencies. The registration requires a dependency name as well as a dependency definition. A dependency name can be a class name, an interface name, or an alias name; and a dependency definition can be a class name, a configuration array, or a PHP callable.
$container = new \yii\di\Container;

// register a class name as is. This can be skipped.
$container->set('yii\db\Connection');

// register an interface
// When a class depends on the interface, the corresponding class
// will be instantiated as the dependent object
$container->set('yii\mail\MailInterface', 'yii\swiftmailer\Mailer');

// register an alias name. You can use $container->get('foo')
// to create an instance of Connection
$container->set('foo', 'yii\db\Connection');

// register an alias with `Instance::of`
$container->set('bar', Instance::of('foo'));

// register a class with configuration. The configuration
// will be applied when the class is instantiated by get()
$container->set('yii\db\Connection', [
    'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
    'username' => 'root',
    'password' => '',
    'charset' => 'utf8',
]);

// register an alias name with class configuration
// In this case, a "class" or "__class" element is required to specify the class
$container->set('db', [
    'class' => 'yii\db\Connection',
    'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
    'username' => 'root',
    'password' => '',
    'charset' => 'utf8',
]);

// register callable closure or array
// The callable will be executed each time when $container->get('db') is called
$container->set('db', function ($container, $params, $config) {
    return new \yii\db\Connection($config);
});
$container->set('db', ['app\db\DbFactory', 'create']);

// register a component instance
// $container->get('pageCache') will return the same instance each time it is called
$container->set('pageCache', new FileCache);
Tip: If a dependency name is the same as the corresponding dependency definition, you do not need to register it with the DI container.
 
A dependency registered via set() will generate an instance each time the dependency is needed. You can use yii\di\Container::setSingleton() to register a dependency that only generates a single instance :
$container->setSingleton('yii\db\Connection', [
    'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
    'username' => 'root',
    'password' => '',
    'charset' => 'utf8',
]);
Once you have registered dependencies, you can use the DI container to create new objects, and the container will automatically resolve dependencies by instantiating them and injecting them into the newly created objects. The dependency resolution is recursive, meaning that if a dependency has other dependencies, those dependencies will also be resolved automatically.
 
You can use get() to either create or get object instance. The method takes a dependency name, which can be a class name, an interface name or an alias name. The dependency name may be registered via set() or setSingleton(). You may optionally provide a list of class constructor parameters and a configuration to configure the newly created object.
 
For example :
// "db" is a previously registered alias name
$db = $container->get('db');

// equivalent to: $engine = new \app\components\SearchEngine($apiKey, $apiSecret, ['type' => 1]);
$engine = $container->get('app\components\SearchEngine', [$apiKey, $apiSecret], ['type' => 1]);

// equivalent to: $api = new \app\components\Api($host, $apiKey);
$api = $container->get('app\components\Api', ['host' => $host, 'apiKey' => $apiKey]);
Behind the scene, the DI container does much more work than just creating a new object. The container will first inspect the class constructor to find out dependent class or interface names and then automatically resolve those dependencies recursively.
 
The following code shows a more sophisticated example. The UserLister class depends on an object implementing the UserFinderInterface interface; the UserFinder class implements this interface and depends on a Connection object. All these dependencies are declared through type hinting of the class constructor parameters. With proper dependency registration, the DI container is able to resolve these dependencies automatically and creates a new UserLister instance with a simple call of get('userLister').
namespace app\models;

use yii\base\BaseObject;
use yii\db\Connection;
use yii\di\Container;

interface UserFinderInterface
{
    function findUser();
}

class UserFinder extends BaseObject implements UserFinderInterface
{
    public $db;

    public function __construct(Connection $db, $config = [])
    {
        $this->db = $db;
        parent::__construct($config);
    }

    public function findUser()
    {
    }
}

class UserLister extends BaseObject
{
    public $finder;

    public function __construct(UserFinderInterface $finder, $config = [])
    {
        $this->finder = $finder;
        parent::__construct($config);
    }
}

$container = new Container;
$container->set('yii\db\Connection', [
    'dsn' => '...',
]);
$container->set('app\models\UserFinderInterface', [
    'class' => 'app\models\UserFinder',
]);
$container->set('userLister', 'app\models\UserLister');

$lister = $container->get('userLister');

// which is equivalent to:

$db = new \yii\db\Connection(['dsn' => '...']);
$finder = new UserFinder($db);
$lister = new UserLister($finder);
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 exists as only a single instance, 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 a 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 the request, response, and urlManager components. You may configure these components, or even replace them with your own implementations, easily through functionality provided by the service locator.
 
Besides the application object, each module object is also a service locator. Modules implement tree traversal.
 
To use a service locator, the first step is to register components with it. A component can be registered via yii\di\ServiceLocator::set(). The following code shows different ways of registering components :
use yii\di\ServiceLocator;
use yii\caching\FileCache;

$locator = new ServiceLocator;

// register "cache" using a class name that can be used to create a component
$locator->set('cache', 'yii\caching\ApcCache');

// register "db" using a configuration array that can be used to create a component
$locator->set('db', [
    'class' => 'yii\db\Connection',
    'dsn' => 'mysql:host=localhost;dbname=demo',
    'username' => 'root',
    'password' => '',
]);

// register "search" using an anonymous function that builds a component
$locator->set('search', function () {
    return new app\components\SolrService;
});

// register "pageCache" using a component
$locator->set('pageCache', new FileCache);
Once a component has been registered, you can access it using its ID, in one of the two following ways :
$cache = $locator->get('cache');
// or alternatively
$cache = $locator->cache;
Built on top of PDO, Yii DAO (Database Access Objects) provides an object-oriented API for accessing relational databases. It is the foundation for other more advanced database access methods, including query builder and active record.
 
When using Yii DAO, you mainly need to deal with plain SQLs and PHP arrays. As a result, it is the most efficient way to access databases. However, because SQL syntax may vary for different databases, using Yii DAO also means you have to take extra effort to create a database-agnostic application.
 
In Yii 2.0, DAO supports the following databases out of the box:
 
* MySQL
* MariaDB
* SQLite
* PostgreSQL: version 8.4 or higher
* CUBRID: version 9.3 or higher.
* Oracle
* MSSQL: version 2008 or higher.

Note : New version of pdo_oci for PHP 7 currently exists only as the source code. Follow instruction provided by community to compile it or use PDO emulation layer.
 
Creating DB Connections : To access a database, you first need to connect to it by creating an instance of yii\db\Connection:
$db = new yii\db\Connection([
    'dsn' => 'mysql:host=localhost;dbname=example',
    'username' => 'root',
    'password' => '',
    'charset' => 'utf8',
]);
Because a DB connection often needs to be accessed in different places, a common practice is to configure it in terms of an application component like the following :
return [
    // ...
    'components' => [
        // ...
        'db' => [
            'class' => 'yii\db\Connection',
            'dsn' => 'mysql:host=localhost;dbname=example',
            'username' => 'root',
            'password' => '',
            'charset' => 'utf8',
        ],
    ],
    // ...
];
You can then access the DB connection via the expression Yii::$app->db.
 
Tip : You can configure multiple DB application components if your application needs to access multiple databases.
 
When configuring a DB connection, you should always specify its Data Source Name (DSN) via the dsn property. The format of DSN varies for different databases. Please refer to the PHP manual for more details. Below are some examples: 
 
MySQL, MariaDB : mysql:host=localhost;dbname=mydatabase
SQLite : sqlite:/path/to/database/file
PostgreSQL : pgsql:host=localhost;port=5432;dbname=mydatabase
CUBRID : cubrid:dbname=demodb;host=localhost;port=33000
MS SQL Server (via sqlsrv driver) : sqlsrv:Server=localhost;Database=mydatabase
MS SQL Server (via dblib driver) : dblib:host=localhost;dbname=mydatabase
MS SQL Server (via mssql driver) : mssql:host=localhost;dbname=mydatabase
Oracle : oci:dbname=//localhost:1521/mydatabase

Note that if you are connecting with a database via ODBC, you should configure the yii\db\Connection::$driverName property so that Yii can know the actual database type. For example : 
'db' => [
    'class' => 'yii\db\Connection',
    'driverName' => 'mysql',
    'dsn' => 'odbc:Driver={MySQL};Server=localhost;Database=test',
    'username' => 'root',
    'password' => '',
],
Once you have a database connection instance, you can execute a SQL query by taking the following steps :
 
* Create a yii\db\Command with a plain SQL query;
* Bind parameters (optional);
* Call one of the SQL execution methods in yii\db\Command.

The following example shows various ways of fetching data from a database :
// return a set of rows. each row is an associative array of column names and values.
// an empty array is returned if the query returned no results
$posts = Yii::$app->db->createCommand('SELECT * FROM post')
            ->queryAll();

// return a single row (the first row)
// false is returned if the query has no result
$post = Yii::$app->db->createCommand('SELECT * FROM post WHERE id=1')
           ->queryOne();

// return a single column (the first column)
// an empty array is returned if the query returned no results
$titles = Yii::$app->db->createCommand('SELECT title FROM post')
             ->queryColumn();

// return a scalar value
// false is returned if the query has no result
$count = Yii::$app->db->createCommand('SELECT COUNT(*) FROM post')
             ->queryScalar();
To display data in a more readable format for users, you may format them using the formatter application component. By default the formatter is implemented by yii\i18n\Formatter which provides a set of methods to format data as date/time, numbers, currencies, and other commonly used formats. You can use the formatter like the following,
$formatter = \Yii::$app->formatter;

// output: January 1, 2014
echo $formatter->asDate('2014-01-01', 'long');
 
// output: 12.50%
echo $formatter->asPercent(0.125, 2);
 
// output: <a href="mailto:cebe@example.com">cebe@example.com</a>
echo $formatter->asEmail('cebe@example.com'); 

// output: Yes
echo $formatter->asBoolean(true); 
// it also handles display of null values:

// output: (not set)
echo $formatter->asDate(null); 
In the Pagination and Sorting sections, we have described how to allow end users to choose a particular page of data to display and sort them by some columns. Because the task of paginating and sorting data is very common, Yii provides a set of data provider classes to encapsulate it.
 
A data provider is a class implementing yii\data\DataProviderInterface. It mainly supports retrieving paginated and sorted data. It is usually used to work with data widgets so that end users can interactively paginate and sort data.
 
The following data provider classes are included in the Yii releases :
 
yii\data\ActiveDataProvider : uses yii\db\Query or yii\db\ActiveQuery to query data from databases and return them in terms of arrays or Active Record instances.

yii\data\SqlDataProvider : executes a SQL statement and returns database data as arrays.

yii\data\ArrayDataProvider : takes a big array and returns a slice of it based on the paginating and sorting specifications.

The usage of all these data providers share the following common pattern :
// create the data provider by configuring its pagination and sort properties
$provider = new XyzDataProvider([
    'pagination' => [...],
    'sort' => [...],
]);

// retrieves paginated and sorted data
$models = $provider->getModels();

// get the number of data items in the current page
$count = $provider->getCount();

// get the total number of data items across all pages
$totalCount = $provider->getTotalCount();
You specify the pagination and sorting behaviors of a data provider by configuring its pagination and sort properties which correspond to the configurations for yii\data\Pagination and yii\data\Sort, respectively. You may also configure them to be false to disable pagination and/or sorting features.
 
Data widgets, such as yii\grid\GridView, have a property named dataProvider which can take a data provider instance and display the data it provides. For example :
echo yii\grid\GridView::widget([
    'dataProvider' => $dataProvider,
]);
In this section we'll review the following security aspects:
 
* Generating Pseudorandom Data
* Encryption and Decryption
* Confirming Data Integrity

Generating Pseudorandom Data
Pseudorandom data is useful in many situations. For example when resetting a password via email you need to generate a token, save it to the database, and send it via email to end user which in turn will allow them to prove ownership of that account. It is very important that this token be unique and hard to guess, else there is a possibility that attacker can predict the token's value and reset the user's password.
 
Yii security helper makes generating pseudorandom data simple :
$key = Yii::$app->getSecurity()->generateRandomString();
Encryption and Decryption : Yii provides convenient helper functions that allow you to encrypt/decrypt data using a secret key. The data is passed through the encryption function so that only the person which has the secret key will be able to decrypt it. For example, we need to store some information in our database but we need to make sure only the user who has the secret key can view it (even if the application database is compromised):
// $data and $secretKey are obtained from the form
$encryptedData = Yii::$app->getSecurity()->encryptByPassword($data, $secretKey);
// store $encryptedData to database

Subsequently when user wants to read the data:

// $secretKey is obtained from user input, $encryptedData is from the database
$data = Yii::$app->getSecurity()->decryptByPassword($encryptedData, $secretKey);

It's also possible to use key instead of password via yii\base\Security::encryptByKey() and yii\base\Security::decryptByKey().

 
Confirming Data Integrity : There are situations in which you need to verify that your data hasn't been tampered with by a third party or even corrupted in some way. Yii provides an easy way to confirm data integrity in the form of two helper functions.
 
Prefix the data with a hash generated from the secret key and data
// $secretKey our application or user secret, $genuineData obtained from a reliable source

$data = Yii::$app->getSecurity()->hashData($genuineData, $secretKey);

Checks if the data integrity has been compromised

// $secretKey our application or user secret, $data obtained from an unreliable source

$data = Yii::$app->getSecurity()->validateData($data, $secretKey);
Data caching is about storing some PHP variables in cache and retrieving it later from cache. It is also the foundation for more advanced caching features, such as query caching and page caching.
 
The following code is a typical usage pattern of data caching, where $cache refers to a cache component :
// try retrieving $data from cache
$data = $cache->get($key);

if ($data === false) {
    // $data is not found in cache, calculate it from scratch
    $data = $this->calculateSomething();

    // store $data in cache so that it can be retrieved next time
    $cache->set($key, $data);
}
// $data is available here
 
Since version 2.0.11, cache component provides getOrSet() method that simplifies code for data getting, calculating and storing. The following code does exactly the same as the previous example:
$data = $cache->getOrSet($key, function () {
    return $this->calculateSomething();
});
When cache has data associated with the $key, the cached value will be returned. Otherwise, the passed anonymous function will be executed to calculate the value that will be cached and returned.
 
If the anonymous function requires some data from the outer scope, you can pass it with the use statement. For example :
$user_id = 42;
$data = $cache->getOrSet($key, function () use ($user_id) {
    return $this->calculateSomething($user_id);
});
Fragment caching refers to caching a fragment of a Web page. For example, if a page displays a summary of yearly sale in a table, you can store this table in cache to eliminate the time needed to generate this table for each request. Fragment caching is built on top of data caching.
 
To use fragment caching, use the following construct in a view :
if ($this->beginCache($id)) {

    // ... generate content here ...

    $this->endCache();
}
That is, enclose content generation logic in a pair of beginCache() and endCache() calls. If the content is found in the cache, beginCache() will render the cached content and return false, thus skip the content generation logic. Otherwise, your content generation logic will be called, and when endCache() is called, the generated content will be captured and stored in the cache.
Besides server-side caching that we have described in the previous sections, Web applications may also exploit client-side caching to save the time for generating and transmitting the same page content.
 
To use client-side caching, you may configure yii\filters\HttpCache as a filter for controller actions whose rendering result may be cached on the client-side. HttpCache only works for GET and HEAD requests. It can handle three kinds of cache-related HTTP headers for these requests:
 
* Last-Modified
* Etag
* Cache-Control

Last-Modified Header : The Last-Modified header uses a timestamp to indicate if the page has been modified since the client caches it.
 
You may configure the yii\filters\HttpCache::$lastModified property to enable sending the Last-Modified header. The property should be a PHP callable returning a UNIX timestamp about the page modification time. The signature of the PHP callable should be as follows,
/**
 * @param Action $action the action object that is being handled currently
 * @param array $params the value of the "params" property
 * @return int a UNIX timestamp representing the page modification time
 */
function ($action, $params)
 
The following is an example of making use of the Last-Modified header :
public function behaviors()
{
    return [
        [
            'class' => 'yii\filters\HttpCache',
            'only' => ['index'],
            'lastModified' => function ($action, $params) {
                $q = new \yii\db\Query();
                return $q->from('post')->max('updated_at');
            },
        ],
    ];
}
The above code states that HTTP caching should be enabled for the index action only. It should generate a Last-Modified HTTP header based on the last update time of posts. When a browser visits the index page for the first time, the page will be generated on the server and sent to the browser; If the browser visits the same page again and there is no post being modified during the period, the server will not re-generate the page, and the browser will use the cached version on the client-side. As a result, server-side rendering and page content transmission are both skipped.
 
ETag Header : The "Entity Tag" (or ETag for short) header use a hash to represent the content of a page. If the page is changed, the hash will be changed as well. By comparing the hash kept on the client-side with the hash generated on the server-side, the cache may determine whether the page has been changed and should be re-transmitted.
 
You may configure the yii\filters\HttpCache::$etagSeed property to enable sending the ETag header. The property should be a PHP callable returning a seed for generating the ETag hash. The signature of the PHP callable should be as follows,
/**
 * @param Action $action the action object that is being handled currently
 * @param array $params the value of the "params" property
 * @return string a string used as the seed for generating an ETag hash
 */
function ($action, $params)
The following is an example of making use of the ETag header :
public function behaviors()
{
    return [
        [
            'class' => 'yii\filters\HttpCache',
            'only' => ['view'],
            'etagSeed' => function ($action, $params) {
                $post = $this->findModel(\Yii::$app->request->get('id'));
                return serialize([$post->title, $post->content]);
            },
        ],
    ];
}
The above code states that HTTP caching should be enabled for the view action only. It should generate an ETag HTTP header based on the title and content of the requested post. When a browser visits the view page for the first time, the page will be generated on the server and sent to the browser; If the browser visits the same page again and there is no change to the title and content of the post, the server will not re-generate the page, and the browser will use the cached version on the client-side. As a result, server-side rendering and page content transmission are both skipped.
 
ETags allow more complex and/or more precise caching strategies than Last-Modified headers. For instance, an ETag can be invalidated if the site has switched to another theme.
 
Expensive ETag generation may defeat the purpose of using HttpCache and introduce unnecessary overhead, since they need to be re-evaluated on every request. Try to find a simple expression that invalidates the cache if the page content has been modified.
 
Cache-Control Header : The Cache-Control header specifies the general caching policy for pages. You may send it by configuring the yii\filters\HttpCache::$cacheControlHeader property with the header value. By default, the following header will be sent :
Cache-Control: public, max-age=3600
Yii provides many classes that help simplify common coding tasks, such as string or array manipulations, HTML code generation, and so on. 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).
 
You use a helper class by directly calling one of its static methods, like the following :
use yii\helpers\Html;

echo Html::encode('Test > test');
Note : To support customizing helper classes, Yii breaks each core helper class into two classes: a base class (e.g. BaseArrayHelper) and a concrete class (e.g. ArrayHelper). When you use a helper, you should only use the concrete version and never use the base class.
 
Core Helper Classes  : The following core helper classes are provided in the Yii releases:
 
* ArrayHelper
* Console
* FileHelper
* FormatConverter
* Html
* HtmlPurifier
* Imagine (provided by yii2-imagine extension)
* Inflector
* Json
* Markdown
* StringHelper
* Url
* VarDumper

Customizing Helper Classes : To customize a core helper class (e.g. yii\helpers\ArrayHelper), you should create a new class extending from the helpers corresponding base class (e.g. yii\helpers\BaseArrayHelper) and name your class the same as the corresponding concrete class (e.g. yii\helpers\ArrayHelper), including its namespace. This class will then be set up to replace the original implementation of the framework.
 
The following example shows how to customize the merge() method of the yii\helpers\ArrayHelper class :
<?php

namespace yii\helpers;

class ArrayHelper extends BaseArrayHelper
{
    public static function merge($a, $b)
    {
        // your custom implementation
    }
}
Save your class in a file named ArrayHelper.php. The file can be in any directory, for example @app/components.
 
Next, in your application's entry script, add the following line of code after including the yii.php file to tell the Yii class autoloader to load your custom class instead of the original helper class from the framework:
Yii::$classMap['yii\helpers\ArrayHelper'] = '@app/components/ArrayHelper.php';
Note that customizing of helper classes is only useful if you want to change the behavior of an existing function of the helpers. If you want to add additional functions to use in your application, you may be better off creating a separate helper for that.
A unit test verifies that a single unit of code is working as expected. That is, given different input parameters, the test verifies the class method returns expected results. Unit tests are usually developed by people who write the classes being tested.
 
Unit testing in Yii is built on top of PHPUnit and, optionally, Codeception so it's recommended to go through their docs :
 
Functional test verifies scenarios from a user's perspective. It is similar to acceptance test but instead of communicating via HTTP it is filling up environment such as POST and GET parameters and then executes application instance right from the code.
 
Functional tests are generally faster than acceptance tests and are providing detailed stack traces on failures. As a rule of thumb, they should be preferred unless you have a special web server setup or complex UI powered by JavaScript.
 
Functional testing is implemented with the help of Codeception framework which has a nice documentation about it :
 
Acceptance test verifies scenarios from a user's perspective. The application tested is accessed via either PhpBrowser or a real browser. In both cases the browsers are communicating via HTTP so application should be served via web server.
 
Acceptance testing is implemented with the help of Codeception framework which has a nice documentation about it :
 
Fixtures are an 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 both when running your tests with Codeception and independently.
 
A key concept in the Yii fixture framework is the so-called fixture object. A fixture object represents a particular aspect of a test environment and is an instance of yii\test\Fixture or its child class. For example, you may use UserFixture to make sure the user DB table contains a fixed set of data. You load one or multiple fixture objects before running a test and unload them when finishing.
 
A fixture may depend on other fixtures, specified via its yii\test\Fixture::$depends property. When a fixture is being loaded, the fixtures it depends on will be automatically loaded BEFORE the fixture; and when the fixture is being unloaded, the dependent fixtures will be unloaded AFTER the fixture.
 
Defining a Fixture : To define a fixture, create a new class by extending yii\test\Fixture or yii\test\ActiveFixture. The former is best suited for general purpose fixtures, while the latter has enhanced features specifically designed to work with database and ActiveRecord.
 
The following code defines a fixture about the User ActiveRecord and the corresponding user table.
<?php
namespace app\tests\fixtures;

use yii\test\ActiveFixture;

class UserFixture extends ActiveFixture
{
    public $modelClass = 'app\models\User';
}