Installation:
composer require mozex/laravel-modules
Publish the config (optional, for customization):
php artisan vendor:publish --provider="Mozex\Modules\ModulesServiceProvider" --tag="config"
Directory Structure:
Create a Modules/ directory at your project root. Each module should be a subdirectory (e.g., Modules/Admin, Modules/Blog).
First Module: Create a basic module structure:
Modules/Blog/
├── config/
├── routes/
│ └── web.php
├── views/
├── migrations/
└── ...
The package auto-discovers and registers:
config/blog.php → config/modules/blog.php).routes/web.php → /blog/*).views/ → resources/views/modules/blog/*).migrations/ → auto-published).First Use Case:
Define a route in Modules/Blog/routes/web.php:
Route::get('/posts', [\App\Http\Controllers\Blog\PostController::class, 'index']);
Access it at /blog/posts without manual registration.
Module Creation:
Use the module:make Artisan command:
php artisan module:make Blog --features=all
Generates a scaffold with common files (routes, migrations, controllers, etc.).
Asset Registration:
Modules/{Module}/views/; they’re auto-loaded as modules.{module}.*.Modules/{Module}/config/. Access via config('modules.blog.key')./{module}/... by default (configurable).Service Providers:
Register providers in Modules/{Module}/Providers/. The package auto-loads them during boot.
Database Migrations: Run module-specific migrations:
php artisan module:migrate Blog
Or all modules:
php artisan module:migrate
Commands & Tasks:
Define Artisan commands in Modules/{Module}/Console/Commands/. Register them via the module’s service provider or use the @module directive in the command class.
Translations:
Place JSON/PO files in Modules/{Module}/lang/. Load via __('modules.blog::key').
Dependency Management:
module:install to install dependencies (e.g., Composer packages) for a module:
php artisan module:install Blog --with="laravel/breeze"
Modules/{Module}/composer.json.Module Isolation:
Modules\{Module}\ (e.g., Modules\Blog\Http\Controllers\PostController).Modules/{Module}/config/module.php:
return [
'prefix' => 'admin', // Overrides route prefix
];
Dynamic Module Loading:
Enable/disable modules at runtime via the Modules facade:
use Mozex\Modules\Facades\Modules;
Modules::enable('Blog');
Modules::disable('Admin');
Testing:
Use module:test to run tests for a specific module:
php artisan module:test Blog
Mock module dependencies in tests via Modules::shouldReceive('isEnabled')->andReturn(true).
APIs & Controllers:
Group API routes in Modules/{Module}/routes/api.php. Use middleware via the module’s service provider:
protected $middleware = [
\App\Http\Middleware\Authenticate::class,
];
Route Conflicts:
/blog/*). Override in module.php:
'route' => [
'prefix' => 'admin/blog',
],
php artisan route:list to check registered routes. Conflicts may arise if two modules define the same route path.Asset Loading Order:
@include or @extends directives if dependencies exist between modules.priority in module.php:
'priority' => 10, // Higher = loaded later
Migration Hell:
php artisan migrate skips module migrations. Always use php artisan module:migrate or php artisan migrate --path=database/migrations/modules.php artisan module:migrate:rollback {module}.Service Provider Collisions:
AppServiceProvider in modules. Use unique names like BlogServiceProvider.config/app.php for registered providers. Use php artisan package:discover to clear cached discoveries if issues arise.Livewire/Filament/Nova Auto-Discovery:
Modules/{Module}/Livewire/.Modules/{Module}/Filament/.Modules/{Module}/Nova/.NovaServiceProvider in the module. Use the --with=nova flag during module:make.Translation Fallback:
modules.{module}::key. Ensure your Blade files use the correct namespace:
{{ __('modules.blog::posts.title') }}
resources/lang/vendor/modules for generated files.Log Module Events:
Enable debug mode in config/modules.php:
'debug' => env('MODULES_DEBUG', false),
Logs module loading events to storage/logs/laravel.log.
Check Module Status:
php artisan module:list
Lists enabled/disabled modules and their status.
Clear Caches: If modules aren’t loading, run:
php artisan config:clear
php artisan view:clear
php artisan route:clear
php artisan module:discover
Environment-Specific Modules:
Disable modules in config/modules.php:
'disabled' => [
'Admin' => env('APP_ENV') !== 'local',
],
Custom Module Events:
Listen to module lifecycle events (e.g., ModulesBooted, ModuleEnabled):
use Mozex\Modules\Events\ModuleEnabled;
ModuleEnabled::listen(function (ModuleEnabled $event) {
Log::info("Module {$event->module} enabled!");
});
Dynamic Module Loading:
Implement Mozex\Modules\Contracts\Module to create custom module logic:
namespace Modules\Custom;
use Mozex\Modules\Module as BaseModule;
class CustomModule extends BaseModule {
public function boot() {
// Custom logic on module boot
}
}
Asset Compilation:
Extend the asset pipeline by publishing assets via Modules/{Module}/Resources/assets/. Use Laravel Mix or Vite with module-specific configs.
API Versioning: Use route middleware to version module APIs:
Route::middleware(['api', 'version:v1'])->group(function () {
// Module routes
});
Define middleware in Modules/{Module}/Http/Middleware/.
Testing Hooks: Override module behavior in tests using facades:
Modules::shouldReceive('getModulePath')
->with('Blog')
->andReturn(base_path('Modules/CustomBlog'));
How can I help you explore Laravel packages today?