Yii之单一页面CRUD(非Ajax)理解MVC

默认Yii的代码生成器Gii生成的CRUD的特点是:

1、创建actionCreate,不带GET参数

$model = new  MyModel;

if(isset($_POST['MyModel'])){  //带POST变量值,这是提交后的处理

    $model->attributes = $_POST['MyModel'];   //批量属性赋值

    if(isset($_POST['keyname'])      $v = $_POST['keyname'];    //可以有和模型属性不对应的POST变量

    $model->attr1 = $_POST['keyname'].'一定处理';        //可以在批赋值后对个别属性值进行调整(和POST变量无关的调整不放这里,应该放入beforeSave)

   if($model->save()){

     //保存成功,通常$this->redirect(array('view', 'id' => $model->id));重定向

  }

}

//渲染create视图,一般保存后因为重定向不会到此,所以$model是空的数据收集器

//create视图主要就是渲染分部视图 _form,以便用户输入。表单动作的指向如果未设定CActiveForm的action属性,默认就是当前页面URL,即 MyModel/create

$this->render('create', array('model' => $model));  

2、读取单条记录actionView($id),带GET参数 ?id=nnn

用$this->loadModel($id)读取id为$id的模型,渲染view视图,将读取的模型$model作为参数传递

Gii生成的view视图用zii.widgets.CDetailView部件展示$model中的数据,主要是定制每个属性列(和CGridView有类似之处,但又不同),

因为模型只有一个,所以每列中引用模型时直接用变量$model,定制'value'值不用对表达式加引号

3、读取所有记录(即列表)actionIndex,不带GET参数

显然,此时有很多个模型,因此需要“数据提供者”这一重要角色,数据提供者$dateProvider和查询标准$criteria对最终展示哪些数据,数据排序、分页起着重要作用。

渲染index视图时,主要的参数就是数据提供者$dataProvider。Gii生成的index视图用zii.widgets.CListView部件展示数据,每个模型用分部视图_view进行渲染。

因为有很多模型了,所以_view分部视图用$data变量表示当前模型,可以像设计一小块页面一样设计_view分部视图。

4、删除单条记录actionDelete($id),带GET参数 ?id=nnn

delete没有也不需要对应的视图,而且Gii生成的代码delete动作只能从admin管理视图下进行操作,并且是Ajax方式的。delete动作主要包括

找出id为$id的模型,执行其实例方法delete(),如果不是Ajax请求,重定向到前一位置或admin

5、更新单条记录actionUpdate($id),带GET参数 ?id=nnn

更新部分的代码和创建非常类似,只有一点区别,创建时通过new MyModel给$model赋值,更新时用$this->loadModel($id)给$model赋值。值得注意的是,new MyModel得到的模型,其isNewRecord属性值为true,而$this->loadModel方法得到的模型,其isNewRecord属性值为false。而且,渲染update视图时,$model变量是包含了旧模型数据的,它需要展示到分部视图_form(和create共享的分部视图)

6、管理所有记录actionAdmin,不带GET参数(但可以有GET过来的表单数据)

        $model=new Labclass('search');                  //新建search场景的模型,场景主要决定需要验证哪些字段
        $model->unsetAttributes();  // clear any default values     //因为此模型用作过滤器,所以清除所有属性的默认值
        if(isset($_GET['Labclass']))
            $model->attributes=$_GET['Labclass'];        //这里用GET变量区分是否已经输入过滤器表单的数据

        $this->render('admin',array(
            'model'=>$model,                     //渲染视图,如果$model是空的,就显示表单给用户来输入,如果$model含有数据,那么同时被search()方法用于数据提供者
        ));

admin视图中包含了一个初始隐藏的表单_search(分部视图),该表单用于高级搜索,包含$model变量,并且是用GET方法传递参数的(对照上述代码)

admin视图的重头戏是CGridView,它的过滤器也是$model变量,而数据提供者是$model->search()实例方法得到的(注意,如果$model是包含数据的,这些数据会被search()方法中的查询标准所利用,从而过滤出数据)。CGridView的列定义在另一个帖子中已经详细描述,就是要注意,和CDetailView相比,它定义列时'value'对应的表达式要用引号(可以用单引号,然后表达式内用双引号或转义的单引号)

------------------------------------------------------------------------------------------------------------------------------------------------------------------------

理解了Gii生成的CRUD,我们来表述单页面的CRUD(即CRUD杂合体),用于批量操作

public function actionBatch($cid = '', $oid = '', $tid = '', $id = '')        //参数  $cid/$oid/$tid为模型公共数据,充当过滤器角色, $id识别模型用
    {
        $model =  $id ? $this->loadModel($id) : new Labclass;        //带GET[‘id’]参数,用于更新操作
        $oldmodels = array();
 
        if($cid && $oid && $tid){
            $model->class_id = $cid; $model->course_id = $oid; $model->teacher_id = $tid;          //预置模型公共部分数据,在视图中用于判断公共部分信息是否确定
            $oldmodels = Labclass::model()->findAllByAttributes(array(
                'class_id'=>$cid, 'course_id'=>$oid, 'teacher_id'=>$tid                      //过滤出已经存在的同类模型数据
            ));
        }
        
        if(isset($_POST['Labclass'])){                             //有POST数据,可能是公共部分,也可能是新模型(含公共部分)
            $model->attributes = $_POST['Labclass'];
            if(isset($_POST['week'])){    //带week参数,是新模型,修正部分属性,再保存
                $model->date = Term::getDateByWeekDay($_POST['week'], $_POST['day']);
                $sectionNames = Term::getSectionMap(true);
                $timeSegs = Term::getSectionMap(false);
                $model->section = $sectionNames[$_POST['section']];
                $model->timebegin = $timeSegs[$model->section][0];
                $model->timeend = $timeSegs[$model->section][1];
                $model->status = Labclass::STATUS_APPROVED;
                
                if($model->save()){}
                
            }
            $this->redirect(array('batch', 'cid' => $model->class_id,
                        'oid' => $model->course_id, 'tid' => $model->teacher_id));  //重定向到自己,但带上公共数据作为参数,实际进入batch,最后到render部分

        }
    
        $this->render('batch', array(                //如果$model,$oldmodels均为空的,此时用表单获取公共部分数据
            'model' => $model,                      //如果$model非空,$oldmodels为空,此时$model包含的是公共部分数据
            'oldmodels' => $oldmodels,    //如果$model,$oldmodels均非空,是更新
        ));
    }

batch视图:

如果有flash,显示

================表单开始

根据$model->isNewRecord,设置$form->action属性(如果是更新,传递id参数回actionBatch)

公共部分信息已经确定,表格显示已经存在的同类模型数据(每个模型后有链接按钮可以提交到deleteForBatch、updateForBatch)

渲染添加新数据或修改旧数据的表单(公共部分数据可以用隐含字段POST,同样用isNewRecord可以区分新旧)

未确定公共信息,就显示表单让用户输入

===============表单结束


    public function actionDeleteForBatch($id)
    {
        $modelToDelete = $this->loadModel($id);
        $modelToDelete->delete();
        
        $this->redirect(array('batch', 'cid'=>$modelToDelete->class_id,
            'oid'=>$modelToDelete->course_id, 'tid'=>$modelToDelete->teacher_id));
    }
    
    public function actionUpdateForBatch($id)
    {
        $modelToUpdate = $this->loadModel($id);
        $this->redirect(array('batch', 'id'=>$id, 'cid'=>$modelToUpdate->class_id,
            'oid'=>$modelToUpdate->course_id, 'tid'=>$modelToUpdate->teacher_id));
    }


总的来说,我们让actionBatch不带参数,是新增(包含第一步获取公共信息,第三步新增记录),我们让actionBatch不带id参数,但带cid/oid/tid参数,这用于第二步获取公共信息后的重定向筛选显示,以及删除记录后的重定向筛选显示,类似列表显示index,我们让actionBatch带id参数和cid/oid/tid参数,这包含了更新过程。

你可能感兴趣的:(Yii,MVC,CRUD)