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,我们就在视图脚本语句中调用以下语句:
- $this->widget('zii.widgets.grid.CGridView', array(
- 'dataProvider'=>$dataProvider,
- ));
1.2.2 应用组件
要使用一个应用组件,我们要在项目的配置文件中的components字段中,加入一个新的选项,如下:
- return array(
- // 'preload'=>array('xyz',...),
- 'components'=>array(
- 'xyz'=>array(
- 'class'=>'ext.xyz.XyzClass',
- 'property1'=>'value1',
- 'property2'=>'value2',
- ),
- // other component configurations
- ),
- );
然后,我们就可以在任何地方调用Yii::app()->xyz。组件会滞后创建(也就是,在第一次访问的时候再生成),除非,我们在预装载的属性列表中指定该组件的装载属性。
1.2.3 行为
行为可以被用于任何类型的组件。他的使用包括2个步骤。第一步,一个行为要绑定到一个指定的组件。第二步,通过这个目标组件来调用这个行为。例如:
- // $name uniquely identifies the behavior in the component
- $component->attachBehavior($name,$behavior);
- // test() is a method of $behavior
- $component->test();
更多情况下,我们是通过配置的方式来绑定一个行为到目标组件上,而不是调用attachBehavior的方法。例如,要绑定一个行为到应用组件中,我们可以配置项目工程如下:
- return array(
- 'components'=>array(
- 'db'=>array(
- 'class'=>'CDbConnection',
- 'behaviors'=>array(
- 'xyz'=>array(
- 'class'=>'ext.xyz.XyzBehavior',
- 'property1'=>'value1',
- 'property2'=>'value2',
- ),
- ),
- ),
- //....
- ),
- );
上面的代码中,把xyz的行为绑定到了一个数据库组件中。我们之所以可以这么做,是因为CApplicationComponent定义了一个叫做behaviors的属性。通过设置这个属性为一个行为配置列表,当这个组件初始化的时候,会绑定这些行为。
对于CController, CFormModel 和 CActiveRecord这些经常被用于扩展的类,可以通过重载他们的behaviors的方法来绑定。这些类会在初始化的时候,自动加载这个方法里的所有行为:
- public function behaviors()
- {
- return array(
- 'xyz'=>array(
- 'class'=>'ext.xyz.XyzBehavior',
- 'property1'=>'value1',
- 'property2'=>'value2',
- ),
- );
- }
1.2.4 小工具Widget
widget一般用于视图。假设一个widget类XyzClass属于xyz扩展,我们可以在视图中这样使用:
- // widget that does not need body content
- <?php $this->widget('ext.xyz.XyzClass', array(
- 'property1'=>'value1',
- 'property2'=>'value2')); ?>
- // widget that can contain body content
- <?php $this->beginWidget('ext.xyz.XyzClass', array(
- 'property1'=>'value1',
- 'property2'=>'value2')); ?>
- ...body content of the widget...
- <?php $this->endWidget(); ?>
1.2.5 动作
动作是一个控制器用来相应特定的用户请求的。假设一个动作类XyzClass属于xyz这个扩展,我们可以在控制器中重载CController::actions的方法来使用:
- class TestController extends CController
- {
- public function actions()
- {
- return array(
- 'xyz'=>array(
- 'class'=>'ext.xyz.XyzClass',
- 'property1'=>'value1',
- 'property2'=>'value2',
- ),
- // other actions
- );
- }
- }
这样,这个动作就可以就可以通过路由test/xyz来访问了。
1.2.6 过滤器
过滤器跟动作一样,也是用于控制器的。他们一般是在一个动作捕获到用户时,预先处理,或者是最后处理。假设一个过滤器类XyzClass属于xyz扩展,我们可以通过重载CController::filters的方法来使用:
- class TestController extends CController
- {
- public function filters()
- {
- return array(
- array(
- 'ext.xyz.XyzClass',
- 'property1'=>'value1',
- 'property2'=>'value2',
- ),
- // other filters
- );
- }
- }
在上例中,我们可以在第一个元素组中,用+号或者是减号来限制过滤器只作用于哪些指定的动作。更多详情请参见控制器说明。
1.2.7 控制器
一个控制器提供了一些能被用户请求的动作。要用控制器扩展,我们要在项目的配置文件中配置CWebApplication::controllerMap:
- return array(
- 'controllerMap'=>array(
- 'xyz'=>array(
- 'class'=>'ext.xyz.XyzClass',
- 'property1'=>'value1',
- 'property2'=>'value2',
- ),
- // other controllers
- ),
- );
这样,控制器中的方法a,我们就可以通过路由xyz/a来访问了。
1.2.8 校验器
一个校验器主要用于模型类(不管是继承于CFormModel 或CActiveRecord的都可以)。假设一个校验器类XyzClass属于扩展xyz的,我们可以在模型类中重载CModel::rules():
- class MyModel extends CActiveRecord // or CFormModel
- {
- public function rules()
- {
- return array(
- array(
- 'attr1, attr2',
- 'ext.xyz.XyzClass',
- 'property1'=>'value1',
- 'property2'=>'value2',
- ),
- // other validation rules
- );
- }
- }
1.2.9 控制台命令
一个控制台命令扩展一般用于加强yiic功能。假设一个控制台命令类属于xyz扩展,我们可以为该控制台配置如下:
- return array(
- 'commandMap'=>array(
- 'xyz'=>array(
- 'class'=>'ext.xyz.XyzClass',
- 'property1'=>'value1',
- 'property2'=>'value2',
- ),
- // other commands
- ),
- );
然后,我们就能使用配备了额外命令 xyz
的 yiic
工具了。
注意:一个控制台程序的配置文件使用方法,一般跟web工程的是不同的。如果工程是通过yiic webapp命令创建的,那么控制台配置文件就是protected/config/console.php,web工程的配置文件是protected/config/main.php。
1.2.10 模块
参考模块的使用说明
1.2.11 通用组件
要使用一个通用组件, 我们首先要导入他的类:
- 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的属性值。
- class TimestampBehavior extends CActiveRecordBehavior
- {
- public function beforeSave($event)
- {
- if($this->owner->isNewRecord)
- $this->owner->create time=time();
- else
- $this->owner->update time=time();
- }
- }
1.3.3 小工具
一个widget可以继承于CWidget或者是他的子类。
一个创建小工具的最简单的方法,就是继承于现有的小工具,重写他的方法或者是设置他的属性。例如,你要给CTableView用一个更好的css样式,你可以在使用小工具的时候,设置他的CTabView::cssFile属性。你也可以继承于CTableView,这样在使用这个widget时就不要配置他的属性了:
- class MyTabView extends CTabView
- {
- public function init()
- {
- if($this->cssFile===null)
- {
- $file=dirname(__FILE__).DIRECTORY SEPARATOR.'tabview.css';
- $this->cssFile=Yii::app()->getAssetManager()->publish($file);
- }
- parent::init();
- }
- }
上例中,我们重载了CWidget::init方法,然后如果是没有指定cssFile的属性,我们就指定为特定的文件。由于css文件是web不能直接访问的,所以我们必须作为一个asset来发布。
咳,精力实在不足了,先暂停到此。