AthenaeumAthenaeum
Packages
  • next
  • current
  • v9.x
  • v8.x
  • v7.x
  • v6.x
  • v5.x
  • v4.x
  • v3.x
  • v2.x
  • v1.x
Changelog
GitHub
Packages
  • next
  • current
  • v9.x
  • v8.x
  • v7.x
  • v6.x
  • v5.x
  • v4.x
  • v3.x
  • v2.x
  • v1.x
Changelog
GitHub
  • Version 10.x

    • Release Notes
    • Upgrade Guide
    • New to this...
    • Contribution Guide
    • Security Policy
    • Code of Conduct
    • Origin
  • ACL

    • Introduction
    • How to install
    • Setup
    • Permissions
    • Roles
    • Users
    • Cached Permissions
  • Antivirus

    • Introduction
    • How to install
    • Setup
    • How to use
    • Scanners

      • Introduction
      • ClamAV
      • Null
      • Custom
    • Events
    • PSR
  • Audit

    • Audit
    • How to install
    • Setup
    • Recording
    • Events
    • Formatting
  • Auth

    • Introduction
    • How to install
    • Fortify

      • Prerequisites
      • Exceptions

        • Failed Login Attempt
        • Password Reset Link Failure
      • Responses

        • Failed Password Reset Link
  • Circuits

    • Circuits
    • How to install
    • Setup
    • Usage
    • Events
  • Collections

    • Collections
    • How to install
    • Summation

      • Summation Collection
      • Items Processor
  • Config

    • Configuration Loader
    • How to install
    • Setup
    • Load Configuration Files
    • Custom File Parsers
  • Console

    • Command and Schedule Registration
    • How to install
    • Setup
    • Commands
    • Schedules
  • Container

    • IoC Service Container
    • How to install
    • Container
    • List Resolver
  • Core

    • Athenaeum Core Application
    • How to install
    • Setup
    • Usage

      • Configuration
      • Service Providers
      • Service Container
      • Events
      • Caching
      • Logging
      • Console
      • Task Scheduling
      • Exception Handling
      • Extending Core Application
      • Testing
  • Database

    • Introduction
    • How to install
    • Models

      • Instantiatable
      • Sluggable
    • Query

      • Criteria (Query Filter)
  • Dto

    • Data Transfer Object (DTO)
    • How to install
    • How to use
  • ETags

    • Introduction
    • How to install
    • Setup
    • ETags usage

      • How to use
      • Generators

        • Default Generator
        • Custom Generator
      • Eloquent Models
    • Http Request Preconditions

      • Introduction
      • Resource Context
      • Preconditions
      • Actions
      • RFC 9110

        • If-Match
        • If-Unmodified-Since
        • If-None-Match
        • If-Modified-Since
        • If-Range
      • Extensions

        • Introduction
        • Range
      • Range Validator
      • Download Stream
    • Macros
  • Events

    • Register Listeners and Subscribers
    • How to install
    • Setup
    • Listeners
    • Subscribers
  • Filters

    • Search Filter Utilities
    • Prerequisites
    • How to install
    • Setup
    • Processor
    • Filters Builder
    • Predefined Resources

      • Search Processor
      • Sorting Processor
      • Constraints Processor
      • Matching Processor
    • Tip: Create a base builder
  • Flysystem

    • Introduction
    • Database Adapter

      • Introduction
      • How to install
      • Setup
      • Data Deduplication
      • MIME-Type Detection
  • Http

    • Api

      • Http API
      • How to install
      • Setup
      • Resources

        • Introduction
        • Timestamps
        • Self-Link
        • Relations
        • Caching
        • Registrar
      • Requests

        • Introduction
        • List Resources
        • List Deleted
        • Show Resource
        • Create Resource
        • Update Resource
        • Delete Resource
        • List Related
        • Process Multiple Resources
        • Helpers
      • Middleware

        • Introduction
        • Request Must Be Json
        • Capture Fields To Select
        • Remove Response Payload
    • Clients

      • Http Clients
      • How to install
      • Setup
      • Basic Usage
      • Available Methods

        • Fluent Api
        • Protocol Version
        • Base Uri
        • Http Method and Uri
        • Headers
        • Accept & Content-Type
        • Authentication
        • Http Query
        • Payload Format
        • Payload
        • Attachments
        • Cookies
        • Response Expectations
        • Middleware
        • Conditions
        • Criteria
        • Redirects
        • Timeout
        • Debugging
        • Logging
        • Driver Options
        • Driver
      • Http Query Builder

        • Introduction
        • Select
        • Where
        • Dates
        • Include
        • Pagination
        • Sorting
        • Raw Expressions
        • Custom Grammar
    • Cookies

      • Http Cookies
      • How to install
      • Usage
    • Messages

      • Http Messages
      • How to install
      • Serializers
  • Maintenance

    • Modes

      • Maintenance Modes
      • How to install
      • Setup
      • Basic Usage
      • Available Drivers
  • Mime Types

    • MIME-Types
    • How to install
    • Setup
    • Usage
    • Drivers

      • Available Drivers
      • File Info
  • Properties

    • Properties Overload
    • How to install
    • Usage
    • Naming Convention
    • Properties Visibility
  • Redmine

    • Redmine Api Client
    • How to install
    • Setup
    • General Usage

      • Supported Operations
      • Fetch list of resources
      • Find
      • Fetch
      • Create new record
      • Update existing record
      • Delete existing record
      • Relations
    • Available Resources

      • Predefined Resources
      • Attachments
      • Enumerations
      • Issue Relations
      • Users
      • User Groups
      • Roles
      • Project Memberships
      • Versions (Milestones)
      • Issue Categories
      • Trackers
  • Service

    • Service Registrar
    • How to install
    • How to use
  • Streams

    • Streams
    • How to install
    • Setup
    • How to use

      • Introduction
      • Open and Close
      • Raw Resource
      • Seeking
      • Reading
      • Writing
      • Size
      • Truncate
      • Sync
      • Flush
      • Hash
      • MIME-Type
      • Filename
      • Output
      • Locking
      • Transactions
      • Meta
      • Misc
  • Support

    • Introduction
    • How to install
    • Laravel Aware-of Helpers

      • How to use
      • Enforce Via Interface
      • Custom Default
      • Pros and Cons
      • Available Helpers
    • Env File
    • Aware-of Properties

      • Generator
    • Live Templates
  • Testing

    • Introduction
    • How to install
    • Test Cases
    • Testing Aware-of Helpers
  • Translation

    • Introduction
    • How to install
    • Exporters

      • Introduction
      • Setup
      • How to use
      • Drivers

        • Introduction
        • Array
        • Lang.js (Array)
        • Lang.js (JSON)
        • Cache
  • Utils

    • Introduction
    • How to install
    • Array
    • Duration
    • Json
    • Math
    • Memory
    • Method Helper
    • Invoker
    • Populatable
    • String
    • Version
  • Validation

    • Introduction
    • How to install
    • Setup
    • Rules

      • Alpha-Dash-Dot
      • Date Format
      • Semantic Version

