Laravel 模型关联基础教程详解


Posted in PHP onSeptember 17, 2019

在 Laravel 中定义模型关联是每个 Laravel 开发者可能已经做过不止一次的事情。但是在试图实现关联时可能会遇到各种问题。因为 Laravel 有各种各样的关联,你应该选择哪一个?当涉及到查询模型时,我们如何充分利用模型关联的功能?

Laravel 的模型关联可能会让人糊涂。如果你不完全理解 Laravel 的关联在这一点上是如何工作的,别担心,读完这篇文章后,你会更好地理解它。

我们应该使用哪个模型关联?

要回答这个问题,首先你要知道有哪些可用的选项。Laravel 有 3 种不同的关联类型。

  • 一对一
  • 一对多
  • 多对多

我们将逐个探讨不同的关联类型并解释一下应该什么时候使用它们。

一对一

一对一关联是目前存在的最基本的关联。这种关联意味着 A 模型只能链接到 B 模型,相反也是如此。举个例子,一个 User 模型和一个 Passport 模型会成为一对一的关联。一个用户只能拥有一张通行证,同样,一张通行证也只属于一个用户。

让我们看看如何在代码中定义这种关联。

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
  public function passport() {
    return $this->hasOne(App\Passport::class);
  }
}

在 User 模型中我们创建了一个 passport 方法。我们通过 hasOne 方法告诉 Laravel User 模型有一个 Passport 。

注意:
所有用于定义关联的方法都有可选的额外参数,你可以在这些参数中定义本地键和外键。默认情况下,Laravel会假设你在用户模型中定义了 passport_id ,因为你试图创建与 passport 模型的关联。创建迁移文件时也请注意这一点!

在 Passport 模型中,我们需要定义逆向的关联。我们要让 Passport 模型知道它属于 User 模型。我们可以使用 belongsTo 方法来实现这一点。

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Passport extends Model
{
  public function user() {
    return $this->belongsTo(App\User::class);
  }
}

一对多

你可以在 Laravel 中定义的下一个关联是一对多关联。 这种类型的关联意味着一个类型A的模型可以链接到多个类型B的模型。但是类型B的模型只属于一个类型A的模型。

例如,User 模型和 Invoice 模型之间的关联是一对多关联。 用户可以拥有多个账单,但账单仅属于一个用户。

在代码中是这样写的:

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
  public function invoices() {
    return $this->hasMany(App\Invoice::class);
  }
}

它看起来就像我们之前用于定义一对一关联的代码,对吧?

我们现在要做的就是让 Invoice 模型知道它属于 User 模型。 让我们定义一对多关联的反向对应关联吧。

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Invoice extends Model
{
  public function user() {
    return $this->belongsTo(App\User::class);
  }
}

多对多

最后要定义的关联是多对多关联。 这种类型的关联意味着类型A的一个模型可以链接到类型B的多个模型,反之亦然。

例如,Invoice  模型和 Product  模型之间的关联将是多对多关联。 账单可以包含多个产品,而产品可以属于多个账单。

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Invoice extends Model
{
  public function products() {
    return $this->belongsToMany(App\Product::class);
  }
}

你可以像这样定义这种关联的反向关系:

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
  public function invoices() {
    return $this->belongsToMany(App\Invoice::class);
  }
}

多对多关联实现起来稍微困难一些,因为它们需要数据库中的中间表。 你可以通过创建迁移文件在 Laravel 中创建此中间表。

远程关联

远程一对一

has one through 关联通过单个中间关联模型实现。 如果每个供应商都有一个用户,并且每个用户与一个用户历史记录相关联,那么供应商可以通过用户访问用户的历史记录。

这就是定义这种关联所需的数据库表:

suppliers:
- idproducts:
- id
- supplier_idproduct_history:
- id
- product_id

即使 product_history 表不包含 supplier_id 列,供应商也可以通过使用 「has one through」 关系访问 product_history 记录。

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Supplier extends Model
{
  public function productHistory() {
    return $this->hasOneThrough(App\History::class, App\Product::class);
  }
}

传递给 hasOneThrough 方法的第一个参数是希望访问模型的名称。 第二个参数是中间模型的名称。

远程一对多

「has many through」 关联相当于 「has one through」 关联,只是对于多个记录的。 让我们使用前面的示例,但我们改变一件事:产品现在可以有多个历史条目而不是一个。 数据库表保持不变。

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Supplier extends Model
{
  public function productHistory() {
    return $this->hasManyThrough(App\History::class, App\Product::class);
  }
}

这样,供应商模型可以访问产品的历史记录条目。

查询关联

查询一个关联非常简单。因为我们定义了 Passport 的一对一关联和 Invoice 的一对多关联,所以我们可以在 User 模型中使用它们。在 User 模型的每个实例上,我们都可以得到对应的 Passport 和 Invoice。

<?php
$user = \App\User::find(1);

// 查询 passport 关联
$user->passport->expiration_date;

// 查询 invoice 关联
foreach($user->invoices as $invoice) {
  $invoice->total_amount;
}

也可以查询关联的反向关联。 如果您有账单,则可以获得该账单的用户。

<?php
$invoice = \App\Invoice::find(1);
// Get the user
$invoice->user->first_name;

查询多对多关联的工作方式与其他关联完全相同。 此外,多对多关联有一个pivot 属性。 此属性表示中间表,可以像任何其他模型一样使用。

