Ресурсная маршрутизация в Laravel 12

Фактически, любой CRUD состоит из 7 маршрутов, контроллера и шаблонов. Причем большая часть этого кода идентична, особенно маршруты. Они не содержат логики и всегда строятся по одному и тому же принципу.

Laravel частично заимствовал из Rails еще один механизм, который называется «ресурсная маршрутизация». Он упрощает создание типичных CRUD, за счет полной унификации всех маршрутов и способов их обработки. Вместо описания 7 разных маршрутов, ресурсная маршрутизация позволяет указать один метамаршрут:

<?php

Route::resource('articles', ArticleController::class);

Внутри себя он превращается в те самые семь маршрутов, которые мы реализовывали в предыдущих уроках. Их можно увидеть с помощью команды artisan:

php artisan route:list

+-----------+-------------------------+------------------+---------+
| Method    | URI                     | Name             | Action  |
+-----------+-------------------------+------------------+---------+
| GET|HEAD  | /                       |                  | Closure |
| GET|HEAD  | articles                | articles.index   | index   |
| POST      | articles                | articles.store   | store   |
| GET|HEAD  | articles/create         | articles.create  | create  |
| GET|HEAD  | articles/{article}      | articles.show    | show    |
| PUT|PATCH | articles/{article}      | articles.update  | update  |
| DELETE    | articles/{article}      | articles.destroy | destroy |
| GET|HEAD  | articles/{article}/edit | articles.edit    | edit    |
+-----------+-------------------------+------------------+---------+
# Обратите внимание на имя плейсхолдера. Ниже станет понятно почему здесь article, а не id

Довольно неплохо. В проектах где подобных CRUD много (любой типичный веб-проект), ресурсный маршрутизатор очень помогает. Он не просто сокращает количество кода, но и дает хорошую унификацию. Нужно меньше думать и меньше спорить. Все уже спроектировано.

Следующий шаг – упрощение контроллера. Во-первых, можно сразу сгенерировать контроллер, со всеми нужными обработчиками. Во-вторых, этот контроллер можно интегрировать с нужной моделью:

php artisan make:controller ArticleController --resource --model Article

На выходе получим такой контроллер:

<?php

namespace App\Http\Controllers;

use App\Models\Article;
use Illuminate\Http\Request;

class ArticleController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        //
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        //
    }

    /**
     * Display the specified resource.
     *
     * @param  \App\Models\Article  $article
     * @return \Illuminate\Http\Response
     */
    public function show(Article $article)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  \App\Models\Article  $article
     * @return \Illuminate\Http\Response
     */
    public function edit(Article $article)
    {
        //
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \App\Models\Article  $article
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, Article $article)
    {
        //
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  \App\Models\Article  $article
     * @return \Illuminate\Http\Response
     */
    public function destroy(Article $article)
    {
        //
    }
}

Обратите внимание на параметры обработчиков. Laravel самостоятельно находит нужную сущность и достает ее из базы данных. Это позволяет хоть немного, но сократить код.

Ресурсы могут быть вложенными. Это дает возможность строить пути, отражающие зависимости между сущностями на сайте:

# Примеры с Хекслета

# Урок /courses/{course}/lessons/{lesson}
/courses/js-testing/lessons/asserts
# Список пройденных курсов /u/{user}/courses
/u/mokevnin/courses

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

# Список
/entities/{entity}/subentities

# Сущность
/entities/{entity}/subentities/{subentity}

# Все остальные маршруты строятся по такому же принципу.
# Впереди добавляется /entities/{entity}.

Вложенный ресурс можно генерировать автоматически:

php artisan make:controller ArticleCommentController --resource --model ArticleComment --parent Article

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

<?php
use App\Http\Controllers\ArticleCommentController;

Route::resource('articles.comments', ArticleCommentController::class);

Для вложенного ресурса, в экшены, кроме самой сущности передается и родительская сущность:

<?php

# /articles/{article}/comments/{comment}
# Обе сущности можно получить через параметры
public function edit(Article $article, ArticleComment $comment)
{
    return view('article_comment.edit', compact('article', 'comment'));
}

Если ресурс называется articles.comments, то параметр следует назвать $comment, а не $articleComment. Другими словами, имя параметра выбирается в единственном числе по имени ресурса.

Немного по-другому начинает работать хелпер route. Для построения ссылок, там где участвуют оба ресурса, нужно использовать массив для их передачи:

<?php

route('articles.comments.edit', [$article, $comment]);

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

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