phpexperts/simple-dto

A quick and easy DTO package.

v3.5.1 2023-09-21 05:48 UTC

README

TravisCI Maintainability Test Coverage

SimpleDTO is a PHP Experts, Inc., Project meant to facilitate easy Data Transfer Objects.

Basically, any protected property on the DTO can be set as an array element passed in to the __constructor and/or as a default value on the property itself.

The DTOs are immutable: Once created, they cannot be changed. Create a new object instead.

Installation

Via Composer

composer require phpexperts/simple-dto

Usage

As of version 2, you must define class-level @property docblocks for each one of your properties.

You also must define the data type.

use Carbon\Carbon;
use PHPExperts\SimpleDTO\SimpleDTO;

/**
 * @property-read string $name
 * @property-read Carbon $date
 */
class BirthdayDTO extends SimpleDTO
{
    /** @var string */
    protected $name;
    
    /** @var Carbon */
    protected $date;
}

$birthdayDTO = new BirthdayDTO([
    'name' => 'Donald J. Trump',
    'date' => '1946-06-14',
]);

// Access as a property:
echo $birthday->name; // Donald J. Trump

// Properties with the data type of "Carbon" or "Carbon\Carbon" 
// are automagically converted to Carbon objects.
echo $birthday->date->format('F jS, Y'); // June 14th, 1946

// Easily output as an array:
$birthday->toArray();

// Copy from one to another:
$newDTO = new BirthdayDTO($birthdayDTO->toArray());

// Copy from one to another, with new properties:
$newDTO = new BirthdayDTO($birthdayDTO->toArray() + [
    'date' => '2020-11-03',
]);

// Easily output as JSON:
echo json_encode($birthdayDTO);
/* Output: 
{
    "name": "Donald J. Trump",
    "date": "1946-06-14T00:00:00.000000Z"
}
*/

Fuzzy Data Types

But what if you aren't ready / able to dive into strict PHP data types yet?

Well, just instantiate the parent class like this:

    use PHPExperts\DataTypeValidator\DataTypeValidator;
    use PHPExperts\DataTypeValidator\IsAFuzzyDataType;
    
    /**
     * @property int   $daysAlive
     * @property float $age
     * @property bool  $isHappy
     */
    class MyFuzzyDTO extends SimpleDTO
    {
        public function __construct(array $input)
        {
            parent::__construct($input, new DataTypeValidator(new IsAFuzzyDataType());
        }
    }

    $person = new MyFuzzyDTO([
        'daysAlive' => '5000',
        'age'       => '13.689',
        'isHappy'   => 1,
    ]);

    echo json_encode($person, JSON_PRETTY_PRINT);
    /*
    {
        "daysAlive": "5000",
        "age": "13.689",
        "isHappy": 1
    }
    */

NestedDTOs

You can nest DTOs inside of each other.

    $myDTO = new MyTestDTO([
        'name' => 'PHP Experts, Inc.',
        'age'  => 7.01,
        'year' => 2019,
    ]);

    /**
     * @property MyTestDTO $myDTO
     */
    $dto = new class(['myDTO' => $myDTO], ['myDTO' => MyTestDTO::class]) extends NestedDTO
    {
    };
    
    /*
    PHPExperts\SimpleDTO\NestedDTO@anonymous {
      -dataTypeRules: array:1 [
        "myDTO" => "?MyTestDTO"
      ]
      -data: array:1 [
        "myDTO" => PHPExperts\SimpleDTO\Tests\MyTestDTO {#355
          -dataTypeRules: array:3 [
            "name" => "?string"
            "age" => "?float"
            "year" => "?int"
          ]
          -data: array:3 [
            "name" => "PHP Experts, Inc."
            "age" => 7.01
            "year" => 2019
          ]
        }
      ]
    }
    */

Use cases

PHPExperts\SimpleDTO\SimpleDTO
✔ Properties are set via the constructor
✔ Properties are accessed as public properties
✔ Constructor assigns default values of typed properties
✔ Public, private and static protected properties will be ignored
✔ Each DTO is immutable
✔ Setting any property returns an exception
✔ Concrete properties can be used to set default values
✔ Properties with the type carbon become carbon dates
✔ Can easily output to array
✔ Can easily be JSON encoded
✔ Can easily be JSON decoded
✔ Nullable properties are allowed
✔ Every property is nullable with permissive mode
✔ Can be serialized
✔ Can be unserialized
✔ Extra validation can be added
✔ Can get the internal data
✔ Can identify if it is permissive or not

PHPExperts\SimpleDTO\NestedDTO
✔ Will construct nested DTOs
✔ Can construct arrays of nested DTOs
✔ Can retrieve the stored DTOs.
✔ Will convert array data into the appropriate Nested DTOs
✔ Will convert stdClasses into the appropriate Nested DTOs
✔ Nested DTOs use Loose typing
✔ Nested DTOs can be built using Typed Properties
✔ Nested DTOs with Typed Properties use Strict typing
✔ All registered Nested DTOs are required
✔ Optional, unregistered, Nested DTOs are handled gracefully
✔ Can be serialized
✔ Can be unserialized
✔ Can validate the DTO manually
✔ Can get the internal data

PHPExperts\SimpleDTO\WriteOnceTrait
✔ Can accept null values
✔ Will validate on serialize
✔ Will validate on to array
✔ Can write each null value once
✔ Write-Once values must validate

SimpleDTO Sad Paths
✔ Cannot initialize with a nonexisting property
✔ Accessing a nonexisting property throws an error
✔ A DTO must have class property docblocks -or- typehint for each concrete property
✔ Carbon date strings must be parsable dates
✔ Properties must match their data types
✔ Will not unserialize DTOs with invalid data
✔ Cannot overwrite a non-existing property

Testing

phpunit --testdox

Contributors

Theodore R. Smith theodore@phpexperts.pro
GPG Fingerprint: 4BF8 2613 1C34 87AC D28F 2AD8 EB24 A91D D612 5690
CEO: PHP Experts, Inc.

License

MIT license. Please see the license file for more information.