This package provides a robust, modular architecture for Laravel applications. Designed for consistency and maintainability, it allows you to build features in isolation within the app/Modules directory.
π Zero-Config: As of v2.0.0, this package automatically handles PSR-4 autoloading, Service Provider registration, and API route discovery. No manual
composer.jsonorapp.phpedits are required.
| Requirement | Supported Versions |
|---|---|
| PHP | ^8.2 |
| Laravel | ^11.0 |
composer require jackwander/laravel-module-makerTo keep your application maintainable and scalable, this package encourages an Intermediate Base Class (Bridge) pattern. This allows you to customize global behaviorβlike custom response formatting or shared business logicβwithout ever touching the vendor/ directory.
Your generated modules follow this hierarchy:
Vendor Base β App Core β Module File
- Vendor Base: The raw logic provided by the package inside
ModuleMaker/Resources(Read-only). - App Core: Your custom bridge where you add project-specific logic (Editable).
- Module File: The specific logic for a feature (e.g.,
PersonService).
By default, the generator extends the package's internal resources. To take full control of your architecture, follow these steps to use your own custom "Core" files.
Publish the config file to your application's config directory:
php artisan vendor:publish --provider="Jackwander\ModuleMaker\ModuleServiceProvider" --tag="config"We recommend creating a Core directory to house your bridge classes at app/Modules/Core/. Create a file (e.g., BaseService.php) and extend the package's resource:
<?php
namespace App\Modules\Core;
// Import the package's base resource from the vendor folder
use Jackwander\ModuleMaker\Resources\BaseService as VendorBaseService;
class BaseService extends VendorBaseService
{
/**
* Add global methods here.
* Every module generated in the future will inherit these.
*/
public function customGlobalLogic()
{
// Your custom logic here
}
}Update config/module-maker.php to tell the generator to use your local files as the parent classes:
// config/module-maker.php
return [
'base_classes' => [
'service' => \App\Modules\Core\BaseService::class,
'api_controller' => \App\Modules\Core\BaseApiController::class,
'model' => \App\Modules\Core\BaseModel::class,
]
];Now, whenever you run php artisan jw:make-service, the generated file will automatically extend App\Modules\Core\BaseService instead of the vendor class. This gives you total control over your project's architecture while still automating the boring boilerplate.
To generate a complete module structure (Folders, Service Providers, and Routes), run:
php artisan jw:make-module PersonIn v2.0.0, the jw:make-model command is the most efficient way to build your feature. I have updated it to support standard Laravel-style flags so you can generate the entire stack at once:
# Generate Model + Migration + Service + Controller + Routes
php artisan jw:make-model CivilStatus --module=Person -a
# Or use specific flags:
php artisan jw:make-model CivilStatus --module=Person -m -s -cAvailable Flags:
-m|--migration: Generate a Migration file.-s|--service: Generate a Service class.-c|--controller: Generate a Controller.-a|--all: Generate All (Full Stack).
If you need to add a single component to an existing module, you can use these granular commands:
php artisan jw:make-migration insert_status_column --module=Person --table=personsTo generate a new seeder for a specific module, use the jw:make-seeder command. The package automatically singularizes the name and appends the Seeder suffix for you.
php artisan jw:make-seeder Status --module=PersonWhat happens next?
File Creation: A new seeder is created at app/Modules/Person/Database/Seeders/StatusSeeder.php.
Smart Output: The terminal will provide a ready-to-copy snippet so you can register it instantly.
Example Output:
Seeder created: app/Modules/Person/Database/Seeders/StatusSeeder.php
π± Add this to your database/seeders/DatabaseSeeder.php:
$this->call(\App\Modules\Person\Database\Seeders\StatusSeeder::class);
By keeping seeders inside the module, you ensure that your features are completely portable. If you move the Person module to a different project, your data-seeding logic goes with it.
Modular factories require an explicit $model property because they live outside the default Laravel namespace. Use the jw:make-factory command to generate one:
php artisan jw:make-factory Person --module=PersonIf the convention do not apply automatically to your particular application or factory, you may add the UseFactory attribute to the model to manually specify the model's factory:
use Illuminate\Database\Eloquent\Attributes\UseFactory;
use App\Modules\Person\Database\Factories\PersonFactory;
#[UseFactory(PersonFactory::class)]
class Person extends model
{
}Alternatively, you may overwrite the newFactory method on your model to return an instance of the model's corresponding factory directly:
use App\Modules\Person\Database\Factories\PersonFactory;
/**
* Create a new factory instance for the model.
*/
protected static function newFactory()
{
return PersonFactory::new();
}php artisan jw:make-controller CivilStatus --module=Personphp artisan jw:make-service CivilStatus --module=PersonI have included a health-check command to ensure your environment is correctly configured and that all modules are being detected by the system:
php artisan jw:checkGenerated modules follow this PSR-4 compliant structure automatically:
app/Modules/
βββ Person/
βββ Controllers/ # Module-specific Controllers
βββ Models/ # Eloquent Models
βββ Services/ # Business Logic / Service Layer
βββ Providers/ # Module Service Provider (Auto-registered)
βββ Database/
β βββ Migrations/ # Module-specific Migrations
βββ Routes/
βββ api.php # Module API Routes (Prefix: api/v1/person)