Как работают параметры маршрута/контроллера Laravel?

Я понимаю, что если у меня есть маршрут, скажем, api/users/{id}, то он будет передан функции контроллера как параметр $id.

Однако, если у меня есть маршрут API:

Route::patch('roadmap/{roadmapcourse}', 'RoadmapCourseController@update');

и метод контроллера:

/**
   * Update the specified resource in storage.
   *
   * @param  \Illuminate\Http\Request  $request
   * @param  \App\RoadmapCourse $roadmapcourse
   * @return \Illuminate\Http\Response
   */
  public function update(Request $request, RoadmapCourse $roadmapcourse)
  {
    $data = $request->validate([
      'user_id' => 'required|integer',
      'course_id' => 'required|integer',
      'stage' => 'required|integer',
      'title' => 'required|string',
      'creator' => 'required|string',
      'url' => 'required|string',
      'hours' => 'required',
      'completed' => 'required|boolean'
    ]);

    $roadmapcourse->update($data);

    return response($roadmapcourse, 200);
  }

Затем я отправляю запрос на http://projectname/api/roadmap/2 — тогда 2 передается как параметр функции обновления, не так ли?

Но, судя по внешнему виду функции обновления, ожидается экземпляр RoadmapCourse, а не одна цифра, например «2»?

Ищет ли Laravel в фоновом режиме запись в базе данных для RoadmapCourse с идентификатором 2, а затем вводит ее в функцию как $roadmapcourse?

Это единственное, о чем я могу думать, и я не могу найти никакой документации, объясняющей, что происходит.

P.S. Я также не могу найти никакой документации, касающейся соглашения об именах переменных класса $variable, то есть RoadmapCourse $roadmapcourse, я понимаю, что он делает, просто не могу найти никаких документов.

PPS Я также не могу найти никакой документации, объясняющей «докблоки» над методом контроллера, например.

/**
   * Update the specified resource in storage.
   *
   * @param  \Illuminate\Http\Request  $request
   * @param  \App\RoadmapCourse $roadmapcourse
   * @return \Illuminate\Http\Response
   */

И для чего на самом деле нужны эти объявления '@param'??

Будем признательны за любую помощь или ссылки на документы (я просматривал документы Laravel, но не могу найти ни одного упоминания или какой-либо из этих вещей, поэтому публикую здесь)

Спасибо!


person Paul B    schedule 10.10.2019    source источник
comment
Я не знаю Laravel под капотом достаточно хорошо, чтобы понять все рассуждения, но в вашем примере вы, по сути, создаете экземпляр $roadmapcourse как объект RoadmapCourse. Если бы у вас был просто Request $request, $roadmapcourse, вы могли бы получить доступ к $roadmapcourse как к стандартной переменной, которая была бы тем, что вы указали в URL-адресе, в данном случае 2   -  person Andy Holmes    schedule 11.10.2019
comment
Спасибо, Энди. Да, я понимаю это. В данном случае я на самом деле пытался получить доступ к объекту с идентификатором 2, и код работал — я просто не понимал, почему он работает и что происходит за кулисами. Привязка модели маршрута была ответом.   -  person Paul B    schedule 11.10.2019
comment
Аааа, да, я на самом деле еще не изучал это. Думаю, я буду следовать этому. Спасибо за публикацию!   -  person Andy Holmes    schedule 11.10.2019


Ответы (2)


Ищет ли Laravel в фоновом режиме запись в базе данных для RoadmapCourse с идентификатором 2, а затем вводит ее в функцию как $roadmapcourse?

Да, действительно так. См. https://laravel.com/docs/5.8/routing#route-model-binding для получения дополнительной информации.

Поскольку тип переменной $user указывает на модель App\User Eloquent, а имя переменной соответствует сегменту URI {user}, Laravel автоматически внедрит экземпляр модели, идентификатор которого соответствует соответствующему значению из URI запроса. Если соответствующий экземпляр модели не найден в базе данных, автоматически будет сгенерирован HTTP-ответ 404.

Что касается других вопросов (обратите внимание, в будущем постарайтесь ограничиться одним кратким вопросом), имя переменной не имеет значения; $roadmapcourse может быть чем угодно, если внедренная Модель верна. Если вы не используете RoadmapCourse, он попытается найти любую модель, которую вы передадите, на основе первичного ключа (обычно id).

Для docblocks это стандартное комментирование функций. @param и @return можно анализировать и отображать эти значения в документе REST API, но по умолчанию они ничего не делают, кроме предоставления визуальной ссылки. Вы можете смело игнорировать их, если хотите.

person Tim Lewis    schedule 10.10.2019
comment
Спасибо, Тим, да, я думал о том, чтобы не публиковать 3 вопроса сразу, но я подумал, что тот, кто ответил, может знать ответ на все 3! - person Paul B; 11.10.2019
comment
Без проблем! В этой ситуации все они довольно хорошо взаимосвязаны, так что это не имеет большого значения :) Но просто кое-что, о чем нужно знать; в некоторых случаях могут быть плохо восприняты. - person Tim Lewis; 11.10.2019

Я понимаю, что если у меня есть маршрут, скажем, api/users/{id}, то он будет передан функции контроллера как параметр $id.

Это связано с тем, что параметр будет храниться как обычная переменная.

Однако, если у меня есть маршрут API (...) и мой контроллер выглядит так:

public function update(Request $request, RoadmapCourse $roadmapcourse) { /** ... */ }

Это не работает.

Это связано с тем, что вы пытаетесь использовать привязку модели, но, учитывая ваши имя переменной (и параметр маршрута) Laravel не может разрешить правильный класс.

Если вы сделаете это вместо этого:

Route::patch('roadmap/{roadmapcourse}', 'RoadmapCourseController@update');
public function update(Request $request, $roadmapcourse)
{ //                                     ^^^^^^^^^^^^^^
    dd($roadmapcourse); // you'll get the value
}

Конечно, вы можете указать laravel правильно разрешить вашу переменную пути, чтобы получить запись из вашей базы данных. Для этого вам нужно настроить Явная привязка. Из документов:

Явная привязка

Чтобы зарегистрировать явную привязку, используйте метод model маршрутизатора, чтобы указать класс для данного параметра. Вы должны определить свои явные привязки модели в методе boot класса RouteServiceProvider:

public function boot()
{
    parent::boot();

    Route::model('user', App\User::class);
}

Затем определите маршрут, который содержит параметр {user}:

Route::get('profile/{user}', function (App\User $user) {
    //
});

Итак, в вашем случае попробуйте следующее:

# app/Providers/RouteServiceProvider.php

public function boot()
{
    parent::boot();

    Route::model('roadmapcourse', App\RoadmapCourse::class);
}

Именно тогда Laravel сможет разрешить ваш параметр маршрута:

Route::patch('roadmap/{roadmapcourse}', 'RoadmapCourseController@update');
person Kenny Horna    schedule 10.10.2019