Честно: Livewire — не про «чистую архитектуру» и не про «лучшие практики». Это про «завтра дедлайн, фронтендер слился, давай жахнем CRUD сами». И вот тут начинается магия: ты пишешь на PHP, а у тебя «динамичный интерфейс». Красиво звучит? На деле — очередной костыль. Но иногда именно он тебя и спасает.

1. Ставим Livewire

composer require livewire/livewire

Всё, дальше готовься материться.

2. Делаем модель и миграцию

Нужен список задач. Схема стандартная:

Schema::create('tasks', function (Blueprint $table) {
    $table->id();
    $table->string('title');
    $table->text('description')->nullable();
    $table->boolean('completed')->default(false);
    $table->timestamps();
});

php artisan migrate — и база готова.

3. Генерим Livewire-компонент

php artisan make:livewire tasks

Laravel, как всегда, насоздавал тебе кучу файлов. Спасибо, мать его.

4. Лепим логику

Примерный код внутри Tasks.php:

class Tasks extends Component
{
    public $tasks, $title, $description, $task_id;
    public $isOpen = 0;

    public function render()
    {
        $this->tasks = Task::all();
        return view('livewire.tasks');
    }

    public function store()
    {
        $this->validate([
            'title' => 'required',
            'description' => 'required',
        ]);

        Task::updateOrCreate(['id' => $this->task_id], [
            'title' => $this->title,
            'description' => $this->description
        ]);

        session()->flash('message',
            $this->task_id ? 'Task updated.' : 'Task created.');

        $this->closeModal();
        $this->resetInputFields();
    }
}

Классика жанра: CRUD через одну сущность. Работает быстро, поддерживать больно.

5. Вёрстка

Blade-шаблон выглядит как дешёвый jQuery-клон:

<div>
    <button wire:click="create()">Create Task</button>
    <table>
        <tbody>
            @foreach($tasks as $task)
                <tr>
                    <td>{{ $task->title }}</td>
                    <td>{{ $task->description }}</td>
                    <td>
                        <button wire:click="edit({{ $task->id }})">Edit</button>
                        <button wire:click="delete({{ $task->id }})">Delete</button>
                    </td>
                </tr>
            @endforeach
        </tbody>
    </table>
</div>

На скриншотах в блогах это всегда выглядит «вау, как удобно». А в продакшене — «почему оно тупит, и где мой Vue/React».

Реальность и грабли

  • Говнокод-архитектура.
    Логика, валидация, работа с БД и вёрстка — всё перемешано. Смотришь через месяц и думаешь: «Какой идиот это писал?» Потом вспоминаешь: «А, это был я».
  • Производительность.
    Да, Livewire дёргает сервер на каждый чих. Хотел обновить поле? Готовься к реквесту. Хотел поменять флажок? Ещё один реквест. Удивительно, что оно вообще летает.
  • Юзабилити.
    Пользователь жмёт «Создать задачу», а у тебя всё это падает с SQLSTATE[23000] прямо в браузер. Красота.

Итог

В итоге CRUD на Livewire — это палка о двух концах. Да, можно быстро влепить добавление, редактирование и удаление записей, показать это начальству и выдохнуть. Но платить за скорость потом будешь ты же — когда через месяц залезешь в этот код и поймёшь, что поддерживать всё это удовольствие — боль.