The Definitive Guide To Yii 2.0 En

User Manual:

Open the PDF directly: View PDF PDF.
Page Count: 589

DownloadThe Definitive Guide To Yii 2.0 Yii-guide-2.0-en
Open PDF In BrowserView 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  ’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:

field($model, ’username’) ?>
field($model, ’password’)->passwordInput() ?>
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: 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:

  • : name) ?>
  • : email) ?>
The entry view displays an HTML form. It should be stored in the file views/site/entry.php. field($model, ’name’) ?> field($model, ’email’) ?>
’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: field($model, ’name’)->label(’Your Name’) ?> 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

  • code} ({$country->name})") ?>: population ?>
$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’; ?>

title) ?>

Please fill out the following fields to login:

field($model, ’username’) ?> field($model, ’password’)->passwordInput() ?> 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:
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:
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: 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: 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: 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::encode($this->title) ?> head() ?> beginBody() ?>
My Company
© 2014 by My Company
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’])): ?> blocks[’block1’] ?> ... default content for block1 ... ... blocks[’block2’])): ?> blocks[’block2’] ?> ... default content for block2 ... ... blocks[’block3’])): ?> 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: ’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. $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
tags at the place where begin() and end() are called, respectively. Anything in between will be rendered as is. ’login-form’]); ?> field($model, ’username’) ?> field($model, ’password’)->passwordInput() ?>
Note that unlike yii\base\Widget::widget() which returns the rendering result of a widget, the method yii\base\Widget::begin() returns an instance of the widget which you can use to build the widget content. Note: Some widgets will use output buffering23 to adjust the enclosed content when yii\base\Widget::end() is called. For this reason calling yii\base\Widget::begin() and yii\base \Widget::end() is expected to happen in the same view file. Not following this rule may result in unexpected output. Configuring global defaults Global defaults for a widget type could be configured via DI container: \Yii::$container->set(’yii\widgets\LinkPager’, [’maxButtonCount’ => 5]); See “Practical Usage” section in Dependency Injection Container guide for details. 3.10.2 Creating Widgets Widget can be created in either of two different ways depending on the requirement. 1: Utilizing widget() method To create a widget, extend from yii\base\Widget and override the yii\base \Widget::init() and/or yii\base\Widget::run() methods. Usually, the init() method should contain the code that initializes the widget properties, while the run() method should contain the code that generates the rendering result of the widget. The rendering result may be directly “echoed” or returned as a string by run(). 23 http://php.net/manual/en/book.outcontrol.php 118 CHAPTER 3. APPLICATION STRUCTURE In the following example, HelloWidget HTML-encodes and displays the content assigned to its message property. If the property is not set, it will display “Hello World” by default. namespace app\components; use yii\base\Widget; use yii\helpers\Html; class HelloWidget extends Widget { public $message; public function init() { parent::init(); if ($this->message === null) { $this->message = ’Hello World’; } } public function run() { return Html::encode($this->message); } } To use this widget, simply insert the following code in a view: ’Good morning’]) ?> Sometimes, a widget may need to render a big chunk of content. While you can embed the content within the run() method, a better approach is to put it in a view and call yii\base\Widget::render() to render it. For example, public function run() { return $this->render(’hello’); } 2: Utilizing begin() and end() methods This is similar to above one with minor difference. Below is a variant of HelloWidget which takes the content enclosed within the begin() and end() calls, HTML-encodes it and then displays it. namespace app\components; use yii\base\Widget; use yii\helpers\Html; 3.10. WIDGETS 119 class HelloWidget extends Widget { public function init() { parent::init(); ob_start(); } public function run() { $content = ob_get_clean(); return Html::encode($content); } } As you can see, PHP’s output buffer is started in init() so that any output between the calls of init() and run() can be captured, processed and returned in run(). Info: When you call yii\base\Widget::begin(), a new instance of the widget will be created and the init() method will be called at the end of the widget constructor. When you call yii\base\Widget::end(), the run() method will be called whose return result will be echoed by end(). The following code shows how to use this new variant of HelloWidget: sample content that may contain one or more HTML
tags
If this content grows too big, use sub views For e.g. render(’viewfile’); // Note: here render() method is of class \yii\base\View as this part of code is within view file and not in Widget class file ?> By default, views for a widget should be stored in files in the WidgetPath /views directory, where WidgetPath stands for the directory containing the widget class file. Therefore, the above example will render the view file @app/components/views/hello.php, assuming the widget class is located under @app/components. You may override the yii\base\Widget::getViewPath() method to customize the directory containing the widget view files. 120 3.10.3 CHAPTER 3. APPLICATION STRUCTURE Best Practices Widgets are an object-oriented way of reusing view code. When creating widgets, you should still follow the MVC pattern. In general, you should keep logic in widget classes and keep presentation in views. Widgets should be designed to be self-contained. That is, when using a widget, you should be able to just drop it in a view without doing anything else. This could be tricky if a widget requires external resources, such as CSS, JavaScript, images, etc. Fortunately, Yii provides the support for asset bundles, which can be utilized to solve the problem. When a widget contains view code only, it is very similar to a view. In fact, in this case, their only difference is that a widget is a redistributable class, while a view is just a plain PHP script that you would prefer to keep within your application. 3.11 Assets An asset in Yii is a file that may be referenced in a Web page. It can be a CSS file, a JavaScript file, an image or video file, etc. Assets are located in Web-accessible directories and are directly served by Web servers. It is often preferable to manage assets programmatically. For example, when you use the yii\jui\DatePicker widget in a page, it will automatically include the required CSS and JavaScript files, instead of asking you to manually find these files and include them. And when you upgrade the widget to a new version, it will automatically use the new version of the asset files. In this tutorial, we will describe the powerful asset management capability provided in Yii. 3.11.1 Asset Bundles Yii manages assets in the unit of asset bundle. An asset bundle is simply a collection of assets located in a directory. When you register an asset bundle in a view, it will include the CSS and JavaScript files in the bundle in the rendered Web page. 3.11.2 Defining Asset Bundles Asset bundles are specified as PHP classes extending from yii\web\AssetBundle. The name of a bundle is simply its corresponding fully qualified PHP class name (without the leading backslash). An asset bundle class should be autoloadable. It usually specifies where the assets are located, what CSS and JavaScript files the bundle contains, and how the bundle depends on other bundles. 3.11. ASSETS 121 The following code defines the main asset bundle used by the basic project template: ’print’], ]; public $js = [ ]; public $depends = [ ’yii\web\YiiAsset’, ’yii\bootstrap\BootstrapAsset’, ]; } The above AppAsset class specifies that the asset files are located under the @webroot directory which corresponds to the URL @web; the bundle contains a single CSS file css/site.css and no JavaScript file; the bundle depends on two other bundles: yii\web\YiiAsset and yii\bootstrap\BootstrapAsset. More detailed explanation about the properties of yii\web\AssetBundle can be found in the following: • sourcePath: specifies the root directory that contains the asset files in this bundle. This property should be set if the root directory is not Web accessible. Otherwise, you should set the basePath property and baseUrl, instead. Path aliases can be used here. • basePath: specifies a Web-accessible directory that contains the asset files in this bundle. When you specify the sourcePath property, the asset manager will publish the assets in this bundle to a Web-accessible directory and overwrite this property accordingly. You should set this property if your asset files are already in a Web-accessible directory and do not need asset publishing. Path aliases can be used here. • baseUrl: specifies the URL corresponding to the directory basePath. Like basePath, if you specify the sourcePath property, the asset manager will publish the assets and overwrite this property accordingly. Path aliases can be used here. • css: an array listing the CSS files contained in this bundle. Note that only forward slash “/” should be used as directory separators. Each file can be specified on its own as a string or in an array together with attribute tags and their values. 122 CHAPTER 3. APPLICATION STRUCTURE • js: an array listing the JavaScript files contained in this bundle. The format of this array is the same as that of css. Each JavaScript file can be specified in one of the following two formats: – a relative path representing a local JavaScript file (e.g. js/main. js). The actual path of the file can be determined by prepending yii\web\AssetManager::$basePath to the relative path, and the actual URL of the file can be determined by prepending yii\web \AssetManager::$baseUrl to the relative path. – an absolute URL representing an external JavaScript file. For example, http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min .js or //ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js. • depends: an array listing the names of the asset bundles that this bundle depends on (to be explained shortly). • jsOptions: specifies the options that will be passed to the yii\web \View::registerJsFile() method when it is called to register every JavaScript file in this bundle. • cssOptions: specifies the options that will be passed to the yii\web \View::registerCssFile() method when it is called to register every CSS file in this bundle. • publishOptions: specifies the options that will be passed to the yii \web\AssetManager::publish() method when it is called to publish source asset files to a Web directory. This is only used if you specify the sourcePath property. Asset Locations Assets, based on their location, can be classified as: • source assets: the asset files are located together with PHP source code which cannot be directly accessed via Web. In order to use source assets in a page, they should be copied to a Web directory and turned into the so-called published assets. This process is called asset publishing which will be described in detail shortly. • published assets: the asset files are located in a Web directory and can thus be directly accessed via Web. • external assets: the asset files are located on a Web server that is different from the one hosting your Web application. When defining an asset bundle class, if you specify the sourcePath property, it means any assets listed using relative paths will be considered as source assets. If you do not specify this property, it means those assets are published assets (you should therefore specify basePath and baseUrl to let Yii know where they are located). It is recommended that you place assets belonging to an application in a Web directory to avoid the unnecessary asset publishing process. This is why AppAsset in the prior example specifies basePath instead of sourcePath. 3.11. ASSETS 123 For extensions, because their assets are located together with their source code in directories that are not Web accessible, you have to specify the sourcePath property when defining asset bundle classes for them. Note: Do not use @webroot/assets as the source path. This directory is used by default by the asset manager to save the asset files published from their source location. Any content in this directory is considered temporarily and may be subject to removal. Asset Dependencies When you include multiple CSS or JavaScript files in a Web page, they have to follow a certain order to avoid overriding issues. For example, if you are using a jQuery UI widget in a Web page, you have to make sure the jQuery JavaScript file is included before the jQuery UI JavaScript file. We call such ordering the dependencies among assets. Asset dependencies are mainly specified through the yii\web\AssetBundle ::$depends property. In the AppAsset example, the asset bundle depends on two other asset bundles: yii\web\YiiAsset and yii\bootstrap\BootstrapAsset, which means the CSS and JavaScript files in AppAsset will be included after those files in the two dependent bundles. Asset dependencies are transitive. This means if bundle A depends on B which depends on C, A will depend on C, too. Asset Options You can specify the cssOptions and jsOptions properties to customize the way that CSS and JavaScript files are included in a page. The values of these properties will be passed to the yii\web\View::registerCssFile() and yii\web\View::registerJsFile() methods, respectively, when they are called by the view to include CSS and JavaScript files. Note: The options you set in a bundle class apply to every CSS/JavaScript file in the bundle. If you want to use different options for different files, you should use the format mentioned above or create separate asset bundles, and use one set of options in each bundle. For example, to conditionally include a CSS file for browsers that are IE9 or below, you can use the following option: public $cssOptions = [’condition’ => ’lte IE9’]; This will cause a CSS file in the bundle to be included using the following HTML tags: 124 CHAPTER 3. APPLICATION STRUCTURE To wrap the generated CSS link tags within

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                     : SinglePage
EXIF Metadata provided by
EXIF.tools

Navigation menu