Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Domain Maker Laravel Package

phpsquad/domain-maker

Domain Maker is a Laravel package for scaffolding domain-driven design structures. Use Artisan commands to generate domains, actions, DTOs, models, and related classes, keeping business logic organized and your application easier to maintain.

View on GitHub
Deep Wiki
Context7

Getting Started

The package is a scaffolding generator, not a runtime framework — nothing changes in how Laravel boots. Get it installed on a scratch branch first and confirm it works with your Laravel version before committing to it.

Minimal install

composer require phpsquad/domain-maker --dev
php artisan vendor:publish --tag=domain-maker   # or --provider=...; see the package README

The publish step matters: it drops a config file (typically config/domain-maker.php) and/or stubs that control where domains are written and what namespace they use. Inspect it before generating anything, because the paths/namespace it defines become the contract for every file it produces.

Where to look first

  1. The published config — source/target paths and PSR-4 base namespace.
  2. php artisan list | grep domain — the generator family is prefixed (domain:make:* / make:domain-* depending on version). Signatures shifted between releases, so confirm before scripting anything.
  3. One generated domain, end-to-end — generate it, read every file, then decide what you'd keep.

First use case

Pick a genuinely bounded slice — e.g. Billing — not Core or App. Generate the domain container, then one vertical slice through it:

php artisan domain:make Billing
php artisan domain:make:model Billing Invoice
php artisan domain:make:action Billing CreateInvoice
php artisan domain:make:controller Billing InvoiceController

You should end up with something like app/Domain/Billing/{Models,Actions,Http/Controllers} (exact layout per config). Immediately run composer dump-autoload and hit the route — if the namespace isn't autoloadable, that's your first integration task, not a bug in your code.

Implementation Patterns

One domain = one bounded context. The generator creates folders; it does not create boundaries. Treat each top-level domain as a namespace you can eventually extract into its own package. If two domains share a model, you've found a missing shared kernel or a boundary you drew wrong.

Generate by layer, not by feature. The value of the generators is consistency across many small files, so map your team's canonical layers onto them and always generate in the same order:

Domain/<Context>/
  Actions/          # invokable use cases, one public __invoke
  DataTransferObjects/
  Models/           # Eloquent, thin
  Contracts/        # interfaces for cross-domain + persistence
  Repositories/     # Eloquent implementations of Contracts
  Events/ Listeners/
  Http/Controllers/ Requests/ Resources/
  Providers/        # bind interfaces, register routes, migrations
  Tests/

Wire each domain through its own service provider. Register bindings (Contract → EloquentRepository), load the domain's routes, and point migrations at the domain's Database/Migrations folder. Generate the provider with the package, then treat it as the only place the domain touches the framework.

Cross-domain communication: events or contracts, never models. Domain A should never use App\Domain\B\...\Models\.... Publish an event from A and listen in B, or define a contract in A and bind an adapter in B's provider. This is what makes eventual extraction possible and is the single highest-leverage discipline the folder structure is meant to enforce.

Actions as the integration surface. Controllers, jobs, listeners, and console commands all call the same action. The package can generate the wrapper for each; keep the logic in the action so the wrappers stay thin.

final class CreateInvoice
{
    public function __construct(private InvoiceRepository $invoices) {}

    public function __invoke(CreateInvoiceData $data): Invoice
    {
        return $this->invoices->store(Invoice::open($data->customerId, $data->lines));
    }
}

DTOs at every boundary — HTTP request → DTO → action → repository. Generate them with the package rather than hand-rolling array shapes; consistency is the whole point.

Migrations and seeders belong to the domain. Use the config's migrations path so php artisan migrate picks up domain migrations without copying files into the app root. Same for factories and seeders.

Tests: point PHPUnit at the domain test dirs in phpunit.xml (./app/Domain/*/Tests), and generate the test alongside the class so it's never orphaned.

Team workflow. Scaffold on a short-lived branch, review the generated diff, delete what you don't need, then commit. Generated files are a starting point — the reviewer's job is to reject ceremony (empty repositories wrapping Eloquent one-to-one, DTOs for two-field payloads).

Gotchas and Tips

Archived status is the headline risk. Last release was December 2022, so it predates Laravel 10/11 conventions. Expect to loosen composer constraints or fork. Test on a throwaway branch against your exact Laravel and PHP versions before proposing it to a team; if the service provider or stubs break, forking and patching a dozen files is usually faster than finding a successor.

New domains are not autoloadable automatically. Composer's PSR-4 map is static. Either add a wildcard-ish base mapping once ("App\\Domain\\": "app/Domain/") or add a mapping per domain and composer dump-autoload every time. "Class not found" right after generating is almost always this.

Config caching bites during setup. If you change the config after publishing while config:cache is on, generated paths silently stay stale. php artisan config:clear after any config edit.

Duplicate class names across domains. Two contexts will both want User, Address, Status. Because generators name files after the class, you'll get collisions in IDE search and in any code doing string-based class resolution. Namespace carefully and prefer context-prefixed names (BillingInvoice) at the edges.

Command signatures drift between releases. Don't bake generator commands into CI scripts or onboarding docs without pinning the package version; domain:make:model vs make:domain-model and argument ordering have both varied. php artisan list is the source of truth for your lockfile.

Stubs are the extension point. Publish and edit the stubs to encode house style — declare(strict_types=1), final classes, readonly DTOs, your base test case, your enum conventions. That is the cheapest way to make the tool produce code your team would actually merge. Don't modify vendor files; re-publish or fork.

Generated tests may use outdated PHPUnit syntax (annotations vs attributes). Fix the stub once rather than every generated test.

The structure is inert. Nothing prevents App\Domain\Billing\Models\Invoice from calling App\Domain\Shipping\Models\Shipment. Enforce boundaries with code review, a Deptrac or PHPArkitect ruleset, or PHPStan baseline — otherwise the folders become decoration within a quarter.

Debugging generation failures: run with -vvv, check write permissions on the target directory, and confirm the configured namespace prefix matches what's in composer.json. Most "it did nothing" reports are a silently mismatched path.

Scope discipline. Start with Actions + DTOs + Models + one provider per domain. Add repositories, events, and policies only when a real seam demands them. DDD-by-scaffolding tends to over-produce folders, and a codebase with twelve empty Contracts/ directories reads as cargo cult to the next hire.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings