zoukankan      html  css  js  c++  java
  • 《TP5.0学习笔记---模型篇》

    https://blog.csdn.net/self_realian/article/details/78596261

    一、什么是模型 

    为什么我们要在项目中使用模型,其实我们知道,我们可以直接在控制器中进行数据库的增、删、改、查,其实已经能基本完成我们的需求,但是,为什么还要有模型的存在呢? 

    比如说我们现在要做一个用户注册的操作,用户注册我们可能用两个表来保存用户的信息,一个是user表(保存用户基本信息),一个是user_info表(保存用户扩展信息,比如爱好等等),如果我们现在直接在我们的控制器中编写,那么我们需要对数据库两个表进行操作,我们就需要写两个db的方法来进行操作,我们需要将这些方法进行封装,最后放在模型里,只要执行这个模型里的某一个方法,那么就会自动完成我们所有操作的操作,也就是说,把我们数据库完成同一件事情的操作,放在一个公共方法里,这样我们在控制器里进行调用就会变得很方便。特别是代码复用的部分,我们可以编写这样的方法,让我们在任何地方可以使用用户注册这个方法。那么下面就看看如何定义模型: 

    首先在我们的application/index/创建一个model目录,专门放模型文件,然后在model目录下创建一个User.php文件 

    模型文件的命名规范: 首先我们的模型名和我们的表名要是对应的。比如我们要写我们数据库中的shulv_user表,那么我们的模型名就是去掉前缀之后使用驼峰的命名方式,也就是User.php,当数据库中有这种包含下划线的表名时,去掉下划线,并将下划线后边的字母大写,即时模型名,shulv_user_info 对应模型名就是UserInfo,这样他就会自动对应到数据库中的表。下边写代码验证一下:

    namespace appindexcontroller;

     

    use thinkController;

    use appindexmodelUser;//使用我们刚刚新建的那个模型

     

    class Index extends Controller

    {

        public function index()

        {

            $res = User::get(51);//通过get()方法,取出user表中的id=51的这条数据(现在可以不用知道为什么使用get方法,后边会说)

            $res = $res->toArray();//将取出的数据转换成数组

            dump($res);

        }

    }

    •  

    你会发现,我们没有在模型中的User.php中编写任何的代码,但是在控制器中use进来User模型之后,就可以直接使用静态方法,这是为什么呢? 

    因为在我们的模型文件中的类都继承了thinkModel这个类,thinkModel中其实有这样的方法,这些方法,后边会说到。同样我们还可以在控制器中使用new的方式

    $user = new User();

            $res = $user::get(53);

            $res = $res->toArray();

            dump($res);

    •  

    当我们,不想通过use的方式将User模型引入进来的时候,我们还可以通过下边的方法:

    namespace appindexcontroller;

     

    use thinkController;

    //use appindexmodelUser;//使用我们刚刚新建的那个模型

    use thinkLoader;//通过引入think下的Loader类

    class Index extends Controller

    {

        public function index()

        {

            $user = Loader::model("User");//通过Loader下的model这个静态方法来引入对应模型

            $res = $user::get(52);

            $res = $res->toArray();

            dump($res);

     

        }

    }

    //说明:这种方式,是当我们的控制器下有多个模型的时候,我们使用这种方式,这样我们就不用在使用每一个模型的时候都use一下,我们直接使用Loader::model()这种方法直接引入。另外,它还提供了一个助手函数model(),此时我们连Loader类都不用引入了

    /*

        $user = model("User");

        $res = $user::get(52);

        $res = $res->toArray();

        dump($res);

    */

     

    //在这里建议大家使用前两种方式,因为助手函数式可能被覆盖掉的,当然这种情况很少发生,但是为了避免,或者让我们的代码可读性更高,建议大家使用第一种方式,也就是将需要的模型都use进来,通过它的静态方法来获取数据,这样我们的代码看起来更清晰,我们可以在最上边就看见我们当前的控制器使用了哪些模型类,这样在后期维护中会变得很方便

    •  

    二、通过模型进行数据查询

    namespace appindexcontroller;

     

    use thinkController;

    use appindexmodelUser;//使用我们刚刚新建的那个模型

    //use thinkLoader;//通过引入think下的Loader类

    class Index extends Controller

    {

        public function index()

        {

            //之前我们查询一条数据的时候是通过给get()方法传递一个主键来获取对应数据,我们还可以传递一个闭包函数

            $res = User::get(function($query){//在这里边构造查询条件

                $query->where("id", "eq", 55);//这里条件的构造和前边的博客中说的一样(同样可以在后边继续添加链式方法)

            });

            $res = $res->toArray();

            dump($res);

        }

    }

    •  

     

    我们还可以通过下边这种方法构造where条件

    namespace appindexcontroller;

     

    use thinkController;

    use appindexmodelUser;//使用我们刚刚新建的那个模型

    //use thinkLoader;//通过引入think下的Loader类

    class Index extends Controller

    {

        public function index()

        {

            $res = User::where("id", 51)

                ->find();//同样我们可以在后边添加更多的链式方法

            $res = $res->toArray();

            dump($res);

        }

    }

    /*

    当我们想获取表中的多条数据时,我们可以使用User::all();参数是主键名,可以使用字符串的方式,也可以使用数组的方式

    $res = User::all("1,2,3");//这个时候返回的每一条记录都是一个对象,我们就可以通过foreach进行遍历输出

    //或$res = User::all([1,2,3]);

    foreach($res as $value){

        dump($value->toArray());//这个时候我们就会获得三条数据

    }

     

    //这个all()还可以接收一个闭包函数作为参数,来构造where条件

    $res = User::all(function($query){

        $query->where("id", "<", 5); //同样可以添加更多的链式方法

    });

     

    */

    •  

    当我们想要获取单独的一个字段,我们知道Db类有一个value() 方法,模型我们也可以这样

    $res = User::where()->value("email");//直接返回的是字符串

    dump($res);

    //获取某一个字段那一列时

    $res = User::column("email");//返回的是一个数组

    •  

    三、使用模型添加数据 

    在thinkphp,它的model为我们提供了一个create()方法(静态方法),直接向数据库中插入数据

    namespace appindexcontroller;

     

    use thinkController;

    use appindexmodelUser;//使用我们刚刚新建的那个模型

    //use thinkLoader;//通过引入think下的Loader类

    class Index extends Controller

    {

        public function index()

        {

           $res = User::create([

                'username'   =>  'shulv',

                'password'   =>  md5('shulv'),

                'email'      =>  'shulv@qq.com',

                'num'        =>  100

           ]);//它的返回结果依然是一个对象

           dump($res->id);//获得此时的自增id

           dump($res);

        }

    }

    •  

     

    namespace appindexcontroller;

     

    use thinkController;

    use appindexmodelUser;//使用我们刚刚新建的那个模型

    //use thinkLoader;//通过引入think下的Loader类

    class Index extends Controller

    {

        public function index()

        {

           // $res = User::create([

           //      'username'   =>  'shulv',

           //      'password'   =>  md5('shulv'),

           //      'email'      =>  'shulv@qq.com',

           //      'num'        =>  100

           //      'demo'       =>  15245

           // ]);//当我们要插入一个表中并没有的字段时,不传递第二个参数时,运行时会报错,说该字段不存在(此时数据库也并不会插入这条数据)

    /*

        我们知道,当前台传递数据时,往往直接传到$_POST中,我们会将POST中所有的数据插入到表中,那么我们就应该让它有的就插入表中,没有的就不插入,此时我们就需要给它传入第二个参数"true"

    */

            $res = User::create([

                'username'   =>  'shulv1',

                'password'   =>  md5('shulv1'),

                'email'      =>  'shulv1@qq.com',

                'num'        =>  101,

                'demo'       =>  15245

           ],true);

     

           dump($res);

        }

    }

    •  

     

    当我们仅允许添加指定的字段时,我们可以将第二个参数传递一个数组,数组中的元素就是,你指定添加的字段

    public function index()

        {

            $res = User::create([

                'username'   =>  'shulv2',

                'password'   =>  md5('shulv2'),

                'email'      =>  'shulv2@qq.com',

                'num'        =>  102,

                'demo'       =>  145

           ],['username','password']);

     

           dump($res->id);

        }

    •  

     

    模型中还为我们提供了一个save()方法来插入数据(如果我们想使用save()就要先实例化我们的模型)

    namespace appindexcontroller;

     

    use thinkController;

    use appindexmodelUser;//使用我们刚刚新建的那个模型

    //use thinkLoader;//通过引入think下的Loader类

    class Index extends Controller

    {

        public function index()

        {

            $userModel = new User;

            //那么此时,我们就可以对数据库进行添加的操作了

            $userModel->username = 'shulv3';

            $userModel->password = md5('shulv3');

            $userModel->email = 'shulv3@qq.com';

            $userModel->num = 103;

     

            $userModel->save();

     

            dump($userModel->id);

        }

    }

    •  

     

    当然我们还可以使用一种简单的方法,就是直接给save()传递一个数组,数组的元素为插入的值,就像create()方法传递参数那样。不一样的地方是,但遇见插入的字段,表中不存在的时候,它的处理方法是调用一个allowField()方法

    $userModel = new User;

            $res = $userModel

            ->allowField(true)

            ->save([//allowField('true')也可以传递一个数组,元素为允许插入的字段名

                'username' => 'shulv4',

                'password' => md5('shulv5'),

                'email'    => 'shulv@qq.com',

                'demo'     => 123

            ]);//返回值是插入的条数

     

            dump($res);

    •  

     

    那么当我们想要添加多条记录时,我们可以使用saveAll()方法,参数为一个二维数组

    public function index()

        {

            $userModel = new User;

            $res = $userModel->saveAll([

                ['email' => 'shulv4@qq.com'],

                ['email' => 'shulv5@qq.com']

            ]);//我这里只插入了email

     

            foreach($res as $value){

                dump($value->id);

                //dump($value->toArray());

            }

        }

    •  
    •  

    一、使用模型更新数据 

    如果我们想更新数据,我们在前边说Db类的时候我们知道,我们需要一些where条件,我直接用代码演示:

    public function index()

        {

           $res = User::update([//通过Model的update()方法,传递一个数组进行数据更新

                'username'  => '3404767031'

           ], ['id'=>80]);//表示更新id=80的这条记录的username

           dump($res);

        }

    第二个参数,还可以支持一个闭包函数,和之前说的一样:

     public function index()

        {

           $res = User::update([//通过Model的update()方法,传递一个数组进行数据更新

                'username'  => 'test'

           ], function($query){

                $query->where("id", "<", 85);

           });//表示更新id<85的这几条记录的username

           dump($res);

           //当然可以直接通过我们之前说的那种,链式操作的方式来构造where条件:User::where()->update();

    •  

     

    其实,我们还有一种更新数据的方法,那就是,现获取到某条记录,然后再对记录中的字段进行修改:

    $userModel = User::get(80);

            $userModel->username = 'shulv_80';

            $res = $userModel->save();

           dump($res);

    •  

    我们还可以通过saveAll()的方法进行批量更新数据

    $userModel = new User;

            $res = $userModel->saveAll([

                ['id'=>88, 'username' => 'hhhhhh'],

                ['id'=>89, 'username' => 'tttttt']

            ]);

           dump($res);

    •  

    二、使用模型删除数据

    //Model类为我们提供了destory()静态方法来删除数据

            $res = User::destroy(79);//如果表中存在主键,我们可以直接传递主键进行删除 

            dump($res); 

    •  

     

    //Model类为我们提供了destory()静态方法来删除数据

            // $res = User::destroy(79);//如果表中存在主键,我们可以直接传递主键进行删除 

            // dump($res);  

            $res = User::destroy(['id'=>80]);//也可以通过传递数组的方式

     

            $res = User::destroy(function($query){

                $query->where("id", "<", 85);

            });//还可以通过闭包函数的方式

     

            //通过先获取到执行的记录,然后进行删除

            $userModel = User::get(90);

            $res = $userModel->delete();

     

            //添加where条件进行删除

            $res = User::where("id", "=", 91)->delete();//返回值是删除的记录数

            //删除所有数据  $res = User::where("1=1")->delete();

            dump($res);

    •  

    三、模型聚合操作 

    在thinkphp的model中为我们提供了很方便获取平均值、最大值、最小值、数据条数的方法。下边就用代码演示这些函数的用法:

     $res1 = User::count();//获取总记录数

            dump($res1);

            $res2 = User::where("id", ">", 90)//获取id>90的记录数

                 ->count();

            dump($res2);

     

            $res3 = User::max('num');//获取num字段中的最大值

            dump($res3);

     

            $res4 = User::where("id", ">", 90)//获取id>90的记录中num值最大的那个记录

                 ->max('num');

            dump($res4);

     

            //其余的还有sum(),avg()等方法的使用都是这样,就不一一写了

    •  

     

    四、模型获取器 

    在我们的实际应用中,我们经常会存在这样的场景,比如说我们存用户的性别,我们可能在数据库中只使用0,1,20或1,2,3的方式来存用户的性别。0:男1:女2:未知。我们在数据库中存的是0,1,2而我们在页面中展示的是男女和未知,那么在获取这个数据的过程中,我们就使用获取器,可以自动的将我们的数据转化成我们想要的显示格式

    app/index/model/User.php

    <?php

    namespace appindexmodel;

    use thinkModel;

     

    class User extends Model{

        public function getSexAttr($val){//注意这个方法名的写法是固定的

            //dump($val);//我们在这里先直接打印这个$val,可以看到输出的是int(0),也就是说我们能直接获取到我们当前获取的数据的value值,那么我们就可以对其进行判断

            switch ($val) {

                case '1':

                    return "男";

                    break;

                case '2':

                    return "女";

                    break;

                default:

                    return "未知";

                    break;

            }

        }//写完这个函数之后,刚才输出的0,现在就会输出  未知

    •  

    app/index/controller/Index.php

     

    <?php

    namespace appindexcontroller;

     

    use thinkController;

    use appindexmodelUser;//使用我们刚刚新建的那个模型

    //use thinkLoader;//通过引入think下的Loader类

    class Index extends Controller

    {

        public function index()

        {

           //首先我们先看一下怎么常规的获取到一条记录的sex字段值

           $res = User::get(80);

           echo $res->sex;

           //那么现在我们如果想让0:未知 1:男 2:女    那么这个时候我们需要在模型中编写一个函数

     

           dump($res->toArray());//此时会打印出id=80的这条记录,我们会发现sex显示的是 未知

           //那么,如果我们想获取到原始数据,可以使用getData()

           dump($res->getData());

        }

    •  

    一、模型修改器+自动完成 

    将这两个放在一起学习,是因为这两个有很多的相似之处,下边看一下修改器

    控制器Index.php

    public function index()

        {

           //首先我们向数据库中添加一条数据

            $res = User::create([

                'username'  => 'liangyu',

                'password'  => 'liangyu',//注意,我这里没有对其加密,后边我会让它自动完成修改,也就是要说的修改器

                'email'     => 'liangyu@qq.com',

                'num'       => 520

            ]);

            dump($res->id);

        //密码没有加密,那么我们如何通过修改器让它进行自动的修改,这个时候就需要在模型中编写代码

        }

    •  

    模型User.php

    public function setPasswordAttr($val){

            return md5($val);//定义了这个方法之后,它会自动传递password给$val

        //这个时候,当我们再进行数据插入的时候,它就会对密码自动的进行加密

        }

        //当然我们还可以传递第二个参数$data,它接收的是,我们插入的这条数据的所有元素(之前说的那个自动将0在输出的时候打印为“未知”,那个getSexAttr的方法,也可以传递第二个参数$data,表示的含义是一样的)

        public function setPasswordAttr($val, $data){

            return $val . $data['email'];//这个就表示,将密码+email整体当做最终密码,当然还可以对整体进行加密,这样更安全

            //return md5($val . $data['email']);

        }

    •  

     

    然后我们说一下自动完成:

    控制器Index.php

     public function index()

        {

           //首先我们向数据库中添加一条数据

            $res = User::create([

                'username'  => 'liangyu',

                'password'  => 'liangyu',

                'email'     => 'liangyu@qq.com',

                'num'       => 520

            ]);

            dump($res->id);

        }

    •  

    模型User.php

    //如果想使用自动完成,那么就需要在模型中声明

        protected $auto = [//数组中的内容,就是我们要自动的字段

            'time'

        ];//这个$auto是在我们进行数据添加和更新的时候都会发生变化,都会发生的操作。它的方法和我们的修改器是一样的

        public function setTimeAttr(){//首先,我们修改一下自己的数据库,在我们的数据库中添加一个time字段

            return time();

        }//这个时候,刷新数据库,新添加的这条数据就有了time()

    •  

     

    控制器:Index.php

    public function index()

        {

           //首先我们向数据库中添加一条数据

            $res = User::create([

                'username'  => 'liangyu',

                'password'  => 'liangyu',

                'email'     => 'liangyu@qq.com',

                'num'       => 520

            ]);

            // $userModel = new User;

            // $userModel->get(101);

            // $userModel->sex = 1;

            // $res = $userModel->save(); 

            dump($res->id);

        }

    •  

    模型User.php

    namespace appindexmodel;

    use thinkModel;

     

    class User extends Model{

    //如果想使用自动完成,那么就需要在模型中声明

        protected $auto = [//数组中的内容,就是我们要自动的字段

            'time'

        ];//这个$auto是在我们进行数据添加和更新的时候都会发生变化,都会发生的操作。它的方法和我们的修改器是一样的

     

    //另外,我们还可以声明一个$insert数组,这个数组,它只在数据插入的时候有效

        protected $insert = [

            'time_insert'

        ];

        //同样我们还可以添加$update数组,它是在数据更新的时候发生改变

        $protected $update = [//我们在数据库中首先使用之前学过的修改记录的值,进行修改,那么该修改器会被自动调用

            'time_update'

        ];

        public function setTimeAttr(){//首先,我们修改一下自己的数据库,在我们的数据库中添加一个time字段

            return time();

        }//这个时候,刷新数据库,新添加的这条数据就有了time()

        public function setTimeInsertAttr(){//这个时候,我们先去给我们的数据表添加一个time_insert字段

            return time();//插入时间

        }//这样我们再刷新一下我们的页面,机会看见数据表中新添的记录中有了time_insert值

        public function setTimeUpdateAttr(){

            return time();

        }

        //这种修改器函数的命名是set+字段名(驼峰命名法)+Attr()

    }

    •  

    二、模型时间戳+软删除 

    时间戳是做什么使用的呢? 

    比如说我们对数据进行新增或更新的操作时,我们往往需要在数据库中记录我们的插入时间和更改时间。通过前边的知识我们知道,我们可以使用自动完成的方式来实现这个功能,但是,我们大多数的数据库会有这样的字段,如果我们每一个都要这样去编写这样自动更新或自动完成的操作,那么我们的代码就会变得很臃肿,我们实现起来也不是很方便。所以thinkphp的model类,为我们提供了自动的时间戳功能,它会将我们数据的更新时间和创建时间记录到数据库中。 

    软删除 

    在我们对数据进行删除的操作,我们往往不会将这条数据真正的从数据库中删除,而是将它的某一个字段设置为一个特定的值,代表这个字段已经被删除,或者代表这条记录已经被删除。下边用代码演示一下:

    首先我会将之前的那个表删除掉,重新创建一个表,因为之前的表字段太多,模拟起来不方便(表名不变) 

    表结构 

     

    控制器:Index.php

    namespace appindexcontroller;

     

    use thinkController;

    use appindexmodelUser;//使用我们刚刚新建的那个模型

    //use thinkLoader;//通过引入think下的Loader类

    class Index extends Controller

    {

        public function index()

        {

    //第一种方式

    //如果我们想全局的开启添加时间和更新时间,时间戳的自动完成这个操作,那么我们可以修改配置文件(database.php中找到auto_timestamp,将它的值设置为true)

        //然后我们现在开始插入数据

            $res = User::create([

                'name'     =>  'shulv',

                'password' =>  md5('liangyu')

            ]);

            dump($res);//当我们刷新页面的时候就会发现,create_time和update_time字段已经有值了

        //但是,并不是所有的表都有新增时间和更新时间的字段,所以一般情况下不建议直接在配置文件中进行修改。因为它如果修改的话,如果你的一个表中不存在时间戳的字段,那么程序可能就会报错,所以我们还是将它设置为false

     

        //这个时候我们进入对应的模型(User.php)中添加一个属性$autoWriteTimestamp

     

    //我们再进行一下修改的操作

            $user = User::get(0);

            $user->name = 'liangyu';

            $res = $user->save();

            dump($res);//此时我们会发现数据库中id=0的这条记录的两个时间戳字段的值也发生了更新

     

    /*

    现在有一个问题就是,如果我们数据库中的两个时间戳字段名不是create_time和update_time,比如说我给它们改成create_at和update_at,那么此时我们再刷新的时候,他就会报错,说update_time和update_time不存在。因为我们在使用配置的时候,它的默认配置就是update_time,所以我们需要在model中继续申请一个属性

    */

        }

    }

    •  

    模型:User.php

    namespace appindexmodel;

    use thinkModel;

     

    class User extends Model{

        protected $autoWriteTimestamp = true;//利用这个属性来开启时间戳功能。这个时候我们再更新页面,那两个时间戳字段也会被添加进去

        protected $createTime = 'create_at';//这里直接写上我们的字段名

        protected $updateTime = 'update_at';//这个时候我们再刷新浏览器就不会报错了,时间也会被更新

    //当然我们还可以将$createTime或$updateTime设置为false,便是关闭该项,那么它会使用默认值(0),就不会去更新这个字段了

    }

    •  

    软删除

    控制器:Index.php

    namespace appindexcontroller;

     

    use thinkController;

    use appindexmodelUser;//使用我们刚刚新建的那个模型

    //use thinkLoader;//通过引入think下的Loader类

    class Index extends Controller

    {

        public function index()

        {

    //在说软删除的时候,我们先向数据库中添加一个delete_time字段(允许为null,null代表这条数据没有被删除)

    //如果我们想使用软删除,我们需要在模型中引入traitsmodelSoftDelete(去看模型User.php)

            //在模型中引入traitsmodelSoftDelete之后,就可以直接在控制器中进行删除了

            $res = User::destroy(0);

            dump($res);

    //这个时候我们在数据表中可以看见id=0的字段并没有被真正的删除,它的delete_time字段名变成了时间戳,说明这条数据在指定的时间点被删除(软删除)。这个时候当你尝试获取刚刚被软删除的记录时,返回的是null,也就是说不能再获取了。如果你确实需要获取到我们包含软删除的这些记录,那么我们就可以使用下边这样的方式

            $res = User::withTrashed(true)->find(0);//这个时候就能得到了

            dump($res);

            dump($res->getData());//可以获取原始数据

     

    //还有一种方式就是,比如说我们软删除的记录都放在了垃圾箱里,那么我们要获取这些被软删除的数据,就可以这样

            $res = User::onlyTrashed()->select();//返回的是数组,我们可以通过foreach遍历

            dump($res);

    //那么,如果我们想对数据进行恢复,可以直接使用update方法,将delete_time的值设置为null即可

    //当我们不想软删除这个字段名为delete_time时,我们还是使用更改create_time那种在model中声明变量的方式进行更改

     

    //那么如果我们真正的想删除某一个记录时应该怎么做呢?

            $res = User::destroy(0, true);//传递第二个参数为true即可

            dump($res);

    //还可以通过先获取,再删除的方式

            $user = User::get(0);

            $res = $user->delete(0, true);

            dump($res);

        }

    }

    •  

    模型:User.php

     

    namespace appindexmodel;

    use thinkModel;

    use traitsmodelSoftDelete;

    class User extends Model{

     

        use SoftDelete;

        protected $autoWriteTimestamp = true;//利用这个属性来开启时间戳功能。这个时候我们再更新页面,那两个时间戳字段也会被添加进去

        protected $createTime = 'create_at';//这里直接写上我们的字段名

        protected $updateTime = 'update_at';//这个时候我们再刷新浏览器就不会报错了,时间也会被更新

    //当然我们还可以将$createTime或$updateTime设置为false,便是关闭该项,那么它会使用默认值(0),就不会去更新这个字段了

        protected $updateTime = 'delete_at';

    }

    •  
  • 相关阅读:
    【AGC010E】Rearranging(博弈,图论,拓扑排序)
    【ARC074F】Lotus Leaves(最小割)
    【ARC069F】Flags(2-SAT,Tarjan,线段树优化建图)
    [CTS 2019] 氪金手游
    HDU
    LOJ
    LOJ
    [TJOI 2015] 概率论
    [AGC 018F] Two Trees
    LOJ
  • 原文地址:https://www.cnblogs.com/rxbook/p/9365646.html
Copyright © 2011-2022 走看看