upgrade-from-v1.md 16.8 KB
Newer Older
Qiang Xue committed
1 2 3 4 5 6 7 8
Upgrading from Yii 1.1
======================

In this chapter, we list the major changes introduced in Yii 2.0 since version 1.1.
We hope this list will make it easier for you to upgrade from Yii 1.1 and quickly
master Yii 2.0 based on your existing Yii knowledge.


Qiang Xue committed
9 10 11 12 13 14 15
Namespace
---------

The most obvious change in Yii 2.0 is the use of namespaces. Almost every core class
is namespaced, e.g., `yii\web\Request`. The "C" prefix is no longer used in class names.
The naming of the namespaces follows the directory structure. For example, `yii\web\Request`
indicates the corresponding class file is `web/Request.php` under the Yii framework folder.
ploaiza committed
16
You can use any core class without explicitly including that class file, thanks to the Yii
Qiang Xue committed
17 18 19
class loader.


Qiang Xue committed
20 21 22 23 24 25 26 27 28
Component and Object
--------------------

Yii 2.0 breaks the `CComponent` class in 1.1 into two classes: `Object` and `Component`.
The `Object` class is a lightweight base class that allows defining class properties
via getters and setters. The `Component` class extends from `Object` and supports
the event feature and the behavior feature.

If your class does not need the event or behavior feature, you should consider using
br0sk committed
29
`Object` as the base class. This is usually the case for classes that represent basic
Qiang Xue committed
30 31 32 33 34 35
data structures.


Object Configuration
--------------------

36 37 38
The `Object` class introduces a uniform way of configuring objects. Any descendant class
of `Object` should declare its constructor (if needed) in the following way so that
it can be properly configured:
Qiang Xue committed
39

40
```php
Qiang Xue committed
41 42
class MyClass extends \yii\Object
{
Alexander Makarov committed
43
    public function __construct($param1, $param2, $config = [])
Qiang Xue committed
44
    {
45 46
        // ... initialization before configuration is applied

Qiang Xue committed
47 48 49 50 51 52
        parent::__construct($config);
    }

    public function init()
    {
        parent::init();
53 54

        // ... initialization after configuration is applied
Qiang Xue committed
55 56
    }
}
57
```
Alexander Makarov committed
58

59 60 61 62
In the above, the last parameter of the constructor must take a configuration array
which contains name-value pairs for initializing the properties at the end of the constructor.
You can override the `init()` method to do initialization work that should be done after
the configuration is applied.
Qiang Xue committed
63

64 65
By following this convention, you will be able to create and configure a new object
using a configuration array like the following:
Qiang Xue committed
66

67
```php
Alexander Makarov committed
68
$object = Yii::createObject([
Qiang Xue committed
69 70 71
    'class' => 'MyClass',
    'property1' => 'abc',
    'property2' => 'cde',
Alexander Makarov committed
72
], $param1, $param2);
73
```
Alexander Makarov committed
74

Qiang Xue committed
75 76 77 78 79 80 81 82 83


Events
------

There is no longer the need to define an `on`-method in order to define an event in Yii 2.0.
Instead, you can use whatever event names. To attach a handler to an event, you should
use the `on` method now:

84
```php
Qiang Xue committed
85 86 87
$component->on($eventName, $handler);
// To detach the handler, use:
// $component->off($eventName, $handler);
88
```
Alexander Makarov committed
89

Qiang Xue committed
90 91 92 93

When you attach a handler, you can now associate it with some parameters which can be later
accessed via the event parameter by the handler:

94
```php
Qiang Xue committed
95
$component->on($eventName, $handler, $params);
96
```
Alexander Makarov committed
97

Qiang Xue committed
98 99 100 101

Because of this change, you can now use "global" events. Simply trigger and attach handlers to
an event of the application instance:

102
```php
Qiang Xue committed
103 104 105 106
Yii::$app->on($eventName, $handler);
....
// this will trigger the event and cause $handler to be invoked.
Yii::$app->trigger($eventName);
107
```
Qiang Xue committed
108

109 110 111
If you need to handle all instances of a class instead of the object you can attach a handler like the following:

```php
Alexander Makarov committed
112
Event::on([ActiveRecord::className(), ActiveRecord::EVENT_AFTER_INSERT], function ($event) {
113 114 115 116 117
	Yii::trace(get_class($event->sender) . ' is inserted.');
});
```

The code above defines a handler that will be triggered for every Active Record object's `EVENT_AFTER_INSERT` event.
Qiang Xue committed
118

119 120 121 122 123 124 125 126 127 128
Path Alias
----------

Yii 2.0 expands the usage of path aliases to both file/directory paths and URLs. An alias
must start with a `@` character so that it can be differentiated from file/directory paths and 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, `FileCache::cachePath` can take
both a path alias and a normal directory path.

