josheli

Laravel: Simple Method for Modules

In my day job, I maintain a fairly large-ish Laravel application. It started out as a few separate vanilla PHP web apps, which I consolidated onto Laravel 4, then upgraded to Laravel 5. I've added a few new apps to the suite as business needs arose.

In the Laravel 4 version, I used creolab/laravel-modules to, well, modularize, the various apps under one Laravel instance. It worked well with a few gotchas, but the package wasn't updated for Laravel 5. At that point I looked at a couple other module packages, but in the end decided it was simple enough to add modules to Laravel.

Assume our namespace is "CorpName".

Add your namespace to composer.json

[js] ... "psr-4": { "App\": "app/", "CorpName\": "app/CorpName/" } ... [/js]

Create a directory structure like the following:

Add your Service Provider to the 'providers' array in config/app.php

[php] ... 'CorpName\Core\Providers\CorpNameServiceProvider', ... [/php]

Create "app/CorpName/Core/Providers/CorpNameServiceProvider.php":

[php]

app['CorpName']->boot(); } /\*\* \* Register the application services. \* \* @return void \*/ public function register() { // $this->app->singleton('CorpName', function($app) { return new Bootstrap($app); }); } } [/php] #### Create "app/CorpName/Core/Bootstrap.php": [php] app = $app; } public function boot() { $this->loadModules(); } /\*\* \* Scan the CorpName/Modules directory for Modules, and load them (routes, views, includes) \*/ public function loadModules() { /\*\* \* @var \Illuminate\Contracts\Filesystem\Filesystem $disk \*/ $disk = \Storage::disk('modules'); $modules = $disk->directories(); $modules\_path = config('filesystems.disks.modules.root'); foreach ($modules as $module) { $module\_path = $modules\_path . '/' . $module; //register routes if($disk->exists("{$module}/routes.php")) { include $module\_path . '/routes.php'; } //set up views if($disk->exists("{$module}/views")) { $this->app['view']->addNamespace($module, $module\_path . '/views'); } //include files if($disk->exists("{$module}/includes")) { $includes = $disk->files("{$module}/includes"); foreach ($includes as $include) { if(substr($include, -4) == '.php') { include\_once $modules\_path . '/' . $include; } } } } } } [/php] Note that I'm using a "modules" storage "disk" configured in "config/filesystem.php": [php] ... 'modules' => [ 'driver' => 'local', 'root' => app\_path().'/CorpName/Modules', ], ... [/php] #### And... That's basically it. You'll probably want a routes.php file in each module, and a views directory, but you can structure your Modules as you see fit. If you use migrations, you'll need to add your module/migrations directory to the autoload classmap in composer.json: [js] ... "autoload": { "classmap": [ "database", "app/CorpName/Modules/ModuleOne/migrations", "app/CorpName/Modules/ModuleTwo/migrations", "app/CorpName/Modules/ZeeAppModule/migrations" ], ... [/js] Also, views can be referenced by module name in your controller and blade templates: Controller: [php] ... return view('ModuleOne::index', $this->data); ... [/php] Blade: [php] ... @extends('ModuleOne::layouts.master') @section('apphead') @include('ModuleTwo::partials.head') @stop ... [/php] This setup has been running in Laravel 5.0 and 5.1 for a year or so without problems. It could probably use some improvements, like caching, but it works as is.