jooservices / dto
PHP 8.5+ DTO and Data library with immutable DTOs and mutable Data objects
Requires
- php: >=8.5
- ext-dom: *
- ext-libxml: *
- psr/http-message: ^2.0
Requires (Dev)
- captainhook/captainhook: ^5.23
- captainhook/plugin-composer: ^5.3
- fakerphp/faker: ^1.24
- friendsofphp/php-cs-fixer: ^3.65
- laravel/pint: ^1.18
- phpbench/phpbench: ^1.6
- phpmd/phpmd: ^2.15
- phpstan/phpstan: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- phpstan/phpstan-strict-rules: ^2.0
- phpunit/phpunit: ^12.0 || ^13.0
- squizlabs/php_codesniffer: ^3.8 || ^4.0
Suggests
- psr/log: Enables debug logging during DTO hydration via Engine constructor injection.
Provides
None
Conflicts
None
Replaces
None
README
A PHP 8.5+ attribute-driven DTO and Data library: immutable Dto and mutable Data objects, constructor-first hydration, opt-in validation, serialization control, collections, and JSON Schema / OpenAPI generation. One runtime dependency: psr/http-message (interface-only).
Warning
v3.0.0 is a complete ground-up rebuild of this package and is NOT backward compatible with any previous version (v1.x, v2.x).
Rewrite DTO classes for the v3 API before upgrading; there are no legacy shims or deprecation bridges. See the changelog.
Upgrade highlights
- v3 has a new DTO/Data engine, constructor-first hydration, and explicit key-space rules.
jooservices/exceptionsis no longer a runtime dependency;psr/http-messagesupportsfromRequest().with(),merge(), andclone()use property names and rebuild through the constructor.
Features
- Immutable
Dtoand mutableDataobjects with typed, constructor-first hydration. - Factories for arrays, JSON, objects, and PSR-7 requests; collection and partial-payload support.
- Attribute-driven mapping, casting, transforms, validation, and serialization control.
- Immutable copies, merging, comparison, hashing, and lazy derived properties.
- JSON Schema and OpenAPI generation, structured exceptions, and cached reflection metadata.
Requirements
- PHP
>= 8.5 - Extensions:
dom,libxml psr/http-message(fromRequest()), optional:psr/log(Engine debug logging)- Docker (recommended — all local tooling runs in
php:8.5-cli-bookworm)
Installation
composer require jooservices/dto:^3.0
Quick start
use JOOservices\Dto\Attributes\MapFrom; use JOOservices\Dto\Core\Dto; final class UserDto extends Dto { public function __construct( public readonly string $id, #[MapFrom('email_address')] public readonly string $email, public readonly \DateTimeImmutable $createdAt, ) {} } // External input — source keys resolved through MapFrom / naming strategy $user = UserDto::from([ 'id' => 'u_123', 'email_address' => 'john@example.com', 'createdAt' => '2026-01-15T10:30:00+00:00', ]); // Immutable copy — property-name keys only, patched value cast to string $updated = $user->with(email: 'other@example.com'); $updated->toArray(); // ['id' => 'u_123', 'email' => 'other@example.com', ...] $updated->toJson();
Design notes
- Every DTO declares a constructor with public promoted properties; constructor-less classes are unsupported.
- Each entry point owns exactly one key space:
| Entry point | Key space |
|---|---|
new UserDto(...) |
Property names — already-typed values |
UserDto::from() / fromArray() / fromJson() / fromObject() / fromRequest() |
Source keys — resolved via MapFrom / naming strategy |
$dto->with(...) / merge(...) |
Property names only — immutable copies built through the constructor |
- Validation is opt-in via
Context; casting and pipelines never silently change scope when a Context argument is omitted.
Documentation
- Changelog — version history and upgrade notes
- Contributing guide — setup, quality gates, and pull requests
- Development workflows — branches, CI, releases, and repository automation
- Security policy — private vulnerability reporting
Development
All PHP tooling runs inside Docker (php:8.5-cli-bookworm via Docker Compose).
make build # build the tooling image make install # composer install in the container make shell # interactive container shell
| Command | Purpose |
|---|---|
make validate |
composer validate --strict |
make lint |
Pint, PHPCS, PHPStan, PHPMD, PHP-CS-Fixer |
make test |
PHPUnit (Unit + Integration) |
make test-coverage |
PHPUnit with Clover coverage |
make audit |
Composer audit |
make bench |
phpbench |
make ci |
lint + coverage run (local CI parity) |
Every linter runs at maximum strictness with no ignore lists — fix issues at the source instead of suppressing them.
IDE setup: Cursor / VS Code — install recommended workspace extensions; format-on-save runs Pint via tools/pint (Docker). PHPStorm — inspection profile + Pint file watcher.
Community
- Contributing guide — setup, git workflow, commit convention, quality gates, PR rules
- Security policy — how to report vulnerabilities privately
- Code of Conduct
- Support
- Governance
License
MIT — see LICENSE.