Laravel Localisation messing with Route Resource parameter

1k Views Asked by At

On my second try I implemented a Multi lingual implementation for a site I am working on by using a Route::group that prefixes the {locale} in the first segment of the url using routeMiddleware Kernel. It works very well except when retrieving route Resources with parameters.

The implementation has a hiccup in that for some reason it turns the parameter into %2F{id} (which is not correct) and do not retrieve the resource that my PublicGalleriesController requested. I do not understand why, because when I hover over the generated anchor href I see the correct url format. But when I click it give a 404 Not Found message with the messed up url.

web.php This is my route group that encapsulates all routes with a function

Route::group([
    'prefix' => '{locale}',
    'middleware' => 'setlocale',
], function() {

   // all my routes are within this route group including:
   Route::resource('gallery', 'PublicGalleriesController');

   Auth::routes();

   Route::group(['middleware' => 'auth'], function() {

       ...

   });

});

App/Http/Middleware/Localisation.php Route Middleware that is routed through Kernel.php

public function handle($request, Closure $next)
    {
        \App::setLocale($request->segment(1));
        return $next($request);
    }

PublicGalleriesController.php Retrieves image paths from model and returns it to client view

    public function show($id)
    {
        // Show gallery group images for given group id
        $pics = null;
        $path = null;
        $path = GalleryGroup::find($id);
        
        $pics = Gallery::select('imagefilename', 'group_id')->where('group_id', $id)->orderBy('id', 'asc')->get()->toArray();

        return view('gallery.show', compact('pics', 'path'));
    }

When I hover over a gallery group photo link that is visible on the index.blade it shows in the browser left corner as: localhost/en/gallery/41. The index.blade retrieves the gallery group primary keys and builds html anchor links in a loop: <a href="{{ url(app()->getLocale(), 'gallery/' . $item['id']) }}">{{$item['descrp']}}</a>

When I click this link it should via the PublicGalleriesController run the show function and retrieve all those gallery group photos but instead returns a 404 Not Found with the url in the browser showing localhost/en/gallery%2F41. The %2F I believe is a Url encoded forward slash.

php artisan route:list shows the show resource as follows:

| Domain | Method    | URI                         | Name         | Action   
         | Middleware                              |
+--------+-----------------------------------------+--------------+-----------------------
|        | GET|HEAD  | {locale}/gallery/{gallery}  | gallery.show | App\Http\Controllers\PublicGalleriesController@show   
         | web,setlocale                           |

Can someone please help me to understand why the url is becoming so messy?

Laravel version: 5.6.39

1

There are 1 best solutions below

12
On BEST ANSWER

The signature for the url helper is:

function url($path = null, $parameters = [], $secure = null)

$parameters is an array of parameters, not a path, so it is encoding the / that you are using, since parameters are a segment of the URL not a path.

You can adjust the call to url to have a more full path or use the parameters array as the additional segments, not paths:

url(app()->getLocale() .'/gallery/'. $item['id']); // 1 argument
url(app()->getLocale() .'/gallery', [$item['id']]); // 2 arguments
url(app()->getLocale(), ['gallery', $item['id']]);  // 2 arguments

You can also use the route helper:

route('gallery.show', ['locale' => app()->getLocale(), 'gallery' => $item['id']]);

If you don't want to have to pass locale in for all the URLs you want to generate with the route helper you can adjust your middleware to set a default for this parameter:

public function handle($request, Closure $next)
{
    App::setLocale($locale = $request->route('locale'));

    URL::defaults(['locale' => $locale]); // set default

    return $next($request);
}

Now you don't have to pass that parameter:

route('gallery.show', ['gallery' => ...]);

If you wanted to not have the locale parameter passed to all your route "actions" (Controller methods and closures) that can be done as well. You can add a line like so to that middleware before you return the response:

$request->route()->forgetParameter('locale');