• ThinkPHP---thinkphp模型(M)拓展


    (1)创建数据对象

    数据对象就是父类模型中的$this->data,AR模式的底层数据操作用到了数据对象。模型实例化之前数据对象只是空数组,后来使用了魔术方法__set设置了数据对象的值。

    上述流程可以得出,使用数据对象前必须先创建数据对象。__set是设置数据对象的一种方法,但是应用时不便,设置一个属性就得设置一行代码。

    因此ThinkPHP中系统封装了批量设置数据对象的方法:create方法

    语法:$model->create();

    关于参数,这里去分析父类模型

    public function create($data='',$type='') {
            // 如果没有传值,默认取POST数据
            if(empty($data)) {
                $data   =   I('post.');
            }elseif(is_object($data)){
                $data   =   get_object_vars($data);
            }
    }

    通过实现代码发现,若不给create方法传参,则默认使用post中的数据。在结尾,将处理完成的data数据赋值给了data属性,这步便是创建数据对象;将处理完成的数据返回出去,

    谁调用返回给谁。

    案例:改写之前编写的部门信息入库的代码,使用数据对象的创建方式。

    //判断请求类型,若是post则提交,否则展示
                if (IS_POST) {
                    //处理表单请求
                    //成功接收后,写入数据
                    $model = M('dept');//模型实例化
                    // echo $_POST['name'];
                    $data = $model->create();// 数据对象的创建需要模型去调用,所以必须放在实例化模型后(不传递参数,接收post数据)
                    // dump($data);die;
                    $result = $model->add();
                    //判断返回值
                    if ($result) {
                        $this->success('添加成功',U('showList'),3);
                    }else{
                        $this->error('添加失败');//默认跳到上一页
                    }
                }else{...}

    注意:如表单中字段和数据表的字段不匹配,则创建数据对象时会被过滤掉。

    如果想用打印方法查看数据是否正确,可以接收返回值。如果不想打印则可以不接受,在CURD操作时不需要给具体的操作方法传递参数。除非在使用自动验证时,必须接收

    返回值。

    (2)自动验证

    ①自定义规则:

       在提交数据时,系统按照指定规则进行数据的有效性和合理性验证。系统不知道表单的具体情况,所以没有想过规则,这也就需要我们自己去指定规则。

    如果需要使用自动验证,规则需要自己去定义。

    ②验证:

        在前端的JS里的验证叫前端验证,在ThinkPHP里验证机制为后端 / 服务器验证。两者区别,因为js是在客户端的验证,所以可以完成无刷新的验证。而PHP是服务器端验证,

    伴有刷新。除非用AJAX。

    ③语法:没有语法。。。由数据对象创建方法create方法去实现自动验证,这个在下面列出,我们需要做的就是指定相关验证规则。

    Model.class.php
    //
    数据自动验证 if(!$this->autoValidation($data,$type)) return false;

    所以综上可以得出,若想用自动验证则必须使用数据对象创建方法--create方法接收数据

    ④定义规则:

          在父类模型里存在成员属性_validate,这个属性是二维数组格式,用来保存验证规则

     // 查询表达式参数
        protected $_validate   =   array();  // 自动验证定义

    由于不能在父类模型里直接更改属性,所以这里可以把属性赋值到子类自定义模型中去定义规则。

    数据验证可以进行数据类型、业务规则、安全判断等方面的验证操作。

    数据验证有两种方式:

    1. 静态方式:在模型类里面通过$_validate属性定义验证规则。
    2. 动态方式:使用模型类的validate方法动态创建自动验证规则。

    无论是什么方式,验证规则的定义是统一的规则,定义格式为:

    array(
         array(验证字段1,验证规则,错误提示,[验证条件,附加规则,验证时间]),
         array(验证字段2,验证规则,错误提示,[验证条件,附加规则,验证时间]),
         ......
    );

    必选参数:①验证字段:表单里每一个表单项的name值;

                      ②验证规则:针对验证字段的格式限制。require必须、email邮箱、number数字、URL地址、currentcy货币

                      ③错误提示:验证失败后的提示信息

    可选参数:①验证条件:0默认,字段存在就验证;1必须验证;2字段不为空时验证。

                      ②附加规则:结合验证规则配合使用,具体方法可以参考手册

                      ③验证时间:分3种。新增数据时验证;编辑数据时验证;两者都验证

    (3)案例:针对部门添加功能,使用自动验证来验证字段合法性

    DempModel.class.php:

    // 自动验证定义
            protected $_validate=array(
                //规则编写,参考手册
                // 1.针对部门名称规则
                array('name','require','部门名称不能为空'),//必填
                array('name','','部门名称已经存',0,'unique'),//不重复,这步会走数据库
                //2.针对排序验证
                array('sort','number','排序必须为数字'),//是否为数字,还可以使用函数function来验证
                // array('sort','is_numeric','排序必须是数字',0,'function');//函数名要求是函数库的或当前模型定义声明的
                array('remark','require','必须添加备注'),//备注必填
            );  

    注意:因为这里是定义在了自定义模型里,所以实例化模型时需要实例化自定义模型。控制器DempController.class.php里修改

    $model = D('dept');//模型实例化

    ①验证失败:

              此时提交空表单,输出返回值dump($data);die;浏览器输出false。为什么是false?这里我们可以看父类模型,因为这里返回false

    // 数据自动验证
     if(!$this->autoValidation($data,$type)) return false;

    ②验证成功:如果验证成功,则返回正常数组

    输出用户提示信息:$model->getError();

    $model = D('dept');//模型实例化
                    // echo $_POST['name'];
                    $data = $model->create();// 数据对象的创建需要模型去调用,所以必须放在实例化模型后(不传递参数,接收post数据)
                    if (!$data) {
                        // echo $model->getError();
                        $this -> error($model->getError());exit;//虽然理论上回跳回上一页,但PHP底层代码会继续执行。所以必须加exit
                    }

    (4)批量验证

    一次性验证全部字段,需要配置成员属性

    系统支持数据的批量验证功能,只需要在模型类里面设置patchValidate属性为true( 默认为false),

    protected $patchValidate = true;
    

    设置批处理验证后,getError() 方法返回的错误信息是一个数组,返回格式是:

    array("字段名1"=>"错误提示1","字段名2"=>"错误提示2"... )

    前端可以根据需要需要自行处理,例如转换成json格式返回:

    $User = D("User"); // 实例化User对象
    if (!$User->create()){
         // 如果创建失败 表示验证没有通过 输出错误提示信息
         $this->ajaxReturn($User->getError());
    }else{
         // 验证通过 可以进行其他数据操作
    } 

    (3)字段映射

    ①映射表示对应关系

    ②应用场景:目前表单中的name值和数据表中的字段名一致,有一些人可能通过当前的功能和表单的name值猜测出表名字和表结构。后期可能会找到系统的漏洞,对系统进行

    攻击。系统的安全性存在威胁。因此可以使用类似障眼法,将name值随机指定,这时name值和表字段不一致,那样也就猜测不出表结构了。

    如果字段和数据表中的字段不匹配,会被系统过滤。所以需要有个对照列表,告知系统,不对应的name值是数据表的字段,防止字段被过滤。这时便用到了字段映射

    ③语法:没有语法、、、、只有规则定义$_map,与自动验证一样,在父类模型里有过定义

    // 查询表达式参数
        protected $_validate        =   array();  // 自动验证定义
        protected $_map             =   array();  // 字段映射定义

    将其复制到自定义子模型定义,

    // 字段映射定义
     protected $_map=array(
          //映射规则,键是表单中的name值 = 值是表单中的字段名
         'abcde'=>'pid',
         'fghij'=>'sort'
    ); 

    因为当前映射是建立在父类模型create方法里,所以在控制器里仍然需要create方式进行数据对象的创建

    此时前端表单中替换name值,任然可以运行

    pid:<input type="text" name="abcde"><br/>
    sort:<input type="text" name="fghij"><br/>

    在使用字段映射后,被映射的字段会被放到数组最后。按照字段映射的先后顺序进行排列。

    (4)特殊表的实例化操作

     表没有前缀,或者表前缀不是配置文件里定义的前缀,这些都是特殊表

    ①新建一张特殊数据表szphp

    ②创建模型文件szphpModel.class.php

    ③szphp的实例化操作,D和M。按照之前操作实例化验证输出后报错:Table 'db_oa.sp_szphp' doesn't exist [ SQL语句 ] : SHOW COLUMNS FROM `sp_szphp`

     实例化时会将前缀和表名自动连接起来,所以会报错提示sp_szphp表不存在。

       解决办法:看下父类模型文件关于数据表名的定义

     // 数据表名(不包含表前缀)
      protected $tableName        =   '';
      // 实际数据表名(包含表前缀)
      protected $trueTableName    =   '';//告知系统当前模型所关联的表的真实表名,且是已经包含前缀的表名

    这里我们选第二个,告诉ThinkPHP,这张表名已经包含前缀了,不要再加前缀。

    通过父类模型属性中的成员属性trueTableName属性,进行表名的指定。告知模型表名真实名字,让其不要再关联上前缀。

    输出$model结果

    ["model":protected] => string(5) "szphp"
        ["queryStr":protected] => string(25) "SHOW COLUMNS FROM `szphp`"//没有加前缀
        ["modelSql":protected] => array(1) {
          ["szphp"] => string(25) "SHOW COLUMNS FROM `szphp`"
        }
  • 相关阅读:
    java子类重写父类的要点
    转:swing 中paint与paintComponent的区别(jcomponent)
    证明二叉查找树所有节点的平均深度为O(logN)
    O(logN)中logN的底数
    Stanford依存句法关系解释
    java中的interface
    转:java中Vector的使用
    final类与final方法
    转:NLP+句法结构(三)︱中文句法结构(CIPS2016、依存句法、文法)
    英文语法分析树标注集
  • 原文地址:https://www.cnblogs.com/fightjianxian/p/8677588.html
Copyright © 2020-2023  润新知