Path alias is also closely related with class namespaces. It is recommended that a path
ploaiza committed
129
alias be defined for each root namespace so that you can use Yii the class autoloader without
130 131
any further configuration. For example, because `@yii` refers to the Yii installation directory,
a class like `yii\web\Request` can be autoloaded by Yii. If you use a third party library
ploaiza committed
132 133
such as Zend Framework, you may define a path alias `@Zend` which refers to its installation 
directory and Yii will be able to autoload any class in this library.
134 135


Qiang Xue committed
136 137 138
View
----

ploaiza committed
139
Yii 2.0 introduces a `View` class to represent the view part of the MVC pattern.
Qiang Xue committed
140 141 142 143 144 145 146 147 148 149
It can be configured globally through the "view" application component. It is also
accessible in any view file via `$this`. This is one of the biggest changes compared to 1.1:
**`$this` in a view file no longer refers to the controller or widget object.**
It refers to the view object that is used to render the view file. To access the controller
or the widget object, you have to use `$this->context` now.

Because you can access the view object through the "view" application component,
you can now render a view file like the following anywhere in your code, not necessarily
in controllers or widgets:

150
```php
Qiang Xue committed
151 152 153 154
$content = Yii::$app->view->renderFile($viewFile, $params);
// You can also explicitly create a new View instance to do the rendering
// $view = new View;
// $view->renderFile($viewFile, $params);
155
```
Alexander Makarov committed
156

Qiang Xue committed
157 158 159 160

Also, there is no more `CClientScript` in Yii 2.0. The `View` class has taken over its role
with significant improvements. For more details, please see the "assets" subsection.

161 162
While Yii 2.0 continues to use PHP as its main template language, it comes with two official extensions
adding support for two popular template engines: Smarty and Twig. The Prado template engine is
Qiang Xue committed
163
no longer supported. To use these template engines, you just need to use `tpl` as the file
164
extension for your Smarty views, or `twig` for Twig views. You may also configure the
165 166
`View::renderers` property to use other template engines. See [Using template engines](template.md) section
of the guide for more details.
167

Qiang Xue committed
168 169 170 171

Models
------

ploaiza committed
172
A model is now associated with a form name returned by its `formName()` method. This is
173 174 175
mainly used when using HTML forms to collect user inputs for a model. Previously in 1.1,
this is usually hardcoded as the class name of the model.

176 177 178 179 180 181 182 183 184 185 186 187 188
A new methods called `load()` and `Model::loadMultiple()` is introduced to simplify the data population from user inputs
to a model. For example,

```php
$model = new Post;
if ($model->load($_POST)) {...}
// which is equivalent to:
if (isset($_POST['Post'])) {
    $model->attributes = $_POST['Post'];
}

$model->save();

Alexander Makarov committed
189
$postTags = [];
190
$tagsCount = count($_POST['PostTag']);
191
while ($tagsCount-- > 0) {
Alexander Makarov committed
192
    $postTags[] = new PostTag(['post_id' => $model->id]);
193 194 195
}
Model::loadMultiple($postTags, $_POST);
```
196 197 198 199 200 201

Yii 2.0 introduces a new method called `scenarios()` to declare which attributes require
validation under which scenario. Child classes should overwrite `scenarios()` to return
a list of scenarios and the corresponding attributes that need to be validated when
`validate()` is called. For example,

202
```php
203 204
public function scenarios()
{
Alexander Makarov committed
205 206 207 208
    return [
        'backend' => ['email', 'role'],
        'frontend' => ['email', '!name'],
    ];
209
}
210
```
Alexander Makarov committed
211

212 213 214 215 216 217 218 219 220 221

This method also determines which attributes are safe and which are not. In particular,
given a scenario, if an attribute appears in the corresponding attribute list in `scenarios()`
and the name is not prefixed with `!`, it is considered *safe*.

Because of the above change, Yii 2.0 no longer has "safe" and "unsafe" validators.

If your model only has one scenario (very common), you do not have to overwrite `scenarios()`,
and everything will still work like the 1.1 way.

222 223
To learn more about Yii 2.0 models refer to [Models](model.md) section of the guide.

224

Qiang Xue committed
225 226 227
Controllers
-----------

228 229 230
The `render()` and `renderPartial()` methods now return the rendering results instead of directly
sending them out. You have to `echo` them explicitly, e.g., `echo $this->render(...);`.

231
To learn more about Yii 2.0 controllers refer to [Controller](controller.md) section of the guide.
232

233 234 235 236 237 238 239 240
Widgets
-------

Using a widget is more straightforward in 2.0. You mainly use the `begin()`, `end()` and `widget()`
methods of the `Widget` class. For example,

