# Module System Core PHP Framework uses a modular monolith architecture where features are organized into self-contained modules that communicate through events and contracts. ## What is a Module? A module is a self-contained feature with its own: - Routes (web, admin, API) - Models and migrations - Controllers and actions - Views and assets - Configuration - Tests Modules declare their lifecycle event interests and are only loaded when needed. ## Module Types ### Core Modules (`app/Core/`) Foundation modules that provide framework functionality: ``` app/Core/ ├── Events/ # Lifecycle events ├── Module/ # Module system ├── Actions/ # Actions pattern ├── Config/ # Configuration system ├── Media/ # Media handling └── Storage/ # Cache and storage ``` **Namespace:** `Core\` **Purpose:** Framework internals, shared utilities ### Feature Modules (`app/Mod/`) Business domain modules: ``` app/Mod/ ├── Tenant/ # Multi-tenancy ├── Commerce/ # E-commerce features ├── Blog/ # Blogging └── Analytics/ # Analytics ``` **Namespace:** `Mod\` **Purpose:** Application features ### Website Modules (`app/Website/`) Site-specific implementations: ``` app/Website/ ├── Marketing/ # Marketing site ├── Docs/ # Documentation site └── Support/ # Support portal ``` **Namespace:** `Website\` **Purpose:** Deployable websites/frontends ### Plugin Modules (`app/Plug/`) Optional integrations: ``` app/Plug/ ├── Stripe/ # Stripe integration ├── Mailchimp/ # Mailchimp integration └── Analytics/ # Analytics integrations ``` **Namespace:** `Plug\` **Purpose:** Third-party integrations, optional features ## Module Structure Standard module structure created by `php artisan make:mod`: ``` app/Mod/Example/ ├── Boot.php # Module entry point ├── config.php # Module configuration │ ├── Actions/ # Business logic │ ├── CreateExample.php │ └── UpdateExample.php │ ├── Controllers/ # HTTP controllers │ ├── Admin/ │ │ └── ExampleController.php │ └── ExampleController.php │ ├── Models/ # Eloquent models │ └── Example.php │ ├── Migrations/ # Database migrations │ └── 2026_01_01_create_examples_table.php │ ├── Database/ │ ├── Factories/ # Model factories │ │ └── ExampleFactory.php │ └── Seeders/ # Database seeders │ └── ExampleSeeder.php │ ├── Routes/ # Route definitions │ ├── web.php # Public routes │ ├── admin.php # Admin routes │ └── api.php # API routes │ ├── Views/ # Blade templates │ ├── index.blade.php │ └── show.blade.php │ ├── Requests/ # Form requests │ ├── StoreExampleRequest.php │ └── UpdateExampleRequest.php │ ├── Resources/ # API resources │ └── ExampleResource.php │ ├── Policies/ # Authorization policies │ └── ExamplePolicy.php │ ├── Events/ # Domain events │ └── ExampleCreated.php │ ├── Listeners/ # Event listeners │ └── SendExampleNotification.php │ ├── Jobs/ # Queued jobs │ └── ProcessExample.php │ ├── Services/ # Domain services │ └── ExampleService.php │ ├── Mcp/ # MCP tools │ └── Tools/ │ └── GetExampleTool.php │ └── Tests/ # Module tests ├── Feature/ │ └── ExampleTest.php └── Unit/ └── ExampleServiceTest.php ``` ## Creating Modules ### Using Artisan Commands ```bash # Create a feature module php artisan make:mod Blog # Create a website module php artisan make:website Marketing # Create a plugin module php artisan make:plug Stripe ``` ### Manual Creation 1. Create directory structure 2. Create `Boot.php` with `$listens` array 3. Register lifecycle event handlers ```php 'onWebRoutes', ]; public function onWebRoutes(WebRoutesRegistering $event): void { $event->views('example', __DIR__.'/Views'); $event->routes(fn () => require __DIR__.'/Routes/web.php'); } } ``` ## Module Discovery ### Auto-Discovery Modules are automatically discovered by scanning configured paths: ```php // config/core.php 'module_paths' => [ app_path('Core'), app_path('Mod'), app_path('Plug'), ], ``` ### Manual Registration Disable auto-discovery and register modules explicitly: ```php // config/core.php 'modules' => [ 'auto_discover' => false, ], // app/Providers/AppServiceProvider.php use Core\Module\ModuleRegistry; public function boot(): void { $registry = app(ModuleRegistry::class); $registry->register(Mod\Blog\Boot::class); $registry->register(Mod\Commerce\Boot::class); } ``` ## Module Configuration ### Module-Level Configuration Each module can have a `config.php` file: ```php env('BLOG_POSTS_PER_PAGE', 12), 'enable_comments' => env('BLOG_COMMENTS_ENABLED', true), 'cache_duration' => env('BLOG_CACHE_DURATION', 3600), ]; ``` Access configuration: ```php $perPage = config('mod.blog.posts_per_page', 12); ``` ### Publishing Configuration Allow users to customize module configuration: ```php // app/Mod/Blog/BlogServiceProvider.php public function boot(): void { $this->publishes([ __DIR__.'/config.php' => config_path('mod/blog.php'), ], 'blog-config'); } ``` Users can then publish and customize: ```bash php artisan vendor:publish --tag=blog-config ``` ## Inter-Module Communication ### 1. Events (Recommended) Modules communicate via domain events: ```php // Mod/Blog/Events/PostPublished.php class PostPublished { public function __construct(public Post $post) {} } // Mod/Blog/Actions/PublishPost.php PostPublished::dispatch($post); // Mod/Analytics/Listeners/TrackPostPublished.php Event::listen(PostPublished::class, TrackPostPublished::class); ``` ### 2. Service Contracts Define contracts for shared functionality: ```php // Core/Contracts/NotificationService.php interface NotificationService { public function send(Notifiable $notifiable, Notification $notification): void; } // Mod/Email/EmailNotificationService.php class EmailNotificationService implements NotificationService { public function send(Notifiable $notifiable, Notification $notification): void { // Implementation } } // Register in service provider app()->bind(NotificationService::class, EmailNotificationService::class); // Use in other modules app(NotificationService::class)->send($user, $notification); ``` ### 3. Facades Create facades for frequently used services: ```php // Mod/Blog/Facades/Blog.php class Blog extends Facade { protected static function getFacadeAccessor() { return BlogService::class; } } // Usage Blog::getRecentPosts(10); Blog::findBySlug('example-post'); ``` ## Module Dependencies ### Declaring Dependencies Use PHP attributes to declare module dependencies: ```php isLoaded(Mod\Blog\Boot::class)) { // Blog module is available } ``` ## Module Isolation ### Database Isolation Use workspace scoping for multi-tenant isolation: ```php use Core\Mod\Tenant\Concerns\BelongsToWorkspace; class Post extends Model { use BelongsToWorkspace; } // Queries automatically scoped to current workspace Post::all(); // Only returns posts for current workspace ``` ### Cache Isolation Use workspace-scoped caching: ```php use Core\Mod\Tenant\Concerns\HasWorkspaceCache; class Post extends Model { use BelongsToWorkspace, HasWorkspaceCache; } // Cache isolated per workspace Post::forWorkspaceCached($workspace, 600); ``` ### Route Isolation Separate route files by context: ```php // Routes/web.php - Public routes Route::get('/blog', [BlogController::class, 'index']); // Routes/admin.php - Admin routes Route::resource('posts', PostController::class); // Routes/api.php - API routes Route::apiResource('posts', PostApiController::class); ``` ## Module Testing ### Feature Tests Test module functionality end-to-end: ```php published()->count(3)->create(); $response = $this->get('/blog'); $response->assertStatus(200); $response->assertViewHas('posts'); } } ``` ### Unit Tests Test module services and actions: ```php create(['published_at' => null]); PublishPost::run($post); $this->assertNotNull($post->fresh()->published_at); } } ``` ### Module Isolation Tests Test that module doesn't leak dependencies: ```php public function test_module_works_without_optional_dependencies(): void { // Simulate missing optional module app()->forgetInstance(Mod\Analytics\AnalyticsService::class); $response = $this->get('/blog'); $response->assertStatus(200); } ``` ## Best Practices ### 1. Keep Modules Focused Each module should have a single, well-defined responsibility: ``` ✅ Good: Mod\Blog (blogging features) ✅ Good: Mod\Comments (commenting system) ❌ Bad: Mod\BlogAndCommentsAndTags (too broad) ``` ### 2. Use Explicit Dependencies Don't assume other modules exist: ```php // ✅ Good if (class_exists(Mod\Analytics\AnalyticsService::class)) { app(AnalyticsService::class)->track($event); } // ❌ Bad app(AnalyticsService::class)->track($event); // Crashes if not available ``` ### 3. Avoid Circular Dependencies ``` ✅ Good: Blog → Comments (one-way) ❌ Bad: Blog ⟷ Comments (circular) ``` ### 4. Use Interfaces for Contracts Define interfaces for inter-module communication: ```php // Core/Contracts/SearchProvider.php interface SearchProvider { public function search(string $query): Collection; } // Mod/Blog/BlogSearchProvider.php class BlogSearchProvider implements SearchProvider { // Implementation } ``` ### 5. Version Your APIs If modules expose APIs, version them: ```php // Routes/api.php Route::prefix('v1')->group(function () { Route::apiResource('posts', V1\PostController::class); }); Route::prefix('v2')->group(function () { Route::apiResource('posts', V2\PostController::class); }); ``` ## Troubleshooting ### Module Not Loading Check module is in configured path: ```bash # Verify path exists ls -la app/Mod/YourModule # Check Boot.php exists cat app/Mod/YourModule/Boot.php # Verify $listens array grep "listens" app/Mod/YourModule/Boot.php ``` ### Routes Not Registered Ensure event handler calls `$event->routes()`: ```php public function onWebRoutes(WebRoutesRegistering $event): void { // Don't forget this! $event->routes(fn () => require __DIR__.'/Routes/web.php'); } ``` ### Views Not Found Register view namespace: ```php public function onWebRoutes(WebRoutesRegistering $event): void { // Register view namespace $event->views('blog', __DIR__.'/Views'); } ``` Then use namespaced views: ```php return view('blog::index'); // Not just 'index' ``` ## Learn More - [Lifecycle Events](/architecture/lifecycle-events) - [Lazy Loading](/architecture/lazy-loading) - [Multi-Tenancy](/patterns-guide/multi-tenancy) - [Actions Pattern](/patterns-guide/actions)