How to structure a modular app in Laravel 5?

imperium2335 picture imperium2335 · Feb 12, 2015 · Viewed 38.9k times · Source

I would like to divide my application in modules. For instance, there would be a "core" modules that contains the basic login functionality, app layout/formatting (CSS etc), user management and a diary.

Later on I may create other modules like a contact manager that can easily be added or removed from the application.

There would be some logic in the apps navigation for determining which modules are present and to show/hide the links to them.

How can I do this in terms of directory structure, namespaces and anything else that's needed?


I am looking at creolab/laravel-modules but it states that it is for Laravel 4. Can I still use it with 5 in exactly the same way?

The documentation says to place models, controllers and views within each module directory, but how does this work with routes? Ideally I would like each module to have its own routes.php file. How will all of this work with the stuff in the http and the resources directory?


I was thinking of something like this:

Module idea

But I have no idea how I would get it to work.


I have just tried the tutorial here:

http://creolab.hr/2013/05/modules-in-laravel-4/

With no extra libraries etc, just pure Laravel 5.

I seem to have hit a brick wall with an error message:

FatalErrorException in ServiceProvider.php line 16:
Call to undefined method Illuminate\Config\Repository::package()

Regarding the following:

<?php namespace App\Modules;

abstract class ServiceProvider extends \Illuminate\Support\ServiceProvider
{

    public function boot()
    {
        if ($module = $this->getModule(func_get_args())) {
            $this->package('app/' . $module, $module, app_path() . '/modules/' . $module);
        }
    }

    public function register()
    {
        if ($module = $this->getModule(func_get_args())) {
            $this->app['config']->package('app/' . $module, app_path() . '/modules/' . $module . '/config');

// Add routes
            $routes = app_path() . '/modules/' . $module . '/routes.php';
            if (file_exists($routes)) require $routes;
        }
    }

    public function getModule($args)
    {
        $module = (isset($args[0]) and is_string($args[0])) ? $args[0] : null;

        return $module;
    }

}

What is causing this and how can I fix it?


Got my head around this a bit more now. Got my package/module routes and views working which is great:

abstract class ServiceProvider extends \Illuminate\Support\ServiceProvider
{

    public function boot()
    {
        if ($module = $this->getModule(func_get_args())) {
            include __DIR__.'/'.$module.'/routes.php';
        }
        $this->loadViewsFrom(__DIR__.'/'.$module.'/Views', 'core');
    }

    public function register()
    {
        if ($module = $this->getModule(func_get_args())) {

        }
    }

    public function getModule($args)
    {
        $module = (isset($args[0]) and is_string($args[0])) ? $args[0] : null;

        return $module;
    }

}

I have one last question, how would I load all my controllers from inside my package, much like how the loadViewsFrom() method works?

Answer

imperium2335 picture imperium2335 · Feb 12, 2015

I seem to have figured it all out.

I'll post it here in case it helps other beginners, it was just about getting the namespaces right.

In my composer.json I have:

...
"autoload": {
    "classmap": [
        "database",
        "app/Modules"
    ],
    "psr-4": {
        "App\\": "app/",
        "Modules\\": "Modules/"
    }
}

My directory and files ended up like this:

enter image description here

I got my Core module router.php to work by wrapping my controllers for that module in a group specifying the namespace:

Route::group(array('namespace' => 'Modules\Core'), function() {
    Route::get('/test', ['uses' => 'TestController@index']);
});

I imagine when I come to doing my models for the package it will be a similar case of getting the namespaces right.

Thanks for all your help and patience!