nandan108 / dto-toolkit
A modern, framework-agnostic PHP 8.1+ DTO system with attribute-driven data normalization and mapping to entities or arrays.
Requires
- php: >=8.1 <8.6
- nandan108/prop-access: ^0.7.0
- nandan108/prop-path: ^0.4.1
Requires (Dev)
- php: >=8.1 <8.6
- friendsofphp/php-cs-fixer: ^3.92
- mockery/mockery: ^1.6
- nunomaduro/collision: ^6.4
- phpunit/phpunit: ^10.0
- symfony/var-dumper: ^6.0 || ^7.0
- vimeo/psalm: ^6.12
- wikimedia/composer-merge-plugin: ^2.1
README
β Requires PHP 8.1β8.5
DTO Toolkit Core is a lightweight, framework-agnostic library for processing Data Transfer Objects (DTOs) in PHP. It provides a unified model for normalization, validation, transformation, and export β with first-class support for nested structures and context-aware execution.
The API is fully declarative and attribute-driven: casters, validators, and control-flow modifiers compose into explicit processing pipelines that are JIT-compiled into efficient runtime chains, without coupling to any specific framework.
DTO Toolkit treats data transformation as a lifecycle, not a side effect.
β¨ Features
- π§± Conceptually lightweight, framework-agnostic core
- π·οΈ Attribute-based processing pipelines with explicit control flow
- π― Optional validation and normalization layers
- π Easily transform between DTOs and entities/models
- 𧬠First-class support for nested DTO processing (inbound and outbound), with consistent context propagation
- π§© Designed to work with pluggable framework adapters (Laravel, Symfony, etc.)
π¦ Installation
composer require nandan108/dto-toolkit
π Quick Start
use Nandan108\DtoToolkit\Core\{FullDto, CastTo}; // FullDto includes all standard traits (CreatesFromArrayOrEntity, ProcessesFromAttributes, ExportsOutbound) class MyDto extends FullDto { #[CastTo\Trimmed()] public ?string $name = null; } final class MyEntity { public ?string $name = null; } // Build DTO from array $dto = MyDto::newFromArray(['name' => ' Alice ']); // Transform into an entity (optionally recursive) $entity = $dto->exportToEntity(MyEntity::class, recursive: true);
Use a framework adapter (e.g. Symfony or Laravel) to unlock request/response integration and validation support.
π¦ Core Namespace
If you're not using a framework, start with:
Nandan108\DtoToolkit\Core\FullDtoNandan108\DtoToolkit\Core\CastToNandan108\DtoToolkit\Core\Assert
These provide a convenient, framework-free entry point with all standard functionality included.
π Documentation
- DTO Fundamentals β what DTOs are, why they matter, and how to use them in modern PHP
- Casting β how casting works and how to write your own
- Attributes - List of attributes
- Lifecycle β Understanding the lifecycle of a DTO
- Lifecycle Hooks β customize behavior with
postLoad()andpreOutput() - Toolkit Comparison β see how this toolkit compares to other PHP DTO/mapping libraries
- Processing in detail β Validating and Transforming Data Through Nodes
- Built-In Core Casters β Full list of available
CastTo\*casters - Built-In Core Validators β list of available
Validate\*validators (more are planned) - Built-In Core Modifiers β Full list of available
Mod\*chain modifiers - Dependency Injection
- I18n β locale-aware casters and error-message translation setup
- Writing Adapters (planned)
π Runtime & Concurrency
- Multi-threaded runtimes (
pthreads/parallel) are not supported by the core and are not planned to be. - Execution context storage is abstracted behind
ContextStorageInterface, allowing adapters to provide execution-local storage (e.g. for fibers/coroutines/tasks). - Fiber/event-loop runtimes (Swoole, RoadRunner, ReactPHP, etc.) are not officially supported yet.
- Adapter hooks exist, but full concurrent-runtime support still requires synchronization guarantees around cache warm-up paths, which are not implemented yet.
π Immutability & Value Objects
DTO Toolkit is not an immutable DTO library.
DTOs in DTOT are mutable by design and act as transformation builders: they ingest raw input, apply validation and normalization, and produce clean, structured output. This mutability is what enables DTOTβs dynamic processing model (casting chains, modifiers, context-aware behavior, recursive imports/exports).
That said, DTOT plays very well with immutable objects.
While DTOs themselves are mutable, DTOT is designed to export into immutable value objects or entities via constructor-based instantiation. This allows you to use DTOT as a builder for immutable domain models (value objects), without compromising immutability where it matters.
π If youβre looking for immutability at the DTO layer itself, DTOT may not be the right fit.
π If you want powerful, declarative transformation pipelines to produce immutable domain objects, DTOT is a strong match.
π§© Adapter Packages
- Laravel Adapter:
nandan108/dto-toolkit-laravel(coming soon) - Symfony Adapter:
nandan108/dto-toolkit-symfony(planned)
Adapters will provide support for:
- Framework-compatible error handling and translations, for both validators and casters
fromRequest()for DTO hydration from HTTP requestsexportToEntity()ortoModel()adapter-specific hydrationtoResponse()generation- DI for class-based casters resolution
- Graceful handling of validation and casting exceptions in HTTP contexts, with standardized API error responses
π§ͺ Testing & Quality
- 100% test coverage using PHPUnit
- Psalm level 1 (maximum strictness)
- Code style enforced with PHP-CS-Fixer:
- Based on the
@Symfonyrule set - Aligned
=>for better readability - Disallows implicit loose comparisons (
==,!=) except in explicit operator-semantics helpers
- Based on the
- Commit message style: conventional, with details if any
CI Checks
GitHub Actions (.github/workflows/ci.yml) runs:
phpuniton PHP8.1to8.5php-cs-fixer --dry-run(on one matrix leg)psalm(on one matrix leg)composer api-audit-strict(on one matrix leg)
Run Locally Before Push
composer test
composer psalm
composer cs-fix
composer api-audit-strict
Optional: install repository Git hooks (pre-commit + pre-push):
./scripts/setup-hooks.sh
Installed pre-commit runs staged-file PHP-CS-Fixer checks and then optional local extension hook .git/hooks/pre-commit.local if present.
Installed pre-push runs composer api-audit-strict, PHPUnit, Psalm, and then optional local extension hook .git/hooks/pre-push.local if present.
π€ Contributing
Bug reports, ideas, and contributions welcome! This project aims to stay lean, clean, and focused. If you're building an adapter or extending the system, feel free to open a discussion or issue.
π§ Design Philosophy
This toolkit is built on a simple idea: do the most work with the least number of moving parts.
It favors:
- Declarative code over procedural boilerplate
- Clever, expressive syntax without falling into obfuscation
- Minimalism with power β clean by default, extensible when needed
- Framework-agnostic design with optional adapters that integrate smoothly when needed
- Zero magic in the core β everything is traceable, explicit, and predictable
- Opt-in magic in adapters β for just the right touch of convenience when working with frameworks
- Separation of concerns and composability β inspired by the Unix philosophy of doing one thing well
- Performance-conscious by design β DTOs should feel lightweight and fast to use, even in large batch transformations.
Verbose code is a tax on your time. This toolkit aims to keep things sharp, concise, and purposeful β so you can focus on what matters.
MIT License Β© nandan108