Because an extension is meant to be used by third-party developers, it takes some additional efforts to create it. The followings are some general guidelines:
In the following, we describe how to create a new extension, according to its categorization as described in overview. These descriptions also apply when you are creating a component mainly used in your own projects.
An application component should implement the interface IApplicationComponent or extend from CApplicationComponent. The main method needed to be implemented is IApplicationComponent::init in which the component performs some initialization work. This method is invoked after the component is created and the initial property values (specified in application configuration) are applied.
By default, an application component is created and initialized only when it is accessed for the first time during request handling. If an application component needs to be created right after the application instance is created, it should require the user to list its ID in the CApplication::preload property.
To create a behavior, one must implement the IBehavior interface. For convenience, Yii provides a base class CBehavior that already implements this interface and provides some additional convenient methods. Child classes mainly need to implement the extra methods that they intend to make available to the components being attached to.
When developing behaviors for CModel and CActiveRecord, one can also extend CModelBehavior and CActiveRecordBehavior, respectively. These base classes offer additional features that are specifically made for CModel and CActiveRecord. For example, the CActiveRecordBehavior class implements a set of methods to respond to the life cycle events raised in an ActiveRecord object. A child class can thus override these methods to put in customized code which will participate in the AR life cycles.
The following code shows an example of an ActiveRecord behavior. When this behavior is
attached to an AR object and when the AR object is being saved by calling
save(), it will
automatically sets the
update_time attributes with the current timestamp.
class TimestampBehavior extends CActiveRecordBehavior
public function beforeSave($event)
The easiest way of creating a new widget is extending an existing widget and overriding its methods or changing its default property values. For example, if you want to use a nicer CSS style for CTabView, you could configure its CTabView::cssFile property when using the widget. You can also extend CTabView as follows so that you no longer need to configure the property when using the widget.
class MyTabView extends CTabView
public function init()
In the above, we override the CWidget::init method and assign to
CTabView::cssFile the URL to our new default CSS style if the property
is not set. We put the new CSS style file under the same directory
MyTabView class file so that they can be packaged as
an extension. Because the CSS style file is not Web accessible, we need
to publish as an asset.
To create a new widget from scratch, we mainly need to implement two methods:
CWidget::init and CWidget::run. The first method is called when we
$this->beginWidget to insert a widget in a view, and the
second method is called when we call
If we want to capture and process the content displayed between these two
method invocations, we can start output buffering
in CWidget::init and retrieve the buffered output in CWidget::run
for further processing.
class MyWidget extends CWidget
protected function registerClientScript()
A widget may also have its own view files. If so, create a directory named
views under the directory containing the widget class file, and put all the
view files there. In the widget class, in order to render a widget view, use
$this->render('ViewName'), which is similar to what we do in a controller.
A filter should extend from CFilter or its child classes. The main methods that need to be implemented for a filter are CFilter::preFilter and CFilter::postFilter. The former is invoked before the action is executed while the latter after.
class MyFilter extends CFilter
protected function preFilter($filterChain)
// logic being applied before the action is executed
return true; // false if the action should not be executed
protected function postFilter($filterChain)
// logic being applied after the action is executed
$filterChain is of type CFilterChain which contains information
about the action that is currently filtered.
A controller distributed as an extension
should extend from CExtController, instead of CController. The main reason
is because CController assumes the controller view files are located under
application.views.ControllerID, while CExtController assumes the view
files are located under the
views directory which is a subdirectory of
the directory containing the controller class file. Therefore, it is easier
to redistribute the controller since its view files are staying together
with the controller class file.
class MyValidator extends CValidator
protected function validateAttribute($model,$attribute)
if($value has error)
A console command should extend from CConsoleCommand and implement its CConsoleCommand::run method. Optionally, we can override CConsoleCommand::getHelp to provide some nice help information about the command.
class MyCommand extends CConsoleCommand
public function run($args)
// $args gives an array of the command-line arguments for this command
public function getHelp()
return 'Usage: how to use this command';
Please refer to the section about modules on how to create a module.
Developing a generic component extension is like writing a class. Again, the component should also be self-contained so that it can be easily used by other developers.