The Definitive Guide To Yii 2.0 En
User Manual:
Open the PDF directly: View PDF
.
Page Count: 589
| Download | |
| Open PDF In Browser | View PDF |
The Definitive Guide
to
Yii 2.0
http://www.yiiframework.com/doc/guide
Qiang Xue,
Alexander Makarov,
Carsten Brandt,
Klimov Paul,
and
many contributors from the Yii community
This tutorial is released under the Terms of Yii Documentation.
Copyright 2014 Yii Software LLC. All Rights Reserved.
Contents
1 Introduction
1.1 What is Yii . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2 Upgrading from Version 1.1 . . . . . . . . . . . . . . . . . . .
2 Getting Started
2.1 What do you need to know
2.2 Installing Yii . . . . . . . .
2.3 Running Applications . . .
2.4 Saying Hello . . . . . . . . .
2.5 Working with Forms . . . .
2.6 Working with Databases . .
2.7 Generating Code with Gii .
2.8 Looking Ahead . . . . . . .
3 Application Structure
3.1 Overview . . . . . . . .
3.2 Entry Scripts . . . . . .
3.3 Applications . . . . . . .
3.4 Application Components
3.5 Controllers . . . . . . .
3.6 Models . . . . . . . . . .
3.7 Views . . . . . . . . . .
3.8 Modules . . . . . . . . .
3.9 Filters . . . . . . . . . .
3.10 Widgets . . . . . . . . .
3.11 Assets . . . . . . . . . .
3.12 Extensions . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
4 Handling Requests
4.1 Overview . . . . . . . . . .
4.2 Bootstrapping . . . . . . . .
4.3 Routing and URL Creation
4.4 Requests . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
iii
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
1
1
2
.
.
.
.
.
.
.
.
13
13
14
21
25
28
34
40
46
.
.
.
.
.
.
.
.
.
.
.
.
49
49
50
52
64
67
76
87
101
108
116
120
139
.
.
.
.
151
151
152
153
168
iv
CONTENTS
4.5
4.6
4.7
4.8
Responses . . . . . .
Sessions and Cookies
Handling Errors . . .
Logging . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
172
177
185
189
5 Key Concepts
5.1 Components . . . . . . . . . . . .
5.2 Properties . . . . . . . . . . . . .
5.3 Events . . . . . . . . . . . . . . .
5.4 Behaviors . . . . . . . . . . . . .
5.5 Configurations . . . . . . . . . .
5.6 Aliases . . . . . . . . . . . . . . .
5.7 Class Autoloading . . . . . . . .
5.8 Service Locator . . . . . . . . . .
5.9 Dependency Injection Container .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
199
199
201
203
211
218
223
226
228
231
6 Working with Databases
6.1 Database Access Objects
6.2 Query Builder . . . . . .
6.3 Active Record . . . . . .
6.4 Database Migration . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
243
243
256
275
310
7 Getting Data from Users
7.1 Creating Forms . . . . . . . . . . . . . . .
7.2 Validating Input . . . . . . . . . . . . . .
7.3 Uploading Files . . . . . . . . . . . . . . .
7.4 Collecting tabular input . . . . . . . . . .
7.5 Getting Data for Multiple Models . . . . .
7.6 Extending ActiveForm on the Client Side
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
333
333
338
355
359
362
363
8 Displaying Data
8.1 Data Formatting . . . . . .
8.2 Pagination . . . . . . . . . .
8.3 Sorting . . . . . . . . . . . .
8.4 Data Providers . . . . . . .
8.5 Data widgets . . . . . . . .
8.6 Working with Client Scripts
8.7 Theming . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
369
369
374
376
378
385
399
404
.
.
.
.
407
407
407
411
429
9 Security
9.1 Security . . . . . . . . .
9.2 Authentication . . . . .
9.3 Authorization . . . . . .
9.4 Working with Passwords
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
CONTENTS
9.5
9.6
v
Cryptography . . . . . . . . . . . . . . . . . . . . . . . . . . . 430
Security best practices . . . . . . . . . . . . . . . . . . . . . . 431
10 Caching
10.1 Caching . . . . . .
10.2 Data Caching . . .
10.3 Fragment Caching
10.4 Page Caching . . .
10.5 HTTP Caching . .
.
.
.
.
.
11 RESTful Web Services
11.1 Quick Start . . . . .
11.2 Resources . . . . . .
11.3 Controllers . . . . .
11.4 Routing . . . . . . .
11.5 Response Formatting
11.6 Authentication . . .
11.7 Rate Limiting . . . .
11.8 Versioning . . . . . .
11.9 Error Handling . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
439
439
439
448
452
453
.
.
.
.
.
.
.
.
.
457
457
461
466
470
472
476
479
480
482
12 Development Tools
485
13 Testing
13.1 Testing . . . . . . . . . . .
13.2 Testing environment setup
13.3 Unit Tests . . . . . . . . .
13.4 Functional Tests . . . . .
13.5 Acceptance Tests . . . . .
13.6 Fixtures . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
487
487
488
489
490
490
491
14 Special Topics
14.1 Creating your own Application structure
14.2 Console applications . . . . . . . . . . .
14.3 Core Validators . . . . . . . . . . . . . .
14.4 Yii and Docker . . . . . . . . . . . . . .
14.5 Internationalization . . . . . . . . . . . .
14.6 Mailing . . . . . . . . . . . . . . . . . .
14.7 Performance Tuning . . . . . . . . . . .
14.8 Shared Hosting Environment . . . . . .
14.9 Using template engines . . . . . . . . . .
14.10Working with Third-Party Code . . . . .
14.11Using Yii as a Micro-framework . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
499
499
500
507
522
524
540
544
549
550
551
555
15 Widgets
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
561
vi
16 Helpers
16.1 Helpers . .
16.2 ArrayHelper
16.3 Html helper
16.4 Url Helper .
CONTENTS
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
563
563
564
573
580
Chapter 1
Introduction
1.1
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 thought of
as an acronym for Yes It Is!
1.1.1
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 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.
1.1.2
How does Yii Compare with Other Frameworks?
If you’re already familiar with another framework, you may appreciate knowing how Yii compares:
• Like most PHP frameworks, Yii implements the MVC (Model-ViewController) 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-touse features: query builders and ActiveRecord for both relational and
NoSQL databases; RESTful API development support; multi-tier caching support; and more.
1
2
CHAPTER 1. INTRODUCTION
• 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 team1 ,
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.
1.1.3
Yii Versions
Yii currently has two major versions available: 1.1 and 2.0. Version 1.1 is
the old generation and is now in maintenance mode. Version 2.0 is a complete rewrite of Yii, adopting the latest technologies and protocols, including
Composer, PSR, namespaces, traits, and so forth. Version 2.0 represents the
current generation of the framework and will receive the main development
efforts over the next few years. This guide is mainly about version 2.0.
1.1.4
Requirements and Prerequisites
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 namespaces2 and traits3 . Understanding these concepts will help you more easily pick up Yii 2.0.
1.2
Upgrading from Version 1.1
There are many differences between versions 1.1 and 2.0 of Yii as the framework was completely rewritten for 2.0. As a result, upgrading from version
1.1 is not as trivial as upgrading between minor versions. In this guide you’ll
find the major differences between the two versions.
If you have not used Yii 1.1 before, you can safely skip this section and
turn directly to “Getting started“.
Please note that Yii 2.0 introduces more new features than are covered
in this summary. It is highly recommended that you read through the whole
1
http://www.yiiframework.com/team/
http://www.php.net/manual/en/language.namespaces.php
3
http://www.php.net/manual/en/language.oop5.traits.php
2
1.2. UPGRADING FROM VERSION 1.1
3
definitive guide to learn about them all. Chances are that some features you
previously had to develop for yourself are now part of the core code.
1.2.1
Installation
Yii 2.0 fully embraces Composer4 , the de facto PHP package manager. Installation of the core framework, as well as extensions, are handled through
Composer. Please refer to the Installing Yii section to learn how to install
Yii 2.0. If you want to create new extensions, or turn your existing 1.1 extensions into 2.0-compatible extensions, please refer to the Creating Extensions
section of the guide.
1.2.2
PHP Requirements
Yii 2.0 requires PHP 5.4 or above, which is a huge improvement over PHP
version 5.2 that is required by Yii 1.1. As a result, there are many differences
on the language level that you should pay attention to. Below is a summary
of the major changes regarding PHP:
• Namespaces5 .
• Anonymous functions6 .
• Short array syntax [...elements...] is used instead of array(...elements
...).
• Short echo tags = are used in view files. This is safe to use starting
from PHP 5.4.
• SPL classes and interfaces7 .
• Late Static Bindings8 .
• Date and Time9 .
• Traits10 .
• intl11 . Yii 2.0 makes use of the intl PHP extension to support internationalization features.
1.2.3
Namespace
The most obvious change in Yii 2.0 is the use of namespaces. Almost every
core class is namespaced, e.g., yii\web\Request. The “C” prefix is no longer
used in class names. The naming scheme now follows the directory structure.
For example, yii\web\Request indicates that the corresponding class file is web
/Request.php under the Yii framework folder.
4
https://getcomposer.org/
http://php.net/manual/en/language.namespaces.php
6
http://php.net/manual/en/functions.anonymous.php
7
http://php.net/manual/en/book.spl.php
8
http://php.net/manual/en/language.oop5.late-static-bindings.php
9
http://php.net/manual/en/book.datetime.php
10
http://php.net/manual/en/language.oop5.traits.php
11
http://php.net/manual/en/book.intl.php
5
4
CHAPTER 1. INTRODUCTION
(You can use any core class without explicitly including that class file,
thanks to the Yii class loader.)
1.2.4
Component and Object
Yii 2.0 breaks the CComponent class in 1.1 into two classes: yii\base\BaseObject
and yii\base\Component. The BaseObject class is a lightweight base class
that allows defining object properties via getters and setters. The Component
class extends from BaseObject and supports events and behaviors.
If your class does not need the event or behavior feature, you should
consider using BaseObject as the base class. This is usually the case for
classes that represent basic data structures.
1.2.5
Object Configuration
The BaseObject class introduces a uniform way of configuring objects. Any
descendant class of BaseObject should declare its constructor (if needed) in
the following way so that it can be properly configured:
class MyClass extends \yii\base\BaseObject
{
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, the last parameter of the constructor must take a configuration
array that contains name-value pairs for initializing the properties at the end
of the constructor. You can override the init() method to do initialization
work that should be done after the configuration has been applied.
By following this convention, you will be able to create and configure
new objects using a configuration array:
$object = Yii::createObject([
’class’ => ’MyClass’,
’property1’ => ’abc’,
’property2’ => ’cde’,
], [$param1, $param2]);
More details about configurations can be found in the Configurations section.
1.2. UPGRADING FROM VERSION 1.1
1.2.6
5
Events
In Yii 1, events were created by defining an on-method (e.g., onBeforeSave).
In Yii 2, you can now use any event name. You trigger an event by calling
the trigger() method:
$event = new \yii\base\Event;
$component->trigger($eventName, $event);
To attach a handler to an event, use the on() method:
$component->on($eventName, $handler);
// To detach the handler, use:
// $component->off($eventName, $handler);
There are many enhancements to the event features. For more details, please
refer to the Events section.
1.2.7
Path Aliases
Yii 2.0 expands the usage of path aliases to both file/directory paths and
URLs. Yii 2.0 also now requires an alias name to start with the @ character,
to differentiate aliases from normal file/directory paths or URLs. For example, the alias @yii refers to the Yii installation directory. Path aliases are
supported in most places in the Yii core code. For example, yii\caching
\FileCache::$cachePath can take both a path alias and a normal directory
path.
A path alias is also closely related to a class namespace. It is recommended that a path alias be defined for each root namespace, thereby allowing you to use Yii class autoloader without any further configuration.
For example, because @yii refers to the Yii installation directory, a class like
yii\web\Request can be autoloaded. If you use a third party library, such as
the Zend Framework, you may define a path alias @Zend that refers to that
framework’s installation directory. Once you’ve done that, Yii will be able
to autoload any class in that Zend Framework library, too.
More on path aliases can be found in the Aliases section.
1.2.8
Views
The most significant change about views in Yii 2 is that the special variable
$this in a view no longer refers to the current controller or widget. Instead,
$this now refers to a view object, a new concept introduced in 2.0. The view
object is of type yii\web\View, which represents the view part of the MVC
pattern. If you want to access the controller or widget in a view, you can
use $this->context.
To render a partial view within another view, you use $this->render(),
not $this->renderPartial(). The call to render also now has to be explicitly
6
CHAPTER 1. INTRODUCTION
echoed, as the render() method returns the rendering result, rather than
directly displaying it. For example:
echo $this->render(’_item’, [’item’ => $item]);
Besides using PHP as the primary template language, Yii 2.0 is also equipped
with official support for two popular template engines: Smarty and Twig.
The Prado template engine is no longer supported. To use these template
engines, you need to configure the view application component by setting the
View::$renderers property. Please refer to the Template Engines section
for more details.
1.2.9
Models
Yii 2.0 uses yii\base\Model as the base model, similar to CModel in 1.1.
The class CFormModel has been dropped entirely. Instead, in Yii 2 you should
extend yii\base\Model to create a form model class.
Yii 2.0 introduces a new method called scenarios() to declare supported
scenarios, and to indicate under which scenario an attribute needs to be
validated, can be considered as safe or not, etc. For example:
public function scenarios()
{
return [
’backend’ => [’email’, ’role’],
’frontend’ => [’email’, ’!role’],
];
}
In the above, two scenarios are declared: backend and frontend. For the
scenario, both the email and role attributes are safe, and can be
massively assigned. For the frontend scenario, email can be massively assigned
while role cannot. Both email and role should be validated using rules.
The rules() method is still used to declare the validation rules. Note
that due to the introduction of scenarios(), there is no longer an unsafe
validator.
In most cases, you do not need to override scenarios() if the rules()
method fully specifies the scenarios that will exist, and if there is no need to
declare unsafe attributes.
To learn more details about models, please refer to the Models section.
backend
1.2.10
Controllers
Yii 2.0 uses yii\web\Controller as the base controller class, which is similar
to CController in Yii 1.1. yii\base\Action is the base class for action classes.
The most obvious impact of these changes on your code is that a controller action should return the content that you want to render instead of
echoing it:
1.2. UPGRADING FROM VERSION 1.1
7
public function actionView($id)
{
$model = \app\models\Post::findOne($id);
if ($model) {
return $this->render(’view’, [’model’ => $model]);
} else {
throw new \yii\web\NotFoundHttpException;
}
}
Please refer to the Controllers section for more details about controllers.
1.2.11
Widgets
Yii 2.0 uses yii\base\Widget as the base widget class, similar to CWidget in
Yii 1.1.
To get better support for the framework in IDEs, Yii 2.0 introduces a new
syntax for using widgets. The static methods begin(), end(), and widget()
have been introduced, to be used like so:
use yii\widgets\Menu;
use yii\widgets\ActiveForm;
// Note that you have to "echo" the result to display it
echo Menu::widget([’items’ => $items]);
// Passing an array to initialize the object properties
$form = ActiveForm::begin([
’options’ => [’class’ => ’form-horizontal’],
’fieldConfig’ => [’inputOptions’ => [’class’ => ’input-xlarge’]],
]);
... form input fields here ...
ActiveForm::end();
Please refer to the Widgets section for more details.
1.2.12
Themes
Themes work completely differently in 2.0. They are now based on a path
mapping mechanism that maps a source view file path to a themed view
file path. For example, if the path map for a theme is [’/web/views’ => ’/
web/themes/basic’], then the themed version for the view file /web/views/site
/index.php will be /web/themes/basic/site/index.php. For this reason, themes
can now be applied to any view file, even a view rendered outside of the
context of a controller or a widget.
Also, there is no more CThemeManager component. Instead, theme is a configurable property of the view application component.
Please refer to the Theming section for more details.
8
CHAPTER 1. INTRODUCTION
1.2.13
Console Applications
Console applications are now organized as controllers, like Web applications.
Console controllers should extend from yii\console\Controller, similar
to CConsoleCommand in 1.1.
To run a console command, use yii , where stands for a
controller route (e.g. sitemap/index). Additional anonymous arguments are
passed as the parameters to the corresponding controller action method,
while named arguments are parsed according to the declarations in yii
\console\Controller::options().
Yii 2.0 supports automatic generation of command help information from
comment blocks.
Please refer to the Console Commands section for more details.
1.2.14
I18N
Yii 2.0 removes the built-in date formatter and number formatter pieces in
favor of the PECL intl PHP module12 .
Message translation is now performed via the i18n application component. This component manages a set of message sources, which allows you to
use different message sources based on message categories.
Please refer to the Internationalization section for more details.
1.2.15
Action Filters
Action filters are implemented via behaviors now. To define a new, custom
filter, extend from yii\base\ActionFilter. To use a filter, attach the filter
class to the controller as a behavior. For example, to use the yii\filters
\AccessControl filter, you would have the following code in a controller:
public function behaviors()
{
return [
’access’ => [
’class’ => ’yii\filters\AccessControl’,
’rules’ => [
[’allow’ => true, ’actions’ => [’admin’], ’roles’ => [’@’]],
],
],
];
}
Please refer to the Filtering section for more details.
12
http://pecl.php.net/package/intl
1.2. UPGRADING FROM VERSION 1.1
1.2.16
9
Assets
Yii 2.0 introduces a new concept called asset bundle that replaces the script
package concept found in Yii 1.1.
An asset bundle is a collection of asset files (e.g. JavaScript files, CSS
files, image files, etc.) within a directory. Each asset bundle is represented
as a class extending yii\web\AssetBundle. By registering an asset bundle
via yii\web\AssetBundle::register(), you make the assets in that bundle
accessible via the Web. Unlike in Yii 1, the page registering the bundle will
automatically contain the references to the JavaScript and CSS files specified
in that bundle.
Please refer to the Managing Assets section for more details.
1.2.17
Helpers
Yii 2.0 introduces many commonly used static helper classes, including.
• yii\helpers\Html
• yii\helpers\ArrayHelper
• yii\helpers\StringHelper
• yii\helpers\FileHelper
• yii\helpers\Json
Please refer to the Helper Overview section for more details.
1.2.18
Forms
Yii 2.0 introduces the field concept for building a form using yii\widgets
\ActiveForm. A field is a container consisting of a label, an input, an error
message, and/or a hint text. A field is represented as an ActiveField object.
Using fields, you can build a form more cleanly than before:
= $form->field($model, ’username’) ?>
= $form->field($model, ’password’)->passwordInput() ?>
= Html::submitButton(’Login’) ?>
Please refer to the Creating Forms section for more details.
1.2.19
Query Builder
In 1.1, query building was scattered among several classes, including CDbCommand
, CDbCriteria, and CDbCommandBuilder. Yii 2.0 represents a DB query in terms
of a Query object that can be turned into a SQL statement with the help of
QueryBuilder behind the scene. For example:
10
CHAPTER 1. INTRODUCTION
$query = new \yii\db\Query();
$query->select(’id, name’)
->from(’user’)
->limit(10);
$command = $query->createCommand();
$sql = $command->sql;
$rows = $command->queryAll();
Best of all, such query building methods can also be used when working with
Active Record.
Please refer to the Query Builder section for more details.
1.2.20
Active Record
Yii 2.0 introduces a lot of changes to Active Record. The two most obvious
ones involve query building and relational query handling.
The CDbCriteria class in 1.1 is replaced by yii\db\ActiveQuery in Yii 2.
That class extends from yii\db\Query, and thus inherits all query building
methods. You call yii\db\ActiveRecord::find() to start building a query:
// To retrieve all *active* customers and order them by their ID:
$customers = Customer::find()
->where([’status’ => $active])
->orderBy(’id’)
->all();
To declare a relation, simply define a getter method that returns an ActiveQuery
object. The property name defined by the getter represents the relation
name. For example, the following code declares an orders relation (in 1.1,
you would have to declare relations in a central place relations()):
class Customer extends \yii\db\ActiveRecord
{
public function getOrders()
{
return $this->hasMany(’Order’, [’customer_id’ => ’id’]);
}
}
Now you can use $customer->orders to access a customer’s orders from the
related table. You can also use the following code to perform an on-the-fly
relational query with a customized query condition:
$orders = $customer->getOrders()->andWhere(’status=1’)->all();
When eager loading a relation, Yii 2.0 does it differently from 1.1. In particular, in 1.1 a JOIN query would be created to select both the primary and
the relational records. In Yii 2.0, two SQL statements are executed without
using JOIN: the first statement brings back the primary records and the
second brings back the relational records by filtering with the primary keys
of the primary records.
1.2. UPGRADING FROM VERSION 1.1
11
Instead of returning ActiveRecord objects, you may chain the asArray()
method when building a query to return a large number of records. This will
cause the query result to be returned as arrays, which can significantly reduce
the needed CPU time and memory if large number of records . For example:
$customers = Customer::find()->asArray()->all();
Another change is that you can’t define attribute default values through
public properties anymore. If you need those, you should set them in the
init method of your record class.
public function init()
{
parent::init();
$this->status = self::STATUS_NEW;
}
There were some problems with overriding the constructor of an ActiveRecord
class in 1.1. These are not present in version 2.0 anymore. Note that when
adding parameters to the constructor you might have to override yii\db
\ActiveRecord::instantiate().
There are many other changes and enhancements to Active Record.
Please refer to the Active Record section for more details.
1.2.21
Active Record Behaviors
In 2.0, we have dropped the base behavior class CActiveRecordBehavior. If you
want to create an Active Record Behavior, you will have to extend directly
from yii\base\Behavior. If the behavior class needs to respond to some events
of the owner, you have to override the events() method like the following:
namespace app\components;
use yii\db\ActiveRecord;
use yii\base\Behavior;
class MyBehavior extends Behavior
{
// ...
public function events()
{
return [
ActiveRecord::EVENT_BEFORE_VALIDATE => ’beforeValidate’,
];
}
public function beforeValidate($event)
{
// ...
}
}
12
CHAPTER 1. INTRODUCTION
1.2.22
User and IdentityInterface
The CWebUser class in 1.1 is now replaced by yii\web\User, and there is
no more CUserIdentity class. Instead, you should implement the yii\web
\IdentityInterface which is much more straightforward to use. The advanced project template provides such an example.
Please refer to the Authentication, Authorization, and Advanced Project
Template13 sections for more details.
1.2.23
URL Management
URL management in Yii 2 is similar to that in 1.1. A major enhancement
is that URL management now supports optional parameters. For example,
if you have a rule declared as follows, then it will match both post/popular
and post/1/popular. In 1.1, you would have had to use two rules to achieve
the same goal.
[
’pattern’ => ’post//’,
’route’ => ’post/index’,
’defaults’ => [’page’ => 1],
]
Please refer to the Url manager docs section for more details.
An important change in the naming convention for routes is that camel
case names of controllers and actions are now converted to lower case where
each word is separated by a hypen, e.g. the controller id for the CamelCaseController
will be camel-case. See the section about controller IDs and action IDs for
more details.
1.2.24
Using Yii 1.1 and 2.x together
If you have legacy Yii 1.1 code that you want to use together with Yii 2.0,
please refer to the Using Yii 1.1 and 2.0 Together section.
13
https://www.yiiframework.com/extension/yiisoft/yii2-app-advanced/doc/
guide
Chapter 2
Getting Started
2.1
What do you need to know
The Yii learning curve is not as steep as other PHP frameworks but still
there are some things you should learn before starting with Yii.
2.1.1
PHP
Yii is a PHP framework so make sure you read and understand language
reference1 . When developing with Yii you will be writing code in an object
oriented fashion, so make sure you are familiar with Classes and Objects2 as
well as namespaces3 .
2.1.2
Object oriented programming
Basic understanding of object oriented programming is required. If you’re
not familiar with it, check one of the many tutorials available such as the
one from tuts+4 .
Note that the more complicated your application is the more advanced
OOP concepts you should learn in order to successfully manage that complexity.
2.1.3
Command line and composer
Yii extensively uses de-facto standard PHP package manager, Composer5 so
make sure you read and understand its guide6 . If you are not familiar with
1
http://php.net/manual/en/langref.php
https://secure.php.net/manual/en/language.oop5.basic.php
3
https://secure.php.net/manual/en/language.namespaces.php
4
https://code.tutsplus.com/tutorials/object-oriented-php-for-beginners--net-12762
5
https://getcomposer.org/
6
https://getcomposer.org/doc/01-basic-usage.md
2
13
14
CHAPTER 2. GETTING STARTED
using command line it is time to start trying. Once you learn the basics
you’ll never want to work without it.
2.2
Installing Yii
You can install Yii in two ways, using the Composer7 package manager or by
downloading an archive file. The former is the preferred way, as it allows you
to install new extensions or update Yii by simply running a single command.
Standard installations of Yii result in both the framework and a project
template being downloaded and installed. A project template is a working
Yii project implementing some basic features, such as login, contact form,
etc. Its code is organized in a recommended way. Therefore, it can serve as
a good starting point for your projects.
In this and the next few sections, we will describe how to install Yii with
the so-called Basic Project Template and how to implement new features on
top of this template. Yii also provides another template called the Advanced
Project Template8 which is better used in a team development environment
to develop applications with multiple tiers.
Info: The Basic Project Template is suitable for developing 90
percent of Web applications. It differs from the Advanced Project
Template mainly in how their code is organized. If you are new
to Yii, we strongly recommend you stick to the Basic Project
Template for its simplicity yet sufficient functionalities.
2.2.1
Installing via Composer
Installing Composer
If you do not already have Composer installed, you may do so by following
the instructions at getcomposer.org9 . On Linux and Mac OS X, you’ll run
the following commands:
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
On Windows, you’ll download and run Composer-Setup.exe10 .
Please refer to the Troubleshooting section of the Composer Documentation11 if you encounter any problems. If you are new to Composer, we
7
https://getcomposer.org/
https://www.yiiframework.com/extension/yiisoft/yii2-app-advanced/doc/
guide
9
https://getcomposer.org/download/
10
https://getcomposer.org/Composer-Setup.exe
11
https://getcomposer.org/doc/articles/troubleshooting.md
8
2.2. INSTALLING YII
15
also recommend to read at least the Basic usage section12 of the Composer
documentation.
In this guide all composer commands assume you have installed composer
globally13 so that it is available as the composer command. If you are using the
composer.phar in the local directory instead, you have to adjust the example
commands accordingly.
If you had Composer already installed before, make sure you use an up
to date version. You can update Composer by running composer self-update.
Note: During the installation of Yii, Composer will need to request a lot of information from the Github API. The number of
requests depends on the number of dependencies your application has and may be bigger than the Github API rate limit.
If you hit this limit, Composer may ask for your Github login
credentials to obtain a Github API access token. On fast connections you may hit this limit earlier than Composer can handle
so we recommend to configure the access token before installing
Yii. Please refer to the Composer documentation about Github
API tokens14 for instructions on how to do this.
Installing Yii
With Composer installed, you can install Yii application template by running
the following command under a Web-accessible folder:
composer create-project --prefer-dist yiisoft/yii2-app-basic basic
This will install the latest stable version of Yii application template in a
directory named basic. You can choose a different directory name if you
want.
Info: If the composer create-project command fails you may also
refer to the Troubleshooting section of the Composer Documentation15 for common errors. When you have fixed the error, you
can resume the aborted installation by running composer update
inside of the basic directory.
Tip: If you want to install the latest development version of
Yii, you may use the following command instead, which adds a
stability option16 :
12
https://getcomposer.org/doc/01-basic-usage.md
https://getcomposer.org/doc/00-intro.md#globally
14
https://getcomposer.org/doc/articles/troubleshooting.md#
api-rate-limit-and-oauth-tokens
15
https://getcomposer.org/doc/articles/troubleshooting.md
16
https://getcomposer.org/doc/04-schema.md#minimum-stability
13
16
CHAPTER 2. GETTING STARTED
composer create-project --prefer-dist --stability=dev yiisoft/
yii2-app-basic basic
Note that the development version of Yii should not be used for
production as it may break your running code.
2.2.2
Installing from an Archive File
Installing Yii from an archive file involves three steps:
1. Download the archive file from yiiframework.com17 .
2. Unpack the downloaded file to a Web-accessible folder.
3. Modify the config/web.php file by entering a secret key for the cookieValidationKey
configuration item (this is done automatically if you are installing Yii
using Composer):
// !!! insert a secret key in the following (if it is empty) - this is
required by cookie validation
’cookieValidationKey’ => ’enter your secret key here’,
2.2.3
Other Installation Options
The above installation instructions show how to install Yii, which also creates
a basic Web application that works out of the box. This approach is a good
starting point for most projects, either small or big. It is especially suitable
if you just start learning Yii.
But there are other installation options available:
• If you only want to install the core framework and would like to build
an entire application from scratch, you may follow the instructions as
explained in Building Application from Scratch.
• If you want to start with a more sophisticated application, better suited
to team development environments, you may consider installing the
Advanced Project Template18 .
2.2.4
Installing Assets
Yii relies on Bower19 and/or NPM20 packages for the asset (CSS and JavaScript) libraries installation. It uses Composer to obtain these libraries, allowing PHP and CSS/JavaScript package versions to resolve at the same time.
17
http://www.yiiframework.com/download/
https://github.com/yiisoft/yii2-app-advanced/blob/master/docs/guide/
README.md
19
http://bower.io/
20
https://www.npmjs.org/
18
2.2. INSTALLING YII
17
This can be achieved either by usage of asset-packagist.org21 or composer
asset plugin22 . Please refer to Assets documentation for more details.
You may want to either manage your assets via native Bower/NPM client,
use CDN or avoid assets installation entirely. In order to prevent assets
installation via Composer, add the following lines to your ‘composer.json’:
"replace": {
"bower-asset/jquery": ">=1.11.0",
"bower-asset/inputmask": ">=3.2.0",
"bower-asset/punycode": ">=1.3.0",
"bower-asset/yii2-pjax": ">=2.0.0"
},
Note: in case of bypassing asset installation via Composer, you
are responsible for the assets installation and resolving version
collisions. Be prepared for possible inconsistencies among asset
files from different extensions.
2.2.5
Verifying the Installation
After installation is done, either configure your web server (see next section) or use the built-in PHP web server23 by running the following console
command while in the project web directory:
php yii serve
Note: By default the HTTP-server will listen to port 8080. However if that port is already in use or you wish to serve multiple
applications this way, you might want to specify what port to
use. Just add the –port argument:
php yii serve --port=8888
You can use your browser to access the installed Yii application with the
following URL:
http://localhost:8080/
21
https://asset-packagist.org
https://github.com/francoispluchino/composer-asset-plugin/
23
https://secure.php.net/manual/en/features.commandline.webserver.php
22
18
CHAPTER 2. GETTING STARTED
You should see the above “Congratulations!“ page in your browser. If
not, please check if your PHP installation satisfies Yii’s requirements. You
can check if the minimum requirements are met using one of the following
approaches:
• Copy /requirements.php to /web/requirements.php and then use a browser
to access it via http://localhost/requirements.php
• Run the following commands:
cd basic
php requirements.php
You should configure your PHP installation so that it meets the minimum
requirements of Yii. Most importantly, you should have PHP 5.4 or above.
Ideally latest PHP 7. You should also install the PDO PHP Extension24 and
a corresponding database driver (such as pdo_mysql for MySQL databases),
if your application needs a database.
2.2.6
Configuring Web Servers
Info: You may skip this subsection for now if you are just test
driving Yii with no intention of deploying it to a production
server.
The application installed according to the above instructions should work out
of box with either an Apache HTTP server25 or an Nginx HTTP server26 ,
24
http://www.php.net/manual/en/pdo.installation.php
http://httpd.apache.org/
26
http://nginx.org/
25
2.2. INSTALLING YII
19
on Windows, Mac OS X, or Linux running PHP 5.4 or higher. Yii 2.0 is also
compatible with facebook’s HHVM27 . However, there are some edge cases
where HHVM behaves different than native PHP, so you have to take some
extra care when using HHVM.
On a production server, you may want to configure your Web server
so that the application can be accessed via the URL http://www.example.com
/index.php instead of http://www.example.com/basic/web/index.php. Such configuration requires pointing the document root of your Web server to the
basic/web folder. You may also want to hide index.php from the URL, as described in the Routing and URL Creation section. In this subsection, you’ll
learn how to configure your Apache or Nginx server to achieve these goals.
Info: By setting basic/web as the document root, you also prevent end users from accessing your private application code and
sensitive data files that are stored in the sibling directories of
basic/web. Denying access to those other folders is a security
improvement.
Info: If your application will run in a shared hosting environment where you do not have permission to modify its Web
server configuration, you may still adjust the structure of your
application for better security. Please refer to the Shared Hosting
Environment section for more details.
Info: If you are running your Yii application behind a reverse
proxy, you might need to configure Trusted proxies and headers
in the request component.
Recommended Apache Configuration
Use the following configuration in Apache’s httpd.conf file or within a virtual
host configuration. Note that you should replace path/to/basic/web with the
actual path for basic/web.
# Set document root to be "basic/web"
DocumentRoot "path/to/basic/web"
# use mod_rewrite for pretty URL support
RewriteEngine on
# If a directory or a file exists, use the request directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Otherwise forward the request to index.php
RewriteRule . index.php
27
http://hhvm.com/
20
CHAPTER 2. GETTING STARTED
# if $showScriptName is false in UrlManager, do not allow accessing URLs
with script name
RewriteRule ^index.php/ - [L,R=404]
# ...other settings...
Recommended Nginx Configuration
To use Nginx28 , you should install PHP as an FPM SAPI29 . You may use
the following Nginx configuration, replacing path/to/basic/web with the actual
path for basic/web and mysite.test with the actual hostname to serve.
server {
charset utf-8;
client_max_body_size 128M;
listen 80; ## listen for ipv4
#listen [::]:80 default_server ipv6only=on; ## listen for ipv6
server_name mysite.test;
root
/path/to/basic/web;
index
index.php;
access_log
error_log
/path/to/basic/log/access.log;
/path/to/basic/log/error.log;
location / {
# Redirect everything that isn’t a real file to index.php
try_files $uri $uri/ /index.php$is_args$args;
}
# uncomment to avoid processing of calls to non-existing static files by
Yii
#location ~ \.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar)$ {
#
try_files $uri =404;
#}
#error_page 404 /404.html;
# deny accessing php files for the /assets directory
location ~ ^/assets/.*\.php$ {
deny all;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass 127.0.0.1:9000;
#fastcgi_pass unix:/var/run/php5-fpm.sock;
try_files $uri =404;
28
29
http://wiki.nginx.org/
http://php.net/install.fpm
2.3. RUNNING APPLICATIONS
21
}
location ~* /\. {
deny all;
}
}
When using this configuration, you should also set cgi.fix_pathinfo=0 in the
php.ini file in order to avoid many unnecessary system stat() calls.
Also note that when running an HTTPS server, you need to add fastcgi_param
HTTPS on; so that Yii can properly detect if a connection is secure.
2.3
Running Applications
After installing Yii, you have a working Yii application that can be accessed via the URL http://hostname/basic/web/index.php or http://hostname/
index.php, depending upon your configuration. This section will introduce
the application’s built-in functionality, how the code is organized, and how
the application handles requests in general.
Info: For simplicity, throughout this “Getting Started” tutorial,
it’s assumed that you have set basic/web as the document root
of your Web server, and configured the URL for accessing your
application to be http://hostname/index.php or something similar.
For your needs, please adjust the URLs in our descriptions accordingly.
Note that unlike framework itself, after project template is installed it’s all
yours. You’re free to add or delete code and overall modify it as you need.
2.3.1
Functionality
The basic application installed contains four pages:
• the homepage, displayed when you access the URL http://hostname/
index.php,
• the “About” page,
• the “Contact” page, which displays a contact form that allows end users
to contact you via email,
• and the “Login” page, which displays a login form that can be used to
authenticate end users. Try logging in with “admin/admin”, and you
will find the “Login” main menu item will change to “Logout”.
These pages share a common header and footer. The header contains a main
menu bar to allow navigation among different pages.
You should also see a toolbar at the bottom of the browser window.
This is a useful debugger tool30 provided by Yii to record and display a
30
https://github.com/yiisoft/yii2-debug/blob/master/docs/guide/README.md
22
CHAPTER 2. GETTING STARTED
lot of debugging information, such as log messages, response statuses, the
database queries run, and so on.
Additionally to the web application, there is a console script called yii,
which is located in the applications base directory. This script can be used
to run background and maintenance tasks for the application, which are
described in the Console Application Section.
2.3.2
Application Structure
The most important directories and files in your application are (assuming
the application’s root directory is basic):
basic/
application base path
composer.json
used by Composer, describes package information
config/
contains application and other configurations
console.php
the console application configuration
web.php
the Web application configuration
commands/
contains console command classes
controllers/
contains controller classes
models/
contains model classes
runtime/
contains files generated by Yii during runtime, such
as logs and cache files
vendor/
contains the installed Composer packages, including
the Yii framework itself
views/
contains view files
web/
application Web root, contains Web accessible files
assets/
contains published asset files (javascript and css)
by Yii
index.php
the entry (or bootstrap) script for the application
yii
the Yii console command execution script
In general, the files in the application can be divided into two types: those
under basic/web and those under other directories. The former can be directly
accessed via HTTP (i.e., in a browser), while the latter can not and should
not be.
Yii implements the model-view-controller (MVC)31 architectural pattern,
which is reflected in the above directory organization. The models directory
contains all model classes, the views directory contains all view scripts, and
the controllers directory contains all controller classes.
The following diagram shows the static structure of an application.
31
http://wikipedia.org/wiki/Model-view-controller
2.3. RUNNING APPLICATIONS
23
Each application has an entry script web/index.php which is the only Web
accessible PHP script in the application. The entry script takes an incoming
request and creates an application instance to handle it. The application
resolves the request with the help of its components, and dispatches the
request to the MVC elements. Widgets are used in the views to help build
complex and dynamic user interface elements.
2.3.3
Request Lifecycle
The following diagram shows how an application handles a request.
24
CHAPTER 2. GETTING STARTED
1. A user makes a request to the entry script web/index.php.
2. The entry script loads the application configuration and creates an
application instance to handle the request.
3. The application resolves the requested route with the help of the request application component.
4. The application creates a controller instance to handle the request.
5. The controller creates an action instance and performs the filters for
the action.
6. If any filter fails, the action is cancelled.
7. If all filters pass, the action is executed.
8. The action loads some data models, possibly from a database.
9. The action renders a view, providing it with the data models.
10. The rendered result is returned to the response application component.
11. The response component sends the rendered result to the user’s browser.
2.4. SAYING HELLO
2.4
25
Saying Hello
This section describes how to create a new “Hello” page in your application.
To achieve this goal, you will create an action and a view:
• The application will dispatch the page request to the action
• and the action will in turn render the view that shows the word “Hello”
to the end user.
Through this tutorial, you will learn three things:
1. how to create an action to respond to requests,
2. how to create a view to compose the response’s content, and
3. how an application dispatches requests to actions.
2.4.1
Creating an Action
For the “Hello” task, you will create a say action that reads a message parameter from the request and displays that message back to the user. If the
request does not provide a message parameter, the action will display the
default “Hello” message.
Info: Actions are the objects that end users can directly refer to
for execution. Actions are grouped by controllers. The execution
result of an action is the response that an end user will receive.
Actions must be declared in controllers. For simplicity, you may declare the
say action in the existing SiteController. This controller is defined in the
class file controllers/SiteController.php. Here is the start of the new action:
render(’say’, [’message’ => $message]);
}
}
In the above code, the say action is defined as a method named actionSay
in the SiteController class. Yii uses the prefix action to differentiate action
methods from non-action methods in a controller class. The name after the
action prefix maps to the action’s ID.
26
CHAPTER 2. GETTING STARTED
When it comes to naming your actions, you should understand how Yii
treats action IDs. Action IDs are always referenced in lower case. If an action
ID requires multiple words, they will be concatenated by dashes (e.g., create
-comment). Action method names are mapped to action IDs by removing any
dashes from the IDs, capitalizing the first letter in each word, and prefixing
the resulting string with action. For example, the action ID create-comment
corresponds to the action method name actionCreateComment.
The action method in our example takes a parameter $message, whose
value defaults to "Hello" (in exactly the same way you set a default value for
any function or method argument in PHP). When the application receives a
request and determines that the say action is responsible for handling said
request, the application will populate this parameter with the same named
parameter found in the request. In other words, if the request includes a
message parameter with a value of "Goodbye", the $message variable within the
action will be assigned that value.
Within the action method, render() is called to render a view file named
say. The message parameter is also passed to the view so that it can be used
there. The rendering result is returned by the action method. That result
will be received by the application and displayed to the end user in the
browser (as part of a complete HTML page).
2.4.2
Creating a View
Views are scripts you write to generate a response’s content. For the “Hello”
task, you will create a say view that prints the message parameter received
from the action method:
= Html::encode($message) ?>
The say view should be saved in the file views/site/say.php. When the method
render() is called in an action, it will look for a PHP file named as views/
ControllerID/ViewName.php.
Note that in the above code, the message parameter is HTML-encoded
before being printed. This is necessary as the parameter comes from an
end user, making it vulnerable to cross-site scripting (XSS) attacks32 by
embedding malicious JavaScript code in the parameter.
Naturally, you may put more content in the say view. The content can
consist of HTML tags, plain text, and even PHP statements. In fact, the
say view is just a PHP script that is executed by the render() method. The
content printed by the view script will be returned to the application as the
response’s result. The application will in turn output this result to the end
user.
32
http://en.wikipedia.org/wiki/Cross-site_scripting
2.4. SAYING HELLO
2.4.3
27
Trying it Out
After creating the action and the view, you may access the new page by
accessing the following URL:
http://hostname/index.php?r=site%2Fsay&message=Hello+World
This URL will result in a page displaying “Hello World”. The page shares
the same header and footer as the other application pages.
If you omit the message parameter in the URL, you would see the page
display just “Hello”. This is because message is passed as a parameter to the
actionSay() method, and when it is omitted, the default value of "Hello" will
be used instead.
Info: The new page shares the same header and footer as other
pages because the render() method will automatically embed
the result of the say view in a so-called layout which in this case
is located at views/layouts/main.php.
The r parameter in the above URL requires more explanation. It stands for
route, an application wide unique ID that refers to an action. The route’s
format is ControllerID/ActionID. When the application receives a request, it
will check this parameter, using the ControllerID part to determine which
controller class should be instantiated to handle the request. Then, the
controller will use the ActionID part to determine which action should be
instantiated to do the real work. In this example case, the route site/say
will be resolved to the SiteController controller class and the say action. As
a result, the SiteController::actionSay() method will be called to handle the
request.
28
CHAPTER 2. GETTING STARTED
Info: Like actions, controllers also have IDs that uniquely identify
them in an application. Controller IDs use the same naming rules
as action IDs. Controller class names are derived from controller
IDs by removing dashes from the IDs, capitalizing the first letter
in each word, and suffixing the resulting string with the word
Controller. For example, the controller ID post-comment corresponds to the controller class name PostCommentController.
2.4.4
Summary
In this section, you have touched the controller and view parts of the MVC
architectural pattern. You created an action as part of a controller to handle
a specific request. And you also created a view to compose the response’s
content. In this simple example, no model was involved as the only data
used was the message parameter.
You have also learned about routes in Yii, which act as the bridge between
user requests and controller actions.
In the next section, you will learn how to create a model, and add a new
page containing an HTML form.
2.5
Working with Forms
This section describes how to create a new page with a form for getting data
from users. The page will display a form with a name input field and an
email input field. After getting those two pieces of information from the
user, the page will echo the entered values back for confirmation.
To achieve this goal, besides creating an action and two views, you will
also create a model.
Through this tutorial, you will learn how to:
• create a model to represent the data entered by a user through a form,
• declare rules to validate the data entered,
• build an HTML form in a view.
2.5.1
Creating a Model
The data to be requested from the user will be represented by an EntryForm
model class as shown below and saved in the file models/EntryForm.php. Please
refer to the Class Autoloading section for more details about the class file
naming convention.
name = ’Qiang’;
$model->email = ’bad’;
if ($model->validate()) {
// Good!
} else {
// Failure!
// Use $model->getErrors()
}
2.5.2
Creating an Action
Next, you’ll need to create an entry action in the site controller that will use
the new model. The process of creating and using actions was explained in
the Saying Hello section.
30
CHAPTER 2. GETTING STARTED
load(Yii::$app->request->post()) && $model->validate())
{
// valid data received in $model
// do something meaningful here about $model ...
return $this->render(’entry-confirm’, [’model’ => $model]);
} else {
// either the page is initially displayed or there is some
validation error
return $this->render(’entry’, [’model’ => $model]);
}
}
}
The action first creates an EntryForm object. It then tries to populate the
model with the data from $_POST, provided in Yii by yii\web\Request::
post(). If the model is successfully populated (i.e., if the user has submitted
the HTML form), the action will call validate() to make sure the values
entered are valid.
Info: The expression Yii::$app represents the application instance, which is a globally accessible singleton. It is also a service locator that provides components such as request, response,
db, etc. to support specific functionality. In the above code, the
request component of the application instance is used to access
the $_POST data.
If everything is fine, the action will render a view named entry-confirm to
confirm the successful submission of the data to the user. If no data is submitted or the data contains errors, the entry view will be rendered, wherein
the HTML form will be shown, along with any validation error messages.
Note: In this very simple example we just render the confirmation page upon valid data submission. In practice, you should
2.5. WORKING WITH FORMS
31
consider using refresh() or redirect() to avoid form resubmission problems33 .
2.5.3
Creating Views
Finally, create two view files named entry-confirm and entry. These will be
rendered by the entry action, as just described.
The entry-confirm view simply displays the name and email data. It
should be stored in the file views/site/entry-confirm.php.
You have entered the following information:
- : = Html::encode($model->name) ?>
- : = Html::encode($model->email) ?>
The entry view displays an HTML form. It should be stored in the file
views/site/entry.php.
= $form->field($model, ’name’) ?>
= $form->field($model, ’email’) ?>
= Html::submitButton(’Submit’, [’class’ => ’btn btn-primary’]) ?>
The view uses a powerful widget called ActiveForm to build the HTML
form. The begin() and end() methods of the widget render the opening and
closing form tags, respectively. Between the two method calls, input fields are
created by the field() method. The first input field is for the “name” data,
and the second for the “email” data. After the input fields, the yii\helpers
\Html::submitButton() method is called to generate a submit button.
2.5.4
Trying it Out
To see how it works, use your browser to access the following URL:
http://hostname/index.php?r=site%2Fentry
33
http://en.wikipedia.org/wiki/Post/Redirect/Get
32
CHAPTER 2. GETTING STARTED
You will see a page displaying a form with two input fields. In front of
each input field, a label indicates what data is to be entered. If you click
the submit button without entering anything, or if you do not provide a
valid email address, you will see an error message displayed next to each
problematic input field.
After entering a valid name and email address and clicking the submit
button, you will see a new page displaying the data that you just entered.
2.5. WORKING WITH FORMS
33
Magic Explained
You may wonder how the HTML form works behind the scene, because it
seems almost magical that it can display a label for each input field and show
error messages if you do not enter the data correctly without reloading the
page.
Yes, the data validation is initially done on the client-side using JavaScript, and secondarily performed on the server-side via PHP. yii\widgets
\ActiveForm is smart enough to extract the validation rules that you have
declared in EntryForm, turn them into executable JavaScript code, and use the
JavaScript to perform data validation. In case you have disabled JavaScript
on your browser, the validation will still be performed on the server-side, as
shown in the actionEntry() method. This ensures data validity in all circumstances.
Warning: Client-side validation is a convenience that provides
for a better user experience. Server-side validation is always required, whether or not client-side validation is in place.
The labels for input fields are generated by the field() method, using the
property names from the model. For example, the label Name will be generated
for the name property.
You may customize a label within a view using the following code:
= $form->field($model, ’name’)->label(’Your Name’) ?>
= $form->field($model, ’email’)->label(’Your Email’) ?>
Info: Yii provides many such widgets to help you quickly build
complex and dynamic views. As you will learn later, writing
a new widget is also extremely easy. You may want to turn
much of your view code into reusable widgets to simplify view
development in future.
2.5.5
Summary
In this section of the guide, you have touched every part in the MVC architectural pattern. You have learned how to create a model class to represent
the user data and validate said data.
You have also learned how to get data from users and how to display
data back in the browser. This is a task that could take you a lot of time
when developing an application, but Yii provides powerful widgets to make
this task very easy.
In the next section, you will learn how to work with databases, which
are needed in nearly every application.
34
CHAPTER 2. GETTING STARTED
2.6
Working with Databases
This section will describe how to create a new page that displays country
data fetched from a database table named country. To achieve this goal, you
will configure a database connection, create an Active Record class, define
an action, and create a view.
Through this tutorial, you will learn how to:
• configure a DB connection,
• define an Active Record class,
• query data using the Active Record class,
• display data in a view in a paginated fashion.
Note that in order to finish this section, you should have basic knowledge and
experience using databases. In particular, you should know how to create a
database, and how to execute SQL statements using a DB client tool.
2.6.1
Preparing the Database
To begin, create a database named yii2basic, from which you will fetch
data in your application. You may create an SQLite, MySQL, PostgreSQL,
MSSQL or Oracle database, as Yii has built-in support for many database
applications. For simplicity, MySQL will be assumed in the following description.
Info: While MariaDB used to be a drop-in replacement for
MySQL this is no longer fully true. In case you wish to use
advanced features like JSON support in MariaDB, please check
the MariaDB extension listed below.
Next, create a table named country in the database, and insert some sample
data. You may run the following SQL statements to do so:
CREATE TABLE ‘country‘ (
‘code‘ CHAR(2) NOT NULL PRIMARY KEY,
‘name‘ CHAR(52) NOT NULL,
‘population‘ INT(11) NOT NULL DEFAULT ’0’
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INTO
INTO
INTO
INTO
INTO
INTO
INTO
INTO
INTO
INTO
‘country‘
‘country‘
‘country‘
‘country‘
‘country‘
‘country‘
‘country‘
‘country‘
‘country‘
‘country‘
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
(’AU’,’Australia’,24016400);
(’BR’,’Brazil’,205722000);
(’CA’,’Canada’,35985751);
(’CN’,’China’,1375210000);
(’DE’,’Germany’,81459000);
(’FR’,’France’,64513242);
(’GB’,’United Kingdom’,65097000);
(’IN’,’India’,1285400000);
(’RU’,’Russia’,146519759);
(’US’,’United States’,322976000);
At this point, you have a database named yii2basic, and within it a country
table with three columns, containing ten rows of data.
2.6. WORKING WITH DATABASES
2.6.2
35
Configuring a DB Connection
Before proceeding, make sure you have installed both the PDO34 PHP extension and the PDO driver for the database you are using (e.g. pdo_mysql
for MySQL). This is a basic requirement if your application uses a relational
database.
With those installed, open the file config/db.php and change the parameters to be correct for your database. By default, the file contains the
following:
’yii\db\Connection’,
’dsn’ => ’mysql:host=localhost;dbname=yii2basic’,
’username’ => ’root’,
’password’ => ’’,
’charset’ => ’utf8’,
];
The config/db.php file is a typical file-based configuration tool. This particular configuration file specifies the parameters needed to create and initialize
a yii\db\Connection instance through which you can make SQL queries
against the underlying database.
The DB connection configured above can be accessed in the application
code via the expression Yii::$app->db.
Info: The config/db.php file will be included by the main application configuration config/web.php, which specifies how the
application instance should be initialized. For more information,
please refer to the Configurations section.
If you need to work with databases support for which isn’t bundled with Yii,
check the following extensions:
• Informix35
• IBM DB236
• Firebird37
• MariaDB38
2.6.3
Creating an Active Record
To represent and fetch the data in the country table, create an Active Recordderived class named Country, and save it in the file models/Country.php.
34
http://www.php.net/manual/en/book.pdo.php
https://github.com/edgardmessias/yii2-informix
36
https://github.com/edgardmessias/yii2-ibm-db2
37
https://github.com/edgardmessias/yii2-firebird
38
https://github.com/sam-it/yii2-mariadb
35
36
CHAPTER 2. GETTING STARTED
orderBy(’name’)->all();
// get the row whose primary key is "US"
$country = Country::findOne(’US’);
// displays "United States"
echo $country->name;
// modifies the country name to be "U.S.A." and save it to database
$country->name = ’U.S.A.’;
$country->save();
Info: Active Record is a powerful way to access and manipulate
database data in an object-oriented fashion. You may find more
detailed information in the Active Record section. Alternatively,
you may also interact with a database using a lower-level data
accessing method called Database Access Objects.
2.6.4
Creating an Action
To expose the country data to end users, you need to create a new action.
Instead of placing the new action in the site controller, like you did in the
previous sections, it makes more sense to create a new controller specifically for all actions related to the country data. Name this new controller
CountryController, and create an index action in it, as shown in the following.
2.6. WORKING WITH DATABASES
37
5,
’totalCount’ => $query->count(),
]);
$countries = $query->orderBy(’name’)
->offset($pagination->offset)
->limit($pagination->limit)
->all();
return $this->render(’index’, [
’countries’ => $countries,
’pagination’ => $pagination,
]);
}
}
Save the above code in the file controllers/CountryController.php.
The index action calls Country::find(). This Active Record method builds
a DB query that can be used to retrieve all of the data from the country
table. To limit the number of countries returned in each request, the query
is paginated with the help of a yii\data\Pagination object. The Pagination
object serves two purposes:
• Sets the offset and limit clauses for the SQL statement represented
by the query so that it only returns a single page of data at a time (at
most 5 rows in a page).
• It’s used in the view to display a pager consisting of a list of page
buttons, as will be explained in the next subsection.
At the end of the code, the index action renders a view named index, and
passes the country data as well as the pagination information to it.
2.6.5
Creating a View
Under the views directory, first create a sub-directory named country. This
folder will be used to hold all the views rendered by the country controller.
Within the views/country directory, create a file named index.php containing
38
CHAPTER 2. GETTING STARTED
the following:
Countries
-
= Html::encode("{$country->code} ({$country->name})") ?>:
= $country->population ?>
= LinkPager::widget([’pagination’ => $pagination]) ?>
The view has two sections relative to displaying the country data. In the
first part, the provided country data is traversed and rendered as an unordered HTML list. In the second part, a yii\widgets\LinkPager widget
is rendered using the pagination information passed from the action. The
LinkPager widget displays a list of page buttons. Clicking on any of them will
refresh the country data in the corresponding page.
2.6.6
Trying it Out
To see how all of the above code works, use your browser to access the
following URL:
http://hostname/index.php?r=country%2Findex
2.6. WORKING WITH DATABASES
39
At first, you will see a page showing five countries. Below the countries,
you will see a pager with four buttons. If you click on the button “2”, you
will see the page display another five countries in the database: the second
page of records. Observe more carefully and you will find that the URL in
the browser also changes to
http://hostname/index.php?r=country%2Findex&page=2
Behind the scenes, Pagination is providing all of the necessary functionality
to paginate a data set:
• Initially, Pagination represents the first page, which reflects the country SELECT query with the clause LIMIT 5 OFFSET 0. As a result, the
first five countries will be fetched and displayed.
• The LinkPager widget renders the page buttons using the URLs created by Pagination. The URLs will contain the query parameter page,
which represents the different page numbers.
• If you click the page button “2”, a new request for the route country/
index will be triggered and handled. Pagination reads the page query
parameter from the URL and sets the current page number to 2. The
new country query will thus have the clause LIMIT 5 OFFSET 5 and return
the next five countries for display.
2.6.7
Summary
In this section, you learned how to work with a database. You also learned
how to fetch and display data in pages with the help of yii\data\Pagination
40
CHAPTER 2. GETTING STARTED
and yii\widgets\LinkPager.
In the next section, you will learn how to use the powerful code generation tool, called Gii39 , to help you rapidly implement some commonly
required features, such as the Create-Read-Update-Delete (CRUD) operations for working with the data in a database table. As a matter of fact, the
code you have just written can all be automatically generated in Yii using
the Gii tool.
2.7
Generating Code with Gii
This section will describe how to use Gii40 to automatically generate code
that implements some common Web site features. Using Gii to auto-generate
code is simply a matter of entering the right information per the instructions
shown on the Gii Web pages.
Through this tutorial, you will learn how to:
• enable Gii in your application,
• use Gii to generate an Active Record class,
• use Gii to generate the code implementing the CRUD operations for a
DB table,
• customize the code generated by Gii.
2.7.1
Starting Gii
Gii41 is provided in Yii as a module. You can enable Gii by configuring it in
the modules property of the application. Depending upon how you created
your 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’,
];
}
The above configuration states that when in development environment, the
application should include a module named gii, which is of class yii\gii
\Module.
If you check the entry script web/index.php of your application, you will
find the following line, which essentially makes YII_ENV_DEV to be true.
defined(’YII_ENV’) or define(’YII_ENV’, ’dev’);
39
https://www.yiiframework.com/extension/yiisoft/yii2-gii/doc/guide
https://www.yiiframework.com/extension/yiisoft/yii2-gii/doc/guide
41
https://www.yiiframework.com/extension/yiisoft/yii2-gii/doc/guide
40
2.7. GENERATING CODE WITH GII
41
Thanks to that line, your application is in development mode, and will have
already enabled Gii, per the above configuration. You can now access Gii
via the following URL:
http://hostname/index.php?r=gii
Note: If you are accessing Gii from a machine other than localhost, the access will be denied by default for security purpose.
You can configure Gii to add the allowed IP addresses as follows,
’gii’ => [
’class’ => ’yii\gii\Module’,
’allowedIPs’ => [’127.0.0.1’, ’::1’, ’192.168.0.*’, ’
192.168.178.20’] // adjust this to your needs
],
2.7.2
Generating an Active Record Class
To use Gii to generate an Active Record class, select the “Model Generator”
(by clicking the link on the Gii index page). Then fill out the form as follows:
• Table Name: country
• Model Class: Country
42
CHAPTER 2. GETTING STARTED
Next, click on the “Preview” button. You will see models/Country.php is
listed in the resulting class file to be created. You may click on the name of
the class file to preview its content.
When using Gii, if you have already created the same file and would be
overwriting it, click the diff button next to the file name to see the differences
between the code to be generated and the existing version.
2.7. GENERATING CODE WITH GII
43
When overwriting an existing file, check the box next to “overwrite” and
then click the “Generate” button. If creating a new file, you can just click
“Generate”.
Next, you will see a confirmation page indicating the code has been
successfully generated. If you had an existing file, you’ll also see a message
indicating that it was overwritten with the newly generated code.
2.7.3
Generating CRUD Code
CRUD stands for Create, Read, Update, and Delete, representing the four
common tasks taken with data on most Web sites. To create CRUD functionality using Gii, select the “CRUD Generator” (by clicking the link on the
Gii index page). For the “country” example, fill out the resulting form as
follows:
• Model Class: app\models\Country
• Search Model Class: app\models\CountrySearch
• Controller Class: app\controllers\CountryController
44
CHAPTER 2. GETTING STARTED
Next, click on the “Preview” button. You will see a list of files to be
generated, as shown below.
If you previously created the controllers/CountryController.php and views
/country/index.php files (in the databases section of the guide), check the
“overwrite” box to replace them. (The previous versions did not have full
CRUD support.)
2.7. GENERATING CODE WITH GII
2.7.4
45
Trying it Out
To see how it works, use your browser to access the following URL:
http://hostname/index.php?r=country%2Findex
You will see a data grid showing the countries from the database table. You
may sort the grid, or filter it by entering filter conditions in the column
headers.
For each country displayed in the grid, you may choose to view its details,
update it, or delete it. You may also click on the “Create Country” button
on top of the grid to be provided with a form for creating a new country.
46
CHAPTER 2. GETTING STARTED
The following is the list of the files generated by Gii, in case you want to
investigate how these features are implemented, or to customize them:
• Controller: controllers/CountryController.php
• Models: models/Country.php and models/CountrySearch.php
• Views: views/country/*.php
Info: Gii is designed to be a highly customizable and extensible
code generation tool. Using it wisely can greatly accelerate your
application development speed. For more details, please refer to
the Gii42 section.
2.7.5
Summary
In this section, you have learned how to use Gii to generate the code that
implements complete CRUD functionality for content stored in a database
table.
2.8
Looking Ahead
If you’ve read through the entire “Getting Started” chapter, you have now
created a complete Yii application. In the process, you have learned how to
implement some commonly needed features, such as getting data from users
via an HTML form, fetching data from a database, and displaying data in a
42
https://www.yiiframework.com/extension/yiisoft/yii2-gii/doc/guide
2.8. LOOKING AHEAD
47
paginated fashion. You have also learned how to use Gii43 to generate code
automatically. Using Gii for code generation turns the bulk of your Web
development process into a task as simple as just filling out some forms.
This section will summarize the Yii resources available to help you be
more productive when using the framework.
• Documentation
– The Definitive Guide44 : As the name indicates, the guide precisely
defines how Yii should work and provides general guidance about
using Yii. It is the single most important Yii tutorial, and one
that you should read before writing any Yii code.
– The Class Reference45 : This specifies the usage of every class
provided by Yii. It should be mainly used when you are writing code and want to understand the usage of a particular class,
method, property. Usage of the class reference is best only after
a contextual understanding of the entire framework.
– The Wiki Articles46 : The wiki articles are written by Yii users
based on their own experiences. Most of them are written like
cookbook recipes, and show how to solve particular problems using Yii. While the quality of these articles may not be as good as
the Definitive Guide, they are useful in that they cover broader
topics and can often provide ready-to-use solutions.
– Books47
• Extensions48 : Yii boasts a library of thousands of user-contributed
extensions that can be easily plugged into your applications, thereby
making your application development even faster and easier.
• Community
– Forum: http://www.yiiframework.com/forum/
– IRC chat: The #yii channel on the freenode network (irc://
irc.freenode.net/yii)
– Slack chanel: https://yii.slack.com
– Gitter chat: https://gitter.im/yiisoft/yii2
– GitHub: https://github.com/yiisoft/yii2
– Facebook: https://www.facebook.com/groups/yiitalk/
– Twitter: https://twitter.com/yiiframework
– LinkedIn: https://www.linkedin.com/groups/yii-framework-1483367
– Stackoverflow: http://stackoverflow.com/questions/tagged/
yii2
43
https://www.yiiframework.com/extension/yiisoft/yii2-gii/doc/guide
http://www.yiiframework.com/doc-2.0/guide-README.html
45
http://www.yiiframework.com/doc-2.0/index.html
46
http://www.yiiframework.com/wiki/?tag=yii2
47
http://www.yiiframework.com/doc/
48
http://www.yiiframework.com/extensions/
44
48
CHAPTER 2. GETTING STARTED
Chapter 3
Application Structure
3.1
Overview
Yii applications are organized according to the model-view-controller (MVC)1
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:
1
http://wikipedia.org/wiki/Model-view-controller
49
50
CHAPTER 3. APPLICATION STRUCTURE
3.2
Entry Scripts
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 [arguments] [options].
Entry scripts mainly do the following work:
• Define global constants;
• Register Composer autoloader2 ;
• Include the Yii class file;
• Load application configuration;
• Create and configure an application instance;
2
https://getcomposer.org/doc/01-basic-usage.md#autoloading
3.2. ENTRY SCRIPTS
51
• Call yii\base\Application::run() to process the incoming request.
3.2.1
Web Applications
The following is the code in the entry script for the Basic Web Project
Template.
run();
3.2.2
Console Applications
Similarly, the following is the code for the entry script of a console application:
#!/usr/bin/env php
run();
52
CHAPTER 3. APPLICATION STRUCTURE
exit($exitCode);
3.2.3
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.
3.3
Applications
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.
3.3. APPLICATIONS
3.3.1
53
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.
3.3.2
Application Properties
There are many important application properties that you should configure
in application configurations. These properties typically describe the environment that applications are running in. For example, applications need to
know how to load controllers, where to store temporary files, etc. In the
following, we will summarize these properties.
Required Properties
In any application, you should at least configure two properties: id and
basePath.
id
The id property specifies a unique ID that differentiates an application from others. It is mainly used programmatically. Although not a
requirement, for best interoperability it is recommended that you use only
alphanumeric characters when specifying an application ID.
basePath The basePath property specifies the root directory of an application. It is the directory that contains all protected source code of an application system. Under this directory, you normally will see sub-directories such
as models, views, and controllers, which contain source code corresponding
to the MVC pattern.
You may configure the basePath property using a directory path or a
path alias. In both forms, the corresponding directory must exist, or an
exception will be thrown. The path will be normalized by calling the realpath
() function.
54
CHAPTER 3. APPLICATION STRUCTURE
The basePath property is often used to derive other important paths (e.g.
the runtime path). For this reason, a path alias named @app is predefined to
represent this path. Derived paths may then be formed using this alias (e.g.
@app/runtime to refer to the runtime directory).
Important Properties
The properties described in this subsection often need to be configured because they differ across different applications.
aliases This property allows you to define a set of aliases in terms of
an array. The array keys are alias names, and the array values are the
corresponding path definitions. For example:
[
’aliases’ => [
’@name1’ => ’path/to/path1’,
’@name2’ => ’path/to/path2’,
],
]
This property is provided so that you can define aliases in terms of application configurations instead of by calling the Yii::setAlias() method.
bootstrap This is a very useful property. It allows you to specify an array
of components that should be run during the application bootstrapping
process. For example, if you want a module to customize the URL rules,
you may list its ID as an element in this property.
Each component listed in this property may be specified in one of the
following formats:
• an application component ID as specified via components,
• a module ID as specified via modules,
• a class name,
• a configuration array,
• an anonymous function that creates and returns a component.
For example:
[
’bootstrap’ => [
// an application component ID or module ID
’demo’,
// a class name
’app\components\Profiler’,
// a configuration array
[
’class’ => ’app\components\Profiler’,
’level’ => 3,
3.3. APPLICATIONS
55
],
// an anonymous function
function () {
return new app\components\Profiler();
}
],
]
Info: If a module ID is the same as an application component ID,
the application component will be used during the bootstrapping
process. If you want to use the module instead, you may specify
it using an anonymous function like the following:
[
function () {
return Yii::$app->getModule(’user’);
},
]
During the bootstrapping process, each component will be instantiated. If
the component class implements yii\base\BootstrapInterface, its bootstrap()
method will also be called.
Another practical example is in the application configuration for the Basic Project Template, where the debug and gii modules are configured as
bootstrapping components when the application is running in the development environment:
if (YII_ENV_DEV) {
// configuration adjustments for ’dev’ environment
$config[’bootstrap’][] = ’debug’;
$config[’modules’][’debug’] = ’yii\debug\Module’;
$config[’bootstrap’][] = ’gii’;
$config[’modules’][’gii’] = ’yii\gii\Module’;
}
Note: Putting too many components in bootstrap will degrade
the performance of your application because for each request, the
same set of components need to be run. So use bootstrapping
components judiciously.
catchAll This property is supported by Web applications only. It specifies a controller action which should handle all user requests. This is mainly
used when the application is in maintenance mode and needs to handle all
incoming requests via a single action.
The configuration is an array whose first element specifies the route of
the action. The rest of the array elements (key-value pairs) specify the
parameters to be bound to the action. For example:
56
CHAPTER 3. APPLICATION STRUCTURE
[
’catchAll’ => [
’offline/notice’,
’param1’ => ’value1’,
’param2’ => ’value2’,
],
]
Info: Debug panel on development environment will not work
when this property is enabled.
components This is the single most important property. It allows you to
register a list of named components called application components that you
can use in other places. For example:
[
’components’ => [
’cache’ => [
’class’ => ’yii\caching\FileCache’,
],
’user’ => [
’identityClass’ => ’app\models\User’,
’enableAutoLogin’ => true,
],
],
]
Each application component is specified as a key-value pair in the array. The
key represents the component ID, while the value represents the component
class name or configuration.
You can register any component with an application, and the component
can later be accessed globally using the expression \Yii::$app->componentID.
Please read the Application Components section for details.
controllerMap This property allows you to map a controller ID to an
arbitrary controller class. By default, Yii maps controller IDs to controller
classes based on a convention (e.g. the ID post would be mapped to app\
controllers\PostController). By configuring this property, you can break the
convention for specific controllers. In the following example, account will be
mapped to app\controllers\UserController, while article will be mapped to
app\controllers\PostController.
[
’controllerMap’ => [
’account’ => ’app\controllers\UserController’,
’article’ => [
’class’ => ’app\controllers\PostController’,
’enableCsrfValidation’ => false,
],
],
]
3.3. APPLICATIONS
57
The array keys of this property represent the controller IDs, while the array
values represent the corresponding controller class names or configurations.
controllerNamespace This property specifies the default namespace under which controller classes should be located. It defaults to app\controllers.
If a controller ID is post, by convention the corresponding controller class
name (without namespace) would be PostController, and the fully qualified
class name would be app\controllers\PostController.
Controller classes may also be located under sub-directories of the directory corresponding to this namespace. For example, given a controller ID
admin/post, the corresponding fully qualified controller class would be app\
controllers\admin\PostController.
It is important that the fully qualified controller classes should be autoloadable and the actual namespace of your controller classes match the value
of this property. Otherwise, you will receive a “Page Not Found” error when
accessing the application.
In case you want to break the convention as described above, you may
configure the controllerMap property.
language This property specifies the language in which the application
should display content to end users. The default value of this property is
en, meaning English. You should configure this property if your application
needs to support multiple languages.
The value of this property determines various internationalization aspects, including message translation, date formatting, number formatting,
etc. For example, the yii\jui\DatePicker widget will use this property
value by default to determine in which language the calendar should be displayed and how the date should be formatted.
It is recommended that you specify a language in terms of an IETF
language tag3 . For example, en stands for English, while en-US stands for
English (United States).
More details about this property can be found in the Internationalization
section.
modules This property specifies the modules that the application contains.
The property takes an array of module classes or configurations with the
array keys being the module IDs. For example:
[
’modules’ => [
// a "booking" module specified with the module class
’booking’ => ’app\modules\booking\BookingModule’,
3
http://en.wikipedia.org/wiki/IETF_language_tag
58
CHAPTER 3. APPLICATION STRUCTURE
// a "comment" module specified with a configuration array
’comment’ => [
’class’ => ’app\modules\comment\CommentModule’,
’db’ => ’db’,
],
],
]
Please refer to the Modules section for more details.
name This property specifies the application name that may be displayed
to end users. Unlike the id property, which should take a unique value, the
value of this property is mainly for display purposes; it does not need to be
unique.
You do not always need to configure this property if none of your code
is using it.
params This property specifies an array of globally accessible application
parameters. Instead of using hardcoded numbers and strings everywhere in
your code, it is a good practice to define them as application parameters in
a single place and use the parameters in places where needed. For example,
you may define the thumbnail image size as a parameter like the following:
[
’params’ => [
’thumbnail.size’ => [128, 128],
],
]
Then in your code where you need to use the size value, you can simply use
code like the following:
$size = \Yii::$app->params[’thumbnail.size’];
$width = \Yii::$app->params[’thumbnail.size’][0];
Later if you decide to change the thumbnail size, you only need to modify
it in the application configuration; you don’t need to touch any dependent
code.
sourceLanguage This property specifies the language that the application
code is written in. The default value is ’en-US’, meaning English (United
States). You should configure this property if the text content in your code
is not in English.
Like the language property, you should configure this property in terms
of an IETF language tag4 . For example, en stands for English, while en-US
stands for English (United States).
More details about this property can be found in the Internationalization
section.
4
http://en.wikipedia.org/wiki/IETF_language_tag
3.3. APPLICATIONS
59
timeZone This property is provided as an alternative way of setting the
default time zone of the PHP runtime. By configuring this property, you are
essentially calling the PHP function date_default_timezone_set()5 . For
example:
[
’timeZone’ => ’America/Los_Angeles’,
]
For more details on the implications of setting the time zone, please check
the section on date formatting.
version This property specifies the version of the application. It defaults
to ’1.0’. You do not need to configure this property if none of your code is
using it.
Useful Properties
The properties described in this subsection are not commonly configured
because their default values derive from common conventions. However, you
may still configure them in case you want to break the conventions.
charset This property specifies the charset that the application uses. The
default value is ’UTF-8’, which should be kept as-is for most applications
unless you are working with a legacy system that uses a lot of non-Unicode
data.
defaultRoute This property specifies the route that an application should
use when a request does not specify one. The route may consist of a child
module ID, a controller ID, and/or an action ID. For example, help, post/
create, or admin/post/create. If an action ID is not given, this property will
take the default value specified in yii\base\Controller::$defaultAction.
For Web applications, the default value of this property is ’site’, which
means the SiteController controller and its default action should be used. As
a result, if you access the application without specifying a route, it will show
the result of app\controllers\SiteController::actionIndex().
For console applications, the default value is ’help’, which means the
core command yii\console\controllers\HelpController::actionIndex()
should be used. As a result, if you run the command yii without providing
any arguments, it will display the help information.
extensions This property specifies the list of extensions that are installed
and used by the application. By default, it will take the array returned by
the file @vendor/yiisoft/extensions.php. The extensions.php file is generated
5
http://php.net/manual/en/function.date-default-timezone-set.php
60
CHAPTER 3. APPLICATION STRUCTURE
and maintained automatically when you use Composer6 to install extensions.
So in most cases, you do not need to configure this property.
In the special case when you want to maintain extensions manually, you
may configure this property as follows:
[
’extensions’ => [
[
’name’ => ’extension name’,
’version’ => ’version number’,
’bootstrap’ => ’BootstrapClassName’,
configuration array
’alias’ => [ // optional
’@alias1’ => ’to/path1’,
’@alias2’ => ’to/path2’,
],
],
// optional, may also be a
// ... more extensions like the above ...
],
]
As you can see, the property takes an array of extension specifications. Each
extension is specified with an array consisting of name and version elements. If
an extension needs to run during the bootstrap process, a bootstrap element
may be specified with a bootstrapping class name or a configuration array.
An extension may also define a few aliases.
layout This property specifies the name of the default layout that should
be used when rendering a view. The default value is ’main’, meaning the
layout file main.php under the layout path should be used. If both of the
layout path and the view path are taking the default values, the default
layout file can be represented as the path alias @app/views/layouts/main.php.
You may configure this property to be false if you want to disable layout
by default, although this is very rare.
layoutPath This property specifies the path where layout files should be
looked for. The default value is the layouts sub-directory under the view
path. If the view path is taking its default value, the default layout path
can be represented as the path alias @app/views/layouts.
You may configure it as a directory or a path alias.
runtimePath This property specifies the path where temporary files, such
as log files and cache files, can be generated. The default value is the directory represented by the alias @app/runtime.
6
https://getcomposer.org
3.3. APPLICATIONS
61
You may configure it as a directory or a path alias. Note that the runtime
path must be writable by the process running the application. And the path
should be protected from being accessed by end users, because the temporary
files under it may contain sensitive information.
To simplify access to this path, Yii has predefined a path alias named
@runtime for it.
viewPath This property specifies the root directory where view files are
located. The default value is the directory represented by the alias @app/
views. You may configure it as a directory or a path alias.
vendorPath This property specifies the vendor directory managed by Composer7 . It contains all third party libraries used by your application, including the Yii framework. The default value is the directory represented by the
alias @app/vendor.
You may configure this property as a directory or a path alias. When you
modify this property, make sure you also adjust the Composer configuration
accordingly.
To simplify access to this path, Yii has predefined a path alias named
@vendor for it.
enableCoreCommands This property is supported by console applications
only. It specifies whether the core commands included in the Yii release
should be enabled. The default value is true.
3.3.3
Application Events
An application triggers several events during the lifecycle of handling a request. You may attach event handlers to these events in application configurations as follows:
[
’on beforeRequest’ => function ($event) {
// ...
},
]
The use of the on eventName syntax is described in the Configurations section.
Alternatively, you may attach event handlers during the bootstrapping
process after the application instance is created. For example:
\Yii::$app->on(\yii\base\Application::EVENT_BEFORE_REQUEST, function ($event
) {
// ...
});
7
https://getcomposer.org
62
CHAPTER 3. APPLICATION STRUCTURE
EVENT_BEFORE_REQUEST
This event is triggered before an application handles a request. The actual
event name is beforeRequest.
When this event is triggered, the application instance has been configured
and initialized. So it is a good place to insert your custom code via the
event mechanism to intercept the request handling process. For example, in
the event handler, you may dynamically set the yii\base\Application::
$language property based on some parameters.
EVENT_AFTER_REQUEST
This event is triggered after an application finishes handling a request but
before sending the response. The actual event name is afterRequest.
When this event is triggered, the request handling is completed and you
may take this chance to do some postprocessing of the request or customize
the response.
Note that the response component also triggers some events while it is
sending out response content to end users. Those events are triggered after
this event.
EVENT_BEFORE_ACTION
This event is triggered before running every controller action. The actual
event name is beforeAction.
The event parameter is an instance of yii\base\ActionEvent. An event
handler may set the yii\base\ActionEvent::$isValid property to be false
to stop running the action. For example:
[
’on beforeAction’ => function ($event) {
if (some condition) {
$event->isValid = false;
} else {
}
},
]
Note that the same beforeAction event is also triggered by modules and controllers. Application objects are the first ones triggering this event, followed
by modules (if any), and finally controllers. If an event handler sets yii\base
\ActionEvent::$isValid to be false, all of the subsequent events will NOT
be triggered.
EVENT_AFTER_ACTION
This event is triggered after running every controller action. The actual
event name is afterAction.
3.3. APPLICATIONS
63
The event parameter is an instance of yii\base\ActionEvent. Through
the yii\base\ActionEvent::$result property, an event handler may access or modify the action result. For example:
[
’on afterAction’ => function ($event) {
if (some condition) {
// modify $event->result
} else {
}
},
]
Note that the same afterAction event is also triggered by modules and controllers. These objects trigger this event in the reverse order as for that of
beforeAction. That is, controllers are the first objects triggering this event,
followed by modules (if any), and finally applications.
3.3.4
Application Lifecycle
When an entry script is being executed to handle a request, an application
will undergo the following lifecycle:
1. The entry script loads the application configuration as an array.
2. The entry script creates a new instance of the application:
64
CHAPTER 3. APPLICATION STRUCTURE
• preInit() is called, which configures some high priority application properties, such as basePath.
• Register the error handler.
• Configure application properties.
• init() is called which further calls bootstrap() to run bootstrapping components.
3. The entry script calls yii\base\Application::run() to run the application:
• Trigger the EVENT_BEFORE_REQUEST event.
• Handle the request: resolve the request into a route and the associated parameters; create the module, controller, and action
objects as specified by the route; and run the action.
• Trigger the EVENT_AFTER_REQUEST event.
• Send response to the end user.
4. The entry script receives the exit status from the application and completes the request processing.
3.4
Application Components
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’,
3.4. APPLICATION COMPONENTS
65
// 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;
},
],
]
Info: While you can register as many application components
as you want, you should do this judiciously. Application components are like global variables. Using too many application
components can potentially make your code harder to test and
maintain. In many cases, you can simply create a local component and use it when needed.
3.4.1
Bootstrapping Components
As mentioned above, an application component will only be instantiated
when it is being accessed the first time. If it is not accessed at all during
a request, it will not be instantiated. Sometimes, however, you may want
to instantiate an application component for every request, even if it is not
explicitly accessed. To do so, you may list its ID in the bootstrap property
of the application.
You can also use Closures to bootstrap customized components. Returning an instantiated component is not required. A Closure can also be used
simply for running code after yii\base\Application instantiation.
For example, the following application configuration makes sure the log
component is always loaded:
[
’bootstrap’ => [
’log’,
function($app){
return new ComponentX();
},
function($app){
// some code
return;
}
],
’components’ => [
’log’ => [
// configuration for "log" component
66
CHAPTER 3. APPLICATION STRUCTURE
],
],
]
3.4.2
Core Application Components
Yii defines a set of core application components with fixed IDs and default
configurations. For example, the request component is used to collect information about a user request and resolve it into a route; the db component
represents a database connection through which you can perform database
queries. It is with help of these core application components that Yii applications are able to handle user requests.
Below is the list of the predefined core application components. You may
configure and customize them like you do with normal application components. When you are configuring a core application component, if you do not
specify its class, the default one will be used.
• assetManager: manages asset bundles and asset publishing. Please
refer to the Assets section for more details.
• db: represents a database connection through which you can perform
DB queries. Note that when you configure this component, you must
specify the component class as well as other required component properties, such as yii\db\Connection::$dsn. Please refer to the Database Access Objects section for more details.
• errorHandler: handles PHP errors and exceptions. Please refer to the
Handling Errors section for more details.
• formatter: formats data when they are displayed to end users. For
example, a number may be displayed with thousand separator, a date
may be formatted in long format. Please refer to the Data Formatting
section for more details.
• i18n: supports message translation and formatting. Please refer to the
Internationalization section for more details.
• log: manages log targets. Please refer to the Logging section for more
details.
• yii\swiftmailer\Mailer: supports mail composing and sending. Please
refer to the Mailing section for more details.
• response: represents the response being sent to end users. Please refer
to the Responses section for more details.
• request: represents the request received from end users. Please refer
to the Requests section for more details.
• session: represents the session information. This component is only
available in Web applications. Please refer to the Sessions and Cookies section for more details.
• urlManager: supports URL parsing and creation. Please refer to the
Routing and URL Creation section for more details.
3.5. CONTROLLERS
67
• user: represents the user authentication information. This component
is only available in Web applications. Please refer to the Authentication section for more details.
• view: supports view rendering. Please refer to the Views section for
more details.
3.5
Controllers
Controllers are part of the MVC8 architecture. They are objects of classes
extending from yii\base\Controller and are responsible for processing
requests and generating responses. In particular, after taking over the control
from applications, controllers will analyze incoming request data, pass them
to models, inject model results into views, and finally generate outgoing
responses.
3.5.1
Actions
Controllers are composed of actions which are the most basic units that end
users can address and request for execution. A controller can have one or
multiple actions.
The following example shows a post controller with two actions: view and
create:
namespace app\controllers;
use
use
use
use
Yii;
app\models\Post;
yii\web\Controller;
yii\web\NotFoundHttpException;
class PostController extends Controller
{
public function actionView($id)
{
$model = Post::findOne($id);
if ($model === null) {
throw new NotFoundHttpException;
}
return $this->render(’view’, [
’model’ => $model,
]);
}
public function actionCreate()
{
$model = new Post;
8
http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller
68
CHAPTER 3. APPLICATION STRUCTURE
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect([’view’, ’id’ => $model->id]);
} else {
return $this->render(’create’, [
’model’ => $model,
]);
}
}
}
In the view action (defined by the actionView() method), the code first loads
the model according to the requested model ID; If the model is loaded successfully, it will display it using a view named view. Otherwise, it will throw
an exception.
In the create action (defined by the actionCreate() method), the code
is similar. It first tries to populate a new instance of the model using the
request data and save the model. If both succeed it will redirect the browser
to the view action with the ID of the newly created model. Otherwise it will
display the create view through which users can provide the needed input.
3.5.2
Routes
End users address actions through the so-called routes. A route is a string
that consists of the following parts:
• a module ID: this exists only if the controller belongs to a non-application
module;
• a controller ID: a string that uniquely identifies the controller among
all controllers within the same application (or the same module if the
controller belongs to a module);
• an action ID: a string that uniquely identifies the action among all
actions within the same controller.
Routes take the following format:
ControllerID/ActionID
or the following format if the controller belongs to a module:
ModuleID/ControllerID/ActionID
So if a user requests with the URL http://hostname/index.php?r=site/index,
the index action in the site controller will be executed. For more details on
how routes are resolved into actions, please refer to the Routing and URL
Creation section.
3.5.3
Creating Controllers
In Web applications, controllers should extend from yii\web\Controller
or its child classes. Similarly in console applications, controllers should
3.5. CONTROLLERS
69
extend from yii\console\Controller or its child classes. The following
code defines a site controller:
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
}
Controller IDs
Usually, a controller is designed to handle the requests regarding a particular
type of resource. For this reason, controller IDs are often nouns referring to
the types of the resources that they are handling. For example, you may use
article as the ID of a controller that handles article data.
By default, controller IDs should contain these characters only: English
letters in lower case, digits, underscores, hyphens, and forward slashes. For
example, article and post-comment are both valid controller IDs, while article
?, PostComment, admin\post are not.
A controller ID may also contain a subdirectory prefix. For example,
admin/article stands for an article controller in the admin subdirectory under the controller namespace. Valid characters for subdirectory prefixes
include: English letters in lower and upper cases, digits, underscores, and
forward slashes, where forward slashes are used as separators for multi-level
subdirectories (e.g. panels/admin).
Controller Class Naming
Controller class names can be derived from controller IDs according to the
following procedure:
1. Turn the first letter in each word separated by hyphens into upper case.
Note that if the controller ID contains slashes, this rule only applies to
the part after the last slash in the ID.
2. Remove hyphens and replace any forward slashes with backward slashes.
3. Append the suffix Controller.
4. Prepend the controller namespace.
The following are some examples, assuming the controller namespace takes
the default value app\controllers:
• article becomes app\controllers\ArticleController;
• post-comment becomes app\controllers\PostCommentController;
70
CHAPTER 3. APPLICATION STRUCTURE
• admin/post-comment becomes app\controllers\admin\PostCommentController
;
• adminPanels/post-comment becomes app\controllers\adminPanels\PostCommentController
.
Controller classes must be autoloadable. For this reason, in the above examples, the article controller class should be saved in the file whose alias is
@app/controllers/ArticleController.php; while the admin/post-comment controller should be in @app/controllers/admin/PostCommentController.php.
Info: The last example admin/post-comment shows how you can
put a controller under a sub-directory of the controller namespace.
This is useful when you want to organize your controllers into
several categories and you do not want to use modules.
Controller Map
You can configure the controller map to overcome the constraints of the
controller IDs and class names described above. This is mainly useful when
you are using third-party controllers and you do not have control over their
class names.
You may configure the controller map in the application configuration.
For example:
[
’controllerMap’ => [
// declares "account" controller using a class name
’account’ => ’app\controllers\UserController’,
// declares "article" controller using a configuration array
’article’ => [
’class’ => ’app\controllers\PostController’,
’enableCsrfValidation’ => false,
],
],
]
Default Controller
Each application has a default controller specified via the yii\base\Application
::$defaultRoute property. When a request does not specify a route, the
route specified by this property will be used. For Web applications, its
value is ’site’, while for console applications, it is help. Therefore, if
a URL is http://hostname/index.php, then the site controller will handle the
request.
You may change the default controller with the following application
configuration:
3.5. CONTROLLERS
71
[
’defaultRoute’ => ’main’,
]
3.5.4
Creating Actions
Creating actions can be as simple as defining the so-called action methods in
a controller class. An action method is a public method whose name starts
with the word action. The return value of an action method represents the
response data to be sent to end users. The following code defines two actions,
index and hello-world:
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
public function actionIndex()
{
return $this->render(’index’);
}
public function actionHelloWorld()
{
return ’Hello World’;
}
}
Action IDs
An action is often designed to perform a particular manipulation of a resource. For this reason, action IDs are usually verbs, such as view, update,
etc.
By default, action IDs should contain these characters only: English
letters in lower case, digits, underscores, and hyphens (you can use hyphens
to separate words). For example, view, update2, and comment-post are all valid
action IDs, while view? and Update are not.
You can create actions in two ways: inline actions and standalone actions. An inline action is defined as a method in the controller class, while a
standalone action is a class extending yii\base\Action or its child classes.
Inline actions take less effort to create and are often preferred if you have
no intention to reuse these actions. Standalone actions, on the other hand,
are mainly created to be used in different controllers or be redistributed as
extensions.
72
CHAPTER 3. APPLICATION STRUCTURE
Inline Actions
Inline actions refer to the actions that are defined in terms of action methods
as we just described.
The names of the action methods are derived from action IDs according
to the following procedure:
1. Turn the first letter in each word of the action ID into upper case.
2. Remove hyphens.
3. Prepend the prefix action.
For example, index becomes actionIndex, and hello-world becomes actionHelloWorld
.
Note: The names of the action methods are case-sensitive. If
you have a method named ActionIndex, it will not be considered
as an action method, and as a result, the request for the index
action will result in an exception. Also note that action methods
must be public. A private or protected method does NOT define
an inline action.
Inline actions are the most commonly defined actions because they take little
effort to create. However, if you plan to reuse the same action in different
places, or if you want to redistribute an action, you should consider defining
it as a standalone action.
Standalone Actions
Standalone actions are defined in terms of action classes extending yii\base
\Action or its child classes. For example, in the Yii releases, there are yii
\web\ViewAction and yii\web\ErrorAction, both of which are standalone
actions.
To use a standalone action, you should declare it in the action map by
overriding the yii\base\Controller::actions() method in your controller
classes like the following:
public function actions()
{
return [
// declares "error" action using a class name
’error’ => ’yii\web\ErrorAction’,
// declares "view" action using a configuration array
’view’ => [
’class’ => ’yii\web\ViewAction’,
’viewPrefix’ => ’’,
],
3.5. CONTROLLERS
73
];
}
As you can see, the actions() method should return an array whose keys are
action IDs and values the corresponding action class names or configurations.
Unlike inline actions, action IDs for standalone actions can contain arbitrary
characters, as long as they are declared in the actions() method.
To create a standalone action class, you should extend yii\base\Action
or a child class, and implement a public method named run(). The role of
the run() method is similar to that of an action method. For example,
redirect(’http://example.com’);
}
74
CHAPTER 3. APPLICATION STRUCTURE
Action Parameters
The action methods for inline actions and the run() methods for standalone
actions can take parameters, called action parameters. Their values are
obtained from requests. For Web applications, the value of each action
parameter is retrieved from $_GET using the parameter name as the key; for
console applications, they correspond to the command line arguments.
In the following example, the view action (an inline action) has declared
two parameters: $id and $version.
namespace app\controllers;
use yii\web\Controller;
class PostController extends Controller
{
public function actionView($id, $version = null)
{
// ...
}
}
The action parameters will be populated as follows for different requests:
• http://hostname/index.php?r=post/view&id=123: the $id parameter will be
filled with the value ’123’, while $version is still null because there is
no version query parameter.
• http://hostname/index.php?r=post/view&id=123&version=2: the $id and $version
parameters will be filled with ’123’ and ’2’, respectively.
• http://hostname/index.php?r=post/view: a yii\web\BadRequestHttpException
exception will be thrown because the required $id parameter is not
provided in the request.
• http://hostname/index.php?r=post/view&id[]=123: a yii\web\BadRequestHttpException
exception will be thrown because $id parameter is receiving an unexpected array value [’123’].
If you want an action parameter to accept array values, you should type-hint
it with array, like the following:
public function actionView(array $id, $version = null)
{
// ...
}
Now if the request is http://hostname/index.php?r=post/view&id[]=123, the $id
parameter will take the value of [’123’]. If the request is http://hostname
/index.php?r=post/view&id=123, the $id parameter will still receive the same
array value because the scalar value ’123’ will be automatically turned into
an array.
The above examples mainly show how action parameters work for Web
applications. For console applications, please refer to the Console Commands
section for more details.
3.5. CONTROLLERS
75
Default Action
Each controller has a default action specified via the yii\base\Controller
::$defaultAction property. When a route contains the controller ID only,
it implies that the default action of the specified controller is requested.
By default, the default action is set as index. If you want to change the
default value, simply override this property in the controller class, like the
following:
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
public $defaultAction = ’home’;
public function actionHome()
{
return $this->render(’home’);
}
}
3.5.5
Controller Lifecycle
When processing a request, an application will create a controller based on
the requested route. The controller will then undergo the following lifecycle
to fulfill the request:
1. The yii\base\Controller::init() method is called after the controller is created and configured.
2. The controller creates an action object based on the requested action
ID:
• If the action ID is not specified, the default action ID will be
used.
• If the action ID is found in the action map, a standalone action
will be created;
• If the action ID is found to match an action method, an inline
action will be created;
• Otherwise an yii\base\InvalidRouteException exception will
be thrown.
3. The controller sequentially calls the beforeAction() method of the application, the module (if the controller belongs to a module), and the
controller.
76
CHAPTER 3. APPLICATION STRUCTURE
• If one of the calls returns false, the rest of the uncalled beforeAction
() methods will be skipped and the action execution will be cancelled.
• By default, each beforeAction() method call will trigger a beforeAction
event to which you can attach a handler.
4. The controller runs the action.
• The action parameters will be analyzed and populated from the
request data.
5. The controller sequentially calls the afterAction() method of the controller, the module (if the controller belongs to a module), and the
application.
• By default, each afterAction() method call will trigger an afterAction
event to which you can attach a handler.
6. The application will take the action result and assign it to the response.
3.5.6
Best Practices
In a well-designed application, controllers are often very thin, with each
action containing only a few lines of code. If your controller is rather complicated, it usually indicates that you should refactor it and move some code
to other classes.
Here are some specific best practices. Controllers
• may access the request data;
• may call methods of models and other service components with request
data;
• may use views to compose responses;
• should NOT process the request data - this should be done in the model
layer;
• should avoid embedding HTML or other presentational code - this is
better done in views.
3.6
Models
Models are part of the MVC9 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;
9
http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller
3.6. MODELS
77
• 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.
Info: You are not required to base your model classes on yii
\base\Model. However, because there are many Yii components
built to support yii\base\Model, it is usually the preferable base
class for a model.
3.6.1
Attributes
Models represent business data in terms of attributes. Each attribute is like
a publicly accessible property of a model. The method yii\base\Model::
attributes() specifies what attributes a model class has.
You can access an attribute like accessing a normal object property:
$model = new \app\models\ContactForm;
// "name" is an attribute of ContactForm
$model->name = ’example’;
echo $model->name;
You can also access attributes like accessing array elements, thanks to the
support for ArrayAccess10 and Traversable11 by yii\base\Model:
$model = new \app\models\ContactForm;
// accessing attributes like array elements
$model[’name’] = ’example’;
echo $model[’name’];
// Model is traversable using foreach.
foreach ($model as $name => $value) {
echo "$name: $value\n";
}
Defining Attributes
By default, if your model class extends directly from yii\base\Model, all
its non-static public member variables are attributes. For example, the
10
11
http://php.net/manual/en/class.arrayaccess.php
http://php.net/manual/en/class.traversable.php
78
CHAPTER 3. APPLICATION STRUCTURE
model class below has four attributes: name, email, subject and
The ContactForm model is used to represent the input data received
from an HTML form.
ContactForm
body.
namespace app\models;
use yii\base\Model;
class ContactForm extends Model
{
public $name;
public $email;
public $subject;
public $body;
}
You may override yii\base\Model::attributes() to define attributes in a
different way. The method should return the names of the attributes in a
model. For example, yii\db\ActiveRecord does so by returning the column
names of the associated database table as its attribute names. Note that you
may also need to override the magic methods such as __get(), __set() so that
the attributes can be accessed like normal object properties.
Attribute Labels
When displaying values or getting input for attributes, you often need to display some labels associated with attributes. For example, given an attribute
named firstName, you may want to display a label First Name which is more
user-friendly when displayed to end users in places such as form inputs and
error messages.
You can get the label of an attribute by calling yii\base\Model::getAttributeLabel().
For example,
$model = new \app\models\ContactForm;
// displays "Name"
echo $model->getAttributeLabel(’name’);
By default, attribute labels are automatically generated from attribute names.
The generation is done by the method yii\base\Model::generateAttributeLabel().
It will turn camel-case variable names into multiple words with the first letter in each word in upper case. For example, username becomes Username, and
firstName becomes First Name.
If you do not want to use automatically generated labels, you may override yii\base\Model::attributeLabels() to explicitly declare attribute
labels. For example,
namespace app\models;
use yii\base\Model;
3.6. MODELS
79
class ContactForm extends Model
{
public $name;
public $email;
public $subject;
public $body;
public function attributeLabels()
{
return [
’name’ => ’Your name’,
’email’ => ’Your email address’,
’subject’ => ’Subject’,
’body’ => ’Content’,
];
}
}
For applications supporting multiple languages, you may want to translate
attribute labels. This can be done in the attributeLabels() method as
well, like the following:
public function attributeLabels()
{
return [
’name’ => \Yii::t(’app’, ’Your name’),
’email’ => \Yii::t(’app’, ’Your email address’),
’subject’ => \Yii::t(’app’, ’Subject’),
’body’ => \Yii::t(’app’, ’Content’),
];
}
You may even conditionally define attribute labels. For example, based on
the scenario the model is being used in, you may return different labels for
the same attribute.
Info: Strictly speaking, attribute labels are part of views. But
declaring labels in models is often very convenient and can result
in very clean and reusable code.
3.6.2
Scenarios
A model may be used in different scenarios. For example, a User model
may be used to collect user login inputs, but it may also be used for the
user registration purpose. In different scenarios, a model may use different
business rules and logic. For example, the email attribute may be required
during user registration, but not so during user login.
A model uses the yii\base\Model::$scenario property to keep track
of the scenario it is being used in. By default, a model supports only a single
scenario named default. The following code shows two ways of setting the
scenario of a model:
80
CHAPTER 3. APPLICATION STRUCTURE
// scenario is set as a property
$model = new User;
$model->scenario = User::SCENARIO_LOGIN;
// scenario is set through configuration
$model = new User([’scenario’ => User::SCENARIO_LOGIN]);
By default, the scenarios supported by a model are determined by the validation rules declared in the model. However, you can customize this behavior
by overriding the yii\base\Model::scenarios() method, like the following:
namespace app\models;
use yii\db\ActiveRecord;
class User extends ActiveRecord
{
const SCENARIO_LOGIN = ’login’;
const SCENARIO_REGISTER = ’register’;
public function scenarios()
{
return [
self::SCENARIO_LOGIN => [’username’, ’password’],
self::SCENARIO_REGISTER => [’username’, ’email’, ’password’],
];
}
}
Info: In the above and following examples, the model classes
are extending from yii\db\ActiveRecord because the usage of
multiple scenarios usually happens to Active Record classes.
The scenarios() method returns an array whose keys are the scenario names
and values the corresponding active attributes. An active attribute can be
massively assigned and is subject to validation. In the above example, the
username and password attributes are active in the login scenario; while in the
register scenario, email is also active besides username and password.
The default implementation of scenarios() will return all scenarios found
in the validation rule declaration method yii\base\Model::rules(). When
overriding scenarios(), if you want to introduce new scenarios in addition to
the default ones, you may write code like the following:
namespace app\models;
use yii\db\ActiveRecord;
class User extends ActiveRecord
{
const SCENARIO_LOGIN = ’login’;
3.6. MODELS
81
const SCENARIO_REGISTER = ’register’;
public function scenarios()
{
$scenarios = parent::scenarios();
$scenarios[self::SCENARIO_LOGIN] = [’username’, ’password’];
$scenarios[self::SCENARIO_REGISTER] = [’username’, ’email’, ’
password’];
return $scenarios;
}
}
The scenario feature is primarily used by validation and massive attribute
assignment. You can, however, use it for other purposes. For example, you
may declare attribute labels differently based on the current scenario.
3.6.3
Validation Rules
When the data for a model is received from end users, it should be validated
to make sure it satisfies certain rules (called validation rules, also known
as business rules). For example, given a ContactForm model, you may want
to make sure all attributes are not empty and the email attribute contains
a valid email address. If the values for some attributes do not satisfy the
corresponding business rules, appropriate error messages should be displayed
to help the user to fix the errors.
You may call yii\base\Model::validate() to validate the received
data. The method will use the validation rules declared in yii\base\Model
::rules() to validate every relevant attribute. If no error is found, it will
return true. Otherwise, it will keep the errors in the yii\base\Model::
$errors property and return false. For example,
$model = new \app\models\ContactForm;
// populate model attributes with user inputs
$model->attributes = \Yii::$app->request->post(’ContactForm’);
if ($model->validate()) {
// all inputs are valid
} else {
// validation failed: $errors is an array containing error messages
$errors = $model->errors;
}
To declare validation rules associated with a model, override the yii\base
\Model::rules() method by returning the rules that the model attributes
should satisfy. The following example shows the validation rules declared for
the ContactForm model:
public function rules()
{
return [
82
CHAPTER 3. APPLICATION STRUCTURE
// the name, email, subject and body attributes are required
[[’name’, ’email’, ’subject’, ’body’], ’required’],
// the email attribute should be a valid email address
[’email’, ’email’],
];
}
A rule can be used to validate one or multiple attributes, and an attribute
may be validated by one or multiple rules. Please refer to the Validating
Input section for more details on how to declare validation rules.
Sometimes, you may want a rule to be applied only in certain scenarios.
To do so, you can specify the on property of a rule, like the following:
public function rules()
{
return [
// username, email and password are all required in "register"
scenario
[[’username’, ’email’, ’password’], ’required’, ’on’ => self::
SCENARIO_REGISTER],
// username and password are required in "login" scenario
[[’username’, ’password’], ’required’, ’on’ => self::SCENARIO_LOGIN
],
];
}
If you do not specify the on property, the rule would be applied in all scenarios. A rule is called an active rule if it can be applied in the current
scenario.
An attribute will be validated if and only if it is an active attribute
declared in scenarios() and is associated with one or multiple active rules
declared in rules().
3.6.4
Massive Assignment
Massive assignment is a convenient way of populating a model with user
inputs using a single line of code. It populates the attributes of a model
by assigning the input data directly to the yii\base\Model::$attributes
property. The following two pieces of code are equivalent, both trying to assign the form data submitted by end users to the attributes of the ContactForm
model. Clearly, the former, which uses massive assignment, is much cleaner
and less error prone than the latter:
$model = new \app\models\ContactForm;
$model->attributes = \Yii::$app->request->post(’ContactForm’);
$model = new \app\models\ContactForm;
$data = \Yii::$app->request->post(’ContactForm’, []);
$model->name = isset($data[’name’]) ? $data[’name’] : null;
3.6. MODELS
83
$model->email = isset($data[’email’]) ? $data[’email’] : null;
$model->subject = isset($data[’subject’]) ? $data[’subject’] : null;
$model->body = isset($data[’body’]) ? $data[’body’] : null;
Safe Attributes
Massive assignment only applies to the so-called safe attributes which are the
attributes listed in yii\base\Model::scenarios() for the current scenario
of a model. For example, if the User model has the following scenario declaration, then when the current scenario is login, only the username and password
can be massively assigned. Any other attributes will be kept untouched.
public function scenarios()
{
return [
self::SCENARIO_LOGIN => [’username’, ’password’],
self::SCENARIO_REGISTER => [’username’, ’email’, ’password’],
];
}
Info: The reason that massive assignment only applies to safe
attributes is because you want to control which attributes can be
modified by end user data. For example, if the User model has
a permission attribute which determines the permission assigned
to the user, you would like this attribute to be modifiable by
administrators through a backend interface only.
Because the default implementation of yii\base\Model::scenarios() will
return all scenarios and attributes found in yii\base\Model::rules(), if
you do not override this method, it means an attribute is safe as long as it
appears in one of the active validation rules.
For this reason, a special validator aliased safe is provided so that you can
declare an attribute to be safe without actually validating it. For example,
the following rules declare that both title and description are safe attributes.
public function rules()
{
return [
[[’title’, ’description’], ’safe’],
];
}
Unsafe Attributes
As described above, the yii\base\Model::scenarios() method serves for
two purposes: determining which attributes should be validated, and determining which attributes are safe. In some rare cases, you may want to
validate an attribute but do not want to mark it safe. You can do so by
84
CHAPTER 3. APPLICATION STRUCTURE
prefixing an exclamation mark ! to the attribute name when declaring it in
like the secret attribute in the following:
scenarios(),
public function scenarios()
{
return [
self::SCENARIO_LOGIN => [’username’, ’password’, ’!secret’],
];
}
When the model is in the login scenario, all three attributes will be validated.
However, only the username and password attributes can be massively assigned.
To assign an input value to the secret attribute, you have to do it explicitly
as follows,
$model->secret = $secret;
The same can be done in rules() method:
public function rules()
{
return [
[[’username’, ’password’, ’!secret’], ’required’, ’on’ => ’login’]
];
}
In this case attributes username, password and secret are required, but secret
must be assigned explicitly.
3.6.5
Data Exporting
Models often need to be exported in different formats. For example, you
may want to convert a collection of models into JSON or Excel format. The
exporting process can be broken down into two independent steps:
• models are converted into arrays;
• the arrays are converted into target formats.
You may just focus on the first step, because the second step can be achieved
by generic data formatters, such as yii\web\JsonResponseFormatter.
The simplest way of converting a model into an array is to use the yii
\base\Model::$attributes property. For example,
$post = \app\models\Post::findOne(100);
$array = $post->attributes;
By default, the yii\base\Model::$attributes property will return the values of all attributes declared in yii\base\Model::attributes().
A more flexible and powerful way of converting a model into an array is
to use the yii\base\Model::toArray() method. Its default behavior is the
same as that of yii\base\Model::$attributes. However, it allows you to
choose which data items, called fields, to be put in the resulting array and
how they should be formatted. In fact, it is the default way of exporting
3.6. MODELS
85
models in RESTful Web service development, as described in the Response
Formatting.
Fields
A field is simply a named element in the array that is obtained by calling
the yii\base\Model::toArray() method of a model.
By default, field names are equivalent to attribute names. However, you
can change this behavior by overriding the fields() and/or extraFields()
methods. Both methods should return a list of field definitions. The fields
defined by fields() are default fields, meaning that toArray() will return these
fields by default. The extraFields() method defines additionally available
fields which can also be returned by toArray() as long as you specify them
via the $expand parameter. For example, the following code will return all
fields defined in fields() and the prettyName and fullAddress fields if they are
defined in extraFields().
$array = $model->toArray([], [’prettyName’, ’fullAddress’]);
You can override fields() to add, remove, rename or redefine fields. The
return value of fields() should be an array. The array keys are the field
names, and the array values are the corresponding field definitions which
can be either property/attribute names or anonymous functions returning
the corresponding field values. In the special case when a field name is the
same as its defining attribute name, you can omit the array key. For example,
// explicitly list every field, best used when you want to make sure the
changes
// in your DB table or model attributes do not cause your field changes (to
keep API backward compatibility).
public function fields()
{
return [
// field name is the same as the attribute name
’id’,
// field name is "email", the corresponding attribute name is "
email_address"
’email’ => ’email_address’,
// field name is "name", its value is defined by a PHP callback
’name’ => function () {
return $this->first_name . ’ ’ . $this->last_name;
},
];
}
// filter out some fields, best used when you want to inherit the parent
implementation
// and blacklist some sensitive fields.
public function fields()
86
CHAPTER 3. APPLICATION STRUCTURE
{
$fields = parent::fields();
// remove fields that contain sensitive information
unset($fields[’auth_key’], $fields[’password_hash’], $fields[’
password_reset_token’]);
return $fields;
}
Warning: Because by default all attributes of a model will be
included in the exported array, you should examine your data
to make sure they do not contain sensitive information. If there
is such information, you should override fields() to filter them
out. In the above example, we choose to filter out auth_key,
password_hash and password_reset_token.
3.6.6
Best Practices
Models are the central places to represent business data, rules and logic.
They often need to be reused in different places. In a well-designed application, models are usually much fatter than controllers.
In summary, models
• may contain attributes to represent business data;
• may contain validation rules to ensure the data validity and integrity;
• may contain methods implementing business logic;
• should NOT directly access request, session, or any other environmental data. These data should be injected by controllers into models;
• should avoid embedding HTML or other presentational code - this is
better done in views;
• avoid having too many scenarios in a single model.
You may usually consider the last recommendation above when you are developing large complex systems. In these systems, models could be very fat
because they are used in many places and may thus contain many sets of
rules and business logic. This often ends up in a nightmare in maintaining
the model code because a single touch of the code could affect several different places. To make the model code more maintainable, you may take the
following strategy:
• Define a set of base model classes that are shared by different applications or modules. These model classes should contain minimal sets of
rules and logic that are common among all their usages.
• In each application or module that uses a model, define a concrete
model class by extending from the corresponding base model class.
The concrete model classes should contain rules and logic that are
specific for that application or module.
3.7. VIEWS
87
For example, in the Advanced Project Template12 , you may define a base
model class common\models\Post. Then for the front end application, you
define and use a concrete model class frontend\models\Post which extends
from common\models\Post. And similarly for the back end application, you
define backend\models\Post. With this strategy, you will be sure that the code
in frontend\models\Post is only specific to the front end application, and if
you make any change to it, you do not need to worry if the change may
break the back end application.
3.7
Views
Views are part of the MVC13 architecture. They are code responsible for
presenting data to end users. In a Web application, views are usually created
in terms of view templates which are PHP script files containing mainly
HTML code and presentational PHP code. They are managed by the view
application component which provides commonly used methods to facilitate
view composition and rendering. For simplicity, we often call view templates
or view template files as views.
3.7.1
Creating Views
As aforementioned, a view is simply a PHP script mixed with HTML and
PHP code. The following is the view that presents a login form. As you can
see, PHP code is used to generate the dynamic content, such as the page title
and the form, while HTML code organizes them into a presentable HTML
page.
title = ’Login’;
?>
= Html::encode($this->title) ?>
Please fill out the following fields to login:
= $form->field($model, ’username’) ?>
= $form->field($model, ’password’)->passwordInput() ?>
= Html::submitButton(’Login’) ?>
12
https://github.com/yiisoft/yii2-app-advanced/blob/master/docs/guide/
README.md
13
http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller
88
CHAPTER 3. APPLICATION STRUCTURE
Within a view, you can access $this which refers to the view component
managing and rendering this view template.
Besides $this, there may be other predefined variables in a view, such
as $model in the above example. These variables represent the data that are
pushed into the view by controllers or other objects which trigger the view
rendering.
Tip: The predefined variables are listed in a comment block at
beginning of a view so that they can be recognized by IDEs. It
is also a good way of documenting your views.
Security
When creating views that generate HTML pages, it is important that you
encode and/or filter the data coming from end users before presenting them.
Otherwise, your application may be subject to cross-site scripting14 attacks.
To display a plain text, encode it first by calling yii\helpers\Html::
encode(). For example, the following code encodes the user name before
displaying it:
= Html::encode($user->name) ?>
To display HTML content, use yii\helpers\HtmlPurifier to filter the content first. For example, the following code filters the post content before
displaying it:
= HtmlPurifier::process($post->text) ?>
Tip: While HTMLPurifier does excellent job in making output
safe, it is not fast. You should consider caching the filtering result
if your application requires high performance.
14
http://en.wikipedia.org/wiki/Cross-site_scripting
3.7. VIEWS
89
Organizing Views
Like controllers and models, there are conventions to organize views.
• For views rendered by a controller, they should be put under the directory @app/views/ControllerID by default, where ControllerID refers to
the controller ID. For example, if the controller class is PostController,
the directory would be @app/views/post; if it is PostCommentController,
the directory would be @app/views/post-comment. In case the controller
belongs to a module, the directory would be views/ControllerID under
the module directory.
• For views rendered in a widget, they should be put under the WidgetPath
/views directory by default, where WidgetPath stands for the directory
containing the widget class file.
• For views rendered by other objects, it is recommended that you follow
the similar convention as that for widgets.
You may customize these default view directories by overriding the yii\base
\ViewContextInterface::getViewPath() method of controllers or widgets.
3.7.2
Rendering Views
You can render views in controllers, widgets, or any other places by calling
view rendering methods. These methods share a similar signature shown as
follows,
/**
* @param string $view view
rendering method
* @param array $params the
* @return string rendering
*/
methodName($view, $params =
name or file path, depending on the actual
data to be passed to the view
result
[])
Rendering in Controllers
Within controllers, you may call the following controller methods to render
views:
• render(): renders a named view and applies a layout to the rendering
result.
• renderPartial(): renders a named view without any layout.
• renderAjax(): renders a named view without any layout, and injects
all registered JS/CSS scripts and files. It is usually used in response
to AJAX Web requests.
• renderFile(): renders a view specified in terms of a view file path or
alias.
• renderContent(): renders a static string by embedding it into the
currently applicable layout. This method is available since version
2.0.1.
90
CHAPTER 3. APPLICATION STRUCTURE
For example,
namespace app\controllers;
use
use
use
use
Yii;
app\models\Post;
yii\web\Controller;
yii\web\NotFoundHttpException;
class PostController extends Controller
{
public function actionView($id)
{
$model = Post::findOne($id);
if ($model === null) {
throw new NotFoundHttpException;
}
// renders a view named "view" and applies a layout to it
return $this->render(’view’, [
’model’ => $model,
]);
}
}
Rendering in Widgets
Within widgets, you may call the following widget methods to render views.
• render(): renders a named view.
• renderFile(): renders a view specified in terms of a view file path or
alias.
For example,
namespace app\components;
use yii\base\Widget;
use yii\helpers\Html;
class ListWidget extends Widget
{
public $items = [];
public function run()
{
// renders a view named "list"
return $this->render(’list’, [
’items’ => $this->items,
]);
}
}
3.7. VIEWS
91
Rendering in Views
You can render a view within another view by calling one of the following
methods provided by the view component:
• render(): renders a named view.
• renderAjax(): renders a named view and injects all registered JS/CSS
scripts and files. It is usually used in response to AJAX Web requests.
• renderFile(): renders a view specified in terms of a view file path or
alias.
For example, the following code in a view renders the _overview.php view
file which is in the same directory as the view being currently rendered.
Remember that $this in a view refers to the view component:
= $this->render(’_overview’) ?>
Rendering in Other Places
In any place, you can get access to the view application component by the expression Yii::$app->view and then call its aforementioned methods to render
a view. For example,
// displays the view file "@app/views/site/license.php"
echo \Yii::$app->view->renderFile(’@app/views/site/license.php’);
Named Views
When you render a view, you can specify the view using either a view name
or a view file path/alias. In most cases, you would use the former because it
is more concise and flexible. We call views specified using names as named
views.
A view name is resolved into the corresponding view file path according
to the following rules:
• A view name may omit the file extension name. In this case, .php will be
used as the extension. For example, the view name about corresponds
to the file name about.php.
• If the view name starts with double slashes //, the corresponding view
file path would be @app/views/ViewName. That is, the view is looked for
under the application’s view path. For example, //site/about will
be resolved into @app/views/site/about.php.
• If the view name starts with a single slash /, the view file path is formed
by prefixing the view name with the view path of the currently active
module. If there is no active module, @app/views/ViewName will be used.
For example, /user/create will be resolved into @app/modules/user/views
/user/create.php, if the currently active module is user. If there is no
active module, the view file path would be @app/views/user/create.php.
92
CHAPTER 3. APPLICATION STRUCTURE
• If the view is rendered with a context and the context implements yii
\base\ViewContextInterface, the view file path is formed by prefixing the view path of the context to the view name. This mainly applies
to the views rendered within controllers and widgets. For example,
about will be resolved into @app/views/site/about.php if the context is
the controller SiteController.
• If a view is rendered within another view, the directory containing the
other view file will be prefixed to the new view name to form the actual
view file path. For example, item will be resolved into @app/views/post
/item.php if it is being rendered in the view @app/views/post/index.php.
According to the above rules, calling $this->render(’view’) in a controller app
\controllers\PostController will actually render the view file @app/views/post/
view.php, while calling $this->render(’_overview’) in that view will render the
view file @app/views/post/_overview.php.
Accessing Data in Views
There are two approaches to access data within a view: push and pull.
By passing the data as the second parameter to the view rendering methods, you are using the push approach. The data should be represented as
an array of name-value pairs. When the view is being rendered, the PHP
extract() function will be called on this array so that the array is extracted
into variables in the view. For example, the following view rendering code in
a controller will push two variables to the report view: $foo = 1 and $bar = 2.
echo $this->render(’report’, [
’foo’ => 1,
’bar’ => 2,
]);
The pull approach actively retrieves data from the view component or other
objects accessible in views (e.g. Yii::$app). Using the code below as an
example, within the view you can get the controller object by the expression
$this->context. And as a result, it is possible for you to access any properties
or methods of the controller in the report view, such as the controller ID
shown in the following:
The controller ID is: = $this->context->id ?>
The push approach is usually the preferred way of accessing data in views,
because it makes views less dependent on context objects. Its drawback is
that you need to manually build the data array all the time, which could
become tedious and error prone if a view is shared and rendered in different
places.
3.7. VIEWS
93
Sharing Data among Views
The view component provides the params property that you can use to share
data among views.
For example, in an about view, you can have the following code which
specifies the current segment of the breadcrumbs.
$this->params[’breadcrumbs’][] = ’About Us’;
Then, in the layout file, which is also a view, you can display the breadcrumbs
using the data passed along params:
= yii\widgets\Breadcrumbs::widget([
’links’ => isset($this->params[’breadcrumbs’]) ? $this->params[’
breadcrumbs’] : [],
]) ?>
3.7.3
Layouts
Layouts are a special type of views that represent the common parts of
multiple views. For example, the pages for most Web applications share the
same page header and footer. While you can repeat the same page header
and footer in every view, a better way is to do this once in a layout and
embed the rendering result of a content view at an appropriate place in the
layout.
Creating Layouts
Because layouts are also views, they can be created in the similar way as
normal views. By default, layouts are stored in the directory @app/views/
layouts. For layouts used within a module, they should be stored in the views
/layouts directory under the module directory. You may customize the
default layout directory by configuring the yii\base\Module::$layoutPath
property of the application or modules.
The following example shows how a layout looks like. Note that for
illustrative purpose, we have greatly simplified the code in the layout. In
practice, you may want to add more content to it, such as head tags, main
menu, etc.
beginPage() ?>
94
CHAPTER 3. APPLICATION STRUCTURE
= Html::csrfMetaTags() ?>
= Html::encode($this->title) ?>
head() ?>
beginBody() ?>
My Company
= $content ?>
endBody() ?>
endPage() ?>
As you can see, the layout generates the HTML tags that are common to
all pages. Within the section, the layout echoes the $content variable
which represents the rendering result of content views and is pushed into the
layout when yii\base\Controller::render() is called.
Most layouts should call the following methods like shown in the above
code. These methods mainly trigger events about the rendering process so
that scripts and tags registered in other places can be properly injected into
the places where these methods are called.
• beginPage(): This method should be called at the very beginning of
the layout. It triggers the EVENT_BEGIN_PAGE event which indicates
the beginning of a page.
• endPage(): This method should be called at the end of the layout. It
triggers the EVENT_END_PAGE event which indicates the end of a page.
• head(): This method should be called within the section of an
HTML page. It generates a placeholder which will be replaced with
the registered head HTML code (e.g. link tags, meta tags) when a
page finishes rendering.
• beginBody(): This method should be called at the beginning of the
section. It triggers the EVENT_BEGIN_BODY event and generates
a placeholder which will be replaced by the registered HTML code (e.g.
JavaScript) targeted at the body begin position.
• endBody(): This method should be called at the end of the section. It triggers the EVENT_END_BODY event and generates a placeholder
which will be replaced by the registered HTML code (e.g. JavaScript)
targeted at the body end position.
Accessing Data in Layouts
Within a layout, you have access to two predefined variables: $this and
The former refers to the view component, like in normal views,
while the latter contains the rendering result of a content view which is
rendered by calling the render() method in controllers.
If you want to access other data in layouts, you have to use the pull
$content.
3.7. VIEWS
95
method as described in the Accessing Data in Views subsection. If you want
to pass data from a content view to a layout, you may use the method
described in the Sharing Data among Views subsection.
Using Layouts
As described in the Rendering in Controllers subsection, when you render a
view by calling the render() method in a controller, a layout will be applied
to the rendering result. By default, the layout @app/views/layouts/main.php
will be used.
You may use a different layout by configuring either yii\base\Application
::$layout or yii\base\Controller::$layout. The former governs the layout used by all controllers, while the latter overrides the former for individual
controllers. For example, the following code makes the post controller to use
@app/views/layouts/post.php as the layout when rendering its views. Other
controllers, assuming their layout property is untouched, will still use the
default @app/views/layouts/main.php as the layout.
namespace app\controllers;
use yii\web\Controller;
class PostController extends Controller
{
public $layout = ’post’;
// ...
}
For controllers belonging to a module, you may also configure the module’s
layout property to use a particular layout for these controllers.
Because the layout property may be configured at different levels (controllers, modules, application), behind the scene Yii takes two steps to determine
what is the actual layout file being used for a particular controller.
In the first step, it determines the layout value and the context module:
• If the yii\base\Controller::$layout property of the controller is
not null, use it as the layout value and the module of the controller as
the context module.
• If the yii\base\Controller::$layout property of the controller is
null, search through all ancestor modules (including the application
itself) of the controller and find the first module whose layout property
is not null. Use that module and its layout value as the context
module and the chosen layout value. If such a module cannot be found,
it means no layout will be applied.
In the second step, it determines the actual layout file according to the layout
value and the context module determined in the first step. The layout value
can be:
96
CHAPTER 3. APPLICATION STRUCTURE
• a path alias (e.g. @app/views/layouts/main).
• an absolute path (e.g. /main): the layout value starts with a slash.
The actual layout file will be looked for under the application’s layout
path which defaults to @app/views/layouts.
• a relative path (e.g. main): the actual layout file will be looked for under
the context module’s layout path which defaults to the views/layouts
directory under the module directory.
• the boolean value false: no layout will be applied.
If the layout value does not contain a file extension, it will use the default
one .php.
Nested Layouts
Sometimes you may want to nest one layout in another. For example, in
different sections of a Web site, you want to use different layouts, while all
these layouts share the same basic layout that generates the overall HTML5
page structure. You can achieve this goal by calling beginContent() and
endContent() in the child layouts like the following:
beginContent(’@app/views/layouts/base.php’); ?>
...child layout content here...
endContent(); ?>
As shown above, the child layout content should be enclosed within beginContent()
and endContent(). The parameter passed to beginContent() specifies what
is the parent layout. It can be either a layout file or alias.
Using the above approach, you can nest layouts in more than one levels.
Using Blocks
Blocks allow you to specify the view content in one place while displaying
it in another. They are often used together with layouts. For example, you
can define a block in a content view and display it in the layout.
You call beginBlock() and endBlock() to define a block. The block
can then be accessed via $view->blocks[$blockID], where $blockID stands for
a unique ID that you assign to the block when defining it.
The following example shows how you can use blocks to customize specific
parts of a layout in a content view.
First, in a content view, define one or multiple blocks:
...
beginBlock(’block1’); ?>
...content of block1...
3.7. VIEWS
97
endBlock(); ?>
...
beginBlock(’block3’); ?>
...content of block3...
endBlock(); ?>
Then, in the layout view, render the blocks if they are available, or display
some default content if a block is not defined.
...
blocks[’block1’])): ?>
= $this->blocks[’block1’] ?>
... default content for block1 ...
...
blocks[’block2’])): ?>
= $this->blocks[’block2’] ?>
... default content for block2 ...
...
blocks[’block3’])): ?>
= $this->blocks[’block3’] ?>
... default content for block3 ...
...
3.7.4
Using View Components
View components provides many view-related features. While you can get
view components by creating individual instances of yii\base\View or its
child class, in most cases you will mainly use the view application component. You can configure this component in application configurations like the
following:
[
// ...
’components’ => [
’view’ => [
’class’ => ’app\components\View’,
],
// ...
],
98
CHAPTER 3. APPLICATION STRUCTURE
]
View components provide the following useful view-related features, each
described in more details in a separate section:
• theming: allows you to develop and change the theme for your Web
site.
• fragment caching: allows you to cache a fragment within a Web page.
• client script handling: supports CSS and JavaScript registration and
rendering.
• asset bundle handling: supports registering and rendering of asset
bundles.
• alternative template engines: allows you to use other template engines,
such as Twig15 , Smarty16 .
You may also frequently use the following minor yet useful features when
you are developing Web pages.
Setting Page Titles
Every Web page should have a title. Normally the title tag is being displayed
in a layout. However, in practice the title is often determined in content
views rather than layouts. To solve this problem, yii\web\View provides
the title property for you to pass the title information from content views
to layouts.
To make use of this feature, in each content view, you can set the page
title like the following:
title = ’My page title’;
?>
Then in the layout, make sure you have the following code in the
section:
= Html::encode($this->title) ?>
Registering Meta Tags
Web pages usually need to generate various meta tags needed by different
parties. Like page titles, meta tags appear in the section and are
usually generated in layouts.
If you want to specify what meta tags to generate in content views,
you can call yii\web\View::registerMetaTag() in a content view, like the
following:
15
16
http://twig.sensiolabs.org/
http://www.smarty.net/
3.7. VIEWS
99
registerMetaTag([’name’ => ’keywords’, ’content’ => ’yii, framework,
php’]);
?>
The above code will register a “keywords” meta tag with the view component.
The registered meta tag is rendered after the layout finishes rendering. The
following HTML code will be generated and inserted at the place where you
call yii\web\View::head() in the layout:
Note that if you call yii\web\View::registerMetaTag() multiple times, it
will register multiple meta tags, regardless whether the meta tags are the
same or not.
To make sure there is only a single instance of a meta tag type, you can
specify a key as a second parameter when calling the method. For example,
the following code registers two “description” meta tags. However, only the
second one will be rendered.
$this->registerMetaTag([’name’ => ’description’, ’content’ => ’This is my
cool website made with Yii!’], ’description’);
$this->registerMetaTag([’name’ => ’description’, ’content’ => ’This website
is about funny raccoons.’], ’description’);
Registering Link Tags
Like meta tags, link tags are useful in many cases, such as customizing
favicon, pointing to RSS feed or delegating OpenID to another server. You
can work with link tags in the similar way as meta tags by using yii\web
\View::registerLinkTag(). For example, in a content view, you can register a link tag like follows,
$this->registerLinkTag([
’title’ => ’Live News for Yii’,
’rel’ => ’alternate’,
’type’ => ’application/rss+xml’,
’href’ => ’http://www.yiiframework.com/rss.xml/’,
]);
The code above will result in
Similar as registerMetaTag(), you can specify a key when calling registerLinkTag()
to avoid generating repeated link tags.
3.7.5
View Events
View components trigger several events during the view rendering process.
You may respond to these events to inject content into views or process the
rendering results before they are sent to end users.
100
CHAPTER 3. APPLICATION STRUCTURE
• EVENT_BEFORE_RENDER: triggered at the beginning of rendering a file
in a controller. Handlers of this event may set yii\base\ViewEvent
::$isValid to be false to cancel the rendering process.
• EVENT_AFTER_RENDER: triggered after rendering a file by the call of
yii\base\View::afterRender(). Handlers of this event may obtain
the rendering result through yii\base\ViewEvent::$output and may
modify this property to change the rendering result.
• EVENT_BEGIN_PAGE: triggered by the call of yii\base\View::beginPage()
in layouts.
• EVENT_END_PAGE: triggered by the call of yii\base\View::endPage()
in layouts.
• EVENT_BEGIN_BODY: triggered by the call of yii\web\View::beginBody()
in layouts.
• EVENT_END_BODY: triggered by the call of yii\web\View::endBody()
in layouts.
For example, the following code injects the current date at the end of the
page body:
\Yii::$app->view->on(View::EVENT_END_BODY, function () {
echo date(’Y-m-d’);
});
3.7.6
Rendering Static Pages
Static pages refer to those Web pages whose main content are mostly static
without the need of accessing dynamic data pushed from controllers.
You can output static pages by putting their code in the view, and then
using the code like the following in a controller:
public function actionAbout()
{
return $this->render(’about’);
}
If a Web site contains many static pages, it would be very tedious repeating
the similar code many times. To solve this problem, you may introduce a
standalone action called yii\web\ViewAction in a controller. For example,
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
public function actions()
{
return [
’page’ => [
’class’ => ’yii\web\ViewAction’,
],
3.8. MODULES
101
];
}
}
Now if you create a view named about under the directory @app/views/site/
pages, you will be able to display this view by the following URL:
http://localhost/index.php?r=site%2Fpage&view=about
The GET parameter view tells yii\web\ViewAction which view is requested.
The action will then look for this view under the directory @app/views/site
/pages. You may configure yii\web\ViewAction::$viewPrefix to change
the directory for searching these views.
3.7.7
Best Practices
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.
• should not contain code that performs DB queries. Such code should
be done in models.
• should avoid direct access to request data, such as $_GET, $_POST. This
belongs to controllers. If request data is needed, they should be pushed
into views by controllers.
• may read model properties, but should not modify them.
To make views more manageable, avoid creating views that are too complex
or contain too much redundant code. You may use the following techniques
to achieve this goal:
• use layouts to represent common presentational sections (e.g. page
header, footer).
• divide a complicated view into several smaller ones. The smaller views
can be rendered and assembled into a bigger one using the rendering
methods that we have described.
• create and use widgets as building blocks of views.
• create and use helper classes to transform and format data in views.
3.8
Modules
Modules are self-contained software units that consist of models, views, controllers, and other supporting components. End users can access the controllers of a module when it is installed in application. For these reasons,
modules are often viewed as mini-applications. Modules differ from applications in that modules cannot be deployed alone and must reside within
applications.
102
CHAPTER 3. APPLICATION STRUCTURE
3.8.1
Creating Modules
A module is organized as a directory which is called the base path of the
module. Within the directory, there are sub-directories, such as controllers,
models, views, which hold controllers, models, views, and other code, just like
in an application. The following example shows the content within a module:
forum/
Module.php
controllers/
DefaultController.php
models/
views/
layouts/
default/
index.php
the module class file
containing controller class files
the default controller class file
containing model class files
containing controller view and layout files
containing layout view files
containing view files for DefaultController
the index view file
Module Classes
Each module should have a unique module class which extends from yii
\base\Module. The class should be located directly under the module’s base
path and should be autoloadable. When a module is being accessed, a single
instance of the corresponding module class will be created. Like application
instances, module instances are used to share data and components for code
within modules.
The following is an example how a module class may look like:
namespace app\modules\forum;
class Module extends \yii\base\Module
{
public function init()
{
parent::init();
$this->params[’foo’] = ’bar’;
// ... other initialization code ...
}
}
If the init() method contains a lot of code initializing the module’s properties, you may also save them in terms of a configuration and load it with the
following code in init():
public function init()
{
parent::init();
// initialize the module with the configuration loaded from config.php
\Yii::configure($this, require __DIR__ . ’/config.php’);
}
where the configuration file config.php may contain the following content,
similar to that in an application configuration.
3.8. MODULES
103
[
// list of component configurations
],
’params’ => [
// list of parameters
],
];
Controllers in Modules
When creating controllers in a module, a convention is to put the controller
classes under the controllers sub-namespace of the namespace of the module class. This also means the controller class files should be put in the
controllers directory within the module’s base path. For example, to create a post controller in the forum module shown in the last subsection, you
should declare the controller class like the following:
namespace app\modules\forum\controllers;
use yii\web\Controller;
class PostController extends Controller
{
// ...
}
You may customize the namespace of controller classes by configuring the
yii\base\Module::$controllerNamespace property. In case some of the
controllers are outside of this namespace, you may make them accessible
by configuring the yii\base\Module::$controllerMap property, similar to
what you do in an application.
Views in Modules
Views in a module should be put in the views directory within the module’s
base path. For views rendered by a controller in the module, they should
be put under the directory views/ControllerID, where ControllerID refers to
the controller ID. For example, if the controller class is PostController, the
directory would be views/post within the module’s base path.
A module can specify a layout that is applied to the views rendered by the
module’s controllers. The layout should be put in the views/layouts directory
by default, and you should configure the yii\base\Module::$layout property to point to the layout name. If you do not configure the layout property,
the application’s layout will be used instead.
104
CHAPTER 3. APPLICATION STRUCTURE
Console commands in Modules
Your module may also declare commands, that will be available through the
Console mode.
In order for the command line utility to see your commands, you will
need to change the yii\base\Module::$controllerNamespace property,
when Yii is executed in the console mode, and point it to your commands
namespace.
One way to achieve that is to test the instance type of the Yii application
in the module’s init() method:
public function init()
{
parent::init();
if (Yii::$app instanceof \yii\console\Application) {
$this->controllerNamespace = ’app\modules\forum\commands’;
}
}
Your commands will then be available from the command line using the
following route:
yii //
3.8.2
Using Modules
To use a module in an application, simply configure the application by listing
the module in the modules property of the application. The following code
in the application configuration uses the forum module:
[
’modules’ => [
’forum’ => [
’class’ => ’app\modules\forum\Module’,
// ... other configurations for the module ...
],
],
]
The modules property takes an array of module configurations. Each array
key represents a module ID which uniquely identifies the module among all
modules in the application, and the corresponding array value is a configuration for creating the module.
Routes
Like accessing controllers in an application, routes are used to address controllers in a module. A route for a controller within a module must begin with
the module ID followed by the controller ID and action ID. For example, if an
application uses a module named forum, then the route forum/post/index would
3.8. MODULES
105
represent the index action of the post controller in the module. If the route
only contains the module ID, then the yii\base\Module::$defaultRoute
property, which defaults to default, will determine which controller/action
should be used. This means a route forum would represent the default controller in the forum module.
The URL manager rules for the modules should be added before yii
\web\UrlManager::parseRequest() is fired. That means doing it in module’s init() won’t work because module will be initialized when routes were
already processed. Thus, the rules should be added at bootstrap stage.
It is a also a good practice to wrap module’s URL rules with yii\web
\GroupUrlRule.
In case a module is used to version API, its URL rules should be added
directly in urlManager section of the application config.
Accessing Modules
Within a module, you may often need to get the instance of the module
class so that you can access the module ID, module parameters, module
components, etc. You can do so by using the following statement:
$module = MyModuleClass::getInstance();
where MyModuleClass refers to the name of the module class that you are
interested in. The getInstance() method will return the currently requested
instance of the module class. If the module is not requested, the method will
return null. Note that you do not want to manually create a new instance
of the module class because it will be different from the one created by Yii
in response to a request.
Info: When developing a module, you should not assume the
module will use a fixed ID. This is because a module can be
associated with an arbitrary ID when used in an application or
within another module. In order to get the module ID, you should
use the above approach to get the module instance first, and then
get the ID via $module->id.
You may also access the instance of a module using the following approaches:
// get the child module whose ID is "forum"
$module = \Yii::$app->getModule(’forum’);
// get the module to which the currently requested controller belongs
$module = \Yii::$app->controller->module;
The first approach is only useful when you know the module ID, while the
second approach is best used when you know about the controllers being
requested.
Once you have the module instance, you can access parameters and components registered with the module. For example,
106
CHAPTER 3. APPLICATION STRUCTURE
$maxPostCount = $module->params[’maxPostCount’];
Bootstrapping Modules
Some modules may need to be run for every request. The yii\debug\Module
module is such an example. To do so, list the IDs of such modules in the
bootstrap property of the application.
For example, the following application configuration makes sure the debug
module is always loaded:
[
’bootstrap’ => [
’debug’,
],
’modules’ => [
’debug’ => ’yii\debug\Module’,
],
]
3.8.3
Nested Modules
Modules can be nested in unlimited levels. That is, a module can contain
another module which can contain yet another module. We call the former
parent module while the latter child module. Child modules must be declared
in the modules property of their parent modules. For example,
namespace app\modules\forum;
class Module extends \yii\base\Module
{
public function init()
{
parent::init();
$this->modules = [
’admin’ => [
// you should consider using a shorter namespace here!
’class’ => ’app\modules\forum\modules\admin\Module’,
],
];
}
}
For a controller within a nested module, its route should include the IDs of
all its ancestor modules. For example, the route forum/admin/dashboard/index
represents the index action of the dashboard controller in the admin module
which is a child module of the forum module.
Info: The getModule() method only returns the child module
directly belonging to its parent. The yii\base\Application::
3.8. MODULES
107
$loadedModules property keeps a list of loaded modules, including both direct children and nested ones, indexed by their class
names.
3.8.4
Accessing components from within modules
Since version 2.0.13 modules support tree traversal. This allows module developers to reference (application) components via the service locator that
is their module. This means that it is preferable to use $module->get(’db’)
over Yii::$app->get(’db’). The user of a module is able to specify a specific component to be used for the module in case a different component
(configuration) is required.
For example consider partial this application configuration:
’components’ => [
’db’ => [
’tablePrefix’ => ’main_’,
’class’ => Connection::class,
’enableQueryCache’ => false
],
],
’modules’ => [
’mymodule’ => [
’components’ => [
’db’ => [
’tablePrefix’ => ’module_’,
’class’ => Connection::class
],
],
],
],
The application database tables will be prefixed with main_, while all module
tables will be prefixed with module_. Note that configuration above is not
merged; the modules’ component for example will have the query cache
enabled since that is the default value.
3.8.5
Best Practices
Modules are best used in large applications whose features can be divided
into several groups, each consisting of a set of closely related features. Each
such feature group can be developed as a module which is developed and
maintained by a specific developer or team.
Modules are also a good way of reusing code at the feature group level.
Some commonly used features, such as user management, comment management, can all be developed in terms of modules so that they can be reused
easily in future projects.
108
CHAPTER 3. APPLICATION STRUCTURE
3.9
Filters
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).
3.9.1
Using Filters
Filters are essentially a special kind of behaviors. Therefore, using filters is
the same as using behaviors. You can declare filters in a controller class by
overriding its behaviors() method like the following:
public function behaviors()
{
return [
[
’class’ => ’yii\filters\HttpCache’,
’only’ => [’index’, ’view’],
’lastModified’ => function ($action, $params) {
$q = new \yii\db\Query();
return $q->from(’user’)->max(’updated_at’);
},
],
];
}
By default, filters declared in a controller class will be applied to all actions
in that controller. You can, however, explicitly specify which actions the
filter should be applied to by configuring the only property. In the above
example, the HttpCache filter only applies to the index and view actions. You
can also configure the except property to blacklist some actions from being
filtered.
Besides controllers, you can also declare filters in a module or application.
When you do so, the filters will be applied to all controller actions belonging
to that module or application, unless you configure the filters’ only and
except properties like described above.
Note: When declaring filters in modules or applications, you
should use routes instead of action IDs in the only and except
properties. This is because action IDs alone cannot fully specify
actions within the scope of a module or application.
When multiple filters are configured for a single action, they are applied
according to the rules described below:
3.9. FILTERS
109
• Pre-filtering
– Apply filters declared in the application in the order they are
listed in behaviors().
– Apply filters declared in the module in the order they are listed
in behaviors().
– Apply filters declared in the controller in the order they are listed
in behaviors().
– If any of the filters cancel the action execution, the filters (both
pre-filters and post-filters) after it will not be applied.
• Running the action if it passes the pre-filtering.
• Post-filtering
– Apply filters declared in the controller in the reverse order they
are listed in behaviors().
– Apply filters declared in the module in the reverse order they are
listed in behaviors().
– Apply filters declared in the application in the reverse order they
are listed in behaviors().
3.9.2
Creating Filters
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);
}
110
CHAPTER 3. APPLICATION STRUCTURE
}
3.9.3
Core Filters
Yii provides a set of commonly used filters, found primarily under the yii\
filters namespace. In the following, we will briefly introduce these filters.
AccessControl
AccessControl provides simple access control based on a set of rules. In
particular, before an action is executed, AccessControl will examine the listed
rules and find the first one that matches the current context variables (such
as user IP address, user login status, etc.) The matching rule will dictate
whether to allow or deny the execution of the requested action. If no rule
matches, the access will be denied.
The following example shows how to allow authenticated users to access
the create and update actions while denying all other users from accessing
these two actions.
use yii\filters\AccessControl;
public function behaviors()
{
return [
’access’ => [
’class’ => AccessControl::className(),
’only’ => [’create’, ’update’],
’rules’ => [
// allow authenticated users
[
’allow’ => true,
’roles’ => [’@’],
],
// everything else is denied by default
],
],
];
}
For more details about access control in general, please refer to the Authorization section.
Authentication Method Filters
Authentication method filters are used to authenticate a user using various
methods, such as HTTP Basic Auth17 , OAuth 218 . These filter classes are
all under the yii\filters\auth namespace.
17
18
http://en.wikipedia.org/wiki/Basic_access_authentication
http://oauth.net/2/
3.9. FILTERS
111
The following example shows how you can use yii\filters\auth\HttpBasicAuth
to authenticate a user using an access token based on HTTP Basic Auth
method. Note that in order for this to work, your user identity class
must implement the findIdentityByAccessToken() method.
use yii\filters\auth\HttpBasicAuth;
public function behaviors()
{
return [
’basicAuth’ => [
’class’ => HttpBasicAuth::className(),
],
];
}
Authentication method filters are commonly used in implementing RESTful
APIs. For more details, please refer to the RESTful Authentication section.
ContentNegotiator
ContentNegotiator supports response format negotiation and application
language negotiation. It will try to determine the response format and/or
language by examining GET parameters and Accept HTTP header.
In the following example, ContentNegotiator is configured to support
JSON and XML response formats, and English (United States) and German
languages.
use yii\filters\ContentNegotiator;
use yii\web\Response;
public function behaviors()
{
return [
[
’class’ => ContentNegotiator::className(),
’formats’ => [
’application/json’ => Response::FORMAT_JSON,
’application/xml’ => Response::FORMAT_XML,
],
’languages’ => [
’en-US’,
’de’,
],
],
];
}
Response formats and languages often need to be determined much earlier
during the application lifecycle. For this reason, ContentNegotiator is designed in a way such that it can also be used as a bootstrapping component
112
CHAPTER 3. APPLICATION STRUCTURE
besides being used as a filter. For example, you may configure it in the
application configuration like the following:
use yii\filters\ContentNegotiator;
use yii\web\Response;
[
’bootstrap’ => [
[
’class’ => ContentNegotiator::className(),
’formats’ => [
’application/json’ => Response::FORMAT_JSON,
’application/xml’ => Response::FORMAT_XML,
],
’languages’ => [
’en-US’,
’de’,
],
],
],
];
Info: In case the preferred content type and language cannot be
determined from a request, the first format and language listed
in formats and languages will be used.
HttpCache
HttpCache implements client-side caching by utilizing the Last-Modified and
Etag HTTP headers. For example,
use yii\filters\HttpCache;
public function behaviors()
{
return [
[
’class’ => HttpCache::className(),
’only’ => [’index’],
’lastModified’ => function ($action, $params) {
$q = new \yii\db\Query();
return $q->from(’user’)->max(’updated_at’);
},
],
];
}
Please refer to the HTTP Caching section for more details about using HttpCache.
3.9. FILTERS
113
PageCache
PageCache implements server-side caching of whole pages. In the following
example, PageCache is applied to the index action to cache the whole page for
maximum 60 seconds or until the count of entries in the post table changes. It
also stores different versions of the page depending on the chosen application
language.
use yii\filters\PageCache;
use yii\caching\DbDependency;
public function behaviors()
{
return [
’pageCache’ => [
’class’ => PageCache::className(),
’only’ => [’index’],
’duration’ => 60,
’dependency’ => [
’class’ => DbDependency::className(),
’sql’ => ’SELECT COUNT(*) FROM post’,
],
’variations’ => [
\Yii::$app->language,
]
],
];
}
Please refer to the Page Caching section for more details about using PageCache.
RateLimiter
RateLimiter implements a rate limiting algorithm based on the leaky bucket
algorithm19 . It is primarily used in implementing RESTful APIs. Please
refer to the Rate Limiting section for details about using this filter.
VerbFilter
VerbFilter checks if the HTTP request methods are allowed by the requested
actions. If not allowed, it will throw an HTTP 405 exception. In the following
example, VerbFilter is declared to specify a typical set of allowed request
methods for CRUD actions.
use yii\filters\VerbFilter;
public function behaviors()
{
return [
’verbs’ => [
19
http://en.wikipedia.org/wiki/Leaky_bucket
114
CHAPTER 3. APPLICATION STRUCTURE
’class’ => VerbFilter::className(),
’actions’ => [
’index’ => [’get’],
’view’
=> [’get’],
’create’ => [’get’, ’post’],
’update’ => [’get’, ’put’, ’post’],
’delete’ => [’post’, ’delete’],
],
],
];
}
Cors
Cross-origin resource sharing CORS20 is a mechanism that allows many resources (e.g. fonts, JavaScript, etc.) on a Web page to be requested from
another domain outside the domain the resource originated from. In particular, JavaScript’s AJAX calls can use the XMLHttpRequest mechanism. Such
“cross-domain” requests would otherwise be forbidden by Web browsers, per
the same origin security policy. CORS defines a way in which the browser
and the server can interact to determine whether or not to allow the crossorigin request.
The Cors filter should be defined before Authentication / Authorization filters to make sure the CORS headers will always be sent.
use yii\filters\Cors;
use yii\helpers\ArrayHelper;
public function behaviors()
{
return ArrayHelper::merge([
[
’class’ => Cors::className(),
],
], parent::behaviors());
}
Also check the section on REST Controllers if you want to add the CORS
filter to an yii\rest\ActiveController class in your API.
The Cors filtering could be tuned using the $cors property.
• cors[’Origin’]: array used to define allowed origins. Can be [’*’
] (everyone) or [’http://www.myserver.net’, ’http://www.myotherserver.
com’]. Default to [’*’].
• cors[’Access-Control-Request-Method’]: array of allowed verbs like [’
GET’, ’OPTIONS’, ’HEAD’]. Default to [’GET’, ’POST’, ’PUT’, ’PATCH’, ’
DELETE’, ’HEAD’, ’OPTIONS’].
20
https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS
3.9. FILTERS
115
• cors[’Access-Control-Request-Headers’]: array of allowed headers. Can
be [’*’] all headers or specific ones [’X-Request-With’]. Default to [’*
’].
• cors[’Access-Control-Allow-Credentials’]: define if current request can
be made using credentials. Can be true, false or null (not set). Default
to null.
• cors[’Access-Control-Max-Age’]: define lifetime of pre-flight request. Default to 86400.
For example, allowing CORS for origin : http://www.myserver.net with method
GET, HEAD and OPTIONS :
use yii\filters\Cors;
use yii\helpers\ArrayHelper;
public function behaviors()
{
return ArrayHelper::merge([
[
’class’ => Cors::className(),
’cors’ => [
’Origin’ => [’http://www.myserver.net’],
’Access-Control-Request-Method’ => [’GET’, ’HEAD’, ’OPTIONS’
],
],
],
], parent::behaviors());
}
You may tune the CORS headers by overriding default parameters on a per
action basis. For example adding the Access-Control-Allow-Credentials for
the login action could be done like this :
use yii\filters\Cors;
use yii\helpers\ArrayHelper;
public function behaviors()
{
return ArrayHelper::merge([
[
’class’ => Cors::className(),
’cors’ => [
’Origin’ => [’http://www.myserver.net’],
’Access-Control-Request-Method’ => [’GET’, ’HEAD’, ’OPTIONS’
],
],
’actions’ => [
’login’ => [
’Access-Control-Allow-Credentials’ => true,
]
]
],
], parent::behaviors());
}
116
CHAPTER 3. APPLICATION STRUCTURE
3.10
Widgets
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:
= DatePicker::widget([’name’ => ’date’]) ?>
There are a good number of widgets bundled with Yii, such as active form,
menu, jQuery UI widgets21 , Twitter Bootstrap widgets22 . 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.
3.10.1
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.
= 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 Source Exif Data:
File Type : PDF File Type Extension : pdf MIME Type : application/pdf PDF Version : 1.5 Linearized : No Author : " Qiang Xue, Alexander Makarov, Carsten Brandt, Klimov Paul, and many contributors from the Yii community " Creator : LaTeX with hyperref package Modify Date : 2018:11:23 22:55:28+02:00 Subject : Trapped : False Create Date : 2018:11:23 01:06:44+01:00 PXC Viewer Info : PDF-XChange Viewer;2.5.322.9 [ ];Jul 3 2018;10:04:47;D:20181123225528+02'00' PTEX Fullbanner : This is pdfTeX, Version 3.14159265-2.6-1.40.17 (TeX Live 2016/Debian) kpathsea version 6.2.2 Page Count : 589 XMP Toolkit : XMP Core 4.1.1 Creator Tool : LaTeX with hyperref package Producer : pdfTeX-1.40.17 Format : application/pdf Description : Title : "The definitive Guide to Yii 2.0" Page Mode : None Page Layout : SinglePageEXIF Metadata provided by EXIF.tools