How to use

Create new DTO class

To create a new DTO, extend the ArrayDto abstraction. Specify which properties are allowed and their corresponding data types (see supported types).

use Aedart\Dto\ArrayDto;

/**
* Organisation
 *
 * @property string $name
 * @property int $employees
 * @property bool $hasInsurance
 * @property float $profitScore
 * @property string[] $boardMembers
 * @property \Carbon\Carbon $started
 */
class Organisation extends ArrayDto
{
    protected array $allowed = [
        'name'          => 'string',
        'employees'     => 'int',
        'hasInsurance'  => 'bool',
        'profitScore'   => 'float',
        'boardMembers'  => 'array',
        'started'       => 'date',
    ];
}

Later in you application, you can instantiate a new instance and populate it with data.

$dto = new Organisation([
    'name'          => 'Acme Ltd',
    'employees'     => 134,
    'hasInsurance'  => true,
    'profitScore'   => 33.8,
    'boardMembers'  => [ 'Sawyer', 'Stine', 'Jim' ],
    'started'       => '2018-06-15 10:00:00'
]);

echo $dto->name; // Acme Ltd

$dto['employees'] = 136; // 'employees' property set to 136

Supported Types

By default, each declared property is nullable, meaning that a property is either of the declared data type or null.

The following are the supported data types:

  • string
  • int
  • float,
  • bool
  • array
  • date (property is parsed into a Carbon instance)

Note

You can change how each type is cast or converted, by overwriting the castPropertyValue() method.

Alternatively, you can overwrite each type's individual casting method, e.g. castAsDate(), castAsBoolean(), castAsString(), ...etc.

For more information, please review the source code of \Aedart\Dto\Partials\CastingPartial trait, which is used by the ArrayDto.

Nested DTOs

In order to work with nested DTOs, you must declare their class path as the data type, in the $allowed property.

use Aedart\Dto\ArrayDto;

class Address extends ArrayDto
{
    protected array $allowed = [
        'street' => 'string',
        'city' => 'string',
        'zipcode' => 'string',
    ];
}
use Aedart\Dto\ArrayDto;
use Acme\Dto\Address;

class Organisation extends ArrayDto
{
    protected array $allowed = [
        'name'          => 'string',
        'address'       => Address::class, // Class path to nested DTO
    ];
}

When populating you DTO, simply provide the nested DTO's instance.

$organisation = new Organisation([
    'name' => 'Acme',
    'address' => new Address([
        'street' => 'Somewhere str. 44',
        'city' => 'Copenhagen',
        'zipcode' => 'DK-1050',
    ])
]);

Resolving Nested DTOs from array

It is also possible to populate a nested DTO via an array, without instantiating a new instance. The ArrayDto abstraction will automatically resolve the expected nested DTO and populate it.

$organisation = new Organisation([
    'name' => 'Acme',
    'address' => [
        'street' => 'Somewhere str. 44',
        'city' => 'Copenhagen',
        'zipcode' => 'DK-1050',
    ]
]);

