Обновление записей в базе Laravel Eloquent

Eloquent – это объектно-реляционный преобразователь (ORM), который включен в структуру Laravel по умолчанию. В этой серии статей вы узнаете, как делать запросы к базе данных и как работать с отношениями в Laravel Eloquent. Также вы сможете попрактиковаться на примерах: мы попробуем улучшить демо-приложение с помощью новых моделей и отношений.

Примечание: Все мануалы данной серии можно найти по тегу Laravel Eloquent.

В предыдущем разделе этой серии мы обновили существующую команду Artisan для поддержки новой функции. В нашем демо-приложении есть команды для вставки и удаления ссылок, однако в настоящее время в нем нет команды для редактирования существующих ссылок. Такая команда может быть полезна, например, для перемещения ссылок между списками или для обновления описания ссылки.

В этом руководстве вы создадим новую команду Artisan для обновления существующих ссылок в базе данных.

Откройте терминал и убедитесь, что вы находитесь в корневом каталоге своего проекта, а затем выполните следующую команду, чтобы загрузить новую команду Artisan:

docker-compose exec app php artisan make:command LinkUpdate

У вас появится новый файл LinkUpdate.php, расположенный в app/Console/Commands. Откройте этот файл в любом редакторе кода:

app/Console/Commands/LinkUpdate.php

Этот файл содержит шаблонный код для новой команды Artisan. Сейчас мы изменим его, чтобы команда могла обрабатывать редактирование ссылки при условии ее уникального идентификатора. Вот что будет делать метод handle():

  • Получит предоставленный пользователем идентификатор и проверит наличие ссылки с указанным идентификатором в БД.
  • Если такой ссылки нет в БД, он отобразит сообщение об ошибке и завершит работу.
  • Если действительная ссылка найдена в БД, он предложит пользователю обновить описание ссылки и присвоить ее другому списку.
  • Затем он попросит пользователя подтвердить изменения.
  • После подтверждения он обновит элемент в базе данных.

Сперва давайте добавим пару определений use в начало файла, чтобы впоследствии было проще ссылаться на классы Link и LinkList:

<?php

namespace App\Console\Commands;

use App\Models\Link;
use App\Models\LinkList;
use Illuminate\Console\Command;

...

Чтобы получить id ссылки, вы должны установить в новой команде link:update обязательный аргумент, тогда пользователи будут обязаны указать этот параметр во время выполнения. Найдите определение сигнатуры команды в верхней части файла и замените его выделенной строкой:

...

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

Если вы сохраните файл и попробуете запустить нашу новую команду без аргументов, вы получите ошибку:

docker-compose exec app php artisan link:update
Not enough arguments (missing: "link_id").

Методу handle() необходимо получить id ссылки, предоставленный пользователем, и найти его в базе данных. Это можно сделать с помощью метода arguments(), который поставляется через родительский класс Command. Затем можно использовать метод find() для запроса в базе данных ссылки с этим идентификатором. Если метод find() возвращает значение null, значит, ссылка с этим id не найдена, поэтому программа должна завершить работу с ошибкой.

...
   /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        $link_id = $this->argument('link_id');
        $link = Link::find($link_id);

        if ($link === null) {
            $this->error("Invalid or non-existent link ID.");
            return 1;
        }

        // obtain updated information from user
    }
...

Если же искомая ссылка найдена в БД, методу нужно запросить у пользователя новую информацию об этой ссылке. Это можно сделать с помощью метода ask, как показано в следующем примере:

...
        if ($link === null) {
            $this->error("Invalid or non-existent link ID.");
            return 1;
        }

        $link->description = $this->ask('Link Description (ENTER to keep current)') ?? $link->description;
        $list_name = $this->ask('Link List (ENTER to keep current)') ?? $link->link_list->title;
...

Этот код будет запрашивать у пользователя обновленное описание и название нового списка, сохраняя при этом текущие значения по умолчанию на случай, если пользователь не предоставит новые данные (чтобы пропустить запрос данных, нужно нажать Enter).

Как только у нас будет вся эта информация, мы можем переходить к обновлению данных. Чтобы пользователь подтвердил изменения перед запуском обновления БД, рекомендуется использовать метод confirm(). Вот как будет выглядеть такой код:

