Framework: Routing problem with controllers outside of default namespace.

Created on 11 Jun 2015  路  12Comments  路  Source: laravel/framework

If you create a controller outside of the default namespace, you can't route to it with

action('\Package\Controller@getIndex');

The problem is that in the routes file you have to route to the controller with the FQN, with the leading backslash

Route::Controller('route','\Package\Controller');

The leading backslash is then saved to the route.

But the action function in Illuminate/Routing/UrlGenerator.php:540 is deliberately moving any leading slash before matching. This causes any attempts to access this controller method to fail to find a match.

To replicate:

  • Create a controller outside of the default (\App\Http\Controllers) namespace.
  • Route to that controller in the main routes.php file.
  • Try to generate a link to any of the controller methods using action(), in a view, for example.

It will say "method not found".

Removing the "else" condition at Illuminate/Routing/UrlGenerator.php:545 seems to fix the problem, but I don't know if this line is required for some use-case I'm not aware of.

Most helpful comment

When you registering routes in routes.php namespace App\Http\Controllers added automatically.

File routes.php is included from RouteServiceProvider.

https://github.com/laravel/laravel/blob/master/app/Providers/RouteServiceProvider.php#L38

All 12 comments

When you registering routes in routes.php namespace App\Http\Controllers added automatically.

File routes.php is included from RouteServiceProvider.

https://github.com/laravel/laravel/blob/master/app/Providers/RouteServiceProvider.php#L38

Just set $namespace to null in your RouteServiceProvider.
Then you can specify the FQN (without starting backslash though) of the controller.

@lukasgeiter if I remove the namespace then I have to change all my views to use FQN for controllers that are within the default namespace.

Shouldn't it be able to work with a default namespace, but provide exception for controllers outside of it, if you specify with leading backslash?

Not necessarily, you can just create a group with 'namespace' => 'App\Http\Controllers' and put all other routes in there.
I agree that it would be nice if you where able to use a backslash to reference classes from the root namespace, but definitely wouldn't consider the current behavior a bug.

if I remove the namespace then I have to change all my views to use FQN for controllers that are within the default namespace.

Unless you have a way to intelligently swap the root namespace depending on how/where your routes goes. I don't think it's possible to fix this.

@lukasgeiter that doesn't fix it in the views.

@crynobone

call controllers within the default namespace without leading slash, and controllers outside of them _with_ leading slash..

@GrahamCampbell - reason for close?

call controllers within the default namespace without leading slash

Call from where? the view? there no direct link between a controller and a view. Different controller from different namespace could be using the same view. Say layouts.navbar view for example.

@crynobone this whole problem is with the action() function

you can use action() function in view to provide a link to a controller method.

I noticed similar problem with groups, even if you start namespace with '' still default namespace is applied. This makes it impossible to have controllers outside default folder structure unless you want to change RouteServiceProvider. But however you change it it will break compatibility with existing code which uses default controller paths. Currently I solved it by changing formatUsesPrefix function line 428 to:
return isset($old['namespace']) && !(substr($new['namespace'],0,1)=='')
? trim($old['namespace'], '').''.trim($new['namespace'], '')
: trim($new['namespace'], '');
Generally if someone starts namespace with \ he expects it to start from root, so if this change does not brake anything else it could make sense.
Also, in our case we do not add \ in the beginning of nested groups so above code works, however if someone is starting with \ inside subgroups it would break that code. So probably best is to return $new['namespace'] only if length of $old is same as length of starting $old namespace (default one).
This is all hack anyway because way it is solved with RouteServiceProvider together with Router class is not optimal.

Go to RouteServiceProvider.php, create a protected function with something like this:
Route::group([
'namespace' => 'your/folder', //FILE CONTAIN YOUR CONTROLLER
], function ($router) {
require base_path('routes/spotify.php'); // FILE CONTAIN ROUTES
});
Then go to function: map(), in same file (RouteServiceProvider) and add the previous function.
You should have this:

public function map()
{
$this->mapApiRoutes();

    $this->mapWebRoutes();

    $this->yourFunction();
    //
}

protected function yourFunction()
{
Route::group([
'namespace' => 'your/Folder',
], function () {
require base_path('routes/routefile.php');
});
}

and in your "routefile.php" you have to create your routes.
Route::get('/',function() {return 'Hello'};);

Was this page helpful?
0 / 5 - 0 ratings

Related issues

iivanov2 picture iivanov2  路  3Comments

Anahkiasen picture Anahkiasen  路  3Comments

progmars picture progmars  路  3Comments

shopblocks picture shopblocks  路  3Comments

SachinAgarwal1337 picture SachinAgarwal1337  路  3Comments