ThinkPHP模型详解
模型定义,默认情况下,thinkphp的模型类是位于/home/model/目录之下,模型类通常需要继承系统的\think\model类或其子类,下面是一个home\model\usermodel类的定义:
文件命名遵守usermodel.class.php的方式,跟控制器的命名一样
<?php namespace home\model; use think\model; class usermodel extends model { }
模型类的作用大多数情况是操作数据表的,如果按照系统的规范来命名模型类的话,大多数情况下是可以自动对应数据表,但你可以根据自己的需求来定制自己的数据表设置和操作。
首先我们需要在配置文件设置我们的数据库连接信息:
'db_type' => 'mysql', 'db_host' => 'localhost', 'db_name' => 'database', 'db_user' => 'username', 'db_pwd' => 'password', 'db_port' => '3306',
这些配置信息还是在/home/conf/config.php文件里设置。
指定数据表前缀
指定标前缀,我们在第一课的配置项已经指定,以下的文字表示你可以灵活配置你的数据表。
protected $tableprefix = 'top_';
如果数据库的表没有表前缀,使用空字符串代替
protected $tableprefix = '';
指定数据表,此处的指定的数据表的不需要添加表前缀:
protected $tablename = 'user';
举个例子说,比如说你的数据库中有一个没有表前缀的,名为users的数据表,可以用以下的两种方法在模型中进行下面的定义:
第一,直接根据系统的规范来命名模型类来命名模型,比如说就命名为usersmodel那么只需要在这个类里面加上下面的设置就可以了:
protected $tableprefix = '';
thinkphp系统就会自动定位到users表了。
第二种情况时,如果你的模型类没有按照系统规范来命名,比如说不小心命名为usermodel,这种情况下可以同时指定表前缀和表明,比如:
protected $tableprefix = ''; protected $tablename = 'users';
或者你直接指定truetablename:
protected $truetablename = 'users';
既然模型通常是用来操作数据表,那么我们来看看模型的基本curd:
注:为了方便演示,我们在usercontroller中定义一个testdemo()方法用于演示
public function testdemo() { }
以下的代码将会一段一段在这个方法里演示,你可以通过访问http://localhost:8999/index.php/home/user/testdemo来看到实际效果。
添加纪录
$user = m('user'); $data['username'] = 'thinkphp'; $data['email'] = 'thinkphp@gmail.com'; $user->create($data); $record = $user->add(); dump($record);
add()返回的是插入数据的id,对于不存在的表字段,add()方法会自动过滤。
读取纪录
在thinkphp中读取数据的方式很多,通常分为读取数据、读取数据集和读取字段值
$user = m('user'); $record = $user->where('username="thinkphp"')->find(); dump($record);
读取字段值
$user = m('user'); $record = $user->where('id=3')->getfield('username'); dump($record);
默认情况下,当只有一个字段的时候,返回满足条件的数据表中的该字段的第一行的值.如果getfield()传入多个字段,返回值将是一个关联数组:
$user = m('user'); $record = $user->getfield('username,email'); dump($record);
这个数组总是以传入的第一个第一个字段为键值的。如果修改为:
$user = m('user'); $record = $user->getfield('email,username'); dump($record);
将上面的两次代码分别放到testdemo(),你就会看到不一样的结果集。
用save()方法更新数据
$user = m('user'); $data['username'] = 'thinkphpsave'; $data['email'] = 'thinkphpsave@outlook.com'; $record = $user->where('id=3')->save($data); dump($record);
这里的$record返回的事1,表示成功更改。
当然,你也可以这样:
$user = m('user'); $user->username = 'thinkphp'; $user->email = 'thinkphp@outlook.com'; $record = $user->where('id=3')->save(); dump($record);
日常开发的时候经常会遇到一些只更新某些字段的情况,可以通过下面的方式来实现:
$user = m("user"); $record = $user->where('id=4')->setfield('username','thinkphpchangename'); dump($record);
同时更新多个字段,可以将数据以数组的形式传给setfield()方法:
$user = m('user'); $data = array('username'=>'thinkphpchangearray','email'=>'thinkphp@array.com'); $record = $user-> where('id=6')->setfield($data); dump($record);
thinkphp删除数据使用delete方法,例如:
$user = m('user'); $record = $user->where('id=3')->delete(); dump($record);
或者你可以直接使用:
$record = $user->delete('1,2,5'); dump($record);
这样就达到了删除主键1,2,5这三条纪录了。
activerecords
thinkphp实现了activerecords模式的orm模型,采用了非标准的orm模型:表映射到类,记录映射到对象。以下实例将使用activerecords重现对数据表的curd,看看activerecords给我们带来了什么好处。
$user = m("user"); $user->username = 'thinkphpwithactive'; $user->email = 'thinkphpactive@gmail.com'; $record = $user->add(); dump($record);
读取纪录
ar最大的特点可能就是它的查询模式了,模式简单易用,因为更多情况下面查询条件都是以主键或者某个关键的字段。这种类型的查询,thinkphp有着很好的支持。
比如说获取主键为2的用户信息:
$user = m("user"); $record = $user->find(2); dump($record);
直接不用where()查询了,简单友好吧。再比如:
$user = m("user"); $record = $user->getbyusername("jelly"); dump($record);
如果是查询多条纪录,使用以下方式:
$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);
删除记录
删除单条纪录
$user = m("user"); $record = $user->delete(8); dump($record);
删除多条纪录
$user = m("user"); $record = $user->delete('15,16'); dump($record); // todo: 这里的自动验证和关联模型 调试不出来。
自动完成
自动完成是thinkphp提供用来完成数据自动处理和过滤的方法,当使用create()方法创建数据对象的时候会触发自动完成数机制。
因此,在thinkphp鼓励使用create()方法来创建数据对象,因为这是一种更加安全的方式,直接通过add()或者save()方法实现数据写入无法出发自动完成机制。
自动完成通常用来完成默认字段写入(比如添加时间戳),安全字段过滤(比如加密密码)以及业务逻辑的自动处理等。可以通过模型类里面通过$_auto属性定义处理规则。下面演示如何自动完成添加时间戳:
在usermodel中,声明自动完成的定义数组$_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()方法动态设置自动完成的机制,可以到官方文档去看看
设置完成之后,我们在testdemo()方法中创建一条用户数据:
$user = d('user'); $data['username'] = "thinkphp"; $data['email'] = "thinkphp@gmail.com"; $user->create($data); $record = $user->add(); dump($record);
测试,如果返回纪录的id值,说明用户纪录创建成功。要验证数据是否自动完成,你可以直接使用:
$user = d('user'); $record = $user->find(id); dump($record);
自动验证
自动验证是thinkphp模型层提供的一种数据验证方法,可以在使用create()创建数据对象的时候自动进行数据验证。
数据验证可以进行数据类型、业务规则、安全判断等方面的验证操作。
通常用于表单验证
数据验证有两种方式:
静态方式:在模型类里面通过$_validate属性定义验证规则。
动态方式:使用模型类的validate()方法动态创建自动验证规则。
无论是什么方式,验证规则的定义是统一的规则,定义格式为:
array(
array(验证字段1,验证规则,错误提示,[验证条件,附加规则,验证时间]),
array(验证字段2,验证规则,错误提示,[验证条件,附加规则,验证时间]),
......
);
下面以$_validate静态方式举例如何使用自动验证:
在usercontroller中创建register()方法,对,几乎每一个web应用都需要实现用户注册这一步。
public function register() { $this->display(); }
对,就是这么简单,这个方法只是将相应的视图文件渲染出来。所以接下来我们创建对应的视图文件,也就是:./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代码和一点模板的知识,对于模板,我们后续会讲到,但不管怎样,现在我们访问
http://localhost:8999/home/user/register,就可以看到我们的注册表单页面了。
注意到form表单中,action="__url__/registervalidate",这表示提交到当前的控制器的registervalidate()方法处理,所以我们在usercontroller中增加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) )会触发自动验证并判断验证是否通过验证。你可以尝试在表单里填写不同的数据来进行测试,也可以修改一下验证规则,更多规则可以到官网查看:
关联模型
通常我们所说的关联关系包括下面三种:
一对一关联 :one_to_one,包括has_one 和 belongs_to
一对多关联 :one_to_many,包括has_many 和 belongs_to
多对多关联 :many_to_many
关联定义
thinkphp可以很轻松的完成数据表的关联curd操作,目前支持的关联关系包括下面四种:
has_one、belongs_to、has_many和many_to_many。
一个模型根据业务模型的复杂程度可以同时定义多个关联,不受限制,所有的关联定义都统一在模型类的 $_link 成员变量里面定义,并且可以支持动态定义。要支持关联操作,模型类必须继承think\model\relationmodel类,关联定义的格式类似于:
namespace home\model; use think\model\relationmodel; class usermodel extends relationmodel{ protected $_link = array( '关联' => array( '关联属性1' => '定义', '关联属性n' => '定义', ), ); }
关于关联属性的定义和值,你可以到官方文档仔细查看,我们下面也会给出一些最常用的。
在我们的讲解例子中,会采用has_many和belongs_to来演示,对于其他的几个关系模型,可以参考官方文档举一反三。
首先我们知道数据库里面有两张表,用户表和文章表,并且我们也为其创建了不同的模型(usermodel articelmodel)。
现在我们仔细来想想他们之间的对应关系:一个用户可以拥有多篇文章,而每一篇文章都属于某个特定的用户。所以我们可以分别为这两种关系添加关联模型:
在usermodel中:
protected $_link = array( 'article' => self::has_many );
在articlemodel中:
protected $_link = array( 'user' => self::belongs_to );
以上者两种都是最简洁的模型关联声明。因为在最开始设计数据库的时候,我们遵守了thinkphp的官方的规范:
外键的默认规则是当前数据对象名称_id,例如:usermodel对应的可能是表think_user,那么think_user表的外键默认为user_id,如果你的外键不是user_id,而是其他自定义的字段如:user_identify,那么就必须在定义关联的时候定义 foreign_key 。如下:
在usermodel中:
protected $_link = array( 'mapping_type' => self::has_many, 'class_name' => 'article', 'foreign_key' => 'user_identify', );
更多自定义的关联模型参数可以到官网查看。
有了以上的定义之后,我们就可以在检索用户数据的同时将属于他的文章也一起检索出来,使用relation()。
同样是在testdemo()这个方法中:
$user = d('user'); $record = $user->relation(true)->find(4); dump($record);
访问熟悉的http://localhost:8999/home/user/testdemo,你将会看到神奇的结果。
以上所述就是本文的全部内容了,希望大家能够喜欢。
下一篇: php技术实现加载字体并保存成图片