| Install | |
|---|---|
composer require anas/easy-dev |
|
| Latest Version: | v2.1.1 |
| PHP: | ^8.1 |
| License: | MIT |
| Last Updated: | Mar 22, 2026 |
| Links: | GitHub · Packagist |
Laravel Easy Dev is a powerful code generation toolkit that supercharges your Laravel development. Generate complete CRUD systems with Repository & Service patterns, auto-detect model relationships, create policies, DTOs, observers, filters, enums, and more โ all with a beautiful interactive CLI.
| Feature | Description |
|---|---|
| ๐๏ธ CRUD Generation | Model, Migration, Controllers (API + Web), Requests, Resources, Routes |
| ๐๏ธ Repository Pattern | Repository + Interface with full CRUD method signatures |
| ๐ง Service Layer | Service + Interface with business logic separation |
| ๐ก๏ธ Policies | Authorization policy with viewAny, view, create, update, delete, restore, forceDelete |
| ๐ฆ DTOs | Data Transfer Objects with fromRequest(), fromModel(), toArray() |
| ๐๏ธ Observers | Model lifecycle hooks: creating, created, updating, updated, deleting, deleted |
| ๐ Query Filters | Reusable filter classes with apply() method |
| ๐ท๏ธ Enums | PHP 8.1+ string-backed enums with values() and label() helpers |
| ๐ Relationship Detection | Auto-detect belongsTo, hasMany, morphTo, morphMany from schema |
| ๐ฎ Dry-Run Mode | Preview all files before creating โ nothing is written to disk |
| โฉ๏ธ Rollback | Automatic cleanup on generation failure |
| ๐จ Beautiful CLI | Progress bars, colored output, interactive wizard |
composer require anas/easy-dev --dev
The package auto-registers via Laravel package discovery. No manual setup needed.
php artisan vendor:publish --tag=easy-dev-config
php artisan vendor:publish --tag=easy-dev-stubs
Stubs are copied to resources/stubs/vendor/easy-dev/ where you can customize them.
# 1. Generate a complete CRUD for "Product"
php artisan easy-dev:crud Product
# 2. Run the generated migration
php artisan migrate
# 3. Check your routes
php artisan route:list --path=products
That's it! You now have a Model, Migration, Web Controller, API Controller, Form Requests, API Resources, and Routes โ all generated and ready to use.
easy-dev:crudThe core command. Generates a complete CRUD system for a model.
php artisan easy-dev:crud {model} [options]
| Option | Description |
|---|---|
--with-repository |
Generate Repository pattern (Repository + Interface) |
--with-service |
Generate Service layer (Service + Interface) |
--with-policy |
Generate authorization Policy |
--with-dto |
Generate Data Transfer Object |
--with-observer |
Generate model Observer |
--api-only |
Generate only API controller and routes (no web) |
--web-only |
Generate only web controller and routes (no API) |
--without-interface |
Skip Interface generation for Repository/Service |
--dry-run |
Preview files without creating them |
# Basic CRUD (Model + Migration + Controllers + Requests + Resources + Routes)
php artisan easy-dev:crud Post
# Full architecture stack
php artisan easy-dev:crud Order --with-repository --with-service --with-policy --with-dto --with-observer
# API-only with service layer
php artisan easy-dev:crud Product --api-only --with-service
# Preview what would be generated
php artisan easy-dev:crud Invoice --with-repository --with-service --dry-run
| File | Path |
|---|---|
| Model | app/Models/Post.php |
| Migration | database/migrations/xxxx_create_posts_table.php |
| Web Controller | app/Http/Controllers/PostController.php |
| API Controller | app/Http/Controllers/Api/PostApiController.php |
| Store Request | app/Http/Requests/StorePostRequest.php |
| Update Request | app/Http/Requests/UpdatePostRequest.php |
| API Resource | app/Http/Resources/PostResource.php |
| API Collection | app/Http/Resources/PostCollection.php |
| Flag | Files Generated |
|---|---|
--with-repository |
app/Repositories/PostRepository.php, app/Repositories/Contracts/PostRepositoryInterface.php |
--with-service |
app/Services/PostService.php, app/Services/Contracts/PostServiceInterface.php |
--with-policy |
app/Policies/PostPolicy.php |
--with-dto |
app/DTOs/PostData.php |
--with-observer |
app/Observers/PostObserver.php |
easy-dev:makeInteractive CRUD generator with a guided wizard. Wraps easy-dev:crud with a beautiful step-by-step UI.
# Interactive mode (no arguments โ wizard asks questions)
php artisan easy-dev:make
# Non-interactive mode (same options as easy-dev:crud)
php artisan easy-dev:make Product --with-repository --with-service
easy-dev:policyGenerate an authorization policy for an existing model.
php artisan easy-dev:policy {model}
Generated file: app/Policies/{Model}Policy.php
Methods included:
viewAny(User $user) โ List permissionview(User $user, Model $model) โ Read permissioncreate(User $user) โ Create permissionupdate(User $user, Model $model) โ Update permissiondelete(User $user, Model $model) โ Delete permissionrestore(User $user, Model $model) โ Restore soft-deletedforceDelete(User $user, Model $model) โ Permanently deleteUsage in controllers:
$this->authorize('viewAny', Post::class);
$this->authorize('update', $post);
easy-dev:dtoGenerate a Data Transfer Object for a model.
php artisan easy-dev:dto {model}
Generated file: app/DTOs/{Model}Data.php
Methods included:
fromRequest(Request $request): self โ Create from validated requestfromModel(Model $model): self โ Create from Eloquent modeltoArray(): array โ Convert to arrayUsage:
// In a controller
$dto = PostData::fromRequest($request);
$dto = PostData::fromModel($post);
$array = $dto->toArray();
easy-dev:observerGenerate a model observer with lifecycle hooks.
php artisan easy-dev:observer {model}
Generated file: app/Observers/{Model}Observer.php
Hooks included: creating, created, updating, updated, deleting, deleted
Register in AppServiceProvider::boot():
use App\Models\Post;
use App\Observers\PostObserver;
Post::observe(PostObserver::class);
Or use the #[ObservedBy] attribute (Laravel 10+):
use App\Observers\PostObserver;
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
#[ObservedBy(PostObserver::class)]
class Post extends Model { }
easy-dev:filterGenerate a query filter class for a model.
php artisan easy-dev:filter {model}
Generated file: app/Filters/{Model}Filter.php
Usage:
// In a controller
$query = Post::query();
$filtered = PostFilter::apply($query, $request->validated());
return PostResource::collection($filtered->paginate());
easy-dev:enumGenerate a PHP 8.1+ backed enum.
php artisan easy-dev:enum {name} --values={comma-separated-values}
Generated file: app/Enums/{Name}.php
Example:
php artisan easy-dev:enum OrderStatus --values=pending,processing,shipped,delivered,cancelled
Generated code:
enum OrderStatus: string
{
case PENDING = 'pending';
case PROCESSING = 'processing';
case SHIPPED = 'shipped';
case DELIVERED = 'delivered';
case CANCELLED = 'cancelled';
public static function values(): array { ... }
public function label(): string { ... }
}
Usage:
// In a migration
$table->string('status')->default(OrderStatus::PENDING->value);
// In a model cast
protected $casts = ['status' => OrderStatus::class];
// In code
OrderStatus::values(); // ['pending', 'processing', 'shipped', ...]
OrderStatus::PENDING->label(); // 'Pending'
easy-dev:repositoryGenerate repository pattern files for an existing model.
php artisan easy-dev:repository {model} [--without-interface]
Generated files:
app/Repositories/{Model}Repository.phpapp/Repositories/Interfaces/{Model}RepositoryInterface.phpRegister the binding in a service provider:
$this->app->bind(
PostRepositoryInterface::class,
PostRepository::class
);
Use via dependency injection:
public function __construct(protected PostRepositoryInterface $repository) {}
easy-dev:api-resourceGenerate API Resource and Collection classes for an existing model.
php artisan easy-dev:api-resource {model} [--without-collection]
Generated files:
app/Http/Resources/{Model}Resource.phpapp/Http/Resources/{Model}Collection.phpUsage:
return new PostResource($post);
return new PostCollection(Post::paginate());
easy-dev:sync-relationsAuto-detect relationships from your database schema or migration files and add them to models.
# Sync a specific model
php artisan easy-dev:sync-relations Product
# Sync ALL models
php artisan easy-dev:sync-relations --all
Detects:
belongsTo โ from foreignId columns in the model's migrationhasMany โ by scanning other migrations for foreign keys referencing this modelmorphTo / morphMany โ from $table->morphs() columnsHow it works:
foreignId() and morphs() callseasy-dev:add-relationManually add a relationship method to an existing model.
php artisan easy-dev:add-relation {model} {relation} {related-model} [--method=name]
Supported relation types: hasOne, hasMany, belongsTo, belongsToMany, morphTo, morphOne, morphMany
Example:
php artisan easy-dev:add-relation User hasMany Post
# Adds posts() method to User model
# Optionally adds belongsTo inverse on Post model
easy-dev:helpDisplay the built-in help guide with all commands, options, and examples.
php artisan easy-dev:help
php artisan easy-dev:help --examples
When you run easy-dev:crud with all flags, the generated file structure follows clean architecture principles:
app/
โโโ DTOs/
โ โโโ ProductData.php # Data Transfer Object
โโโ Enums/
โ โโโ ProductStatus.php # PHP 8.1+ Enum
โโโ Filters/
โ โโโ ProductFilter.php # Query Filter
โโโ Http/
โ โโโ Controllers/
โ โ โโโ ProductController.php # Web Controller
โ โ โโโ Api/
โ โ โโโ ProductApiController.php # API Controller
โ โโโ Requests/
โ โ โโโ StoreProductRequest.php # Store Validation
โ โ โโโ UpdateProductRequest.php # Update Validation
โ โโโ Resources/
โ โโโ ProductResource.php # API Resource
โ โโโ ProductCollection.php # API Collection
โโโ Models/
โ โโโ Product.php # Eloquent Model
โโโ Observers/
โ โโโ ProductObserver.php # Model Observer
โโโ Policies/
โ โโโ ProductPolicy.php # Authorization Policy
โโโ Repositories/
โ โโโ ProductRepository.php # Repository Implementation
โ โโโ Contracts/
โ โโโ ProductRepositoryInterface.php # Repository Interface
โโโ Services/
โโโ ProductService.php # Service Implementation
โโโ Contracts/
โโโ ProductServiceInterface.php # Service Interface
database/
โโโ migrations/
โโโ xxxx_create_products_table.php # Migration
routes/
โโโ api.php # API routes appended
โโโ web.php # Web routes appended
Preview exactly what would be generated โ without writing a single file:
php artisan easy-dev:crud Invoice --with-repository --with-service --with-policy --dry-run
Output:
๐ DRY RUN โ Previewing CRUD generation for Invoice...
Files that would be created:
๐ app/Models/Invoice.php
๐ database/migrations/*_create_invoices_table.php
๐ app/Repositories/InvoiceRepository.php
๐ app/Repositories/Contracts/InvoiceRepositoryInterface.php
๐ app/Services/InvoiceService.php
๐ app/Services/Contracts/InvoiceServiceInterface.php
๐ app/Http/Controllers/Api/InvoiceApiController.php
๐ app/Http/Resources/InvoiceResource.php
๐ app/Http/Resources/InvoiceCollection.php
๐ app/Http/Controllers/InvoiceController.php
๐ app/Http/Requests/StoreInvoiceRequest.php
๐ app/Http/Requests/UpdateInvoiceRequest.php
๐ app/Policies/InvoicePolicy.php
Files that would be modified:
โ๏ธ routes/api.php
โ๏ธ routes/web.php
โ๏ธ app/Providers/RepositoryServiceProvider.php
No files were created or modified (dry-run mode).
After publishing the config (php artisan vendor:publish --tag=easy-dev-config), edit config/easy-dev.php:
'model_namespace' => 'App\\Models\\',
'paths' => [
'models' => app_path('Models'),
'controllers' => app_path('Http/Controllers'),
'api_controllers' => app_path('Http/Controllers/Api'),
'requests' => app_path('Http/Requests'),
'repositories' => app_path('Repositories'),
'repository_contracts' => app_path('Repositories/Contracts'),
'services' => app_path('Services'),
'service_contracts' => app_path('Services/Contracts'),
'migrations' => database_path('migrations'),
],
'routes' => [
'api_prefix' => 'api',
'web_prefix' => '',
'web_middleware' => ['web'],
'api_middleware' => ['api'],
'route_model_binding' => true,
],
Set defaults so you don't repeat flags every time:
'defaults' => [
'with_repository' => false, // Set true to always generate repos
'with_service' => false, // Set true to always generate services
'with_interface' => true, // Generate interfaces by default
'generate_api_controller' => true, // Generate API controllers
'generate_web_controller' => true, // Generate web controllers
],
Auto-generated validation rules based on column types:
'validation' => [
'rules' => [
'string' => 'required|string|max:255',
'text' => 'required|string',
'integer' => 'required|integer',
'decimal' => 'required|numeric',
'boolean' => 'required|boolean',
'date' => 'required|date',
'email' => 'required|email|max:255',
'json' => 'required|json',
],
'field_patterns' => [
'email' => 'required|email|max:255',
'password' => 'required|string|min:8',
'slug' => 'required|string|max:255|unique:{table}',
'_id' => 'required|integer|exists:{table},id',
],
],
'relationships' => [
'auto_detect' => true,
'detect_polymorphic' => true,
'generate_reverse_relationships' => true,
'foreign_key_suffix' => '_id',
'polymorphic_suffix' => '_type',
],
'ui' => [
'show_progress_bar' => true,
'show_banner' => true,
'use_icons' => true,
'colored_output' => true,
'interactive_mode_default' => false,
],
After publishing stubs with php artisan vendor:publish --tag=easy-dev-stubs, you can customize any template in resources/stubs/vendor/easy-dev/.
| Category | Stubs |
|---|---|
| Models | model.stub |
| Controllers | controller.stub, controller.enhanced.stub, controller.api.stub, controller.api.enhanced.stub, controller.repository.stub, controller.api.service.stub, controller.web.service.stub |
| Repository | repository.stub, repository.enhanced.stub, repository.interface.stub, repository.interface.enhanced.stub |
| Service | service.stub, service.enhanced.stub, service.interface.stub, service.interface.enhanced.stub |
| Requests | request.store.stub, request.update.stub, request.enhanced.stub |
| Resources | api.resource.stub, api.collection.stub |
| New Generators | policy.stub, dto.stub, observer.stub, filter.stub, enum.stub |
| Relations | relations/belongsTo.stub, relations/hasOne.stub, relations/hasMany.stub, relations/belongsToMany.stub, relations/morphTo.stub, relations/morphOne.stub, relations/morphMany.stub |
| Other | factory.stub |
All stubs use {{ variable }} placeholders:
| Variable | Description | Example |
|---|---|---|
{{ ModelName }} |
PascalCase model name | Product |
{{ modelName }} |
camelCase model name | product |
{{ tableName }} |
Snake_case plural table | products |
{{ RepositoryName }} |
Repository class name | ProductRepository |
{{ InterfaceName }} |
Interface class name | ProductRepositoryInterface |
{{ ServiceName }} |
Service class name | ProductService |
{{ fillable }} |
Fillable fields array | ['name', 'price', 'stock'] |
{{ validationRules }} |
Validation rules | 'name' => 'required|string|max:255' |
The sync-relations command uses a multi-source approach:
graph TD
A[easy-dev:sync-relations] --> B{Database tables exist?}
B -->|Yes| C[Query PRAGMA foreign_key_list]
B -->|No| D[Parse migration files]
C --> E[Extract belongsTo relations]
D --> F[Regex parse foreignId calls]
D --> G[Regex parse morphs calls]
F --> E
G --> H[Extract morphTo relations]
E --> I[Scan other migrations for reverse FK]
I --> J[Extract hasMany relations]
E & H & J --> K[Deduplicate by method name]
K --> L[Insert into Model file]
Detection sources:
PRAGMA foreign_key_list (SQLite) or information_schema (MySQL/PgSQL)foreignId(), constrained(), and morphs() calls# 1. Create the enum for product status
php artisan easy-dev:enum ProductStatus --values=draft,active,archived
# 2. Create the full Product CRUD with all layers
php artisan easy-dev:crud Product --with-repository --with-service --with-policy --with-dto --with-observer
# 3. Create Category with basic CRUD
php artisan easy-dev:crud Category
# 4. Run migrations
php artisan migrate
# 5. Auto-detect relationships between Product and Category
php artisan easy-dev:sync-relations --all
# 6. Add a filter for product queries
php artisan easy-dev:filter Product
# API-only CRUD with service layer
php artisan easy-dev:crud User --api-only --with-service --with-dto
# Generate API resources for responses
php artisan easy-dev:api-resource User
# Add policies for authorization
php artisan easy-dev:policy User
# Add repository pattern to existing model
php artisan easy-dev:repository Customer
# Add API resources
php artisan easy-dev:api-resource Customer
# Add relationships
php artisan easy-dev:add-relation Customer hasMany Order
php artisan easy-dev:add-relation Order belongsTo Customer
The package includes a comprehensive test suite:
cd packages/laravel-easy-dev
composer test
# Or with testdox output
vendor/bin/phpunit --testdox
Test suite: 67 tests, 176 assertions โ covering CRUD generation, dry-run mode, individual generators, relationship commands, and all services.
Contributions are welcome! Please follow these steps:
git checkout -b feature/amazing-featurecomposer testgit commit -m 'Add amazing feature'git push origin feature/amazing-featureThe MIT License (MIT). See LICENSE.md for details.
Made with โค๏ธ for the Laravel community
โญ Star on GitHub โข ๐ Report Issues โข ๐ฌ Discussions