diff --git a/composer.json b/composer.json index 8361343..dac7419 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,8 @@ "phpunit/phpunit": "^10.0", "laravel/pint": "^1.10", "orchestra/testbench": "^8.0|^9.0", - "fab2s/math": "*" + "nesbot/carbon": "^2.62|^3.3", + "fab2s/math": "^1.0" }, "suggest": { "fab2s/laravel-dt0": "To use Dt0 in Laravel (the awesome) with full validation and attribute casting", diff --git a/src/Caster/ArrayOfTypeCaster.php b/src/Caster/ArrayOfTypeCaster.php new file mode 100644 index 0000000..10bafb0 --- /dev/null +++ b/src/Caster/ArrayOfTypeCaster.php @@ -0,0 +1,67 @@ +|ScalarType|string */ + public readonly ScalarType|string $type, + ) { + if (is_string($type)) { + $logicalType = match (true) { + is_subclass_of(Dt0::class, $type) => ArrayType::DT0, + is_subclass_of(UnitEnum::class, $type) => ArrayType::ENUM, + default => ScalarType::tryFrom($type), + }; + } else { + $logicalType = $type; + } + + if (! $logicalType) { + throw new CasterException('[' . Dt0::classBasename(static::class) . "] $type is not an ArrayType nor a ScalarType"); + } + + $this->logicalType = $logicalType; + $this->scalarTypeCaster = $this->logicalType instanceof ScalarType ? new ScalarTypeCaster($this->logicalType) : null; + } + + /** + * @throws Dt0Exception + * @throws JsonException + */ + public function cast(mixed $value): ?array + { + if (! is_array($value)) { + return null; + } + + $result = []; + foreach ($value as $item) { + $result[] = match ($this->logicalType) { + ArrayType::DT0 => $this->type->tryFrom($item), + ArrayType::ENUM => Property::tryEnum($this->type, $item), + default => $this->scalarTypeCaster->cast($item), + }; + } + + return $result; + } +} diff --git a/src/Caster/ArrayType.php b/src/Caster/ArrayType.php new file mode 100644 index 0000000..3e8b85a --- /dev/null +++ b/src/Caster/ArrayType.php @@ -0,0 +1,16 @@ +type = $type; + + } + + /** + * @param scalar $value + * + * @return string|int|float|bool|null|resource + */ + public function cast(mixed $value): mixed + { + if (! is_scalar($value)) { + return null; + } + + return match ($this->type) { + ScalarType::resource => is_resource($value) ? $value : null, + default => settype($value, $this->type?->value) ? $value : null, + }; + } +} diff --git a/src/Exception/CasterException.php b/src/Exception/CasterException.php new file mode 100644 index 0000000..e2401b0 --- /dev/null +++ b/src/Exception/CasterException.php @@ -0,0 +1,14 @@ +|null $enumFqn + * @param string|int|null $value + */ + public static function tryEnum(?string $enumFqn, UnitEnum|string|int|null $value): UnitEnum|BackedEnum|null { if (! $enumFqn) { return null; } + if (is_object($value)) { + return $value instanceof $enumFqn ? $value : null; + } + if (is_subclass_of($enumFqn, BackedEnum::class)) { return $enumFqn::tryFrom($value); } @@ -130,6 +138,9 @@ public static function tryEnum(?string $enumFqn, string|int|null $value): UnitEn return static::tryEnumFromName($enumFqn, $value); } + /** + * @param class-string $enumFqn + */ public static function tryEnumFromName(string $enumFqn, ?string $name): UnitEnum|BackedEnum|null { if ($name && is_subclass_of($enumFqn, UnitEnum::class)) {