PHPackages                             creativecrafts/laravel-domain-driven-design-lite - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. creativecrafts/laravel-domain-driven-design-lite

ActiveLibrary[Framework](/categories/framework)

creativecrafts/laravel-domain-driven-design-lite
================================================

Domain‑Driven Design (DDD)‑lite scaffolding for Laravel. This package generates a lightweight, opinionated module structure under Modules/\[Module\] and provides Artisan commands to scaffold common artifacts (Actions, Queries, DTOs, Repositories, Models, Controllers, Requests, Mappers, Migrations, Factories, and Tests).

0.0.3(3mo ago)180[2 PRs](https://github.com/CreativeCrafts/laravel-domain-driven-design-lite/pulls)MITPHPPHP ^8.3CI passing

Since Nov 25Pushed 1mo agoCompare

[ Source](https://github.com/CreativeCrafts/laravel-domain-driven-design-lite)[ Packagist](https://packagist.org/packages/creativecrafts/laravel-domain-driven-design-lite)[ Docs](https://github.com/creativecrafts/laravel-domain-driven-design-lite)[ GitHub Sponsors](https://github.com/CreativeCrafts)[ RSS](/packages/creativecrafts-laravel-domain-driven-design-lite/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (2)Dependencies (18)Versions (8)Used By (0)

[![Latest Version on Packagist](https://camo.githubusercontent.com/2375a9c3473cafb714d740d5f1b9d095bf5bdebe93741ba8ed1e49ded33e969b/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f63726561746976656372616674732f6c61726176656c2d646f6d61696e2d64726976656e2d64657369676e2d6c6974652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/creativecrafts/laravel-domain-driven-design-lite)[![GitHub Tests Action Status](https://camo.githubusercontent.com/52bf074f841fbf4ad6b7bbfb8e4a6dad4c9beec84178499e5c7a62b046a57072/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f63726561746976656372616674732f6c61726176656c2d646f6d61696e2d64726976656e2d64657369676e2d6c6974652f63692e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/creativecrafts/laravel-domain-driven-design-lite/actions?query=workflow%3ACI+branch%3Amain)[![Code Style](https://camo.githubusercontent.com/77ab795aa0b5650fd6ff95e341504e7893101304fb3218c830491c30734c7432/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f636f64652532307374796c652d70696e742d626c75653f7374796c653d666c61742d737175617265)](https://github.com/creativecrafts/laravel-domain-driven-design-lite/actions/workflows/pint-autofix.yml)[![Total Downloads](https://camo.githubusercontent.com/f2c928f51964cd35ca7e69210b45e560baf1e5a885c9de803f917eaf24109f4a/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f63726561746976656372616674732f6c61726176656c2d646f6d61696e2d64726976656e2d64657369676e2d6c6974652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/creativecrafts/laravel-domain-driven-design-lite)

> Pragmatic, Laravel-native **DDD modules** with generators, safety rails, and CI helpers – without drowning you in ceremony.

---

✅ Quick Start (60s)
-------------------

[](#-quick-start-60s)

```
composer require creativecrafts/laravel-domain-driven-design-lite --dev
php artisan ddd-lite:module Planner
php artisan ddd-lite:make:dto Planner CreateTripData --props="id:Ulid|nullable,title:string"
php artisan ddd-lite:publish:quality --target=all
```

---

📚 Contents
----------

[](#-contents)

- [Start Here](#start-here)
- [What is DDD‑Lite?](#what-is-ddd-lite)
- [Architecture Overview](#architecture-overview)
- [Requirements](#requirements)
- [Installation](#installation)
- [Provider &amp; Publishing](#provider--publishing)
- [Getting Started (QuickStart)](#getting-started-quickstart)
- [Command Reference](#command-reference)
- [Project Initialization](#project-initialization)
- [Enforcing Strict Architecture with Deptrac + PHPStan](#enforcing-strict-architecture-with-deptrac--phpstan)
- [Limitations: Circular Dependencies at Scale](#limitations-circular-dependencies-at-scale)
- [Safety Rails: Manifest &amp; Rollback](#safety-rails-manifest--rollback)
- [Package Quality: PHPStan, Deptrac &amp; Pest](#package-quality-phpstan-deptrac--pest)
- [Common Workflows](#common-workflows)
- [Testing Philosophy](#testing-philosophy)
- [Design Principles](#design-principles)
- [Troubleshooting](#troubleshooting)
- [Changelog](#changelog)
- [Security](#security)
- [Credits](#credits)
- [License](#license)

🧩 Start Here
------------

[](#-start-here)

If you only read three sections:

- **Getting Started (QuickStart)** – a 60‑second setup.
- **Common Workflows** – the most practical end‑to‑end examples.
- **Command Reference** – every command and flag in one place.

### 🧭 What is DDD-Lite?

[](#-what-is-ddd-lite)

**DDD-Lite** is a developer-tooling package that helps you organise your Laravel 12+ application into **modular, domain-oriented boundaries**.

It gives you:

- A **module structure** (`modules/`) with a clear split between:
    - `App/` – adapters &amp; Laravel-specific glue (controllers, requests, models, providers, repositories)
    - `Domain/` – pure PHP domain code (DTOs, actions, contracts, queries, value objects)
- **Generators** for:
    - DTOs, Actions, Contracts, Repositories, Value Objects
    - Queries and Query Builders
    - Aggregate Roots
    - Controllers, Requests, Models, Migrations, Providers, Routes
- A **conversion engine** to move existing `app/*` code into modules:
    - Discovers move candidates (controllers, models, requests, actions, DTOs, contracts)
    - Applies moves with AST-based namespace rewrites
- **Safety rails** for all file operations:
    - Every run produces a **Manifest** (with creates/updates/deletes/moves/mkdirs)
    - `--dry-run` on everything
    - **Rollback** by manifest id
- **Quality &amp; CI tooling**:
    - Publishable PHPStan &amp; Deptrac configs
    - Optional Pest architecture tests
    - `ddd-lite:doctor` / `ddd-lite:doctor:domain` / `ddd-lite:doctor-ci` to keep modules healthy

The goal is: **clean seams, safer refactors, better testability** – without requiring you to rewrite your entire app in one go.

---

🧱 Architecture Overview
-----------------------

[](#-architecture-overview)

A DDD-Lite **module** lives under `modules/`:

```
modules//
├─ App/
│  ├─ Http/
│  │  ├─ Controllers/
│  │  └─ Requests/
│  ├─ Models/
│  ├─ Providers/
│  └─ Repositories/
├─ Domain/
│  ├─ Actions/
│  ├─ Contracts/
│  ├─ DTO/
│  ├─ Queries/
│  └─ ValueObjects/
├─ database/
│  └─ migrations/
├─ Routes/
│  ├─ api.php
│  └─ web.php
└─ tests/
   ├─ Feature/
   └─ Unit/

```

✅ Rules of thumb

**Domain:**

- Pure PHP, no hard dependency on Laravel.
- Orchestrates use cases with Actions (e.g. CreateTripAction).
- Talks to the outside world through Contracts (e.g. TripRepositoryContract).
- Uses DTOs and Value Objects for data.

**App:**

- Typical Laravel adapters (controllers, form requests, models).
- Implements contracts using Eloquent (e.g. TripRepository).
- Wires things together using module service providers.

### ⚙️ Requirements

[](#️-requirements)

- PHP: ^8.3
- Laravel (Illuminate components): ^12.0
- Composer

Recommended dev dependencies in your app (for quality tooling integration):

- larastan/larastan
- deptrac/deptrac
- pestphp/pest
- pestphp/pest-plugin-laravel
- pestphp/pest-plugin-arch

### ⚙️ Installation

[](#️-installation)

Require the package in your Laravel app (usually as a dev dependency):

```
composer require creativecrafts/laravel-domain-driven-design-lite --dev
```

> This package is primarily a developer tool (scaffolding, conversion, quality helpers), so installing under --dev is recommended. Laravel’s package discovery will automatically register the service provider.

### 📦 Provider &amp; Publishing

[](#-provider--publishing)

DDD-Lite ships with stubs and quality configs you can copy into your app.

**Stubs (module scaffolding &amp; generators)**

To publish the stubs:

```
php artisan vendor:publish --tag=ddd-lite
php artisan vendor:publish --tag=ddd-lite-stubs
```

This will create:

- `stubs/ddd-lite/*.stub` – templates for:
    - DTOs, Actions, Contracts, Repositories, Value Objects, Aggregates
    - Controllers (including an --inertia variant)
    - Requests
    - Models &amp; migrations
    - Module providers and route/event providers
    - Routes (web &amp; api)

You typically don’t need to touch these unless you want to customise the generated code style.

**Quality tooling**

To seed PHPStan, Deptrac and Pest architecture tests into your application:

```
php artisan ddd-lite:publish:quality --target=all
```

This will (in your app):

- Create `phpstan.app.neon` with sensible defaults for `app/` + `modules/`
- Create `deptrac.app.yaml` describing layer boundaries (Http, Models, Domain, Modules, etc.)
- Add `tests/ArchitectureTest.php` with baseline rules:
    - No debug helpers (`dd`, `dump`, `var_dump`, …)
    - No stray `env()` calls
    - Enforce strict types

**Safe publishing tip**

- Run once, then commit the generated files so changes are visible in code review.

You can also publish selectively:

```
php artisan ddd-lite:publish:quality --target=phpstan
php artisan ddd-lite:publish:quality --target=deptrac
php artisan ddd-lite:publish:quality --target=pest-arch
```

**Customising stubs (recommended workflow)**

1. Publish the stubs once:

```
php artisan vendor:publish --tag=ddd-lite-stubs
```

2. Edit the generated files under `stubs/ddd-lite/` in your app (e.g. tweak DTO or controller templates).
3. Re-run the generator command. Your customised stubs are now the source of truth.

Tip: keep your stub changes small and version-controlled so upgrades are easy to diff.

✅ Enforcing Strict Architecture with Deptrac + PHPStan
------------------------------------------------------

[](#-enforcing-strict-architecture-with-deptrac--phpstan)

This package ships publishable templates you can wire into your app to enforce module boundaries and strict layered architecture.

### 1) Publish the configs

[](#1-publish-the-configs)

```
php artisan ddd-lite:publish:quality --target=deptrac
php artisan ddd-lite:publish:quality --target=phpstan
```

This creates (in your app):

- `deptrac.app.yaml` – layer rules for `app/` and `modules/`
- `phpstan.app.neon` – analysis paths + defaults for `modules/`

### 2) Deptrac: strict module boundaries

[](#2-deptrac-strict-module-boundaries)

The template already defines layers like `Http`, `Models`, `Repositories`, `Domain`, `Providers`, and `ModulesAll`. To enforce stricter module boundaries, extend the ruleset to constrain `Modules\*\Domain` and `Modules\*\App` explicitly.

Example (add to `deptrac.app.yaml`):

```
layers:
  - name: ModuleDomain
    collectors:
      - type: classNameRegex
        value: '#^Modules\\[^\\]+\\Domain\\.*$#'

  - name: ModuleApp
    collectors:
      - type: classNameRegex
        value: '#^Modules\\[^\\]+\\App\\.*$#'

ruleset:
  ModuleDomain:
    - Framework
  ModuleApp:
    - ModuleDomain
    - Framework
```

For cross‑module rules, add a shared kernel (e.g. `Modules\Shared`) and only allow `ModuleDomain` to depend on `Modules\Shared` (not other modules).

### 3) PHPStan: include modules and tighten strictness

[](#3-phpstan-include-modules-and-tighten-strictness)

The published `phpstan.app.neon` already includes:

- `paths: [app, modules]`
- Larastan extension include

To go stricter, set `level: max` and enable stricter checks:

```
parameters:
  level: max
  checkMissingIterableValueType: true
  checkGenericClasses: true
```

### 4) CI integration

[](#4-ci-integration)

Use the existing Composer scripts:

```
composer run deptrac:app-template
composer run stan
```

⚠️ Limitations: Circular Dependencies at Scale
----------------------------------------------

[](#️-limitations-circular-dependencies-at-scale)

- Deptrac detects circular dependencies at the **layer graph** level. If you do not model modules as distinct layers, cycles across modules may be invisible.
- Dynamic resolution (service container bindings, facades, late static calls) can hide cycles that Deptrac cannot infer statically.
- Large modular systems can produce noisy or slow analysis. You may need to scope rules (`paths`, `exclude_files`) or split configs per module to keep feedback fast.
- PHPStan does **not** detect architectural cycles; it only validates types and static correctness. Use Deptrac (or Pest Arch tests) for structure enforcement.

🚀 Getting Started (QuickStart)
------------------------------

[](#-getting-started-quickstart)

We’ll build a simple Planner module with a Trip aggregate.

**1) Scaffold a module**

```
php artisan ddd-lite:module Planner
```

This creates modules/Planner with:

- Providers (module, route, event) under App/Providers
- Routes in Routes/api.php and Routes/web.php
- Domain folders (Actions, DTOs, Contracts, Queries, ValueObjects)
- Tests folders

Core flags:

- --dry-run – preview actions without writing
- --fix-psr4 – auto-rename lowercased module folders to proper PascalCase
- --shared – scaffold a Shared Kernel (domain‑only) module
- --rollback= – undo a previous scaffold
- --force – overwrite content when needed (with backups)

> For full details see: docs/module-scaffold.md

**2) Generate a DTO**

```
php artisan ddd-lite:make:dto Planner CreateTripData \
  --props="id:Ulid|nullable,title:string,startsAt:CarbonImmutable,endsAt:CarbonImmutable"
```

This generates modules/Planner/Domain/DTO/CreateTripData.php:

- Properly typed constructor
- readonly by default
- Optional unit test (unless --no-test is passed)

**3) Generate a domain Action**

```
php artisan ddd-lite:make:action Planner CreateTrip \
  --in=Trip \
  --input=FQCN --param=data \
  --returns=ulid
```

This creates Domain/Actions/Trip/CreateTripAction.php similar to:

```
namespace Modules\Planner\Domain\Actions\Trip;

use Modules\Planner\Domain\Contracts\TripRepositoryContract;
use Modules\Planner\Domain\DTO\CreateTripData;

final class CreateTripAction
{
    public function __construct(
        private TripRepositoryContract $repo,
    ) {}

    public function __invoke(CreateTripData $data): string
    {
        // Domain invariants live here
        return $this->repo->create($data);
    }
}
```

**4) Implement the repository &amp; bind it**Create an Eloquent repository in modules/Planner/App/Repositories/TripRepository.php (or let ddd-lite:make:repository scaffold it):

```
php artisan ddd-lite:make:repository Planner Trip
```

Then wire the contract to the implementation:

```
php artisan ddd-lite:bind Planner TripRepositoryContract TripRepository
```

ddd-lite:bind edits your module provider so that:

```
$this->app->bind(
    TripRepositoryContract::class,
    TripRepository::class,
);
```

is registered.

**5) Expose via HTTP**Generate a controller + request:

```
php artisan ddd-lite:make:controller Planner Trip --resource
php artisan ddd-lite:make:request Planner StoreTrip
```

### ✅ Recipes

[](#-recipes)

**Recipes index**

- Controller orchestrates a Domain action
- Payments module walkthrough
- Orders module creation + structure

#### Controller Orchestrates a Domain Action (HTTP stays in App)

[](#controller-orchestrates-a-domain-action-http-stays-in-app)

This is the missing piece most people want: the controller only adapts HTTP input and delegates to the Domain action. The action stays HTTP‑free.

**1) Generate the pieces**

```
php artisan ddd-lite:make:action Billing CreateInvoice --in=Invoice --input=FQCN
php artisan ddd-lite:make:controller Billing Invoice
php artisan ddd-lite:make:request Billing StoreInvoice
```

**2) Domain action (pure business logic)**

```
