1.1 扩展Yii

扩展Yii在开发过程中是很常见的。例如,当你编写一个新的控制器,你从Yii继承CController类;当你写一个新的小工具widget,你继承于CWidget或者是另外的一个widget。我们这些扩展代码可以被第三方使用,我们称之为yii的扩展。

一个扩展一般只提供单一功能。在Yii里,可以分为以下几类:

●应用组件 application component
●行为          behavior
●小工具      widget
●控制器      controller
●动作          action
●过滤器      filter
●控制命令 console command
●验证器      validator
●帮助类      helper
●模块          module

扩展也可以是一个组件,不属于以上的分类。实际上,yii非常小心的设计每段代码,让每个人可以自己扩展或者是自定义组件。

1.2 使用扩展

使用一个扩展包括以下几个步骤:

1、从官网地址http://www.yiiframework.com/extensions/ 下载要使用的扩展。

2、在项目的子目录extensions/xyz下,解压该扩展。(xyz代表扩展的名称)

3、导入,配置扩展,然后就可以调用了。

每个扩展都有一个唯一的名称。假设我们要用的扩展名称为xyz,那么我们一直都可以用路径别名ext.xyz来访问扩展的目录。该目录下包含了该扩展的所有文件。

不同的扩展有不同的导入要求,配置,以及使用方法。下面,我们按照之前的分类,总结一些常见的扩展使用场景。

1.2.1 Zii扩展

在我们开始介绍使用第三方扩展之前,我们想先介绍以下Zii这个扩展。这个扩展是Yii开发小组开发的,在每个yii的发型版本中都自带有的。

当要使用Zii扩展时,你必须在当前类中调用路径别名zii.path.to.ClassName。这里的跟目录别名zii是在Yii里已经预先定义好的,他指向Zii库的根目录。例如,要使用CGridView,我们就在视图脚本语句中调用以下语句:

 
  
  1. $this->widget('zii.widgets.grid.CGridView'array(  
  2. 'dataProvider'=>$dataProvider,  
  3. )); 

1.2.2 应用组件

要使用一个应用组件,我们要在项目的配置文件中的components字段中,加入一个新的选项,如下:

 
  
  1. return array(  
  2.     // 'preload'=>array('xyz',...),  
  3.     'components'=>array(  
  4.         'xyz'=>array(  
  5.             'class'=>'ext.xyz.XyzClass',  
  6.             'property1'=>'value1',  
  7.             'property2'=>'value2',  
  8.         ),  
  9.     // other component configurations  
  10.     ),  
  11. ); 

然后,我们就可以在任何地方调用Yii::app()->xyz。组件会滞后创建(也就是,在第一次访问的时候再生成),除非,我们在预装载的属性列表中指定该组件的装载属性。

1.2.3 行为

行为可以被用于任何类型的组件。他的使用包括2个步骤。第一步,一个行为要绑定到一个指定的组件。第二步,通过这个目标组件来调用这个行为。例如:

 
  
  1. // $name uniquely identifies the behavior in the component  
  2. $component->attachBehavior($name,$behavior);  
  3. // test() is a method of $behavior  
  4. $component->test(); 

更多情况下,我们是通过配置的方式来绑定一个行为到目标组件上,而不是调用attachBehavior的方法。例如,要绑定一个行为到应用组件中,我们可以配置项目工程如下:

 
  
  1. return array(  
  2.     'components'=>array(  
  3.         'db'=>array(  
  4.             'class'=>'CDbConnection',  
  5.             'behaviors'=>array(  
  6.                 'xyz'=>array(  
  7.                     'class'=>'ext.xyz.XyzBehavior',  
  8.                     'property1'=>'value1',  
  9.                     'property2'=>'value2',  
  10.                 ),  
  11.             ),  
  12.         ),  
  13.     //....  
  14.     ),  
  15. ); 

上面的代码中,把xyz的行为绑定到了一个数据库组件中。我们之所以可以这么做,是因为CApplicationComponent定义了一个叫做behaviors的属性。通过设置这个属性为一个行为配置列表,当这个组件初始化的时候,会绑定这些行为。

