diff --git a/clover.xml b/clover.xml index 51124f8..05321c4 100644 --- a/clover.xml +++ b/clover.xml @@ -1,6 +1,6 @@ - - + + @@ -261,6 +261,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -300,192 +371,203 @@ - - - - - + + + + - - - - - - - - - - - + + + + + + + + + + + - - - + + + - - - - + + + + - - + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + + - + - - - - - - - - - - + + + + + + + + + + - - - + + + - - + + + + - - - - - + + + + - - - - - - - - - - - - - + + + + + + + + + + + + - - + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - + - - - - + + + + - - - - - - + + + + + + - - - - - - + + + + + - - + + - - - - + + + + + + + + + + + + + + + + + @@ -705,6 +787,16 @@ + + + + + + + + + + @@ -996,6 +1088,27 @@ + + + + + + + + + + + + + + + + + + + + + @@ -1137,13 +1250,13 @@ - - - + + + + - - + @@ -1318,6 +1431,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1346,6 +1485,21 @@ + + + + + + + + + + + + + + + @@ -1375,73 +1529,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/docs/CloneableData.md b/docs/CloneableData.md index 3f3143a..004ca7f 100644 --- a/docs/CloneableData.md +++ b/docs/CloneableData.md @@ -53,11 +53,11 @@ $todoWithDueDate = $todo->with( ); ``` -> We are using the `empty` method +> **Note:** We are using the `empty` method > from [Empty Data](https://github.com/nuxtifyts/php-dto/blob/main/docs/EmptyData.md) > here -> `emptyTodo`, `todo` and `todoWithDueDate` are all different instances. +> **Important:** `emptyTodo`, `todo` and `todoWithDueDate` are all different instances. Computed properties - diff --git a/docs/DataConfiguration.md b/docs/DataConfiguration.md new file mode 100644 index 0000000..2e73108 --- /dev/null +++ b/docs/DataConfiguration.md @@ -0,0 +1,43 @@ +Data Configuration += + +The library uses a configuration based approach to define, load and save data. +It uses a `DataConfiguration` object to define many things: + +```php +use Nuxtifyts\PhpDto\Configuration\DataConfiguration; + +$config = DataConfiguration::getInstance(); +``` + +The function's signature is: + +| Argument | Type | Description | +|-------------|---------------|-------------------------------------------------------------------------------------------------| +| config | array \| null | The configuration array to load, by default it's `null`, which means switch to default configs. | +| forceCreate | bool | If `true`, it will create a new instance of `DataConfiguration` even if it's already created. | + +If nothing is passed, it will be the equivalent of: + +```php +DataConfiguration::getInstance([ + 'normalizers' => [ + 'baseNormalizers' => [ + JsonStringNormalizer::class, + StdClassNormalizer::class, + ArrayAccessNormalizer::class, + ArrayNormalizer::class, + ], + ], + + 'serializers' => [ + 'baseSerializers' => [ + ArraySerializer::class, + DataSerializer::class, + DateTimeSerializer::class, + BackedEnumSerializer::class, + ScalarTypeSerializer::class, + ] + ] +]) +``` diff --git a/docs/DefaultValues.md b/docs/DefaultValues.md index 0ff45e9..e076321 100644 --- a/docs/DefaultValues.md +++ b/docs/DefaultValues.md @@ -70,7 +70,7 @@ class UserConfigDataFallbackResolver implements FallbackResolver } ``` ->! When using `DefaultsTo` attribute, priority is given to the attribute instead of the parameter's default value. +> When using `DefaultsTo` attribute, priority is given to the attribute instead of the parameter's default value. If ever needed to create a new instance of a DTO with complex default value, using the constructor is no longer possible, instead, you can make use of the diff --git a/docs/EmptyData.md b/docs/EmptyData.md index e83acdb..ed40dc4 100644 --- a/docs/EmptyData.md +++ b/docs/EmptyData.md @@ -36,7 +36,7 @@ By calling the `empty()` method, we can create a new instance of the `TodoData` $emptyTodo = TodoData::empty(); ``` -> This is really useful with [Cloneable Data](https://github.com/nuxtifyts/php-dto/blob/main/docs/CloneableData.md) +> **Note:** This is really useful with [Cloneable Data](https://github.com/nuxtifyts/php-dto/blob/main/docs/CloneableData.md) The `$emptyTodo` variable will contain the following data: diff --git a/docs/Normalizers.md b/docs/Normalizers.md index a08c39c..7d83418 100644 --- a/docs/Normalizers.md +++ b/docs/Normalizers.md @@ -7,10 +7,15 @@ data into (preferable) an `array`/`ArrayAccess`. By default, there are 4 normalizers: - **JsonStringNormalizer** will cast json string. -- **StrClassNormalizer** will cast stdObject. +- **StdClassNormalizer** will cast stdObject. - **ArrayAccessNormalizer** will cast ArrayAccess. - **ArrayNormalizer** will cast array. +> **Note:** In order to adjust there default normalizers, for example, you don't need +> to use the `StdClassNormalizer` and you want to simply remove it, you need +> to [configure](https://github.com/nuxtifyts/php-dto/blob/main/docs/DataConfiguration.md) +> the `DataConfiguration` object. + Custom normalizers: = diff --git a/docs/Quickstart.md b/docs/Quickstart.md index 9378613..51d25e4 100644 --- a/docs/Quickstart.md +++ b/docs/Quickstart.md @@ -81,3 +81,4 @@ can be found here: - [Data Refiners](https://github.com/nuxtifyts/php-dto/blob/main/docs/DataRefiners.md) - [Empty Data](https://github.com/nuxtifyts/php-dto/blob/main/docs/EmptyData.md) - [Cloneable Data](https://github.com/nuxtifyts/php-dto/blob/main/docs/CloneableData.md) +- [Data Configuration](https://github.com/nuxtifyts/php-dto/blob/main/docs/DataConfiguration.md) diff --git a/src/Concerns/BaseData.php b/src/Concerns/BaseData.php index 0b2ec52..f9cc34a 100644 --- a/src/Concerns/BaseData.php +++ b/src/Concerns/BaseData.php @@ -6,9 +6,9 @@ use Nuxtifyts\PhpDto\Exceptions\DataCreationException; use Nuxtifyts\PhpDto\Exceptions\DeserializeException; use Nuxtifyts\PhpDto\Exceptions\SerializeException; +use Nuxtifyts\PhpDto\Normalizers\Concerns\HasNormalizers; use Nuxtifyts\PhpDto\Pipelines\DeserializePipeline\DeserializePipeline; use Nuxtifyts\PhpDto\Pipelines\DeserializePipeline\DeserializePipelinePassable; -use Nuxtifyts\PhpDto\Support\Traits\HasNormalizers; use ReflectionClass; use Throwable; diff --git a/src/Concerns/CloneableData.php b/src/Concerns/CloneableData.php index 44fbb57..be763b7 100644 --- a/src/Concerns/CloneableData.php +++ b/src/Concerns/CloneableData.php @@ -4,7 +4,7 @@ use Nuxtifyts\PhpDto\Contexts\ClassContext; use Nuxtifyts\PhpDto\Exceptions\DataCreationException; -use Nuxtifyts\PhpDto\Support\Traits\HasNormalizers; +use Nuxtifyts\PhpDto\Normalizers\Concerns\HasNormalizers; use ReflectionClass; use Throwable; @@ -36,7 +36,7 @@ public function with(mixed ...$args): static ? $this->cloneInstanceWithConstructorCall($context, $value) : $this->cloneInstanceWithoutConstructorCall($context, $value); } catch (Throwable $t) { - throw DataCreationException::unableToCloneInstanceWithNewData($t); + throw DataCreationException::unableToCloneInstanceWithNewData(static::class, $t); } } diff --git a/src/Configuration/Configuration.php b/src/Configuration/Configuration.php new file mode 100644 index 0000000..14c511e --- /dev/null +++ b/src/Configuration/Configuration.php @@ -0,0 +1,18 @@ + $config + * + * @throws DataConfigurationException + */ + public static function getInstance( + ?array $config = null, + bool $forceCreate = false + ): self; +} diff --git a/src/Configuration/DataConfiguration.php b/src/Configuration/DataConfiguration.php new file mode 100644 index 0000000..cfc2046 --- /dev/null +++ b/src/Configuration/DataConfiguration.php @@ -0,0 +1,42 @@ + $config + * + * @throws DataConfigurationException + */ + public static function getInstance( + ?array $config = null, + bool $forceCreate = false + ): self { + if (self::$instance && !$forceCreate) { + return self::$instance; + } + + return self::$instance = new self( + normalizers: NormalizersConfiguration::getInstance( + Arr::getArray($config ?? [], 'normalizers'), + $forceCreate + ), + serializers: SerializersConfiguration::getInstance( + Arr::getArray($config ?? [], 'serializers'), + $forceCreate + ) + ); + } +} diff --git a/src/Configuration/NormalizersConfiguration.php b/src/Configuration/NormalizersConfiguration.php new file mode 100644 index 0000000..27edf61 --- /dev/null +++ b/src/Configuration/NormalizersConfiguration.php @@ -0,0 +1,57 @@ +> $baseNormalizers + */ + protected function __construct( + protected(set) array $baseNormalizers + ) { + } + + /** + * @param ?array $config + * + * @throws DataConfigurationException + */ + public static function getInstance( + ?array $config = null, + bool $forceCreate = false + ): self { + if (self::$instance && !$forceCreate) { + return self::$instance; + } + + $baseNormalizers = $config['baseNormalizers'] ?? [ + JsonStringNormalizer::class, + StdClassNormalizer::class, + ArrayAccessNormalizer::class, + ArrayNormalizer::class, + ]; + + if ( + !is_array($baseNormalizers) + || !Arr::isArrayOfClassStrings($baseNormalizers, Normalizer::class) + ) { + throw DataConfigurationException::invalidBaseNormalizers(); + } + /** @var array> $baseNormalizers */ + + return self::$instance = new self( + baseNormalizers: $baseNormalizers + ); + } +} diff --git a/src/Configuration/SerializersConfiguration.php b/src/Configuration/SerializersConfiguration.php new file mode 100644 index 0000000..647af9c --- /dev/null +++ b/src/Configuration/SerializersConfiguration.php @@ -0,0 +1,59 @@ +> $baseSerializers + */ + protected function __construct( + protected(set) array $baseSerializers, + ) { + } + + /** + * @param ?array $config + * + * @throws DataConfigurationException + */ + public static function getInstance( + ?array $config = null, + bool $forceCreate = false + ): self { + if (self::$instance && !$forceCreate) { + return self::$instance; + } + + $baseSerializers = $config['baseSerializers'] ?? [ + ArraySerializer::class, + DataSerializer::class, + DateTimeSerializer::class, + BackedEnumSerializer::class, + ScalarTypeSerializer::class, + ]; + + if ( + !is_array($baseSerializers) + || !Arr::isArrayOfClassStrings($baseSerializers, Serializer::class) + ) { + throw DataConfigurationException::invalidBaseSerializers(); + } + /** @var array> $baseSerializers */ + + return self::$instance = new self( + baseSerializers: $baseSerializers + ); + } +} diff --git a/src/Support/Traits/HasTypes.php b/src/Contexts/Concerns/HasTypes.php similarity index 94% rename from src/Support/Traits/HasTypes.php rename to src/Contexts/Concerns/HasTypes.php index 7ae90a0..3b5f8c2 100644 --- a/src/Support/Traits/HasTypes.php +++ b/src/Contexts/Concerns/HasTypes.php @@ -1,6 +1,6 @@ * * @throws UnknownTypeException + * @throws DataConfigurationException */ protected function resolveSerializers(): array { @@ -184,6 +186,7 @@ protected function resolveSerializers(): array * * @throws DeserializeException * @throws UnknownTypeException + * @throws DataConfigurationException */ public function deserializeFrom(array $value): mixed { diff --git a/src/Contexts/TypeContext.php b/src/Contexts/TypeContext.php index 4e502a1..e863afd 100644 --- a/src/Contexts/TypeContext.php +++ b/src/Contexts/TypeContext.php @@ -2,23 +2,25 @@ namespace Nuxtifyts\PhpDto\Contexts; +use BackedEnum; +use DateTime; +use DateTimeImmutable; use DateTimeInterface; +use Exception; +use Nuxtifyts\PhpDto\Contracts\BaseData as BaseDataContract; use Nuxtifyts\PhpDto\Data; use Nuxtifyts\PhpDto\Enums\Property\Type; +use Nuxtifyts\PhpDto\Exceptions\DataConfigurationException; +use Nuxtifyts\PhpDto\Exceptions\UnknownTypeException; use Nuxtifyts\PhpDto\Exceptions\UnsupportedTypeException; +use Nuxtifyts\PhpDto\Serializers\Concerns\HasSerializers; use Nuxtifyts\PhpDto\Serializers\Serializer; -use Nuxtifyts\PhpDto\Support\Traits\HasSerializers; use ReflectionClass; +use ReflectionEnum; use ReflectionNamedType; use ReflectionProperty; use ReflectionType; use ReflectionUnionType; -use ReflectionEnum; -use BackedEnum; -use Exception; -use DateTime; -use DateTimeImmutable; -use Nuxtifyts\PhpDto\Contracts\BaseData as BaseDataContract; /** * @template T of Type @@ -212,6 +214,9 @@ private static function getPropertyStringTypes(ReflectionProperty $property): ar /** * @return list + * + * @throws DataConfigurationException + * @throws UnknownTypeException */ protected function resolveSerializers(): array { diff --git a/src/Exceptions/DataConfigurationException.php b/src/Exceptions/DataConfigurationException.php new file mode 100644 index 0000000..e29841e --- /dev/null +++ b/src/Exceptions/DataConfigurationException.php @@ -0,0 +1,22 @@ + $class * * @return array|false + * + * @throws DataConfigurationException */ protected static function normalizeValue(mixed $value, string $class): array|false { @@ -30,16 +30,15 @@ protected static function normalizeValue(mixed $value, string $class): array|fal } /** - * @return non-empty-array, class-string> + * @return list> + * + * @throws DataConfigurationException */ final protected static function allNormalizer(): array { return array_values(array_unique([ ...static::normalizers(), - JsonStringNormalizer::class, - StdClassNormalizer::class, - ArrayAccessNormalizer::class, - ArrayNormalizer::class, + ...DataConfiguration::getInstance()->normalizers->baseNormalizers, ])); } diff --git a/src/Serializers/ArraySerializer.php b/src/Serializers/ArraySerializer.php index 0c9c148..21781cf 100644 --- a/src/Serializers/ArraySerializer.php +++ b/src/Serializers/ArraySerializer.php @@ -65,7 +65,6 @@ protected function deserializeItem(mixed $item, PropertyContext $property): ?arr foreach ($typeContext->subTypeSerializers() as $serializer) { try { if ($serializer instanceof SerializesArrayOfItems) { - // @phpstan-ignore-next-line return $serializer->deserializeArrayOfItems($property, $item); } } catch (Exception) { diff --git a/src/Support/Traits/HasSerializers.php b/src/Serializers/Concerns/HasSerializers.php similarity index 72% rename from src/Support/Traits/HasSerializers.php rename to src/Serializers/Concerns/HasSerializers.php index 424534d..a32cb93 100644 --- a/src/Support/Traits/HasSerializers.php +++ b/src/Serializers/Concerns/HasSerializers.php @@ -1,17 +1,14 @@ * * @throws UnknownTypeException + * @throws DataConfigurationException */ protected function getSerializersFromPropertyContext( PropertyContext $propertyContext @@ -35,7 +33,7 @@ protected function getSerializersFromPropertyContext( array_column($propertyContext->types, 'value'), array_column($serializer::supportedTypes(), 'value') )) ? new $serializer() : null, - self::serializersList() + DataConfiguration::getInstance()->serializers->baseSerializers ))) ?: throw UnknownTypeException::unknownType(...$propertyContext->types); } @@ -43,6 +41,9 @@ protected function getSerializersFromPropertyContext( * @param TypeContext $typeContext * * @return list + * + * @throws UnknownTypeException + * @throws DataConfigurationException */ protected function getSerializersFromTypeContext( TypeContext $typeContext, @@ -54,28 +55,15 @@ protected function getSerializersFromTypeContext( array_column($typeContext->arrayElementTypes, 'value'), array_column($serializer::supportedTypes(), 'value') )) ? new $serializer() : null, - self::serializersList() - ))); - } - - /** - * @return list> - */ - protected static function serializersList(): array - { - return [ - ArraySerializer::class, - DataSerializer::class, - DateTimeSerializer::class, - BackedEnumSerializer::class, - ScalarTypeSerializer::class, - ]; + DataConfiguration::getInstance()->serializers->baseSerializers + ))) ?: throw UnknownTypeException::unknownType(...$typeContext->arrayElementTypes); } /** * @return list * * @throws UnknownTypeException + * @throws DataConfigurationException */ public function serializers(): array { diff --git a/src/Serializers/Concerns/SerializesArrayOfItems.php b/src/Serializers/Concerns/SerializesArrayOfItems.php index fc936f0..cb7712d 100644 --- a/src/Serializers/Concerns/SerializesArrayOfItems.php +++ b/src/Serializers/Concerns/SerializesArrayOfItems.php @@ -13,7 +13,7 @@ trait SerializesArrayOfItems { /** - * @return array> + * @return array> * * @throws SerializeException */ @@ -38,7 +38,7 @@ public function serializeArrayOfItems( } /** - * @param array $data + * @param array $data * * @return ?array * diff --git a/src/Serializers/Contracts/SerializesArrayOfItems.php b/src/Serializers/Contracts/SerializesArrayOfItems.php index adedfe5..4909d67 100644 --- a/src/Serializers/Contracts/SerializesArrayOfItems.php +++ b/src/Serializers/Contracts/SerializesArrayOfItems.php @@ -9,7 +9,7 @@ interface SerializesArrayOfItems { /** - * @return array> + * @return array> * * @throws SerializeException */ @@ -19,7 +19,7 @@ public function serializeArrayOfItems( ): array; /** - * @param array $data + * @param array $data * * @return ?array * diff --git a/src/Support/Arr.php b/src/Support/Arr.php new file mode 100644 index 0000000..0a83032 --- /dev/null +++ b/src/Support/Arr.php @@ -0,0 +1,33 @@ + $array + * @param string $key + * @param array $default + * + * @return array + */ + public static function getArray(array $array, string $key, array $default = []): array + { + $value = $array[$key] ?? null; + + return is_array($value) ? $value : $default; + } + + /** + * @param array $array + * @param class-string $classString + */ + public static function isArrayOfClassStrings(array $array, string $classString): bool + { + return array_all( + $array, + static fn (mixed $value): bool => is_string($value) + && is_subclass_of($value, $classString) + ); + } +} diff --git a/tests/Dummies/Serializers/HasSerializersDummyClass.php b/tests/Dummies/Serializers/HasSerializersDummyClass.php index 2b7660f..b07e72b 100644 --- a/tests/Dummies/Serializers/HasSerializersDummyClass.php +++ b/tests/Dummies/Serializers/HasSerializersDummyClass.php @@ -2,11 +2,13 @@ namespace Nuxtifyts\PhpDto\Tests\Dummies\Serializers; +use Nuxtifyts\PhpDto\Configuration\DataConfiguration; use Nuxtifyts\PhpDto\Contexts\PropertyContext; +use Nuxtifyts\PhpDto\Exceptions\DataConfigurationException; use Nuxtifyts\PhpDto\Exceptions\UnknownTypeException; +use Nuxtifyts\PhpDto\Serializers\Concerns\HasSerializers; use Nuxtifyts\PhpDto\Serializers\DateTimeSerializer; use Nuxtifyts\PhpDto\Serializers\Serializer; -use Nuxtifyts\PhpDto\Support\Traits\HasSerializers; class HasSerializersDummyClass { @@ -14,11 +16,18 @@ class HasSerializersDummyClass /** * @throws UnknownTypeException + * @throws DataConfigurationException * * @return list */ public static function testGetSerializersFromPropertyContext(PropertyContext $propertyContext): array { + DataConfiguration::getInstance([ + 'serializers' => [ + 'baseSerializers' => self::serializersList() + ], + ], true); + return new self()->getSerializersFromPropertyContext($propertyContext); } diff --git a/tests/Dummies/Support/DoesNotHaveAdditionalNormalizersDummy.php b/tests/Dummies/Support/DoesNotHaveAdditionalNormalizersDummy.php index ed0fdc9..052972c 100644 --- a/tests/Dummies/Support/DoesNotHaveAdditionalNormalizersDummy.php +++ b/tests/Dummies/Support/DoesNotHaveAdditionalNormalizersDummy.php @@ -2,8 +2,8 @@ namespace Nuxtifyts\PhpDto\Tests\Dummies\Support; +use Nuxtifyts\PhpDto\Normalizers\Concerns\HasNormalizers; use Nuxtifyts\PhpDto\Normalizers\Normalizer; -use Nuxtifyts\PhpDto\Support\Traits\HasNormalizers; final class DoesNotHaveAdditionalNormalizersDummy { diff --git a/tests/Dummies/Support/HasNormalizersDummy.php b/tests/Dummies/Support/HasNormalizersDummy.php index 8b2b284..906b5c3 100644 --- a/tests/Dummies/Support/HasNormalizersDummy.php +++ b/tests/Dummies/Support/HasNormalizersDummy.php @@ -3,8 +3,9 @@ namespace Nuxtifyts\PhpDto\Tests\Dummies\Support; use Nuxtifyts\PhpDto\Data; +use Nuxtifyts\PhpDto\Exceptions\DataConfigurationException; +use Nuxtifyts\PhpDto\Normalizers\Concerns\HasNormalizers; use Nuxtifyts\PhpDto\Normalizers\Normalizer; -use Nuxtifyts\PhpDto\Support\Traits\HasNormalizers; use Nuxtifyts\PhpDto\Tests\Dummies\Normalizers\DummyNormalizer; final class HasNormalizersDummy @@ -15,6 +16,8 @@ final class HasNormalizersDummy * @param class-string $class * * @return array|false + * + * @throws DataConfigurationException */ public static function testNormalizeValue(mixed $value, string $class): array|false { @@ -22,7 +25,9 @@ public static function testNormalizeValue(mixed $value, string $class): array|fa } /** - * @return non-empty-array, class-string> + * @return list> + * + * @throws DataConfigurationException */ public static function getAllNormalizer(): array { diff --git a/tests/Unit/Contexts/PropertyContextTest.php b/tests/Unit/Contexts/PropertyContextTest.php index 4859d9d..4d2c517 100644 --- a/tests/Unit/Contexts/PropertyContextTest.php +++ b/tests/Unit/Contexts/PropertyContextTest.php @@ -119,8 +119,13 @@ public function __construct( $reflectionProperty = new ReflectionProperty($object::class, 'value'); $propertyContext = PropertyContext::getInstance($reflectionProperty); - self::expectException(UnknownTypeException::class); - HasSerializersDummyClass::testGetSerializersFromPropertyContext($propertyContext); + try { + HasSerializersDummyClass::testGetSerializersFromPropertyContext($propertyContext); + } catch (Throwable $t) { + self::assertInstanceOf(UnknownTypeException::class, $t); + } + + self::resetConfig(); } /** diff --git a/tests/Unit/DataConfigurationTest.php b/tests/Unit/DataConfigurationTest.php new file mode 100644 index 0000000..9be82eb --- /dev/null +++ b/tests/Unit/DataConfigurationTest.php @@ -0,0 +1,101 @@ +normalizers, $normalizersConfig); + + $serializersConfig = SerializersConfiguration::getInstance(); + self::assertSame($config->serializers, $serializersConfig); + + $sameConfig = DataConfiguration::getInstance(); + self::assertSame($config, $sameConfig); + + $newConfig = DataConfiguration::getInstance(forceCreate: true); + self::assertNotSame($config, $newConfig); + + self::resetConfig(); + } + + /** + * @throws Throwable + */ + #[Test] + public function can_override_default_configuration(): void + { + $config = DataConfiguration::getInstance(); + + $baseNormalizers = $config->normalizers->baseNormalizers; + + $config = DataConfiguration::getInstance([ + 'normalizers' => [ + 'baseNormalizers' => [ + ArrayNormalizer::class, + ], + ], + ], forceCreate: true); + + self::assertNotEquals($baseNormalizers, $config->normalizers->baseNormalizers); + self::assertEquals([ArrayNormalizer::class], $config->normalizers->baseNormalizers); + + self::resetConfig(); + } + + /** + * @throws Throwable + */ + #[Test] + public function will_throw_an_exception_if_invalid_normalizers_are_provided(): void + { + self::expectException(DataConfigurationException::class); + + DataConfiguration::getInstance([ + 'normalizers' => [ + 'baseNormalizers' => [ + 'invalidNormalizer', + ], + ], + ], forceCreate: true); + } + + /** + * @throws Throwable + */ + #[Test] + public function will_throw_an_exception_if_invalid_serializers_are_provided(): void + { + self::expectException(DataConfigurationException::class); + + DataConfiguration::getInstance([ + 'serializers' => [ + 'baseSerializers' => [ + 'invalidSerializer', + ], + ], + ], forceCreate: true); + } +} diff --git a/tests/Unit/Support/Traits/HasNormalizersTest.php b/tests/Unit/Normalizers/HasNormalizersTest.php similarity index 97% rename from tests/Unit/Support/Traits/HasNormalizersTest.php rename to tests/Unit/Normalizers/HasNormalizersTest.php index cb1f90d..d9579a4 100644 --- a/tests/Unit/Support/Traits/HasNormalizersTest.php +++ b/tests/Unit/Normalizers/HasNormalizersTest.php @@ -1,20 +1,20 @@ $parameters + */ + #[Test] + #[DataProvider('get_arr_provider')] + #[DataProvider('is_array_of_class_strings_provider')] + public function arr_helper_functions( + string $functionName, + array $parameters, + mixed $expected + ): void { + self::assertTrue(method_exists(Arr::class, $functionName)); + self::assertEquals( + $expected, + Arr::{$functionName}(...$parameters) + ); + } + + /** + * @return array + */ + public static function get_arr_provider(): array + { + return [ + 'get array existing key, invalid value' => [ + 'getArray', + [ + 'array' => ['key' => 'value'], + 'key' => 'key', + ], + [], + ], + 'get array existing key, valid value' => [ + 'getArray', + [ + 'array' => ['key' => ['value']], + 'key' => 'key', + ], + ['value'], + ], + 'get array non-existing key' => [ + 'getArray', + [ + 'array' => ['key' => 'value'], + 'key' => 'nonExistingKey', + ], + [], + ], + ]; + } + + /** + * @return array + */ + public static function is_array_of_class_strings_provider(): array + { + return [ + 'is array of class strings, valid' => [ + 'isArrayOfClassStrings', + [ + 'array' => [ + ScalarTypeSerializer::class, + BackedEnumSerializer::class, + ], + 'classString' => Serializer::class, + ], + true, + ], + 'is array of class strings, invalid' => [ + 'isArrayOfClassStrings', + [ + 'array' => [ + ScalarTypeSerializer::class, + BackedEnumSerializer::class, + 'invalid', + ], + 'classString' => Serializer::class, + ], + false, + ], + ]; + } +} diff --git a/tests/Unit/UnitCase.php b/tests/Unit/UnitCase.php index 2a59986..46d6949 100644 --- a/tests/Unit/UnitCase.php +++ b/tests/Unit/UnitCase.php @@ -2,8 +2,17 @@ namespace Nuxtifyts\PhpDto\Tests\Unit; +use Nuxtifyts\PhpDto\Configuration\DataConfiguration; +use Nuxtifyts\PhpDto\Exceptions\DataConfigurationException; use PHPUnit\Framework\TestCase; abstract class UnitCase extends Testcase { + /** + * @throws DataConfigurationException + */ + protected static function resetConfig(): void + { + DataConfiguration::getInstance(forceCreate: true); + } }