75

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?

imperium2335
  • 23,402
  • 38
  • 111
  • 190
  • 1
    While the question is actually pretty interesting it is very broad. Quoting the close reason: *There are either too many possible answers, or good answers would be too long for this format. Please add details to narrow the answer set or to isolate an issue that can be answered in a few paragraphs.* (I didn't downvote but voted to close) – lukasgeiter Feb 12 '15 at 19:22
  • 1
    @lukasgeiter I added more specifics. – imperium2335 Feb 12 '15 at 19:27
  • Mr. Otwell considers HMVC like an antipattern. Since you have PSR-4 in Laravel 5, you are free to emulate modules with namespaces. Then you should bind a module controller to a view composer. http://laravel.com/docs/5.0/views#view-composers – user2094178 Feb 12 '15 at 19:37
  • @user2094178 Do you have an example of a modular approach using such a method? I have Googled my nuts off and not found anything that details a custom modular app :( – imperium2335 Feb 12 '15 at 19:47
  • Whilst we have a general guidelines here that questions should not be too broad or discursive, I think this is sufficiently grey-area to escape closure (IMO). Being interesting/novel helps, I think. If you find a solution yourself in the future, please do post it as an answer. – halfer Feb 12 '15 at 20:13
  • Here is a hack for Laravel 4 to exactly replicate the hmvc behavior from CodeIgniter: http://forumsarchive.laravel.io/viewtopic.php?id=8664 Maybe with some tweaks to L5 you can get exactly where you want. – user2094178 Feb 12 '15 at 22:47
  • Yeah.. I'm not sure why "modules" are necessary when you are perfectly able to organize these different functionalities into their respective models/controllers. This seems like an unnecessary layer of abstraction to me. If your system is REALLY complex it might just be better to start using microservices. – heisian Jan 19 '17 at 09:01

6 Answers6

37

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!

imperium2335
  • 23,402
  • 38
  • 111
  • 190
  • 1
    Thank you for question and all the efforts to figure out the answer. This is exactly what I need. In my opinion, Laravel 5 structure works perfectly fine for small-to-medium application. However, when it comes to large projects with different modules and different developers, Modularize a L5 app is essential @imperium2335 – DucCuong May 08 '15 at 06:39
  • 1
    Route::group(array('namespace' => 'Modules\Admin'), function() { Route::get('/admin/dashboard','AdminController@index'); }); This always returns error "Class Modules\Admin\AdminController does not exist". I have the same folder structure and my issue is already here. http://stackoverflow.com/questions/33996528/routing-in-laravel-module/33996808?noredirect=1 It would be great if someone could find a solution. – I'm nidhin Nov 30 '15 at 13:13
17

Solution:

Step1: Create Folder “Modules” inside “app/”


Step2: In Modules folder create your Module (Module1( suppose admin Module))

 Inside admin module : create the following folder 

 1. Controllers  (here will your controller files)
 2. Views  (here will your View files)
 3. Models  (here will your Model files)
 4. routes.php (here will your route code in this file)

Similarly, you can create multiple modules

Module2( suppose API )
-Controllers
-Views
-Models
-routes.php

Step3 : Create ModulesServiceProvider.php inside “Modules/” Folder


Step4 : Paste following code inside ModulesServiceProvider.php

<?php

namespace App\Modules;

/**
 * ServiceProvider
 *
 * The service provider for the modules. After being registered
 * it will make sure that each of the modules are properly loaded
 * i.e. with their routes, views etc.
 *
 * @author kundan Roy <query@programmerlab.com>
 * @package App\Modules
 */

use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;

class ModulesServiceProvider extends ServiceProvider {

    /**
     * Will make sure that the required modules have been fully loaded
     *
     * @return void routeModule
     */
    public function boot() {
        // For each of the registered modules, include their routes and Views
        $modules=config("module.modules");

        while (list(,$module)=each($modules)) {

            // Load the routes for each of the modules

            if (file_exists(DIR.'/'.$module.'/routes.php')) {

                include DIR.'/'.$module.'/routes.php';
            }

            if (is_dir(DIR.'/'.$module.'/Views')) {
                $this->loadViewsFrom(DIR.'/'.$module.'/Views',$module);
            }
        }
    }

    public function register() { }

}

Step5 : Add following line inside ‘config/app.php’ file

App\Modules\ModulesServiceProvider::class,

Step6 : Create module.php file inside ‘config’ folder

Step7 : Add following code inside module.php (path => “config/module.php”)

<?php

return [
    'modules'=>[
        'admin',
        'web',
        'api'
    ]
];

Note : You can add your module name whichever you have created. Here there are modules.

Step8 : Run this command

composer dump-autoload
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Kundan roy
  • 3,082
  • 3
  • 18
  • 22
8

A little late, but if you want to use modules in your future projects, i've written a module generator. It generates modules via php artisan make:module name You can also just drop some modules in the app/Modules folder and they are ready to use/work. Take a look. Save some time ;)

l5-modular

Gordon Freeman
  • 3,260
  • 1
  • 22
  • 42
  • 1
    Would it be possible to enable or disable the modules by using a central GUI? Or is your structure not fit for that? – Aschwin Wesselius Jan 18 '16 at 12:21
  • 2
    what do you mean by "central GUI"? by default you can disable the modules in the corresponding `app/config/modules.php` file. If you need to manage your modules dynamically, I would recommend to fork my git and adapt the `ModuleServiceProvider.php` (line 19) the way you need it (FA. get your modules loading list from DB). – Gordon Freeman Jan 18 '16 at 19:02
  • 2
    Also you could set the `modules.enable` config on runtime. FA. `config(['modules.enable' => ['customer', 'contract', 'reporting']]);` – Gordon Freeman Jan 20 '16 at 08:03
  • @GordonFreeman: i've checked ur work. in installation you said to add a line in composer.json . but u didn't tell under what and where exactly that line should be added in composer.json? – saadk May 31 '16 at 12:36
  • 2
    @saadk you must add the line into the `require` node. just like every other php-package which you installed via composer. Take a look at the docs https://getcomposer.org/doc/04-schema.md#package-links – Gordon Freeman May 31 '16 at 13:19
3

You can also use pingpong-labs

documentations Here.

Here is an example.

You can just install and check the process.

Note: I am not advertising. Just checked that cms built on Laravel with module support. So thought that might be helpful for you and others.

Jnanaranjan
  • 1,304
  • 15
  • 31
2

Kundan roy: I liked your solution but I copied your code from StackOverflow, I had to change the quotes and semi-quotes to get it working - I think SOF replace these. Also changed Dir for base_path() to be more inline with Laravel's (new) format.

namespace App\Modules;

/**
* ServiceProvider
*
* The service provider for the modules. After being registered
* it will make sure that each of the modules are properly loaded
* i.e. with their routes, views etc.
*
* @author kundan Roy <query@programmerlab.com>
* @package App\Modules
*/

use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;

class ModulesServiceProvider extends ServiceProvider
{

/**
* Will make sure that the required modules have been fully loaded
* @return void routeModule
*/
   public function boot()
{
    // For each of the registered modules, include their routes and Views
    $modules = config("module.modules");

    while (list(,$module) = each($modules)) {

        // Load the routes for each of the modules
        if(file_exists(base_path('app/Modules/'.$module.'/routes.php'))) {
            include base_path('app/Modules/'.$module.'/routes.php');
        }

        // Load the views                                           
        if(is_dir(base_path('app/Modules/'.$module.'/Views'))) {
            $this->loadViewsFrom(base_path('app/Modules/'.$module.'/Views'), $module);
        }
    }
}

public function register() {}

}
gabrielkolbe
  • 145
  • 9
0

pingpong/modules is a laravel package which created to manage your large laravel app using modules. Module is like a laravel package for easy structure, it have some views, controllers or models.

It's working in both Laravel 4 and Laravel 5.

To install through composer, simply put the following in your composer.json file:

{
    "require": {
        "pingpong/modules": "~2.1"
    }
}

And then run composer install to fetch the package.

To create a new module you can simply run :

php artisan module:make <module-name>

- Required. The name of module will be created. Create a new module

php artisan module:make Blog

Create multiple modules

php artisan module:make Blog User Auth

for more visit: https://github.com/pingpong-labs/modules

Sagar Naliyapara
  • 3,971
  • 5
  • 41
  • 61