Skip to content

Commit

Permalink
improve
Browse files Browse the repository at this point in the history
  • Loading branch information
vjik committed Feb 8, 2024
1 parent da206bf commit df578eb
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 15 deletions.
6 changes: 3 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Yii Hydrator Change Log

## 1.0.1 under development
## 1.1.0 under development

- no changes in this release.
- New #74: Add option `castEmptyStringToNull` to `PhpNativeTypeCaster` (@vjik)

## 1.0.0 January 29, 2024

- Initial release.
- Initial release.
22 changes: 13 additions & 9 deletions src/TypeCaster/PhpNativeTypeCaster.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@
*/
final class PhpNativeTypeCaster implements TypeCasterInterface
{
public function __construct(
public bool $castEmptyStringToNull = false,
) {
}

public function cast(mixed $value, TypeCastContext $context): Result
{
$type = $context->getReflectionType();
Expand All @@ -49,8 +54,12 @@ public function cast(mixed $value, TypeCastContext $context): Result
* - when pass `"42"` to `int|string` type, `string` will be used.
*/
foreach ($types as $t) {
if ($value === null && $t->allowsNull()) {
return Result::success(null);
if ($t->allowsNull()) {
if ($value === null
|| ($this->castEmptyStringToNull && $value === '')
) {
return Result::success(null);
}
}
if (!$t->isBuiltin()) {
continue;
Expand Down Expand Up @@ -108,8 +117,7 @@ public function cast(mixed $value, TypeCastContext $context): Result
return Result::success((int) $value);
}
if ($value instanceof Stringable || is_string($value)) {
$value = NumericHelper::normalize($value);
return Result::success($t->allowsNull() && $value === '' ? null : (int) $value);
return Result::success((int) NumericHelper::normalize($value));
}
break;

Expand All @@ -118,15 +126,11 @@ public function cast(mixed $value, TypeCastContext $context): Result
return Result::success((float) $value);
}
if ($value instanceof Stringable || is_string($value)) {
$value = NumericHelper::normalize($value);
return Result::success($t->allowsNull() && $value === '' ? null : (float) $value);
return Result::success((float) NumericHelper::normalize($value));
}
break;

case 'bool':
if ($t->allowsNull() && $value === '') {
return Result::success(null);
}
if (is_scalar($value) || $value === null || is_array($value) || is_object($value)) {
return Result::success((bool) $value);
}
Expand Down
57 changes: 54 additions & 3 deletions tests/TypeCaster/PhpNativeTypeCasterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public function dataBase(): array
static fn(float $a) => null,
],
'empty string to int|null' => [
Result::success(null),
Result::success(0),
'',
static fn(?int $a) => null,
],
Expand All @@ -36,15 +36,20 @@ public function dataBase(): array
static fn(?string $a) => null,
],
'empty string to float|null' => [
Result::success(null),
Result::success(0.0),
'',
static fn(?float $a) => null,
],
'empty string to bool|null' => [
Result::success(null),
Result::success(false),
'',
static fn(?bool $a) => null,
],
'empty string to array|null' => [
Result::fail(),
'',
static fn(?array $a) => null,
],
];
}

Expand All @@ -61,4 +66,50 @@ public function testBase(Result $expected, mixed $value, Closure $closure): void
$this->assertSame($expected->isResolved(), $result->isResolved());
$this->assertSame($expected->getValue(), $result->getValue());
}

public function dataWithCastEmptyStringToNull(): array
{

return [
'empty string to int|null' => [
Result::success(null),
'',
static fn(?int $a) => null,
],
'empty string to string|null' => [
Result::success(null),
'',
static fn(?string $a) => null,
],
'empty string to float|null' => [
Result::success(null),
'',
static fn(?float $a) => null,
],
'empty string to bool|null' => [
Result::success(null),
'',
static fn(?bool $a) => null,
],
'empty string to array|null' => [
Result::success(null),
'',
static fn(?array $a) => null,
],
];
}

/**
* @dataProvider dataWithCastEmptyStringToNull
*/
public function testWithCastEmptyStringToNull(Result $expected, mixed $value, Closure $closure): void
{
$typeCaster = new PhpNativeTypeCaster(castEmptyStringToNull: true);
$context = TestHelper::createTypeCastContext($closure);

$result = $typeCaster->cast($value, $context);

$this->assertSame($expected->isResolved(), $result->isResolved());
$this->assertSame($expected->getValue(), $result->getValue());
}
}

0 comments on commit df578eb

Please sign in to comment.