Skip to content

Commit

Permalink
#508 Adding Specific exceptions
Browse files Browse the repository at this point in the history
  • Loading branch information
nyamsprod committed Oct 30, 2023
1 parent 3fbfae2 commit 28cc281
Show file tree
Hide file tree
Showing 12 changed files with 70 additions and 39 deletions.
20 changes: 20 additions & 0 deletions src/ColumnMappingFailed.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

/**
* League.Csv (https://csv.thephpleague.com)
*
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
*
* 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
{
}
6 changes: 3 additions & 3 deletions src/Mapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@

use ArrayIterator;
use Iterator;
use League\Csv\TypeCasting\TypeCastingFailed;
use ReflectionException;
use RuntimeException;

class Mapper
{
Expand All @@ -28,7 +28,7 @@ public function __construct(private readonly string $className)
}

/**
* @throws RuntimeException
* @throws TypeCastingFailed
* @throws ReflectionException
*/
public function map(TabularDataReader $tabularDataReader): Iterator
Expand All @@ -37,7 +37,7 @@ public function map(TabularDataReader $tabularDataReader): Iterator
}

/**
* @throws RuntimeException
* @throws TypeCastingFailed
* @throws ReflectionException
*/
public function __invoke(iterable $records, array $header): Iterator
Expand Down
10 changes: 5 additions & 5 deletions src/RecordMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public function __invoke(array $record): mixed
/**
* @param array<string> $header
*
* @throws RuntimeException
* @throws ColumnMappingFailed
*
* @return array{0:int<0, max>|null, 1:TypeCasting}
*/
Expand All @@ -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 */
Expand All @@ -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];
Expand Down
7 changes: 3 additions & 4 deletions src/RecordMapperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
use League\Csv\TypeCasting\CastToDate;
use League\Csv\TypeCasting\CastToEnum;
use PHPUnit\Framework\TestCase;
use RuntimeException;
use stdClass;
use TypeError;

Expand Down Expand Up @@ -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',
Expand All @@ -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',
Expand All @@ -84,7 +83,7 @@ public function testItWillThrowIfTheHeaderContainsInvalidOffsetName(): void

public function testItWillThrowIfTheColumnAttributesIsUsedMultipleTimeForTheSameAccessor(): void
{
$this->expectException(RuntimeException::class);
$this->expectException(ColumnMappingFailed::class);

new RecordMapper(InvalidWeatherAttributeUsage::class);
}
Expand Down
10 changes: 5 additions & 5 deletions src/TypeCasting/CastToDate.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.'),
};
}

Expand All @@ -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;
Expand Down
3 changes: 1 addition & 2 deletions src/TypeCasting/CastToDateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
use DateTimeInterface;
use DateTimeZone;
use PHPUnit\Framework\TestCase;
use RuntimeException;

final class CastToDateTest extends TestCase
{
Expand All @@ -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);
}
Expand Down
7 changes: 3 additions & 4 deletions src/TypeCasting/CastToEnum.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

use BackedEnum;
use ReflectionEnum;
use RuntimeException;
use Throwable;
use UnitEnum;

Expand All @@ -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.'),
};
}

Expand All @@ -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);
}
}
}
5 changes: 2 additions & 3 deletions src/TypeCasting/CastToEnumTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
namespace League\Csv\TypeCasting;

use PHPUnit\Framework\TestCase;
use RuntimeException;

final class CastToEnumTest extends TestCase
{
Expand Down Expand Up @@ -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);
}
Expand Down
14 changes: 6 additions & 8 deletions src/TypeCasting/CastToScalar.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
{
Expand All @@ -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.'),
};
}

Expand All @@ -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,
};
}
Expand All @@ -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,
};
}
Expand All @@ -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,
};
}
Expand Down
3 changes: 1 addition & 2 deletions src/TypeCasting/CastToScalarTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use RuntimeException;

final class CastToScalarTest extends TestCase
{
Expand Down Expand Up @@ -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');
}
Expand Down
4 changes: 1 addition & 3 deletions src/TypeCasting/TypeCasting.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,13 @@

namespace League\Csv\TypeCasting;

use RuntimeException;

/**
* @template TValue
*/
interface TypeCasting
{
/**
* @throws RuntimeException
* @throws TypeCastingFailed
*
* @return TValue
*/
Expand Down
20 changes: 20 additions & 0 deletions src/TypeCasting/TypeCastingFailed.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

/**
* League.Csv (https://csv.thephpleague.com)
*
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
*
* 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
{
}

0 comments on commit 28cc281

Please sign in to comment.