1. Go to this page and download the library: Download tiny-blocks/mapper library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
tiny-blocks / mapper example snippets
declare(strict_types=1);
final readonly class Amount
{
public function __construct(public int $amount, public Currency $currency)
{
}
}
declare(strict_types=1);
enum Currency: string
{
case BRL = 'BRL';
case USD = 'USD';
}
declare(strict_types=1);
use TinyBlocks\Mapper\Mapper;
use TinyBlocks\Mapper\SnakeCase;
$strict = Mapper::create()
->withNaming(namingStrategy: SnakeCase::create())
->rejectingUnknownKeys();
declare(strict_types=1);
use TinyBlocks\Mapper\Mappable;
use TinyBlocks\Mapper\MappableBehavior;
final readonly class Address implements Mappable
{
use MappableBehavior;
public function __construct(public string $city, public string $street)
{
}
}
declare(strict_types=1);
abstract readonly class PaymentMethod
{
}
declare(strict_types=1);
final readonly class Pix extends PaymentMethod
{
public function __construct(public string $payerId)
{
}
public static function pending(): Pix
{
return new Pix(payerId: 'pending');
}
}
declare(strict_types=1);
final readonly class DebitCard extends PaymentMethod
{
public function __construct(public string $cardNumber)
{
}
}
declare(strict_types=1);
final readonly class MemberId
{
public function __construct(private string $value)
{
}
public function value(): string
{
return $this->value;
}
}
declare(strict_types=1);
final readonly class Owner
{
public function __construct(public MemberId $memberId, public string $name)
{
}
}
declare(strict_types=1);
use TinyBlocks\Mapper\JsonColumn;
use TinyBlocks\Mapper\Layout;
use TinyBlocks\Mapper\Mapper;
$mapper = Mapper::create()->withMapping(
type: Owner::class,
mapping: Layout::from(paths: ['memberId' => new JsonColumn(column: 'member')])
);
$owner = $mapper->toObject(type: Owner::class, source: ['member' => '{"value":"m-1"}', 'name' => 'Alice']);
declare(strict_types=1);
final readonly class Refund
{
public function __construct(public string $reference, public Amount $amount)
{
}
}
declare(strict_types=1);
use Generator;
use IteratorAggregate;
use TinyBlocks\Mapper\ElementType;
use TinyBlocks\Mapper\IterableMappable;
use TinyBlocks\Mapper\Mapper;
#[ElementType(Refund::class)]
class Refunds implements IteratorAggregate, IterableMappable
{
private function __construct(public readonly iterable $elements)
{
}
public static function createFrom(iterable $elements): static
{
return new static(elements: $elements);
}
public function toJson(): string
{
return Mapper::create()->toJson(source: $this);
}
public function toArray(): array
{
return Mapper::create()->toArray(source: $this);
}
public function getIterator(): Generator
{
foreach ($this->elements as $key => $element) {
yield $key => $element;
}
}
}
declare(strict_types=1);
use DateTimeImmutable;
final readonly class CalendarDate
{
private function __construct(private DateTimeImmutable $value)
{
}
public static function fromIso(string $iso): CalendarDate
{
return new CalendarDate(value: DateTimeImmutable::createFromFormat('!Y-m-d', $iso));
}
public function toIso(): string
{
return $this->value->format('Y-m-d');
}
}
declare(strict_types=1);
final readonly class Reservation
{
public function __construct(public CalendarDate $checkIn)
{
}
}
declare(strict_types=1);
use TinyBlocks\Mapper\Codec;
use TinyBlocks\Mapper\Mapper;
$mapper = Mapper::create()->withMapping(
type: CalendarDate::class,
mapping: Codec::from(
decode: static fn(string $iso): CalendarDate => CalendarDate::fromIso(iso: $iso),
encode: static fn(CalendarDate $date): string => $date->toIso()
)
);
# The encode closure drives every write, so the nested date stays a canonical YYYY-MM-DD string.
$row = $mapper->toArray(source: new Reservation(checkIn: CalendarDate::fromIso(iso: '2026-05-23')));
# A bare scalar is decoded directly into the value object.
$checkIn = $mapper->toObject(type: CalendarDate::class, source: '2026-05-23');
declare(strict_types=1);
use TinyBlocks\Mapper\ScalarCodec;
#[ScalarCodec(decode: 'fromLabel', encode: 'toLabel')]
#[ScalarCodec(decode: 'fromNumber', encode: 'toLabel')]
final readonly class Version
{
private function __construct(private string $label)
{
}
public static function fromLabel(string $label): Version
{
return new Version(label: $label);
}
public static function fromNumber(int $number): Version
{
return new Version(label: (string) $number);
}
public function toLabel(): string
{
return $this->label;
}
}
declare(strict_types=1);
final readonly class Release
{
public function __construct(public Version $version)
{
}
}
declare(strict_types=1);
use TinyBlocks\Mapper\Mapper;
$mapper = Mapper::create();
# The string source selects the decode whose parameter is typed string.
$fromLabel = $mapper->toObject(type: Version::class, source: 'v7');
# The integer source, nested in a release, selects the decode whose parameter is typed int.
$release = $mapper->toObject(type: Release::class, source: ['version' => 7]);
# The first declared pair's encode renders the scalar form.
$label = $mapper->toArray(source: Version::fromLabel(label: 'v7'));
declare(strict_types=1);
enum Priority: string
{
case LOW = 'low';
case HIGH = 'high';
}
final readonly class Label
{
public function __construct(public Priority $priority)
{
}
}
declare(strict_types=1);
final readonly class Task
{
public function __construct(public string $name, public Label $label)
{
}
}
declare(strict_types=1);
use TinyBlocks\Mapper\Mapper;
$mapper = Mapper::create();
# The label adopts the backed enum's scalar form, so the column holds a bare value.
$row = $mapper->toArray(source: new Task(name: 'deploy', label: new Label(priority: Priority::HIGH)));
# The same scalar reconstructs the nested label.
$task = $mapper->toObject(type: Task::class, source: ['name' => 'deploy', 'label' => 'high']);
declare(strict_types=1);
final readonly class Organization
{
public function __construct(public string $registrationId)
{
}
}
declare(strict_types=1);
use TinyBlocks\Mapper\Mapper;
use TinyBlocks\Mapper\SnakeCase;
use TinyBlocks\Mapper\Structured;
# Default delegation collapses the wrapper to its inner scalar.
Mapper::create()->toArray(source: new Organization(registrationId: 'org-1'));
# ['org-1']
# Registered with Structured, the wrapper keeps its object shape and rebuilds on read.
$mapper = Mapper::create()->withMapping(type: Organization::class, mapping: Structured::create());
$mapper->toArray(source: new Organization(registrationId: 'org-1'));
# ['registrationId' => 'org-1']
$mapper->toObject(type: Organization::class, source: ['registrationId' => 'org-1']);
# Organization(registrationId: 'org-1')
# It composes with the naming strategy and with omittingNulls.
Mapper::create()
->withNaming(namingStrategy: SnakeCase::create())
->withMapping(type: Organization::class, mapping: Structured::create())
->toArray(source: new Organization(registrationId: 'org-1'));
# ['registration_id' => 'org-1']
declare(strict_types=1);
final readonly class Money
{
private function __construct(public int $cents, public string $currency)
{
}
public static function of(int $cents, string $currency): Money
{
return new Money(cents: $cents, currency: strtoupper($currency));
}
}
declare(strict_types=1);
use TinyBlocks\Mapper\FactoryMethod;
use TinyBlocks\Mapper\Mapper;
$mapper = Mapper::create()->withMapping(
type: Money::class,
mapping: FactoryMethod::using(method: 'of')
);
# Each parameter is resolved from the array by its name, then passed to the factory.
$money = $mapper->toObject(type: Money::class, source: ['cents' => 500, 'currency' => 'brl']);
# Reflection over the declared properties writes the array back, symmetric with the read input.
$row = $mapper->toArray(source: $money);
declare(strict_types=1);
use DateTimeImmutable;
final readonly class Profile
{
public function __construct(
public string $name,
public ?string $title,
public DateTimeImmutable $createdAt,
public Severity $severity
) {
}
}
declare(strict_types=1);
enum Severity
{
case LOW;
case HIGH;
}