internachi/modularize
Add InterNACHI Modular support to your Laravel package commands with simple traits. Provides a --module option and helpers to resolve module config. Includes a GeneratorCommand trait so generated files land in the module directory with correct namespaces.
composer require internachi/modularize
use Illuminate\Console\Command;
use InterNACHI\Modularize\Support\Modularize;
class MyCommand extends Command
{
use Modularize;
public function handle()
{
if ($module = $this->module()) {
// Module is active; use $module->name, $module->path, etc.
}
}
}
--module flag:
php artisan my:command --module=Blog
Convert a file generator to module-aware:
use Illuminate\Console\GeneratorCommand;
use InterNACHI\Modularize\Support\ModularizeGeneratorCommand;
class MakeAdminController extends GeneratorCommand
{
use ModularizeGeneratorCommand;
protected function getStub()
{
return $this->module()
? __DIR__.'/stubs/admin.controller.stub'
: parent::getStub();
}
}
Run:
php artisan make:admin-controller User --module=AdminPanel
Module-Aware Commands:
Modularize trait for commands that need to detect a module (e.g., logging, validation).$this->module() (returns null if --module not provided).$path = $this->module()
? $this->module()->path('database/migrations')
: database_path('migrations');
File Generation:
ModularizeGeneratorCommand for GeneratorCommand-based tools.getDefaultNamespace() to inject module namespaces:
protected function getDefaultNamespace()
{
return $this->module()
? $this->module()->getNamespace('App/Http/Controllers')
: 'App\\Http\\Controllers';
}
modules/{module}/... with correct namespacing.Conditional Logic:
if ($this->module()) {
$this->info("Generating for module: {$this->module()->name}");
} else {
$this->warn("No module specified; using global namespace.");
}
ModuleConfig helpers:
$module->name; // Module name (e.g., "Blog")
$module->path($subdir); // Resolve path (e.g., "modules/Blog/database")
$module->getNamespace($subpath); // Namespace (e.g., "Modules\\Blog\\Http\\Controllers")
internachi/modular:
Ensure your package’s composer.json requires internachi/modular:
"require": {
"internachi/modular": "^1.0"
}
$this->module() in stub files to inject module-specific placeholders (e.g., {{ moduleNamespace }}).No Module, No Graceful Fallback:
$this->module() returns null if --module is omitted. Always check:
if (!$module = $this->module()) {
return $this->error("Module required for this operation.");
}
--module hint in getOptions():
protected function getOptions()
{
return [
['module', 'm', InputOption::VALUE_OPTIONAL, 'Target module (e.g., Blog)', null],
];
}
Namespace Collisions:
App vs. Modules\App), override getDefaultNamespace() explicitly:
protected function getDefaultNamespace()
{
return $this->module()
? 'Modules\\' . str_replace('/', '\\', $this->module()->name) . '\\' . $this->rootNamespace()
: $this->rootNamespace();
}
Laravel 13+ Console Changes:
getArguments()/getOptions() instead of direct $input access.Dynamic Module Discovery:
internachi/modular is configured to load modules before running commands.Verify ModuleConfig: Dump the module object to debug:
dd($this->module());
Expected structure:
ModuleConfig {
name: "Blog",
basePath: "/path/to/modules/Blog",
+getNamespace(string $subpath): string,
+path(string $subdir): string,
}
Check File Permissions: If generated files fail silently, ensure the module directory is writable:
chmod -R 755 modules/{module-name}
Custom Module Paths:
Extend ModuleConfig by binding a custom resolver:
$this->app->bind('internachi/modular.config', function () {
return new CustomModuleConfig($this->module());
});
Pre-Generation Hooks:
Add logic before file generation in ModularizeGeneratorCommand:
protected function getModulePath()
{
if (!$module = $this->module()) {
return null;
}
return $module->path('src/' . $this->argument('type'));
}
Post-Command Actions:
Use the handle() return value to trigger module-specific tasks:
public function handle()
{
if ($module = $this->module()) {
$this->call('module:publish', [
'--module' => $module->name,
'--tag' => 'config',
]);
}
return 0;
}
Batch Module Commands: Create a wrapper command to apply operations to multiple modules:
class ModuleBatchCommand extends Command
{
use Modularize;
protected function handle()
{
foreach ($this->argument('modules') as $moduleName) {
$this->call('my:command', [
'--module' => $moduleName,
]);
}
}
}
Usage:
php artisan module:batch Blog Admin --command=my:command
Module-Aware Testing:
Mock ModuleConfig in tests:
$module = Mockery::mock('internachi/modular.ModuleConfig');
$module->shouldReceive('name')->andReturn('TestModule');
$this->app->instance('internachi/modular.config', $module);
Performance: Cache module lookups in long-running commands:
private $moduleCache;
private function module()
{
if (is_null($this->moduleCache)) {
$this->moduleCache = parent::module();
}
return $this->moduleCache;
}
How can I help you explore Laravel packages today?