Commit 468e4191 by Qiang Xue

events guide wip [skip ci]

parent f629faf9
......@@ -27,7 +27,7 @@ Getting Started
Basic Concepts
--------------
* [Object Properties](basic-properties.md)
* [Properties](basic-properties.md)
* [Events](basic-events.md)
* [Behaviors](basic-behaviors.md)
* [Object Configurations](basic-configs.md)
......
......@@ -158,3 +158,23 @@ widgets without specifying the class for every widget usage, you can do the foll
The code above should be executed once before `LinkPager` widget is used. It can be done in `index.php`, the application
configuration file, or anywhere else.
### Attaching event handlers via config
You can also attach event handlers within your configuration file. To do so, add an element to the component to which the handler should be attached. The syntax is `"on <event>" => handler`:
```php
return [
// ...
'components' => [
'db' => [
// ...
'on afterOpen' => function ($event) {
// do something right after connected to database
}
],
],
];
```
Events
======
Yii uses events to "inject" custom code into existing code at certain execution points. For example, a comment object can trigger
an "add" event when the user adds a comment to a post.
Events allow you to inject custom code into existing code at certain execution points. You can attach custom
code to an event so that when the event is triggered, the code gets executed automatically. For example,
a mailer object may trigger a `messageSent` event when it successfully sends out a message. If you want to keep
track of the messages that are successfully sent, you may attach the tracking code to the `messageSent` event.
Events are very useful for two reasons. First, they can make your components more flexible. Second, you can hook your own code into the regular workflow of both the framework and the extensions in use.
Yii introduces a base class called [[yii\base\Component]] to support events. If a class needs to trigger
events, it should extend from [[yii\base\Component]] or its child class.
Attaching event handlers
------------------------
One or multiple PHP callbacks, called *event handlers*, can be attached to an event. When the event occurs, the event
handlers will be invoked automatically in the order in which they were attached.
Triggering Events
-----------------
There are two main ways to attaching event handlers. You can do so either via inline code or via the application configuration.
Events are triggered by calling the [[yii\base\Component::trigger()]] method. The method requires an *event name*
and optionally an event object which describes the parameters to be passed to the event handlers. For example,
> Tip: In order to get an up-to-date list of framework and extension events, search the framework code for `->trigger`.
```php
namespace app\components;
### Attaching event handlers via code
use yii\base\Component;
use yii\base\Event;
You can assign event handlers witin your code using the `on` method of a component object. The method's first argument is the name of
the event to watch for; the second is the handler (i.e., function) to be called when that event occurs:
class Foo extends Component
{
const EVENT_HELLO = 'hello';
```php
$component->on($eventName, $handler);
public function bar()
{
$this->trigger(self::EVENT_HELLO);
}
}
```
The handler must be a valid PHP callback. This could be represented as any of the following:
In the above code, when you call `bar()`, it will trigger an event named `hello`.
> Tip: It is recommended to use class constants to represent event names. In the above example, the constant
`EVENT_HELLO` is used to represent `hello`. This has two benefits. First, it prevents typos and can get IDE
auto-completion support. Second, you can tell what events are supported by a class by simply checking the constant
declarations.
- The name of a global function
- An array consisting of a model name and method name
- An array consisting of an object and a method name
- An anonymous function
Sometimes when triggering an event, you may want to pass along some additional information to the event handlers.
For example, a mailer may want pass the message information to the handlers of the `messageSent` event so that the handlers
can know what messages are sent. To do so, you can provide an event object as the second parameter to
the [[yii\base\Component::trigger()]] method. The event object must be an instance of the [[yii\base\Event]] class
or its child class. For example,
```php
// Global function:
$component->on($eventName, 'functionName');
namespace app\components;
// Model and method names:
$component->on($eventName, ['Modelname', 'functionName']);
use yii\base\Component;
use yii\base\Event;
// Object and method name:
$component->on($eventName, [$obj, 'functionName']);
class MessageEvent extends Event
{
public $message;
}
// Anonymous function:
$component->on($eventName, function ($event) {
// Use $event.
});
class Mailer extends Component
{
const EVENT_MESSAGE_SENT = 'messageSent';
public function send($message)
{
// ...sending $message...
$event = new MessageEvent;
$event->message = $message;
$this->trigger(self::EVENT_MESSAGE_SENT, $event);
}
}
```
As shown in the anonymous function example, the event handling function must be defined so that it takes one argument.
This will be an [[yii\base\Event]] object.
When the [[yii\base\Component::trigger()]] method is called, it will call handlers that are attached to
the named event.
In order to pass extra data to the handler, supply the data as a third argument to the `on` method. Within the handler, the extra data will be available in `$event->data`:
```php
$component->on($eventName, function ($event) {
// the extra data can be accessed via $event->data
}, $extraData);
```
Event Handlers
--------------
An event handler is a [PHP callback](http://www.php.net/manual/en/language.types.callable.php) that gets executed
when the event it is attached to is triggered. You can use one of the following callbacks:
### Attaching event handlers via config
- a global PHP function specified in terms of a string, e.g., `'trim()'`;
- an object method specified in terms of an array of an object and a method name, e.g., `[$object, $method]`;
- a static class method specified in terms of an array of a class name and a method name, e.g., `[$class, $method]`;
- an anonymous function, e.g., `function ($event) { ... }`.
You can also attach event handlers within your configuration file. To do so, add an element to the component to which the handler should be attached. The syntax is `"on <event>" => handler`:
The signature of an event handler is:
```php
return [
// ...
'components' => [
'db' => [
// ...
'on afterOpen' => function ($event) {
// do something right after connected to database
}
],
],
];
function ($event) {
// $event is an object of yii\base\Event or its child class
}
```
When attaching event handlers in this way, the handler must be an anonymous function.
Through the `$event` parameter, an event handler may get the following information about an event:
Triggering events
-----------------
- [[yii\base\Event::name|event name]]
- [[yii\base\Event::sender|event sender]]: the object whose `trigger()` method is called.
- [[yii\base\Event::data|custom data]]: the data that is provided when attaching the event handler (to be explained shortly).
Most events will be triggered through the normal workflow. For example, the "beforeSave" event occurs before an Active Record model is saved.
But you can also manually trigger an event using the `trigger` method, invoked on the component with the attached event handler:
Attaching Event Handlers
------------------------
You can attach a handler to an event by calling the [[yii\base\Component::on()]] method. For example,
```php
$this->trigger('myEvent');
$foo = new Foo;
// the handler is a global function
$foo->on(Foo::EVENT_HELLO, 'function_name');
// or
// the handler is an object method
$foo->on(Foo::EVENT_HELLO, [$object, 'methodName']);
$event = new CreateUserEvent(); // extended from yii\base\Event
$event->userName = 'Alexander';
$this->trigger('createUserEvent', $event);
// the handler is a static class method
$foo->on(Foo::EVENT_HELLO, ['app\components\Bar', 'methodName']);
// the handler is an anonymous function
$foo->on(Foo::EVENT_HELLO, function ($event) {
// event handling logic
});
```
The event name needs to be unique within the class it is defined. Event names are *case-sensitive*, but it is a good practice
to define event names using class constants:
When attaching an event handler, you may provide additional data as the third parameter to [[yii\base\Component::on()]].
The data will be made available to the handler when the event is triggered and the handler is called. For example,
```php
class Mailer extends Component
{
const EVENT_SEND_EMAIL = 'sendEmail';
public function send()
{
// ...
$this->trigger(self::EVENT_SEND_EMAIL);
}
}
// The following code will display "abc" when the event is triggered
// because $event->data contains the data passed to "on"
$foo->on(Foo::EVENT_HELLO, function ($event) {
echo $event->data;
}, 'abc');
```
Removing Event Handlers
-----------------------
You may attach one or multiple handlers to a single event. When an event is triggered, the attached handlers
will be called in the order they are attached to the event. If a handler needs to stop the invocation of the
handlers behind it, it may set the [[yii\base\Event::handled]] property of the `$event` parameter to be true,
like the following,
The corresponding `off` method removes an event handler:
```php
$foo->on(Foo::EVENT_HELLO, function ($event) {
$event->handled = true;
});
```
By default, a newly attached handler is appended to the existing handler queue for the event.
As a result, the handler will be called in the last place when the event is triggered.
To insert the new handler at the start of the handler queue so that the handler gets called first, y
ou may call [[yii\base\Component::on()]] by passing the fourth parameter `$append` as false:
```php
$component->off($eventName);
$foo->on(Foo::EVENT_HELLO, function ($event) {
// ...
}, $data, false);
```
Yii supports the ability to associate multiple handlers with the same event. When using `off` as in the above,
every handler will be removed. To remove only a specific handler, provide that as the second argument to `off`:
Detaching Event Handlers
------------------------
To detach a handler from an event, call the [[yii\base\Component::off()]] method. For example,
```php
$component->off($eventName, $handler);
// the handler is a global function
$foo->off(Foo::EVENT_HELLO, 'function_name');
// the handler is an object method
$foo->off(Foo::EVENT_HELLO, [$object, 'methodName']);
// the handler is a static class method
$foo->off(Foo::EVENT_HELLO, ['app\components\Bar', 'methodName']);
// the handler is an anonymous function
$foo->off(Foo::EVENT_HELLO, $anonymousFunction);
```
The `$handler` should be presented in the `off` method in the same way as was presented in the `on` call in order to remove it.
Note that in general you should not try to detach an anonymous function unless you store it
somewhere when it is attached to the event. In the above example, we assume the anonymous
function is stored as a variable `$anonymousFunction`.
To detach ALL handlers from an event, simply call [[yii\base\Component::off()]] without the second parameter:
```php
$foo->off(Foo::EVENT_HELLO);
```
> Tip: You probably don't want to use anonymous functions for event handlers that you expect to later remove.
Global Events
-------------
You can use "global" events instead of per-component ones. A global event can take place on any component type.
You can use "global" events instead of per-component ones. A global event can take place on any component type.
In order to attach a handler to a global event, call the `on` method on the application instance:
......
Object Properties
=================
Properties
==========
In PHP, class member variables are also called *properties*. They are part of a class definition and are used
to represent the state of a class instance. In practice, you may often want to do some special handling when
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment