如何在LaravelEloquent中插入新的数据库记录

来自菜鸟教程
跳转至:导航、​搜索

在本系列的前一部分中,您为 LinkListLink 模型之间的 一对多 关系设置了两个模型。 在本节中,您将学习如何使用 Eloquent 模型在数据库中插入链接和列表。 为了限制这项工作的范围,您将使用自定义 Artisan 命令从命令行管理链接和列表,这不需要 Web 表单。

使用 ORM 系统的最大优势之一是能够将数据库表中的行作为代码库中的对象进行操作。 使用 Eloquent,与其他 ORM 一样,对象本身提供了可用于将其持久化到数据库的方法,从而为您节省了编写 SQL 语句和手动管理表中数据的工作。

在 Laravel Eloquent 中处理一对多关系时,您有几个不同的选项来保存相关模型。 在大多数情况下,您需要首先设置表示关系的 one 端的模型,在此演示中是 LinkList 模型,并将其保存到数据库中。 完成此操作后,您将能够在设置关系的 many 端(Link 模型)时引用此模型(保存后表示数据库记录)。 这也意味着您需要首先拥有一个或多个列表才能创建链接。

但是,在创建插入列表的新命令之前,您应该更新现有的 link:new 命令以支持列表功能。

在代码编辑器中打开以下文件:

app/Console/Commands/LinkNew.php

你会看到这样的代码:

应用程序/控制台/命令/LinkNew.php

<?php

namespace App\Console\Commands;

use App\Models\Link;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;

class LinkNew extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'link:new';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Create a New Link';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        $url = $this->ask('Link URL:');

        if (!filter_var($url, FILTER_VALIDATE_URL)) {
            $this->error("Invalid URL. Exiting...");
            return 1;
        }

        $description = $this->ask('Link Description:');

        $this->info("New Link:");
        $this->info($url . ' - ' . $description);

        if ($this->confirm('Is this information correct?')) {
            $link = new Link();
            $link->url = $url;
            $link->description = $description;
            $link->save();

            $this->info("Saved.");
        }

        return 0;
    }
}

handle() 方法是命令执行其过程的地方。 这就是它的作用:

  1. 通过父 Illuminate\Console\Command 类提供的 ask() 方法是一种用于在命令行中获取用户输入的方法。 这将提示用户输入链接,并验证输入以确保它是有效的 URL。
  2. 然后脚本会要求提供可选描述。
  3. 一旦获得 urldescription 的值,脚本将提示使用 confirm() 方法进行确认,该方法可通过父 Illuminate\Console\Command 获得。
  4. 当使用 yyes 提交确认时,脚本将设置一个新的链接对象并使用 save() 方法将其保存到数据库,可通过模型的父级获得Illuminate\Database\Eloquent\Model 类。
  5. 该脚本使用 info 输出方法输出一条消息,通知用户链接已保存到数据库。

返回值注意事项:在bash上运行的命令行应用程序的上下文中,非零返回值用于表示应用程序错误退出,而0表示它成功退出。


如果您现在运行 link:new 命令,它将在完成之前中断,因为数据库希望每个链接都连接到一个列表。 您需要让用户选择链接应包含在哪个列表中,如果用户未提供任何列表,则使用默认列表。

以下代码将要求用户指定一个列表或将其留空以使用默认列表。 然后,它会尝试定位列表或使用指定的 slug 创建一个新列表,以防列表尚不存在。 要检索用户提供的列表,此代码使用 firstWhere 方法根据其 slug 字段查找列表。 最后,它使用可以从 LinkList 对象访问的 links() 关系保存新链接。

LinkNew 命令类中的当前内容替换为:

应用程序/控制台/命令/LinkNew.php

<?php

namespace App\Console\Commands;

use App\Models\Link;
use App\Models\LinkList;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;

class LinkNew extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'link:new';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Create a New Link';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        $url = $this->ask('Link URL');

        if (!filter_var($url, FILTER_VALIDATE_URL)) {
            $this->error("Invalid URL. Exiting...");
            return 1;
        }

        $description = $this->ask('Link Description');
        $list_name = $this->ask('Link List (leave blank to use default)') ?? "default";

        $this->info("New Link:");
        $this->info($url . ' - ' . $description);
        $this->info("Listed in: " . $list_name);

        if ($this->confirm('Is this information correct?')) {
            $list = LinkList::firstWhere('slug', $list_name);
            if (!$list) {
                $list = new LinkList();
                $list->title = $list_name;
                $list->slug = $list_name;
                $list->save();
            }

            $link = new Link();
            $link->url = $url;
            $link->description = $description;
            $list->links()->save($link);

            $this->info("Saved.");
        }

        return 0;
    }
}

完成后保存并关闭文件。 然后,使用以下命令运行命令:

docker-compose exec app php artisan link:new

系统会提示您提供 URL、描述和列表名称,以防您不想将此链接保存到默认列表。

保存新链接后,如果运行 link:show 命令,您应该会看到新链接已添加到结果中。 但是,输出中尚未包含有关列表的信息。 您需要更新 LinkShow 命令以包含显示此信息的列。

在代码编辑器中打开 app/Console/Commands/LinkShow.php 文件:

app/Console/Commands/LinkShow.php

这是该类现在的样子:

应用程序/控制台/命令/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;
    }
}

您会看到当前的 handle() 方法正在获取一定数量的字段并将结果转换为数组。 默认情况下,结果来自 Eloquent 作为 Eloquent 集合,因此此函数将它们转换为数组,以便在 table() 方法中使用该数据。 问题是,当进行数组转换时,您会丢失类模型(LinkLinkList)之间的关系,这使得访问有关链接连接的列表的信息变得更加困难到。

您需要更改此代码,以便它获取完整的 Link 对象,包括数据库中的相关对象。 要创建适合与 table() 方法一起使用的数组,您可以遍历 Link::all() 返回的结果集合。

app/Console/Commands/LinkShow.php 文件中的当前内容替换为以下代码:

应用程序/控制台/命令/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', 'list', 'description' ];
        $links = Link::all();

        $table_rows = [];
        foreach ($links as $link) {
            $table_rows[] = [ $link->id, $link->url, $link->link_list->slug, $link->description ];
        }

        $this->table($headers, $table_rows);

        return 0;
    }
}

现在,如果您运行 link:show 方法,您将看到一个显示列表 slug 的附加列:

Output+----+-----------------------------------------------------------------------------------------+-----------+--------------------------------------+
| id | url                                                                                     | list      | description                          |
+----+-----------------------------------------------------------------------------------------+-----------+--------------------------------------+
| 1  | https://digitalocean.com                                                                | default   | DigitalOcean Website                 |
| 2  | https://digitalocean.com/community/tutorials                                            | tutorials | DO Tutorials                         |
| 3  | initial-server-setup-with-ubuntu-20-04 | tutorials | Initial server setup on ubuntu 20.04 |
+----+-----------------------------------------------------------------------------------------+-----------+--------------------------------------+

在本教程系列的后面,您将更新前端和主路由代码以显示组织成列表的链接。 现在,您将使用命令行来添加、迁移和验证对数据库和模型的更改。

本系列的下一个教程将演示另一种使用 Eloquent 模型在数据库中插入新记录的方法,这次是使用 数据库播种器