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
PHP高级OOP技术演示
Aug 27 PHP
怎样给PHP源代码加密?PHP二进制加密与解密的解决办法
Apr 22 PHP
使用PHPExcel操作Excel用法实例分析
Mar 26 PHP
两款万能的php分页类
Nov 12 PHP
PHP的Laravel框架中使用AdminLTE模板来编写网站后台界面
Mar 21 PHP
PHP实现适用于文件内容操作的分页类
Jun 15 PHP
PHP创建多级目录的两种方法
Oct 28 PHP
Yii框架实现的验证码、登录及退出功能示例
May 20 PHP
PHP调用其他文件中的类
Apr 02 PHP
详解PHP多个进程配合redis的有序集合实现大文件去重
Mar 06 PHP
PHP实现获取文件mime类型多种方法解析
May 28 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
谏山创故乡大分县日田市水坝将设立《进击的巨人》立艾伦、三笠以及阿尔敏的铜像!
2020/03/06 日漫
file_get_contents获取不到网页内容的解决方法
2013/03/07 PHP
一组PHP可逆加密解密算法实例代码
2014/01/21 PHP
PHP实现数组递归转义的方法
2014/08/28 PHP
浅谈php正则表达式中的非贪婪模式匹配的使用
2014/11/25 PHP
thinkPHP5.0框架简单配置作用域的方法
2017/03/17 PHP
javascript 新浪背投广告实现代码
2009/07/07 Javascript
jQuery解决iframe高度自适应代码
2009/12/20 Javascript
javascript 防止刷新,后退,关闭
2010/08/07 Javascript
jquery中的 $(&quot;#jb51&quot;)与document.getElementById(&quot;jb51&quot;) 的区别
2011/07/26 Javascript
分享8款优秀的 jQuery 加载动画和进度条插件
2012/10/24 Javascript
JavaScript Ajax Json实现上下级下拉框联动效果实例代码
2013/11/23 Javascript
Javascript中的回调函数和匿名函数的回调示例介绍
2014/05/12 Javascript
自写的jQuery异步加载数据添加事件
2014/05/15 Javascript
js通过iframe加载外部网页的实现代码
2015/04/05 Javascript
探析浏览器执行JavaScript脚本加载与代码执行顺序
2016/01/12 Javascript
JS实现简单易用的手机端浮动窗口显示效果
2016/09/07 Javascript
使用bootstrapValidator插件进行动态添加表单元素并校验
2016/09/28 Javascript
浅谈Koa服务限流方法实践
2017/10/23 Javascript
vue2.0 如何在hash模式下实现微信分享
2019/01/22 Javascript
解决vue 子组件修改父组件传来的props值报错问题
2019/11/09 Javascript
Python中函数参数调用方式分析
2018/08/09 Python
python实现杨氏矩阵查找
2019/03/02 Python
有关Tensorflow梯度下降常用的优化方法分享
2020/02/04 Python
Python 炫技操作之合并字典的七种方法
2020/04/10 Python
python 比较字典value的最大值的几种方法
2020/04/17 Python
JD Sports马来西亚:英国领先的运动鞋和运动服饰零售商
2018/03/13 全球购物
Under Armour安德玛德国官网:美国高端运动科技品牌
2019/03/09 全球购物
Brasty罗马尼亚:购买手表、香水、化妆品、珠宝
2020/04/21 全球购物
美国亚马逊旗下时尚女装网店:SHOPBOP(支持中文)
2020/10/17 全球购物
毕业生就业自荐书
2013/12/15 职场文书
房地产公司见习自我鉴定
2014/04/28 职场文书
五四演讲稿范文
2014/09/03 职场文书
浅谈Nginx 中的两种限流方式
2021/03/31 Servers
详解python中[-1]、[:-1]、[::-1]、[n::-1]使用方法
2021/04/25 Python
MybatisPlus EntityWrapper如何自定义SQL
2022/03/22 Java/Android