{"id":43146769,"url":"https://github.com/php-collective/dto","last_synced_at":"2026-02-26T12:07:31.116Z","repository":{"id":328748151,"uuid":"1115993506","full_name":"php-collective/dto","owner":"php-collective","description":"The easiest and fastest PHP DTO library in the world - quickly generate useful data transfer objects for your app (mutable/immutable)","archived":false,"fork":false,"pushed_at":"2026-02-06T14:06:27.000Z","size":483,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-02-06T22:26:46.902Z","etag":null,"topics":["dto","dto-entity-mapper","dto-pattern"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/php-collective.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-14T01:08:46.000Z","updated_at":"2026-02-05T21:39:39.000Z","dependencies_parsed_at":"2025-12-18T03:03:37.761Z","dependency_job_id":null,"html_url":"https://github.com/php-collective/dto","commit_stats":null,"previous_names":["php-collective/dto"],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/php-collective/dto","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/php-collective%2Fdto","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/php-collective%2Fdto/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/php-collective%2Fdto/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/php-collective%2Fdto/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/php-collective","download_url":"https://codeload.github.com/php-collective/dto/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/php-collective%2Fdto/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29858465,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-26T08:51:08.701Z","status":"ssl_error","status_checked_at":"2026-02-26T08:50:19.607Z","response_time":89,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dto","dto-entity-mapper","dto-pattern"],"created_at":"2026-01-31T23:48:25.239Z","updated_at":"2026-02-26T12:07:31.110Z","avatar_url":"https://github.com/php-collective.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PHP Data Transfer Objects\n\n[![CI](https://github.com/php-collective/dto/actions/workflows/ci.yml/badge.svg)](https://github.com/php-collective/dto/actions/workflows/ci.yml)\n[![codecov](https://codecov.io/gh/php-collective/dto/branch/master/graph/badge.svg)](https://codecov.io/gh/php-collective/dto)\n[![PHPStan](https://img.shields.io/badge/PHPStan-level%208-brightgreen.svg?style=flat)](https://phpstan.org/)\n[![Latest Stable Version](https://poser.pugx.org/php-collective/dto/v/stable.svg)](https://packagist.org/packages/php-collective/dto)\n[![PHP](https://img.shields.io/badge/PHP-8.2%2B-blue.svg)](https://php.net)\n[![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n\nFramework-agnostic DTO library with **code generation** for PHP.\n\nUnlike runtime reflection libraries, this library generates optimized DTO classes at build time, giving you:\n- **Zero runtime reflection overhead**\n- **Perfect IDE autocomplete** with real methods\n- **Excellent static analysis** support (PHPStan/Psalm work out of the box)\n- **Reviewable generated code** in pull requests\n- **JSON Schema generation** for API documentation\n- **Schema importer** to bootstrap DTOs from JSON data or OpenAPI specs\n\nSee [Motivation](docs/Motivation.md) for why code generation beats runtime reflection.\n\n## Installation\n\n```bash\ncomposer require php-collective/dto\n```\n\n## Quick Start\n\nDefine DTOs in PHP (or XML, YAML, NEON):\n\n```php\n// config/dto.php\nuse PhpCollective\\Dto\\Config\\Dto;\nuse PhpCollective\\Dto\\Config\\Field;\nuse PhpCollective\\Dto\\Config\\Schema;\n\nreturn Schema::create()\n    -\u003edto(Dto::create('Car')-\u003efields(\n        Field::string('color'),\n        Field::dto('owner', 'Owner'),\n    ))\n    -\u003edto(Dto::create('Owner')-\u003efields(\n        Field::string('name'),\n    ))\n    -\u003etoArray();\n```\n\nGenerate and use:\n\n```bash\nvendor/bin/dto generate\n```\n\n```php\n$car = CarDto::createFromArray(['color' =\u003e 'red']);\n$car-\u003esetOwner(OwnerDto::create(['name' =\u003e 'John']));\n$array = $car-\u003etoArray();\n```\n\nSee [Quick Start Guide](docs/README.md) for detailed examples.\n\n## Immutable DTOs\n\nA more realistic example using immutable DTOs for a blog system:\n\n```php\n// config/dto.php\nreturn Schema::create()\n    -\u003edto(Dto::immutable('Article')-\u003efields(\n        Field::int('id')-\u003erequired(),\n        Field::string('title')-\u003erequired(),\n        Field::string('slug')-\u003erequired(),\n        Field::string('content'),\n        Field::dto('author', 'Author')-\u003erequired(),\n        Field::collection('tags', 'Tag')-\u003esingular('tag'),\n        Field::bool('published')-\u003edefaultValue(false),\n        Field::string('publishedAt'),\n    ))\n    -\u003edto(Dto::immutable('Author')-\u003efields(\n        Field::string('name')-\u003erequired(),\n        Field::string('email'),\n        Field::string('avatarUrl'),\n    ))\n    -\u003edto(Dto::immutable('Tag')-\u003efields(\n        Field::string('name')-\u003erequired(),\n        Field::string('slug')-\u003erequired(),\n    ))\n    -\u003etoArray();\n```\n\n```php\n// Creating from API/database response\n$article = ArticleDto::createFromArray($apiResponse);\n```\n\nReading in a template (e.g., Twig, Blade, or plain PHP):\n\n```php\n\u003c!-- templates/article/view.php --\u003e\n\u003carticle\u003e\n    \u003ch1\u003e\u003c?= htmlspecialchars($article-\u003egetTitle()) ?\u003e\u003c/h1\u003e\n    \u003cp class=\"meta\"\u003e\n        By \u003c?= htmlspecialchars($article-\u003egetAuthor()-\u003egetName()) ?\u003e\n        \u003c?php if ($article-\u003egetPublishedAt()) { ?\u003e\n            on \u003c?= $article-\u003egetPublishedAt() ?\u003e\n        \u003c?php } ?\u003e\n    \u003c/p\u003e\n\n    \u003cdiv class=\"tags\"\u003e\n        \u003c?php foreach ($article-\u003egetTags() as $tag) { ?\u003e\n            \u003ca href=\"/tag/\u003c?= $tag-\u003egetSlug() ?\u003e\"\u003e\u003c?= htmlspecialchars($tag-\u003egetName()) ?\u003e\u003c/a\u003e\n        \u003c?php } ?\u003e\n    \u003c/div\u003e\n\n    \u003cdiv class=\"content\"\u003e\n        \u003c?= $article-\u003egetContent() ?\u003e\n    \u003c/div\u003e\n\u003c/article\u003e\n```\n\n## Features\n\n- **Types**: `int`, `float`, `string`, `bool`, `array`, `mixed`, DTOs, classes, enums\n- **Union types**: `int|string`, `int|float|string`\n- **Collections**: `'type' =\u003e 'Item[]', 'collection' =\u003e true` with add/remove/get/has methods\n- **Associative collections**: keyed access with `'associative' =\u003e true`\n- **Immutable DTOs**: `'immutable' =\u003e true` with `with*()` methods\n- **Readonly properties**: `public readonly` with direct property access\n- **Validation rules**: built-in `minLength`, `maxLength`, `min`, `max`, `pattern` constraints\n- **Lazy properties**: deferred DTO/collection hydration with `asLazy()`\n- **Default values**: `'defaultValue' =\u003e 0`\n- **Required fields**: `'required' =\u003e true`\n- **Deprecations**: `'deprecated' =\u003e 'Use newField instead'`\n- **Inflection**: automatic snake_case/camelCase/dash-case conversion\n- **Deep cloning**: `$dto-\u003eclone()`\n- **Nested reading**: `$dto-\u003eread(['path', 'to', 'field'])`\n- **PHPDoc generics**: `@var \\ArrayObject\u003cint, ItemDto\u003e` for static analysis\n- **[TypeScript generation](#typescript-generation)**: Generate TypeScript interfaces from your DTO configs\n- **[Schema Importer](#schema-importer)**: Auto-create DTOs from JSON data or JSON Schema\n\n## Configuration Formats\n\n- **PHP** - native arrays or [fluent builder](docs/ConfigBuilder.md)\n- **XML** - XSD validation, IDE autocomplete\n- **YAML** - requires `pecl install yaml`\n- **NEON** - requires `nette/neon`\n\n## TypeScript Generation\n\nGenerate TypeScript interfaces directly from your DTO configuration - keeping frontend and backend types in sync:\n\n```bash\n# Single file output\nvendor/bin/dto typescript --config-path=config/ --output=frontend/src/types/\n\n# Multi-file with separate imports\nvendor/bin/dto typescript --multi-file --file-case=dashed --output=types/\n```\n\n```typescript\n// Generated: types/dto.ts\nexport interface UserDto {\n    id: number;\n    name: string;\n    email: string;\n    address?: AddressDto;\n    roles?: RoleDto[];\n}\n```\n\nOptions: `--readonly`, `--strict-nulls`, `--file-case=pascal|dashed|snake`\n\nSee [TypeScript Generation](docs/TypeScriptGeneration.md) for full documentation.\n\n## Schema Importer\n\nBootstrap DTO configurations from existing JSON data or JSON Schema definitions:\n\n```php\nuse PhpCollective\\Dto\\Importer\\Importer;\n\n$importer = new Importer();\n\n// From API response example\n$json = '{\"name\": \"John\", \"age\": 30, \"email\": \"john@example.com\"}';\n$config = $importer-\u003eimport($json);\n\n// From JSON Schema\n$schema = file_get_contents('openapi-schema.json');\n$config = $importer-\u003eimport($schema, ['format' =\u003e 'xml']);\n```\n\nOutputs to PHP, XML, YAML, or NEON format. Perfect for integrating with external APIs.\n\nSee [Schema Importer](docs/Importer.md) for full documentation.\n\n## Documentation\n\n- [Quick Start Guide](docs/README.md) - Getting started with examples\n- [Configuration Builder](docs/ConfigBuilder.md) - Fluent API for defining DTOs\n- [Examples](docs/Examples.md) - Practical usage patterns\n- [TypeScript Generation](docs/TypeScriptGeneration.md) - Generate TypeScript interfaces\n- [Schema Importer](docs/Importer.md) - Bootstrap DTOs from JSON data/schema\n- [Performance](docs/Performance.md) - Benchmarks and optimization tips\n- [Motivation](docs/Motivation.md) - Why code generation beats runtime reflection\n\n## Integrations\n\nThis is the standalone core library. For framework-specific integrations:\n\n- **CakePHP**: [dereuromark/cakephp-dto](https://github.com/dereuromark/cakephp-dto) - Bake commands, plugin\n- **Laravel**: [php-collective/laravel-dto](https://github.com/php-collective/laravel-dto) - Artisan commands, service provider\n- **Symfony**: [php-collective/symfony-dto](https://github.com/php-collective/symfony-dto) - Console commands, bundle integration\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphp-collective%2Fdto","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphp-collective%2Fdto","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphp-collective%2Fdto/lists"}