PHP code example of yorcreative / argonaut-dto

1. Go to this page and download the library: Download yorcreative/argonaut-dto 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/ */

    

yorcreative / argonaut-dto example snippets


use YorCreative\ArgonautDTO\ArgonautDTO;

final class UserDTO extends ArgonautDTO
{
    public string $name;
    public string $email;

    protected array $casts = [
        'name' => 'string',
        'email' => 'string',
    ];

    public function rules(): array
    {
        return [
            'name' => ['

$profile = ProfileDTO::fromArray(['fullName' => 'Ada Lovelace']);
$profile = ProfileDTO::fromJson('{"fullName":"Ada Lovelace"}');
$tags    = TagDTO::collection([['name' => 'a'], ['name' => 'b']]); // Collection<TagDTO>

use YorCreative\ArgonautDTO\ArgonautDTO;
use YorCreative\ArgonautDTO\Collection;

final class OrderDTO extends ArgonautDTO
{
    public array $items;
    public Collection $history;
    public ?UserDTO $customer = null;

    protected array $casts = [
        'items' => [OrderItemDTO::class],
        'history' => Collection::class.':'.OrderEventDTO::class,
        'customer' => UserDTO::class,
    ];
}

protected array $casts = [
    'status' => OrderStatus::class,
    'createdAt' => DateTimeImmutable::class,
];

use YorCreative\ArgonautDTO\ArgonautDTO;
use YorCreative\ArgonautDTO\Attributes\CastCollection;
use YorCreative\ArgonautDTO\Attributes\CastEnum;
use YorCreative\ArgonautDTO\Attributes\CastTo;
use YorCreative\ArgonautDTO\Collection;

class OrderDTO extends ArgonautDTO
{
    #[CastTo(CustomerDTO::class)]
    public ?CustomerDTO $customer = null;

    /** @var array<int, LineDTO> */
    #[CastTo(LineDTO::class, many: true)]
    public array $lines = [];

    /** @var Collection<LineDTO> */
    #[CastCollection(LineDTO::class)]
    public ?Collection $lineCollection = null;

    #[CastEnum(Status::class)]
    public ?Status $status = null;
}

class ParentDTO extends ArgonautDTO
{
    #[CastTo(TagDTO::class)]
    public mixed $thing = null;
}

class ChildDTO extends ParentDTO
{
    // Overrides the inherited attribute.
    protected array $casts = ['thing' => 'string'];
}

interface CastsArgonautAttribute
{
    public function get(string $key, mixed $value): mixed;
}

use YorCreative\ArgonautDTO\ArgonautDTO;
use YorCreative\ArgonautDTO\Attributes\CastWith;
use YorCreative\ArgonautDTO\CastsArgonautAttribute;

class MoneyCast implements CastsArgonautAttribute
{
    public function get(string $key, mixed $value): mixed
    {
        return sprintf('$%0.2f', $value / 100);
    }
}

class OrderDTO extends ArgonautDTO
{
    protected array $casts = ['price' => MoneyCast::class];

    public mixed $price = null;
}

class InvoiceDTO extends ArgonautDTO
{
    #[CastWith(MoneyCast::class)]
    public mixed $total = null;
}

(new OrderDTO(['price' => 1999]))->price;    // '$19.99'
(new InvoiceDTO(['total' => 4250]))->total;  // '$42.50'

class OrderDTO extends ArgonautDTO
{
    protected array $casts = [
        'price' => MoneyCast::class,
        'lineTotals' => [MoneyCast::class],
        'refunds' => 'collection:'.MoneyCast::class,
    ];

    public mixed $price = null;

    /** @var array<int, mixed> */
    public array $lineTotals = [];

    /** @var Collection<mixed> */
    public ?Collection $refunds = null;
}

$order = new OrderDTO([
    'price' => 1999,
    'lineTotals' => [500, 750],
    'refunds' => [100],
]);

$order->price;              // '$19.99'
$order->lineTotals;         // ['$5.00', '$7.50']
$order->refunds->all();     // ['$1.00']

class InvoiceDTO extends ArgonautDTO
{
    #[CastWith(MoneyCast::class)]
    public mixed $total = null;

    /** @var array<int, mixed> */
    #[CastWith(MoneyCast::class, many: true)]
    public array $lineTotals = [];

    /** @var Collection<mixed> */
    #[CastWith('collection:'.MoneyCast::class)]
    public ?Collection $refunds = null;
}

$invoice = new InvoiceDTO([
    'total' => 4250,
    'lineTotals' => [500, 750],
    'refunds' => [100],
]);

$invoice->total;              // '$42.50'
$invoice->lineTotals;         // ['$5.00', '$7.50']
$invoice->refunds->all();     // ['$1.00']

class ConflictingDTO extends ArgonautDTO
{
    protected array $casts = ['name' => 'string']; // wins over the attribute below

    #[CastWith(UppercaseCast::class)]
    public mixed $name = null;
}

(new ConflictingDTO(['name' => 'ada']))->name;  // 'ada', not 'ADA'

final class InvoiceSnapshotDTO extends ArgonautImmutableDTO
{
    #[CastWith(MoneyCast::class)]
    public readonly mixed $total;
}

(new InvoiceSnapshotDTO(['total' => 4250]))->total;  // '$42.50'

use YorCreative\ArgonautDTO\ArgonautDTO;
use YorCreative\ArgonautDTO\Attributes\MapFrom;

final class ProfileDTO extends ArgonautDTO
{
    protected array $maps = ['first_name' => 'firstName'];

    public string $firstName = '';

    #[MapFrom('last_name')]
    public string $lastName = '';
}

$profile = new ProfileDTO(['first_name' => 'Ada', 'last_name' => 'Lovelace']);

$profile->firstName; // 'Ada'
$profile->lastName;  // 'Lovelace'

final class ConflictingDTO extends ArgonautDTO
{
    // $maps wins: the #[MapFrom] attribute on $name below is dropped
    // entirely, even though 'legacy_name' and 'name_field' are different
    // incoming keys.
    protected array $maps = ['legacy_name' => 'name'];

    #[MapFrom('name_field')]
    public string $name = '';
}

$dto = new ConflictingDTO(['legacy_name' => 'Ada', 'name_field' => 'ignored']);

$dto->name; // 'Ada' — 'name_field' is no longer a recognized mapping, so it
            // is just an unknown input key and is ignored.

final class AmountDTO extends ArgonautDTO
{
    #[MapFrom('unit_price')]
    public int $price = 0;

    // Casting looks up 'price' — the property name — not 'unit_price', the
    // incoming key, because mapping already ran and renamed the key.
    protected array $casts = ['price' => 'integer'];
}

$amount = new AmountDTO(['unit_price' => '4200']);

$amount->price; // 4200 (int)

use YorCreative\ArgonautDTO\ArgonautImmutableDTO;

final class ContactDTO extends ArgonautImmutableDTO
{
    protected array $maps = ['email_address' => 'email'];

    public readonly string $email;
}

$contact = new ContactDTO(['email_address' => '[email protected]']);
$contact->email; // '[email protected]'

$updated = $contact->with(['email_address' => '[email protected]']);
$updated->email; // '[email protected]'

final class PersonDTO extends ArgonautDTO
{
    protected array $maps = ['first_name' => 'firstName'];

    public string $firstName = '';
}

$person = new PersonDTO(['first_name' => 'Grace']);

$person->toArray();       // ['firstName' => 'Grace']
$person->toJson();        // '{"firstName":"Grace"}'
$person->toMappedArray(); // ['first_name' => 'Grace']
$person->toMappedJson();  // '{"first_name":"Grace"}'

final class AmbiguousDTO extends ArgonautDTO
{
    // fullName is renamed to 'name' on output, but 'name' is a property too.
    protected array $maps = ['name' => 'fullName'];

    public ?string $fullName = null;
    public ?string $name = null;
}

(new AmbiguousDTO(['fullName' => 'Ada']))->toMappedArray();
// LogicException: two keys collide on 'name'

final class AddressDTO extends ArgonautDTO
{
    protected array $maps = ['zip_code' => 'zip'];

    public string $zip = '';
}

final class CustomerDTO extends ArgonautDTO
{
    protected array $casts = ['address' => AddressDTO::class];

    public ?AddressDTO $address = null;
}

$customer = new CustomerDTO(['address' => ['zip_code' => '10001']]);

$customer->toArray();
// ['address' => ['zip' => '10001']]

$customer->toMappedArray();
// ['address' => ['zip' => '10001']] — identical. toMappedArray() only
// renames CustomerDTO's own top-level keys ('address' has no mapping here,
// so it keeps its name). By the time it runs, toArray() has already
// flattened $address into a plain array — AddressDTO's own $maps has no
// object left to apply to.

$dto->toArray();          // full graph
$dto->toArray(2);         // two levels of nested DTOs
$dto->toJson(depth: 2);   // same limit, JSON encoded

use Illuminate\Support\Collection;

final class OrderDTO extends ArgonautDTO
{
    protected array $casts = ['lines' => 'collection:'.LineDTO::class];

    /** @var Collection<int, LineDTO> */
    public Collection $lines;

    protected function collectionClass(): string
    {
        return Collection::class;
    }
}

'lines' => Collection::class.':'.LineDTO::class,   // the class you configured
'lines' => \YorCreative\ArgonautDTO\Collection::class.':'.LineDTO::class,
'lines' => 'collection:'.LineDTO::class,           // shorthand

/** @var Collection<TagDTO> */
public Collection $tags;

$this->tags->first()->name; // PHPStan resolves this to TagDTO::$name

$emails = EmailDTO::collection([
    ['email' => '[email protected]'],
    ['email' => 'not-an-email'],
]);

$emails->isValidAll();          // false
$errors = $emails->validateAll(false);
// [1 => ['email' => ['The email must be a valid email address.']]]

$emails->validateAll();         // throws the failing item's ValidationException

final class UserSnapshotDTO extends ArgonautImmutableDTO
{
    public readonly string $id;
    public readonly string $name;
}

$original = new UserDTO(['firstName' => 'Jane', 'lastName' => 'Doe']);
$updated  = $original->with(['lastName' => 'Smith']);

$updated->lastName;   // 'Smith'
$original->lastName;  // 'Doe' — unchanged

class UserDTO extends ArgonautDTO
{
    public string $firstName = '';

    public string $lastName = '';

    public string $fullName = '';

    /** @var list<string> */
    protected array $prioritizedAttributes = ['firstName', 'lastName'];

    public function setFirstName(string $value): static
    {
        $this->firstName = $value;
        $this->fullName = trim($value.' '.$this->lastName);

        return $this;
    }

    public function setLastName(string $value): static
    {
        $this->lastName = $value;
        $this->fullName = trim($this->firstName.' '.$value);

        return $this;
    }
}

$original = new UserDTO(['firstName' => 'Jane', 'lastName' => 'Doe']);

$original->with(['lastName' => 'Smith'])->fullName;  // 'Jane Smith'

class OrderDTO extends ArgonautDTO
{
    public ?TagDTO $tag = null;

    /** @var array<string, string> */
    protected array $casts = ['tag' => TagDTO::class];
}

$original = new OrderDTO(['tag' => ['name' => 'draft']]);
$copy = $original->with([]);

$copy->tag->name = 'final';

$original->tag->name;   // 'final' — the nested DTO is shared, not copied

final class UserAssembler extends ArgonautAssembler
{
    public static function toUserDTO(object $input): UserDTO
    {
        return new UserDTO([
            'name' => $input->display_name,
            'email' => $input->email,
        ]);
    }
}

$user = UserAssembler::assemble($payload, UserDTO::class);
$users = UserAssembler::fromArray($payloads, UserDTO::class);

$errors = $user->validate(throw: false);
// ['email' => ['The email field failed the email rule.']]