laravel-ddd/starter
Composer starter kit that turns a fresh Laravel 12/13 app into a Domain-Driven Design structure. Includes base Entity/ValueObject/Repository/Service classes, 12 generators, interactive installer (auth, docs, tests, sample module), API-ready routes, and optional AI context.
## Getting Started
1. **Installation**:
```bash
composer create-project laravel/laravel my-project
cd my-project
composer require laravel-ddd/starter
php artisan ddd:install
Follow the interactive prompts to configure auth, sample modules, and testing.
First Use Case:
Create a module for your first domain (e.g., Products):
php artisan ddd:make-module Products
This generates a complete module structure with entities, repositories, services, and tests.
Key Files to Explore:
app/Domains/ – Module organizationroutes/domains/ – Domain-specific routesconfig/ddd.php – Package configurationddd:make-module for a new domain (e.g., Orders).ddd:make-entity for domain-specific entities (e.g., Order, OrderItem).ddd:make-repository) and services (ddd:make-service) to encapsulate business logic.ddd:make-controller) that delegate to services.Example:
php artisan ddd:make-module Orders
php artisan ddd:make-entity Order Orders --migration --model
php artisan ddd:make-service OrderService Orders
php artisan ddd:make-repository OrderRepository Orders --eloquent
php artisan ddd:make-controller OrderController Orders
Entity base class for objects with identity (e.g., User, Product).
class User extends Entity {
public function getEmail(): Email { ... }
}
ValueObject for immutable data (e.g., Email, Price).
class Email extends ValueObject {
public function __construct(protected string $value) { ... }
}
RepositoryInterface for data access abstraction.
class EloquentOrderRepository implements OrderRepositoryInterface { ... }
class OrderService extends Service {
public function createOrder(OrderData $data) { ... }
}
Domains/[Module]/Tests/Unit/.Domains/[Module]/Tests/Feature/.php artisan test --filter=Orders
ddd:make-resource) for JSON serialization.ddd:make-request for validation logic.routes/domains/[Module].php.routes/api.php:
require app_path('Domains/Orders/Routes/Orders.php');
class OrderController extends Controller {
public function store(Request $request, OrderService $service) {
$order = $service->create($request->validated());
return response()->json(['data' => $order], 201);
}
}
--migration flag).app/Models/ (separate from domain logic).php artisan migrate
Namespace Conflicts:
Domains/Users/Entities/User vs. Domains/Admins/Entities/User).CustomerManagement instead of Users).Test Generation Overrides:
config/ddd.php for generate_tests and test_package settings.php artisan vendor:publish --tag=ddd-config
Then update the config and regenerate components.Route Caching:
php artisan route:clear
Eloquent Model Placement:
app/Models/ by default, which may feel out of place in a DDD structure.Domains/[Module]/Infrastructure/Persistence/Models/.Service Provider Registration:
config/app.php.php artisan ddd:list to verify all providers are listed.Interactive Installer Quirks:
app/Domains/).app/Domains/ directory and rerun ddd:install.Command Issues:
composer show laravel-ddd/starter
composer require laravel-ddd/starter --dev
Stub Customization:
vendor/laravel-ddd/starter/src/stubs/.php artisan vendor:publish --tag=ddd-stubs --force
resources/stubs/.AI Agent Context:
AGENTS.md file is optional but useful for AI-assisted development.curl -o AGENTS.md https://raw.githubusercontent.com/MMoza/laravel-ddd/main/agents/AGENTS.md
Custom Base Classes:
Entity, ValueObject, etc.) in app/Domains/Base/.Entity:
namespace App\Domains\Base;
use Illuminate\Database\Eloquent\SoftDeletes;
class Entity extends \Illuminate\Database\Eloquent\Model {
use SoftDeletes;
// ...
}
Additional Artisan Commands:
app/Console/Commands/ to extend DDD functionality.php artisan make:command Ddd:Make:Event
Domain Events:
Events/ directory in each module.php artisan ddd:make-event OrderCreated Orders
Policy Integration:
Domains/[Module]/Policies/ and register them in the module’s service provider.Gate::resource('orders', Order::class, OrderPolicy::class);
Eager Loading:
$repository->with(['items.product'])->find($id);
Caching:
$repository->remember(60, function () { ... });
Batch Processing:
$repository->update([1, 2, 3], ['status' => 'processed']);
Keep Controllers Thin:
// Bad: Business logic in controller
public function update(Request $request) {
$user = User::find($request->id);
$user->update($request->all());
}
// Controller delegates to service
public function update(Request $request, UserService $service) {
$service->update($request->id, $request->validated());
}
Use Value Objects for Primitive Obsession:
string, int) with value objects (e.g., Email, Money).class Money extends ValueObject {
public function __construct(public int $amount, public string $currency) {}
}
Domain Events for Side Effects:
How can I help you explore Laravel packages today?