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 提速工具eAccelerator 配置参数详解
May 16 PHP
用PHP编写和读取XML的几种方式
Jan 12 PHP
PHP数组循环操作详细介绍 附实例代码
Feb 03 PHP
php cookie名使用点号(句号)会被转换
Oct 23 PHP
php操作memcache缓存方法分享
Jun 03 PHP
PHP+MySQL统计该库中每个表的记录数并按递减顺序排列的方法
Feb 15 PHP
Yii2框架实现注册和登录教程
Sep 30 PHP
php 人员权限管理(RBAC)实例(推荐)
May 24 PHP
php 广告点击统计代码(php+mysql)
Feb 21 PHP
PHP封装的完整分页类示例
Aug 21 PHP
Laravel使用Queue队列的技巧汇总
Sep 02 PHP
php新建文件的方法实例
Sep 26 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常用字符串的总结(待续)
2013/06/07 PHP
input 输入框内的输入事件详细分析
2010/03/17 Javascript
分享一道笔试题[有n个直线最多可以把一个平面分成多少个部分]
2012/10/12 Javascript
JavaScript 命名空间 使用介绍
2013/08/29 Javascript
NodeJS使用jQuery选择器操作DOM
2015/02/13 NodeJs
Javascript显示和隐藏ul列表的方法
2015/07/15 Javascript
js实现基于正则表达式的轻量提示插件
2015/08/29 Javascript
JQuery 传送中文乱码问题的简单解决办法
2016/05/24 Javascript
jQuery插件Easyui设置datagrid的pageNumber导致两次请求问题的解决方法
2016/08/06 Javascript
利用jquery给指定的table动态添加一行、删除一行的方法
2016/10/12 Javascript
详解Vue中状态管理Vuex
2017/05/11 Javascript
Vue-Router进阶之滚动行为详解
2017/09/13 Javascript
解决循环中setTimeout执行顺序的问题
2018/06/20 Javascript
详解JavaScript 的变量
2019/03/08 Javascript
vue自定义switch开关组件,实现样式可自行更改
2019/11/01 Javascript
vue2.0 获取从http接口中获取数据,组件开发,路由配置方式
2019/11/04 Javascript
[00:52]黑暗之门更新 新英雄孽主驾临DOTA2
2016/08/24 DOTA
python实现的udp协议Server和Client代码实例
2014/06/04 Python
Python中处理字符串之isalpha()方法的使用
2015/05/18 Python
python dataframe astype 字段类型转换方法
2018/04/11 Python
python 读入多行数据的实例
2018/04/19 Python
win10下python3.5.2和tensorflow安装环境搭建教程
2018/09/19 Python
opencv-python 读取图像并转换颜色空间实例
2019/12/09 Python
Django框架之中间件MiddleWare的实现
2019/12/30 Python
django实现将后台model对象转换成json对象并传递给前端jquery
2020/03/16 Python
泰国网上购物:Shopee泰国
2018/09/14 全球购物
Hurley官方网站:扎根于海滩生活方式的全球青年文化品牌
2020/05/18 全球购物
关于赌博的检讨书
2014/01/08 职场文书
厂长岗位职责
2014/02/19 职场文书
聚美优品恶搞广告词
2014/03/14 职场文书
节水标语大全
2014/06/11 职场文书
工作经常出错的检讨书
2014/09/13 职场文书
庆祝新中国成立65周年“向国旗敬礼”网上签名寄语
2014/09/27 职场文书
学生旷课检讨书500字
2014/10/28 职场文书
银行服务理念口号
2015/12/25 职场文书
jQuery ajax - getScript() 方法和getJSON方法
2021/05/14 jQuery