karnoweb/laravel-module-manager

A powerful module management system for Laravel with dependency resolution, tree structure, and Laravel 12 support

Installs: 2

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/karnoweb/laravel-module-manager

v1.0.1 2026-02-14 07:54 UTC

This package is auto-updated.

Last update: 2026-02-14 07:55:23 UTC


README

A module/feature-flag system for Laravel with dependency resolution, tree structure, system (locked) modules, and Laravel 10–12 support.

For usage scenarios and examples in Persian (فارسی), see سناریوهای کاربردی.

Requirements

  • PHP 8.2+
  • Laravel 10.x, 11.x or 12.x

Installation

composer require karnoweb/laravel-module-manager

Publish config and migrations:

php artisan vendor:publish --tag=module-manager-config
php artisan vendor:publish --tag=module-manager-migrations
php artisan migrate

Configuration

Edit config/module-manager.php:

Key Description
table_prefix Optional prefix for tables (e.g. mm_mm_modules)
tables.modules Modules table name
tables.dependencies Dependencies table name
migration_prefix Prefix for published migration filenames
cache.enabled Enable cache for active status
cache.ttl Cache TTL (seconds)
cache.prefix Cache key prefix
default_deactivation cascade, restrict, or none
events.enabled Fire module events
modules Array of module definitions (see below)

Defining modules in config

Add modules under modules so they can be synced with php artisan module:sync. You can use a nested structure with records: children inherit group and get parent set automatically.

Nested (recommended):

'modules' => [
    'products' => [
        'name' => 'Products',
        'description' => 'Product management',
        'group' => 'shop',
        'icon' => 'fa-box',
        'sort_order' => 0,
        'is_active' => false,
        'on_deactivate' => 'cascade',
        'requires' => [],
        'records' => [
            'simple_product' => [
                'name' => 'Simple Product',
                'is_active' => true,
                'requires' => ['products'],
            ],
            'variable_product' => [
                'name' => 'Variable Product',
                'requires' => ['products'],
            ],
        ],
    ],
],

Flat: same keys at top level; set group and parent on each module.

Sync from config:

php artisan module:sync

API Reference

Status checks

Method Description
Module::active(string|array $keys) Returns true if module(s) are active
Module::inactive(string $key) Returns true if module is inactive
Module::allActive(array $keys) All given keys must be active
Module::someActive(array $keys) At least one key active

Conditional execution

Method Description
Module::when(string $key, Closure $active, ?Closure $inactive = null) Run callback by status
Module::unless(string $key, Closure $callback) Run callback when inactive

Activation / deactivation

Method Description
Module::activate(string $key) Activate module (throws on missing deps / conflicts)
Module::deactivate(string $key) Deactivate (throws for system modules or active dependents)
Module::toggle(string $key) Toggle active state; returns new state

Validation

Method Description
Module::canActivate(string $key) Whether activation is allowed
Module::canDeactivate(string $key) Whether deactivation is allowed
Module::whyCantActivate(string $key) Reasons (e.g. missing_dependencies, conflicts)
Module::whyCantDeactivate(string $key) Reasons (e.g. system_module, active_dependents)

Dependencies

Method Description
Module::requires(string $module, string $dependency) Add required dependency
Module::conflicts(string $module, string $conflictsWith) Add conflict (bidirectional)
Module::suggests(string $module, string $suggestion) Add suggestion
Module::getDependencies(string $key) Get required modules
Module::getDependents(string $key) Get modules that require this one

Tree

Method Description
Module::tree(?string $group = null) Nested tree (with children)
Module::children(string $key) Direct children
Module::descendants(string $key) All descendants
Module::ancestors(string $key) All ancestors
Module::siblings(string $key) Siblings

Metadata

Method Description
Module::meta(string $key, string $metaKey, mixed $default = null) Get metadata value
Module::setMeta(string $key, string|array $metaKey, mixed $value = null) Set metadata

Management

Method Description
Module::define(string $key, string $name, array $options = []) Create or update module
Module::all() All modules (ordered)
Module::groups() List of groups
Module::group(string $group) Modules in group
Module::find(string $key) Find by key or null
Module::findOrFail(string $key) Find or throw
Module::flushCache() Clear active-status cache

Helpers

Function Description
module(?string $key = null) Manager instance or active($key)
module_active(string|array $keys) Same as Module::active()
module_inactive(string $key) Same as Module::inactive()
module_meta(string $key, string $metaKey, mixed $default = null) Same as Module::meta()
when_module(string $key, Closure $active, ?Closure $inactive = null) Same as Module::when()

Artisan commands

Command Description
php artisan module:list List modules (--group=, --active, --inactive)
php artisan module:activate {key} Activate a module
php artisan module:deactivate {key} Deactivate a module
php artisan module:tree Show tree (--group=, --json)
php artisan module:sync Sync modules from config (--force to skip confirm)

Usage examples

Check and run code by module

use Karnoweb\LaravelModuleManager\Facades\Module;

if (Module::active('reports')) {
    return view('reports.dashboard');
}

Module::when('advanced_discount', function () {
    return redirect()->route('discounts.advanced');
}, function () {
    return redirect()->route('discounts.simple');
});

Blade

@module('reports')
    <a href="{{ route('reports.index') }}">Reports</a>
@endmodule

@moduleany(['simple_product', 'coding_product'])
    <a href="{{ route('products.index') }}">Products</a>
@endmoduleany

@modules(['products', 'discounts'])
    <p>Shop modules are active.</p>
@endmodules

Routes and middleware

Route::middleware(['module:reports'])->group(function () {
    Route::get('/reports', [ReportController::class, 'index']);
});

Route::middleware(['module:products,discounts'])->get('/shop', ...);

Define modules and dependencies in code

use Karnoweb\LaravelModuleManager\Facades\Module;

Module::define('products', 'Products', [
    'group' => 'shop',
    'icon' => 'fa-box',
    'is_active' => true,
]);

Module::define('simple_product', 'Simple Product', [
    'group' => 'shop',
    'parent' => 'products',
    'is_active' => true,
]);

Module::requires('simple_product', 'products');
Module::conflicts('legacy_cart', 'new_cart');
Module::suggests('reports', 'products');

System (locked) modules

Set is_system => true in config or when defining. System modules cannot be deactivated via Module::deactivate() or module:deactivate (throws SystemModuleException).

Module::define('core', 'Core', ['is_system' => true]);

Sync from config in app seeder

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use Karnoweb\LaravelModuleManager\ModuleSeeder;

class DatabaseSeeder extends Seeder
{
    public function run(): void
    {
        (new ModuleSeeder)->run();
    }
}

Exceptions

Exception When
ModuleNotFoundException Module key not found
DependencyException Missing deps or active dependents block action
ConflictException Conflicting module is active
CircularDependencyException Circular requires detected
SystemModuleException Deactivate attempted on system module

License

MIT.