Ресурсные контроллеры в CRUD приложении Laravel

от автора

Привет, Хабр. В этой статье я хочу поделиться своим опытом использования ресурсных контроллеров в CRUD приложении на фреймворке Laravel — простенькой CRM. Итак начнём.

Проект опубликован как свободное ПО.

Задача

Создать веб-приложение для учёта бизнес-клиентов: карточки организаций и их представителей, заявки, события, договора по принципу CRUD.

Ингредиенты

Будем использовать свободное программное обеспечение. В качестве PHP — фреймворка будем использовать Laravel и Bootstrap в качестве его компонента для построения страниц HTML. И поскольку это обычное CRUD приложение, то будем использовать ресурсные контроллеры для базовых действий: создание (create), чтение (read), модификация (update), удаление (delete).

Приступаем

Создаём проект Laravel, используя Composer:

composer create-project laravel/laravel crm.example.com cd crm.example.com

Подключаем Bootstrap, делаем форму входа для пользователей и собираем через npm:

composer require laravel/ui php artisan ui bootstrap php artisan ui bootstrap --auth npm install npm run dev

Создаём модель для бизнес-клиентов, а также заодно к ней миграцию, фабрику, наполнитель, политику, контроллер и запрос формы:

php artisan make:model Client --all

Остальные модели также. Генерируем миграции для сессий и очередей:

php artisan session:table php artisan queue:table

Создайте по необходимости в папке database/seeder файлы для наполнения базы данных первичными данными, например для создания пользователя-админа:

<?php  namespace Database\Seeders;  use Illuminate\Database\Seeder; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Hash;  class UserSeeder extends Seeder {     public function run()     {         DB::table('users')->insert([             [                 'name' => 'admin',                 'email' => 'admin@example.com',                 'access_level' => 2,                 'password' => Hash::make('твой_пароль')             ]         ]);     } }

Настраиваем миграции. Таблица для клиентов будет выглядеть примерно так:

<?php // ... class CreateClientsTable extends Migration {     public function up()     {         Schema::create('clients', function (Blueprint $table) {             $table->id();             $table->string('fulltitle', 512)->nullable();             $table->string('title', 128)->nullable();             /* ... тут много полей для всяких реквизитов ... */              $table->string('tel', 10)->nullable(); // Телефон             $table->string('comment', 255)->nullable(); // Комментарий             $table->foreignId('creater_id') // какой пользователь создал                 ->nullable()                 ->constrained('users')                 ->cascadeOnUpdate()                 ->nullOnDelete();             $table->foreignId('updater_id') // какой последний пользователь внёс изменения                 ->nullable()                 ->constrained('users')                 ->cascadeOnUpdate()                 ->nullOnDelete();             $table->timestamps();         });     }      public function down()     {         Schema::dropIfExists('clients');     } }

После запускаем миграции с наполнением БД:

php artisan migrate:fresh --seed

:fresh — удалит существующие таблицы в БД.

Итак, в папке app/Http/Controllers будет нас ждать ресурсный контроллер ClientController. Там будут объявлены методы: index, create, store, show, edit, update, destroy.

Метод index должен отображать список клиентов. Напишем так, чтобы он выводил сначала новые записи, разбивая на страницы по 20 записей, используя для вывода Blade шаблон ‘client-index’:

<?php // ... public function index() {   return view('client-index', ['clients' => Client::orderByDesc('id')->paginate(20)]); }

Метод create должен вывести форму для заполнения данных о клиенте и кнопку для добавления его в БД. Мы используем Blade шаблон ‘client-edit’ и для добавления и для редактирования данных, чтобы шаблон понимал, какое именно из этих действий выполняется, мы будем передавать ему переменную edit , где значение 0 — для добавления нового, а 1 — для изменения существующего. Переменную client мы просто заполняем начальными данными из модели Client

<?php // ... public function create() {   return view('client-edit', ['edit' => 0, 'client' => new Client()]); }

Метод edit похож на метод create. Только здесь edit = 1, а переменная client заполняется моделью существующего клиента, переданного через маршрут:

<?php // ... public function edit(Client $client) {   return view('client-edit', ['edit' => 1, 'client' => $client]); }

Метод show отображает карточку клиента:

<?php // ... public function show(Client $client) {   return view('client-show', ['client' => $client]); }

Метод store добавляет нового клиента в БД, а метод update обновляет данные у существующего в БД:

