behaviors.md 4.51 KB
Newer Older
1 2 3
Behaviors
=========

4
A behavior (also knows as *mixin*) can be used to enhance the functionality of an existing component without modifying the component's
Qiang Xue committed
5
code. In particular, a behavior can "inject" its public methods and properties into the component, making them directly accessible
kate-kate committed
6
via the component itself. A behavior can also respond to  events triggered in the component, thus intercepting the normal
7
code execution. Unlike [PHP's traits](http://www.php.net/traits), behaviors can be attached to classes at runtime.
8 9 10 11

Using behaviors
---------------

12 13 14 15 16 17 18
A behavior can be attached to any class that extends from [[yii\base\Component]] either from code or via application
config.

### Attaching behaviors via `behaviors` method

In order to attach a behavior to a class you can implement the `behaviors` method of the component.
As an example, Yii provides the [[yii\behaviors\TimestampBehavior]] behavior for automatically updating timestamp
19
fields when saving an [[yii\db\ActiveRecord|Active Record]] model:
20 21

```php
Qiang Xue committed
22 23
use yii\behaviors\TimestampBehavior;

24 25 26 27 28 29 30 31
class User extends ActiveRecord
{
	// ...

	public function behaviors()
	{
		return [
			'timestamp' => [
Qiang Xue committed
32
				'class' => TimestampBehavior::className(),
33
				'attributes' => [
Alexander Kochetov committed
34 35
					ActiveRecord::EVENT_BEFORE_INSERT => ['created_at', 'updated_at'],
					ActiveRecord::EVENT_BEFORE_UPDATE => 'updated_at',
36 37 38 39 40 41 42
				],
			],
		];
	}
}
```

Qiang Xue committed
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
In the above, the name `timestamp` can be used to reference the behavior through the component. For example, `$user->timestamp`
gives the attached timestamp behavior instance. The corresponding array is the configuration used to create the
[[yii\behaviors\TimestampBehavior|TimestampBehavior]] object.

Besides responding to the insertion and update events of ActiveRecord, `TimestampBehavior` also provides a method `touch()`
that can assign the current timestamp to a specified attribute. As aforementioned, you can access this method directly
through the component, like the following:

```php
$user->touch('login_time');
```

If you do not need to access a behavior object, or the behavior does not need customization, you can also
use the following simplified format when specifying the behavior,

```php
use yii\behaviors\TimestampBehavior;

class User extends ActiveRecord
{
	// ...

	public function behaviors()
	{
		return [
			TimestampBehavior::className(),
			// or the following if you want to access the behavior object
			// 'timestamp' => TimestampBehavior::className(),
		];
	}
}
```
75

76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
### Attaching behaviors dynamically

Another way to attach a behavior to a component is calling `attachBehavior` method like the followig:

```php
$component = new MyComponent();
$component->attachBehavior();
```

### Attaching behaviors from config

One can attach a behavior to a component when configuring it with a configuration array. The syntax is like the
following:

```php
return [
	// ...
	'components' => [
		'myComponent' => [
			// ...
			'as tree' => [
				'class' => 'Tree',
				'root' => 0,
			],
		],
	],
];
```

In the config above `as tree` stands for attaching a behavior named `tree`, and the array will be passed to [[\Yii::createObject()]]
to create the behavior object.

108 109 110 111

Creating your own behaviors
---------------------------

112
To create your own behavior, you must define a class that extends [[yii\base\Behavior]].
113 114

```php
115 116 117 118 119
namespace app\components;

use yii\base\Behavior;

class MyBehavior extends Behavior
120 121 122 123
{
}
```

Qiang Xue committed
124
To make it customizable, like [[yii\behaviors\TimestampBehavior]], add public properties:
125 126

```php
127 128 129 130 131
namespace app\components;

use yii\base\Behavior;

class MyBehavior extends Behavior
132 133 134 135 136 137 138 139
{
	public $attr;
}
```

Now, when the behavior is used, you can set the attribute to which you'd want the behavior to be applied:

```php
140 141 142 143
namespace app\models;

use yii\db\ActiveRecord;

144 145 146 147 148 149 150 151
class User extends ActiveRecord
{
	// ...

	public function behaviors()
	{
		return [
			'mybehavior' => [
152
				'class' => 'app\components\MyBehavior',
153 154 155 156 157 158 159
				'attr' => 'member_type'
			],
		];
	}
}
```

160 161
Behaviors are normally written to take action when certain events occur. Below we're implementing `events` method
to assign event handlers:
162 163

```php
164 165 166 167 168 169
namespace app\components;

use yii\base\Behavior;
use yii\db\ActiveRecord;

class MyBehavior extends Behavior
170 171
{
	public $attr;
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187

	public function events()
	{
		return [
			ActiveRecord::EVENT_BEFORE_INSERT => 'beforeInsert',
			ActiveRecord::EVENT_BEFORE_UPDATE => 'beforeUpdate',
		];
	}

	public function beforeInsert() {
		$model = $this->owner;
		// Use $model->$attr
	}

	public function beforeUpdate() {
		$model = $this->owner;
188 189 190
		// Use $model->$attr
	}
}
Alexander Kochetov committed
191
```