0

This route will work just fine for a URL like http://localhost:8080/promos/130-unburdened.pdf

  Route::get('/{report_slug}/{report_code}{burdening_tag?}{extension?}', function($report_slug, $report_code, $burdening_tag='', $extension='') {
    return "report_slug: ${report_slug}<br>report_code: ${report_code}<br>burdening_tag: $burdening_tag<br>extension: $extension";
  });

But if I add another optional parameter before the {extension?}, which is what I really need, it will fail, no matter what:

Route::get('/{report_slug}/{report_code}{burdening_tag?}{something?}{extension?}', function($report_slug, $report_code, $burdening_tag='', $something='', $extension='') {
    return "report_slug: ${report_slug}<br>report_code: ${report_code}<br>burdening_tag: $burdening_tag<br>extension: $extension";
  });

All of the optional parameters have patterns defined, so that they CANNOT match the wrong thing:

Route::pattern('report_code', '[0-9]+');
Route::pattern('burdening_tag', '(-burdened|-unburdened)');
Route::pattern('something', 'X');
Route::pattern('extension', '(\.pdf|\.xlsx|\.xls|\.csv)');
Route::pattern('report_slug',
  '(adplan|adplan-update|adplan-proof'
  .'|scandown'
  .'|promos|promo-updates'
  .'|promos-finance|promos-cost-proof'
  .'|retail-price-proof'
  .'|finance'
  .'|dsd-promos|managed-dsd-promos'
  .'|anchor-group)'
);

And yet one works and the other crashes and burns. What is wrong? Is Laravel limited to 2 optional parameters? Is this a bug in Laravel?

iconoclast
  • 21,213
  • 15
  • 102
  • 138
  • Surely you can't have 2 optional parameters, at least not the way you are doing it? See http://stackoverflow.com/questions/22649764/laravel-routes-with-multiple-optional-parameters and http://stackoverflow.com/questions/22877725/pass-many-optional-parameters-to-route-in-laravel-4 – Ian Aug 01 '14 at 23:19
  • Why can't you have 2 or more optional parameters? The patterns constrain them so Laravel ***ought*** to have no problem matching. – iconoclast Aug 01 '14 at 23:40
  • I'm not trying to handle an arbitrary number of unconstrained parameters, like the 2nd question. And I'm not sure why or how the first question might be relevant. – iconoclast Aug 01 '14 at 23:42
  • They are both about multiple optional routes, which i thought is the same problem you are facing – Ian Aug 01 '14 at 23:47
  • Mine are very different, in that I'm specifying *exactly* what can match (and therefore what can't). And in #1 he has 2 parameters, but I can get 2 parameters working perfectly. – iconoclast Aug 02 '14 at 00:21

1 Answers1

0

Because there is an ambiguity: in your first route, this URL http://localhost:8080/promos/130.pdf should not work even if it's supposed to match the pattern.

Let me explain with a simple example:

Route::pattern('foo', 'A');
Route::pattern('bar', 'B');
Route::get('/test/{foo?}{bar?}',function($foo='',$bar=''){
    return "foo: $foo <br> bar: $bar";
});
// http://localhost:8080/test/AB  => work
// http://localhost:8080/test/A   => work
// http://localhost:8080/test/B   => doesn't work

In the third url, foo parameter is not empty but contains letter B (bar is empty in this case), so it doesn't match "foo pattern", hence NotFoundHttpException

What I try in your case (which work fine if you specify something parameter)

Route::pattern('something', 'X?');
// other patterns 
Route::get('/{report_slug}/{report_code}{burdening_tag?}{something?}{extension?}', function($report_slug, $report_code, $burdening_tag='', $something='', $extension= '') {
    return "report_slug: ${report_slug}<br>report_code: ${report_code}<br>burdening_tag: $burdening_tag <br>something: $something <br>extension: $extension ";
});

But if something parameter is not specified (like in the third example), $extension will be empty and $something will be the extension, so you have just to check if $extension is empty:

$realExtension = $extension ? $extension : $something;

I know it's ugly but I don't really have a good answer, maybe someone can provide a real answer.

Razor
  • 9,577
  • 3
  • 36
  • 51
  • But `$foo` ***cannot*** contain 'B' because the `Route::pattern` constrains it to 'A', so `$foo` should be NULL and `$bar` should be 'B'. Otherwise what's the point of the pattern? So I don't see any ambiguity. `/test/B` should match the route and give you `[$foo => NULL, $bar => 'B']` – iconoclast Aug 02 '14 at 05:16
  • Are you saying that an optional route cannot be matched ***if a previous optional route was not matched***? If that were the case I think it might explain the problem, but it seems like a gaping hole in Laravel routing that doesn't make any sense. – iconoclast Aug 02 '14 at 05:22