模型定义
模型类通常需要继承系统的\Think\Model类或其子类,下面是一个Home\Model\UserModel类的定义:
namespace Home\Model;
use Think\Model;
class UserModel extends Model {
}
模型类的作用大多数情况是操作数据表的,如果按照系统的规范来命名模型类的话,大多数情况下是可以自动对应数据表。
模型类的命名规则是除去表前缀的数据表名称,采用驼峰法命名,并且首字母大写,然后加上模型层的名称(默认定义是Model),例如:
模型名 | 约定对应数据表(假设数据库的前缀定义是 think_) |
---|---|
UserModel | think_user |
UserTypeModel | think_user_type |
如果你的规则和上面的系统约定不符合,那么需要设置Model类的数据表名称属性,以确保能够找到对应的数据表。
数据表定义
在ThinkPHP的模型里面,有几个关于数据表名称的属性定义:
属性 | 说明 |
---|---|
tablePrefix | 定义模型对应数据表的前缀,如果未定义则获取配置文件中的DB_PREFIX参数 |
tableName | 不包含表前缀的数据表名称,一般情况下默认和模型名称相同,只有当你的表名和当前的模型类的名称不同的时候才需要定义。 |
trueTableName | 包含前缀的数据表名称,也就是数据库中的实际表名,该名称无需设置,只有当上面的规则都不适用的情况或者特殊情况下才需要设置。 |
dbName | 定义模型当前对应的数据库名称,只有当你当前的模型类对应的数据库名称和配置文件不同的时候才需要定义。 |
举个例子来加深理解,例如,在数据库里面有一个think_categories
表,而我们定义的模型类名称是CategoryModel
,按照系统的约定,这个模型的名称是Category,对应的数据表名称应该是think_category
(全部小写),但是现在的数据表名称是think_categories
,因此我们就需要设置tableName
属性来改变默认的规则(假设我们已经在配置文件里面定义了DB_PREFIX
为 think_)。
namespace Home\Model;
use Think\Model;
class CategoryModel extends Model {
protected $tableName = 'categories';
}
注意这个属性的定义不需要加表的前缀think_
如果我们需要CategoryModel模型对应操作的数据表是 top_category
,那么我们只需要设置数据表前缀即可:
namespace Home\Model;
use Think\Model;
class CategoryModel extends Model {
protected $tablePrefix = 'top_';
}
如果你的数据表直接就是category
,而没有前缀,则可以设置tablePrefix
为空字符串。
namespace Home\Model;
use Think\Model;
class CategoryModel extends Model {
protected $tablePrefix = '';
}
没有表前缀的情况必须设置,否则会获取当前配置文件中的
DB_PREFIX
。
而对于另外一种特殊情况,我们需要操作的数据表是top_categories
,这个时候我们就需要定义 trueTableName
属性
namespace Home\Model;
use Think\Model;
class CategoryModel extends Model {
protected $trueTableName = 'top_categories';
}
注意
trueTableName
需要完整的表名定义。
除了数据表的定义外,还可以对数据库进行定义(用于操作当前数据库以外的数据表),例如 top.top_categories
:
namespace Home\Model;
use Think\Model;
class CategoryModel extends Model {
protected $trueTableName = 'top_categories';
protected $dbName = 'top';
}
实例化模型
D()方法;
D方法可以自动检测模型类,如果存在自定义的模型类,则实例化自定义模型类,如果不存在,则会实例化系统的\Think\Model基类,同时对于已实例化过的模型,不会重复实例化。
M方法实例化模型
例如:
// 使用M方法实例化
$User = M('User');
// 和用法 $User = new \Think\Model('User'); 等效
// 执行其他的数据操作
$User->select();
M方法也可以支持跨库操作,例如:
// 使用M方法实例化 操作db_name数据库的ot_user表
$User = M('db_name.User','ot_');
// 执行其他的数据操作
$User->select();
M方法实例化的时候,默认情况下是直接实例化系统的\Think\Model类,如果我们希望实例化其他的公共模型类的话,可以使用如下方法:
$User = M('\Home\Model\CommonModel:User','think_','db_config');
// 相当于 $User = new \Home\Model\CommonModel('User','think_','db_config');
实例化空模型类
如果你仅仅是使用原生SQL查询的话,不需要使用额外的模型类,实例化一个空模型类即可进行操作了,例如:
//实例化空模型
$Model = new Model();
//或者使用M快捷方法是等效的
$Model = M();
//进行原生的SQL查询
$Model->query('SELECT * FROM think_user WHERE status = 1');
实例化空模型类后还可以用table方法切换到具体的数据表进行操作
字段定义
可以通过设置DB_FIELDS_CACHE
参数来关闭字段自动缓存,如果在开发的时候经常变动数据库的结构,而不希望进行数据表的字段缓存,可以在项目配置文件中增加如下配置:
// 关闭字段缓存
'DB_FIELDS_CACHE'=>false
注意:调试模式下面由于考虑到数据结构可能会经常变动,所以默认是关闭字段缓存的。
全局配置定义
常用的配置方式是在应用配置文件或者模块配置文件中添加下面的配置参数:
//数据库配置信息
'DB_TYPE' => 'mysql', // 数据库类型
'DB_HOST' => '127.0.0.1', // 服务器地址
'DB_NAME' => 'thinkphp', // 数据库名
'DB_USER' => 'root', // 用户名
'DB_PWD' => '123456', // 密码
'DB_PORT' => 3306, // 端口
'DB_PARAMS' => array(), // 数据库连接参数
'DB_PREFIX' => 'think_', // 数据库表前缀
'DB_CHARSET'=> 'utf8', // 字符集
'DB_DEBUG' => TRUE, // 数据库调试模式 开启后可以记录SQL日志
数据库的类型由DB_TYPE参数设置。
下面是目前支持的数据库设置:
DB_TYPE设置 | 数据库类型 |
---|---|
mysql | mysql |
pgsql | pgsql |
sqlite | sqlite |
sqlsrv | sqlserver |
oracle | oracle |
firebird | ibase |
mongo | mongo |
连贯操作
WHERE
字符串条件
使用字符串条件直接查询和操作,例如:
$User = M("User"); // 实例化User对象
$User->where('type=1 AND status=1')->select();
数组条件
数组条件的where用法是ThinkPHP推荐的用法。
普通查询
最简单的数组查询方式如下:
$User = M("User"); // 实例化User对象
$map['name'] = 'thinkphp';
$map['status'] = 1;
// 把查询条件传入查询方法
$User->where($map)->select();
表达式查询
上面的查询条件仅仅是一个简单的相等判断,可以使用查询表达式支持更多的SQL查询语法,查询表达式的使用格式:
$map['字段1'] = array('表达式','查询条件1');
$map['字段2'] = array('表达式','查询条件2');
$Model->where($map)->select(); // 也支持
表达式不分大小写,支持的查询表达式有下面几种,分别表示的含义是:
表达式 | 含义 |
---|---|
EQ | 等于(=) |
NEQ | 不等于(<>) |
GT | 大于(>) |
EGT | 大于等于(>=) |
LT | 小于(<) |
ELT | 小于等于(<=) |
LIKE | 模糊查询 |
[NOT] BETWEEN | (不在)区间查询 |
[NOT] IN | (不在)IN 查询 |
EXP | 表达式查询,支持SQL语法 |
多次调用
where方法支持多次调用,但字符串条件只能出现一次,例如:
$map['a'] = array('gt',1);
$where['b'] = 1;
$Model->where($map)->where($where)->where('status=1')->select();
多次的数组条件表达式会最终合并,但字符串条件则只支持一次。
TABLE
ALIAS
alias用于设置当前数据表的别名,便于使用其他的连贯操作例如join方法等。
DATA
写操作
通常情况下我们都是通过create方法或者赋值的方式生成数据对象,然后写入数据库,例如:
$Model = D('User');
$Model->create();
// 这里略过具体的自动生成和验证判断
$Model->add();
data方法则是直接生成要操作的数据对象,例如:
$Model = M('User');
$data['name'] = '流年';
$data['email'] = 'thinkphp@qq.com';
$Model->data($data)->add();
读操作
除了写操作外,data方法还可以用于读取当前的数据对象,例如:
$User = M('User');
$map['name'] = '流年';
$User->where($map)->find();
// 读取当前数据对象
$data = $User->data();
FIELD
属于模型的连贯操作方法之一,主要目的是标识要返回或者操作的字段,可以用于查询和写入操作。
field方法的参数可以支持数组,例如:
$Model->field(array('id','title','content'))->select();
ORDER
order方法属于模型的连贯操作方法之一,用于对操作的结果排序。
用法如下:
$Model->where('status=1')->order('id desc')->limit(5)->select();
注意:连贯操作方法没有顺序,可以在select方法调用之前随便改变调用顺序。
支持对多个字段的排序,例如:
$Model->where('status=1')->order('id desc,status')->limit(5)->select();
如果没有指定desc或者asc排序规则的话,默认为asc。
LIMIT
limit方法也是模型类的连贯操作方法之一,主要用于指定查询和操作的数量,特别在分页查询的时候使用较多。
限制结果数量
例如获取满足要求的10个用户,如下调用即可:
$User = M('User');
$User->where('status=1')->field('id,name')->limit(10)->select();
limit方法也可以用于写操作,例如更新满足要求的3条数据:
$User = M('User');
$User->where('score=100')->limit(3)->save(array('level'=>'A'));
分页查询
用于文章分页查询是limit方法比较常用的场合,例如:
$Article = M('Article');
$Article->limit('10,25')->select();
表示查询文章数据,从第10行开始的25条数据(可能还取决于where条件和order排序的影响 这个暂且不提)。
你也可以这样使用,作用是一样的:
$Article = M('Article');
$Article->limit(10,25)->select();
对于大数据表,尽量使用limit限制查询结果,否则会导致很大的内存开销和性能问题。
PAGE
page方法也是模型的连贯操作方法之一,是完全为分页查询而诞生的一个人性化操作方法。
$Article = M('Article');
$Article->page('1,10')->select(); // 查询第一页数据
$Article->page('2,10')->select(); // 查询第二页数据
显而易见的是,使用page方法你不需要计算每个分页数据的起始位置,page方法内部会自动计算。
和limit方法一样,page方法也支持2个参数的写法
page方法还可以和limit方法配合使用,例如:
$Article->limit(25)->page(3)->select();
当page方法只有一个值传入的时候,表示第几页,而limit方法则用于设置每页显示的数量,也就是说上面的写法等同于:
$Article->page('3,25')->select();
GROUP
通常用于结合合计函数,根据一个或多个列对结果集进行分组 。
支持对多个字段进行分组,例如:
$this->field('user_id,test_time,username,max(score)')->group('user_id,test_time')->select();
HAVING
用于配合group方法完成从分组的结果中筛选(通常是聚合条件)数据。
having方法只有一个参数,并且只能使用字符串,例如:
$this->field('username,max(score)')->group('user_id')->having('count(test_time)>3')->select();
JOIN
用于根据两个或多个表中的列之间的关系,从这些表中查询数据。
join通常有下面几种类型,不同类型的join操作会影响返回的数据结果。
- INNER JOIN: 等同于 JOIN(默认的JOIN类型),如果表中有至少一个匹配,则返回行
- LEFT JOIN: 即使右表中没有匹配,也从左表返回所有的行
- RIGHT JOIN: 即使左表中没有匹配,也从右表返回所有的行
- FULL JOIN: 只要其中一个表中存在匹配,就返回行
join方法可以支持以上四种类型,例如:
$Model = M('Artist');
$Model
->join('think_work ON think_artist.id = think_work.artist_id')
->join('think_card ON think_artist.card_id = think_c