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 相关文章推荐
防止MySQL注入或HTML表单滥用的PHP程序
Jan 21 PHP
SESSION信息保存在哪个文件目录下以及能够用来保存什么类型的数据
Jun 17 PHP
高性能PHP框架Symfony2经典入门教程
Jul 08 PHP
php实现的click captcha点击验证码类实例
Sep 23 PHP
php中mail函数发送邮件失败的解决方法
Dec 24 PHP
PHP、Java des加密解密实例
Apr 27 PHP
一个完整的PHP类包含的七种语法说明
Jun 04 PHP
PHP读取汉字的点阵数据
Jun 22 PHP
JSON字符串传到后台PHP处理问题的解决方法
Jun 05 PHP
php的单例模式及应用场景详解
Feb 27 PHP
PHP常用字符串输出方法分析(echo,print,printf及sprintf)
Mar 09 PHP
YII2 全局异常处理深入讲解
Mar 24 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数组函数序列之in_array() - 查找数组中是否存在指定值
2011/11/07 PHP
php引用地址改变变量值的问题
2012/03/23 PHP
php中的路径问题与set_include_path使用介绍
2014/02/11 PHP
php和jquery实现地图区域数据统计展示数据示例
2014/02/12 PHP
浅谈PHP发送HTTP请求的几种方式
2017/07/25 PHP
thinkphp诸多限制条件下如何getshell详解
2020/12/09 PHP
js操作select控件的几种方法
2010/06/02 Javascript
jQuery 操作option的实现代码
2011/03/03 Javascript
15款优秀的jQuery导航菜单插件分享
2011/07/19 Javascript
jQuery实现渐变弹出层和弹出菜单的方法
2015/02/20 Javascript
jQuery实现列表内容的动态载入特效
2015/08/08 Javascript
Bootstrap每天必学之导航组件
2016/04/25 Javascript
Three.js学习之几何形状
2016/08/01 Javascript
浅谈js中startsWith 函数不能在任何浏览器兼容的问题
2017/03/01 Javascript
JS简单获取当前日期时间的方法(如:2017-03-29 11:41:10 星期四)
2017/03/29 Javascript
Vue2.0表单校验组件vee-validate的使用详解
2017/05/02 Javascript
利用JS如何计算字符串所占字节数示例代码
2017/09/13 Javascript
jquery ajax异步提交表单数据的方法
2017/10/27 jQuery
vue-cli项目中使用公用的提示弹层tips或加载loading组件实例详解
2018/05/28 Javascript
js+springMVC 提交数组数据到后台的实例
2019/09/21 Javascript
layui+SSM的数据表的增删改实例(利用弹框添加、修改)
2019/09/27 Javascript
JavaScript实现滚动加载更多
2020/12/27 Javascript
[02:17]TI4西雅图DOTA2前线报道 啸天mik夫妻档解说
2014/07/08 DOTA
[50:45]2018DOTA2亚洲邀请赛 4.6 淘汰赛 VP vs TNC 第一场
2018/04/10 DOTA
[51:17]Mski vs VGJ.S Supermajor小组赛C组 BO3 第三场 6.3
2018/06/04 DOTA
Python与shell的3种交互方式介绍
2015/04/11 Python
Django ORM 常用字段与不常用字段汇总
2019/08/09 Python
tensorflow 获取checkpoint中的变量列表实例
2020/02/11 Python
python如何用matplotlib创建三维图表
2021/01/26 Python
英国最大的美妆产品在线零售商之一:Beauty Bay
2017/09/29 全球购物
遗嘱继承公证书
2014/04/09 职场文书
2014年师德承诺书
2014/05/23 职场文书
关于有小孩的离婚协议书
2014/10/26 职场文书
就业推荐表导师评语
2014/12/31 职场文书
小学数学教学随笔
2015/08/14 职场文书
2016年读书月活动总结范文
2016/04/06 职场文书