TP5提供了強大的Model功能,跟隨這篇文章來一探究竟。
簡介
tp5的model只做業務層操作,不做具體的連結資料庫sql操作。
think\db\Connection.php做連結資料庫操作
think\db\Builder.php做建立sql操作
think\db\Query.php做資料CURD操作
功能清單
資料自動完成
自動寫入時間戳記
時間欄位自動格式化輸出欄位
欄位驗證器
自動關聯寫入
唯讀欄位
隱藏欄位
事件回調
虛刪除
類型轉換
功能詳情
1. 資料自動完成
//設定自動完成的欄位,支援索引值對數組和索引數組 //新增和更新時都會使用 //如:['name'=>'zhangsan','sex'=>'男'] // ['name','sex'] protected $auto = []; //新增 自動完成列表 //只在新增資料的時候使用 protected $insert = []; //更新 自動完成列表 //只在更新資料的時候使用 protected $update = []; //用來標記當前操作被修改的欄位 //如 ['name','sex'] protected $change = []; //依賴方法,model類會自動調用解析auto數組 //我們只需配置auto數組即可 protected function autoCompleteData($auto = []){}
在model中設定完auto欄位後在更新或新增的時候首先會判斷auto中設定的欄位是否存在於被更新的欄位($this->change)中
如果存在則不用auto裡設定的欄位和值
如果不存在則將auto裡設定的欄位和值添加到this−>data中並把該欄位新增到this->change中。
如果auto是索引數組,也就是只設定了欄位名,沒有設定子欄位值,這是就會根據欄位名去$this->data中查詢該欄位值,並添加的到要更新的屬性數組中去。
新增資料的方法是create, 修改資料的方法是update,批量新增和修改的方法是saveAll,這幾個方法的最終實現都是調用的save方法
saveAll方法批量新增和修改,並不是組合sql語句,而是開啟事務,然後調用save方法,一條一條添加和修改,最後提交事務。
在更新操作中,model會自動檢查data的所有欄位的值是否被更改,只會跟新被更改過得欄位的值。沒被更改的則被忽略。
insert、update的功能和auto的功能類似,只不過auto是不管是新增資料和是更新資料都會使用,而insert值針對新增,update只針對更新。如果設定了相同的屬性,insert和update的則會覆蓋auto中的欄位。
2. 自動寫入時間戳記
//是否需要自動寫入時間戳記 //可以是字串類型和boolean類型 //字串類型代表要寫入的時間格式 //如: 'Y-m-d H:i:s' //boolean類型就是true和false,代表是否開啟 //預設時間格式為int類型 protected $autoWriteTimestamp; //預設自動寫入的欄位有 //建立時間和更新時間,他們對應的欄位名分別是 //create_time,和update_time //也可以在model裡自己設定。 protected $createTime = 'create_time'; protected $updateTime = 'update_time';
配置方式
該配置TP5預設為false,需要手動開啟
在資料庫配置(database.php)中添加全域配置。
'auto_timestamp' => true //或者設定時間格式 // 'auto_timestamp' => 'datatime'
在單獨的模型類裡設定
protected $autoWriteTimestamp = true; //或者設定時間格式 // protected $autoWriteTimestamp = 'datatime';
知識的欄位類型 timestamp/datetime/int
如果自己的資料欄位不是預設值得話,可以在自己的model裡修改。
//如: protected $createTime = 'my_create_time_filed'; protected $updateTime = 'my_careate_time_field';
如果只需要createTime而不需要updateTIme,則可以在model中關閉updateTIme
//如 protected $updateTime = false;123
在model中開啟和關閉只針對單獨的model起作用,想要全域起作用還是要在設定檔裡配置。
3. 時間欄位自動格式化輸出
//輸出格式 protected $dateFormat;123
配置方式
該配置TP5模式輸出格式為 ‘Y-m-d H:i:s’
可以自己在資料庫設定檔(database.php)中配置。如
'datetime_format' => 'Y/m/d H:i',12
也可以在model中設定
protected $dateFormat = 'Y/m/d H:i';12
4. 欄位驗證器
//欄位驗證規則 protected $validate = []; //是否採用批量驗證 protected $batchValidate = false; /** * 設定欄位驗證 * @access public * @param array|string|bool $rule 驗證規則 true表示自動讀取驗證器類 * @param array $msg 提示資訊 * @param bool $batch 批量驗證 * @return $this */ public function validate($rule = ture,$msg=[],$bath=false){} /** * 自動驗證資料 * @access protected * @param array $data 驗證資料 * @param mixed $rule 驗證規則 * @param bool $batch 批量驗證 * @return bool */ public function validateData($data,$rule=null,$batch=null){}
使用方式
在model中配置欄位驗證規則,在整個model中新增和更新操作都通用。
// 優點:只需要設定一次,即可通用
// 缺點:無法針對化設定
//比如:新增使用者和編輯使用者功能,
//新增是密碼為必填項,編輯時密碼就是選填項了
//所以就不能再model裡設定密碼的驗證規則了,
這個時候就只能在新增的action裡為密碼做驗證了。
protected $validate = [ 'rule' => [ 'name' => 'require', //多個規則可以是用字串用|分隔 //也可以使用數組['require','number','min'=>10,'max'=>80] //使用字串配置要被使用explode('|',$rule)轉化成數組,所以使用數組配置效率更高 'age' => 'require|number|min:10|max:80', 'height' => 'between:100,200' ], 'msg' => [ 'name' => 'name不可為空', 'age.require' => 'age不能沒空', 'age.number' => 'age必須是一個數字', 'age.min' => 'age最小為10', 'age.max' => 'age最大為80', 'height' => 'height只能在100到200之間' ] ];
在具體操作時調用think\Validate類來實現
//在類的頭部,因為Validate檔案。 use think\Validate; $validate = new Validate([ 'name' => 'require', 'age' => 'require|number|min:10|max:80' ],[ 'name' => 'name不可為空', 'age.require' => 'age不能沒空', 'age.number' => 'age必須是一個數字', 'age.min' => 'age最小為10', 'age.max' => 'age最大為80', ]); //使用check檢查資料 if($validate->check($data)){ echo '資料格式符合要求'; }else{ //比如:name不可為空 echo $validate->getError(); }
對比
使用第一種方法在model裡設定驗證規則,雖然說結構看著比較合理,但是這種方法靈活性比較低,因為他是在save的時候去判斷的,如果save失敗,你不清楚是資料驗證失敗,還是說插入到資料失敗。所以對於做提示驗證很麻煩(因為資料驗證的提示我們是直接返回給使用者的,而資料庫操作的提示一般我們是不返回給使用者的,所以得到結果後還要做判斷,先對比較麻煩)。
使用第二種方法在action裡定義一個_validate的函數,專門用來做資料校正,這中方法比較靈活,而且他是在在儲存資料之前做的校正,所以返回結果分的比較清楚,對使用者的提示也比較清晰,代碼可讀性也比較好。
5. 自動關聯寫入
// 關聯對象 protected $relation; // 關聯自動寫入(關聯的屬性名稱) protectd $relationWrite = [];
暫時沒有使用,後續再繼續不補充。
6. 唯讀欄位
//用來保護那些不許要被更新的欄位。 //比如,建立時間 //設定後再更新資料時,會欄位過濾掉create_time欄位 //避免更新到資料庫。 protected $readonly = ['create_time'];
7. 隱藏欄位
//設定要隱藏的欄位, //該設定只在toArray(),和subToArray()方法中起作用 protected $hidden = []; //相關方法 public function hidden($hidden=[],$override=false){ }
當使用toArray和subToArray獲得數組資料時,使用hidden欄位和hidden函數可以隱藏數組中的元素。如:
//user表的屬性欄位(類比操作) user_field = ['name','sex','age','height'];
在User模型中設定$hidden欄位
protected $hidden = ['age','height']; dump($User->toArray()); //只有name和sex欄位。 //也可以調用hidden方法隱藏欄位 //會有 name,age,height 三個欄位 dump($User->hidde(['sex'])->toArray()); //只有name欄位了 //第二個參數標識是否合并 $this->hidden dump($user->hidden(['sex'],true)->toArray());
8. 事件回調
支援的回調事件
before_insert 新增前
after_insert 新增後
before_update 更新前
after_update 更新後
before_write 寫入前(新增和更新都會調用)
after_write 寫入後(新增和更新都會調用)
before_delete 刪除前
after_delete 刪除後
註冊的回調方法支援傳入一個參數,當前樣本模型對象,並且before_write,before_insert,before_update,before_delete返回false會結束執行。
使用方法
控制器裡使用
//支援給一個位置註冊多個事件 User::event('before_insert',function($user){ if($user->status != 1){ return false; } }); //這個也會生效,回到函數為beforeInsert User::event('before_insert','beforeInsert');
模型裡使用
//使用init方法統一註冊模型事件 class User extends Model{ protected static function init(){ User::event('before_insert',function($user){ if($user->status != 1){ return false; } } //註冊第二個事件 User::event('before_insert','beforeInsert'); } }
原理
model類裡有一個protected static $event = [];屬性,註冊的時間都存放在這個屬性中。比如:
$event = [ //模型名稱 'user' => [ //事件名稱 'before_insert' => ['callback_funciton','beforeInsert'], 'after_insert' => ['callback_function','afterInsert'], 'before_delete' => ['beforeDelete'] ] ]
註冊事件時,把所有的事件都儲存在$event中了,然後在insert,update,delete等相應的位置調用即可。
9. 虛刪除
簡介
在實際項目中,對資料頻繁的使用刪除操作可能會導致效能問題,虛刪除的作用就是給資料加上刪除標記,而不是真正的刪除,同時也便於需要的時候恢複資料。
設定方式
使用虛刪除功能需要引用SoftDelete trait;如:
namespace app\index\model; use think\Model; use think\model\SoftDelete; class User extends Model{ // 使用SoftDelete // trait 的使用方式 // 使用trait跟類的繼承相似 use SoftDelete; //虛刪除標記的欄位名 protected $deleteTime = 'delete_time'; }
dateteTIme屬性用於標記資料表裡的虛刪除欄位,TP5裡的虛刪除使用的是int類型,預設值為null(這個很重要,因為查詢的時候是用delete_time is not null 來查詢的),用於記錄刪除時間。
可以用類型轉換指定虛刪除的欄位類型,建議資料表裡的所有時間欄位使用同一種資料類型。
使用方式
在model中設定好後,就可以直接使用了
//虛刪除 User::destory(1); //真刪除 User::destory(1,true); //虛刪除 $user = User::get(1); $user->delete(); //真刪除 $user->delete(true);
預設情況下,查詢出來的資料是不包括虛刪除的資料的,如果想要查詢包括虛刪除的資料,可以使用下面的方式。
User::withTrashed()->find(); User::withTrashed()->select();
如果僅需要查詢虛刪除的資料,可以這樣:
User::onlyTranshed()->find(); User::onlyTranshed()->select();
10. 類型轉換
TP5支援給資料表中的欄位設定類型,並會在讀取和寫入的時候自動轉換。如:
class User extends Model{ protected $type = [ 'status' => 'integer', 'score' => 'float', 'login_timme' => 'datetime', 'info' => 'array' ]; }
使用樣本
$user = new User; $user->status = '1'; $user->score = '90.50'; $user->birthday = '2015/5/1'; $user->info = ['a'=>1,'b'=>2]; $user->save(); var_dump($user->status); // int 1 var_dump($user->score); // float 90.5; var_dump($user->birthday); // string '2015-05-01 00:00:00' var_dump($user->info);// array (size=2) 'a' => int 1 'b' => int 2
注意: 如果制定為時間戳記類型(timestamp)的話,該欄位會在寫入的時候自動調用strtotime函數產生對應的時間戳記,輸出是自動使用dateFormat格式化時間戳記,預設格式為Y:m:d H:i:s,如果想要改變輸出格式,可以如下:
class User extends Model{ protected $dataFormat = 'Y/m/d'; protected $type = [ 'status' => 'integer', 'score' => 'float', 'birthday' => 'timestemp'//時間戳記格式 ]; }
或者如下:
class User extends Model{ protected $type = [ 'status' => 'integer', 'socre' => 'float', 'birthday' => 'timestemp:Y/m/d'//寫入時間戳記,讀取按照Y/m/d的格式來格式化輸出。 ]; }
相關閱讀:
最詳細的ThinkPHP5自訂分頁類教程
thinkphp執行原生SQL語句的實現方法.
thinkphp5實現分頁功能的方法介紹