@powercoder

Как построить цепочку роута не прибегая использованию модели для алфавитной литеры?

Здравствуйте. Подскажите, как построить цепочку роута так, чтобы ссылка на модель была следующей структуры /genres/f/fantasy, не прибегая использованию модели для алфавитной литеры?

Пробовал способом ниже, но проблема заключается в том, что на третьем уровне вложенности, когда мы изменяем литеру, например, так /genres/g/fantasy- не выводится 404 ошибка, страница всё-равно доступна.

PS. У данной цепочки ещё планируется дополнительная вложенность - модель книги

Route::group(['namespace' => 'Books', 'prefix' => 'genres'], function() {
    //Все жанры
    Route::get('/', 'IndexController')->name('pages.books');

    //Все жанры -> {литера}
    Route::get('/{litera}', 'LiteraController', function ($firstLetter = null) {
        return $firstLetter;
    })->where(['litera' => '[a-z0-9]+'])->name('pages.books.litera');

    //Жанр
    Route::get('/{litera}/{genre}', 'IndexController')->name('pages.genre');
});
  • Вопрос задан
  • 121 просмотр
Пригласить эксперта
Ответы на вопрос 2
gzhegow
@gzhegow
aka "ОбнимиБизнесмена"
Как я вижу тут два способа.

Способ первый. Дерево есть дерево. Сначала строится дерево всего что может быть, потом контроллеры работают с деревом. Если нету в дереве - 404. Здесь будет работать механизм SubstituteBindings, когда ты на входе пишешь LiteraController::literaAction(Category $model), которая по твоей букве ищет категорию, у которой slug - твоя литера - и т.к. её нет - автоматически выбрасывается 404. Делать труднее, изменять труднее, зато потом получаешь все плюшки работы с деревом и возможностью по нему всячески бегать, подсчитывать суммы элементов в нем и так далее.

Способ второй. Твой. Роут работает с любой литерой, а внутри роута pages.books.litera тянет всё что начинается на букву такую-то, и если ничего не вытянул принудительно кидает 404. Это нормальное абсолютно поведение, когда ты бросаешь 404 вручную, а не автоматически. Делать легче, менять легче, плюшек нет. Зато дешевле. Заказчик захочет изменить - надо ПЕРЕ-делывать и наращивать функционал, доделывать - не прокатит.
Ответ написан
iMedved2009
@iMedved2009
Не люблю людей
Ну если вы хотите валидировать это на уровне роутов чисто теоретически можно прописать /genres/{literaAndGenre} где регуляркой проверять что первый символ совпадает с начальным символом слова. Регулярка для этого простая
([a-z])\/\1[^\/]+
Но ввиду того что laravel эту регулярку под себя подправляет - она бьется и не работает в простом виде. Но так сказать нет препятствий патриотам для костылирования.
Route::any('/genres/{literaGenre}', function ($literaAndGenre) {
dump('Got it', explode('/', $literaAndGenre));
})->where(['literaGenre' => '(?P<litera>[a-z]{1})\/(?P=litera)[^\/]+']);


/genres/f/fantasy - будет работать
/genres/g/fantasy - не будет работать

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

З.Ы. Решение дерьмо конечно. Не легче ловить все подобное в контроллер и там при не совпадении выбрасывать 404? Или на уровне middleware или custom model binding?
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы