I have a categories table that looks like this:
-- id -- parent_id -- name
1 0 electronics
2 1
I propose you change your URLs so they have a part that will be used for routing and one that will be used for SEO purposes. Here's what I mean:
/products/view/{product_id}/{category_name}/{category_name}/{etc}/{product_name}
/products/category/{category_id}/{category_name}/{category_name}/{etc}
This has the advantage that you can ignore the fact that you won't always have the same numbers of categories. Your routing only depends on the first few segments of the URL.
Route::get('products/view/{id}/{seo-slug?}', array('as' => 'product', function($id, $seoSlug){
$product = Product::find($id);
// ...
}))->where('seo-slug', '.*');
Route::get('products/category/{id}/{seo-slug?}', array('as' => 'category', function($id, $seoSlug){
$category = Category::find($id);
// ...
}))->where('seo-slug', '.*');
Now when it comes to generating links you will have a hard time just using Laravels helper functions. Let's create our own. One way is to add a function to the Product and Category models. (You could also write a function that's independent of the models, the core functionality stays the same)
public function getUrl(){
$categoryNames = array('cat1', 'cat2', 'cat3'); // use/create a function on the category model that uses recursion to determine all the categories of the tree
$seoSlug = implode('/', $categoryNames);
// ... maybe add other stuff to $seoSlug
return route('product', array($this->id, $seoSlug));
}
public function getUrl(){
$categoryNames = array('cat1', 'cat2', 'cat3'); // use the same function as above
$seoSlug = implode('/', $categoryNames);
// ... maybe add other stuff to $seoSlug
return route('category', array($this->id, $seoSlug));
}
If you want, you can now redirect URLs that have a wrong SEO slug. Meaning it would also be possible to just enter:
/products/view/183
This can also serve as some kind of URL shortening for sending links in emails etc.
To validate the URL and then redirect you can just compare the current URL with a "freshly" generated one. Like this:
Route::get('products/view/{id}/{seo-slug?}', array('as' => 'product', function($id, $seoSlug){
$product = Product::find($id);
$productUrl = $product->getUrl()
if(Request::url() !== $productUrl){
return Redirect::to($productUrl);
}
// ...
}))->where('seo-slug', '.*');
Oh and Merry late Christmas to you too!