Квест → Как хакнуть форму
Прошли: 77
Этот функционал нельзя назвать новым, и route model binding уже давно есть в Laravel, но в Laravel 5.2 он стал ещё проще.
Давайте предположим, что у нас есть некий стандартный роут привязанный к URL-у и выглядит это как-то так:
Route::get('shoes/{id}', function ($id) { $shoe = Shoe::findOrFail($id); // некий ваш код });
Это тот самый кейс, который встречается очень часто. Было бы неплохо, если бы вам не приходилось бы каждый раз писать строчку с findOrFail
, а просто как-то рассказать роутеру Laravel-а, что этот роут предоставляет Shoe
? И это возможно. В вашем сервис—провайдере роутинга вы можете просто указать, что $router->model('shoe', 'App\Shoe');
. Это означает, что "каждый раз, когда у роута есть параметр с именем shoe
, это ID, представляющий экземпляр App\Shoe
". Это позволяет вам избавиться от строки с findOrFail
и переписать вышеприведенный код примерно так:
Route::get('shoes/{shoe}', function ($shoe) { // некий ваш код });
В Laravel 5.2 это стало ещё проще. Просто пропишите тип передаваемого параметра в вышеприведённом Closure (или в вашем методе контроллера) и назовите параметр также как параметр роута. Вот и всё, это будет автоматически восприниматься как привязка модели:
Route::get('shoes/{shoe}', function (App\Shoe $shoe) { // Do stuff });
И, как вы понимаете, теперь вы можете применять такую привязку без надобности прописывать что-либо в сервис-провайдере роутинга. Easy!
Вот и весь фольклор по поводу неявной привязки модели к роуту.
Эти функции не являются новыми в 5.2, и поэтому не относятся к неявной привязке модели, но, кажется, они не особо известны, поэтому хотелось бы о них рассказать.
Если при привязке модели к роуту вы хотите настроить свою логику по поиску и возврату экземпляра вашей модели, вы можете передать анонимную функцию (Closure) в качестве второго параметра в метод явной привязки вместо передачи имени класса:
$router->bind('shoe', function ($value) { return App\Shoe::where('slug', $value)->where('status', 'public')->first(); });
Также вы можете настроить исключения, которые выбрасываются при привязке моделей к роуту (если не удалось найти экземпляр модели), передав анонимную функцию в качестве третьего параметра:
$router->model('user', 'App\User', function () { throw new NotFoundHttpException; });
По умолчанию Laravel предполагает, что Eloquent-модель соотносится с сегментом URL по столбцу id
. (Прим. переводчика: точнее используется указанный первичный ключ). Но что если вы хотите, чтобы она всегда соотносилась по «читаемому» адресу, как в примере выше с изменённой логикой привязки shoe?
Eloquent реализует интерфейс Illuminate\Contracts\Routing\UrlRoutable
, что означает, что каждый объект Eloquent имеет метод getRouteKeyName()
, который указывает какой столбец следует использовать при поиске экземпляра по сегменту URL-а. По умолчанию это id
, но вы можете переопределить его для любой Eloquent-модели:
class Shoe extends Model { public function getRouteKeyName() { return 'slug'; } }
Теперь вы можете использовать явную или неявную привязку модели к роуту, и она будет искать тот shoe, в котором поле slug
совпадает с сегментом URL. Красота!
Угу, хорошо конечно и приятно. Но вот
Model $model=null
как бы логично иногда, но вместо этого он берёт и хинтит новый инстанс модели :( Можно дальше проверятьisNew()
и прочими костыликами. Ну и при этом перестаёт работать выброс 404-ых исключений (лара не различает пустой слаг или неверный). Короче используйте только если модель является обязательным параметром.