Создание SPA CRUD на Laravel Inertia

Laravel Inertia.js CRUD

Inertia.js — это еще один способ создания SPA (одностраничного приложения). Это не фреймворк и не замена существующих способов. Вся прелесть Inertia.js заключается в том, что нам не нужно поддерживать отдельные API-маршруты, она автоматически передает данные с сервера на клиент как входные параметры для Vue. Вам будет более понятно, когда мы начнём создавать наше CRUD-приложение. CRUD (Create — Создание, Read — Чтение, Update — Обновление и Delete — Удаление). Inertia.js официально поддерживает React, VueJs, Svelte с бэкэндом Laravel, Rails. Мы же будем работать с Laravel и VueJs.

Шаг 01: Установка Laravel

Установите свежую версию фреймворка. Я устанавливаю Laravel 7, но вы также можете работать с Laravel 6.

composer create-project laravel/laravel laravel-inertia-crud

Шаг 02: Установите Laravel UI

Из Laravel 6 был удален UI-каркас и преобразован в отдельный пакет под названием laravel/ui. Нам нужно его установить.

composer require laravel/ui

запустите эту команду для получения каркаса с аутентификацией и vue.

php artisan ui vue --auth

Устанавливаем npm-зависимости и компилим ресурсы

npm install && npm run dev

Шаг 03: Установка Laravel Inertia

Запустите эту команду для установки пакета Laravel Inertia.

composer require inertiajs/inertia-laravel

Создайте файл app.blade.php в каталоге resources/views.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"/>
    <link href="" rel="stylesheet"/>
    <script src="" defer></script>
</head>
<body>

<div class="container">
    <div class="row">
        <div class="col-md-12">
            <h2 class="app-title">Laravel Inertia Js CRUD</h2>
        </div>
    </div>
</div>
<hr>
<div class="container">
    <div class="row">
        @inertia
    </div>
</div>

</body>
</html>

Примечание: Мы просто добавили inertia-директиву @inertia, ничего больше не меняя.

устаналиваем inertia & inertia vue

npm install @inertiajs/inertia @inertiajs/inertia-vue

Cкопируйте этот код и вставьте его в файл resources/js/app.js

require('./bootstrap');

import { InertiaApp } from '@inertiajs/inertia-vue'
import Vue from 'vue'

Vue.use(InertiaApp)

const app = document.getElementById('app')

new Vue({
    render: h => h(InertiaApp, {
        props: {
            initialPage: JSON.parse(app.dataset.page),
            resolveComponent: name => require(`./Pages/${name}`).default,
        },
    }),
}).$mount(app)

Примечание. Настройка Laravel Inertia.js завершена. Откройте командную строку и выполните эту команду для слежения за изменением ваших ресурсов и их автоматической компиляции.

npm run watch

Шаг 04: Ресурсный маршрут

Route::resource('admin/contacts', 'ContactController');

Шаг 05: Модель

Сделайте Модель Contact для CRUD-приложения. В этой модели мы объявили public $timestamps = false, потому что в нашей таблице отсутствуют поля created_at и updated_at.

namespace App;

use Illuminate\Database\Eloquent\Model;

class Contact extends Model
{
    public $timestamps = false;
    protected $guarded = [];
}

Шаг 06: CRUD-Контроллер

Создайте контроллер для CRUD-операций модели Contact. Самое интересное, что нам не нужно создавать отдельный маршрут и контроллер для AJAX-операций. В этом контроллере мы всё будем делать как в обычной ванильной Laravel. Об остальном позаботиться магия.

namespace App\Http\Controllers;

use App\Contact;
use Illuminate\Http\Request;
use Inertia\Inertia;

class ContactController extends Controller
{
    
    public function index()
    {
        $data = Contact::all();
        return Inertia::render('contacts/index', ['data' => $data]);
    }
    
    public function store(Request $request)
    {
        Contact::create($request->all());
        return redirect()->back();
    }

    public function update(Request $request)
    {
        if ($request->has('id')) {
            Contact::find($request->input('id'))->update($request->all());
            return redirect()->back();
        }
    }

    public function destroy(Request $request)
    {
        if ($request->has('id')) {
            Contact::find($request->input('id'))->delete();
            return redirect()->back();
        }
    }
}

Примечание: Все как обычно, за исключением того, что в методе index мы используем рендер Inertia. Он отрендерит шаблон resources/js/Pages/contacts/index. Теперь мы должны создать этот файл как обычный vue-компонент.

Шаг 07: CRUD-Шаблон

Создайте файл index.vue в каталоге resources/js/Pages/contacts:

<template>

    <div class="col-md-6">
        <button class="btn btn-sm btn-primary" @click="openModal()">Add New</button>
        <table class="table table-bordered table-condensed">
            <thead>
            <tr>
                <td>Name</td>
                <td>Phone</td>
                <td>Action</td>
            </tr>
            </thead>
            <tr v-for="row in data">
                <td></td>
                <td></td>
                <td width="130">
                    <button @click="edit(row)" class="btn btn-sm btn-primary">Edit</button>
                    <button @click="deleteRow(row)" class="btn btn-sm btn-danger">Del</button>
                </td>
            </tr>
        </table>

        <div class="modal fade" id="modal">
            <div class="modal-dialog">

                <div class="modal-content">
                    <div class="modal-header">
                        <h4 class="modal-title">New Contact</h4>
                    </div>
                    <div class="modal-body">

                        <div class="form-group">
                            <label for="name">Name</label>
                            <input class="form-control" required id="name" v-model="form.name"/>
                        </div>
                        <div class="form-group">
                            <label for="phone">Phone</label>
                            <input class="form-control" required id="phone" v-model="form.phone"/>
                        </div>


                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-default" @click="closeModal()">Close</button>
                        <button type="submit" class="btn btn-primary" v-show="!editMode" @click="save(form)">Save
                        </button>
                        <button type="submit" class="btn btn-primary" v-show="editMode" @click="update(form)">Update
                        </button>
                    </div>
                </div><!-- /.modal-content -->

            </div><!-- /.modal-dialog -->
        </div><!-- /.modal -->

    </div>


</template>

<script>
    export default {
        props: ['data'],
        data() {
            return {
                editMode: false,
                form: {
                    name: null,
                    phone: null,
                },
            }
        },
        methods: {
            openModal: function () {
                $('#modal').modal('show')
            },
            closeModal: function () {
                $('#modal').modal('hide')
                this.reset();
                this.editMode=false;
            },
            reset: function () {
                this.form = {
                    name: null,
                    phone: null,
                }
            },
            save: function (data) {
                this.$inertia.post('/admin/contacts', data)
                this.reset();
                this.closeModal();
                this.editMode = false;
            },
            edit: function (data) {
                this.form = Object.assign({}, data);
                this.editMode = true;
                this.openModal();
            },
            update: function (data) {
                if (!confirm('Sure')) return;
                data._method = 'PUT';
                this.$inertia.post('/admin/contacts/' + data.id, data)
                this.reset();
                this.closeModal();
            },
            deleteRow: function (data) {
                if (!confirm('Sure')) return;
                data._method = 'DELETE';
                this.$inertia.post('/admin/contacts/' + data.id, data)
                this.reset();
                this.closeModal();
            }
        }
    }
</script>

Наше приложение готово. Откройте другую командную строку и запустите сервер командой

php artisan serve

Страница доступна по адресу: http://localhost:8000/admin/contacts

Автор: Harun
Перевод: Алексей Широков

Наш Телеграм-канал — следите за новостями о Laravel.