在Laravel中, eloquent关系被定义为Eloquent模型类的方法, 它们是非常强大的查询构建器.Eloquent使得管理和处理这些关系毫不费力, 并帮助各种常见的关系。在本教程中, 我们将通过一个例子来了解如何在Laravel中使用多对多关系.
Laravel多对多
Laravel的多对多关系比hasOne和hasMany关系要稍微复杂一些。多对多关系的关键是连接(或透视)表。枢轴表允许一个模型的关系ID与其他许多模型相关,反之亦然。
多对多的关系是通过编写一个返回belongsToMany结果的方法来定义的。
在我们的例子中,我们将定义两个模型:
- 类别
- 产品
在我们的例子中,多个类别有多个产品,而反过来的关系将是多个产品属于多个类别。
所以,我们可以做的是,当我们进入一个特定的类别,我们需要显示所有的产品。
同样,当我们看到特定的产品时,我们需要显示属于该特定产品的所有类别。
我们通过安装Laravel项目来开始这个实际的例子。
第一步: 安装Laravel.
我正在使用Laravel Valet来创建一个新的项目,使用以下命令:
laravel new relationships
如果你没有使用Laravel Valet,请使用以下命令进行安装:
composer create-project laravel/laravel relationship --prefer-dist
进入该项目:
cd relationships
在你的编辑器中打开这个项目:
code .
第一件事, 设置数据库.
第二步: 创建一个模型和迁移.
我们为我们的例子定义了两个模型:
- 类别
- 产品
php artisan make:model Category -m
php artisan make:model Product -m
它将创建产品和类别、表和模型。
现在,在create_categories_table里面, 定义以下模式:
// create_categories_table
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('categories', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->timestamps();
});
}
同时,在create_products_table里面写上下面的模式:
// create_products_table
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->float('price');
$table->timestamps();
});
}
现在,进入终端,使用以下命令创建表。
php artisan migrate
第3步:手动定义随机类别
在这个例子中,我们只是关注多对多的关系是如何运作的,我们如何分配数值并创建一个与另一个表的关系。因此,我们在数据库表内手动创建三个类别。
所以,我们已经手动定义了三个类别。
第四步:定义一个透视表
多对多的关系需要一个中间表来管理这种关系。
最直接的中间表的实现,被称为透视表,仅由两列组成,用于存储指向每一对相关记录的外键。
如何在Laravel中创建一个透视表
- 数据透视表的名称应该由两个表的单数名称组成,用下划线符号隔开,这些名称应该按字母顺序排列,所以我们必须有category_product,而不是product_category。
- 要创建一个透视表,我们可以用artisan make:migration创建简单的迁移,或者使用社区包Laravel 5 Generators Extended.例如, 我们有artisan make:migration:pivot这个命令.
- 数据透视表字段:默认情况下,应该只有两个字段--每个表的外键,在我们的例子中是category_id和product_id。如果你需要,你可以插入更多的字段,然后你需要将它们添加到关系分配中。
让我们在我们的例子中使用上述规则。
所以,我们已经定义了两个表模式:1)类别 2)产品。
现在,我们需要定义第三个表,也就是Pivot表。
透视表是两个表之间的关系。
因此,透视表有这些列:
- id
- category_id
- product_id
现在,我们正在创建多对多的关系;这就是为什么许多产品有类别。例如,要创建一个迁移文件,请输入以下命令。
php artisan make:migration create_category_product_table --create=category_product
现在,在迁移文件中定义以下模式:
// create_category_product_table
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('category_product', function (Blueprint $table) {
$table->increments('id');
$table->integer('category_id')->unsigned();
$table->integer('product_id')->unsigned();
});
}
现在,使用下面的命令进行迁移:
php artisan migrate
第5步:定义多对多关系
现在,多个类别属于多个产品。所以在Product.php 文件中,我们可以定义belongsToMany 关系:
// Product.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
public function categories()
{
return $this->belongsToMany(Category::class);
}
}
同样,对产品也是如此。多个产品属于多个类别。所以在Category.php 文件里面,我们可以定义belongsToMany 关系:
// Category.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use App\Product;
class Category extends Model
{
public function products()
{
return $this->belongsToMany(Product::class);
}
}
所以,我们已经定义了它们之间的关系。
现在,让我们创建一个新的产品,并将类别分配给产品。
第6步:创建一个产品
在一个实时场景中,我们创建一个表单,然后通过POST请求,我们把产品 数据插入到表中。
然而,在这个例子中,我们不会定义任何表单;我们直接将数据存储到数据库中,因为我们的目标是使用多对多关系的复杂场景。
现在,定义一个路由,将产品保存到数据库中,并使用多对多关系将产品分配到类别中。
现在,我们有四(4)个类别。所以,我们创建一个产品并将两个类别分配给一个产品。
首先,使用以下命令创建一个ProductController。
php artisan make:controller ProductController
下一步,定义路由以存储产品。
现在,我使用GET请求来保存数据,因为我们还没有创建表单,所以我们手动获取每一个数据。
// ProductController.php
Route::get('product/create', 'ProductController@create')->name('product.create');
在这个ProductController.php 文件中导入两个模型。
另外,现在我们要做的是,我们将创建一个属于许多类别的产品。
在这个示例教程中,我们将创建一个名为 "战神"的产品 。
现在,"战神 "属于两个类别:
- 视频游戏
- 游戏机
因此,当我们创建一个产品时,我们也需要在透视表中填入这两个类别。
所以,我们的product_id将是一个,但是,category_id将是不同的,这样,它将在category_product 表中创建两行。
现在,在ProductController的 create()函数中写下以下代码:
// ProductController.php
<?php
namespace App\Http\Controllers;
use App\Category;
use App\Product;
use Illuminate\Http\Request;
class ProductController extends Controller
{
public function create(Request $request)
{
$product = new Product;
$product->name = 'God of War';
$product->price = 40;
$product->save();
$category = Category::find([3, 4]);
$product->categories()->attach($category);
return 'Success';
}
}
解释一下:
首先,我们已经创建了产品并将其保存在产品 表中。
现在,是时候为新创建的产品分配类别了。
因为我们需要一个类别的ID,所以现在,我已经手动编码,但在实时的情况下,你有这些ID在表单请求中。
现在,attach()函数将把这些类别的ID分配给新创建的产品,并在数据透视表中创建两行新的记录。每一行都与它的产品和类别有关系。
下一步是去这个URL:relationships.test/product/cre… http://localhost:8000/product/create
你可以看到 "成功"。
现在,进入数据库,看到产品 表。
另外,你可以查看数据透视表,它是一个创建_产品 表。
如果我们做得很正确,我们可以看到表内的两行,两行的product_id都是相同的1,但是category_id的不同,分别是3 和4。
耶!!,我们已经成功地将两个类别连接到一个产品上。
下一步是显示产品信息和显示该产品中的所有类别。
第7步:显示产品信息
定义可以显示所有信息的路由。
// web.php
Route::get('product/{product}', 'ProductController@show')->name('product.show');
现在,定义ProductController的显示函数。
在这个函数中,我使用了路由模型的绑定:
// ProductController.php
public function show(Product $product)
{
return view('product.show', compact('product'));
}
我们在获取请求中传递产品ID,我们通过路由模型绑定直接获取产品细节,并将产品细节交给视图。
在views 文件夹中创建一个名为products 的新文件夹,并在其中创建一个名为show.blade.php的文件。
在show.blade.php 文件中写下以下代码。我们显示产品的名称、价格和所属类别:
// show.blade.php
<h2>Product Name: </h2>
<p>{{ $product->name }} || ${{ money_format($product->price, 2) }}</p>
<h3>Product Belongs to</h3>
<ul>
@foreach($product->categories as $category)
<li>{{ $category->title }}</li>
@endforeach
</ul>
由于我们已经定义了关系,我们可以直接从产品模型中获取所有的类别,这就是Laravel中Eloquent Relationships的神奇之处。
现在, 转到这个网址:http://relationships.test/product/1或 http://localhost:8000/product/1
正如你所看到的, 我们只创建了一个产品,只看到一个产品细节。
所以, 这就是你如何为一个产品添加多个类别,并为一个产品显示多个类别。
现在,你可以创建任意多的产品并为它们指定多个类别。
你还可以使用detach()函数删除表之间的关系。
Detach()函数
// ProductController.php
public function removeCategory(Product $product)
{
$category = Category::find(3);
$product->categories()->detach($category);
return 'Success';
}
现在,在web.php 文件内定义以下路由:
// web.php
Route::get('category/product/{product}', 'ProductController@removeCategory')->name('category.product.delete');
接下来,输入这个URL:relationships.test/category/pr… http://localhost:8000/category/product/1。
点击回车,我们现在得到了成功。转到MySQL数据库,检查category_product 表。
你可以看到,category_id = 3行被删除了,我们不再属于category_id = 3:
所以, 这就是你如何在Laravel中维护多对多的关系.
总结
Laravel的 "多对多 "关系将表中的一条记录与另一个表中的一条或多条记录联系起来,反之亦然。与Laravel的一对多和一对一不同, 在这种关系中, 关键是一个透视表.枢轴表是一个你在两个表之间定义的表,以连接它们。一个透视表允许一个模型的关系ID与许多其他模型相关,反之亦然。
我们可以想到的一个现实生活中的例子是产品和类别。一个类别可以有许多产品,而一个产品可以与许多类别相关联;简单的不是。
这个多对多关系教程就到此为止。




