diff --git a/docs/pages/how-to/transform-input.md b/docs/pages/how-to/transform-input.md index 40ec5539..a49c0237 100644 --- a/docs/pages/how-to/transform-input.md +++ b/docs/pages/how-to/transform-input.md @@ -1,6 +1,6 @@ # Transforming input -Any source can be given to the mapper, be it an array, some json, yaml or even a +Any source can be given to the mapper, be it an array, some JSON, YAML or even a file: ```php @@ -30,6 +30,20 @@ $mapper->map( ); ``` +!!! info + + JSON or YAML given to a source may be invalid, in which case an exception + can be caught and manipulated. + + ```php + try { + $source = \CuyZ\Valinor\Mapper\Source\Source::json('invalid JSON'); + } catch (\CuyZ\Valinor\Mapper\Source\Exception\InvalidSource $exception) { + // Let the application handle the exception in the desired way. + // It is possible to get the original source with `$exception->source()` + } + ``` + ## Modifiers Sometimes the source is not in the same format and/or organised in the same diff --git a/src/Mapper/Source/Exception/FileExtensionNotHandled.php b/src/Mapper/Source/Exception/FileExtensionNotHandled.php index 83f9fc9b..5196e369 100644 --- a/src/Mapper/Source/Exception/FileExtensionNotHandled.php +++ b/src/Mapper/Source/Exception/FileExtensionNotHandled.php @@ -4,10 +4,10 @@ namespace CuyZ\Valinor\Mapper\Source\Exception; -use RuntimeException; +use LogicException; /** @internal */ -final class FileExtensionNotHandled extends RuntimeException implements SourceException +final class FileExtensionNotHandled extends LogicException { public function __construct(string $extension) { diff --git a/src/Mapper/Source/Exception/InvalidJson.php b/src/Mapper/Source/Exception/InvalidJson.php index 90d44af2..ea6c31d5 100644 --- a/src/Mapper/Source/Exception/InvalidJson.php +++ b/src/Mapper/Source/Exception/InvalidJson.php @@ -7,13 +7,18 @@ use RuntimeException; /** @internal */ -final class InvalidJson extends RuntimeException implements SourceException +final class InvalidJson extends RuntimeException implements InvalidSource { - public function __construct() + public function __construct(private string $source) { parent::__construct( - "The given value is not a valid JSON entry.", + 'Invalid JSON source.', 1566307185 ); } + + public function source(): string + { + return $this->source; + } } diff --git a/src/Mapper/Source/Exception/InvalidSource.php b/src/Mapper/Source/Exception/InvalidSource.php new file mode 100644 index 00000000..cb180fe9 --- /dev/null +++ b/src/Mapper/Source/Exception/InvalidSource.php @@ -0,0 +1,13 @@ +source; + } } diff --git a/src/Mapper/Source/Exception/SourceException.php b/src/Mapper/Source/Exception/SourceException.php deleted file mode 100644 index cdb5d179..00000000 --- a/src/Mapper/Source/Exception/SourceException.php +++ /dev/null @@ -1,10 +0,0 @@ -source; + } } diff --git a/src/Mapper/Source/Exception/UnableToReadFile.php b/src/Mapper/Source/Exception/UnableToReadFile.php index 9ae0fc80..6ad8a0ff 100644 --- a/src/Mapper/Source/Exception/UnableToReadFile.php +++ b/src/Mapper/Source/Exception/UnableToReadFile.php @@ -4,10 +4,10 @@ namespace CuyZ\Valinor\Mapper\Source\Exception; -use RuntimeException; +use LogicException; /** @internal */ -final class UnableToReadFile extends RuntimeException implements SourceException +final class UnableToReadFile extends LogicException { public function __construct(string $filename) { diff --git a/src/Mapper/Source/Exception/YamlExtensionNotEnabled.php b/src/Mapper/Source/Exception/YamlExtensionNotEnabled.php index 142e1632..ab6330ad 100644 --- a/src/Mapper/Source/Exception/YamlExtensionNotEnabled.php +++ b/src/Mapper/Source/Exception/YamlExtensionNotEnabled.php @@ -4,7 +4,7 @@ namespace CuyZ\Valinor\Mapper\Source\Exception; -use RuntimeException; +use LogicException; /** * @internal @@ -12,7 +12,7 @@ * @codeCoverageIgnore * @infection-ignore-all */ -final class YamlExtensionNotEnabled extends RuntimeException implements SourceException +final class YamlExtensionNotEnabled extends LogicException { public function __construct() { diff --git a/src/Mapper/Source/JsonSource.php b/src/Mapper/Source/JsonSource.php index 62a4ea60..c85b9f66 100644 --- a/src/Mapper/Source/JsonSource.php +++ b/src/Mapper/Source/JsonSource.php @@ -5,6 +5,7 @@ namespace CuyZ\Valinor\Mapper\Source; use CuyZ\Valinor\Mapper\Source\Exception\InvalidJson; +use CuyZ\Valinor\Mapper\Source\Exception\InvalidSource; use CuyZ\Valinor\Mapper\Source\Exception\SourceNotIterable; use Iterator; use IteratorAggregate; @@ -23,16 +24,19 @@ final class JsonSource implements IteratorAggregate /** @var iterable */ private iterable $source; + /** + * @throws InvalidSource + */ public function __construct(string $jsonSource) { $source = json_decode($jsonSource, true); if ($source === null) { - throw new InvalidJson(); + throw new InvalidJson($jsonSource); } if (! is_iterable($source)) { - throw new SourceNotIterable($source); + throw new SourceNotIterable($jsonSource); } $this->source = $source; diff --git a/src/Mapper/Source/Source.php b/src/Mapper/Source/Source.php index 90d50180..f50bf322 100644 --- a/src/Mapper/Source/Source.php +++ b/src/Mapper/Source/Source.php @@ -4,6 +4,7 @@ namespace CuyZ\Valinor\Mapper\Source; +use CuyZ\Valinor\Mapper\Source\Exception\InvalidSource; use CuyZ\Valinor\Mapper\Source\Modifier\CamelCaseKeys; use CuyZ\Valinor\Mapper\Source\Modifier\PathMapping; use IteratorAggregate; @@ -39,11 +40,17 @@ public static function array(array $data): Source return new Source($data); } + /** + * @throws InvalidSource + */ public static function json(string $jsonSource): Source { return new Source(new JsonSource($jsonSource)); } + /** + * @throws InvalidSource + */ public static function yaml(string $yamlSource): Source { return new Source(new YamlSource($yamlSource)); diff --git a/src/Mapper/Source/YamlSource.php b/src/Mapper/Source/YamlSource.php index ae336674..2756d93a 100644 --- a/src/Mapper/Source/YamlSource.php +++ b/src/Mapper/Source/YamlSource.php @@ -4,6 +4,7 @@ namespace CuyZ\Valinor\Mapper\Source; +use CuyZ\Valinor\Mapper\Source\Exception\InvalidSource; use CuyZ\Valinor\Mapper\Source\Exception\InvalidYaml; use CuyZ\Valinor\Mapper\Source\Exception\SourceNotIterable; use CuyZ\Valinor\Mapper\Source\Exception\YamlExtensionNotEnabled; @@ -26,6 +27,9 @@ final class YamlSource implements IteratorAggregate /** @var iterable */ private iterable $source; + /** + * @throws InvalidSource + */ public function __construct(string $yamlSource) { /** @infection-ignore-all */ @@ -38,11 +42,11 @@ public function __construct(string $yamlSource) $source = @yaml_parse($yamlSource); if ($source === false) { - throw new InvalidYaml(); + throw new InvalidYaml($yamlSource); } if (! is_iterable($source)) { - throw new SourceNotIterable($source); + throw new SourceNotIterable($yamlSource); } $this->source = $source; diff --git a/tests/Unit/Mapper/Source/JsonSourceTest.php b/tests/Unit/Mapper/Source/JsonSourceTest.php index fcc8b3ba..12551ec6 100644 --- a/tests/Unit/Mapper/Source/JsonSourceTest.php +++ b/tests/Unit/Mapper/Source/JsonSourceTest.php @@ -22,19 +22,27 @@ public function test_valid_json_is_parsed_correctly(): void public function test_invalid_json_throws_exception(): void { - $this->expectException(InvalidJson::class); - $this->expectExceptionCode(1566307185); - $this->expectExceptionMessage('The given value is not a valid JSON entry.'); - - new JsonSource('@'); + try { + new JsonSource('some invalid JSON entry'); + + self::fail(); + } catch (InvalidJson $exception) { + self::assertSame(1566307185, $exception->getCode()); + self::assertSame('Invalid JSON source.', $exception->getMessage()); + self::assertSame('some invalid JSON entry', $exception->source()); + } } public function test_invalid_json_type_throws_exception(): void { - $this->expectException(SourceNotIterable::class); - $this->expectExceptionCode(1566307291); - $this->expectExceptionMessage('Invalid source true, expected an iterable.'); - - new JsonSource('true'); + try { + new JsonSource('true'); + + self::fail(); + } catch (SourceNotIterable $exception) { + self::assertSame(1566307291, $exception->getCode()); + self::assertSame('Invalid source, expected an iterable.', $exception->getMessage()); + self::assertSame('true', $exception->source()); + } } } diff --git a/tests/Unit/Mapper/Source/YamlSourceTest.php b/tests/Unit/Mapper/Source/YamlSourceTest.php index 42080eae..0b15268e 100644 --- a/tests/Unit/Mapper/Source/YamlSourceTest.php +++ b/tests/Unit/Mapper/Source/YamlSourceTest.php @@ -25,19 +25,27 @@ public function test_valid_yaml_is_parsed_correctly(): void public function test_invalid_yaml_throws_exception(): void { - $this->expectException(InvalidYaml::class); - $this->expectExceptionCode(1629990223); - $this->expectExceptionMessage('The given value is not a valid YAML entry.'); - - new YamlSource('@'); + try { + new YamlSource('@ invalid yaml'); + + self::fail(); + } catch (InvalidYaml $exception) { + self::assertSame(1629990223, $exception->getCode()); + self::assertSame('Invalid YAML source.', $exception->getMessage()); + self::assertSame('@ invalid yaml', $exception->source()); + } } public function test_invalid_yaml_type_throws_exception(): void { - $this->expectException(SourceNotIterable::class); - $this->expectExceptionCode(1566307291); - $this->expectExceptionMessage("Invalid source 'foo', expected an iterable."); - - new YamlSource('foo'); + try { + new YamlSource('foo'); + + self::fail(); + } catch (SourceNotIterable $exception) { + self::assertSame(1566307291, $exception->getCode()); + self::assertSame('Invalid source, expected an iterable.', $exception->getMessage()); + self::assertSame('foo', $exception->source()); + } } }