php – Laravel 7.1 – URL::defaults() not working in high priority middleware-ThrowExceptions

Exception or error:

I am using subdomain routing heavily within my project, as it’s a multi-tenant application with each tenant having their own subdomain.

As a result, all of my routes are wrapped in:

Route::domain('{tenant}.'.config('app.base_url'))->group(function () {
    // My routes here!
});

To use the route() helper within my code, I need to pass it all of the route parameters associated with it. Every single route has tenant associated with it, so I constantly found myself repeating code and writing route('my-route-name', ['tenant' => $request->route('tenant')]);

I’ve created a middleware with the following code in it:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use URL;

class SetTenantFromRequest
{
    public function handle(Request $request, Closure $next)
    {
        list($subdomain) = explode('.', $request->getHost(), 2);
        URL::defaults(['tenant' => $subdomain]);

        return $next($request);
    }
}

And placed it in the HTTP Kernel.php file like so:

protected $middleware = [
    TrustProxies::class,
    CheckForMaintenanceMode::class,
    ValidatePostSize::class,
    TrimStrings::class,
    ConvertEmptyStringsToNull::class,
    WebHeaders::class,
    SetLanguage::class,
    SetTenantFromRequest::class,
];

// Removed for brevity...
protected $middlewarePriority = [
    StartSession::class,
    ShareErrorsFromSession::class,
    SetTenantFromRequest::class,
    Authenticate::class,
    ThrottleRequests::class,
    AuthenticateSession::class,
    SubstituteBindings::class,
    Authorize::class,
];

I had to add it to the $middlewarePriority array as it needs to run before the Authenticate middleware. Since Authenticate calls return route('login');, I need that URL parameter available beforehand.

Now with doing all of this, I still get the following error thrown from the Authenticate middleware: Missing required parameters for [Route: login] [URI: login].

If I run ddd(URL::getDefaultParameters()); within the Authenticate middleware, it prints an empty array. However if I run the same ddd(...) within the SetTenantFromRequest middleware, it shows the tenant in there as I expect it to be.

Does anyone have an idea on how I can solve this problem?

How to solve:

Moving this from the global middleware stack to the web middleware stack alleviates the issue.

This forces me to add the tenant parameter to the route(...) call within my Authenticate middleware, but it does allow me to forgo it everywhere else.

Leave a Reply

Your email address will not be published. Required fields are marked *