framework icon indicating copy to clipboard operation
framework copied to clipboard

URL::defaults() + route group prefix causes positional parameter misalignment in route() calls

Open ibilalkhilji opened this issue 4 months ago • 10 comments

Laravel Version

12.22.1

PHP Version

8.2.3

Database Driver & Version

No response

Description

When a route has a parameter in the group prefix (e.g. {workspace:uuid?}) and its value is set via URL::defaults() in middleware, calling route() with positional parameters for other route parameters results in Laravel incorrectly assigning values.

The prefix parameter gets overwritten by the first positional parameter, and the intended parameter is left missing — often causing errors or producing URLs with an empty ?workspace= query string.

Note: this works without any issues in v12.3.0

Steps To Reproduce

  1. Define routes:
Route::group(['prefix' => 'app/{workspace:uuid?}', 'as' => 'app.', 'middleware' => [EnsureCurrentWorkspace::class]], function () {
        Route::get('', function (Workspace $workspace) {
            return view('dashboard');
        })->name('dashboard');

        Route::group(['prefix' => 'customers', 'as' => 'customers.', 'controller' => CustomerController::class], function () {
            Route::get('', 'index')->name('index');
            Route::get('create', 'create')->name('create');
            Route::post('create', 'store')->name('store');
            Route::get('modify/{customer}', 'modify')->name('modify');
            Route::post('modify/{customer}', 'update')->name('update');
            Route::delete('delete/{customer}', 'destroy')->name('delete');
        });
});
  1. In Middleware:
class EnsureCurrentWorkspace
{
    /**
     * Handle an incoming request.
     *
     * @param Closure(Request): (Response) $next
     */
    public function handle(Request $request, Closure $next): Response
    {
        if ($request->user() && $request->route()->parameter('workspace') != null) {
            auth()->user()->workspaces->where('id', $request->route()->parameter('workspace')->id)->firstOrFail();
            URL::defaults(['workspace' => $request->route()->parameter('workspace')->uuid]);
        } else if ($workspace = Workspace::where('uuid', $request->route()->parameter('workspace'))->first()) {
            URL::defaults(['workspace' => $workspace->uuid]);
        } else
            if ($request->path() != 'workspaces')
                return Redirect::to('workspaces');
        return $next($request);
    }
}
  1. Route Call:
route('app.customers.modify',$customer->id)

Expected Behavior Should generate: /app/7b1c3cbe-675e-43cc-aed6-55bc36e7f79a/customers/123

Actual Behavior

Illuminate\Routing\Exceptions\UrlGenerationException
Missing required parameter for [Route: app.customers.modify] [URI: app/{workspace?}/customers/modify/{customer}] [Missing parameter: customer].

View:

<a href="{{ route('app.customers.modify',$customer->id) }}" class="btn btn-sm btn-primary">Edit</a>

When writing the route like:

<a href="{{ route('app.customers.modify',['customer'=>$customer->id]) }}" class="btn btn-sm btn-primary">Edit</a>

It works without any issues but have to rewrite everywhere and its too hectic for bigger projects

ibilalkhilji avatar Aug 10 '25 10:08 ibilalkhilji