《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 app\index\controller;

 

use think\Controller;

use app\index\model\User;//使用我們剛剛新建的那個模型

 

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模型之后,就可以直接使用靜態方法,這是為什么呢? 

因為在我們的模型文件中的類都繼承了think\Model這個類,think\Model中其實有這樣的方法,這些方法,后邊會說到。同樣我們還可以在控制器中使用new的方式

$user = new User();

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

        $res = $res->toArray();

        dump($res);

  •  

當我們,不想通過use的方式將User模型引入進來的時候,我們還可以通過下邊的方法:

namespace app\index\controller;

 

use think\Controller;

//use app\index\model\User;//使用我們剛剛新建的那個模型

use think\Loader;//通過引入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 app\index\controller;

 

use think\Controller;

use app\index\model\User;//使用我們剛剛新建的那個模型

//use think\Loader;//通過引入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 app\index\controller;

 

use think\Controller;

use app\index\model\User;//使用我們剛剛新建的那個模型

//use think\Loader;//通過引入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 app\index\controller;

 

use think\Controller;

use app\index\model\User;//使用我們剛剛新建的那個模型

//use think\Loader;//通過引入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 app\index\controller;

 

use think\Controller;

use app\index\model\User;//使用我們剛剛新建的那個模型

//use think\Loader;//通過引入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 app\index\controller;

 

use think\Controller;

use app\index\model\User;//使用我們剛剛新建的那個模型

//use think\Loader;//通過引入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 app\index\model;

use think\Model;

 

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 app\index\controller;

 

use think\Controller;

use app\index\model\User;//使用我們剛剛新建的那個模型

//use think\Loader;//通過引入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 app\index\model;

use think\Model;

 

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 app\index\controller;

 

use think\Controller;

use app\index\model\User;//使用我們剛剛新建的那個模型

//use think\Loader;//通過引入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 app\index\model;

use think\Model;

 

class User extends Model{

    protected $autoWriteTimestamp = true;//利用這個屬性來開啟時間戳功能。這個時候我們再更新頁面,那兩個時間戳字段也會被添加進去

    protected $createTime = 'create_at';//這里直接寫上我們的字段名

    protected $updateTime = 'update_at';//這個時候我們再刷新瀏覽器就不會報錯了,時間也會被更新

//當然我們還可以將$createTime或$updateTime設置為false,便是關閉該項,那么它會使用默認值(0),就不會去更新這個字段了

}

  •  

軟刪除

控制器:Index.php

namespace app\index\controller;

 

use think\Controller;

use app\index\model\User;//使用我們剛剛新建的那個模型

//use think\Loader;//通過引入think下的Loader類

class Index extends Controller

{

    public function index()

    {

//在說軟刪除的時候,我們先向數據庫中添加一個delete_time字段(允許為null,null代表這條數據沒有被刪除)

//如果我們想使用軟刪除,我們需要在模型中引入traits\modelSoftDelete(去看模型User.php)

        //在模型中引入traits\modelSoftDelete之后,就可以直接在控制器中進行刪除了

        $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 app\index\model;

use think\Model;

use traits\modelSoftDelete;

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';

}

  •  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM