Try Live
Add Docs
Rankings
Pricing
Docs
Install
Theme
Install
Docs
Pricing
More...
More...
Try Live
Rankings
Enterprise
Create API Key
Add Docs
Laravel Modular
https://github.com/saeedvir/laravel-modular
Admin
A powerful modular architecture package for Laravel applications that allows organizing the codebase
...
Tokens:
25,581
Snippets:
272
Trust Score:
8.1
Update:
3 months ago
Context
Skills
Chat
Benchmark
61.3
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# Laravel Modular Laravel Modular is a powerful modular architecture package for Laravel applications that enables developers to organize their codebase into independent, reusable modules with automatic discovery and zero configuration. The package leverages Composer's merge plugin to provide native autoloading, eliminating the need for manual module registration while maintaining optimal performance through built-in caching and lazy loading mechanisms. This package is designed for Laravel 11 & 12 applications running PHP 8.2+, providing a complete module structure including controllers, models, views, routes, migrations, and translations. It features debug-aware logging that respects the APP_DEBUG environment variable, comprehensive Artisan commands for module management, automatic state persistence for enabled/disabled modules, and performance monitoring capabilities. With 23.1% improved peak memory usage compared to alternatives like nWidart/laravel-modules, it offers a lightweight, composer-first approach to modular application architecture. ## Installation Install the package via Composer and configure the merge plugin for automatic module discovery. ```bash composer require saeedvir/laravel-modular ``` ```json { "extra": { "merge-plugin": { "include": ["modules/*/composer.json"] } }, "config": { "allow-plugins": { "wikimedia/composer-merge-plugin": true } } } ``` ```bash # Optional: publish configuration file php artisan vendor:publish --tag=module-config ``` ## Creating a Module Create a new module with complete directory structure, service provider, and configuration. ```bash # Create a new Blog module php artisan module:make Blog # Refresh autoloading to register the module composer dump-autoload ``` ``` # Generated structure: modules/Blog/ ├── app/ │ ├── Console/ │ ├── Http/ │ │ ├── Controllers/ │ │ │ └── BlogController.php │ │ ├── Middleware/ │ │ └── Requests/ │ ├── Models/ │ ├── Providers/ │ │ └── BlogServiceProvider.php │ └── Services/ ├── config/ │ └── config.php ├── database/ │ ├── migrations/ │ ├── seeders/ │ └── factories/ ├── resources/ │ ├── views/ │ └── lang/ ├── routes/ │ ├── web.php │ └── api.php └── composer.json ``` ## Listing All Modules Display all discovered modules with their status (enabled/disabled) and metadata. ```bash php artisan module:list ``` ``` # Output example: +--------+---------+--------------------------------------------------+ | Name | Status | Path | +--------+---------+--------------------------------------------------+ | Blog | Enabled | /var/www/html/modules/Blog | | Shop | Enabled | /var/www/html/modules/Shop | | Admin | Enabled | /var/www/html/modules/Admin | +--------+---------+--------------------------------------------------+ ``` ## Creating Module Models Generate models within a module with optional migrations, factories, and seeders. ```bash # Create a basic model php artisan module:make-model Blog Post # Create model with migration php artisan module:make-model Blog Post --migration # Create model with factory php artisan module:make-model Blog Post --factory # Create model with seeder php artisan module:make-model Blog Post --seed # Create model with all options php artisan module:make-model Blog Post --migration --factory --seed ``` ```php <?php namespace Modules\Blog\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Factories\HasFactory; class Post extends Model { use HasFactory; protected $fillable = ['title', 'slug', 'content', 'published_at']; protected $casts = ['published_at' => 'datetime']; } ``` ## Creating a Module Controller Generate a controller within a specific module with support for API and resource patterns. ```bash # Create a standard controller php artisan module:make-controller Blog PostController # Create an API controller php artisan module:make-controller Blog PostController --api # Create a resource controller with all CRUD methods php artisan module:make-controller Blog PostController --resource ``` ```php <?php namespace Modules\Blog\Http\Controllers; use Illuminate\Http\Request; use Modules\Blog\Models\Post; class PostController extends Controller { public function index() { $posts = Post::latest()->paginate(10); return view('blog::posts.index', compact('posts')); } public function store(Request $request) { $validated = $request->validate([ 'title' => 'required|string|max:255', 'content' => 'required|string', 'slug' => 'required|string|unique:posts' ]); $post = Post::create($validated); return redirect()->route('blog.posts.show', $post->id); } } ``` ## Creating Module Migrations Generate database migrations within a module's migration directory. ```bash # Create a migration for the Blog module php artisan module:make-migration Blog create_posts_table # Run all migrations (includes module migrations) php artisan migrate ``` ```php <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { public function up(): void { Schema::create('posts', function (Blueprint $table) { $table->id(); $table->string('title'); $table->string('slug')->unique(); $table->text('content'); $table->timestamp('published_at')->nullable(); $table->timestamps(); }); } public function down(): void { Schema::dropIfExists('posts'); } }; ``` ## Creating Form Requests Generate form request classes for validation within modules. ```bash php artisan module:make-request Blog StorePostRequest ``` ```php <?php namespace Modules\Blog\Http\Requests; use Illuminate\Foundation\Http\FormRequest; class StorePostRequest extends FormRequest { public function authorize(): bool { return true; } public function rules(): array { return [ 'title' => 'required|string|max:255', 'content' => 'required|string|min:50', 'slug' => 'required|string|unique:posts,slug', 'published_at' => 'nullable|date' ]; } } ``` ## Creating API Resources Generate API resource transformers for consistent JSON responses. ```bash php artisan module:make-resource Blog PostResource ``` ```php <?php namespace Modules\Blog\Http\Resources; use Illuminate\Http\Resources\Json\JsonResource; class PostResource extends JsonResource { public function toArray($request): array { return [ 'id' => $this->id, 'title' => $this->title, 'slug' => $this->slug, 'content' => $this->content, 'published_at' => $this->published_at?->toISOString(), 'created_at' => $this->created_at->toISOString(), 'updated_at' => $this->updated_at->toISOString(), ]; } } ``` ## Defining Module Routes Configure web and API routes with automatic module prefixing. ```php <?php // modules/Blog/routes/web.php use Illuminate\Support\Facades\Route; use Modules\Blog\Http\Controllers\PostController; // All routes automatically prefixed with /blog/ Route::get('/', [PostController::class, 'index'])->name('index'); Route::resource('posts', PostController::class); // Routes accessible at: // GET /blog/ -> blog.index // GET /blog/posts -> blog.posts.index // POST /blog/posts -> blog.posts.store // GET /blog/posts/{id} -> blog.posts.show ``` ```php <?php // modules/Blog/routes/api.php use Illuminate\Support\Facades\Route; use Modules\Blog\Http\Controllers\Api\PostApiController; // All routes automatically prefixed with /api/blog/ Route::get('/posts', [PostApiController::class, 'index']); Route::get('/posts/{id}', [PostApiController::class, 'show']); Route::middleware('auth:sanctum')->group(function () { Route::post('/posts', [PostApiController::class, 'store']); Route::put('/posts/{id}', [PostApiController::class, 'update']); Route::delete('/posts/{id}', [PostApiController::class, 'destroy']); }); // Routes accessible at: // GET /api/blog/posts // GET /api/blog/posts/{id} // POST /api/blog/posts (authenticated) ``` ## Loading Module Views Reference views using the module namespace convention. ```php <?php namespace Modules\Blog\Http\Controllers; use Modules\Blog\Models\Post; class PostController extends Controller { public function index() { $posts = Post::latest()->paginate(10); // Load view from modules/Blog/resources/views/posts/index.blade.php return view('blog::posts.index', compact('posts')); } public function show($id) { $post = Post::findOrFail($id); // Load view from modules/Blog/resources/views/posts/show.blade.php return view('blog::posts.show', compact('post')); } } ``` ## Module Configuration Define and access module-specific configuration values. ```php <?php // modules/Blog/config/config.php return [ 'name' => 'Blog', 'enabled' => true, 'version' => '1.0.0', 'posts_per_page' => 15, 'allow_comments' => true, 'cache_duration' => 3600, ]; ``` ```php <?php // Access configuration anywhere in your application $postsPerPage = config('blog.posts_per_page'); // 15 $allowComments = config('blog.allow_comments'); // true $cacheDuration = config('blog.cache_duration'); // 3600 ``` ## Module Manager API Programmatically interact with modules using the ModuleManager class or Module facade. ```php <?php use Laravel\Modular\Facades\Module; use Laravel\Modular\ModuleManager; // Get all modules $allModules = Module::all(); // Get enabled modules only $enabledModules = Module::enabled(); // Get disabled modules only $disabledModules = Module::disabled(); // Check if module exists if (Module::exists('Blog')) { // Module exists } // Get specific module information $blogModule = Module::get('Blog'); // Returns: ['name' => 'Blog', 'path' => '...', 'enabled' => true, 'provider' => '...'] // Get module path $modulesPath = Module::getPath(); // /var/www/html/modules $blogPath = Module::getPath('Blog'); // /var/www/html/modules/Blog // Create module programmatically Module::create('Shop'); // Delete module programmatically Module::delete('Shop'); // Enable or disable modules programmatically Module::enable('Blog'); Module::disable('Shop'); // Clear module cache Module::clearCache(); // Get performance metrics $metrics = Module::getPerformanceMetrics(); ``` ## Enabling and Disabling Modules Enable or disable modules dynamically with automatic state persistence. ```bash # Disable a specific module php artisan module:disable Blog # Enable a specific module php artisan module:enable Blog # Check status of all modules php artisan module:status ``` ``` # Output example from module:status: +--------+---------+--------------------------------------------------+ | Name | Status | Path | +--------+---------+--------------------------------------------------+ | Blog | Enabled | /var/www/html/modules/Blog | | Shop | Disabled| /var/www/html/modules/Shop | | Admin | Enabled | /var/www/html/modules/Admin | +--------+---------+--------------------------------------------------+ ``` Module states are automatically persisted in `modules/modules.json`. Alternatively, you can configure disabled modules in `config/module.php`: ```php <?php // config/module.php return [ 'path' => base_path('modules'), 'disabled' => [ 'OldBlog', 'LegacyShop', 'DeprecatedAdmin', ], 'cache' => [ 'enabled' => env('MODULE_CACHE_ENABLED', true), 'key' => 'laravel_modular_cache', 'lifetime' => 86400, ], 'auto_register_routes' => true, 'stubs_path' => null, ]; ``` ## Caching Module Discovery Optimize performance by caching module discovery results. ```bash # Cache module discovery for production php artisan module:cache # Pre-calculate and optimize module discovery (recommended for production) php artisan module:optimize # Clear module cache php artisan cache:clear ``` ```php <?php // Manual cache management use Laravel\Modular\Facades\Module; // Clear cache after creating/deleting modules Module::clearCache(); // Cache is automatically refreshed on next discovery $modules = Module::discover(); ``` ## Creating Module Factories Generate model factories for testing within modules. ```bash php artisan module:make-factory Blog PostFactory ``` ```php <?php namespace Modules\Blog\Database\Factories; use Modules\Blog\Models\Post; use Illuminate\Database\Eloquent\Factories\Factory; class PostFactory extends Factory { protected $model = Post::class; public function definition(): array { return [ 'title' => $this->faker->sentence(), 'slug' => $this->faker->slug(), 'content' => $this->faker->paragraphs(5, true), 'published_at' => $this->faker->dateTimeBetween('-1 year', 'now'), ]; } } ``` ## Creating Module Seeders Generate database seeders for populating module data. ```bash php artisan module:make-seeder Blog PostSeeder ``` ```php <?php namespace Modules\Blog\Database\Seeders; use Illuminate\Database\Seeder; use Modules\Blog\Models\Post; class PostSeeder extends Seeder { public function run(): void { Post::factory()->count(50)->create(); // Create featured posts Post::factory()->count(5)->create([ 'published_at' => now(), 'featured' => true, ]); } } ``` ## Creating Module Tests Generate test classes for modules with support for Feature and Unit tests. ```bash # Create a Feature test php artisan module:make-test Blog PostTest --feature # Create a Unit test php artisan module:make-test Blog PostServiceTest --unit # Create a test without specifying type (defaults to Feature) php artisan module:make-test Blog PostControllerTest ``` ## Running Module Tests Execute tests specific to a module. ```bash # Run tests for a specific module php artisan module:test Blog # Run tests for all modules php artisan module:test --all # Run all tests including module tests php artisan test ``` ```php <?php namespace Modules\Blog\Tests\Feature; use Tests\TestCase; use Modules\Blog\Models\Post; class PostControllerTest extends TestCase { public function test_can_list_posts(): void { Post::factory()->count(5)->create(); $response = $this->get('/blog/posts'); $response->assertStatus(200); $response->assertViewHas('posts'); } public function test_can_create_post(): void { $data = [ 'title' => 'Test Post', 'slug' => 'test-post', 'content' => 'This is test content for the post.', ]; $response = $this->post('/blog/posts', $data); $response->assertRedirect(); $this->assertDatabaseHas('posts', ['slug' => 'test-post']); } } ``` ## Removing a Module Delete a module and all its files from the filesystem. ```bash # Remove a module completely php artisan module:remove Blog # Confirm deletion when prompted # This will delete the entire modules/Blog directory # Refresh autoloading after removal composer dump-autoload ``` ## Module Service Provider Customize module bootstrapping, route registration, and resource publishing. ```php <?php namespace Modules\Blog\Providers; use Illuminate\Support\ServiceProvider; use Illuminate\Support\Facades\Route; use Livewire\Livewire; class BlogServiceProvider extends ServiceProvider { public function register(): void { // Register config $this->mergeConfigFrom( __DIR__.'/../../config/config.php', 'blog' ); // Register services $this->app->singleton(BlogService::class); } public function boot(): void { // Load migrations $this->loadMigrationsFrom(__DIR__.'/../../database/migrations'); // Load views $this->loadViewsFrom(__DIR__.'/../../resources/views', 'blog'); // Load translations $this->loadTranslationsFrom(__DIR__.'/../../resources/lang', 'blog'); // Register routes $this->registerRoutes(); // Register Livewire components $this->registerLivewireComponents(); // Publish resources if ($this->app->runningInConsole()) { $this->publishes([ __DIR__.'/../../config/config.php' => config_path('blog.php'), ], 'blog-config'); $this->publishes([ __DIR__.'/../../resources/views' => resource_path('views/vendor/blog'), ], 'blog-views'); } } protected function registerRoutes(): void { Route::group([ 'middleware' => 'web', 'prefix' => 'blog', 'namespace' => 'Modules\Blog\Http\Controllers', ], function () { $this->loadRoutesFrom(__DIR__.'/../../routes/web.php'); }); Route::group([ 'middleware' => 'api', 'prefix' => 'api/blog', 'namespace' => 'Modules\Blog\Http\Controllers\Api', ], function () { $this->loadRoutesFrom(__DIR__.'/../../routes/api.php'); }); } protected function registerLivewireComponents(): void { Livewire::component('blog::post-list', \Modules\Blog\Livewire\PostList::class); Livewire::component('blog::comment-form', \Modules\Blog\Livewire\CommentForm::class); } } ``` ## Creating Module Models Define Eloquent models within module namespaces with proper relationships. ```php <?php namespace Modules\Blog\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Factories\HasFactory; use Modules\Blog\Database\Factories\PostFactory; class Post extends Model { use HasFactory; protected $fillable = [ 'title', 'slug', 'content', 'published_at', 'featured', ]; protected $casts = [ 'published_at' => 'datetime', 'featured' => 'boolean', ]; protected static function newFactory() { return PostFactory::new(); } public function comments() { return $this->hasMany(Comment::class); } public function scopePublished($query) { return $query->whereNotNull('published_at') ->where('published_at', '<=', now()); } } ``` Laravel Modular provides an elegant solution for building scalable Laravel applications through a modular architecture that emphasizes developer productivity and application maintainability. The primary use cases include organizing large monolithic applications into logical, self-contained modules; building multi-tenant applications where each tenant can have custom modules; creating reusable business logic packages that can be shared across multiple projects; and developing microservice-style architectures within a monolithic Laravel application. Teams can work independently on different modules without conflicts, and modules can be dynamically enabled or disabled with automatic state persistence in `modules/modules.json`, ensuring configurations are maintained across deployments without affecting the rest of the application. The package integrates seamlessly with Laravel's existing ecosystem, requiring no changes to standard Laravel development workflows. All Artisan commands, routing, migrations, views, and configuration work exactly as they do in traditional Laravel applications, but organized within module boundaries. The comprehensive command suite includes 17 essential commands covering module creation (`module:make`), model generation with migrations/factories/seeders (`module:make-model`), test scaffolding (`module:make-test`), state management (`module:enable`, `module:disable`, `module:status`), and production optimization (`module:optimize`). The composer-first approach means that module autoloading is handled natively by Composer's PSR-4 specification, eliminating custom autoloader overhead and ensuring optimal performance. With built-in caching, debug-aware logging, and performance monitoring, Laravel Modular is production-ready and designed for high-traffic applications where performance and maintainability are critical requirements.