$address = $organisation->address; // Address DTO instance

Union Types

If you define properties that accept union types, then the ArrayDto will attempt to populate the value accordingly.

class Article extends ArrayDto
{
    protected array $allowed = [
        'id' => 'string|int|float|bool|null',
        'content' => 'array|null',
        'createdAt' => 'date|null',
        'author' => ['string', Person::class, Organisation::class, 'null'],
    ];
}
$article = new Article([
    'id' => 'allan-james-jr'
]);
echo gettype($article->id); // string

$article->id = 42;
echo gettype($person->id)); // integer  

For nested DTO's, if you provide an array, instead of an object instance, then the "best fitting" nested DTO will be resolved. This is determined by what properties are allowed and what properties are given.

$article = new Article([
    'author' => 'Allan James Jr.'
]);
echo gettype($article->author); // string

// ------------------------------------------------------------------- //

// Populates Person DTO, if given properties are supported
$article->author = [
    'name' => 'Allan James Jr.'
];
$author = $person->author; // Person DTO instance  

// ------------------------------------------------------------------- //

// Populates Organisation DTO, if given properties are supported
$article->author = [
    'name' => 'Acme',
    'address' => [
        'street' => 'Somewhere str. 44',
        'city' => 'Copenhagen',
        'zipcode' => 'DK-1050',
    ]
];
$author = $person->author; // Organisation DTO instance

Getters and Setters

If you require a more advanced way to resolve a property, then you can define custom accessor or mutator methods. Doing will automatically ignore the initial declared data type of the property.

use Aedart\Dto\ArrayDto;

class Organisation extends ArrayDto
{
    protected array $allowed = [
        'name'          => 'string', // Type ignored!
    ];
    
    public function setName(string|null $name)
    {
        $this->properties['name'] = strtoupper($name);

        return $this;
    }

    public function getName() : string|null
    {
        return $this->properties['name'] ?? null;
    }
}
$organisation = new Organisation([
    'name' => 'acme',
]);

echo $organisation->name; // ACME

Naming Convention

Method names must follow CamelCase and be prefixed with get for accessor methods (getters), and set for mutator methods (setters).

getterMethod = getPrefix, camelCasePropertyName;
getPrefix = "get";

setterMethod = setPrefix, camelCasePropertyName;
setPrefix = "set";

camelCasePropertyName = {uppercaseLetter, {lowercaseLetter}};

uppercaseLetter = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J"
| "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W"
| "X" | "Y" | "Z" ;

lowercaseLetter = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j"
| "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w"
| "x" | "y" | "z" ;

Above stated syntax / rules is expressed in EBNF

Backed Enums

BackedEnum are also supported as a data types. Note, that basic enums (UnitEnum) are not supported.

enum Status: string
{
    case DRAFT = 'draft';
    case PUBLISHED = 'published';
    case UNPUBLISHED = 'unpublished';
    case UNDER_REVIEW = 'review';
}

class Article extends ArrayDto
{
    protected array $allowed = [
        'title' => 'string',
        'status' => Status::class
    ];
}
$article = new Article([
    'name' => 'Long Island Journey',
    'status' => Status::DRAFT
]);

// Or, use enum case value...
$article->status = 'review'; // Auto-resolved to UNDER_REVIEW Status enum case

Populate

To populating your DTO with data, provide the constructor with an array, using the populate() method, or from a JSON string using the fromJson() method.

Note

Getters and setter methods are automatically invoked for each property, if available.

Constructor

$person = new Person([
    'name' => 'Carmen Rock',
    'age'  => 25
]);

echo $person->name; // Carmen Rock

populate()

$person->populate([
    'name' => 'Timmy Jones',
    'age'  => 32
]);

echo $person->name; // Timmy Jones

JSON

$json = '{"name":"Miss Mossie Wehner Sr.","age":28}';

$person = Person::fromJson($json);

echo $person->name; // Miss Mossie Wehner Sr.

Export

By default, the ArrayDto can be exported to an array, using the toArray() method.

$properties = $person->toArray();
var_dump($properties);  
array(2) {
  ["name"]=> string(5) "Timmy"
  ["age"]=> int(19)
}

JSON

The ArrayDto abstraction inherits from JsonSerializable. This means that you can use json_encode() directly on your DTO instance.

$person = new Person([
    'name' => 'Rian Dou',
    'age' => 29
]);

echo json_encode($person);
{
    "name":"Rian Dou",
    "age":29
}

The same can be achieved via the toJson() method.

$person = new Person([
    'name' => 'Rian Dou',
    'age' => 29
]);

echo $person->toJson(); // The same as invoking json_encode($person);

Serialization

You can also serialise and unserialise your DTOs, using PHP's native methods.

$serialised = serialize($person);
$person = unserialize($serialised);
Edit page
Last Updated: 22/03/2026, 15:04
Contributors: Alin Eugen Deac, alin, aedart
Prev
How to install