{"id":21557027,"url":"https://github.com/rutek/dataclass","last_synced_at":"2025-04-10T10:23:27.680Z","repository":{"id":62538495,"uuid":"226712115","full_name":"rutek/dataclass","owner":"rutek","description":"PHP Library for fast building data structures from arrays using type-hinted classes","archived":false,"fork":false,"pushed_at":"2023-06-16T07:35:46.000Z","size":89,"stargazers_count":23,"open_issues_count":2,"forks_count":6,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-03T14:51:45.559Z","etag":null,"topics":["php","php-library","php7","schema-validation"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rutek.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2019-12-08T18:26:25.000Z","updated_at":"2025-02-25T16:51:47.000Z","dependencies_parsed_at":"2024-11-24T10:03:05.407Z","dependency_job_id":null,"html_url":"https://github.com/rutek/dataclass","commit_stats":{"total_commits":15,"total_committers":2,"mean_commits":7.5,"dds":0.06666666666666665,"last_synced_commit":"a2f677333ec79a9ce3144c3b89daed022e543cae"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rutek%2Fdataclass","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rutek%2Fdataclass/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rutek%2Fdataclass/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rutek%2Fdataclass/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rutek","download_url":"https://codeload.github.com/rutek/dataclass/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248199082,"owners_count":21063641,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["php","php-library","php7","schema-validation"],"created_at":"2024-11-24T08:10:42.062Z","updated_at":"2025-04-10T10:23:27.657Z","avatar_url":"https://github.com/rutek.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PHP Dataclass library\n\nDataclass allows you to quickly change your plain `array` to type-hinted PHP class with automatic denormalization of embeded objects and collections which normally requires much work if you use normalizers and denormalizers. Library is insipired by\nPython [pydantic](https://pydantic-docs.helpmanual.io/) module. It uses type-hinting power available since PHP 7.4.\n\nMain goal of this package is to provide fast way for having strictly type-hinted classes for further usage, for example to map request payload to strictly typed class so you can use it instead of array which may or may not match your requirements. It won't replace your data validation but will make you sure that f.x. received JSON payload matches types which your backend operations expect to receive. It's something like mentioned above [pydantic `BaseModel`](https://pydantic-docs.helpmanual.io/) or [TypeScript interface](https://www.typescriptlang.org/docs/handbook/interfaces.html).\n\nAll you need is create class or two:\n\n```php\ndeclare(strict_types=1);\n\nclass MyEmbededClass\n{\n    public float $number;\n}\n\nclass MyClass\n{\n    public int $number;\n    public ?string $optionalText = null;\n    public MyEmbededClass $embeded;\n}\n```\n\nAs next step pass main class name and received data, for example from received JSON to `transform` method:\n\n```php\n$data = '{\n    \"number\": 1,\n    \"embeded\": {\n        \"number\": 1.23\n    }\n}';\n$object = transform(MyClass::class, json_decode($data, true));\n```\n\nTo quickly map received data to fully functional dataclass:\n\n```php\nvar_dump($object)\n```\n\n```php\nobject(MyClass) {\n  [\"number\"]=\u003e int(1)\n  [\"optionalText\"]=\u003e NULL\n  [\"embeded\"]=\u003e\n  object(MyEmbededClass) {\n    [\"number\"]=\u003e\n    float(1.23)\n  }\n}\n```\n\nYou don't have to worry about passing `null` from `json_decode`, it will throw `TransformException` for `root` field if it's detected.\n\nYou don't have to worry about missing fields and invalid types as library detects all type-hinted requirements and throws `TransformException` with errors (ready to be served as response) pointing to exact fields with simple reason message, for example:\n\n```php\necho json_encode($transformException, JSON_PRETTY_PRINT)\n```\n\n```json\n{\n    \"errors\": [\n        {\n            \"field\": \"optionalText\",\n            \"reason\": \"Field must have value\"\n        },\n        {\n            \"field\": \"embeded\",\n            \"reason\": \"Field must have value\"\n        }\n    ]\n}\n```\n\nYou can also use `Transform::to` method which is in fact called by `transform` helper function. Helper function will always use optimal settings for `Transform` objects (as soon as they appear).\n\n```php\n$data = '{\n    \"number\": 1,\n    \"embeded\": {\n        \"number\": 1.23\n    }\n}';\n$transformer = new Transform();\n$object = $transformer-\u003eto(MyClass::class, json_decode($data, true));\n```\n\n### Constructors\n\nIf you need to use constructor with type-hinted arguments you can do it, but in the limited way. The library only\nsupports filling in constructor arguments with values from the payload. It means that constructor must use\nthe same types and variable names as the class properties. For example:\n\n```php\nclass MyClass\n{\n    public float $number;\n    public ?int $numberTwo = null;\n\n    public function __construct(float $number)\n    {\n        $this-\u003enumber = $number;\n    }\n}\n```\n\nUsing different name or type for the constructor argument won't work. The goal is to support enforcing\ndeveloper to fill in the properties.\n\nAny constructor that contains any other parameter than the properties will throw `UnsupportedException`. Parameters\nmust have the same type as properties. Order is irrelevant. If it's needed, only some subset of properties can exist\nin the constructor.\n\n### More examples\n\nPlease check out [docs/ directory](docs/) for more examples.\n\n## Installation\n\nAs simple as\n\n```\ncomposer install rutek/dataclass\n```\n\n## Supported type hints\n\n**Attention:** please be aware of using `array` type hints. They cannot be used (will throw `UnsupportedException` if detected) as PHP does not provide way to type-hint items of array. Please check *Collections* section below for further information.\n\n### Scalars\n\nAll [four PHP scalars](https://www.php.net/manual/en/language.types.intro.php) are supported.\n\n### Nullable fields\n\nType-hinting nullability is supported. You can safely use for example `?string` to accept both `string` and `null`. Please be aware as using only `?string $field` does not mean that transformed array may not contain this field. It only means that this value accepts `null`.\n\n### Default values\n\nIf you need to accept transformation of data which does not contain some fields you can use default values, for exmaple: `?string $field = null`. Dataclass library will detect that this property does not exist in payload and will use default value instead.\n\n### Collections\n\nPHP does not support type-hinting `array` fields if you need to embed collection of objects or scalars you have to use `Collection` class. You need to extend it with constructor with type-hinted arguments deconstruction, for example:\n\n```php\nclass Tags extends Collection\n{\n    public function __construct(string ...$names)\n    {\n        $this-\u003eitems = $names;\n    }\n}\n```\n\nType-hinted arrays like `string[]` [were rejected in RFC](https://wiki.php.net/rfc/arrayof) so propably this behaviour will not change soon.\n\nLibrary will check if provided values match type-hinting of constructor.\n\nThere is no possiblity to check minimum and maxiumum items but there may be such feature in next versions.\n\nPlease note that you can also use Collection as base class which you want to transform, for example:\n\n```php\n$tags = transform(Tags::class, ['tag1', 'tag2']);\n```\n\n## Exceptions\n\n## `TransformException` - data does not match your schema\n\nThis is base exception you can expect. Every time your data (payload) passed to function `transform(string $class, $data)` or `Transform::to` will not match your type-hinted classes, you will receive `TransformException` with `getErrors(): FieldError[]` method which describes what really happened.\n\nEvery `FieldError` contains both `field` describing which field failed type check and `reason` describing in simple words why it has been rejected. If there are nested objects you can expect to receive `field` values like `parentProperty.childrenProperty` (levels separated by dot).\n\nClass supports JSON serialization and will always return something like:\n\n```json\n{\n    \"errors\": [\n        {\n            \"field\": \"optionalText\",\n            \"reason\": \"Field must have value\"\n        },\n        {\n            \"field\": \"embeded\",\n            \"reason\": \"Field must have value\"\n        }\n    ]\n}\n```\n\nPlease note that `code` field may be added in future.\n\n## `UnsupportedException` - only if your type-hints are not supported\n\nLibrary does not cover all scenarios as you can define type hints which would not have strict context. For example if you use `object` property, it would not be possible to validate it as any object will match your schema. In such cases you can expect `UnsupportedException`.\n\n## Unsupported (yet?)\n\n### Intersection and union types\n\nPHP 8.0 [union types](https://wiki.php.net/rfc/union_types_v2) and PHP 8.1 [intersection types](https://wiki.php.net/rfc/pure-intersection-types) are unsupported right now.\n\n### Enums\n\nNative PHP 8.1 [enums](https://www.php.net/manual/en/language.types.enumerations.php) are unsupported right now.\n\n### Private and protected properties\n\nAll type-hinted fields must be public as for now. Implementing such feature is questionable as you would have to create getters for such properties which is unwanted overhead. Library is meant to create possiblity to define internal schemas for data received from remote systems (APIs, queues/bus messages, browsers).\n\n### Reflection cache\n\nAll reflection checks are made every time `transform` or `Transform::to` function is called. You can expect caching functionality for better performance soon.\n\n## Remarks\n\nPlease remember that goal of this package is not to fully validate data you receive but to create simple classes which makes your payloads fully type-hinted also when they have some complicated structure. You will not have to encode you classes in JSON with `class` fields as your type hints will tell your code what object or array should be created in place of some embeded values.\n\nIf you are creating API and you need enterprise-grade OpenAPI schema validation you should check [hkarlstrom/openapi-validation-middleware](https://github.com/hkarlstrom/openapi-validation-middleware) and afterwards you can map received payload to type-hinted classes using this library! :)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frutek%2Fdataclass","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frutek%2Fdataclass","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frutek%2Fdataclass/lists"}