目录 搜索
基础 安装ThinkPHP5.1 开发规范 目录结构 配置基础 架构 路由 控制器 请求 架构总览 入口文件 URL访问 模块设计 命名空间 容器和依赖注入 Facade 钩子和行为 路由定义 变量规则 路由地址 闭包支持 路由参数 跨域请求 注解路由 路由分组 MISS路由 资源路由 快捷路由 路由别名 路由绑定 域名路由 URL生成 控制器定义 前置操作 跳转和重定向 空操作和空控制器 分层控制器 资源控制器 请求对象 输入变量 请求类型 HTTP头信息 伪静态 参数绑定 请求缓存 响应 响应输出 响应参数 重定向 数据库 模型 视图 连接数据库 查询数据 添加数据 更新数据 删除数据 查询表达式 链式操作 where table alias field strict limit page order group having join union distinct lock cache comment fetchSql force partition failException sequence 聚合查询 时间查询 高级查询 视图查询 JSON字段 子查询 原生查询 查询事件 事务操作 监听SQL 存储过程 数据集 分布式数据库 定义 新增 更新 删除 查询 JSON数据字段 获取器 修改器 自动时间戳 只读字段 软删除 类型转换 数据完成 查询范围 模型输出 事件 关联 一对一关联 一对多关联 远程一对多 多对多关联 多态关联 关联预载入 关联统计 关联输出 视图渲染 视图赋值 视图过滤 模板引擎 模板 变量输出 使用函数 运算符 原样输出 模板注释 模板布局 模板继承 包含文件 输出替换 标签库 内置标签 循环标签 比较标签 条件判断 资源文件加载 标签嵌套 原生PHP 定义标签 错误和日志 异常处理 日志处理 调试 验证 杂项 命令行 扩展库 安全和性能 附录 调试模式 性能调试 SQL调试 变量调试 远程调试 验证器 验证规则 错误信息 验证场景 路由验证 内置规则 独立验证 静态调用 表单令牌 缓存 Session Cookie 多语言 分页 上传 自动生成目录结构 创建类库文件 生成类库映射文件 清除缓存文件 生成配置缓存文件 生成数据表字段缓存 生成路由映射缓存 自定义指令 验证码 图像处理 Time 数据库迁移工具 Workerman MongoDb 单元测试 安全建议 优化建议 助手函数 升级指导 更新日志
文字

模型关联

通过模型关联操作把数据表的关联关系对象化,解决了大部分常用的关联场景,封装的关联操作比起常规的数据库联表操作更加智能和高效,并且直观。

避免在模型内部使用复杂的join查询和视图查询。

从面向对象的角度来看关联的话,模型的关联其实应该是模型的某个属性,比如用户的档案关联,就应该是下面的情况:

// 获取用户模型实例
$user = User::get(1);
// 获取用户的档案
$user->profile;
// 获取用户的档案中的手机资料
$user->profile->mobile;

为了更方便和灵活的定义模型的关联关系,框架选择了方法定义而不是属性定义的方式,每个关联属性其实是对应了一个模型的(关联)方法,这个关联属性和模型的数据一样是动态的,并非模型类的实体属性。

例如上面的关联属性就是在User模型类中定义了一个profile方法(mobile属性是Profile模型的属性):

<?php

namespace app\index\model;

use think\Model;

class User extends Model
{
    public function profile()
    {
        return $this->hasOne('Profile');
    }
}

一个模型可以定义多个不同的关联,增加不同的关联方法即可

同时,我们必须定义一个Profile模型(即使是一个空模型)。

<?php
namespace app\index\model;
use think\Model;
class Profile extends Model
{
}

关联方法返回的是不同的关联对象,例如这里的profile方法返回的是一个HasOne关联对象(think\model\relation\HasOne)实例。

当我们访问User模型对象实例的profile属性的时候,其实就是调用了profile方法来完成关联查询。

按照PSR-2规范,模型的方法名都是驼峰命名的,所以系统做了一个兼容处理,如果我们定义了一个userProfile的关联方法的时候,在获取关联属性的时候,下面两种方式都是有效的:

$user->userProfile;
$user->user_profile;

推荐关联属性统一使用后者,和数据表的字段命名规范一致,因此在很多时候系统自动获取关联属性的时候采用的也是后者。

可以简单的理解为关联定义就是在模型类中添加一个方法(注意不要和模型的对象属性以及其它业务逻辑方法冲突),一般情况下无需任何参数,并在方法中指定一种关联关系,比如上面的hasOne关联关系,5.1版本支持的关联关系包括下面8种,后面会给大家陆续介绍:


模型方法关联类型
hasOne一对一
belongsTo一对一
hasMany一对多
hasManyThrough远程一对多
belongsToMany多对多
morphMany多态一对多
morphOne多态一对一
morphTo多态

关联方法的第一个参数就是要关联的模型名称,也就是说当前模型的关联模型必须也是已经定义好的一个模型。


一般不需要使用命名空间,会自动使用当前模型的命名空间,如果不同请使用完整命名空间定义,例如:


<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
    public function profile()
    {
        // Profile模型和当前模型的命名空间不一致
        return $this->hasOne('app\model\Profile');
    }
}

两个模型之间因为参照模型的不同就会产生相对的但不一定相同的关联关系,并且相对的关联关系只有在需要调用的时候才需要定义,下面是每个关联类型的相对关联关系对照:

类型关联关系相对的关联关系
一对一hasOnebelongsTo
一对多hasManybelongsTo
多对多belongsToManybelongsToMany
远程一对多hasManyThrough不支持
多态一对一morphOnemorphTo
多态一对多morphManymorphTo

例如,Profile模型中就可以定义一个相对的关联关系。

<?php
namespace app\index\model;
use think\Model;
class Profile extends Model
{
    public function user()
    {
        return $this->belongsTo('User');
    }
}

在进行关联查询的时候,也是类似,只是当前模型不同。

// 获取档案实例
$profile = Profile::get(1);
// 获取档案所属的用户名称
echo $profile->user->name;

如果你需要对关联模型进行更多的查询约束,可以在关联方法的定义方法后面追加额外的查询链式方法(但切忌不要滥用,并且不要使用实际的查询方法),例如:

<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
    public function book()
    {
        return $this->hasMany('Book')->order('pub_time');
    }
}

5.1版本的模型关联支持调用模型的方法

具体不同的关联关系的详细使用,请继续参考后面的内容。

上一篇: 下一篇: