TL;DR —
composer require bouda/laravel-make-pattern→php artisan make:pattern Post→ 9 consistent files in seconds. DDD-ready, rollback included, every stub is yours to override.
The problem I kept running into
Every new Laravel project starts the same way. You know the architecture you want: Repository, Service, Controller, some Form Requests, a Resource, a Policy, a test. You've written this stack dozens of times. And every time, you either:
-
Copy-paste from a previous project — and immediately introduce inconsistency between how
PostRepositoryis structured vsCategoryRepository. - Write everything from scratch — which is slow and error-prone.
-
Use
make:model -a— which gives you the Model, Migration, Factory, Controller, but nothing about repositories, services, or policies wired together.
None of these feel like the right answer when you want a clean, layered architecture.
So I built laravel-make-pattern.
What it does
One command:
php artisan make:pattern Post
Generates 9 files:
app/Models/Post.php
app/Repositories/Contracts/PostRepositoryInterface.php
app/Repositories/PostRepository.php
app/Services/PostService.php
app/Http/Controllers/PostController.php
app/Http/Requests/PostStoreRequest.php
app/Http/Requests/PostUpdateRequest.php
app/Http/Resources/PostResource.php
app/Policies/PostPolicy.php
tests/Feature/PostTest.php
All consistently named, all using the same conventions, all generated from stubs you own and can override.
The generated code
Here's what the repository looks like out of the box:
<?php
namespace App\Repositories;
use App\Models\Post;
use App\Repositories\Contracts\PostRepositoryInterface;
class PostRepository implements PostRepositoryInterface
{
public function all()
{
return Post::all();
}
public function find(string $id)
{
return Post::findOrFail($id);
}
public function create(array $data)
{
return Post::create($data);
}
public function update(string $id, array $data)
{
$model = $this->find($id);
$model->update($data);
return $model;
}
public function delete(string $id)
{
$model = $this->find($id);
$model->delete();
}
}
Real, runnable code — not a stub you still have to fill in for 20 minutes.
Features
🏗 DDD / Domain mode
One flag changes everything:
php artisan make:pattern Post --domain=Blog
Generates everything under app/Domain/Blog/ with auto-adapted namespaces:
app/Domain/Blog/Models/Post.php
app/Domain/Blog/Repositories/Contracts/PostRepositoryInterface.php
app/Domain/Blog/Repositories/PostRepository.php
app/Domain/Blog/Services/PostService.php
app/Domain/Blog/Http/Controllers/PostController.php
App\Domain\Blog\Models, App\Domain\Blog\Services — no manual find-and-replace.
🔧 Custom root namespace
php artisan make:pattern Post --namespace=Acme
# => Acme\Models\Post, Acme\Services\PostService, etc.
# Combine with --domain:
php artisan make:pattern Post --domain=Blog --namespace=Acme
# => Acme\Domain\Blog\Models\Post
🎯 Generate only what you need
Already have a Model? Skip it:
php artisan make:pattern Post --only=repository,service,controller
↩️ Rollback support
Every run is recorded in an append-only audit log:
php artisan make:pattern:history
+----+----------+------------------+-------+
| ID | Entity | Date | Files |
+----+----------+------------------+-------+
| 3 | Comment | 2026-08-03 09:15 | 9 |
| 2 | Category | 2026-08-03 09:10 | 9 |
| 1 | Post | 2026-08-03 09:02 | 9 |
+----+----------+------------------+-------+
Undo the last run:
php artisan make:pattern:undo
Target a specific run by ID — files modified since generation are reported, not silently deleted:
php artisan make:pattern:undo --id=01ARZ3NDEKTSV4RRFFQ69G5FAV
📝 Fully customizable stubs
php artisan vendor:publish --tag=make-pattern-stubs
Edit any stub (repository.stub, service.stub, controller.stub...) and the generator uses your version automatically. Override one layer, leave the rest untouched.
🔒 Repository with error logging (opt-in)
Set this in your config:
// config/make-pattern.php
'wrap_repository_calls' => true,
Every mutating method is then generated with a try/catch that logs before rethrowing:
public function create(array $data)
{
try {
return Post::create($data);
} catch (\Throwable $e) {
Log::error('PostRepository::create failed', ['exception' => $e]);
throw $e;
}
}
🏷 Primary key strategy
'primary_key' => [
'strategy' => 'ulid', // or 'uuid' or 'increment'
],
Installation
composer require bouda/laravel-make-pattern
Auto-discovered — nothing to register manually.
Publish the config (optional):
php artisan vendor:publish --tag=make-pattern-config
Requirements: PHP 8.2+, Laravel 11, 12, or 13.
Why not make:model -a?
make:model -a is great for an Eloquent-centric approach: Model, migration, factory, seeder, controller. It's the right tool if you stay close to Eloquent.
make:pattern targets a different need — teams that want a layered architecture (Repository pattern, Service layer) but don't want to hand-write the same interfaces, bindings, and boilerplate every single time.
It's not opinionated about what you put inside these files — the stubs are yours. It's opinionated about the structure, which is exactly what keeps a codebase consistent across a team.
Links
- 📦 Packagist: packagist.org/packages/bouda/laravel-make-pattern
- 💻 GitHub: github.com/Bouda-Bissari/laravel-make-pattern
If you find it useful, a ⭐ on GitHub goes a long way. Issues and PRs are very welcome.
Top comments (0)