In this recipe, you will learn how to declare and use both predefined and custom events in your application.
To declare an event in your CComponent
child class, you should add a method with a name starting with on. For example, if you add the onRegister
method, you will get a corresponding event declared.
Tip
A method used to declare an event becomes the default event handler.
Typically, events are used like this:
Declare an event by adding a corresponding method
Attach one or multiple event handlers
The component raises an event by using the CComponent::raiseEvent
method
All subscribed handlers are called automatically
Let's look at how we can attach an event handler to an event. To achieve it, we can use the CComponent::attachEventHandler
method. It accepts the following two parameters:
In PHP, we have several ways to define a callback as follows:
Use a global function and just pass its name as a string, such as 'my_function'
.
Use a static class method. You should pass an array: array('ClassName', 'staticMethodName')
.
Use an object method: array($object, 'objectMethod')
.
Create and pass anonymous function using create_function
as follows:
Since PHP 5.3, you can use anonymous functions without create_function
:
Note
When you use CComponent::attachEventHandler
, event handler is added to the end of the handlers list.
To keep your code shorter, you can use component properties to manage event handlers as follows:
To manage event handlers more precisely, you can get handlers list (CList
) using CComponent::getEventHandlers
and work with it. For example, you can attach an event handler the same way as with attachEventHandler
using the following code:
To add an event handler to the beginning of handlers list, use:
To delete a particular handler you can use CComponent::detachEventHandler
as follows:
Alternatively, get a list of handlers as shown earlier and delete handlers from it.
Note
CComponent::hasEvent
checks if event specified is defined in the component.
CComponent::hasEventHandler
checks if there are handlers attached to the event specified.
As we now know how to define and use handlers, let's review some real life examples as follows:
It is common practice to compress your application output using gzip to save client bandwidth and speed up page loading time. If you have an access to fine-tune your server, then you can instruct it to do so, but in some environments such as shared hosting, you can't.
Fortunately, PHP can gzip the application output using output buffering and ob_gzhandler
. In order to do so, we should start buffering the output when the application starts and releases the gzipped output, when it finishes.
Yii's application component has two events that will come in handy in this case: CApplication::onBeginRequest
and CApplication::onEndRequest
. Let's use them. Put the following in index.php
after configuring an application but before running it:
Note
There are many handy events defined inside Yii core classes. You can get them all by searching for "function on" text in the framework
folder using your favorite IDE.
Now, let's look at another example. In Yii, you can translate strings to different languages using Yii::t
. As we all love perfect projects all language translations should be up to date. If they are not, we would like to receive an e-mail about it.
Events come in handy again here. In particular, the CMessageSource::onMissingTranslation
event that is called when the translation for a string passed to Yii::t
is missing.
This time we will use the application configuration file protected/config/main.php
to attach an event handler as follows:
Now, we should implement our handler. Create protected/components/MyEventHandler.php
as follows:
Let's look at the last example. We have a blog application and we need to send an e-mail when there is a new comment (Comment
) to the blog post (Post
).
Comment is a standard AR model generated with Gii. Post is the same Gii-generated model except some customized methods. We will need a custom event NewCommentEvent
to store both Post
and Comment
models and a handler class Notifier
that will do the work.
Let's start with protected/components/NewCommentEvent.php
:
It is pretty simple. We have just added two properties.
Now, let's move on to protected/models/Post.php
. All standard AR methods are omitted to emphasize on what was added:
Now, it is time to implement a notifier. Create protected/components/Notifier.php
as follows:
Now, it is time to get these together in protected/controllers/PostController.php
:
After the comment has been added, admin will receive an e-mail about it.
It is not always necessary to attach an event handler. Let's look at how we can handle an event that is already declared inside an existing component by overriding a base class method. For example, we have a form model UserForm
used to collect some information about our application user and we need to get the complete name from the first and the last name entered by the user.
Fortunately, in CModel
, which is a base class for all Yii models including form models, CModel::afterValidate
method is defined. This method is being called after a successful form validation. Let's use it in our protected/models/UserForm.php
model:
We need to call parent method inside of afterValidate
because parent implementation calls onAfterValidate
that actually raises events:
Note
An event method name should always be defined as function eventHandler($event){…}
, where $event
is a CEvent
instance. The CEvent
class contains just two properties named sender
and handled
. First property contains an object that called the current event while the second can be used to prevent calling all others not yet executed handlers by setting it to false
.
The approach described above can be used to customize your Active Record models and implement your own model behaviors.
For further information, refer to the following URLs: