Laravel多态多对多关系数据透视表与另一个模型的关系

Posted

技术标签:

【中文标题】Laravel多态多对多关系数据透视表与另一个模型的关系【英文标题】:Laravel Polymorphic Many-to-Many relationship pivot table with relationship to another Model 【发布时间】:2021-09-05 11:17:56 【问题描述】:

我有如下表结构,如图所示:

简而言之,它由几个多对多的多态关系组成,如下所述:

许多resources 可以有许多sources 并且数据透视表sourceables 包含catalog_numberlot_number 信息,以使数据透视表中的每一行都是唯一的。许多资源也可能来自同一来源或不同来源,由数据透视表上的目录号和批号区分。

许多resources 也可以通过publicationables 表和数据透视表上的notes 附加许多publications

资源的来源也可以在许多出版物中描述。

我的问题:

    由于资源的来源是由数据透视表sourceables区分的,我应该如何将sourceables的数据透视行之间的关系保存到publications? 您能否在sourceables 和“publicationables”之间创建一个自定义中间表模型以链接到publications? 如何检索包含所有出版物的资源以及包含所有相应出版物的来源?

【问题讨论】:

我打算今晚或下午回复这个。 谢谢@RicardoVargas。如果需要任何澄清,请告诉我。 抱歉耽搁了,我正在努力完成我的回答。我能够为您创建一个包含实时示例的完整 Github 存储库。我会在早上完成所有细节。 没问题。我很高兴你能提供帮助。 【参考方案1】:

这是我的回答,希望能给你的问题带来一些启示。我已经发布了GitHub repository,其中包含我在这里编写的所有代码的示例。我在那里添加了有关如何复制我的场景的更多信息。

数据库和关系

这是我对数据库及其关系的解释。您可以检查存储库上的所有迁移。

解决方案

问题一:

我应该如何保存sourceable的pivot行与出版物之间的关系?

答案:

在继续代码示例之前,我想解释一些需要理解的重要概念。我将使用表达式 tag 来指代用于关联模型的 identifierindex 变形关系。 它的工作方式是将标签分配给您要添加到关系中的任何模型。使用这些标签的任何模型都可以存储在 Morph Pivot Table 中。 Laravel 使用 _"modelable"type 列来过滤对存储模型名称的关系的调用。您可以使用 Relation“标记”您的模型,在模型中创建一个返回 morphToMany 关系函数的方法。

对于这种特定情况,以下是如何继续: 在您的资源模型中,您有两种方法,一种与 sourceable 索引相关,另一种与使用 morphToManypublicationable 标签相关/em> 作为回报。 以下是资源模型 (./app/Models/Resource.php) 的外观:

<?php
namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Resource extends Model

    use HasFactory;
    protected $guarded = [];

    public function publications()
    
        return $this->morphToMany(Publication::class, 'publicationable')->withPivot('notes');
    

    public function sources()
    
        return $this->morphToMany(Source::class, 'sourceable')->withPivot(['catalog_number', 'lot_number']);
    

在您的发布模型中,您有两种方法,一种与 sourceable 索引相关,另一种与 inverse 关系publicationable 的资源方法相关 标签使用 morphedByMany 作为回报。 以下是发布模型 (./app/Models/Publication.php) 的外观:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Publication extends Model

    use HasFactory;
    protected $guarded = [];

    public function sources()
    
        return $this->morphToMany(Source::class, 'sourceable')->withPivot(['catalog_number', 'lot_number']);
    

    public function resources()
    
        return $this->morphedByMany(Resource::class, 'publicationable');
    

With this, you can be able to accomplish your goal of relating Publications with Resources and Sources.

问题 2:您能否在 sourceablepublicationable 之间有一个中间表来链接到出版物?

答案:

不,你不需要。您可以使用 sourceables 表来完成此操作。您始终可以通过创建将 morphToMany 关系返回到 Source 模型的方法,将 Source 与 ANY 模型相关联。这些是我们对问题 1 上的出版物所做的。

问题 3:如何检索资源及其所有出版物以及所有相应出版物的来源?

答案:

我认为 Eloquent 是整个 Laravel 框架中我最喜欢的功能。这是蛋糕上的樱桃,我们在模型定义上所做的一切。

如果您再次检查资源和发布模型定义,我们会添加一个 withPivot() 方法,其中包含我们希望在对与 eloquent 的关系进行的任何调用中包含的相关字段。这种方法可以从数据透视表中读取自定义值。

