Route parameters are a very common approach to pass input data to your controller methods. Laravel provides a lot of different features and possiblities for using route parameters in your application.
Recently I had to implement some content pages that are backed by a database table. This means that every content page has a unique slug and this slug is used to lookup the page content in the database.
<?php
// routes.php
Route::get('/imprint', 'ContentController@imprint');
Route::get('/privacy', 'ContentController@privacy');
This route definitions would call the following Controller methods:
<?php
class ContentController {
public function imprint()
{
$content = Content::where('slug', 'imprint')->first();
if (is_null($content)) {
abort(404);
}
return response($content->html);
}
public function privacy()
{
$content = Content::where('slug', 'privacy')->first();
if (is_null($content)) {
abort(404);
}
return response($content->html);
}
}
This code duplication annoys me. I want to have a generic controller action like show
that gets the content slug as a parameter. So I started to refactor my controller:
<?php
class ContentController {
public function show($slug)
{
$content = Content::where('slug', $slug)->first();
if (is_null($content)) {
abort(404);
}
return response($content->html);
}
}
Now the controller code looks clean and should be understandable for others. But the problem is, that this controller action is only useable with route parameters. So I tried to refactor my routes file.
<?php
// routes.php
Route::get('/{slug}', 'ContentController@show');
In the example cases defined above the new route definition would work but it has some downsides. At first all first level domain routes would get matched by this route definition and this is not desired. The second problem that arised for me is that some content pages have a url signature with a different slug, like /imprint
has a slug b2c-imprint
. To get around of this problem I looked for a solution that allows me to define a static route signature and allows me to pass the corresponding slug to the controller method.
The Route
class defines a method called defaults
to set a default parameter value for a given route. This method is the perfect match for my problem.
<?php
// routes.php
Route::get('/imprint', 'ContentController@show')->defaults('slug', 'b2c-imprint');
Route::get('/privacy', 'ContentController@show')->defaults('slug', 'privacy');
This solution allows me to clean up my controller methods and define my routes for the static pages in an easy and understandable way. I’m not totally sure if the use of the defaults
method is intended in such situations but the neatness of the code speaks for it.