举个例子,假设连接的表有 created_at 字段,我们就可以使用 pivot 来获取 created_at 字段。

<?php
$invoice = \App\Invoice::find(1);
// 获取 product 的 `created_at` 字段
foreach($invoice->products as $product) {
  $product->pivot->created_at;
}

查询 has one through 和 has many through 的工作方式与其他关联完全相同。

添加约束

可以在查询时向关系添加约束。看看下面的示例:

<?php
$user->passport()->where('active', 1)->orderBy('expiration_date');

检查关联是否存在

有时候你希望检查模型中是否有添加某些关联, Laravel有一些方法可以帮助你用来检查:

<?php
// 找到拥有护照的所有用户
$users = App\User::has('passport')->get();

// 找到没拥有护照的所有用户
$users = App\User::doesntHave('passport')->get();

// 找到拥有 5 个及以上产品的发票
$invoices = App\Invoice::has('products', '>=', 5)->get();

希望这篇文章能让你对Laravel的模型关联有更好的理解。谢谢你的阅读!也希望大家多多支持三水点靠木。

PHP 相关文章推荐
PHP 中的一些经验积累
Oct 09 PHP
snoopy PHP版的网络客户端提供本地下载
Apr 15 PHP
php 表单验证实现代码
Mar 10 PHP
PHP显示今天、今月、上月、今年的起点/终点时间戳的代码
May 25 PHP
php 转换字符串编码 iconv与mb_convert_encoding的区别说明
Nov 10 PHP
php旋转图片90度的方法
Nov 07 PHP
mantis安装、配置和使用中的问题小结
Jul 14 PHP
php使用explode()函数将字符串拆分成数组的方法
Feb 17 PHP
PHP ADODB实现分页功能简单示例
May 25 PHP
PHP验证类的封装与使用方法详解
Jan 10 PHP
laravel 查询数据库获取结果实现判断是否为空
Oct 24 PHP
YII2框架中actions的作用与使用方法示例
Mar 13 PHP
PHP实现的微信APP支付功能示例【基于TP5框架】
Sep 16 #PHP
php实现的支付宝网页支付功能示例【基于TP5框架】
Sep 16 #PHP
PHP实现的AES 128位加密算法示例
Sep 16 #PHP
Laravel项目中timeAgo字段语言转换的改善方法示例
Sep 16 #PHP
php解决crontab定时任务不能写入文件问题的方法分析
Sep 16 #PHP
PHP实现一个限制实例化次数的类示例
Sep 16 #PHP
thinkPHP5框架路由常用知识点汇总
Sep 15 #PHP
You might like
PHP使用memcache缓存技术提高响应速度的方法
2014/12/26 PHP
PHP mysqli_free_result()与mysqli_fetch_array()函数详解
2016/09/21 PHP
php记录搜索引擎爬行记录的实现代码
2018/03/02 PHP
JavaScript 自动分号插入(JavaScript synat:auto semicolon insertion)
2009/11/04 Javascript
Javascript图像处理思路及实现代码
2012/12/25 Javascript
封装了一个支持匿名函数的Javascript事件监听器
2014/06/05 Javascript
javascript实现简单计算器效果【推荐】
2016/04/19 Javascript
Bootstrap php制作动态分页标签
2016/12/23 Javascript
vue2.0结合DataTable插件实现表格动态刷新的方法详解
2017/03/17 Javascript
Angular学习教程之RouterLink花式跳转
2018/05/03 Javascript
Vue.js结合bootstrap前端实现分页和排序效果
2018/12/29 Javascript
vue组件之间的数据传递方法详解
2019/04/19 Javascript
在layui中使用form表单监听ajax异步验证注册的实例
2019/09/03 Javascript
vue+Element-ui前端实现分页效果
2020/11/15 Javascript
Python处理PDF及生成多层PDF实例代码
2017/04/24 Python
Python Flask基础教程示例代码
2018/02/07 Python
使用Python爬了4400条淘宝商品数据,竟发现了这些“潜规则”
2018/03/23 Python
解决Python一行输出不显示的问题
2018/12/03 Python
如何利用Pyecharts可视化微信好友
2019/07/04 Python
PyCharm专业最新版2019.1安装步骤(含激活码)
2019/10/09 Python
numpy库reshape用法详解
2020/04/19 Python
python中逻辑与或(and、or)和按位与或异或(&amp;、|、^)区别
2020/08/05 Python
pytorch加载语音类自定义数据集的方法教程
2020/11/10 Python
python help函数实例用法
2020/12/06 Python
CSS3 Media Queries详细介绍和使用实例
2014/05/08 HTML / CSS
门诊挂号室室长岗位职责
2013/11/27 职场文书
八年级音乐教学反思
2014/01/09 职场文书
2014全国两会学习心得体会2000字
2014/03/10 职场文书
条幅标语大全
2014/06/20 职场文书
2014年教研工作总结
2014/12/06 职场文书
2014年园林绿化工作总结
2014/12/11 职场文书
优秀共产党员推荐材料
2014/12/18 职场文书
2015年后备干部工作总结
2015/05/15 职场文书
python实现批量提取指定文件夹下同类型文件
2021/04/05 Python
解决flex布局中子项目尺寸不受flex-shrink限制
2022/05/11 HTML / CSS
Win11 KB5015814遇安装失败 影响开始菜单性能解决方法
2022/07/15 数码科技