Правильный способ вложения контроллеров динамических ресурсов в Laravel при создании REST API

Я нашел хорошую информацию об обработке вложенных контроллеров ресурсов и передаче нескольких ограничений, но, похоже, ничего не нашел по этой конкретной проблеме (вероятно, потому что я неправильно об этом думаю!).

Если я хочу создать следующее в своем API

  • /cars (показать все автомобили)
  • /cars/1 (показать carId = 1)
  • /cars/1/performance (показать производительность для carId=1)
  • /cars/1/performance/parts (показать производительность запчастей для carId=1)
  • /cars/1/performance/parts/1 (показать производительность partId=1 для carId=1)
  • /cars/performance (показать производительность всех автомобилей)
  • /автомобили/производительность/детали
  • /детали
  • /parts/1 и т. д. (то же самое для деталей, что и автомобили выше)

должен ли я создавать маршруты и контроллеры для большинства из них таким образом

Route::group(array('prefix' => 'myAwesomeCarApi'), function()
{
    Route::resource('cars', 'CarsController'); 
    Route::resource('cars/performance', 'CarsPerController');
    Route::resource('cars/performance/parts', 'CarsPerPartsController');
    Route::resource('cars.performance/parts', 'CarsPerPartsController');
    Route::resource('parts', 'PartsController');
    Route::resource('parts/performance', 'PartsPerController');
    etc...
});

или есть какая-то хитрость, которую мне не хватает для создания динамических контроллеров, например, только 3 (CarController, PartsController, PerformanceController) и обработки разных маршрутов в коде?


person Nick    schedule 25.03.2015    source источник


Ответы (1)


Я думаю, что вы ищете вложенные контроллеры ресурсов. Это позволяет вам строить такие маршруты, как /car/1/part/1. Этот маршрут сопоставляется с действием CarPartController@show и передает два параметра: идентификатор автомобиля и идентификатор детали.

С точки зрения производительности автомобилей/деталей, я бы сказал, что это похоже на метод «show» (поскольку производительность не является сущностью сама по себе), поэтому создайте еще один метод в ваших контроллерах, например:

class CarPartController extends Controller {

    public function show($carId, $partId)
    {
        // Show specified part for specified car
    }

    public function performance($carId, $partId)
    {
        // Show the performance for specified part on specified car
    }

}

Тогда ваши маршруты будут выглядеть так:

Route::get('car/{car}/performance', 'CarController@performance');
Route::get('car/{car}/part/{part}/performance', 'CarPartController@performance');

Route::resource('car', 'CarController');
Route::resource('car/{car}/part', 'CarPartController');

Согласно документации Laravel, нересурсные методы должны быть определены до контроллеров ресурсов.

Вы также можете сделать еще один шаг в этом подходе и реализовать привязку модели маршрута, чтобы экземпляры вашей модели Car и Part внедрялись в действия вашего контроллера, а не в идентификаторы:

Route::model('car', 'Car');
Route::model('part', 'Part');

И пример действия контроллера:

public function performance(Car $car, Part $part)
{
    // Show performance for specified part on specified car
}

Надеюсь это поможет.

person Martin Bean    schedule 25.03.2015
comment
Спасибо, это здорово, именно то, что мне нужно. Когда вы только начинаете использовать маршруты, mvc и REST API, есть много концепций, с которыми нужно разобраться, поэтому их применение иногда может сбивать с толку! - person Nick; 25.03.2015
comment
Я предполагаю, что мой дополнительный вопрос заключается в том, как это согласуется с принципами REST, потому что как только я начну использовать Route::get('car/{car}/performance', 'CarController@performance'); разве я не отхожу от строго GET/PUT/DELETE и т.д. принципов REST? - person Nick; 25.03.2015
comment
Как я понял ваше приложение, конечные точки performance просто сопоставляли статистику и возвращали ее, а не были сами по себе сущностью, которую можно было бы обновлять, удалять и т. д. Это правильно? - person Martin Bean; 25.03.2015
comment
Да, точно. Я думаю, что я просто продолжаю думать о производительности как о сущности, которой можно управлять с помощью CRUD, когда все это просто дополнительная функциональность, добавленная к контроллерам Car и Parts для получения сопоставленных данных. (Я полагаю, что вы думаете о данных, которые собираются в реальном времени из автомобиля, их никогда не следует подделывать) - person Nick; 26.03.2015
comment
Ура Мартин, это действительно помогло мне! - person Nick; 26.03.2015
comment
Без проблем. Дайте мне знать, если у вас есть другие вопросы, и я сделаю все возможное, чтобы ответить на них. - person Martin Bean; 26.03.2015
comment
Вам не нужно добавлять сегмент, содержащий подстановочный знак, вы можете написать его так: Route::resource('car.part', 'CarPartController'); - person cdarken; 12.08.2016
comment
@cdarken О чем ваш комментарий? Нет сегмента, содержащего подстановочный знак? - person Martin Bean; 12.08.2016
comment
Я имел в виду это: Route::resource('car/{car}/part', 'CarPartController');. Вы можете опустить часть {автомобиль} и просто написать ее как car.part - person cdarken; 15.08.2016
comment
@cdarken Это не подстановочный знак. Это параметр маршрута. - person Martin Bean; 16.08.2016
comment
@MartinBean, ты прав. И этот параметр будет сгенерирован автоматически, если вы используете точку. - person cdarken; 17.08.2016
comment
Просто убедитесь, что последующий вопрос. Следует ли создать другой PartController для всех действий CRUD и использовать только CarPartController в качестве конечной точки показа? Я собираюсь следовать тому же подходу с Posts и Comments и думаю, что будет более подходящим. Есть ли действия comment CRUD в PostCommentController или есть отдельный, например CommentController ? - person LefterisL; 11.10.2016
comment
@TerisL Это действительно зависит от каждого случая, поскольку нет жесткого и быстрого правила. Для комментариев я бы, наверное, выделил отдельный контроллер (даже если комментарий будет принадлежать посту). Для CRUD-обработки автозапчастей я бы выбрал то, что будет иметь наибольший смысл для пользователя. Будет ли пользователь переходить к детали, сначала пройдя через автомобиль? Если это так, я бы создал вложенный контроллер ресурсов в этом экземпляре. - person Martin Bean; 11.10.2016