111

I'm new to Laravel. To try and keep my app organized I would like to put my controllers into subfolders of the controller folder.

controllers\
---- folder1
---- folder2

I tried to route to a controller, but laravel doesn't find it.

Route::get('/product/dashboard', 'folder1.MakeDashboardController@showDashboard');

What am I doing wrong?

Burak
  • 5,252
  • 3
  • 22
  • 30
Tino
  • 3,340
  • 5
  • 44
  • 74

16 Answers16

150

For Laravel 5.3 above:

php artisan make:controller test/TestController

This will create the test folder if it does not exist, then creates TestController inside.

TestController will look like this:

<?php
namespace App\Http\Controllers\test;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class TestController extends Controller
{
    public function getTest()
    {
        return "Yes";
    }
}

You can then register your route this way:

Route::get('/test','test\TestController@getTest');
Nicolapps
  • 819
  • 13
  • 29
Ja22
  • 1,712
  • 1
  • 12
  • 13
75

Add your controllers in your folders:

controllers\
---- folder1
---- folder2

Create your route not specifying the folder:

Route::get('/product/dashboard', 'MakeDashboardController@showDashboard');

Run

composer dump-autoload

And try again

Antonio Carlos Ribeiro
  • 86,191
  • 22
  • 213
  • 204
  • i think you need `artisan dump-autoload` too or is `composer dump-autoload` enough? – reikyoushin Sep 17 '13 at 20:50
  • 1
    For /controllers, just composer. But if you have something in `ClassLoader::addDirectories` you don't have on composer, you'll need artisan too. – Antonio Carlos Ribeiro Sep 17 '13 at 20:53
  • I've suddenly remembered I've encountered something like this.. see my comment on the OP's answer – reikyoushin Sep 17 '13 at 20:55
  • `composer dump-autoload` work for me too. If you use Windows OS, you can use a .bat file to run `composer dump-autoload` instead to type in CMD everytime. This is what I am using: `PUSHD "E:\path\to\non-public" newline START /B "Window 1" composer dump-autoload newline pause` – vinsa Jan 06 '15 at 16:35
  • 7
    What if we have two controllers with the same name in forlder1 and folder2? For instance: admin/PostsController.php and frontend/PostsController.php – Levent Yumerov Apr 19 '16 at 07:40
  • This is still not working for me (`5.4`), is Auth a special folder? I moved a previously working controller from `Controllers` to `Controllers/Auth`, updated namespace, didnt specify the subfolder in `web.php`, left it the same, cleared routes, autoload, and cache, nothing seems to help. – blamb Nov 10 '17 at 01:16
  • I had to add the folders too (e.g. `Folder\Class@method`) – The Onin Sep 26 '19 at 16:33
  • That is really a big added advantage over Symfony for Laravel that really beats Symfony in this situation, because Symfony in this situation is more hard coded with .yaml configuration options to be changed to each controller and each dependency the controller will use in the constructor or the route function itself. You will end up with 200 lines .yaml configuration. Thanks to zero config Laravel that is well architected. – Mostafa A. Hamid May 03 '20 at 09:18
52

For those using Laravel 5 you need to set the namespace for the controller within the sub-directory (Laravel 5 is still in development and changes are happening daily)

To get a folder structure like:

Http
----Controllers
    ----Admin
            PostsController.php
    PostsController.php

namespace Admin\PostsController.php file like so:

<?php namespace App\Http\Controller\Admin;

use App\Http\Controllers\Controller;

class PostsController extends Controller {

    //business logic here
}

Then your route for this is:

$router->get('/', 'Admin\PostsController@index');

And lastly, don't for get to do either composer or artisan dump

composer dump-autoload

or

