internachi/modular

repository·main·Indexed 22 days ago

https://github.com/internachi/modular

A lightweight module system for Laravel applications that organizes large projects into discrete, convention-based modules in an app-modules/ directory. It leverages Composer path repositories and Laravel's native package discovery. Version 3.0 introduces a plugin-based architecture requiring PHP 8.3+ and Laravel 11+, allowing developers to extend module discovery and lifecycle management via custom plugins and PHP 8 attributes.

Tokens
8.9K
Snippets
52
Records
58
Agent score
78%

What's inside internachi/modular

  1. Use PHP 8 Attributes for Plugin lifecycle hooks

    main

    When creating custom plugins, you can use PHP 8 attributes to control when specific logic is executed during the application boot process:

    • #[AfterResolving(Service::class)]: Defers execution until the specified service is resolved from the container.
    • #[OnBoot]: Executes the plugin logic during the application's booting() hook.
    • No Attribute: If no attribute is provided, the plugin must be explicitly called via PluginHandler::handle().
  2. Use Blade components from a module

    main

    Blade components defined within a module are automatically registered under a component namespace derived from the module name.

    Pattern: <x-{module-name}::{component-name} />

    <!-- If component is at app-modules/demo/src/View/Components/Basic.php -->
    <x-demo::basic />
    
    <!-- If component is at app-modules/demo/src/View/Components/Nested/One.php -->
    <x-demo::nested.one />
    
    <!-- If anonymous component is at app-modules/demo/resources/components/anonymous.blade.php -->
    <x-demo::anonymous />
  3. Use translations from a module

    main

    Translations located in a module's resources/lang/ directory are automatically registered under a namespace.

    Pattern: __('{module-name}::file.key')

    // If translation is at app-modules/demo/resources/lang/en/messages.php
    __('demo::messages.welcome');
  4. Create a new module

    main

    Scaffold a new module in the app-modules/ directory. This command creates a standard directory structure including composer.json, src/, tests/, routes/, resources/, and database/.

    After running the command, you must run a composer update for the newly created module to register it as a path repository and dependency.

    # 1. Scaffold the module
    php artisan make:module my-module
    
    # 2. Register the module dependency
    composer update modules/my-module
  5. Extend Modular with custom plugins

    main

    Modular 3.0 uses a plugin-based architecture for module discovery and lifecycle management. To extend the system, you can create custom plugins that extend InterNACHI\Modular\Plugins\Plugin and register them in your application's service provider.

    Custom plugins are automatically integrated into the caching system and can use PHP 8 attributes to hook into the application lifecycle.

    public function register(): void
    {
        PluginRegistry::register(MyPlugin::class);
    }
  6. Synchronize project configurations

    main

    Run the sync command to ensure your project is fully optimized for module support. This command:

    • Adds a Modules test suite to your phpunit.xml file.
    • Updates PhpStorm Laravel plugin configurations to correctly locate module views.

    It is safe to run at any time and only adds missing configurations. You can automate this by adding it to your post-autoload-dump scripts in composer.json.

    php artisan modules:sync
  7. Migrate to Modular v3.0

    main

    Version 3.0 introduces a plugin-based architecture. If you are upgrading from a previous version, follow these steps to ensure compatibility with the new requirements and structure:

    1. Upgrade Environment: Ensure you are running PHP 8.3+ and Laravel 11+.
    2. Clear Old Cache: Run php artisan modules:clear to remove legacy cache files.
    3. Update Package: Run composer update internachi/modular.
    4. Livewire Users: The make:livewire --module command has been removed. You must now install the dedicated package: composer require internachi/modular-livewire.
    5. Refactor Code:
      • Replace AutoDiscoveryHelper references with FinderFactory.
      • Remove ModularEventServiceProvider (functionality is now handled by the auto-registered EventsPlugin).
      • Replace ModuleRegistry::getCachePath() with Cache::path().
    php artisan modules:clear
    composer update internachi/modular
    composer require internachi/modular-livewire
  8. Customize the default module structure

    main

    You can customize the boilerplate generated by make:module by publishing the app-modules.php config file and providing custom stubs. The following placeholders are available for filenames and file contents:

    • StubBasePath
    • StubModuleNamespace
    • StubComposerNamespace
    • StubModuleNameSingular
    • StubModuleNamePlural
    • StubModuleName
    • StubClassNamePrefix
    • StubComposerName
    • StubMigrationPrefix
    • StubFullyQualifiedTestCaseBase
    • StubTestCaseBase
  9. Configure the module namespace

    main

    By default, modules use the Modules\ namespace. To make modules easier to extract into separate packages later, it is highly recommended to customize this to an organization namespace (e.g., InterNACHI\).

    Publish the configuration file to make these changes:

    php artisan vendor:publish --tag=modular-config
  10. Configure module namespaces before scaffolding

    main

    By default, modules are created using the Modules namespace. If you intend to eventually extract your modules into standalone packages, it is recommended to use a custom namespace (e.g., your organization name) from the start.

    To customize the namespace before running make:module:

    1. Publish the modular configuration: php artisan vendor:publish --tag=modular-config.
    2. Update the app-modules.modules_namespace and app-modules.modules_vendor keys in your configuration file.
    3. Run make:module again.
  11. Seed databases using a module

    main

    You can target a specific module's seeders using the --module option with the db:seed command. This will look for the seeder within the module's namespace.

    # Calls Modules\MyModule\Database\Seeders\DatabaseSeeder
    php artisan db:seed --module=my-module
    
    # Calls Modules\MyModule\Database\Seeders\MySeeder
    php artisan db:seed --class=MySeeder --module=my-module