重要提示:对于此示例,我隐式添加了数据透视值,因为我没有在迁移时将这些列声明为 NULL。

要使用该关系将出版物与资源关联(存储在数据透视表上),您只需:

(使用工匠修补匠
Psy Shell v0.10.8 (PHP 8.0.6 — CLI) by Justin Hileman
>>> $publication = \App\Models\Publication::find(5)
>>> $resource = \App\Models\Resource::find(19)
>>> $resource->publications()->attach($publication, ["notes" => "Eureka!"]);
### Adding another Publication
>>> $publication = \App\Models\Publication::find(10)
>>> $resource->publications()->attach($publication, ["notes" => "Eureka 2!"]);
(使用控制器)
use App\Models\Resource;
use App\Models\Publication;
...
$id_resource = 1; // This is the Resource Id you want to reach.
$id_publication = 10; // This is the Resource Id you want to reach.

$resource = Resource::find($id_resource);
$publication = Publication::find($id_publication);
$pivotData = [ "notes" => "Eureka!" ];

$resource->publications()->attach($publication, $pivotData);

要从资源中检索所有出版物,您只需:

(使用工匠修补匠
Psy Shell v0.10.8 (PHP 8.0.6 — CLI) by Justin Hileman
>>> $resource = \App\Models\Publication::find(5)
>>> $resource->publications()->get();

简单吧? :) 雄辩的力量!

(使用控制器)
use App\Models\Resource;
...
$id_resource = 1; // This is the Resource Id you want to reach.
$resource = Resource::find($id_resource);

$resource->publications()->get();

如果有任何疑问,您可以通过以下方式存储和检索所有模型:

(使用控制器)
use App\Models\Publication;
use App\Models\Resource;
use App\Models\Source;
...
... Method ...
$id_publication = 1;
$id_resource = 1;
$id_source = 1;

$publication = Publication::find($id_resource);
$resource = Resource::find($id_resource);
$source = Source::find($id_resource);

$publicationPivotColumns = [
    "notes" => "This is a note...",
];

$sourcePivotColumns = [
    "catalog_number" => 100,
    "lot_number" => 4903,
];

// Storing Data
// Attach (Store in the publicationables table) a Publication to a Resource
$resource->publications()->attach($publication, $publicationPivotColumns);

// Attach (Store in the sourceables table) a Source to a Resource
$resource->sources()->attach($source, $sourcePivotColumns);

// Attach (Store in the sourceables table) a Source to a Publication
$publication->sources()->attach($source, $sourcePivotColumns);

// Retraiving Data
// Get all Sources from a Resource
$resource->sources()->get();

// Get all Publications from a Resource
$resource->publications()->get();

// Get all Sources from a Publication
$publication->sources()->get();

【讨论】:

嗨,里卡多。感谢您抽出宝贵时间广泛讨论该主题。我的主要问题仍然是您的解决方案,如下所示。我没有与publications 相关的sources。我在sourceablespublications 之间有关系,即sourceables 表中的行应该与publications 表相关。因此,source_idcatalog_numberlot_number 的独特组合将与许多 publications 相关联。 您仍然可以在我提供的解决方案中执行此操作,只需在迁移时将 catalog_numberlot_number 设置为 nullable()。然后,您只需在将源添加到 Publication 时传递所需的附加信息。这使您无需额外的表来存储这些数据。 试图更好地理解你认为我明白了。您只需要在发布和资源模型之间添加另一个关系即可完成此操作。今晚我可以添加更多细节。 我想我必须重新设计架构。因此,与其在resourcessources 之间建立多对多关系,我认为我应该有3 个表:resources 多一对多source_itemssource_items 多对一sources。然后我可以通过publicationablesource_itemspublications 关联起来。想法? 在标记方面重新表述我的问题 - 我如何将 tag 表中的一行 sourceables 转换为 publication

以上是关于Laravel多态多对多关系数据透视表与另一个模型的关系的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 多列上的多对多同步()

Laravel 与 uuid 的多对多关系返回总是空的

在多对多关系 laravel4 的情况下更新数据透视表

laravel 使用具有多对多关系数据透视表的策略

Laravel - 是不是可以与一个表和一个数据透视表建立多对多关系

Laravel:如何在多态多对多中使用 wherePivot