php artisan dump
BobbyZHolmes
  • 603
  • 6
  • 7
  • Worked for me, as of 1/23/15. This may change later as L5 isn't out yet. – sehummel Jan 23 '15 at 19:16
  • Thanks for this little tidbit. In LV4 you were able to skip the 'use App\Http\Controllers\Controller;' statement because you extended the BaseController which inherits directly from Controller. Not the case in LV5 as it extends Controller directly and the PSR-4 autoloading needs to know where to find the Controller. – Lionel Morrison Apr 07 '15 at 02:04
  • 4
    @user ?php namespace App\Http\Controller\Admin; should be Controller[s] with s at the end – Sven van den Boogaart Jun 01 '15 at 13:34
  • This worked for me, with the caveat that I had to add "-o" to the composer statement e.g.: composer dump-autoload -o – Scott Byers Sep 15 '16 at 22:45
  • This did not work for me, error message now says `App\Http\Controllers\Auth\Controller` not found, why is it append the word `Controller` on there, and losing the actual name of the controller? I think its the slash thats doing that. `-o` didnt help. – blamb Nov 10 '17 at 01:22
  • Ok, i found out why it wasnt working for me, i was extending another controller. I guess i have to extend by full namespace now since this controller is in a subfolder of the controller i need to extend. Finally! – blamb Nov 10 '17 at 01:23
20

For ** Laravel 5 or Laravel 5.1 LTS both **, if you have multiple Controllers in Admin folder, Route::group will be really helpful for you. For example:

Update: Works with Laravel 5.4

My folder Structure:

Http
----Controllers
    ----Api
          ----V1
                 PostsApiController.php
                 CommentsApiController.php
    PostsController.php

PostAPIController:

<?php namespace App\Http\Controllers\Api\V1;

use App\Http\Requests;
use App\Http\Controllers\Controller;   
use Illuminate\Http\Request;

class PostApiController extends Controller {  
...

In My Route.php, I set namespace group to Api\V1 and overall it looks like:

Route::group(
        [           
            'namespace' => 'Api\V1',
            'prefix' => 'v1',
        ], function(){

            Route::get('posts', ['uses'=>'PostsApiController@index']);
            Route::get('posts/{id}', ['uses'=>'PostssAPIController@show']);

    });

For move details to create sub-folder visit this link.

Prashant Pokhriyal
  • 3,727
  • 4
  • 28
  • 40
Ariful Haque
  • 3,662
  • 5
  • 37
  • 59
9

1.create your subfolder just like followings:

app
----controllers
--------admin
--------home

2.configure your code in app/routes.php

<?php
// index
Route::get('/', 'Home\HomeController@index');

// admin/test
Route::group(
    array('prefix' => 'admin'), 
    function() {
        Route::get('test', 'Admin\IndexController@index');
    }
);
?>

3.write sth in app/controllers/admin/IndexController.php, eg:

<?php
namespace Admin;

class IndexController extends \BaseController {

    public function index()
    {
        return "admin.home";
    }
}
?>

4.access your site,eg:localhost/admin/test you'll see "admin.home" on the page

ps: Please ignore my poor English

Mervyn
  • 89
  • 1
  • 3
8

In Laravel 5.6, assuming the name of your subfolder' is Api:

In your controller, you need these two lines:

namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;

And in your route file api.php, you need:

Route::resource('/myapi', 'Api\MyController');
DevonDahon
  • 7,460
  • 6
  • 69
  • 114
6

Just found a way how to do it:

Just add the paths to the /app/start/global.php

ClassLoader::addDirectories(array(

    app_path().'/commands',
    app_path().'/controllers',
    app_path().'/controllers/product',
    app_path().'/models',
    app_path().'/database/seeds',

));
Tino
  • 3,340
  • 5
  • 44
  • 74
  • 5
    Wrong. Since /controllers is already in Laravel's composer.json base, anything below it is automatically autoloaded. You don't need to add /controllers/product on your global.php. – Antonio Carlos Ribeiro Sep 17 '13 at 15:39
  • 1
    @AntonioCarlosRibeiro I've had [this problem](http://stackoverflow.com/questions/18425311/laravel-4-migraterollback-with-path-on-artisan-cli) with trying to put models in folders, but dumping composer and artisan autoloads doesn't seem to work. you have to put them on composer.json or on global.php – reikyoushin Sep 17 '13 at 20:52
  • 2
    It's easy to check: after running composer du, open vendor/composer/autoload_classmap.php and your class must be listed there. – Antonio Carlos Ribeiro Sep 17 '13 at 20:56
6
php artisan make:controller admin/CategoryController

Here admin is sub directory under app/Http/Controllers and CategoryController is controller you want to create inside directory

Dipen
  • 1,056
  • 1
  • 19
  • 36
5

I am using Laravel 4.2. Here how I do it:
I have a directory structure like this one:
app
--controllers
----admin
------AdminController.php

After I have created the controller I've put in the composer.json the path to the new admin directory:

"autoload": {
"classmap": [
"app/commands",
"app/controllers",
"app/controllers/admin",
"app/models",
"app/database/migrations",
"app/database/seeds",
"app/tests/TestCase.php"
]
}, 

Next I have run

composer dump-autoload

and then

php artisan dump-autoload

Then in the routes.php I have the controller included like this:

Route::controller('admin', 'AdminController');

And everything works fine.

Todor Todorov
  • 2,503
  • 1
  • 16
  • 15
5

If you're using Laravel 5.3 or above, there's no need to get into so much of complexity like other answers have said. Just use default artisan command to generate a new controller. For eg, if I want to create a User controller in User folder. I would type

php artisan make:controller User/User

In routes,

Route::get('/dashboard', 'User\User@dashboard');

doing just this would be fine and now on localhost/dashboard is where the page resides.

Hope this helps.

Koushik Das
  • 9,678
  • 3
  • 51
  • 50
5

1) That is how you can make your app organized:

