Framework: Named routes inside domain group fails

Created on 10 Jun 2018  路  8Comments  路  Source: laravel/framework

  • Laravel Version: 5.6.24
  • PHP Version: 7.2.5

Description:

Using route('myroute') inside a template fails with:

Missing required parameters for [Route: myroute] [URI: myroute].

when myroute is defined inside a domain group.

Steps To Reproduce:

Create a brand new Lavavel project with:

# laravel new test

Edit routes/web.php to look like this:

Route::get('/', function () {
    return view('welcome');
});

Route::domain('{subdomain}.test.dev')->group(function () {
    Route::get('/myroute', function(){
        return view('welcome');
    })->name('myroute');

});

Confirm:

#php artisan route:list
+-----------------------+----------+----------+---------+---------+--------------+
| Domain                | Method   | URI      | Name    | Action  | Middleware   |
+-----------------------+----------+----------+---------+---------+--------------+
|                       | GET|HEAD | /        |         | Closure | web          |
|                       | GET|HEAD | api/user |         | Closure | api,auth:api |
| {subdomain}.test.dev | GET|HEAD | myroute  | myroute | Closure | web          |
+-----------------------+----------+----------+---------+---------+--------------+

Add this to your resource/views/welcome.blade.php

<a href="{{ route('myroute') }}">My Route</a>

And view mysubdomain.test.dev in the browser:

ErrorException (E_ERROR)
Missing required parameters for [Route: myroute] [URI: myroute]. (View: /Users/abo/Sites/test/resources/views/welcome.blade.php)

Most helpful comment

@aleangelico Perfect, it worked like a charm!

The only suggestion I would make is to place that bit of code in a service provider or one of the middlewares and then share the variable with all the views rather than passing it from every controllers. Will make life much easier.

I added the code to one of my middlewares as shown below:

\View::share('subdomain', \Route::current()->parameter('subdomain'));

All 8 comments

Since the route has a {subdomain} parameter, you have to specify a value for it:

route('myroute', ['mysubdomain'])

But route() and php artisan route:list do not see things eye to eye. Changing web.php to:

Route::get('/', function () {
    return view('welcome');
});

Route::domain('{subdomain}.test.dev')->group(function ($subdomain) {
    Route::get('/subdomain', function(){
        return "subdomain";
    })->name('home');
});

Route::domain('test.dev')->group(function () {
    Route::get('/system', function(){
        return "system";
    })->name('home');
});

php artisan route:list

| Domain                | Method   | URI       | Name | Action  | Middleware |
+-----------------------+----------+-----------+------+---------+------------+
|                       | GET|HEAD | /         |      | Closure | web        |
| {subdomain}.test.dev | GET|HEAD | subdomain | home | Closure | web        |
| test.dev             | GET|HEAD | system    | home | Closure | web        |
+-----------------------+----------+-----------+------+---------+------------+

But on sub.test.dev using the route('home', ['sub']) renders:

 <a href="https://test.test/system?sub">My Route</a> 

Should be:

 <a href="https://sub.test.test/subdomain">My Route</a> 

And on test.dev using the route('home') renders:

 <a href="https://test.test/system">My Route</a> 

I don't see how to use route() helper in a multitenant system where i group by subdomain, and subdomain is dynamic.

if route() saw the routes like php artisan route:list it would work.

You're defining two routes with the same name. How did you expect laravel to handle this sort of conflict?

By Domain. It's different. Laravel handles it just fine. It's just the route() helper that lags a bit behind.
But this i maybe not a bug. So Im closing it.

By Domain. It's different. Laravel handles it just fine. It's just the route() helper that lags a bit behind.
But this i maybe not a bug. So Im closing it.

I think this is a bug, but the workaround is what @staudenmeir suggested:
route('myroute', ['mysubdomain'])

you can get the group parameter with something like (this is what took me a while to figure out):

public function index()
    {
            $subdomain = Route::current()->parameter('subdomain');
            return view('welcome', compact('subdomain'));
    };

and in your view:
{{ route("home", [$subdomain] )}}

@aleangelico Perfect, it worked like a charm!

The only suggestion I would make is to place that bit of code in a service provider or one of the middlewares and then share the variable with all the views rather than passing it from every controllers. Will make life much easier.

I added the code to one of my middlewares as shown below:

\View::share('subdomain', \Route::current()->parameter('subdomain'));

This is a legit bug.
Passing $subdomain to each route helper manually is not a solution, also the View::share idea is good and does the trick but it is in a way hack.

I've decided to abandon using the route domain group because of this. It's not working great with Laravel Fortify. In the fortify.php config file, you can specify that the fortify routes need to be included in a domain group, but there are downstream consequences. For various features like email verification, Laravel tries to redirect to a named route but with domain grouping enabled, I get the error that it's missing the required parameters. That aside, the user experience, in general, working with domain groups, has not been worth it.

Was this page helpful?
0 / 5 - 0 ratings