eubourne/laravel-plugins

Module support for Laravel projects for better code organization.

v1.1.2 2024-11-18 20:59 UTC

This package is auto-updated.

Last update: 2024-12-25 19:17:40 UTC


README

Laravel Plugins

Laravel plugins

Laravel Plugins is a package designed to organize Laravel code into modules, allowing for better separation of features and easier code management. This package helps you structure your project into logical modules, such as Cart, Catalog, Blog, etc., where each module contains its own service providers, routes, and other resources.

Features

  • Organize project code by modules: Group related code in dedicated module folders, improving structure and maintainability.
  • Automatic module detection: The package automatically scans the modules directory for defined modules.
  • Module-specific resource loading: Each module can contain service providers, routes, translations, and channels that are loaded individually.
  • Module structure: Modules are self-contained and follow a predictable directory structure for easier development and scaling.

Installation

To install the package, run:

composer require eubourne/laravel-plugins

This package makes use of Laravels package auto-discovery mechanism, so you don't have to manually register its service provider.

Run the following artisan command to publish configuration file:

php artisan plugin:install

It will create config/plugins.php file with reasonable defaults.

Instruct composer autoload in composer.json where to look for your module files:

"autoload": {
    "psr-4": {
        "Modules\\": "modules/",
    }
}

NOTE:

The path should match the value specified in the groups.*.path section of your config/plugins.php file. If you have multiple groups, you need to add a separate psr-4 entry in package.json for each group.

After updating the composer.json, run:

composer dump-autoload

Basic Usage

Creating a Module

  1. Add a modules directory: In the root of your project, create a modules folder if it doesn’t already exist.
  2. Create a module folder: For each module, create a directory under modules (e.g., Cart, Catalog, Blog, etc.).
  3. Define the module: Inside each module folder, create a <ModuleName>Module.php file. This file should extend EuBourne\LaravelPlugins\Plugin class, enabling it to be registered by the package.

Directory Structure

A module typically follows this structure:

modules/
├── Cart/
│   ├── Providers/                      # Folder for service providers
│   │   └── ServiceProvider.php
│   ├── Routes/
│   │   ├── web.php                     # Web routes for the module
│   │   ├── api.php                     # API routes for the module
│   │   └── channels.php                # Broadcasting channels
│   ├── Lang/                           # Folder for translations
│   │   └── en/
│   │       └── messages.php
│   └── CartModule.php                  # Main module definition file
└── Catalog/
    ├── Providers/
    ├── Routes/
    ├── Lang/
    └── CatalogModule.php

You can customize the default suffix for plugin descriptor files to better suit your project needs. For example, instead of using <ModuleName>Module.php, you can switch to <ModuleName>Widget.php. To achieve this, update the suffix parameter in the config/plugins.php file. Additionally, if you have multiple groups, you can specify a unique suffix for each group using the groups.*.suffix parameter. This flexibility allows you to tailor the naming conventions to your application's structure.

Registering Module Resources

Service Providers

Each module can register a main service provider by creating a Providers/ServiceProvider.php file inside the module directory. The package automatically registers this provider if it’s found.

  • Additional Service Providers: You can specify more service providers from the main service provider. For convenience, you can inherit module service provider from EuBourne\LaravelPlugins\BaseServiceProvider and override its $providers property with an array of service providers to register.

    namespace Modules\Blog\Providers;
    
    use EuBourne\LaravelPlugins\BaseServiceProvider;
    
    class ServiceProvider extends BaseServiceProvider
    {
      protected array $providers = [
        BlogLoggingServiceProvider::class,
        // ...
      ]
    }

    This way both Modules\Blog\Providers\ServiceProvider and Modules\Blog\Providers\BlogLoggingServiceProvider will be registered.

  • Override Default Providers: To replace auto-discovered providers with a fixed list, override the $providers array in <ModuleName>Module.php.

    namespace Modules\Blog;
    
    class BlogModule extends EuBourne\LaravelPlugins\Plugin
    {
      protected array $providers = [
        \Modules\Blog\Providers\BlogLoggingServiceProvider::class,
        \Modules\Blog\Providers\ServiceProvider::class,
      ];
    }

    NOTE:

    All module service providers should extend Illuminate\Support\ServiceProvider.

