Квест → Как хакнуть форму
Прошли: 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-ых исключений (лара не различает пустой слаг или неверный). Короче используйте только если модель является обязательным параметром.