diff --git a/src/Serialization/AlwaysThrowExceptionOnFailure.php b/src/Serialization/AlwaysThrowExceptionOnFailure.php index f8973dd..66c8891 100644 --- a/src/Serialization/AlwaysThrowExceptionOnFailure.php +++ b/src/Serialization/AlwaysThrowExceptionOnFailure.php @@ -3,16 +3,13 @@ namespace Star\Component\DomainEvent\Serialization; use Assert\Assertion; +use DateTimeImmutable; +use DateTimeInterface; use function json_encode; use function sprintf; final class AlwaysThrowExceptionOnFailure implements PayloadFailureStrategy { - /** - * @param string $key - * @param SerializableAttribute[]|string[]|int[]|bool[]|float[] $payload - * @return SerializableAttribute|bool|float|int|string - */ public function handleKeyNotFound(string $key, array $payload) { throw new PayloadKeyNotFound( @@ -24,19 +21,42 @@ public function handleKeyNotFound(string $key, array $payload) ); } + public function handleInvalidStringValue(string $key, $value): string + { + throw UnexpectedTypeForPayloadKey::unexpectedValueForKey($key, $value, 'string'); + } + + public function handleInvalidIntegerValue(string $key, $value): int + { + throw UnexpectedTypeForPayloadKey::unexpectedValueForKey($key, $value, 'integer'); + } + + public function handleInvalidFloatValue(string $key, $value): float + { + throw UnexpectedTypeForPayloadKey::unexpectedValueForKey($key, $value, 'float'); + } + + public function handleInvalidBooleanValue(string $key, $value): bool + { + throw UnexpectedTypeForPayloadKey::unexpectedValueForKey($key, $value, 'boolean'); + } + + public function handleInvalidDateTimeValue(string $key, $value): DateTimeInterface + { + throw UnexpectedTypeForPayloadKey::unexpectedValueForKey($key, $value, 'datetime'); + } + /** * @param string $value - * @return string */ public function transformRawValueToString($value): string { Assertion::string($value); - return $value; + return (string) $value; } /** - * @param int $value - * @return int + * @param float|int|string $value */ public function transformRawValueToInt($value): int { @@ -45,8 +65,7 @@ public function transformRawValueToInt($value): int } /** - * @param float $value - * @return float + * @param int|float|string $value */ public function transformRawValueToFloat($value): float { @@ -55,8 +74,7 @@ public function transformRawValueToFloat($value): float } /** - * @param bool $value - * @return bool + * @param string|int|bool $value */ public function transformRawValueToBoolean($value): bool { @@ -65,42 +83,11 @@ public function transformRawValueToBoolean($value): bool } /** - * @param string $key * @param string $value - * @return string */ - public function handleInvalidStringValue(string $key, $value): string - { - throw UnexpectedTypeForPayloadKey::unexpectedValueForKey($key, $value, 'string'); - } - - /** - * @param string $key - * @param int $value - * @return int - */ - public function handleInvalidIntegerValue(string $key, $value): int - { - throw UnexpectedTypeForPayloadKey::unexpectedValueForKey($key, $value, 'integer'); - } - - /** - * @param string $key - * @param float $value - * @return float - */ - public function handleInvalidFloatValue(string $key, $value): float - { - throw UnexpectedTypeForPayloadKey::unexpectedValueForKey($key, $value, 'float'); - } - - /** - * @param string $key - * @param bool $value - * @return bool - */ - public function handleInvalidBooleanValue(string $key, $value): bool + public function transformRawValueToDateTime($value): DateTimeInterface { - throw UnexpectedTypeForPayloadKey::unexpectedValueForKey($key, $value, 'boolean'); + Assertion::string($value); + return new DateTimeImmutable($value); } } diff --git a/src/Serialization/Payload.php b/src/Serialization/Payload.php index 98f5e43..ddb2f36 100644 --- a/src/Serialization/Payload.php +++ b/src/Serialization/Payload.php @@ -2,10 +2,12 @@ namespace Star\Component\DomainEvent\Serialization; +use DateTimeInterface; use function array_key_exists; use function in_array; use function is_numeric; use function is_string; +use function json_decode; final class Payload { @@ -66,6 +68,17 @@ public function getBoolean(string $key, PayloadFailureStrategy $strategy = null) return $strategy->transformRawValueToBoolean($value); } + public function getDateTime(string $key, PayloadFailureStrategy $strategy = null): DateTimeInterface + { + $strategy = $this->assertStrategy($strategy); + $value = $this->getValue($key, $strategy); + if (!is_string($value)) { + return $strategy->handleInvalidDateTimeValue($key, $value); + } + + return $strategy->transformRawValueToDateTime($value); + } + private function assertStrategy(PayloadFailureStrategy $strategy = null): PayloadFailureStrategy { if (!$strategy) { @@ -97,4 +110,14 @@ public static function fromArray(array $payload): self { return new self($payload); } + + public static function fromJson(string $json): self + { + /** + * @var string[]|int[]|bool[]|float[] $payload + */ + $payload = json_decode($json, true); + + return self::fromArray($payload); + } } diff --git a/src/Serialization/PayloadFailureStrategy.php b/src/Serialization/PayloadFailureStrategy.php index ef03c20..893b872 100644 --- a/src/Serialization/PayloadFailureStrategy.php +++ b/src/Serialization/PayloadFailureStrategy.php @@ -2,12 +2,15 @@ namespace Star\Component\DomainEvent\Serialization; +use DateTimeInterface; + interface PayloadFailureStrategy { /** * @param string $key * @param SerializableAttribute[]|string[]|int[]|bool[]|float[] $payload * @return SerializableAttribute|bool|float|int|string + * @throws PayloadKeyNotFound */ public function handleKeyNotFound(string $key, array $payload); @@ -15,6 +18,7 @@ public function handleKeyNotFound(string $key, array $payload); * @param string $key * @param mixed $value * @return string + * @throws UnexpectedTypeForPayloadKey */ public function handleInvalidStringValue(string $key, $value): string; @@ -22,6 +26,7 @@ public function handleInvalidStringValue(string $key, $value): string; * @param string $key * @param mixed $value * @return int + * @throws UnexpectedTypeForPayloadKey */ public function handleInvalidIntegerValue(string $key, $value): int; @@ -29,6 +34,7 @@ public function handleInvalidIntegerValue(string $key, $value): int; * @param string $key * @param mixed $value * @return float + * @throws UnexpectedTypeForPayloadKey */ public function handleInvalidFloatValue(string $key, $value): float; @@ -36,9 +42,18 @@ public function handleInvalidFloatValue(string $key, $value): float; * @param string $key * @param mixed $value * @return bool + * @throws UnexpectedTypeForPayloadKey */ public function handleInvalidBooleanValue(string $key, $value): bool; + /** + * @param string $key + * @param mixed $value + * @return DateTimeInterface + * @throws UnexpectedTypeForPayloadKey + */ + public function handleInvalidDateTimeValue(string $key, $value): DateTimeInterface; + /** * @param mixed $value * @return string @@ -62,4 +77,10 @@ public function transformRawValueToFloat($value): float; * @return bool */ public function transformRawValueToBoolean($value): bool; + + /** + * @param mixed $value + * @return DateTimeInterface + */ + public function transformRawValueToDateTime($value): DateTimeInterface; } diff --git a/src/Serialization/ReturnDefaultValueOnFailure.php b/src/Serialization/ReturnDefaultValueOnFailure.php index 06ed271..2c74c9e 100644 --- a/src/Serialization/ReturnDefaultValueOnFailure.php +++ b/src/Serialization/ReturnDefaultValueOnFailure.php @@ -3,6 +3,9 @@ namespace Star\Component\DomainEvent\Serialization; use Assert\Assertion; +use DateTimeImmutable; +use DateTimeInterface; +use RuntimeException; final class ReturnDefaultValueOnFailure implements PayloadFailureStrategy { @@ -19,19 +22,38 @@ public function __construct($value) $this->value = $value; } - /** - * @param string $key - * @param SerializableAttribute[]|string[]|int[]|bool[]|float[] $payload - * @return SerializableAttribute|bool|float|int|string - */ public function handleKeyNotFound(string $key, array $payload) { return $this->value; } + public function handleInvalidStringValue(string $key, $value): string + { + throw new RuntimeException(__METHOD__ . ' not implemented yet.'); + } + + public function handleInvalidIntegerValue(string $key, $value): int + { + throw new RuntimeException(__METHOD__ . ' not implemented yet.'); + } + + public function handleInvalidFloatValue(string $key, $value): float + { + throw new RuntimeException(__METHOD__ . ' not implemented yet.'); + } + + public function handleInvalidBooleanValue(string $key, $value): bool + { + throw new RuntimeException(__METHOD__ . ' not implemented yet.'); + } + + public function handleInvalidDateTimeValue(string $key, $value): DateTimeInterface + { + throw new RuntimeException(__METHOD__ . ' not implemented yet.'); + } + /** * @param string $value - * @return string */ public function transformRawValueToString($value): string { @@ -41,8 +63,7 @@ public function transformRawValueToString($value): string } /** - * @param int $value - * @return int + * @param int|float|string $value */ public function transformRawValueToInt($value): int { @@ -52,8 +73,7 @@ public function transformRawValueToInt($value): int } /** - * @param float $value - * @return float + * @param int|float|string $value */ public function transformRawValueToFloat($value): float { @@ -63,8 +83,7 @@ public function transformRawValueToFloat($value): float } /** - * @param mixed $value - * @return bool + * @param int|float|string|bool $value */ public function transformRawValueToBoolean($value): bool { @@ -74,42 +93,12 @@ public function transformRawValueToBoolean($value): bool } /** - * @param string $key * @param string $value - * @return string - */ - public function handleInvalidStringValue(string $key, $value): string - { - throw new \RuntimeException(__METHOD__ . ' not implemented yet.'); - } - - /** - * @param string $key - * @param int $value - * @return int - */ - public function handleInvalidIntegerValue(string $key, $value): int - { - throw new \RuntimeException(__METHOD__ . ' not implemented yet.'); - } - - /** - * @param string $key - * @param float $value - * @return float */ - public function handleInvalidFloatValue(string $key, $value): float + public function transformRawValueToDateTime($value): DateTimeInterface { - throw new \RuntimeException(__METHOD__ . ' not implemented yet.'); - } + Assertion::string($value); - /** - * @param string $key - * @param bool $value - * @return bool - */ - public function handleInvalidBooleanValue(string $key, $value): bool - { - throw new \RuntimeException(__METHOD__ . ' not implemented yet.'); + return new DateTimeImmutable($value); } } diff --git a/tests/Serialization/PayloadTest.php b/tests/Serialization/PayloadTest.php index 27813ff..8bf3de3 100644 --- a/tests/Serialization/PayloadTest.php +++ b/tests/Serialization/PayloadTest.php @@ -115,4 +115,22 @@ public function test_it_should_use_specified_strategy_when_expected_bool_value_i $this->expectExceptionMessage('Value "string" for key "key" is not of expected type "boolean", got "string".'); Payload::fromArray(['key' => 'string'])->getBoolean('key'); } + + public function test_it_should_create_payload_from_json(): void + { + $payload = Payload::fromJson('{"string":"value","int":123,"float":12.34,"bool":true}'); + self::assertSame('value', $payload->getString('string')); + self::assertSame(123, $payload->getInteger('int')); + self::assertSame(12.34, $payload->getFloat('float')); + self::assertTrue($payload->getBoolean('bool')); + } + + public function test_it_should_allow_date_time(): void + { + $payload = Payload::fromArray(['date' => '2000-01-01 12:34:56']); + self::assertSame( + '2000-01-01 12:34:56', + $payload->getDateTime('date')->format('Y-m-d H:i:s') + ); + } }