```php
// Note that you have to "echo" the result to display it
Alexander Makarov committed
241
echo \yii\widgets\Menu::widget(['items' => $items]);
242

243
// Passing an array to initialize the object properties
Alexander Makarov committed
244 245 246 247
$form = \yii\widgets\ActiveForm::begin([
	'options' => ['class' => 'form-horizontal'],
	'fieldConfig' => ['inputOptions' => ['class' => 'input-xlarge']],
]);
248 249 250 251 252 253 254
... form inputs here ...
\yii\widgets\ActiveForm::end();
```

Previously in 1.1, you would have to enter the widget class names as strings via the `beginWidget()`,
`endWidget()` and `widget()` methods of `CBaseController`. The approach above gets better IDE support.

255

Qiang Xue committed
256 257 258
Themes
------

ploaiza committed
259
Themes work completely different in 2.0. They are now based on a path map to "translate" a source
260
view into a themed view. For example, if the path map for a theme is
Alexander Makarov committed
261
`['/web/views' => '/web/themes/basic']`, then the themed version for a view file
262
`/web/views/site/index.php` will be `/web/themes/basic/site/index.php`.
263 264 265 266 267 268 269 270

For this reason, theme can now be applied to any view file, even if a view rendered outside
of the context of a controller or a widget.

There is no more `CThemeManager`. Instead, `theme` is a configurable property of the "view"
application component.


Qiang Xue committed
271 272 273
Console Applications
--------------------

ploaiza committed
274
Console applications are now composed by controllers, like Web applications. In fact,
275 276 277
console controllers and Web controllers share the same base controller class.

Each console controller is like `CConsoleCommand` in 1.1. It consists of one or several
278
actions. You use the `yii <route>` command to execute a console command, where `<route>`
279 280 281 282 283 284 285
stands for a controller route (e.g. `sitemap/index`). Additional anonymous arguments
are passed as the parameters to the corresponding controller action method, and named arguments
are treated as global options declared in `globalOptions()`.

Yii 2.0 supports automatic generation of command help information from comment blocks.


Qiang Xue committed
286 287 288
I18N
----

289
Yii 2.0 removes date formatter and number formatter in favor of the PECL intl PHP module.
Qiang Xue committed
290

291 292 293 294 295 296 297 298 299 300 301 302 303
Message translation is still supported, but managed via the "i18n" application component.
The component manages a set of message sources, which allows you to use different message
sources based on message categories. For more information, see the class documentation for `I18N`.


Action Filters
--------------

Action filters are implemented via behaviors now. You should extend from `ActionFilter` to
define a new filter. To use a filter, you should attach the filter class to the controller
as a behavior. For example, to use the `AccessControl` filter, you should have the following
code in a controller:

304
```php
305 306
public function behaviors()
{
Alexander Makarov committed
307 308
    return [
        'access' => [
309
            'class' => 'yii\web\AccessControl',
Alexander Makarov committed
310 311
            'rules' => [
                ['allow' => true, 'actions' => ['admin'], 'roles' => ['@']],
312 313 314 315
            ),
        ),
    );
}
316
```
Alexander Makarov committed
317

Qiang Xue committed
318 319 320 321 322


Assets
------

ploaiza committed
323
Yii 2.0 introduces a new concept called *asset bundle*. It is similar to script
324 325 326
packages (managed by `CClientScript`) in 1.1, but with better support.

An asset bundle is a collection of asset files (e.g. JavaScript files, CSS files, image files, etc.)
327 328 329 330
under a directory. Each asset bundle is represented as a class extending `AssetBundle`.
By registering an asset bundle via `AssetBundle::register()`, you will be able to make
the assets in that bundle accessible via Web, and the current page will automatically
contain the references to the JavaScript and CSS files specified in that bundle.
331 332 333



Qiang Xue committed
334 335 336
Static Helpers
--------------

337 338
Yii 2.0 introduces many commonly used static helper classes, such as `Html`, `ArrayHelper`,
`StringHelper`. These classes are designed to be easily extended. Note that static classes
ploaiza committed
339
are usually hard to extend because of the fixed class name references. But Yii 2.0
340 341 342
introduces the class map (via `Yii::$classMap`) to overcome this difficulty.


Qiang Xue committed
343 344 345
`ActiveForm`
------------

346
Yii 2.0 introduces the *field* concept for building a form using `ActiveForm`. A field
Qiang Xue committed
347 348
is a container consisting of a label, an input, an error message, and/or a hint text.
It is represented as an `ActiveField` object. Using fields, you can build a form more cleanly than before:
349

350
```php
351
<?php $form = yii\widgets\ActiveForm::begin(); ?>
Alexander Makarov committed
352 353
	<?= $form->field($model, 'username') ?>
	<?= $form->field($model, 'password')->passwordInput() ?>
Qiang Xue committed
354
	<div class="form-group">
Alexander Makarov committed
355
		<?= Html::submitButton('Login') ?>
356
	</div>
357
<?php yii\widgets\ActiveForm::end(); ?>
358
```
Alexander Makarov committed
359

