PHPackages                             futuretek/data-mapper - 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. [Database &amp; ORM](/categories/database)
4. /
5. futuretek/data-mapper

ActiveLibrary[Database &amp; ORM](/categories/database)

futuretek/data-mapper
=====================

A lightweight, reflection-based PHP 8.4+ data mapping library for converting associative arrays into typed PHP objects (POPOs), and back. Ideal for OpenAPI-generated DTOs, form handling, and request/response serialization in modern API architectures.

1.3.0(3mo ago)0818↓26.9%1Apache-2.0PHPPHP &gt;=8.4.0CI passing

Since Jun 25Pushed 3mo agoCompare

[ Source](https://github.com/futuretek-solutions-ltd/data-mapper)[ Packagist](https://packagist.org/packages/futuretek/data-mapper)[ Docs](https://www.futuretek.cz/)[ RSS](/packages/futuretek-data-mapper/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (4)Versions (7)Used By (1)

DataMapper
==========

[](#datamapper)

A lightweight PHP 8.4+ utility for mapping associative arrays to plain PHP objects (POPOs) and vice versa, using reflection and PHP attributes.

Features
--------

[](#features)

- ⚙️ Supports native PHP 8.4+ typed properties (scalars, nullable, `mixed`, `object`, `iterable`)
- 📌 Declarative mapping via custom attributes
- 📅 Handles date and datetime format conversions via `#[Format]`
- 🗂️ Supports typed arrays of objects via `#[ArrayType]`
- 📅 Supports arrays of date / date-time strings via `#[ArrayType(\DateTimeInterface::class, format: '...')]`
- 🗺️ Supports associative maps via `#[MapType]`
- 📁 Supports file mapping via `SplFileObject` and PSR-7 `UploadedFileInterface`
- 🧩 Backed enum handling with `tryFrom`
- 🔄 Nested object mapping (recursive)
- 🔒 Readonly property support via reflection
- 🔐 PHP 8.4 asymmetric visibility support (e.g., `public private(set)`)
- 🔍 Optional strict validation for required properties
- ✅ Converts objects back to associative arrays (`toArray`)
- 🚫 Skips non-public and static properties
- 💪 Gracefully handles uninitialized properties in `toArray`

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

[](#installation)

```
composer require futuretek/data-mapper
```

Usage
-----

[](#usage)

### Define DTO with Attributes

[](#define-dto-with-attributes)

```
use futuretek\datamapper\attributes\ArrayType;
use futuretek\datamapper\attributes\MapType;
use futuretek\datamapper\attributes\Format;

class BlogPost
{
    public string $title;
    public ?string $subtitle = null;

    #[Format('date-time')]
    public \DateTimeImmutable $publishedAt;

    #[ArrayType(Comment::class)]
    public array $comments;

    #[ArrayType(\DateTimeInterface::class, format: 'date')]
    public array $holidays;

    #[MapType(valueType: Tag::class)]
    public array $tags;

    public StatusEnum $status;
    public Author $author;

    public readonly string $slug;
}
```

### Map From Array

[](#map-from-array)

```
use futuretek\datamapper\DataMapper;

$dto = DataMapper::toObject($dataArray, BlogPost::class);
```

### Convert Back To Array

[](#convert-back-to-array)

```
$array = DataMapper::toArray($dto);
```

Configuration
-------------

[](#configuration)

```
// Throw InvalidArgumentException when a non-nullable property is missing from input
DataMapper::$validateRequiredProperties = true;

// Set a factory for converting file resources to PSR-7 UploadedFileInterface
DataMapper::$fileFactory = new MyFileFactory();
```

Custom Attributes
-----------------

[](#custom-attributes)

### `#[Format]`

[](#format)

Parses date strings into `DateTimeImmutable` instances.

```
#[Format('date')]        // Parses "2025-06-17" using Y-m-d format
public \DateTimeInterface $birthDate;

#[Format('date-time')]   // Parses "2025-06-17T15:00:00+00:00" using ISO 8601 / ATOM format
public \DateTimeInterface $createdAt;
```

When converting back via `toArray`, a `DateTimeInterface` property without `#[Format]` defaults to `date-time` format.

### `#[ArrayType]`

[](#arraytype)

Declares the item type of an array property — supports class names, scalar type names, and `DateTimeInterface` with a `format`.

```
#[ArrayType(Comment::class)]   // Array of objects — each item is recursively mapped
public array $comments;

#[ArrayType('int')]            // Array of scalars — items are passed through as-is
public array $scores;

#[ArrayType(\DateTimeInterface::class, format: 'date')]
public array $holidays;       // Array of "Y-m-d" strings ↔ DateTimeImmutable[]

#[ArrayType(\DateTimeInterface::class, format: 'date-time')]
public array $events;         // Array of ISO 8601 strings ↔ DateTimeImmutable[]
```

When `format` is provided:

- **`toObject`** — each string item is parsed into a `DateTimeImmutable`; an unparseable item becomes `null`.
- **`toArray`** — each `DateTimeInterface` item is formatted back to a string (`Y-m-d` for `'date'`, ATOM for `'date-time'`).

### `#[MapType]`

[](#maptype)

Declares a property as an associative map (string keys to typed values).

```
#[MapType(valueType: Tag::class)]    // Map of objects — values are recursively mapped
public array $tags;

#[MapType(valueType: 'string')]      // Map of scalars — values are passed through as-is
public array $translations;
```

Supported Property Types
------------------------

[](#supported-property-types)

Type`toObject` Behavior`toArray` Behavior`string`, `int`, `float`, `bool`Assigned directlyReturned as-isNullable (`?type`)`null` values accepted; missing keys use default`null` returned`DateTimeInterface` + `#[Format]`Parsed from string via `new DateTimeImmutable()`Formatted to string`array` + `#[ArrayType(ClassName)]`Items mapped recursivelyItems converted recursively`array` + `#[ArrayType(\DateTimeInterface::class, format: 'date|date-time')]`Each string item parsed into `DateTimeImmutable`Each item formatted back to string`array` + `#[MapType]`Values mapped recursively if class typeValues converted recursivelyBacked `enum`Resolved via `tryFrom()`Serialized to backing valueNested classRecursively mapped from sub-arrayRecursively converted to sub-array`object`Cast from array via `(object)`JSON encode/decode to array`mixed`Assigned as-isReturned as-is`UploadedFileInterface`Assigned directly or via `$fileFactory`Returned as-is`SplFileObject`Assigned directlyReturned as-is`readonly`Set via reflectionReturned normally`public private(set)`Set via reflectionReturned normallyUntyped (`public $x`)Assigned as-isReturned as-isProperty Handling Rules
-----------------------

[](#property-handling-rules)

- **Non-public properties** (private, protected) are skipped.
- **Static properties** are always skipped.
- **Unknown keys** in the input array are silently ignored.
- **Missing non-nullable properties** with `$validateRequiredProperties = true` throw `InvalidArgumentException`.
- **Missing non-nullable properties** with `$validateRequiredProperties = false` remain uninitialized.
- **Uninitialized properties** are skipped during `toArray` conversion.
- **Invalid enum values** throw `UnexpectedValueException`.
- **Malformed date strings** result in `null` (via `DateTimeImmutable::createFromFormat` returning `false`).

File Handling
-------------

[](#file-handling)

Supports `SplFileObject` and PSR-7 `UploadedFileInterface` properties.

For `UploadedFileInterface` properties, if the input value is already an `UploadedFileInterface` instance, it is assigned directly. Otherwise, the configured `FileFactoryInterface` is used to convert the value. If no factory is configured, a `RuntimeException` is thrown.

### Implementing FileFactoryInterface

[](#implementing-filefactoryinterface)

```
use futuretek\datamapper\FileFactoryInterface;
use Psr\Http\Message\UploadedFileInterface;

class MyFileFactory implements FileFactoryInterface
{
    public function createFromResource(mixed $resource): UploadedFileInterface
    {
        if (is_string($resource)) {
            // Handle file path
            $stream = fopen($resource, 'r');
            return new MyUploadedFile($stream, filesize($resource), basename($resource));
        }

        throw new \InvalidArgumentException('Unsupported resource type: ' . gettype($resource));
    }
}
```

Limitations
-----------

[](#limitations)

- **Union types** (e.g., `int|string`) are not supported.
- **Intersection types** are not supported.
- The constructor is **bypassed** via `newInstanceWithoutConstructor()` — constructor logic will not run.
- `DateTimeImmutable` is always used for date parsing, regardless of whether the property type is `DateTime` or `DateTimeInterface`.

License
-------

[](#license)

Apache License 2.0

###  Health Score

45

—

FairBetter than 91% of packages

Maintenance82

Actively maintained with recent releases

Popularity18

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity59

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% 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 ~55 days

Recently: every ~6 days

Total

6

Last Release

94d ago

PHP version history (2 changes)1.0.0PHP &gt;=8.1.0

1.1.0PHP &gt;=8.4.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/1ce67c863775f4dd7237db0547fe39aaf85c9841f34773d67e88f62dcf948ae4?d=identicon)[futuretek](/maintainers/futuretek)

---

Top Contributors

[![lukascernydis](https://avatars.githubusercontent.com/u/3111717?v=4)](https://github.com/lukascernydis "lukascernydis (9 commits)")

---

Tags

data mappercute

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/futuretek-data-mapper/health.svg)

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

###  Alternatives

[aws/aws-sdk-php

AWS SDK for PHP - Use Amazon Web Services in your PHP project

6.3k543.5M2.6k](/packages/aws-aws-sdk-php)[symfony/symfony

The Symfony PHP framework

31.4k87.2M2.2k](/packages/symfony-symfony)[guzzlehttp/psr7

PSR-7 message implementation that also provides common utility methods

8.0k1.1B4.0k](/packages/guzzlehttp-psr7)[neuron-core/neuron-ai

The PHP Agentic Framework.

2.0k656.1k38](/packages/neuron-core-neuron-ai)[getgrav/grav

Modern, Crazy Fast, Ridiculously Easy and Amazingly Powerful Flat-File CMS

15.6k86.4k1](/packages/getgrav-grav)[tempest/framework

The PHP framework that gets out of your way.

2.2k34.4k15](/packages/tempest-framework)

PHPackages © 2026

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