Fran Arjona
Fran Arjona

Reputation: 118

Laravel 5 - Routes and variable parameters in controllers

I want to generate SEO friendly URLs like this when searching:
http://www.example.com/search (no filters)
http://**www.example.com/search/region-filter
http://**www.example.com/search/region-filter/city-filter

And to paginate them in this way:
http://www.example.com/search/2 (no filters, page 2)
http://**www.example.com/search/region-filter/2
http://**www.example.com/search/region-filter/city-filter/2

(sorry I can't post more than 2 links because of reputation)

So the second segment can be a filter or a number of page (and the same with the third one).

My Laravel 5 routing file:

Route::pattern('page', '[0-9]+');
...
Route::get('search/{region}/{city}/{page?}', 'SearchController@index');
Route::get('search/{region}/{page?}', 'SearchController@index');
Route::get('search/{page?}', 'SearchController@index');

Routes work fine because of the 'page' pattern, but inside the controller this petition http://**www.example.com/search/2 maps {page} in $region (even using last routing rule):

public function index($region='', $city='', $page='')

Codeigniter parameters are mapped by name, but it looks that Laravel maps them by position, so I always get the first one in $region.

Is it possible to route parameters by name instead of position or use some Laravel alternative to get them in the controller? (I can count segments, but it is an ugly solution for me)

Upvotes: 3

Views: 6191

Answers (1)

Bogdan
Bogdan

Reputation: 44526

You can use the Route::current() method to access the current route and get parameters by name via the parameter method. However there is a problem with your route definitions, which would make the last two routes defined useless.

Because the page parameter in your last two routes is optional, depending on the route path your second and third routes will not match properly, because of the ambiguous definition of the routes. Below you have the test case which proves my point.


If you were to have this in your controller:

public function index()
{
    $route = \Route::current();

    $region = $route->parameter('region');
    $city = $route->parameter('city');
    $page = $route->parameter('page');

    $params = [
        'region' => $region,
        'city' => $city,
        'page' => $page
    ];

    return $params;
}

You'll get the following results for each route:

1. For example.com/search/myregion/mycity/mypage:

{
    "region": "myregion",
    "city": "mycity",
    "page": "mypage"
}

2. For example.com/search/myregion/mypage:

{
    "region": "myregion",
    "city": "mypage",
    "page": null
}

3. For example.com/search/mypage:

{
    "region": "mypage",
    "city": null,
    "page": null
}

So your problem here is not with parameter matching by order or by name, it's with the route definitions. To fix this you can just have the pagination in the query string and drop it altogether the route definitions, because there's absolutely nothing wrong with having your pagination as a query string parameter if it's optional anyway. So your URL would look like this:

example.com/search/myregion/mycity?page=2

You can check the Illuminate\Routing\Route class API to see what other methods you have available there.

Upvotes: 6

Related Questions