360

Qiang Xue committed
361 362 363 364

Query Builder
-------------

365 366
In 1.1, query building is scattered among several classes, including `CDbCommand`,
`CDbCriteria`, and `CDbCommandBuilder`. Yii 2.0 uses `Query` to represent a DB query
ploaiza committed
367
and `QueryBuilder` to generate SQL statements from query objects. For example:
368

369
```php
370 371 372 373 374 375 376 377
$query = new \yii\db\Query;
$query->select('id, name')
      ->from('tbl_user')
      ->limit(10);

$command = $query->createCommand();
$sql = $command->sql;
$rows = $command->queryAll();
378
```
Alexander Makarov committed
379

380 381 382 383

Best of all, such query building methods can be used together with `ActiveRecord`,
as explained in the next sub-section.

Qiang Xue committed
384 385 386 387

ActiveRecord
------------

388
ActiveRecord has undergone significant changes in Yii 2.0. The most important one
ploaiza committed
389
is the relational ActiveRecord query. In 1.1, you have to declare the relations
390 391 392
in the `relations()` method. In 2.0, this is done via getter methods that return
an `ActiveQuery` object. For example, the following method declares an "orders" relation:

393
```php
394 395 396 397
class Customer extends \yii\db\ActiveRecord
{
	public function getOrders()
	{
Alexander Makarov committed
398
		return $this->hasMany('Order', ['customer_id' => 'id']);
399 400
	}
}
401
```
Alexander Makarov committed
402

403 404 405 406 407 408 409 410 411 412 413 414 415

You can use `$customer->orders` to access the customer's orders. You can also
use `$customer->getOrders()->andWhere('status=1')->all()` to perform on-the-fly
relational query with customized query conditions.

When loading relational records in an eager way, Yii 2.0 does it differently from 1.1.
In particular, in 1.1 a JOIN query would be used to bring both the primary and the relational
records; while in 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.


Yii 2.0 no longer uses the `model()` method when performing queries. Instead, you
ploaiza committed
416
use the `find()` method:
417

418
```php
419 420
// to retrieve all *active* customers and order them by their ID:
$customers = Customer::find()
Alexander Makarov committed
421
	->where(['status' => $active])
422 423 424 425
	->orderBy('id')
	->all();
// return the customer whose PK is 1
$customer = Customer::find(1);
426
```
Alexander Makarov committed
427

428 429 430 431 432 433

The `find()` method returns an instance of `ActiveQuery` which is a subclass of `Query`.
Therefore, you can use all query methods of `Query`.

Instead of returning ActiveRecord objects, you may call `ActiveQuery::asArray()` to
return results in terms of arrays. This is more efficient and is especially useful
ploaiza committed
434
when you need to return a large number of records:
435

436
```php
437
$customers = Customer::find()->asArray()->all();
438
```
439

440
By default, ActiveRecord now only saves dirty attributes. In 1.1, all attributes
ploaiza committed
441
are saved to database when you call `save()`, regardless of having changed or not,
442 443 444
unless you explicitly list the attributes to save.


445 446 447 448 449 450
Auto-quoting Table and Column Names
------------------------------------

Yii 2.0 supports automatic quoting of database table and column names. A name enclosed
within double curly brackets is treated as a table name, and a name enclosed within
double square brackets is treated as a column name. They will be quoted according to
ploaiza committed
451
the database driver being used:
452

453
```php
454 455
$command = $connection->createCommand('SELECT [[id]] FROM {{posts}}');
echo $command->sql;  // MySQL: SELECT `id` FROM `posts`
456
```
Alexander Makarov committed
457

458 459 460 461
This feature is especially useful if you are developing an application that supports
different DBMS.


462 463
User and IdentityInterface
--------------------------
Qiang Xue committed
464

465
The `CWebUser` class in 1.1 is now replaced by `\yii\Web\User`, and there is no more
466
`CUserIdentity` class. Instead, you should implement the `IdentityInterface` which
467 468 469
is much more straightforward to implement. The bootstrap application provides such an example.


Qiang Xue committed
470 471 472
URL Management
--------------

473 474 475 476 477
URL management is similar to 1.1. A major enhancement is that it now supports optional
parameters. For example, if you have rule declared as follows, then it will match
both `post/popular` and `post/1/popular`. In 1.1, you would have to use two rules to achieve
the same goal.

478
```php
Alexander Makarov committed
479
[
480 481
	'pattern' => 'post/<page:\d+>/<tag>',
	'route' => 'post/index',
Alexander Makarov committed
482 483
	'defaults' => ['page' => 1],
]
484
```
Alexander Makarov committed
485

486 487


Qiang Xue committed
488
Response
489 490 491 492 493 494 495 496 497 498
--------

Extensions
----------

Integration with Composer
-------------------------

TBD