Reputation: 13
I use laravel 7 and store following tree structures in database:
Catalogs table:
category1
--category11
--category12
----category121
----category122
--category13
Articles table:
news
--news1
--news2
Вasic Laravel routes looks like:
Route::get('category/{id}', 'categoryController@show');
Route::get('news/{id}', 'newsController@show');
But in this case "category" url's segment is necessary for each catalog's URL and "news" url's segment is necessary for each new's URL
How can I route the following urls with Laravel Routes:
http://sitename.com/category1
http://sitename.com/category1/category11
http://sitename.com/category1/category12/category121
http://sitename.com/news
http://sitename.com/news/news1
?
Upvotes: 0
Views: 1819
Reputation: 39429
You would need a “catch-all” route (registered after all of your other routes if you want all of the path to be configurable).
You could then explode the path on slashes, check each element is a valid category slug and is also a child of the previous category.
// All other routes...
Route::get('/{category_path}', 'CategoryController@show')->where('category_path', '.*');
You could also do this with a custom route binding:
Route::bind('category_path', function ($path) {
$slugs = explode('/', $path);
// Look up all categories and key by slug for easy look-up
$categories = Category::whereIn('slug', $slugs)->get()->keyBy('slug');
$parent = null;
foreach ($slugs as $slug) {
$category = $categories->get($slug);
// Category with slug does not exist
if (! $category) {
throw (new ModelNotFoundException)->setModel(Category::class);
}
// Check this category is child of previous category
if ($parent && $category->parent_id != $parent->getKey()) {
// Throw 404 if this category is not child of previous one
abort(404);
}
// Set $parent to this category for next iteration in loop
$parent = $category;
}
// All categories exist and are in correct hierarchy
// Return last category as route binding
return $category;
});
Your category controller would then receive the last category in the path:
class CategoryController extends Controller
{
public function show(Category $category)
{
// Given a URI like /clothing/shoes,
// $category would be the one with slug = shoes
}
}
Upvotes: 3