ThinkPHP模型詳解
模型定義,默認(rèn)情況下,ThinkPHP的模型類(lèi)是位于/Home/Model/目錄之下,模型類(lèi)通常需要繼承系統(tǒng)的\Think\Model類(lèi)或其子類(lèi),下面是一個(gè)Home\Model\UserModel類(lèi)的定義:
文件命名遵守UserModel.class.php的方式,跟控制器的命名一樣
<?php namespace Home\Model; use Think\Model; class UserModel extends Model { }
模型類(lèi)的作用大多數(shù)情況是操作數(shù)據(jù)表的,如果按照系統(tǒng)的規(guī)范來(lái)命名模型類(lèi)的話(huà),大多數(shù)情況下是可以自動(dòng)對(duì)應(yīng)數(shù)據(jù)表,但你可以根據(jù)自己的需求來(lái)定制自己的數(shù)據(jù)表設(shè)置和操作。
首先我們需要在配置文件設(shè)置我們的數(shù)據(jù)庫(kù)連接信息:
'DB_TYPE' => 'mysql', 'DB_HOST' => 'localhost', 'DB_NAME' => 'database', 'DB_USER' => 'username', 'DB_PWD' => 'password', 'DB_PORT' => '3306',
這些配置信息還是在/Home/Conf/config.php文件里設(shè)置。
指定數(shù)據(jù)表前綴
指定標(biāo)前綴,我們?cè)诘谝徽n的配置項(xiàng)已經(jīng)指定,以下的文字表示你可以靈活配置你的數(shù)據(jù)表。
protected $tablePrefix = 'top_';
如果數(shù)據(jù)庫(kù)的表沒(méi)有表前綴,使用空字符串代替
protected $tablePrefix = '';
指定數(shù)據(jù)表,此處的指定的數(shù)據(jù)表的不需要添加表前綴:
protected $tableName = 'user';
舉個(gè)例子說(shuō),比如說(shuō)你的數(shù)據(jù)庫(kù)中有一個(gè)沒(méi)有表前綴的,名為users的數(shù)據(jù)表,可以用以下的兩種方法在模型中進(jìn)行下面的定義:
第一,直接根據(jù)系統(tǒng)的規(guī)范來(lái)命名模型類(lèi)來(lái)命名模型,比如說(shuō)就命名為UsersModel那么只需要在這個(gè)類(lèi)里面加上下面的設(shè)置就可以了:
protected $tablePrefix = '';
ThinkPHP系統(tǒng)就會(huì)自動(dòng)定位到users表了。
第二種情況時(shí),如果你的模型類(lèi)沒(méi)有按照系統(tǒng)規(guī)范來(lái)命名,比如說(shuō)不小心命名為UserModel,這種情況下可以同時(shí)指定表前綴和表明,比如:
protected $tablePrefix = ''; protected $tableName = 'users';
或者你直接指定trueTableName:
protected $trueTableName = 'users';
既然模型通常是用來(lái)操作數(shù)據(jù)表,那么我們來(lái)看看模型的基本CURD:
注:為了方便演示,我們?cè)赨serController中定義一個(gè)testDemo()方法用于演示
public function testDemo() { }
以下的代碼將會(huì)一段一段在這個(gè)方法里演示,你可以通過(guò)訪(fǎng)問(wèn)http://localhost:8999/index.php/Home/User/testDemo來(lái)看到實(shí)際效果。
添加紀(jì)錄
$user = M('User'); $data['username'] = 'ThinkPHP'; $data['email'] = 'ThinkPHP@gmail.com'; $user->create($data); $record = $user->add(); dump($record);
add()返回的是插入數(shù)據(jù)的id,對(duì)于不存在的表字段,add()方法會(huì)自動(dòng)過(guò)濾。
讀取紀(jì)錄
在ThinkPHP中讀取數(shù)據(jù)的方式很多,通常分為讀取數(shù)據(jù)、讀取數(shù)據(jù)集和讀取字段值
$user = M('User'); $record = $user->where('username="ThinkPHP"')->find(); dump($record);
讀取字段值
$user = M('User'); $record = $user->where('id=3')->getField('username'); dump($record);
默認(rèn)情況下,當(dāng)只有一個(gè)字段的時(shí)候,返回滿(mǎn)足條件的數(shù)據(jù)表中的該字段的第一行的值.如果getField()傳入多個(gè)字段,返回值將是一個(gè)關(guān)聯(lián)數(shù)組:
$user = M('User'); $record = $user->getField('username,email'); dump($record);
這個(gè)數(shù)組總是以傳入的第一個(gè)第一個(gè)字段為鍵值的。如果修改為:
$user = M('User'); $record = $user->getField('email,username'); dump($record);
將上面的兩次代碼分別放到testDemo(),你就會(huì)看到不一樣的結(jié)果集。
用save()方法更新數(shù)據(jù)
$user = M('User'); $data['username'] = 'ThinkPHPSave'; $data['email'] = 'ThinkPHPSave@outlook.com'; $record = $user->where('id=3')->save($data); dump($record);
這里的$record返回的事1,表示成功更改。
當(dāng)然,你也可以這樣:
$user = M('User'); $user->username = 'ThinkPHP'; $user->email = 'ThinkPHP@outlook.com'; $record = $user->where('id=3')->save(); dump($record);
日常開(kāi)發(fā)的時(shí)候經(jīng)常會(huì)遇到一些只更新某些字段的情況,可以通過(guò)下面的方式來(lái)實(shí)現(xiàn):
$user = M("User"); $record = $user->where('id=4')->setField('username','ThinkPHPChangeName'); dump($record);
同時(shí)更新多個(gè)字段,可以將數(shù)據(jù)以數(shù)組的形式傳給setField()方法:
$user = M('User'); $data = array('username'=>'ThinkPHPChangeArray','email'=>'ThinkPHP@array.com'); $record = $user-> where('id=6')->setField($data); dump($record);
ThinkPHP刪除數(shù)據(jù)使用delete方法,例如:
$user = M('User'); $record = $user->where('id=3')->delete(); dump($record);
或者你可以直接使用:
$record = $user->delete('1,2,5'); dump($record);
這樣就達(dá)到了刪除主鍵1,2,5這三條紀(jì)錄了。
ActiveRecords
ThinkPHP實(shí)現(xiàn)了ActiveRecords模式的ORM模型,采用了非標(biāo)準(zhǔn)的ORM模型:表映射到類(lèi),記錄映射到對(duì)象。以下實(shí)例將使用ActiveRecords重現(xiàn)對(duì)數(shù)據(jù)表的CURD,看看ActiveRecords給我們帶來(lái)了什么好處。
$user = M("User"); $user->username = 'ThinkPHPWithActive'; $user->email = 'ThinkPHPActive@gmail.com'; $record = $user->add(); dump($record);
讀取紀(jì)錄
AR最大的特點(diǎn)可能就是它的查詢(xún)模式了,模式簡(jiǎn)單易用,因?yàn)楦嗲闆r下面查詢(xún)條件都是以主鍵或者某個(gè)關(guān)鍵的字段。這種類(lèi)型的查詢(xún),ThinkPHP有著很好的支持。
比如說(shuō)獲取主鍵為2的用戶(hù)信息:
$user = M("User"); $record = $user->find(2); dump($record);
直接不用where()查詢(xún)了,簡(jiǎn)單友好吧。再比如:
$user = M("User"); $record = $user->getByUsername("jelly"); dump($record);
如果是查詢(xún)多條紀(jì)錄,使用以下方式:
$user = M("User"); $record = $user->select('1,3,8'); dump($record);
更新記錄
$user = M("User"); $user->find(21); $user->username = 'TOPThinkChangeWithAR'; $record = $user->save(); dump($record);
刪除記錄
刪除單條紀(jì)錄
$user = M("User"); $record = $user->delete(8); dump($record);
刪除多條紀(jì)錄
$user = M("User"); $record = $user->delete('15,16'); dump($record); // todo: 這里的自動(dòng)驗(yàn)證和關(guān)聯(lián)模型 調(diào)試不出來(lái)。
自動(dòng)完成
自動(dòng)完成是ThinkPHP提供用來(lái)完成數(shù)據(jù)自動(dòng)處理和過(guò)濾的方法,當(dāng)使用create()方法創(chuàng)建數(shù)據(jù)對(duì)象的時(shí)候會(huì)觸發(fā)自動(dòng)完成數(shù)機(jī)制。
因此,在ThinkPHP鼓勵(lì)使用create()方法來(lái)創(chuàng)建數(shù)據(jù)對(duì)象,因?yàn)檫@是一種更加安全的方式,直接通過(guò)add()或者save()方法實(shí)現(xiàn)數(shù)據(jù)寫(xiě)入無(wú)法出發(fā)自動(dòng)完成機(jī)制。
自動(dòng)完成通常用來(lái)完成默認(rèn)字段寫(xiě)入(比如添加時(shí)間戳),安全字段過(guò)濾(比如加密密碼)以及業(yè)務(wù)邏輯的自動(dòng)處理等??梢酝ㄟ^(guò)模型類(lèi)里面通過(guò)$_auto屬性定義處理規(guī)則。下面演示如何自動(dòng)完成添加時(shí)間戳:
在UserModel中,聲明自動(dòng)完成的定義數(shù)組$_auto :
protected $_auto = array ( array('created_at','date("Y-m-d H:i:s", time())',3,'function'), array('updated_at','date("Y-m-d H:i:s", time())',3,'function'), );
還有一種是理由auto()方法動(dòng)態(tài)設(shè)置自動(dòng)完成的機(jī)制,可以到官方文檔去看看
設(shè)置完成之后,我們?cè)趖estDemo()方法中創(chuàng)建一條用戶(hù)數(shù)據(jù):
$user = D('User'); $data['username'] = "ThinkPHP"; $data['email'] = "ThinkPHP@gmail.com"; $user->create($data); $record = $user->add(); dump($record);
測(cè)試,如果返回紀(jì)錄的id值,說(shuō)明用戶(hù)紀(jì)錄創(chuàng)建成功。要驗(yàn)證數(shù)據(jù)是否自動(dòng)完成,你可以直接使用:
$user = D('User'); $record = $user->find(id); dump($record);
自動(dòng)驗(yàn)證
自動(dòng)驗(yàn)證是ThinkPHP模型層提供的一種數(shù)據(jù)驗(yàn)證方法,可以在使用create()創(chuàng)建數(shù)據(jù)對(duì)象的時(shí)候自動(dòng)進(jìn)行數(shù)據(jù)驗(yàn)證。
數(shù)據(jù)驗(yàn)證可以進(jìn)行數(shù)據(jù)類(lèi)型、業(yè)務(wù)規(guī)則、安全判斷等方面的驗(yàn)證操作。
通常用于表單驗(yàn)證
數(shù)據(jù)驗(yàn)證有兩種方式:
靜態(tài)方式:在模型類(lèi)里面通過(guò)$_validate屬性定義驗(yàn)證規(guī)則。
動(dòng)態(tài)方式:使用模型類(lèi)的validate()方法動(dòng)態(tài)創(chuàng)建自動(dòng)驗(yàn)證規(guī)則。
無(wú)論是什么方式,驗(yàn)證規(guī)則的定義是統(tǒng)一的規(guī)則,定義格式為:
array(
array(驗(yàn)證字段1,驗(yàn)證規(guī)則,錯(cuò)誤提示,[驗(yàn)證條件,附加規(guī)則,驗(yàn)證時(shí)間]),
array(驗(yàn)證字段2,驗(yàn)證規(guī)則,錯(cuò)誤提示,[驗(yàn)證條件,附加規(guī)則,驗(yàn)證時(shí)間]),
......
);
下面以$_validate靜態(tài)方式舉例如何使用自動(dòng)驗(yàn)證:
在UserController中創(chuàng)建register()方法,對(duì),幾乎每一個(gè)Web應(yīng)用都需要實(shí)現(xiàn)用戶(hù)注冊(cè)這一步。
public function register() { $this->display(); }
對(duì),就是這么簡(jiǎn)單,這個(gè)方法只是將相應(yīng)的視圖文件渲染出來(lái)。所以接下來(lái)我們創(chuàng)建對(duì)應(yīng)的視圖文件,也就是:./Application/Home/View/User/register.html
<extend name="Index/base" /> <block name="main" > <form method="post" action="__URL__/registerValidate"> <div class="form-group"> <label for="exampleInputName">Name</label> <input type="text" name="username" class="form-control" id="exampleInputName" placeholder="Name"> </div> <div class="form-group"> <label for="exampleInputEmail">Email</label> <input type="email" name="email" class="form-control" id="exampleInputEmail" placeholder="Email"> </div> <button type="submit" class="btn btn-default">Submit</button> </form> </block>
上面就是一些HTML代碼和一點(diǎn)模板的知識(shí),對(duì)于模板,我們后續(xù)會(huì)講到,但不管怎樣,現(xiàn)在我們?cè)L問(wèn)
http://localhost:8999/Home/User/register,就可以看到我們的注冊(cè)表單頁(yè)面了。
注意到form表單中,action="__URL__/registerValidate",這表示提交到當(dāng)前的控制器的registerValidate()方法處理,所以我們?cè)赨serController中增加registerValidate()方法:
public function registerValidate() { $data['username'] = $_POST['username']; $data['email'] = $_POST['email']; $user = D("User"); if ( !$user->create($data) ) { exit($user->getError()); } //todo: validation passes, add data to database and redirect somewhere echo 'validation passes'; }
這里的if ( !$user->create($data) )會(huì)觸發(fā)自動(dòng)驗(yàn)證并判斷驗(yàn)證是否通過(guò)驗(yàn)證。你可以嘗試在表單里填寫(xiě)不同的數(shù)據(jù)來(lái)進(jìn)行測(cè)試,也可以修改一下驗(yàn)證規(guī)則,更多規(guī)則可以到官網(wǎng)查看:
http://document.thinkphp.cn/manual_3_2.html#auto_validate
關(guān)聯(lián)模型
通常我們所說(shuō)的關(guān)聯(lián)關(guān)系包括下面三種:
一對(duì)一關(guān)聯(lián) :ONE_TO_ONE,包括HAS_ONE 和 BELONGS_TO
一對(duì)多關(guān)聯(lián) :ONE_TO_MANY,包括HAS_MANY 和 BELONGS_TO
多對(duì)多關(guān)聯(lián) :MANY_TO_MANY
關(guān)聯(lián)定義
ThinkPHP可以很輕松的完成數(shù)據(jù)表的關(guān)聯(lián)CURD操作,目前支持的關(guān)聯(lián)關(guān)系包括下面四種:
HAS_ONE、BELONGS_TO、HAS_MANY和MANY_TO_MANY。
一個(gè)模型根據(jù)業(yè)務(wù)模型的復(fù)雜程度可以同時(shí)定義多個(gè)關(guān)聯(lián),不受限制,所有的關(guān)聯(lián)定義都統(tǒng)一在模型類(lèi)的 $_link 成員變量里面定義,并且可以支持動(dòng)態(tài)定義。要支持關(guān)聯(lián)操作,模型類(lèi)必須繼承Think\Model\RelationModel類(lèi),關(guān)聯(lián)定義的格式類(lèi)似于:
namespace Home\Model; use Think\Model\RelationModel; class UserModel extends RelationModel{ protected $_link = array( '關(guān)聯(lián)' => array( '關(guān)聯(lián)屬性1' => '定義', '關(guān)聯(lián)屬性N' => '定義', ), ); }
關(guān)于關(guān)聯(lián)屬性的定義和值,你可以到官方文檔仔細(xì)查看,我們下面也會(huì)給出一些最常用的。
在我們的講解例子中,會(huì)采用HAS_MANY和BELONGS_TO來(lái)演示,對(duì)于其他的幾個(gè)關(guān)系模型,可以參考官方文檔舉一反三。
首先我們知道數(shù)據(jù)庫(kù)里面有兩張表,用戶(hù)表和文章表,并且我們也為其創(chuàng)建了不同的模型(UserModel ArticelModel)。
現(xiàn)在我們仔細(xì)來(lái)想想他們之間的對(duì)應(yīng)關(guān)系:一個(gè)用戶(hù)可以擁有多篇文章,而每一篇文章都屬于某個(gè)特定的用戶(hù)。所以我們可以分別為這兩種關(guān)系添加關(guān)聯(lián)模型:
在UserModel中:
protected $_link = array( 'Article' => self::HAS_MANY );
在A(yíng)rticleModel中:
protected $_link = array( 'User' => self::BELONGS_TO );
以上者兩種都是最簡(jiǎn)潔的模型關(guān)聯(lián)聲明。因?yàn)樵谧铋_(kāi)始設(shè)計(jì)數(shù)據(jù)庫(kù)的時(shí)候,我們遵守了ThinkPHP的官方的規(guī)范:
外鍵的默認(rèn)規(guī)則是當(dāng)前數(shù)據(jù)對(duì)象名稱(chēng)_id,例如:UserModel對(duì)應(yīng)的可能是表think_user,那么think_user表的外鍵默認(rèn)為user_id,如果你的外鍵不是user_id,而是其他自定義的字段如:user_identify,那么就必須在定義關(guān)聯(lián)的時(shí)候定義 foreign_key 。如下:
在UserModel中:
protected $_link = array( 'mapping_type' => self::HAS_MANY, 'class_name' => 'Article', 'foreign_key' => 'user_identify', );
更多自定義的關(guān)聯(lián)模型參數(shù)可以到官網(wǎng)查看。
有了以上的定義之后,我們就可以在檢索用戶(hù)數(shù)據(jù)的同時(shí)將屬于他的文章也一起檢索出來(lái),使用relation()。
同樣是在testDemo()這個(gè)方法中:
$user = D('User'); $record = $user->relation(true)->find(4); dump($record);
訪(fǎng)問(wèn)熟悉的http://localhost:8999/Home/User/testDemo,你將會(huì)看到神奇的結(jié)果。
以上所述就是本文的全部?jī)?nèi)容了,希望大家能夠喜歡。
- Thinkphp5.0 框架使用模型Model添加、更新、刪除數(shù)據(jù)操作詳解
- Thinkphp5.0 框架Model模型簡(jiǎn)單用法分析
- ThinkPHP5&5.1框架關(guān)聯(lián)模型分頁(yè)操作示例
- ThinkPHP關(guān)聯(lián)模型操作實(shí)例分析
- ThinkPHP實(shí)例化模型的四種方法概述
- thinkPHP模型初始化實(shí)例分析
- 淺談thinkphp的實(shí)例化模型
- thinkphp利用模型通用數(shù)據(jù)編輯添加和刪除的實(shí)例代碼
- thinkphp3.x自定義Action、Model及View的簡(jiǎn)單實(shí)現(xiàn)方法
- ThinkPHP中實(shí)例Model方法的區(qū)別說(shuō)明
- Thinkphp5.0框架使用模型Model的獲取器、修改器、軟刪除數(shù)據(jù)操作示例
相關(guān)文章
學(xué)習(xí)php過(guò)程中的一些注意點(diǎn)的總結(jié)
在學(xué)習(xí)php的過(guò)程中會(huì)有一些細(xì)節(jié)是需要注意的,本文整理了一些比較實(shí)際的問(wèn)題,希望對(duì)大家有所幫助2013-10-10php下統(tǒng)計(jì)用戶(hù)在線(xiàn)時(shí)間的一種嘗試
一直以來(lái),在web開(kāi)發(fā)中,準(zhǔn)確統(tǒng)計(jì)用戶(hù)在線(xiàn)時(shí)間都是一個(gè)老大難的問(wèn)題,雖然已經(jīng)有很多人去嘗試各種不同的方案,可是畢竟項(xiàng)目不同,所用到的方法也是千差萬(wàn)別2010-08-08基于php偽靜態(tài)的實(shí)現(xiàn)方法解析
這篇文章主要介紹了基于php偽靜態(tài)的實(shí)現(xiàn)方法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07Lumen timezone 時(shí)區(qū)設(shè)置方法(慢了8個(gè)小時(shí))
今天用 Lumen 框架寫(xiě)代碼時(shí), 也是初次體驗(yàn) Lumen, 遇到了一個(gè)問(wèn)題, 從數(shù)據(jù)庫(kù)里查出的時(shí)間比數(shù)據(jù)庫(kù)里保存的 TIMESTAMP 時(shí)間慢了8個(gè)小時(shí), 很明顯這是一個(gè)時(shí)區(qū)設(shè)置的問(wèn)題, 本以為可以在1分鐘內(nèi)解決的, 但是我錯(cuò)了2018-01-01php實(shí)現(xiàn)Mysql簡(jiǎn)易操作類(lèi)
這個(gè)PHP實(shí)現(xiàn)的mysql的操作類(lèi)完整版已經(jīng)使用過(guò)了,而這個(gè)簡(jiǎn)化版是經(jīng)過(guò)修改完整版后的簡(jiǎn)化版,適用在一般的 PHP 應(yīng)用中,功能上可以實(shí)現(xiàn)基本的增刪改查的操作,以及打印 MYSQL 錯(cuò)誤,自我感覺(jué)不錯(cuò),如果網(wǎng)站應(yīng)用不是很強(qiáng)大,應(yīng)用這個(gè) MYSQL 的操作類(lèi)已經(jīng)足夠了,2015-10-10