首页 » PHP » 正文

thinkphp5学习笔记(6)

模型和关联

ThinkPHP5.0 的模型是一种对象-关系映射(Object/Relation Mapping,简称 ORM )的封装,并且提供了
简洁的 ActiveRecord 实现。一般来说,每个数据表会和一个“模型”对应。

ORM 的基本特性就是表映射到记录,记录映射到对象,字段映射到对象属性。模型是一种对象化的操作
封装,而不是简单的 CURD 操作,简单的 CURD 操作直接使用前面提过的 Db 类即可。

模型类和 Db 类的区别主要在于对象的封装, Db 类的查询默认返回的是数组(或者集合),而模型类返回
的是当前的模型对象实例(或者集合),模型是比 Db 类更高级的数据封装,支持模型关联、模型事件。

(1)模型定义

为了更好的理解,我们首先在数据库创建一个 think_user 表如下:

CREATE TABLE IF NOT EXISTS `think_user`(
`id` int(8) unsigned NOT NULL AUTO_INCREMENT,
`nickname` varchar(50) NOT NULL COMMENT '昵称',
`email` varchar(255) NULL DEFAULT NULL COMMENT '邮箱',
`birthday` int(11) UNSIGNED NOT NULL DEFAULT '0' COMMENT '生日',
`status` tinyint(2) NOT NULL DEFAULT '0' COMMENT '状态',
`create_time` int(11) UNSIGNED NOT NULL DEFAULT '0' COMMENT '注册时间',
`update_time` int(11) UNSIGNED NOT NULL DEFAULT '0' COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;

数据库配置文件定义如下:

return [
// 数据库类型
'type' => 'mysql',
// 服务器地址
'hostname' => '127.0.0.1',
// 数据库名
'database' => 'demo',
// 数据库用户名
'username' => 'root',
// 数据库密码
'password' => '',
// 数据库连接端口
'hostport' => '',
// 数据库连接参数
'params' => [],
// 数据库编码默认采用utf8
'charset' => 'utf8',
// 数据库表前缀
'prefix' => 'think_',
// 数据库调试模式
'debug' => true,
];

并添加路由定义( application/route.php )如下:

return [
// 全局变量规则定义
'__pattern__' => [
'id' => '\d+',
],
'user/index' => 'index/user/index',
'user/create' => 'index/user/create',
'user/add' => 'index/user/add',
'user/add_list' => 'index/user/addList',
'user/update/:id' => 'index/user/update',
'user/delete/:id' => 'index/user/delete',
'user/:id' => 'index/user/read',
];

我们为 think_user 表定义一个 User 模型(位于 application/index/model/User.php )如下:

namespace app\index\model;
use think\Model;
class User extends Model
{
}

大多情况下,我们无需为模型定义任何的属性和方法即可完成基础的操作。

设置数据表

模型会自动对应一个数据表,规范是:

数据库前缀+当前的模型类名(不含命名空间)

因为模型类命名是驼峰法,所以获取实际的数据表的时候会自动转换为小写+下划线命名的数据表名称。
如果你的模型命名不符合这一数据表对应规范,可以给当前模型定义单独的数据表,包括两种方式。

设置完整数据表:

namespace app\index\model;
use think\Model;
class User extends Model
{
// 设置完整的数据表(包含前缀)
protected $table = 'think_user';
}

设置不带前缀的数据表名:

namespace app\index\model;
use think\Model;
class User extends Model
{
// 设置数据表(不含前缀)
protected $name = 'member';
}

设置数据库连接
如果当前模型类需要使用不同的数据库连接,可以定义模型的 connection 属性,例如:

namespace app\index\model;
use think\Model;
class User extends Model
{
// 设置单独的数据库连接
protected $connection = [
// 数据库类型
'type' => 'mysql',
// 服务器地址
'hostname' => '127.0.0.1',
// 数据库名
'database' => 'test',
// 数据库用户名
'username' => 'root',
// 数据库密码
'password' => '',
// 数据库连接端口
'hostport' => '',
// 数据库连接参数
'params' => [],
// 数据库编码默认采用utf8
'charset' => 'utf8',
// 数据库表前缀
'prefix' => 'think_',
// 数据库调试模式
'debug' => true,
];
}

———————————————————–
(2)基础操作

新增数据
我们先来看下如何写入模型数据,创建一个 User 控制器并增加 add 操作方法如下:

<?php
namespace app\index\controller;
use app\index\model\User as UserModel;
class User
{
// 新增用户数据
public function add()
{
$user = new UserModel;
$user->nickname = '流年';
$user->email = 'thinkphp@qq.com';
$user->birthday = strtotime('1977-03-05');
if ($user->save()) {
return '用户[ ' . $user->nickname . ':' . $user->id . ' ]新增成功';
} else {
return $user->getError();
}
}
}
在当前文件中给 app\index\model\User 模型定义了一个别名 UserModel 是为了避免和当前的
app\index\controller\User 产生冲突,如果你当前的控制器类不是 User 的话可以不需要定义UserModel 别名。

有一种方式可以让你省去别名定义,系统支持统一对控制器类添加 Controller 后缀,修改配置参数:
// 是否启用控制器类后缀
‘controller_suffix’ => true,

然后,控制器类文件改为 UserController.php ,并且修改控制器类的定义如下:

<?php
namespace app\index\controller;
use app\index\model\User;
class UserController
{
// 新增用户数据
public function add()
{
$user = new User;
$user->nickname = '流年';
$user->email = 'thinkphp@qq.com';
$user->birthday = strtotime('1977-03-05');
if ($user->save()) {
return '用户[ ' . $user->nickname . ':' . $user->id . ' ]新增成功';
} else {
return $user->getError();
}
}
}

默认情况下,实例化模型类后执行 save 操作都是执行的数据库 insert 操作,如果你需要实例化执行
save 执行数据库的 update 操作,请确保在save方法之前调用 isUpdate 方法:

$user->isUpdate()->save();

如果你觉得上面的方式给 User 对象一个个赋值太麻烦,可以改为下面的方式:

// 新增用户数据
public function add()
{
$user['nickname'] = '看云';
$user['email'] = 'kancloud@qq.com';
$user['birthday'] = strtotime('2015-04-02');
if ($result = User::create($user)) {
return '用户[ ' . $result->nickname . ':' . $result->id . ' ]新增成功';
} else {
return '新增出错';
}
}

批量新增

也可以直接进行数据的批量新增,给控制器添加如下 addList 操作方法:

// 批量新增用户数据
public function addList()
{
$user = new UserModel;
$list = [
['nickname' => '张三', 'email' => 'zhanghsan@qq.com', 'birthday' => strtotime('1
988-01-15')],
['nickname' => '李四', 'email' => 'lisi@qq.com', 'birthday' => strtotime('1990-0
9-19')],
];
if ($user->saveAll($list)) {
return '用户批量新增成功';
} else {
return $user->getError();
}
}

查询数据
接下来添加 User 模型的查询功能,给 User 控制器增加如下 read 操作方法:

// 读取用户数据
public function read($id='')
{
$user = UserModel::get($id);
echo $user->nickname . '<br/>';
echo $user->email . '<br/>';
echo date('Y/m/d', $user->birthday) . '<br/>';
}

模型的 get 方法用于获取数据表的数据并返回当前的模型对象实例,通常只需要传入主键作为参数,如果没
有传入任何值的话,则表示获取第一条数据。

打开:http://192.168.0.102/user/1
输出:
流年
thinkphp@qq.com
1977/03/05

模型的 get 方法和 Db 类的 find 方法返回结果的区别在于, Db 类默认返回的只是数组(注意这里说的默
认,其实仍然可以设置为对象),而模型的 get 方法查询返回的一定是当前的模型对象实例。
但是系统为模型实现了 ArrayAccess 接口,因此仍然可以通过数组的方式访问对象实例,把控制器的
read 操作方法改成如下:

// 读取用户数据
public function read($id = '')
{
$user = UserModel::get($id);
echo $user['nickname'] . '<br/>';
echo $user['email'] . '<br/>';
echo date('Y/m/d', $user['birthday']) . '<br/>';
}

效果同上。

如果我想通过用户的 email 来查询模型数据的话,应该如何操作呢?
下面是一个查询的例子:

// 根据email读取用户数据
public function read()
{
$user = UserModel::getByEmail('thinkphp@qq.com');
echo $user->nickname . '<br/>';
echo $user->email . '<br/>';
echo date('Y/m/d', $user->birthday) . '<br/>';
}

输出的结果是:
流年
thinkphp@qq.com
1977/03/05

如果不是根据主键查询的话,可以传入数组作为查询条件,例如:

// 根据nickname读取用户数据
public function read()
{
$user = UserModel::get(['nickname'=>'流年']);
echo $user->nickname . '<br/>';
echo $user->email . '<br/>';
echo date('Y/m/d', $user->birthday) . '<br/>';
}

更复杂的查询则可以使用查询构建器来完成,例如:

// 根据nickname读取用户数据
public function read()
{
$user = UserModel::where('nickname', '流年')->find();
echo $user->nickname . '<br/>';
echo $user->email . '<br/>';
echo date('Y/m/d', $user->birthday) . '<br/>';
}

数据列表
如果要查询多个数据,可以使用模型的 all 方法,我们在控制器中添加index操作方法用于获取用户列表:

// 获取用户数据列表
public function index()
{
$list = UserModel::all();
foreach ($list as $user) {
echo $user->nickname . '<br/>';
echo $user->email . '<br/>';
echo date('Y/m/d', $user->birthday) . '<br/>';
echo '----------------------------------<br/>';
}
}

如果不是使用主键查询,可以直接传入数组条件查询,例如:

// 获取用户数据列表
public function index()
{
$list = UserModel::all(['status'=>1]);
foreach ($list as $user) {
echo $user->nickname . '<br/>';
echo $user->email . '<br/>';
echo date('Y/m/d', $user->birthday) . '<br/>';
echo '----------------------------------<br/>';
}
}

我们也可以使用数据库的查询构建器完成更多的条件查询,例如:

// 获取用户数据列表
public function index()
{
$list = UserModel::where('id','<',3)->select();
foreach ($list as $user) {
echo $user->nickname . '<br/>';
echo $user->email . '<br/>';
echo date('Y/m/d', $user->birthday) . '<br/>';
echo '----------------------------------<br/>';
}
}

更新数据
我们可以对查询出来的数据进行更新操作,下面添加一个 update 操作方法:

// 更新用户数据
public function update($id)
{
$user = UserModel::get($id);
$user->nickname = '刘晨';
$user->email = 'liu21st@gmail.com';
if (false !== $user->save()) {
return '更新用户成功';
} else {
return $user->getError();
}
}

默认情况下,查询模型数据后返回的模型示例执行 save 操作都是执行的数据库 update 操作,如果你需要
实例化执行 save 执行数据库的 insert 操作,请确保在save方法之前调用 isUpdate 方法:

$user->isUpdate(false)->save();<pre>
ActiveRecord 模式的更新数据方式需要首先读取对应的数据,如果需要更高效的方法可以把update方法
改成:
<pre lang="php">
// 更新用户数据
public function update($id)
{
$user['id'] = (int) $id;
$user['nickname'] = '刘晨';
$user['email'] = 'liu21st@gmail.com';
$result = UserModel::update($user);
return '更新用户成功';
}

删除数据
我们给User控制器添加delete方法用于删除用户。

// 删除用户数据
public function delete($id)
{
$user = UserModel::get($id);
if ($user) {
$user->delete();
return '删除用户成功';
} else {
return '删除的用户不存在';
}
}

同样我们也可以直接使用 destroy 方法删除模型数据,例如把上面的 delete 方法改成如下:

// 删除用户数据
public function delete($id)
{
$result = UserModel::destroy($id);
if ($result) {
return '删除用户成功';
} else {
return '删除的用户不存在';
}
}
博主的文章或程序如果给您带来了价值,感谢您打赏一二
微信扫码支付 支付宝扫码支付

发表评论