PHPackages                             flyokai/data-mate - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. flyokai/data-mate

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

flyokai/data-mate
=================

Data/Dto helpers and base definitions

v1.1.7(3w ago)0825↓79.5%6MITPHP

Since Dec 4Pushed 3w agoCompare

[ Source](https://github.com/flyokai/data-mate)[ Packagist](https://packagist.org/packages/flyokai/data-mate)[ RSS](/packages/flyokai-data-mate/feed)WikiDiscussions main Synced 2d ago

READMEChangelog (1)Dependencies (6)Versions (15)Used By (6)

flyokai/data-mate
=================

[](#flyokaidata-mate)

> User docs → [`README.md`](README.md) · Agent quick-ref → [`CLAUDE.md`](CLAUDE.md) · Agent deep dive → [`AGENTS.md`](AGENTS.md)

> The DTO foundation of the Flyokai framework — Solid/Draft/GreyData states, identity, enums, and collections.

`data-mate` defines the contract every Data Transfer Object in Flyokai obeys. It pairs the safety of constructor-validated immutables (**Solid**) with the flexibility of dynamic schemas (**Draft**, **GreyData**), and it standardises identity (`HasId` / `HasAltId`), enum helpers, and item collections so the rest of the framework can treat data uniformly.

It is built on top of [`cuyz/valinor`](https://github.com/CuyZ/Valinor) for type-safe deserialization.

Features
--------

[](#features)

- **`Dto` interface** — `toArray()`, `toDbRow()`, `with()`, `cloneWith()`, `fromArgs()`
- **Three data states** — `Solid` (immutable, validated), `Draft` (flexible), `GreyData` (key/value bag)
- **Reflection-cached `DtoTrait`** — automatic Valinor mapping with undefined-vs-null tracking
- **Identity system** — `HasId`, `HasAltId`, `HasIdDto` with primary + alternative/composite keys
- **Enum helpers** — `StringEnumTrait`, `IntEnumTrait`, `LCStringEnumTrait`, `UCStringEnumTrait`
- **Collections** — `ItemJar` interface and `JarTrait` for type-safe iterables
- **Built-in DTOs** — `ConfigJar`, `DdlTable`, `DdlTableColumn`, `DdlTableJar`
- **Validation** — `Assertions`, `ValidationException`, `InvalidEntity` factories

Installation
------------

[](#installation)

```
composer require flyokai/data-mate
```

Quick start
-----------

[](#quick-start)

### A Solid DTO (strict, immutable)

[](#a-solid-dto-strict-immutable)

```
use Flyokai\DataMate\Dto;
use Flyokai\DataMate\DtoTrait;
use Flyokai\DataMate\Solid;

final class UserSolid implements Dto, Solid
{
    use DtoTrait;

    public function __construct(
        public readonly int $userId,
        public readonly string $username,
        public readonly string $email,
        public readonly ?string $firstName = null,
    ) {}
}

$user = UserSolid::fromArray([
    'userId' => 1,
    'username' => 'alice',
    'email' => 'alice@example.com',
]);

$row    = $user->toDbRow();             // ['user_id' => 1, 'username' => 'alice', ...]
$copy   = $user->cloneWith(email: 'a@b.com');
$loose  = $user->with(email: 'a@b.com'); // Valinor-mapped, accepts loose types
```

### A Draft / Solid pairing

[](#a-draft--solid-pairing)

```
use Flyokai\DataMate\Draft;
use Flyokai\DataMate\DtoTrait;

final class User implements Dto, Draft
{
    use DtoTrait;
    protected static string $solidClassName = UserSolid::class;
    // …mutable, flexible properties for input/staging
}
```

### Identity

[](#identity)

```
use Flyokai\DataMate\HasId;
use Flyokai\DataMate\HasAltId;
use Flyokai\DataMate\HasIdDto;

final class UserSolid implements HasIdDto, Solid
{
    use DtoTrait;

    protected static string $type      = 'user';
    protected static string $idKey     = 'user_id';
    protected static array  $altIdKeys = ['username', 'email'];

    public function __construct(
        public readonly int $userId,
        public readonly string $username,
        public readonly string $email,
    ) {}
}

$user->id();                   // 1
$user->idKey();                // 'user_id'
$user->altId('username');      // 'alice'
$user->altId(['username', 'email']);
$user->extractIdentity();      // 1, with fallback to alt IDs
```

The data-state model
--------------------

[](#the-data-state-model)

MarkerMutabilityConstructionUse it for`Solid`Immutable, `public readonly` propsConstructor, validatedDomain objects, repositories return these`Draft`Mutable, flexibleSame DTO class as Solid but relaxedInput staging, partial updates`GreyData`Dynamic key/valueBacked by `$data` arrayAPI payloads, third-party blobs`fromArray()` uses Valinor for tolerant deserialisation; `cloneWith()` goes through the constructor for strict validation.

`toArray()` skips properties that were never assigned (undefined ≠ explicit null). `toDbRow()` builds on top of it and JSON-encodes any remaining array values — so `['data' => ['k' => 'v']]` becomes `['data' => '{"k":"v"}']`.

GreyData
--------

[](#greydata)

`GreyDataTrait` implements a path-aware key/value bag for objects whose schema is dynamic:

```
$config->get('db/connection/default/host');     // path-based
$config->set('feature/flag/x', true);
$config->hasFeatureX();                         // magic getter (snake_case)
$config->withFeatureX(true);                    // immutable variant
```

Enums
-----

[](#enums)

```
use Flyokai\DataMate\StringEnumTrait;

enum Status: string
{
    use StringEnumTrait;

    case Active   = 'active';
    case Disabled = 'disabled';
}

Status::allowedValues();   // ['active', 'disabled']
Status::fromName('Active');
Status::tryFromName('xxx');
Status::validate('active');
Status::normalize('ACTIVE');
```

`LCStringEnumTrait` lower-cases input before lookup; `UCStringEnumTrait` upper-cases.

Collections (ItemJar)
---------------------

[](#collections-itemjar)

```
use Flyokai\DataMate\ItemJar;
use Flyokai\DataMate\JarTrait;

final class UserJar implements ItemJar
{
    use JarTrait;
}

$jar = new UserJar();
$jar->add($user1);
$jar->get($user1->id());
foreach ($jar as $u) { /* … */ }
```

API surface
-----------

[](#api-surface)

Class / TraitPurpose`Dto`Core interface`DtoTrait`Reflection-based Valinor implementation`Solid` / `Draft` / `GreyData`State markers`HasId` / `HasAltId` / `HasIdDto`Identity`EnumTrait`, `StringEnumTrait`, `IntEnumTrait`, `LCStringEnumTrait`, `UCStringEnumTrait`Enum helpers`ItemJar`, `JarTrait`Type-safe collections`ConfigJar`, `DdlTable`, `DdlTableJar`Built-in DTOs`Assertions``assertNotNull`, `assertPositiveInt`, `assertPositiveFloat``ValidationException`, `InvalidEntity`Errors`dtoMapper(...)`Cached configured Valinor `TreeMapper`Gotchas
-------

[](#gotchas)

- `with()` is Valinor-flexible (accepts loose types, slower). `cloneWith()` is constructor-strict (faster).
- `toDbRow()` JSON-encodes arrays — be aware when reading rows back.
- A constructor parameter that was never supplied is "undefined" and is skipped in `toArray()`. An explicit `null` is included.
- `GreyData` does not track undefined — every key in `$data` is preserved.
- `__sleep()` only serializes constructor params — implement `__wakeup()` to reinitialize derived state.
- Reflection caches are global static and never cleared (intentional, for performance).
- Alt-ID keys are strings; composite keys are arrays of strings, normalised via sorting.

See also
--------

[](#see-also)

- [`flyokai/db-schema`](../db-schema/README.md) — `#[Table]` attribute on Solid DTOs becomes the schema source of truth
- [`flyokai/search-criteria`](../search-criteria/README.md) — declarative filters for repositories built on Solid DTOs
- [`flyokai/magento-dto`](../magento-dto/README.md) — DTOs for Magento entities

License
-------

[](#license)

MIT

###  Health Score

44

—

FairBetter than 90% of packages

Maintenance95

Actively maintained with recent releases

Popularity17

Limited adoption so far

Community16

Small or concentrated contributor base

Maturity43

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 76.9% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~18 days

Recently: every ~11 days

Total

11

Last Release

25d ago

Major Versions

0.0.1 → v1.1.42026-06-08

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/247743048?v=4)[flyokai](/maintainers/flyokai)[@flyokai](https://github.com/flyokai)

---

Top Contributors

[![flyokai](https://avatars.githubusercontent.com/u/247743048?v=4)](https://github.com/flyokai "flyokai (10 commits)")[![wtsergo](https://avatars.githubusercontent.com/u/305326?v=4)](https://github.com/wtsergo "wtsergo (3 commits)")

### Embed Badge

![Health badge](/badges/flyokai-data-mate/health.svg)

```
[![Health](https://phpackages.com/badges/flyokai-data-mate/health.svg)](https://phpackages.com/packages/flyokai-data-mate)
```

###  Alternatives

[amphp/parallel-functions

Parallel processing made simple.

28010.6M27](/packages/amphp-parallel-functions)[flow-php/flow

PHP ETL - Extract Transform Load - Data processing framework

85036.3k](/packages/flow-php-flow)[setono/editorjs-php

PHP library for handling data from the EditorJS

4361.4k3](/packages/setono-editorjs-php)[n1ebieski/ksef-php-client

PHP API client that allows you to interact with the API Krajowego Systemu e-Faktur

9067.8k](/packages/n1ebieski-ksef-php-client)[eliashaeussler/cache-warmup

Composer package to warm up website caches, based on a given XML sitemap

76433.8k11](/packages/eliashaeussler-cache-warmup)[integer-net/magento2-sansec-watch

Sansec Watch integration for Magento 2

40207.0k](/packages/integer-net-magento2-sansec-watch)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