Every route file (web.php, api.php ...) is declared in a map() method, in a file

\app\Providers\RouteServiceProvider.php

When you mapping a route file you can set a ->namespace($this->namespace) for it, you will see it there among examples.

It means that you can create more files to make your project more structured!

And set different namespaces for each of them.

But I prefer set empty string for the namespace ""

2) You can set your controllers to rout in a native php way, see the example:

Route::resource('/users', UserController::class);
Route::get('/agents', [AgentController::class, 'list'])->name('agents.list');

Now you can double click your controller names in your IDE to get there quickly and conveniently.

Yevgeniy Afanasyev
  • 37,872
  • 26
  • 173
  • 191
  • Best answer! Totally consistent with Laravel and built on top of what the framework already provides out of the box. – jfoliveira Mar 13 '20 at 17:52
4

This is for laravel 9.

  1. Organize your controllers in subfolder as you wish:
    controller
    ---folder-1
    ------controllerA
    ------controllerB
    ---folder-2
    ------controllerC
    ------controllerD
  2. use the controllers in the route file
    use App\Http\controllers\folder-1\controllerA;
    .....etc
  3. Write your routes as normal
    Route::get('/xyz', [controllerA::class, 'methodName']);
ucheN
  • 161
  • 1
  • 4
3

I think to keep controllers for Admin and Front in separate folders, the namespace will work well.

Please look on the below Laravel directory structure, that works fine for me.

app
--Http
----Controllers
------Admin
--------DashboardController.php
------Front
--------HomeController.php

The routes in "routes/web.php" file would be as below

/* All the Front-end controllers routes will work under Front namespace */

Route::group(['namespace' => 'Front'], function () {
    Route::get('/home', 'HomeController@index');
});

And for Admin section, it will look like

/* All the admin routes will go under Admin namespace */
/* All the admin routes will required authentication, 
   so an middleware auth also applied in admin namespace */

Route::group(['namespace' => 'Admin'], function () {
    Route::group(['middleware' => ['auth']], function() {            
        Route::get('/', ['as' => 'home', 'uses' => 'DashboardController@index']);                                   
    });
});

Hope this helps!!

Mahesh Yadav
  • 2,416
  • 20
  • 23
1

I had this problem recently with laravel 5.8 but i underestand I should define controller in a right way like this below:

php artisan make:controller SubFolder\MyController  // true

Not like this:

php artisan make:controller SubFolder/MyController  // false

Then you can access the controller in routes/web.php like this:

Route::get('/my', 'SubFolder\MyController@index');
Fuad
  • 896
  • 8
  • 10
0

In my case I had a prefix that had to be added for each route in the group, otherwise response would be that the UserController class was not found.

Route::prefix('/user')->group(function() {
    Route::post('/login', [UserController::class, 'login'])->prefix('/user');
    Route::post('/register', [UserController::class, 'register'])->prefix('/user');
});
askepott
  • 250
  • 3
  • 13
-1

Create controller go to cmd and the type php artisan make:controller auth\LoginController