Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
fab2s committed Apr 23, 2024
1 parent 067bc81 commit a36d2a2
Show file tree
Hide file tree
Showing 8 changed files with 182 additions and 3 deletions.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
67 changes: 67 additions & 0 deletions src/Caster/ArrayOfTypeCaster.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

/*
* This file is part of fab2s/dt0.
* (c) Fabrice de Stefanis / https://github.com/fab2s/dt0
* This source file is licensed under the MIT license which you will
* find in the LICENSE file or at https://opensource.org/licenses/MIT
*/

namespace fab2s\Dt0\Caster;

use fab2s\Dt0\Dt0;
use fab2s\Dt0\Exception\CasterException;
use fab2s\Dt0\Exception\Dt0Exception;
use fab2s\Dt0\Property\Property;
use JsonException;
use UnitEnum;

class ArrayOfTypeCaster implements CasterInterface
{
public readonly ArrayType|ScalarType|string $logicalType;
private ?ScalarTypeCaster $scalarTypeCaster;

public function __construct(
/** @var class-string<Dt0|UnitEnum>|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;
}
}
16 changes: 16 additions & 0 deletions src/Caster/ArrayType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

/*
* This file is part of fab2s/dt0.
* (c) Fabrice de Stefanis / https://github.com/fab2s/dt0
* This source file is licensed under the MIT license which you will
* find in the LICENSE file or at https://opensource.org/licenses/MIT
*/

namespace fab2s\Dt0\Caster;

enum ArrayType: string
{
case ENUM = 'enum';
case DT0 = 'dt0';
}
23 changes: 23 additions & 0 deletions src/Caster/ScalarType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

/*
* This file is part of fab2s/dt0.
* (c) Fabrice de Stefanis / https://github.com/fab2s/dt0
* This source file is licensed under the MIT license which you will
* find in the LICENSE file or at https://opensource.org/licenses/MIT
*/

namespace fab2s\Dt0\Caster;

enum ScalarType: string
{
case boolean = 'boolean';
case bool = 'bool';
case integer = 'integer';
case int = 'int';
case float = 'float';
case double = 'double';
case string = 'string';
case null = 'null';
case resource = 'resource';
}
46 changes: 46 additions & 0 deletions src/Caster/ScalarTypeCaster.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

/*
* This file is part of fab2s/dt0.
* (c) Fabrice de Stefanis / https://github.com/fab2s/dt0
* This source file is licensed under the MIT license which you will
* find in the LICENSE file or at https://opensource.org/licenses/MIT
*/

namespace fab2s\Dt0\Caster;

use fab2s\Dt0\Dt0;
use fab2s\Dt0\Exception\CasterException;

class ScalarTypeCaster implements CasterInterface
{
public readonly ?ScalarType $type;

public function __construct(
ScalarType|string $type,
) {
if (is_string($type) && ! ($type = ScalarType::tryFrom($type))) {
throw new CasterException('[' . Dt0::classBasename(static::class) . "] $type is not ScalarType");
}

$this->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,
};
}
}
14 changes: 14 additions & 0 deletions src/Exception/CasterException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

/*
* This file is part of fab2s/dt0.
* (c) Fabrice de Stefanis / https://github.com/fab2s/dt0
* This source file is licensed under the MIT license which you will
* find in the LICENSE file or at https://opensource.org/licenses/MIT
*/

namespace fab2s\Dt0\Exception;

class CasterException extends Dt0Exception
{
}
3 changes: 2 additions & 1 deletion src/Exception/Dt0Exception.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ public function __construct(string $message = '', int $code = 0, ?Throwable $pre
'',
Dt0::classBasename(static::class),
),
'] ',
']',
str_starts_with($message, '[') ? '' : ' ',
$message,
],
);
Expand Down
13 changes: 12 additions & 1 deletion src/Property/Property.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,19 +117,30 @@ public function cast(mixed $value): mixed
return $value;
}

public static function tryEnum(?string $enumFqn, string|int|null $value): UnitEnum|BackedEnum|null
/**
* @param class-string<UnitEnum|BackedEnum>|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);
}

return static::tryEnumFromName($enumFqn, $value);
}

/**
* @param class-string<UnitEnum|BackedEnum> $enumFqn
*/
public static function tryEnumFromName(string $enumFqn, ?string $name): UnitEnum|BackedEnum|null
{
if ($name && is_subclass_of($enumFqn, UnitEnum::class)) {
Expand Down

0 comments on commit a36d2a2

Please sign in to comment.