From 5a96b288923be915a628ad67cf1962bd5799895e Mon Sep 17 00:00:00 2001 From: Made Mas Adi Winata Date: Wed, 18 Sep 2024 09:28:31 +0700 Subject: [PATCH 1/2] Carbon to string convert --- src/Dtos/TypeConverter.php | 4 ++++ tests/Dtos/Dto.php | 1 + tests/Dtos/DtosTest.php | 4 +++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Dtos/TypeConverter.php b/src/Dtos/TypeConverter.php index 6963a05..497f219 100644 --- a/src/Dtos/TypeConverter.php +++ b/src/Dtos/TypeConverter.php @@ -64,6 +64,10 @@ public static function assertType(mixed $value, ReflectionClass $reflector, Refl $message .= get_debug_type($value); self::concatMessage($message, $reflector, $prop); Log::channel('runtime')->error($message); + if (get_debug_type($value) == 'Carbon\Carbon') { + $value = $value->toDateString(); + break; + } $value = (string) $value; break; diff --git a/tests/Dtos/Dto.php b/tests/Dtos/Dto.php index 25580c0..e7c46f6 100644 --- a/tests/Dtos/Dto.php +++ b/tests/Dtos/Dto.php @@ -19,4 +19,5 @@ class Dto public ?string $referal; public Company $company; public Carbon $createdAt; + public string $dob; } \ No newline at end of file diff --git a/tests/Dtos/DtosTest.php b/tests/Dtos/DtosTest.php index a55bb10..013b224 100644 --- a/tests/Dtos/DtosTest.php +++ b/tests/Dtos/DtosTest.php @@ -91,7 +91,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)); @@ -101,5 +102,6 @@ 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", $dto->dob); } } \ No newline at end of file From 8922b8d27f8ecc8d2d448c77525e6d0525600ed0 Mon Sep 17 00:00:00 2001 From: Made Mas Adi Winata Date: Thu, 19 Sep 2024 08:47:04 +0700 Subject: [PATCH 2/2] add new feature TraitConvertibleDtos --- src/Dtos/TraitConvertibleDtos.php | 88 +++++++++++++++++++++++++++++++ src/Dtos/TraitDtos.php | 11 ---- src/Dtos/TypeConverter.php | 4 -- tests/Dtos/Dto.php | 3 +- tests/Dtos/Dto2.php | 17 ++++++ tests/Dtos/DtosTest.php | 62 +++++++++++++++++++++- 6 files changed, 167 insertions(+), 18 deletions(-) create mode 100644 src/Dtos/TraitConvertibleDtos.php create mode 100644 tests/Dtos/Dto2.php diff --git a/src/Dtos/TraitConvertibleDtos.php b/src/Dtos/TraitConvertibleDtos.php new file mode 100644 index 0000000..38d87b7 --- /dev/null +++ b/src/Dtos/TraitConvertibleDtos.php @@ -0,0 +1,88 @@ + + * @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 + * @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); + } +} diff --git a/src/Dtos/TraitDtos.php b/src/Dtos/TraitDtos.php index e575636..35dd7b9 100644 --- a/src/Dtos/TraitDtos.php +++ b/src/Dtos/TraitDtos.php @@ -15,9 +15,6 @@ namespace Spotlibs\PhpLib\Dtos; -use ReflectionClass; -use Throwable; - /** * TraitDtos * @@ -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; } } diff --git a/src/Dtos/TypeConverter.php b/src/Dtos/TypeConverter.php index 497f219..6963a05 100644 --- a/src/Dtos/TypeConverter.php +++ b/src/Dtos/TypeConverter.php @@ -64,10 +64,6 @@ public static function assertType(mixed $value, ReflectionClass $reflector, Refl $message .= get_debug_type($value); self::concatMessage($message, $reflector, $prop); Log::channel('runtime')->error($message); - if (get_debug_type($value) == 'Carbon\Carbon') { - $value = $value->toDateString(); - break; - } $value = (string) $value; break; diff --git a/tests/Dtos/Dto.php b/tests/Dtos/Dto.php index e7c46f6..54747ee 100644 --- a/tests/Dtos/Dto.php +++ b/tests/Dtos/Dto.php @@ -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; diff --git a/tests/Dtos/Dto2.php b/tests/Dtos/Dto2.php new file mode 100644 index 0000000..936a965 --- /dev/null +++ b/tests/Dtos/Dto2.php @@ -0,0 +1,17 @@ + ['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)); @@ -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 */ @@ -102,6 +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", $dto->dob); + $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); } } \ No newline at end of file