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 Structures Laravel Package

andydefer/domain-structures

A Laravel/PHP package that provides reusable domain structures and building blocks for domain-driven design. It helps organize business logic, reduce boilerplate, and keep core rules isolated from framework and infrastructure concerns for cleaner, more maintainable applications.

View on GitHub
Deep Wiki
Context7

Getting Started

The package targets a common Laravel pain point: unstructured arrays crossing layer boundaries. Before writing code, note the maturity signal — 0 stars, 0 dependents, and no ecosystem footprint — so treat the repo's README.md, src/, and especially tests/ as the source of truth rather than assuming API parity with Spatie Data or hand-rolled VOs.

  1. Install with a pinned version. If no tagged release exists:

    composer require andydefer/domain-structures:dev-main#<commit-sha>
    
  2. Check composer.json for extra.laravel.providers (auto-discovery) or register the service provider manually in bootstrap/providers.php.

  3. Read the tests first. For a low-adoption package, tests are the real documentation — scan for base classes covering records, value objects, DTOs, and typed collections, and note whether they are abstract or require specific methods.

  4. Start with one use case: replace a validated request array with a DTO in a controller/action.

Illustrative shape (confirm exact base class names in the repo):

final class CreateUserData extends Data
{
    public function __construct(
        public readonly string $name,
        public readonly string $email,
    ) {}
}
public function store(CreateUserRequest $request, CreateUser $action)
{
    $data = CreateUserData::fromArray($request->validated());
    $action->handle($data);
}

If the package doesn't fit after a 30-minute spike on a single endpoint, stop. At this maturity level the switching cost is low.

Implementation Patterns

DTOs at the boundaries. Use them between HTTP/queue/console input and domain services. Keep fromArray/fromRequest mapping in one place, and keep DTOs plain — do not extend Eloquent models.

Value objects for invariants. Email, Money, Phone, OrderId, DateRange. Construct through named constructors (Email::fromString) so validation lives in one place, and add equals() rather than comparing objects with == or ===.

Typed collections for domain lists. Return UserCollection from repositories instead of a bare Collection. Enforce the item type at insertion, and add domain methods (total(), ids(), pluckEmail()) so callers don't reach for raw arrays.

Records for read models. Use records for query projections — dashboard rows, report lines, export rows — where you need shape and type safety but not behavior. Hydrate from DB::select or ->get()->map(...).

Eloquent casts. This is the highest-leverage integration point: wrap a VO in a custom cast so $user->email returns an Email instance and assignment accepts string|Email. Write one cast per VO and reuse it across models.

Serialization contract. Any DTO used in jobs, events, or cache must round-trip. Implement JsonSerializable/__serialize, or use the package's toArray. Test with dispatchSync before switching to a real queue.

Testing split. Unit-test VOs and typed collections with data providers; test DTO mapping separately from persistence. Use model factories only for Eloquent-backed tests.

Wrap it. Put the package behind your own interfaces (e.g., a DataMapper contract) so swapping to spatie/laravel-data later is a localized change.

Gotchas and Tips

  • Zero adoption means zero ecosystem. No Stack Overflow answers, no third-party integrations, no blog posts. Budget time to read source and vendor-pin; review diffs on every update.
  • Immutability friction. readonly/no-setter designs require with... clone patterns for "modify" flows. Watch for Laravel internals or packages that expect mutable public properties.
  • Type strictness vs. Eloquent. Typed collections may reject model subclasses, proxies, or lazy-loaded relations. Check whether the check is instanceof or exact class.
  • Serialization failures surface at runtime. Closures, resources, and Eloquent models inside DTOs break queue payloads silently until a worker runs. Keep DTOs scalar/VO-only.
  • Casting identity. Each $model->email access may construct a new VO. Use equals(); never ===.
  • Validation vs. exceptions. VO constructors usually throw InvalidArgumentException. Catch these at the boundary and rethrow as ValidationException so users see field errors, not 500s.
  • Performance. Hydrating thousands of DTOs per request is slower than arrays. Use records/lazy mapping for large result sets and benchmark before replacing hot paths.
  • Config and namespaces. Publish config if present (php artisan vendor:publish), and verify namespaces — small packages often change them between 0.x commits.
  • Debugging. When a typed collection throws, dd(get_class($item), $item) at the insertion point. When DTO mapping fails, log the raw payload before the mapping call.
  • Extension points. Subclass base DTO/VO for shared behavior (timestamps, toArray), but keep inheritance shallow; prefer traits where supported.
  • Exit criteria. If the package lacks tests, releases, or an upgrade path, avoid letting it leak into controllers and models. Confine it to the mapping layer so a swap to spatie/laravel-data or hand-rolled VOs remains a one-file change.
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.
dakiquang/laravel-oauth-refresh-lock
woda/laravel-worktrees
dalefranks/ramasite
faghy/laracashbook
roundly-consulting/google-places-for-laravel
roundly-consulting/kubernetes-api-for-laravel
roundly-consulting/plausible-for-laravel
gvp/gvp-laravel-template
metasyncsite/laravel-metasync-client
roundly-consulting/onboarding-for-laravel
andydefer/laravel-notification
adachsoft/cli-process-tester
jhaskell13/laraflow
sebastienheyd/boilerplate-media-manager
ccast/tagixo-primix
pretendtrue/laravel-builder
sawmainek/laravel-scout-tntsearch-driver
tomshaw/laravel-calendar-table
dibakar/laravel-ownership
adachsoft/changelog-linter