• Yii2用Gii自动生成Module+Model+CRUD


    1. 开启gii模块


    common/config/main-local.php加入下面代码

    return [
        'modules' => [
            'gii'   => [
                'class' => 'yiigiiModule',
                'allowedIPs' => ['::1','127.0.0.1'], //只允许本地访问gii
                'generators'=> [
                /*重新定义gii model & crud的生成模板*/
                'module'=> [
                    'class' => 'yiigiigeneratorsmoduleGenerator',
                    'templates'=> [
                        'backend'=>'@common/gii/generators/module/default'
                    ]
                ],
                'model'=> [
                    'class' => 'yiigiigeneratorsmodelGenerator',
                    'baseClass'=> 'baseBaseActiveRecord',
                    'ns'=> 'commonmodels',
                    'templates'=> [
                        'common'=>'@common/gii/generators/model/default',
                        'backend'=>'@common/gii/generators/model/backend'
                    ]
                ],
                'crud'=> [
                    'class' => 'yiigiigeneratorscrudGenerator',
                    'templates'=> [
                        'backend'=>'@common/gii/generators/crud/default'
                    ],
                        'baseControllerClass' => 'BaseBackendController',
                        'messageCategory'=> 'backend'
                    ]
                ]
            ]
        ]
    ];
    

    2. 访问gii


    URL:http://localhost/项目目录/backend/index.php/gii

    或者http://localhost/项目目录/backend/index.php/?r=gii

    3. 生成模块


    以后台模块为示例:
    Module Class 填写要生成module的路径
    Module ID 填写模块名
    Code Template 选择我们自定义好的Module生成模板

    如果生成成功会显示如下:

    4. 生成公共模型


    生成一个公共模型,方便不同入口应用复用和继承。

    生成成功会显示如下:

    5. 生成后台私有模型


    生成后台私有模型,并继承公共模型,在该类中实现后台私有的方法。

    生成成功会显示如下:

    6. 生成CRUD操作和视图


    去掉用不到的视图文件

    生成成功会显示如下:

    7. URL访问默认控制器


    crud组件commongiiCrud来实现基础的action

    Crud里的index方法已经做好了分页处理。
    index视图:backend/modules/test/views/default/index.php
    如非必要,不要直接书写原生的SQL

    joinWidth方法来关联表,需要在Test类定义好表关联。(注意joinWith里的大小写)
    关于关联表的具体用法请参考:
    http://www.yiichina.com/doc/guide/2.0/db-active-record

    backend/modules/test/models/Test.php

        public function getHabitusArticle()
        {
            /**
            * 第一个参数为要关联的字表模型类名称,
            *第二个参数指定 通过子表的 customer_id 去关联主表的 id 字段
            */
            return $this->hasMany(HabitusArticle::className(), ['hid' => 'hid']);
        }

    backend/modules/test/controllers/DefaultController.php

        /**
        * 
        * 查询
        */
        public function actionIndex()
        {
            $model = $this->findModel();
            $search_model = new TestSearch;
            $query = $model::find()->select(['*'])->joinWith('habitusArticle')->orderBy('`test`.`hid` asc');
            $query = $search_model->search($query);
            //$query;
            //如果要打印SQL
            //$query = $query->createCommand();
            //echo $query->sql;die;
            echo Yii::$app->crud->index($query, ['model'=> $model]);
        }
    

    得到的SQL:

    SELECT * FROM `test` LEFT JOIN `habitus_article` ON `test`.`hid` = `habitus_article`.`hid` ORDER BY `hid`
    

    8. 字段显示值的格式化


    先要在modles里定义字段的别名。

    backend/modules/test/models/Test.php

        /**
         * @inheritdoc
         */
        public function attributeLabels()
        {
            return [
                'hid' => 'Hid',
                'name' => '名称',//定义别名
                'remark' => '描述',//定义别名
                'percent' => 'Percent',//....
                'hearttrait' => 'Hearttrait',
                'common' => 'Common',
                'nacs' => 'Nacs',
                'attack' => 'Attack',
                'listorder' => 'Listorder',
                'datetime' => 'Datetime',
                'status' => 'Status',
                'created_by' => 'Created By',
                'updated_by' => 'Updated By',
            ];
        }

    对于字段值重写,只需定义好Model里的attributeFormats()方法来实现字段格式化输出。(非Yii2方法)
    如下:
    访问index方法时,datetime字段会被格式为"Y-m-d H:i:s"格式,
    访问xls方法时,datetime字段会被格式为"Y年m月d日"格式,
    匿名函数中的$value表示字段原始值,$data表示select所列出的所有字段值

    backend/modules/test/models/Test.php

    
        /**
         * 字段格式化
        
         */
        public function attributeFormats()
        {
             return [
                'datetime'=>[//字段名
                    [
                        'action'=> ['index'],
                        'data'=> function($value, $data){
                            return date("Y-m-d H:i:s", $value); 
                        }
                    ],
                    [
                        'action'=> ['xls'],
                        'data'=> function($value, $data){
                            return date("Y年m月d日", $value); 
                        }
                    ],
                ]
            ];
        }
    

    9. 表单搜索设置


    用好yiidbQuery查询构建器包括关联表查询,尽量不要直接写sql语句。
    控制器和视图中所用的字典类,获取数据的方法都应写到Model里。

    backend/modules/test/models/TestSearch.php
    配置好search方法,根据需求来确定字段搜索是like还是=或者其他。
    可参考Yii2的yiidbQueryandFilterWhere等方法和操作符格式
    andFilterWhere可放心使用,搜索时字段非空才会执行。
    http://www.yiichina.com/doc/guide/2.0/db-query-builder

    backend/modules/test/models/TestSearch.php

    public function search($query, $params = [])
    {
        $params = $params ? : Yii::$app->request->getQueryParams();
        $this->attributes = $params;
    
        $start_time = ArrayHelper::getValue($params, 'start_time');//相当于isset($params['start_time']) ? $params['start_time'] : NULL;
        $end_time = ArrayHelper::getValue($params, 'end_time');
    
        $query->andFilterWhere([
            'status' => $this->status,
        ]);
    
        $query->andFilterWhere(['like', 'name', $this->name])
            ->andFilterWhere(['like', 'remark', $this->remark])
            ->andFilterWhere(['between', 'datetime', $start_time ? strtotime($start_time.' 00:00') : NULL, $end_time ? strtotime($end_time.' 23:59') : NULL]);
        return $query;
    }
    

    得出的sql是:

    SELECT * FROM `test` WHERE ((`status`=:qp0) AND (`name` LIKE :qp1)) AND (`datetime` BETWEEN :qp2 AND :qp3) ORDER BY `hid`
    
    
    1. 字段排序


    backend/modules/test/models/Test.php
    需要继承自 baseBaseActiveRecord
    定义参与排序的字段:

    class Test extends commonmodelstestTest{     
        //排序字段
        public $sortFields = ['percent', 'datetime'];
    

    backend/modules/test/controllers/DefaultController.php

    $model = $this->findModel();
    $search_model = new TestSearch;
    $query = $model::find()->select(['*']);
    $query = $search_model->search($query);
    $sort = $search_model->sortOrderBy('`test`.`hid` asc');//默认的排序字段
    $query->orderBy($sort);

    backendmodules estviewsdefault_form.php

    设置排序链接和样式

    <th width="120" class="<?=$model->sortQueryParams('percent', 'class');?>" onClick="window.location.href='<?=$model->sortQueryParams('percent', 'link');?>';">占百分比</th>

    效果:

    1. 视图及表单,


    视图里尽量避免编写复杂的逻辑。

    由于默认生成的表单控件都是input,
    接下来需要修改createupdate的视图文件(表单)。
    按照业务需求设置好字段的表单控件和验证规则

    backendmodules estviewsdefault_form.php

    表单元素为必填项的在lable上的class加上form-required,即:

    <label class="col-sm-2 control-label form-required"><?=$model->getAttributeLabel('name');?></label>
    

    常用的表单控件类型有:
    backend/modules/test/models/Test.php 里定义好了Status的字典

        /**
         * @status
         */
        public static function Status($key = false){
            $array = [
                '0'=> '有效',
                '2'=> '锁定'
            ];
            if ($key === false){
                return $array;
            }else{
                return isset($array[$key]) ? $array[$key] : '';
            }
            
        }

    单行文本框:

    <?= Html::input('text', 'Test[name]', $model->name, ['class' => 'form-control']) ?>

    或者

    <?=  Html::activeInput('text', $model, 'name', ['class' => 'form-control']) ?>
    

    多行文本框:

    <?= Html::textarea('Test[name]', $model->name, ['class' => 'form-control']) ?>
    <?= Html::activeTextarea($model, 'name', ['class' => 'form-control']) ?>
    

    下拉列表:

    <?=Html::dropDownList('Test[status]', $model->status, $model::Status(), ['class' => 'form-control m-b']);?>
    <?=Html::activeDropDownList($model, 'status', $model::Status(), ['class' => 'form-control m-b']);?>
    

    复选框

    <?= Html::checkboxList('Test[status]', $model->status, $model::Status());?>  
    <?= Html::activeCheckboxList($model, 'status', $model::Status());?>  
    

    单选框

    <?= Html::radioList('Test[status2]', $model->status, $model::Status());?>
    <?= Html::activeRadioList($model, 'name', $model::Status()) ?>
    

    单选列表

    <?= Html::listBox('Test[status3]', $model->status, $model::Status(), ['class'=>'form-control']);?>
    <?= Html::activeListBox($model, 'status', $model::Status(), ['class'=>'form-control']);?>
    
    

    多选列表

    <?= Html::listBox('Test[status4]', $model->status, $model::Status(), ['multiple'=>true, 'class'=>'form-control']);?> 
    <?= Html::activeListBox($model, 'status', $model::Status(), ['multiple'=>true, 'class'=>'form-control']);?> 
    

    切换开关

    <?= Html::checkbox('Test[status5]', $model->status, ['class'=> 'js-switch']);?> <?= Html::checkbox('HabitusTest[status6]', $model->status, ['class'=> 'js-switch']);?>   
    <?= Html::activeCheckboxList($model, 'status', $model::Status(), ['class'=> 'js-switch']);?> 
    

    下拉选择带搜索

    <?=Html::dropDownList('Test[status9]', '120000', $model::City(), ['prompt'=>'--请选择--', 'data-placeholder'=>'选择省份...', 'class'=>'chosen-select', 'style'=>'350px;', 'tabindex'=>'2']);?>
    <?=Html::activeDropDownList($model, 'status', $model::City(), ['prompt'=>'--请选择--', 'data-placeholder'=>'选择省份...', 'class'=>'chosen-select', 'style'=>'350px;', 'tabindex'=>'2']);?>
    

    下拉多选带搜索

    <?=Html::dropDownList('Test[status9]', ['120000','110000'], $model::City(), ['multiple'=>true, 'data-placeholder'=>'选择省份...', 'class'=>'chosen-select', 'style'=>'350px;', 'tabindex'=>'2']);?>
    <?=Html::activeDropDownList($model, 'status', $model::City(), ['multiple'=>true, 'data-placeholder'=>'选择省份...', 'class'=>'chosen-select', 'style'=>'350px;', 'tabindex'=>'2']);?>
    
    

    表单验证规则 示例
    更详细的验证方法参考:[jQuery.validate][10] 插件

    <script>  
    $(function () {        
        $("#view-form-form").validate({
            //debug:true, //如果只调试验证不提交数据,可开启这里
            rules: {
               'Test[name]':{
                   required:true,//必填
                   maxlength: 50 //最大长度
                },
                //其他的字段的验证...
            },
            ignore:"",//验证包括hidden的input元素
            messages: {
                'Test[name]':{
                    required:'请输入体质名称',//未输入提示
                    maxlength:'体质名称输入太长'//超出最大长度提示
                },
            }
        });
    });
    </script>
    
    1. 保存表单数据到数据库


    瘦控制器 胖模型

    $model->sava()前会根据Model类的rules()方法定义规则去校验数据

    backend/modules/test/models/Test.php

        /**
         * @inheritdoc
         */
        public function rules()
        {
            return [
                [['name'], 'required'],//必填
                [['percent', 'listorder', 'datetime', 'status', 'created_by', 'updated_by'], 'integer'],//必需为数字
                [['name'], 'string', 'max' => 300],//最长300
                [['remark', 'hearttrait', 'common', 'nacs', 'attack'], 'string', 'max' => 500]//字符串,最长500
            ];
        }

    guide: 详细的rules
    数据验证不通过时可以根据打印$model->getErrors()查看具体错误信息

    对于表单提交过来的数据不是最终保存到数据库里的格式时,如时间戳等,
    可以通过自定义rules或者重组表单数据来实现:(还有其他方法也可以实现)

    backend/modules/test/models/Test.php

        public function validateCountry($attribute, $params)
        {
            $this->$attribute = 'new '.$this->$attribute;//这里可以重新设置name的值
            //也可以使用自定义验证规则
            //if (!in_array($this->$attribute, ['USA', 'Web'])) {
                //$this->addError($attribute, 'The country must be either "USA" or "Web".');
            //}
        }
        /**
         * @inheritdoc
         */
        public function rules()
        {
            return [
                ['name', 'validateCountry'],
                [['name'], 'required'],
                [['percent', 'listorder', 'datetime', 'status', 'created_by', 'updated_by'], 'integer'],
                [['name'], 'string', 'max' => 300],
                [['remark', 'hearttrait', 'common', 'nacs', 'attack'], 'string', 'max' => 500]
            ];
        }
    

    或者我们用behaviors来实现一些字段的数据的自动化填充

    backend/modules/test/models/Test.php

        public function behaviors()
        {
            return [
                [
                    'class' => 'yiiehaviorsBlameableBehavior',
                    'createdByAttribute' => 'created_by',//create时,created_by字段的值会自动填充为当前操作用户的ID:Yii::$app->user->identity->id;
                    'updatedByAttribute' => 'updated_by',
                ],
                'timestamp' => [
                    'class' => 'yiiehaviorsTimestampBehavior',
                    'attributes' => [
                        //insert数据库前datetime的值会自动填充为当前的时间戳
                        BaseActiveRecord::EVENT_BEFORE_INSERT => ['datetime'],
                        //BaseActiveRecord::EVENT_BEFORE_UPDATE => ['updated_at'],
                    ],
                ],
            ];
        } 

    注:本文由王智磊(王大宝儿)整理编写,也参考借鉴了很多大神的笔记,分享代码,分享成功,欢迎各位交流和转载,转载请注明出处(博客园:王大宝儿)http://www.cnblogs.com/wangzhilei/

  • 相关阅读:
    CORS跨域资源共享漏洞
    Linux Restricted Shell Bypass
    无情一点并没有错
    [机器学习]numpy broadcast shape 机制
    Chrome和IE的xss过滤器分析总结
    php使用substr中文乱码问题
    mac下自定义伪协议配置
    【转】前端黑魔法之远程控制地址栏
    Windows可信任路径代码执行漏洞
    小记一次mysql启动失败没有日志的处理
  • 原文地址:https://www.cnblogs.com/wangzhilei/p/6527688.html
Copyright © 2020-2023  润新知