发布于 2026-01-06 4 阅读
0

Laravel 中有很多直通关系,本文将通过示例进行解释,并推荐阅读。

Laravel 有许多通过关系进行解释的示例

推荐阅读

Eloquent Relationships是 Laravel 框架最实用、最强大的功能之一,也是我最喜欢 Laravel 的原因之一。它主要帮助我们以非常简单高效的方式获取和插入数据。

我们知道 Laravel 中有几种关系类型。我们(开发者)最常用的是前四种:一对一一对多一对多(反向)/属于多对多

我最喜欢多对多多对多关系。说实话,我最喜欢这两种关系。今天我将用一个简单的例子来解释多对多关系。希望读完这篇文章后,您能彻底理解。

那么,让我们直接进入正题

假设我们正在创建一家餐厅的菜品/菜单,其中菜品属于类型类型属于类别

简单来说,类别包含多个类型每个类型又包含多个项目。如果我们想要获取所有属于该类别的项目,就需要维护一个category_id包含所有项目的表。而项目主要属于某个类型。基本上,项目与类型直接关联

所以,在这种情况下,我们应该使用Has Many Through关系。通过这种关系,我们可以通过另一个模型获取数据。就像我们的场景一样,我们可以直接通过TypesCategory获取Items

为了方便您理解,我创建了一个GitHub 代码库。您可以访问该代码库。我在那里给出了两种Has Many Through关系的示例。

我尽量举一个非常简单的例子,以便你们容易理解。那么,我们开始吧。

正如我之前提到的,我们使用类别类型项目

所以我让我的迁移过程非常简单。

这是我的分类迁移代码。我们来看一下。

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateCategoriesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('categories', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('categories');
    }
}
Enter fullscreen mode Exit fullscreen mode

您可以看到这里我只保留了类别名称。

我们来看一下我的品类模型

<?php

namespace App\Models;

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

class Category extends Model
{
    use HasFactory;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name',
    ];
}
Enter fullscreen mode Exit fullscreen mode

这是我的类型迁移文件。我们来看一下。

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateTypesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('types', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->unsignedInteger('category_id');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('types');
    }
}
Enter fullscreen mode Exit fullscreen mode

我只是将其保留category_id为外键。因此,类别与类型相关联

这是类型模型。

<?php

namespace App\Models;

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

class Type extends Model
{
    use HasFactory;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'category_id'
    ];
}
Enter fullscreen mode Exit fullscreen mode

你可能会觉得这很简单。

让我们直接跳到我的项目迁移部分

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateItemsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('items', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->longText('description');
            $table->unsignedInteger('type_id');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('items');
    }
}
Enter fullscreen mode Exit fullscreen mode

所以你可以看到,我把它保留type_id为外键。因此,类型(Type )与项目(Item)关联。我没有category_id项目迁移中保留任何内容。你需要理解的关键一点是,项目(Item)并不直接与类别(Category)关联。项目(Item)通过类型(Type)与类别(Category)关联的。这就是为什么它被称为“通过多对多”(Has Many Through)关系。

这是Item的模型。

<?php

namespace App\Models;

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

class Item extends Model
{
    use HasFactory;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'description', 'type_id'
    ];
}
Enter fullscreen mode Exit fullscreen mode

现在我们将建立类别项目的“通过”多对多关系。

让我们建立与类别模型的关系

<?php

namespace App\Models;

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

class Category extends Model
{
    use HasFactory;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name',
    ];

    /**
     * Get all of the items for the user.
     */
    public function items()
    {
        return $this->hasManyThrough(Item::class, Type::class);
    }
}
Enter fullscreen mode Exit fullscreen mode

以下items关系将按类型获取属于该类别的所有项目。

你也可以像这样使用关系:

 return $this->hasManyThrough(
        Item::class,
        Type::class,
        'category_id', // Foreign key on the types table...
        'type_id', // Foreign key on the items table...
        'id', // Local key on the users table...
        'id' // Local key on the categories table...
 );
Enter fullscreen mode Exit fullscreen mode

就这样,我们通过“ Has Many Through”建立的关系已经成功了。

我想再举一个例子,帮助你更好地理解这种关系。

设想

假设我们有三个模型。

团队(id,user_id,名称)
用户(id,名称)
目标(id,user_id,目标数)
所以,关系是这样的。

Team hasMany User (在Userteam_id模型中)

用户拥有多个目标(在目标模型user_id内部)

从这种关系可以看出,这里的用户模型是一个中间模型。

我们不能goal_id直接将数据存储到 Team 表中,因为我们已经将数据存储goal_id在 User 表中了。

现在,User 模型与 Team 模型建立了关系。因此,在 User 模型内部,存在team_id……

最后,如果我们需要了解团队创建了多少个目标,我们可以通过用户模型来获取这些信息。

如果你的用例生成了这种类型的场景,那么你需要定义“通过多对多”关系。

希望现在清楚了。

推荐阅读

文章来源:https://dev.to/mahmudulhsn/laravel-has-many-through-relationship-explained-with-example-22p4