Skip to content

Commit

Permalink
Merge pull request #19 from spotlibs/feature/exploration
Browse files Browse the repository at this point in the history
new trait TraitConvertibleDtos
  • Loading branch information
m45adiwinata committed Sep 19, 2024
2 parents 4a46402 + 8922b8d commit 4a3f3cb
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 14 deletions.
88 changes: 88 additions & 0 deletions src/Dtos/TraitConvertibleDtos.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php

/**
* PHP version 8
*
* @category Library
* @package Dtos
* @author Made Mas Adi Winata <m45adiwinata@gmail.com>
* @license https://mit-license.org/ MIT License
* @version GIT: 0.0.4
* @link https://github.com/spotlibs
*/

declare(strict_types=1);

namespace Spotlibs\PhpLib\Dtos;

use ReflectionClass;
use Throwable;

/**
* TraitDtos
*
* @category Library
* @package Dtos
* @author Made Mas Adi Winata <m45adiwinata@gmail.com>
* @license https://mit-license.org/ MIT License
* @link https://github.com/spotlibs
*/
trait TraitConvertibleDtos
{
/**
* Construct a DTO instance from associative array. Array key and value data type must comply DTO class property
*
* @param array $data associative array
*
* @return mixed
*/
public function __construct(array $data = [])
{
$reflector = new ReflectionClass(static::class);
foreach ($data as $key => $value) {
try {
$prop = $reflector->getProperty($key);
} catch (Throwable) {
// array key is not one of constructed DTO's property name
continue;
}
$value = TypeConverter::assertType($value, $reflector, $prop);
$this->{$key} = $value;
}
}

/**
* Create a DTO instance from associative array. Array key and value data type must comply DTO class property
*
* @param array $data associative array
*
* @return mixed
*/
public static function create(array $data): mixed
{
$self = new self($data);

return $self;
}

/**
* Convert instance to associative array
*
* @return array
*/
public function toArray(): array
{
return (array) $this;
}

/**
* Convert instance to json
*
* @return bool|string
*/
public function toJson()
{
$data = $this->toArray();
return json_encode($data);
}
}
11 changes: 0 additions & 11 deletions src/Dtos/TraitDtos.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@

namespace Spotlibs\PhpLib\Dtos;

use ReflectionClass;
use Throwable;

/**
* TraitDtos
*
Expand All @@ -38,15 +35,7 @@ trait TraitDtos
*/
public function __construct(array $data = [])
{
$reflector = new ReflectionClass(static::class);
foreach ($data as $key => $value) {
try {
$prop = $reflector->getProperty($key);
} catch (Throwable) {
// array key is not one of constructed DTO's property name
continue;
}
$value = TypeConverter::assertType($value, $reflector, $prop);
$this->{$key} = $value;
}
}
Expand Down
4 changes: 3 additions & 1 deletion tests/Dtos/Dto.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
namespace Tests\Dtos;

use Carbon\Carbon;
use Spotlibs\PhpLib\Dtos\TraitConvertibleDtos;
use Spotlibs\PhpLib\Dtos\TraitDtos;

class Dto
{
use TraitDtos;
use TraitConvertibleDtos;
public string $name;
public int $age;
public float $salary;
Expand All @@ -19,4 +20,5 @@ class Dto
public ?string $referal;
public Company $company;
public Carbon $createdAt;
public string $dob;
}
17 changes: 17 additions & 0 deletions tests/Dtos/Dto2.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace Tests\Dtos;
use Spotlibs\PhpLib\Dtos\TraitDtos;

class Dto2
{
use TraitDtos;

public string $name;
public int $employeeId;
public bool $isActive;
public array $relatives;
public Vehicle $vehicle;
}
64 changes: 62 additions & 2 deletions tests/Dtos/DtosTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
namespace Tests\Dtos;

use Carbon\Carbon;
use Exception;
use Laravel\Lumen\Testing\TestCase;
use TypeError;

class DtosTest extends TestCase
{
Expand All @@ -31,7 +33,8 @@ public function testConstructDto()
'chores' => ['eat', 'sleep', 'coding'],
'married' => true,
'referal' => null,
'company' => $company
'company' => $company,
'createdAt' => Carbon::parse("2024-06-18")
];
$dto = new Dto($data);
$this->assertEquals('string', get_debug_type($dto->name));
Expand All @@ -43,6 +46,7 @@ public function testConstructDto()
$this->assertEquals('array', get_debug_type($arrDto));
$jsonDto = $dto->toJson();
$this->assertEquals('string', get_debug_type($jsonDto));
$this->assertEquals('2024-06-18 00:00:00', $arrDto['createdAt']);
}

/** @test */
Expand Down Expand Up @@ -91,7 +95,8 @@ public function testConstructDto3()
'married' => 'perhaps',
'referal' => 'Larry',
'company' => $vehicle,
'createdAt' => "2024-09-17"
'createdAt' => "2024-09-17",
'dob' => Carbon::parse("1973-08-21")
];
$dto = new Dto($data);
$this->assertEquals('string', get_debug_type($dto->name));
Expand All @@ -101,5 +106,60 @@ public function testConstructDto3()
$this->assertEquals('float', get_debug_type($dto->salary));
$this->assertEquals('Carbon\Carbon', get_debug_type($dto->createdAt));
$this->assertFalse($dto->married);
$this->assertEquals("1973-08-21 00:00:00", $dto->dob);
}

/** @test */
/** @runInSeparateProcess */
public function testConstructDto4()
{
$vehicle = new Vehicle("BMW", "matic", 2000);
$data = [
'name' => 'andrew',
'employeeId' => 1,
'isActive' => true,
'relatives' => ['robert', 'lana', 'garry'],
'vehicle' => $vehicle
];
$dto = new Dto2($data);
$this->assertEquals('string', get_debug_type($dto->name));
$this->assertEquals($dto->name, 'andrew');
$arrDto = $dto->toArray();
$jsonDto = $dto->toJson();
$this->assertEquals('array', get_debug_type($arrDto));
$this->assertEquals('string', get_debug_type($jsonDto));
}

/** @test */
/** @runInSeparateProcess */
public function testConstructDto5()
{
$vehicle = new Vehicle("BMW", "matic", 2000);
$data = [
'name' => 'andrew',
'employeeId' => 1,
'isActive' => true,
'relatives' => ['robert', 'lana', 'garry'],
'vehicle' => $vehicle
];
$dto = Dto2::create($data);
$this->assertEquals('string', get_debug_type($dto->name));
$this->assertEquals($dto->name, 'andrew');
}

/** @test */
/** @runInSeparateProcess */
public function testConstructDtoError()
{
$this->expectException(TypeError::class);
$vehicle = new Vehicle("BMW", "matic", 2000);
$data = [
'name' => 123,
'employeeId' => 1,
'isActive' => true,
'relatives' => ['robert', 'lana', 'garry'],
'vehicle' => $vehicle
];
new Dto2($data);
}
}

0 comments on commit 4a3f3cb

Please sign in to comment.