如何在LaravelEloquent中创建一对多关系
作为本系列的先决条件设置的演示 Laravel 应用程序包含一个用于存储链接的数据库表。 在本教程中,您将修改此初始数据库结构以包含第二个表,您将使用该表将链接组织到 列表 中。
对于我们将在本系列中使用的链接和列表示例,每个链接只是一个列表的一部分,但每个列表可以有多个链接。 这种关系也称为一对多关系。
当一个项目(我们将其称为类型 A)可以链接到多个类型为 B 的项目时,就会发生一对多关系,但相反的情况不成立: B 类型的项目只能链接到 一个 类型的 A 项目。 将此场景转换为当前的演示应用模型,A为list类型,B为link类型。
创建 LinkList 模型
首先,您需要创建一个模型和一个数据库表来表示链接的 List。 然后,您将更新现有的 Link 模型和表以包含两个模型之间的关系。 因为术语 List 是为 PHP 内部保留的,所以您将无法使用该术语命名您的新模型。 您可以将此新模型称为 LinkList。
首先,确保您在应用程序目录中:
cd ~/landing-laravel
使用 artisan 创建一个新模型:
docker-compose exec app php artisan make:model LinkList
这将在 app/Model 目录中生成一个新的模型类:
app/Model/LinkList.php
重命名现有的 LinkList CLI 命令
如果您查看 app/Console/Commands 目录,您会注意到已经有一个名为 LinkList.php 的类文件。 不要将这与您刚刚创建的 Eloquent 模型相混淆。 此类包含一个 CLI 命令,该命令通过 artisan 列出数据库中的所有链接。
为避免将来出现混淆,现在是将该类及其命令签名重命名为不同名称的好时机。 在这种情况下,请使用类名 LinkShow,因为该名称也描述了类的作用。 要将 app/Console/Commands/LinkList.php 文件重命名为另一个有效名称,请在终端中运行以下命令:
mv app/Console/Commands/LinkList.php app/Console/Commands/LinkShow.php
然后,在代码编辑器中打开文件 app/Console/Commands/LinkShow.php 将类名从 LinkList 更改为 LinkShow,并将命令签名从 link:list 更改为 link:show,如以下代码清单中突出显示的行。 这是完成后文件的外观:
应用程序/控制台/命令/LinkShow.php
<?php
namespace App\Console\Commands;
use App\Models\Link;
use Illuminate\Console\Command;
class LinkShow extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'link:show';
/**
* The console command description.
*
* @var string
*/
protected $description = 'List links saved in the database';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$headers = [ 'id', 'url', 'description' ];
$links = Link::all(['id', 'url', 'description'])->toArray();
$this->table($headers, $links);
return 0;
}
}
完成后保存并关闭文件。 要检查一切是否按预期工作,请运行新重命名的 link:show artisan 命令:
docker-compose exec app php artisan link:show
您将收到如下输出:
Output+----+-------------------------------------------------+----------------------------------+ | id | url | description | +----+-------------------------------------------------+----------------------------------+ | 1 | https://digitalocean.com/community | DigitalOcean Community | | 2 | https://digitalocean.com/community/tags/laravel | Laravel Tutorias at DigitalOcean | | 3 | https://digitalocean.com/community/tags/php | PHP Tutorials at DigitalOcean | +----+-------------------------------------------------+----------------------------------+
为 LinkList 模型创建迁移
您使用前面的 artisan make:model 命令生成的新 app/Model/LinkList.php 类包含新 Eloquent 类的通用代码。 与 Doctrine 等其他 ORM 不同,Eloquent 不会改变数据库结构,只处理数据本身。 Eloquent 模型通常是精益的,类属性自动从模型的表结构中推断出来。
这种使用 Eloquent 仅处理数据的方法意味着您不需要为 LinkList 类设置任何属性,因为它们将从该模型的数据库表结构中推断出来。
结构数据库操作通常通过 数据库迁移 在 Laravel 中处理。 迁移允许开发人员以编程方式定义对数据库的结构更改,例如创建、修改和删除表。
您现在将创建一个新迁移以在数据库中设置 lists 表。
Laravel 默认包含的 artisan 命令行工具包含几个辅助方法来引导新组件,例如控制器、模型、迁移等。 要使用 artisan 创建新的迁移,请运行:
docker-compose exec app php artisan make:migration create_link_lists_table
Output Created Migration: 2021_07_07_152554_create_link_lists_table
此命令将在 Laravel 应用程序的 database/migrations 目录下生成一个新文件,使用基于当前日期和时间的自动生成名称以及迁移名称。 该文件包含您将修改以设置 lists 表的通用代码。
使用您的代码编辑器,打开生成的迁移文件。 该文件当前如下所示:
数据库/迁移/2021_07_07_152554_create_link_lists_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateLinkListsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('link_lists', function (Blueprint $table) {
$table->id();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('link_lists');
}
}
当使用 artisan migrate 命令执行迁移时,将运行 up() 方法。 这是您的表定义所在,默认情况下,它创建一个 id 主键字段和两个时间戳字段(created_at 和 updated_at),用 [ 定义X172X] 模式方法。 这些字段分别在创建和更新模型时由 Eloquent 自动填充。 down() 方法在使用 artisan rollback 命令回滚迁移时调用,通常执行代码以删除表或恢复结构更改。
您将更改 up 方法以包含以下字段:
title:表示此列表标题的字符串description:表示List描述的字符串slug:基于标题的唯一短字符串,通常用于创建用户友好的 URL
在一对多关系中,many 端(在这种情况下对应于 links 表)是保存列引用(或外键)到其他元素(对应于 lists 表)。 这意味着您必须稍后修改 links 表,以便包含一个将该表链接到 lists 表的引用字段。
另一方面,lists 表不需要任何特殊字段来引用其链接。
将迁移文件中的当前内容替换为以下代码:
数据库/迁移/2021_07_07_152554_create_link_lists_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateLinkListsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('link_lists', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->string('title', 60);
$table->string('slug', 60)->unique();
$table->text('description')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('link_lists');
}
}
完成后保存文件。
更新链接迁移
接下来,在代码编辑器中打开现有的 links 迁移文件。 在演示项目中,您将在以下路径中找到迁移:
2020_11_18_165241_create_links_table.php
首先,在文件开头和最后 use 行之后包含一个 use 指令,指向 LinkList 类的完全限定类名:
… use Illuminate\Support\Facades\Schema; use App\Models\LinkList; ...
接下来,在表定义中包含以下行,在 up 方法中和设置 description 字段的行之后:
$table->text('description');
$table->foreignIdFor(LinkList::class);
foreignIdFor() 方法为引用的 Eloquent 模型创建一个外键列。 它使用默认命名法来设置链接到引用表的主键字段的字段。
完成后,完整的迁移类应该是这样的:
数据库/迁移/2020_11_18_165241_create_links_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use App\Models\LinkList;
class CreateLinksTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('links', function (Blueprint $table) {
$table->id();
$table->string('url', 200);
$table->text('description');
$table->foreignIdFor(LinkList::class);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('links');
}
}
完成编辑后保存文件。 接下来,擦除数据库,然后再次运行迁移命令以使用更新的迁移文件重新创建数据库结构:
docker-compose exec app php artisan db:wipe docker-compose exec app php artisan migrate
配置 Eloquent 模型关系
数据库表现在已经设置好了,但是你仍然需要配置 Eloquent 模型来定义它们之间的关系。
在 List 模型(即关系的 one 一侧)上,您将设置一个名为 links 的新方法。 此方法将作为代理访问与每个列表相关的链接,使用父 Illuminate\Database\Eloquent\Model 类中的 hasMany 方法。
在您的代码编辑器中,打开文件 app/Model/LinkList.php。 将当前通用代码替换为以下内容:
应用程序/模型/LinkList.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class LinkList extends Model
{
use HasFactory;
public function links()
{
return $this->hasMany(Link::class);
}
}
完成后保存文件。
接下来,您将编辑关系的 many 端以包含对 List 模型的引用,以便链接可以访问它们各自的列表。 这是通过父 Model 类的 belongsTo 方法完成的。 此方法用于定义一对多关系的反面。
在代码编辑器中打开 Link 模型:
app/Model/Link.php
将 Link.php 文件中的当前内容替换为以下代码:
应用程序/模型/Link.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Link extends Model
{
public function link_list()
{
return $this->belongsTo(LinkList::class);
}
}
完成后保存文件。
随着两个模型的更新,您的数据库现在已完全配置,但它目前是空的。 在本系列的下一部分中,您将学习如何使用 Eloquent 模型在数据库中插入新记录。