<?php // ... public function store(StoreClientRequest $request) {     $validated = $request->validated();     $client = Client::create($validated);     return redirect()->route('clients.show', $client); }  public function update(UpdateClientRequest $request, Client $client) {     $validated = $request->validated();     $client->fill($validated);     $client->updater_id = Auth::id();     $client->save();     return redirect()->route('clients.show', $client); }

Метод destroy удаляет запись из БД:

<?php // ... public function destroy(Client $client) {   if (Auth::user()->access_level == 2) {     $client->delete();     return redirect()->route('clients.index');   } else {     return null;   } }

Теперь рассмотрим, что такое StoreClientRequest и UpdateClientRequest. Дело в том, что перед внесением записей в БД, мы должны проверить корректность данных и авторизовать действие пользователя, то есть пройти валидацию запроса. Они называются запросами формы и лежат в папке app/Http/Requests. Так будет примерно выглядеть StoreClientRequest, который проверяет данные нового клиента перед добавлением:

<?php  namespace App\Http\Requests;  use Illuminate\Foundation\Http\FormRequest;  class StoreClientRequest extends FormRequest {      */     public function authorize()     {         return ($this->user()->access_level > 0); // имеет ли право пользоваель на это действие     }      public function rules()     {         return [             'fulltitle' => ['nullable', 'string', 'max:512'],             'title' => ['nullable', 'string', 'max:128'],             /* ... тут проверяется много полей для всяких реквизитов ... */             'tel' => ['nullable', 'string', 'max:10'],             'comment' => ['nullable', 'string', 'max:255']         ];     } } 

UpdateClientRequest будет выглядеть примерно также.

Теперь настроим маршруты в routes/web.php:

<?php // ... // объявление маршрутов на входы пользователей, отключив маршруты регистрации, сброса пароля и верификации Auth::routes(['register' => false, 'reset' => false,'verify' => false]);  // ставим посредник auth, чтобы только авторизованные пользователи могли ходить по этим маршрутам Route::group(['middleware' => 'auth'], function() {     Route::resources([         'clients' => ClientController::class,         'clients.representatives' => ClientRepresentativeController::class,         /* тут ещё куча строк */     ]); });

Маршруты для методов ресурсного контроллера создаются автоматически Laravel, не надо для каждого метода прописывать отдельный маршрут. Для объявления маршрутов ресурсного контроллера мы используем Route::resources , передавая массив ресурсных контроллеров. Так для клиентов Laravel создаст следующие маршруты:

  • clients.index

  • clients.show

  • clients.create

  • clients.edit

  • clients.store

  • clients.update

  • clients.destroy

Теперь о 'clients.representatives' => ClientRepresentativeController::class , это объявление маршрутов к методам контроллера вложенных ресурсов. В нашей CRM ведётся учёт представителей бизнес-клиентов. Модель представителей является дочерней для модели клиентов. И чтобы мы могли увидеть, например всех представителей для конкретного клиента по адресу вроде https://crm.example.com/clients/123/representatives, мы создадим контроллер вложенных ресурсов:

<?php  namespace App\Http\Controllers;  use App\Http\Requests\StoreRepresentativeRequest; use App\Models\Representative; use App\Models\Client;  class ClientRepresentativeController extends Controller {     public function index(Client $client)     {         return view('representative-index', ['client' => $client, 'representatives' => Representative::where(['client_id' => $client->id])->orderByDesc('id')->paginate(20)]);     }      public function create(Client $client)     {         return view('representative-edit', ['edit' => 0, 'representative' => new Representative(['client_id' => $client->id])]);     }      public function store(StoreRepresentativeRequest $request, Client $client)     {         $validated = $request->validated();         $representative = new Representative(['client_id' => $client->id]);         $representative->fill($validated);         $representative->save();         return redirect()->route('representatives.show', $representative);     } }

Метод index выведет список представителей для конкретного клиента. Метод create выведет форму для создания представителя, а также укажет для какого клиента он создаётся. Метод store сохранит запись о новом представителе с указанием id клиента.

А для остальных методов нам не нужен контроллер вложенных ресурсов, поскольку каждая существующая запись о представителях имеет уникальный идентификатор, и с ними мы можем взаимодействовать через обычный ресурсный контроллер RepresentativeController. А Laravel нам также создаст маршруты для методов контроллера вложенных ресурсов:

  • clients.representatives.index

  • clients.representatives.create

  • clients.representatives.store

Полностью посмотреть код, в том числе шаблоны Blade вы можете по ссылкеhttps://github.com/deyen01/crm


ссылка на оригинал статьи https://habr.com/ru/post/694176/


Комментарии

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *