Yii使用了MVC的开发模式,意在剥离数据获取,义务逻辑和视图,从而达到职责分离,代码复用的效果。在之前的开发中,一直是在model里面写数据获取,在controller里面写业务逻辑,在view里面写视图代码。对于业务处理流程来说,主要是在controller里面实现。

controller是一个大的划分,更细的粒度是controller里面的action方法。经常在一个controller里面会有多个action方法,例如增删改查,对应于某一个功能小块。有时候有些业务逻辑是共用的,如果还是在controller里面逐个写action方法,那么代码就冗余了,而且违背了”Do Not Repeat Yourself”的原则。为了达到代码复用,并且可维护的目的,可以考虑把action方法从controller中剥离出来,以供不同的controller调用。

在YII运行的过程中,controller里面的action方法实际上也是被实例化成CAction对象,然后再调用。即,在controller里面写一个actionXyz方法同写一个XyzAction的类是等价的,YII调用的时候会实例化成XyzAction对象,然后在运行。框架自带的验证码生成方法,就是一个代码复用的例子。但是如果生成验证码的controller不是当前的controller的话,验证就会出错,说明action实际上和controller也是密切关联的。

例如一个更新密码的action的逻辑,对于注册用户,管理员等是相同的,我们希望能够复用。为了达到这个目的,我们将其写成独立的action。步骤如下:

  1. 在protected下面创建actions文件夹,建立UpdatePasswordAction.php, 放置如下内容:

    class UpdatePasswordAction extends CAction
    {
    public $role;
    
    public function run()
    {
        // do something
    }
    }
    

    这是根据YII的框架要求,所有的action方法必须继承自CAction类,并且要实现run方法。上述代码声明了类名,其有公共变量role,用来区分用户角色。run里面就是具体的业务逻辑代码。

  2. 在controller里面调用。有了独立的action之后,就无需在controller里面写 public function actionUpdatePassword 这样的实现了。回忆起YII自带的验证码(captcha)和关于我(pages/about)的实现,只需在controller里面的actions方法里配置一下即可:

    class UserController extends Controller
    {
    public function actions()
    {
        'updatePassword' => array(
            'class' => 'application.actions.UpdatePasswordAction',
             'role' => 'user', 
        ),
    }
    }
    

    调用的时候需要明确指出action文件的详细路径,同时可以传递参数给action的公有变量。在UpdatePasswordAction中,我们定义了role属性,在调用的时候可以直接传递。当前前提必须是公有变量。

  3. 在其他需要的地方直接调用即可。

通过引入action,可以更方便的复用代码和维护代码。对于一些需要重复的代码,建议从controller里面剥离出来。