Download the PHP package bouda/laravel-make-pattern without Composer
On this page you can find all versions of the php package bouda/laravel-make-pattern. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download bouda/laravel-make-pattern
More information about bouda/laravel-make-pattern
Files in bouda/laravel-make-pattern
Package laravel-make-pattern
Short Description Generate a full CRUD scaffold (Model, Repository, Service, Controller, Requests, Resource, Policy, Test) from a single Artisan command.
License MIT
Informations about the package laravel-make-pattern
Laravel Make Pattern
Generate a complete, working CRUD scaffold from one Artisan command — Model, Migration, Factory, Repository (+ interface), Service, Controller, Form Requests, API Resource, Policy and a Feature test, wired together with a container binding and a route.
The generated test passes immediately, because the scaffold is connected: the repository interface is bound in the container, the policy is registered, and the controller is routed.
Table of contents
- Why
- Requirements
- Installation
- Usage
- What gets generated
- Options
- Domain (DDD) mode
- Custom root namespace
- Configuration
- Overriding the stubs
- History, undo and backups
- Logging
- Testing
- Upgrading from 0.2
- Changelog
- Contributing
- Security
- Credits
- License
Why
Writing the same repository/service/controller boilerplate for every resource gets old fast, and copy-pasting an existing module invites drift between resources.
Most Laravel scaffolders are either too minimal (model + migration) or hard-code an architecture you may not use. Two things make this one different:
- The output runs. Generating a
PostServicethat type-hintsPostRepositoryInterfaceis useless if nothing binds the interface — you get aBindingResolutionExceptionon the first request. This package maintains the binding, the policy registration and the route for you. - Every layer is config-driven. Disable what you don't need, override any stub, point a layer at a different namespace. The generator adapts to your conventions instead of the other way around.
Requirements
- PHP 8.2+
- Laravel 11.x, 12.x, or 13.x (PHP 8.3+ required for Laravel 13)
Installation
The service provider is auto-discovered — nothing to register manually.
On Laravel 11+, routes/api.php doesn't exist until you run php artisan install:api. Run it before generating: install:api silently refuses to wire the file into bootstrap/app.php if it already exists, so the generator deliberately never creates it — it tells you to run install:api and skips route registration instead. Everything else is still generated.
Usage
Preview without writing anything:
What gets generated
Plus two idempotent edits:
routes/api.php—Route::apiResource('posts', PostController::class);bootstrap/providers.php— registersPatternServiceProvider
PatternServiceProvider is the piece that makes the scaffold work. It accumulates one entry per entity:
New entries are inserted above the marker comments. The rest of the file is yours — running the command again never duplicates an entry or overwrites your edits.
Options
| Option | Description |
|---|---|
--only=model,service |
Generate only these layers |
--except=test,migration |
Generate everything except these layers |
--domain=Blog |
Group all layers under a domain (DDD style) |
--namespace=Acme |
Override the root namespace (default: App) |
--path=src |
Directory the overridden root namespace maps to |
--force |
Overwrite existing files (the originals are backed up) |
--dry-run |
Print what would be written, write nothing |
An unknown layer name is an error, not a silent no-op. Valid layer names are the keys of the layers array in the config: model, migration, factory, repository_interface, repository, service, controller, store_request, update_request, resource, policy, test.
Domain (DDD) mode
Each layer's directory is derived from its namespace, so path and namespace can never drift apart: everything stays PSR-4 autoloadable.
Two details that matter in domain mode, and that the generator handles for you:
- Policies are registered explicitly in
PatternServiceProvider, because Laravel's auto-discovery only looks forApp\Policies\PostPolicynext toApp\Models\Post. - Factories are bound with a
newFactory()method on the model, because factory discovery is convention-based too.
Rename the Domain segment (or drop it) in the config:
Custom root namespace
--path defaults to a lowercased mirror of the namespace (Acme → acme/). Only the primary root moves; Tests\ and Database\Factories\ stay where they are. The command reminds you to add the namespace to the psr-4 map in composer.json.
Combine with --domain:
Configuration
Published to config/make-pattern.php.
Roots
Every layer namespace sits under a PSR-4 root. This is what keeps paths and namespaces in sync.
| Key | Meaning |
|---|---|
path |
The directory this namespace maps to in composer.json |
domain |
prefix → App\Domain\Blog\Services, suffix → Tests\Feature\Blog, none → ignore --domain |
primary |
The single root that --namespace rewrites |
Everything else
| Key | Description | Default |
|---|---|---|
layers.*.enabled |
Generate this layer or not | true |
layers.*.namespace |
PSR-4 namespace; the directory is derived from it | Laravel conventions |
layers.*.stub |
Stub name | per layer |
layers.*.suffix |
Appended to the entity name to form the class name | per layer |
primary_key.strategy |
ulid, uuid or increment — drives the model traits, the migration column and the $id type hints |
ulid |
tenancy.enabled / tenancy.driver |
Adds the driver's trait to the model. Drivers are declarable in tenancy.drivers |
false / stancl |
wrap_repository_calls |
Wrap repository writes in try/catch + Log::error(), rethrowing. Uses the repository-with-logging stub |
false |
policies.enforce_in_controller |
Controller calls Gate::authorize() in every action. Uses the controller-authorized stub |
true |
provider.enabled |
Maintain PatternServiceProvider |
true |
provider.class |
Its fully qualified name | App\Providers\PatternServiceProvider |
provider.auto_register |
Add it to bootstrap/providers.php |
true |
routes.enabled / routes.file |
Register a resource route for the controller | true / routes/api.php |
routes.method |
apiResource or resource |
apiResource |
routes.middleware |
e.g. ['auth:sanctum'] |
[] |
user_model |
Imported by the generated policy; null for no type hint |
App\Models\User |
base_controller |
Extended by the generated controller; null to extend nothing |
App\Http\Controllers\Controller |
history.path / history.backups / history.keep |
Where runs and backups are stored, and how many to keep | storage/app/make-pattern/…, 50 |
Overriding the stubs
A published stub always wins over the packaged one, so you can override a single layer without touching the rest.
Every stub receives:
| Placeholder | Example |
|---|---|
{{ namespace }}, {{ class }} |
App\Services, PostService |
{{ entity }}, {{ entityVariable }}, {{ entitySnake }} |
Post, post, post |
{{ entityTable }}, {{ routeUri }} |
posts, posts |
{{ idType }} |
string or int, from the primary key strategy |
{{ <layer>Fqcn }}, {{ <layer>Class }}, {{ <layer>Namespace }} |
{{ repositoryInterfaceFqcn }} → App\Repositories\Contracts\PostRepositoryInterface |
Layer placeholders are generated from the config, so a layer you add yourself gets its own set automatically. Cross-layer references are built from the resolved targets, which is why a stub still imports the right class under --domain.
Feature flags select a stub variant before falling back to the base name, so publishing repository-with-logging.stub or controller-authorized.stub overrides just that variant.
History, undo and backups
Every run is recorded in storage/app/make-pattern/history.json:
Undo is content-aware:
- a file the run created is deleted;
- a file the run overwrote (
--force) or edited (routes, provider) is restored from its backup, never deleted; - a file that changed after generation is left alone and reported. Pass
--forceto roll it back anyway.
Backups live in storage/app/make-pattern/backups/{run-id}/ and are pruned along with the history (history.keep, default 50 runs).
Logging
Technical output goes to the standard Log facade, separate from the history above:
info— start and end of a generationwarning— a skipped file, a missing markererror— an exception, followed by an automatic rollback of that run
To keep generator noise out of laravel.log, define a make-pattern channel in config/logging.php; the package picks it up automatically.
Testing
Tests run against Orchestra Testbench, so no full Laravel app is needed.
Upgrading from 0.2
Version 0.3 is a breaking release.
- Re-publish your config (
vendor:publish --tag=make-pattern-config --force). Layers now declare anamespaceand the directory is derived from it;layers.*.pathis only used by layers without a namespace, likemigration. - Re-publish your stubs if you had published them. The
{{ domainNamespace }}and{{ rootNamespace }}placeholders are gone, replaced by the per-layer{{ <layer>Fqcn }}set. log_pathis replaced byhistory.path. The old key is still honoured if present.primary_key.strategyandtenancy.*were documented but not implemented in 0.2. They now work — check that the defaults match what your 0.2 code actually generated (ulid).- Older history entries are still readable, but they carry no backups, so undoing a pre-0.3 run can only delete.
Changelog
See CHANGELOG.md.
Contributing
Issues and pull requests are welcome. Please run composer test before submitting a PR.
Security
If you discover a security issue, please open a GitHub issue rather than a public PR with exploit details.
Credits
License
The MIT License (MIT). See LICENSE for more information.