...
        $link->description = $this->ask('Link Description (ENTER to keep current)') ?? $link->description;
        $list_name = $this->ask('Link List (ENTER to keep current)') ?? $link->link_list->title;

        $this->info("Description: $link->description");
        $this->info("Listed in: " . $list_name);

        if ($this->confirm('Is this information correct?')) {
            //code that updates the link
        }
...

Внутри блока if нужно проверить, существует ли запрошенный список, в противном случае команда создаст новый список с предоставленным именем. Затем мы добавим метод associate(), чтобы обновить связь между этой ссылкой и ее родительским списком. Метод save() сохранит изменения в базе данных. Вот так выглядит наш код:

...
        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->link_list()->associate($list)->save();
            $this->info("Updated.");
        }
...

В итоге полный код файла LinkUpdate.php будет иметь следующий вид:

<?php

namespace App\Console\Commands;

use App\Models\Link;
use App\Models\LinkList;
use Illuminate\Console\Command;

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

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Update a link in the database';

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

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        $link_id = $this->argument('link_id');
        $link = Link::find($link_id);

        if ($link === null) {
            $this->error("Invalid or non-existent link ID.");
            return 1;
        }

        $link->description = $this->ask('Link Description (ENTER to keep current)') ?? $link->description;
        $list_name = $this->ask('Link List (ENTER to keep current)') ?? $link->link_list->title;

        $this->info("Description: $link->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->link_list()->associate($list)->save();
            $this->info("Updated.");
        }

        return 0;
    }
}

Читайте также: Создание команд Artisan для управления Laravel

Когда закончите, сохраните файл. Затем используйте команду link:show, чтобы извлечь все ссылки и соответствующие идентификаторы:

docker-compose exec app php artisan link:show

Команда вернет такой результат:

+----+-------------------------------------------------+--------------+----------------------------------+
| id | url                                             | list         | description                      |
+----+-------------------------------------------------+--------------+----------------------------------+
| 1  | https://digitalocean.com/community              | default      | DO Community                     |
| 2  | https://digitalocean.com/community/tags/laravel | default      | Laravel Tutorias at DigitalOcean |
| 3  | https://digitalocean.com/community/tags/php     | default      | PHP Tutorials at DigitalOcean    |
| 4  | https://twitter.com/digitalocean                | social       | Twitter                          |
| 5  | https://dev.to/digitalocean                     | social       | DEV.to                           |
| 6  | https://laravel.com/docs/8.x/eloquent           | default      | Laravel Eloquent Docs            |
+----+-------------------------------------------------+--------------+----------------------------------+

Затем выберите элемент для редактирования. Например, давайте создадим список digitalocean и поместим в него ссылки, указывающие на этот веб-сайт (в нашем случае этому условию соответствуют элементы с идентификаторами 1, 2 и 3).

Чтобы обновить ссылку с ID 1, запустите такую команду:

docker-compose exec app php artisan link:update 1

Вы увидите на экране:

Link Description (ENTER to keep current):
 > DO Community

 Link List (ENTER to keep current):
 > digitalocean

Description: DO Community
Listed in: digitalocean

 Is this information correct? (yes/no) [no]:
 > y

Updated.

Затем снова запустите команду link:show, чтобы увидеть обновленную информацию:

+----+-------------------------------------------------+--------------+----------------------------------+
| id | url                                             | list         | description                      |
+----+-------------------------------------------------+--------------+----------------------------------+
| 1  | https://digitalocean.com/community              | digitalocean | DO Community                     |
| 2  | https://digitalocean.com/community/tags/laravel | digitalocean | Laravel Tutorias at DigitalOcean |
| 3  | https://digitalocean.com/community/tags/php     | digitalocean | PHP Tutorials at DigitalOcean    |
| 4  | https://twitter.com/digitalocean                | social       | Twitter                          |
| 5  | https://dev.to/digitalocean                     | social       | DEV.to                           |
| 6  | https://laravel.com/docs/8.x/eloquent           | default      | Laravel Eloquent Docs            |
+----+-------------------------------------------------+--------------+----------------------------------+

Итак, мы успешно создали команду, которая умеет обновлять наши данные в БД. В следующей части этой серии вы узнаете, как создать команду для удаления списка ссылок.

Tags: , ,

Добавить комментарий