From 28cc281cd2c1396c1d4fb8f9821d387267bd6ced Mon Sep 17 00:00:00 2001 From: ignace nyamagana butera Date: Mon, 30 Oct 2023 20:29:57 +0100 Subject: [PATCH] #508 Adding Specific exceptions --- src/ColumnMappingFailed.php | 20 ++++++++++++++++++++ src/Mapper.php | 6 +++--- src/RecordMapper.php | 10 +++++----- src/RecordMapperTest.php | 7 +++---- src/TypeCasting/CastToDate.php | 10 +++++----- src/TypeCasting/CastToDateTest.php | 3 +-- src/TypeCasting/CastToEnum.php | 7 +++---- src/TypeCasting/CastToEnumTest.php | 5 ++--- src/TypeCasting/CastToScalar.php | 14 ++++++-------- src/TypeCasting/CastToScalarTest.php | 3 +-- src/TypeCasting/TypeCasting.php | 4 +--- src/TypeCasting/TypeCastingFailed.php | 20 ++++++++++++++++++++ 12 files changed, 70 insertions(+), 39 deletions(-) create mode 100644 src/ColumnMappingFailed.php create mode 100644 src/TypeCasting/TypeCastingFailed.php diff --git a/src/ColumnMappingFailed.php b/src/ColumnMappingFailed.php new file mode 100644 index 00000000..6f0753e7 --- /dev/null +++ b/src/ColumnMappingFailed.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace League\Csv; + +use RuntimeException; + +final class ColumnMappingFailed extends RuntimeException +{ +} diff --git a/src/Mapper.php b/src/Mapper.php index ff395942..d2b787bb 100644 --- a/src/Mapper.php +++ b/src/Mapper.php @@ -15,8 +15,8 @@ use ArrayIterator; use Iterator; +use League\Csv\TypeCasting\TypeCastingFailed; use ReflectionException; -use RuntimeException; class Mapper { @@ -28,7 +28,7 @@ public function __construct(private readonly string $className) } /** - * @throws RuntimeException + * @throws TypeCastingFailed * @throws ReflectionException */ public function map(TabularDataReader $tabularDataReader): Iterator @@ -37,7 +37,7 @@ public function map(TabularDataReader $tabularDataReader): Iterator } /** - * @throws RuntimeException + * @throws TypeCastingFailed * @throws ReflectionException */ public function __invoke(iterable $records, array $header): Iterator diff --git a/src/RecordMapper.php b/src/RecordMapper.php index 3eb2ad2c..7143e242 100644 --- a/src/RecordMapper.php +++ b/src/RecordMapper.php @@ -74,7 +74,7 @@ public function __invoke(array $record): mixed /** * @param array $header * - * @throws RuntimeException + * @throws ColumnMappingFailed * * @return array{0:int<0, max>|null, 1:TypeCasting} */ @@ -86,7 +86,7 @@ private function getColumn(ReflectionProperty|ReflectionMethod $target, array $h } if (1 < count($attributes)) { - throw new RuntimeException('Using multiple '.Column::class.' attributes on '.$target->getDeclaringClass()->getName().'::'.$target->getName().' is not supported.'); + throw new ColumnMappingFailed('Using multiple '.Column::class.' attributes on '.$target->getDeclaringClass()->getName().'::'.$target->getName().' is not supported.'); } /** @var Column $column */ @@ -95,19 +95,19 @@ private function getColumn(ReflectionProperty|ReflectionMethod $target, array $h $cast = $this->getCast($column); if (is_int($offset)) { return match (true) { - 0 > $offset => throw new RuntimeException(__CLASS__.' can only use 0 or positive column indices.'), + 0 > $offset => throw new ColumnMappingFailed(__CLASS__.' can only use 0 or positive indices to position the column.'), default => [$offset, $cast], }; } if ([] === $header) { - throw new RuntimeException(__CLASS__.' can only use named column if the tabular data has a non-empty header.'); + throw new ColumnMappingFailed(__CLASS__.' can only use named column if the tabular data has a non-empty header.'); } /** @var int<0, max>|false $index */ $index = array_search($offset, $header, true); if (false === $index) { - throw new RuntimeException(__CLASS__.' cound not find the offset `'.$offset.'` in the header; Pleaser verify your header data.'); + throw new ColumnMappingFailed(__CLASS__.' cound not find the offset `'.$offset.'` in the header; Pleaser verify your header data.'); } return [$index, $cast]; diff --git a/src/RecordMapperTest.php b/src/RecordMapperTest.php index ddbc7697..e22e2aae 100644 --- a/src/RecordMapperTest.php +++ b/src/RecordMapperTest.php @@ -20,7 +20,6 @@ use League\Csv\TypeCasting\CastToDate; use League\Csv\TypeCasting\CastToEnum; use PHPUnit\Framework\TestCase; -use RuntimeException; use stdClass; use TypeError; @@ -62,7 +61,7 @@ public function testItConvertsARecordsToAnObjectUsingMethods(): void public function testItWillThrowIfTheHeaderIsMissingAndTheColumnOffsetIsAString(): void { - $this->expectException(RuntimeException::class); + $this->expectException(ColumnMappingFailed::class); $mapper = new RecordMapper(WeatherSetterGetter::class); $mapper([ 'date' => '2023-10-30', @@ -73,7 +72,7 @@ public function testItWillThrowIfTheHeaderIsMissingAndTheColumnOffsetIsAString() public function testItWillThrowIfTheHeaderContainsInvalidOffsetName(): void { - $this->expectException(RuntimeException::class); + $this->expectException(ColumnMappingFailed::class); $mapper = new RecordMapper(WeatherSetterGetter::class, ['date', 'toto', 'foobar']); $mapper([ 'date' => '2023-10-30', @@ -84,7 +83,7 @@ public function testItWillThrowIfTheHeaderContainsInvalidOffsetName(): void public function testItWillThrowIfTheColumnAttributesIsUsedMultipleTimeForTheSameAccessor(): void { - $this->expectException(RuntimeException::class); + $this->expectException(ColumnMappingFailed::class); new RecordMapper(InvalidWeatherAttributeUsage::class); } diff --git a/src/TypeCasting/CastToDate.php b/src/TypeCasting/CastToDate.php index c74222cf..05c314cb 100644 --- a/src/TypeCasting/CastToDate.php +++ b/src/TypeCasting/CastToDate.php @@ -49,7 +49,7 @@ public function toVariable(?string $value, string $type): DateTimeImmutable|Date if (in_array($value, ['', null], true)) { return match (true) { str_starts_with($type, '?') => null, - default => throw new RuntimeException('Unable to convert the `null` value.'), + default => throw new TypeCastingFailed('Unable to convert the `null` value.'), }; } @@ -58,15 +58,15 @@ public function toVariable(?string $value, string $type): DateTimeImmutable|Date DateTimeImmutable::class, DateTimeInterface::class => null !== $this->format ? DateTimeImmutable::createFromFormat($this->format, $value, $this->timezone) : new DateTimeImmutable($value, $this->timezone), DateTime::class => null !== $this->format ? DateTime::createFromFormat($this->format, $value, $this->timezone) : new DateTime($value, $this->timezone), - default => throw new RuntimeException('Unable to cast the given data to a PHP DateTime related object.'), + default => throw new TypeCastingFailed('Unable to cast the given data to a PHP DateTime related object.'), }; if (false === $date) { - throw new RuntimeException('Unable to cast the given data to a PHP DateTime related object.'); + throw new TypeCastingFailed('Unable to cast the given data to a PHP DateTime related object.'); } } catch (Throwable $exception) { - if (! $exception instanceof RuntimeException) { - $exception = new RuntimeException('Unable to cast the given data to a PHP DateTime related object.', 0, $exception); + if (! $exception instanceof TypeCastingFailed) { + $exception = new TypeCastingFailed('Unable to cast the given data to a PHP DateTime related object.', 0, $exception); } throw $exception; diff --git a/src/TypeCasting/CastToDateTest.php b/src/TypeCasting/CastToDateTest.php index 9321bafc..48e61979 100644 --- a/src/TypeCasting/CastToDateTest.php +++ b/src/TypeCasting/CastToDateTest.php @@ -18,7 +18,6 @@ use DateTimeInterface; use DateTimeZone; use PHPUnit\Framework\TestCase; -use RuntimeException; final class CastToDateTest extends TestCase { @@ -43,7 +42,7 @@ public function testItCanConvertADateWithASpecificFormat(): void public function testItCShouldThrowIfNoConversionIsPossible(): void { - $this->expectException(RuntimeException::class); + $this->expectException(TypeCastingFailed::class); (new CastToDate())->toVariable('foobar', DateTimeInterface::class); } diff --git a/src/TypeCasting/CastToEnum.php b/src/TypeCasting/CastToEnum.php index 60d31383..52390e66 100644 --- a/src/TypeCasting/CastToEnum.php +++ b/src/TypeCasting/CastToEnum.php @@ -15,7 +15,6 @@ use BackedEnum; use ReflectionEnum; -use RuntimeException; use Throwable; use UnitEnum; @@ -25,14 +24,14 @@ class CastToEnum implements TypeCasting { /** - * @throws RuntimeException + * @throws TypeCastingFailed */ public function toVariable(?string $value, string $type): BackedEnum|UnitEnum|null { if (in_array($value, ['', null], true)) { return match (true) { str_starts_with($type, '?') => null, - default => throw new RuntimeException('Unable to convert the `null` value.'), + default => throw new TypeCastingFailed('Unable to convert the `null` value.'), }; } @@ -48,7 +47,7 @@ public function toVariable(?string $value, string $type): BackedEnum|UnitEnum|nu return $enumName::from($backedValue); } catch (Throwable $exception) { - throw new RuntimeException('Unable to cast to `'.$enumName.'` the value `'.$value.'`.', 0, $exception); + throw new TypeCastingFailed('Unable to cast to `'.$enumName.'` the value `'.$value.'`.', 0, $exception); } } } diff --git a/src/TypeCasting/CastToEnumTest.php b/src/TypeCasting/CastToEnumTest.php index 3d616232..272d2959 100644 --- a/src/TypeCasting/CastToEnumTest.php +++ b/src/TypeCasting/CastToEnumTest.php @@ -14,7 +14,6 @@ namespace League\Csv\TypeCasting; use PHPUnit\Framework\TestCase; -use RuntimeException; final class CastToEnumTest extends TestCase { @@ -56,14 +55,14 @@ public function testItReturnsNullWhenTheVariableIsNullable(): void public function testThrowsOnNullIfTheVariableIsNotNullable(): void { - $this->expectException(RuntimeException::class); + $this->expectException(TypeCastingFailed::class); (new CastToEnum())->toVariable(null, Currency::class); } public function testThrowsIfTheValueIsNotRecognizedByTheEnum(): void { - $this->expectException(RuntimeException::class); + $this->expectException(TypeCastingFailed::class); (new CastToEnum())->toVariable('green', Colour::class); } diff --git a/src/TypeCasting/CastToScalar.php b/src/TypeCasting/CastToScalar.php index 290175bd..bc757dcd 100644 --- a/src/TypeCasting/CastToScalar.php +++ b/src/TypeCasting/CastToScalar.php @@ -13,8 +13,6 @@ namespace League\Csv\TypeCasting; -use RuntimeException; - use const FILTER_VALIDATE_BOOL; use const FILTER_VALIDATE_FLOAT; use const FILTER_VALIDATE_INT; @@ -25,7 +23,7 @@ final class CastToScalar implements TypeCasting { /** - * @throws RuntimeException + * @throws TypeCastingFailed */ public function toVariable(?string $value, string $type): int|float|bool|string|null { @@ -39,7 +37,7 @@ public function toVariable(?string $value, string $type): int|float|bool|string| 'bool' => filter_var($value, FILTER_VALIDATE_BOOL), 'string' => $this->castToString($value), 'null' => $this->castToNull($value), - default => throw new RuntimeException('Unable to convert the given data to a PHP scalar variable.'), + default => throw new TypeCastingFailed('Unable to convert the given data to a PHP scalar variable.'), }; } @@ -48,14 +46,14 @@ private function castToNull(?string $value) { return match ($value) { null => $value, - default => throw new RuntimeException('The value `'.$value.'` can not be cast to an integer.'), + default => throw new TypeCastingFailed('The value `'.$value.'` can not be cast to an integer.'), }; } private function castToString(?string $value): string { return match (null) { - $value => throw new RuntimeException('The `null` value can not be cast to a string.'), + $value => throw new TypeCastingFailed('The `null` value can not be cast to a string.'), default => $value, }; } @@ -65,7 +63,7 @@ private function castToInt(?string $value): int $returnedValue = filter_var($value, FILTER_VALIDATE_INT); return match (false) { - $returnedValue => throw new RuntimeException('The value `'.$value.'` can not be cast to an integer.'), + $returnedValue => throw new TypeCastingFailed('The value `'.$value.'` can not be cast to an integer.'), default => $returnedValue, }; } @@ -75,7 +73,7 @@ private function castToFloat(?string $value): float $returnedValue = filter_var($value, FILTER_VALIDATE_FLOAT); return match (false) { - $returnedValue => throw new RuntimeException('The value `'.$value.'` can not be cast to a float.'), + $returnedValue => throw new TypeCastingFailed('The value `'.$value.'` can not be cast to a float.'), default => $returnedValue, }; } diff --git a/src/TypeCasting/CastToScalarTest.php b/src/TypeCasting/CastToScalarTest.php index 932a2065..d7042162 100644 --- a/src/TypeCasting/CastToScalarTest.php +++ b/src/TypeCasting/CastToScalarTest.php @@ -15,7 +15,6 @@ use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; -use RuntimeException; final class CastToScalarTest extends TestCase { @@ -84,7 +83,7 @@ public static function providesValidScalarValues(): iterable public function testItThrowsIfTheConversionFails(): void { - $this->expectException(RuntimeException::class); + $this->expectException(TypeCastingFailed::class); (new CastToScalar())->toVariable(null, 'int'); } diff --git a/src/TypeCasting/TypeCasting.php b/src/TypeCasting/TypeCasting.php index d988641a..c0158e67 100644 --- a/src/TypeCasting/TypeCasting.php +++ b/src/TypeCasting/TypeCasting.php @@ -13,15 +13,13 @@ namespace League\Csv\TypeCasting; -use RuntimeException; - /** * @template TValue */ interface TypeCasting { /** - * @throws RuntimeException + * @throws TypeCastingFailed * * @return TValue */ diff --git a/src/TypeCasting/TypeCastingFailed.php b/src/TypeCasting/TypeCastingFailed.php new file mode 100644 index 00000000..f81fc8f9 --- /dev/null +++ b/src/TypeCasting/TypeCastingFailed.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace League\Csv\TypeCasting; + +use RuntimeException; + +final class TypeCastingFailed extends RuntimeException +{ +}