Routes

By default, the package registers routes and applies specific middleware based on file names:

  • Web routes: The package loads routes from web.php and applies the web middleware.
  • API routes: All routes defined in files that match api*.php filename pattern (i.e.: api.php, api_v1.php, api_admin.php, etc.) will be loaded with the api middleware.

To configure additional route file names:

  1. Edit the config/plugins.php file.
  2. Update the routes section to add or modify route files. For example:
'routes' => [
    'web' => [
        'filename' => 'web*.php' // Allows `web.php`, `web_admin.php`, etc.
    ],
    'api' => [
        'filename' => 'api*.php' // Allows `api.php`, `api_v1.php`, etc.
    ]
]

Multiple Module Groups

You can define multiple module groups in the groups section of the configuration file. Each group may have its own root directory and unique route configurations.

Example configuration:

'groups' => [
    'modules' => [
        'path' => 'modules', // modules root directory
        'routes' => [
            'web' => [
                'filename' => 'web*.php'
            ],
            'api' => [
                'filename' => 'api*.php'
            ]
        ]
    ],
    'widgets' => [
        'path' => 'widgets',
        'routes' => [
            'api' => [
                'filename' => 'api_v*.php' // Specific to widgets group
            ]
        ]
    ]
]

In this example:

  • modules is the main group for primary modules.
  • widgets is a secondary group with its own routing configuration. Routes like api_v1.php and api_v2.php are loaded only within widgets.

Example Module Definition

Here’s a sample BlogModule.php for the Blog module:

namespace Modules\Blog;

use EuBourne\LaravelPlugins\Plugin;

class BlogModule extends Plugin
{
}

Blog module service provider, placed in modules/Blog/Providers:

namespace Modules\Home\Providers;

use EuBourne\LaravelPlugins\BaseServiceProvider;

class ServiceProvider extends BaseServiceProvider
{
    public function register(): void
    {
        // Register services
    }

    public function boot(): void
    {
        // Load resources
    }
}

Accessing Plugin Data

You can access plugin data using the PluginManager, which can be retrieved from the service container:

/**
 * Retrieve the PluginManager instance.
 *
 * @var \EuBourne\LaravelPlugins\PluginManager $manager
 */
$manager = app('plugin.manager');

/**
 * Get a list of all registered plugin keys.
 *
 * @var array $keys
 */
$keys = $manager->getKeys();

/**
 * Retrieve data for a specific plugin as an array.
 *
 * @var array $blogPluginData
 */ 
$blogPluginData = $manager->getPluginData('modules.blog');

/**
 * Retrieve a specific field value from a plugin's data.
 *
 * @var mixed $value
 */
$value = $manager->getFromPlugin('modules.blog', 'className');

/**
 * Retrieve the Plugin instance for a specific plugin.
 *
 * @var \EuBourne\LaravelPlugins\Plugin $plugin
 */
$plugin = $manager->getPlugin('modules.blog');

Optimization

Discovering modules on each request may impact performance due to file scan and read operations. To enhance performance, cache module discovery with the following command:

php artisan plugin:cache

To clear the cached module data and reset module discovery, run:

php artisan plugin:clear

The package also supports standard Laravel optimization commands:

php artisan optimize
php artisan optimize:clear

For information about discovered modules, two commands are available:

# Displays a list of all discovered plugins
php artisan plugin:list

# Shows details for a specific plugin
php artisan plugin {plugin_key}

License

This package is open-source and available for free under the MIT license.

Contributing

Feel free to submit issues or pull requests to help improve this package.

Contact

For more information or support, please reach out via GitHub or email.