对于CController, CFormModel 和 CActiveRecord这些经常被用于扩展的类,可以通过重载他们的behaviors的方法来绑定。这些类会在初始化的时候,自动加载这个方法里的所有行为:

 
  
  1. public function behaviors()  
  2. {  
  3.     return array(  
  4.         'xyz'=>array(  
  5.             'class'=>'ext.xyz.XyzBehavior',  
  6.             'property1'=>'value1',  
  7.             'property2'=>'value2',  
  8.         ),  
  9.     );  

1.2.4 小工具Widget

widget一般用于视图。假设一个widget类XyzClass属于xyz扩展,我们可以在视图中这样使用:

 
  
  1. // widget that does not need body content  
  2. <?php $this->widget('ext.xyz.XyzClass'array(  
  3.     'property1'=>'value1',  
  4.     'property2'=>'value2')); ?>  
  5. // widget that can contain body content  
  6. <?php $this->beginWidget('ext.xyz.XyzClass'array(  
  7.     'property1'=>'value1',  
  8.    'property2'=>'value2')); ?>  
  9.     ...body content of the widget...  
  10. <?php $this->endWidget(); ?> 

1.2.5 动作

动作是一个控制器用来相应特定的用户请求的。假设一个动作类XyzClass属于xyz这个扩展,我们可以在控制器中重载CController::actions的方法来使用:

 
  
  1. class TestController extends CController  
  2. {  
  3.     public function actions()  
  4.     {  
  5.         return array(  
  6.             'xyz'=>array(  
  7.                 'class'=>'ext.xyz.XyzClass',  
  8.                 'property1'=>'value1',  
  9.                 'property2'=>'value2',  
  10.             ),  
  11.         // other actions  
  12.         );  
  13.     }  

这样,这个动作就可以就可以通过路由test/xyz来访问了。

1.2.6 过滤器

过滤器跟动作一样,也是用于控制器的。他们一般是在一个动作捕获到用户时,预先处理,或者是最后处理。假设一个过滤器类XyzClass属于xyz扩展,我们可以通过重载CController::filters的方法来使用:

 
  
  1. class TestController extends CController  
  2. {  
  3.     public function filters()  
  4.     {  
  5.         return array(  
  6.             array(  
  7.                 'ext.xyz.XyzClass',  
  8.                 'property1'=>'value1',  
  9.                 'property2'=>'value2',  
  10.             ),          
  11.             // other filters  
  12.         );  
  13.     }  

在上例中,我们可以在第一个元素组中,用+号或者是减号来限制过滤器只作用于哪些指定的动作。更多详情请参见控制器说明。

1.2.7 控制器

一个控制器提供了一些能被用户请求的动作。要用控制器扩展,我们要在项目的配置文件中配置CWebApplication::controllerMap:

 
  
  1. return array(  
  2.     'controllerMap'=>array(  
  3.         'xyz'=>array(  
  4.             'class'=>'ext.xyz.XyzClass',  
  5.             'property1'=>'value1',  
  6.             'property2'=>'value2',  
  7.         ),  
  8.         // other controllers  
  9.     ),  
  10. ); 

这样,控制器中的方法a,我们就可以通过路由xyz/a来访问了。

1.2.8 校验器

一个校验器主要用于模型类(不管是继承于CFormModel 或CActiveRecord的都可以)。假设一个校验器类XyzClass属于扩展xyz的,我们可以在模型类中重载CModel::rules():

 
  
  1. class MyModel extends CActiveRecord // or CFormModel  
  2. {  
  3.     public function rules()  
  4.     {  
  5.         return array(  
  6.             array(  
  7.                 'attr1, attr2',  
  8.                 'ext.xyz.XyzClass',  
  9.                 'property1'=>'value1',  
  10.                 'property2'=>'value2',  
  11.             ),  
  12.             // other validation rules  
  13.         );  
  14.     }  

1.2.9 控制台命令

一个控制台命令扩展一般用于加强yiic功能。假设一个控制台命令类属于xyz扩展,我们可以为该控制台配置如下:

 
  
  1. return array(  
  2.     'commandMap'=>array(  
  3.         'xyz'=>array(  
  4.             'class'=>'ext.xyz.XyzClass',  
  5.             'property1'=>'value1',  
  6.             'property2'=>'value2',  
  7.         ),  
  8.         // other commands  
  9.     ),  
  10. ); 

然后,我们就能使用配备了额外命令 xyzyiic 工具了。

注意:一个控制台程序的配置文件使用方法,一般跟web工程的是不同的。如果工程是通过yiic webapp命令创建的,那么控制台配置文件就是protected/config/console.php,web工程的配置文件是protected/config/main.php。

1.2.10 模块

参考模块的使用说明

1.2.11 通用组件

要使用一个通用组件, 我们首先要导入他的类:

 
  
  1. Yii::import('application.extensions.xyz.XyzClass'); 

然后我们可以创建这个类的实例,配置属性,然后调用他的方法。我们也可以用他创建子类。

1.3 新建扩展

由于扩展是要提供给第三方开发者使用,所以在创建的时候需要额外的工作。以下是一些常规指引:

●扩展最好是只关自身的。也就是,扩展最好不要对外有关联。如果说一个扩展,需要另外的安装包,类,或者是资源,对于开发者来说会很头疼。
●扩展有关的文件都必须放在以该扩展命名的目录下
●类名必须有自己的前缀,避免跟其他扩展的类重名。
●扩展必须有完整的安装说明以及API说明。这样其他开发者在使用的时候就可以节约很多时间。
●一个扩展要有一个合适的许可。如果你想你的扩展应用于开源或者是闭源项目,你可以使用诸如BSD,MIT等许可。GPL只许可用于开源项目。

接下来,我们来看看如何创建一个扩展。之前关于扩展的描述,同样适用于你自己的工程。

1.3.1 应用组件

一个应用组件应该实现接口{IApplicationComponent}或者是继承于IApplicationComponent。主要要实现的方法是IApplicationComponent::init,这个方法里,组件主要完成初始化工作。这个方法在组件创建以后被调用。

默认情况下,应用组件只有在第一次被请求使用的时候才会创建。如果想要一个应用组件在项目运行后就创建,那么必须在CApplication::preload 的属性中列出。

1.3.2 行为

要创建一个行为,必须实现[IBehavior]的接口。为了简便,Yii提供了一个基类CBehavior,他已经实现了这个接口,另外还提供了一些简便的方法。子类主要实现他所想要实现的额外方法。

当为CModel 和CActiveRecord开发行为的是时候,也可以继承于CModelBehavior and CActiveRecordBehavior。这些基类提供了额外的元件,专门为CModel 和CActiveRecord定做的。例如,CActiveRecordBehavior类实现了一组方法,用来相应ActiveRecord对象的生命周期。子类可以重载这些方法,自定义那些AR生命周期中的代码。

下面的例子中演示了AR行为。当这个行为绑定到一个AR对象中,当AR对象调用save方法时,会自动用当前时间设定create_time 和update_time的属性值。

 
  
  1. class TimestampBehavior extends CActiveRecordBehavior  
  2. {  
  3.     public function beforeSave($event)  
  4.     {  
  5.         if($this->owner->isNewRecord)  
  6.             $this->owner->create time=time();  
  7.         else 
  8.             $this->owner->update time=time();  
  9.     }  

1.3.3 小工具

一个widget可以继承于CWidget或者是他的子类。

一个创建小工具的最简单的方法,就是继承于现有的小工具,重写他的方法或者是设置他的属性。例如,你要给CTableView用一个更好的css样式,你可以在使用小工具的时候,设置他的CTabView::cssFile属性。你也可以继承于CTableView,这样在使用这个widget时就不要配置他的属性了:

 
  
  1. class MyTabView extends CTabView  
  2. {  
  3.     public function init()  
  4.     {  
  5.         if($this->cssFile===null)  
  6.         {  
  7.             $file=dirname(__FILE__).DIRECTORY SEPARATOR.'tabview.css';  
  8.             $this->cssFile=Yii::app()->getAssetManager()->publish($file);  
  9.         }  
  10.     parent::init();  
  11.     }  

上例中,我们重载了CWidget::init方法,然后如果是没有指定cssFile的属性,我们就指定为特定的文件。由于css文件是web不能直接访问的,所以我们必须作为一个asset来发布。

咳,精力实在不足了,先暂停到此。