From 4c87cf920c632bd91b85af1e25819e0838e851db Mon Sep 17 00:00:00 2001 From: Andrey Iatsenko Date: Wed, 3 Jul 2024 16:59:50 +0300 Subject: [PATCH] Upd: json support --- src/ArgumentsRepository.php | 10 +- src/Hydrator.php | 20 +- src/InstanceFactory.php | 2 +- .../ClassTransformerFromArrayTest.php | 161 ++++++++++- .../ClassTransformerFromJsonTest.php | 16 +- .../DTO/Full/Address/AddressClean.php | 249 ++++++++++++++++++ .../Integration/DTO/Full/Address/MetroDto.php | 14 + tests/Integration/DTO/Full/ProductDto.php | 14 + tests/Integration/DTO/Full/PurchaseDto.php | 22 ++ tests/Integration/DTO/Full/UserDto.php | 24 ++ tests/Integration/DTO/Full/UserTypeEnum.php | 12 + 11 files changed, 523 insertions(+), 21 deletions(-) create mode 100644 tests/Integration/DTO/Full/Address/AddressClean.php create mode 100644 tests/Integration/DTO/Full/Address/MetroDto.php create mode 100644 tests/Integration/DTO/Full/ProductDto.php create mode 100644 tests/Integration/DTO/Full/PurchaseDto.php create mode 100644 tests/Integration/DTO/Full/UserDto.php create mode 100644 tests/Integration/DTO/Full/UserTypeEnum.php diff --git a/src/ArgumentsRepository.php b/src/ArgumentsRepository.php index 79759f2..4404134 100644 --- a/src/ArgumentsRepository.php +++ b/src/ArgumentsRepository.php @@ -25,19 +25,15 @@ final class ArgumentsRepository /** * - * @param iterable|object|string ...$args + * @param iterable|object ...$args */ public function __construct(...$args) { // Unpacking named arguments $input = sizeof(func_get_args()) === 1 ? $args[0] : $args; - + if (!is_array($input)) { - if (is_string($input)) { - $input = json_decode($input, true); - } else { - $input = (array)$input; - } + $input = (array)$input; } $this->args = $input; diff --git a/src/Hydrator.php b/src/Hydrator.php index 9b8a553..f2235de 100644 --- a/src/Hydrator.php +++ b/src/Hydrator.php @@ -31,7 +31,7 @@ public function __construct() * Create instance T class * * @param class-string $class - * @param iterable|object|string ...$args + * @param iterable|object ...$args * * @return null|T * @throws ClassNotFoundException|InstantiableClassException|ReflectionException|InvalidArgumentException @@ -78,4 +78,22 @@ public function createMultiple(array $classes, array $args): ?array } return $result; } + + /** + * Create instance T class + * + * @param class-string $class + * @param string $json + * + * @return null|T + * @throws ClassNotFoundException + * @throws InvalidArgumentException + * @throws ReflectionException + */ + public function createFromJson(string $class, string $json): mixed + { + $data = json_decode($json, true); + + return $this->create($class, $data); + } } diff --git a/src/InstanceFactory.php b/src/InstanceFactory.php index ca4f3f7..d531548 100644 --- a/src/InstanceFactory.php +++ b/src/InstanceFactory.php @@ -26,7 +26,7 @@ final class InstanceFactory /** * @param class-string $class - * @param iterable|object|string ...$args + * @param iterable|object ...$args * * @return mixed * @throws ClassNotFoundException|InstantiableClassException|ReflectionException|InvalidArgumentException diff --git a/tests/Integration/ClassTransformerFromArrayTest.php b/tests/Integration/ClassTransformerFromArrayTest.php index cfb2d31..168ad38 100644 --- a/tests/Integration/ClassTransformerFromArrayTest.php +++ b/tests/Integration/ClassTransformerFromArrayTest.php @@ -11,6 +11,7 @@ use Tests\Integration\DTO\BasketDTO; use Tests\Integration\DTO\ProductDTO; use Tests\Integration\DTO\PurchaseDTO; +use Tests\Integration\DTO\Full\PurchaseDTO as FullPurchaseDto; use Tests\Integration\DTO\EmptyClassDto; use Tests\Integration\DTO\ArrayScalarDTO; use Tests\Integration\DTO\UserEmptyTypeDTO; @@ -204,10 +205,7 @@ public function testTripleRecursiveArray(): void } } } - - /** - * @throws ReflectionException|ClassNotFoundException - */ + public function testEmptyTypeObject(): void { $data = $this->getBaseArrayData(); @@ -219,4 +217,159 @@ public function testEmptyTypeObject(): void self::assertEquals($data['email'], $userDTO->email); self::assertEquals($data['balance'], $userDTO->balance); } + + public function testFull(): void + { + $data = $this->getPurcheseObject(); + $object = (new Hydrator)->create(FullPurchaseDto::class, $data); + $this->assertEquals($data['user']['id'], $object->user->id); + } + + public function getPurcheseObject(): array + { + return [ + 'products' => [ + [ + 'id' => 1, + 'name' => 'phone', + 'price' => 43.03, + 'description' => 'test description for phone', + 'count' => 123 + ], + [ + 'id' => 2, + 'name' => 'bread', + 'price' => 10.56, + 'description' => 'test description for bread', + 'count' => 321 + ], + [ + 'id' => 3, + 'name' => 'book', + 'price' => 5.5, + 'description' => 'test description for book', + 'count' => 333 + ], + [ + 'id' => 4, + 'name' => 'PC', + 'price' => 100, + 'description' => 'test description for PC', + 'count' => 7 + ] + ], + 'user' => [ + 'id' => 1, + 'contact' => 'fake@mail.com', + 'balance' => 10012.23, + 'type' => 'admin', + 'realAddress' => 'test address', + 'createdAt' => '2023-04-10', + ], + 'createdAt' => '2023-04-10', + 'address' => $this->getAddress() + ]; + } + + private function getAddress() + { + return [ + "source" => "мск сухонска 11/-89", + "result" => "г Москва, ул Сухонская, д 11, кв 89", + "postal_code" => "127642", + "country" => "Россия", + "country_iso_code" => "RU", + "federal_district" => "Центральный", + "region_fias_id" => "0c5b2444-70a0-4932-980c-b4dc0d3f02b5", + "region_kladr_id" => "7700000000000", + "region_iso_code" => "RU-MOW", + "region_with_type" => "г Москва", + "region_type" => "г", + "region_type_full" => "город", + "region" => "Москва", + "area_fias_id" => null, + "area_kladr_id" => null, + "area_with_type" => null, + "area_type" => null, + "area_type_full" => null, + "area" => null, + "city_fias_id" => null, + "city_kladr_id" => null, + "city_with_type" => null, + "city_type" => null, + "city_type_full" => null, + "city" => null, + "city_area" => "Северо-восточный", + "city_district_fias_id" => null, + "city_district_kladr_id" => null, + "city_district_with_type" => "р-н Северное Медведково", + "city_district_type" => "р-н", + "city_district_type_full" => "район", + "city_district" => "Северное Медведково", + "settlement_fias_id" => null, + "settlement_kladr_id" => null, + "settlement_with_type" => null, + "settlement_type" => null, + "settlement_type_full" => null, + "settlement" => null, + "street_fias_id" => "95dbf7fb-0dd4-4a04-8100-4f6c847564b5", + "street_kladr_id" => "77000000000283600", + "street_with_type" => "ул Сухонская", + "street_type" => "ул", + "street_type_full" => "улица", + "street" => "Сухонская", + "house_fias_id" => "5ee84ac0-eb9a-4b42-b814-2f5f7c27c255", + "house_kladr_id" => "7700000000028360004", + "house_type" => "д", + "house_type_full" => "дом", + "house" => "11", + "block_type" => null, + "block_type_full" => null, + "block" => null, + "flat_fias_id" => "f26b876b-6857-4951-b060-ec6559f04a9a", + "flat_type" => "кв", + "flat_type_full" => "квартира", + "flat" => "89", + "flat_area" => "34.6", + "square_meter_price" => "239953", + "flat_price" => "8302374", + "postal_box" => null, + "fias_id" => "f26b876b-6857-4951-b060-ec6559f04a9a", + "fias_code" => "77000000000000028360004", + "fias_level" => "9", + "kladr_id" => "7700000000028360004", + "capital_marker" => "0", + "okato" => "45280583000", + "oktmo" => "45362000", + "tax_office" => "7715", + "tax_office_legal" => "7715", + "timezone" => "UTC+3", + "geo_lat" => "55.8782557", + "geo_lon" => "37.65372", + "beltway_hit" => "IN_MKAD", + "beltway_distance" => null, + "qc_geo" => 0, + "qc_complete" => 0, + "qc_house" => 2, + "qc" => 0, + "unparsed_parts" => null, + "metro" => [ + [ + "distance" => 1.1, + "line" => "Калужско-Рижская", + "name" => "Бабушкинская" + ], + [ + "distance" => 1.2, + "line" => "Калужско-Рижская", + "name" => "Медведково" + ], + [ + "distance" => 2.5, + "line" => "Калужско-Рижская", + "name" => "Свиблово" + ] + ] + ]; + } } diff --git a/tests/Integration/ClassTransformerFromJsonTest.php b/tests/Integration/ClassTransformerFromJsonTest.php index eedc2e0..e555714 100644 --- a/tests/Integration/ClassTransformerFromJsonTest.php +++ b/tests/Integration/ClassTransformerFromJsonTest.php @@ -35,7 +35,7 @@ public function testBaseArray(): void { $data = $this->getBaseArrayData(); - $userDTO = (new Hydrator())->create(UserDTO::class, json_encode($data)); + $userDTO = (new Hydrator())->createFromJson(UserDTO::class, json_encode($data)); self::assertInstanceOf(UserDTO::class, $userDTO); self::assertEquals($data['id'], $userDTO->id); @@ -58,7 +58,7 @@ public function testConstructFormatArray(): void 'address_test' => 'example address', 'color' => 'White' ]; - $userDTO = (new Hydrator())->create(ConstructDto::class, json_encode($data)); + $userDTO = (new Hydrator())->createFromJson(ConstructDto::class, json_encode($data)); self::assertInstanceOf(ConstructDto::class, $userDTO); self::assertEquals($data['id'], $userDTO->id); self::assertEquals($data['email'], $userDTO->email); @@ -76,7 +76,7 @@ public function testConstructFormatArray(): void public function testEmptyClass(): void { $data = $this->getBaseArrayData(); - $instance = (new Hydrator())->create(EmptyClassDto::class, json_encode($data)); + $instance = (new Hydrator())->createFromJson(EmptyClassDto::class, json_encode($data)); self::assertInstanceOf(EmptyClassDto::class, $instance); } @@ -89,7 +89,7 @@ public function testScalarArray(): void 'stringList' => [100, 200, 300], 'intList' => [400, 500, 600] ]; - $dto = (new Hydrator())->create(ArrayScalarDTO::class, json_encode($data)); + $dto = (new Hydrator())->createFromJson(ArrayScalarDTO::class, json_encode($data)); self::assertInstanceOf(ArrayScalarDTO::class, $dto); self::assertIsString($dto->stringList[0]); self::assertEquals($dto->stringList[0], '100'); @@ -107,7 +107,7 @@ public function testNullArray(): void 'products' => null ]; - $userDTO = (new Hydrator())->create(ArrayScalarDTO::class, json_encode($data)); + $userDTO = (new Hydrator())->createFromJson(ArrayScalarDTO::class, json_encode($data)); self::assertInstanceOf(ArrayScalarDTO::class, $userDTO); } @@ -164,7 +164,7 @@ public function testTransformMultiple(): void public function testRecursiveArray(): void { $data = $this->getRecursiveArrayData(); - $purchaseDTO = (new Hydrator())->create(PurchaseDTO::class, json_encode($data)); + $purchaseDTO = (new Hydrator())->createFromJson(PurchaseDTO::class, json_encode($data)); self::assertInstanceOf(PurchaseDTO::class, $purchaseDTO); self::assertInstanceOf(UserDTO::class, $purchaseDTO->user); @@ -193,7 +193,7 @@ public function testTripleRecursiveArray(): void { $data = $this->getTripleRecursiveArray(); - $basketDTO = (new Hydrator())->create(BasketDTO::class, json_encode($data)); + $basketDTO = (new Hydrator())->createFromJson(BasketDTO::class, json_encode($data)); foreach ($basketDTO->orders as $key => $purchase) { self::assertInstanceOf(PurchaseDTO::class, $purchase); @@ -223,7 +223,7 @@ public function testEmptyTypeObject(): void { $data = $this->getBaseArrayData(); - $userDTO = (new Hydrator())->create(UserEmptyTypeDTO::class, json_encode($data)); + $userDTO = (new Hydrator())->createFromJson(UserEmptyTypeDTO::class, json_encode($data)); self::assertInstanceOf(UserEmptyTypeDTO::class, $userDTO); self::assertEquals($data['id'], $userDTO->id); diff --git a/tests/Integration/DTO/Full/Address/AddressClean.php b/tests/Integration/DTO/Full/Address/AddressClean.php new file mode 100644 index 0000000..1abc52f --- /dev/null +++ b/tests/Integration/DTO/Full/Address/AddressClean.php @@ -0,0 +1,249 @@ +|MetroDto[] */ + public ?array $metro; +} diff --git a/tests/Integration/DTO/Full/Address/MetroDto.php b/tests/Integration/DTO/Full/Address/MetroDto.php new file mode 100644 index 0000000..365d6e6 --- /dev/null +++ b/tests/Integration/DTO/Full/Address/MetroDto.php @@ -0,0 +1,14 @@ + */ + public array $products; + + /** @var UserDto $user */ + public UserDto $user; + + public AddressClean $address; + + public \DateTime $createdAt; +} diff --git a/tests/Integration/DTO/Full/UserDto.php b/tests/Integration/DTO/Full/UserDto.php new file mode 100644 index 0000000..c0eafa2 --- /dev/null +++ b/tests/Integration/DTO/Full/UserDto.php @@ -0,0 +1,24 @@ +