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.
Note
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 the 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 the handlers' list, use the following code:
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 the 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 a common practice to compress your application output using gzip to save client bandwidth and speed up page loading time. If you have full access to your server, then you can configure it to do so, but in some environments such as shared hosting, you don't.
Fortunately, PHP can gzip the application output using output buffering and the ob_gzhandler function. In order to do so, we should start buffering the output when the application starts and release the gzipped output, when it completes.
Yii's application component has two events that will come in handy in this case: CApplication::onBeginRequest and CApplication::onEndRequest. Let's use them. Insert the following code snippet in the index.php file after configuring an application but before running it:
Note
There are many handy events defined inside Yii's core classes. You can get them all by searching for the 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's 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 another example. Let's assume 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 for 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 what was added:
Now it is time to implement the Notifier class. 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 method of the base class. 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 the base class for all Yii models including form models, the CModel::afterValidate method is defined. This method is called after a successful form validation. Let's use it in our protected/models/UserForm.php model:
We need to call the parent method inside of the afterValidate function because parent implementation calls onAfterValidate that actually raises events:
Note
An event's 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. The first property contains an object that calls the current event, while the second can be used to prevent calling all other, not yet executed handlers, by setting it to false.
The approach described here can be used to customize your Active Record models and implement your own model behaviors.
For further information, refer to the following URLs: