diff --git a/CHANGELOG.md b/CHANGELOG.md index 86572071..9ee757ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ All Notable changes to `Csv` will be documented in this file - `SwapDelimiter` stream filter to allow working with multibyte CSV delimiter - `League\Csv\Serializer\AfterMapping` to work around the limitation aroud constructor usage. - `Denormalizer` can register type alias to simplify callback usage. +- `League\Csv\Serializer\MapCell` has a new property `ignore` to qllow ignoring a property or a method typcasting during conversion. ### Deprecated diff --git a/docs/9.0/reader/record-mapping.md b/docs/9.0/reader/record-mapping.md index 811f1f7c..1dc02716 100644 --- a/docs/9.0/reader/record-mapping.md +++ b/docs/9.0/reader/record-mapping.md @@ -156,12 +156,14 @@ The above rule can be translated in plain English like this: This attribute will override any automatic resolution and enable fine-tuning type casting. It can be used on class properties and methods regardless of their visibility and their type. -The attribute can take up to three (3) arguments which are all optional: +The attribute can take up to four (4) arguments which are all optional: - The `column` argument tells the engine which record key to use via its numeric or name. If not present the property name or the name of the first argument of the `setter` method will be used. In such case, you are required to specify the property names information. - The `cast` argument which accept the name of a class implementing the `TypeCasting` interface and responsible for type casting the record value. If not present, the mechanism will try to resolve the typecasting based on the property or method argument type. - The `options` argument enables controlling typecasting by providing extra arguments to `TypeCasting::setOptions` method. The argument expects an associative array and relies on named arguments to inject its value to the method. +- The `ignore` arguemnt which is a boolean control if the property or method should be completely ignored by the mechanism. By default its value is `false`. This property takes precedence over all the other properties of the attribute once set to `true`. +

The ignore argument was added in version 9.13.0

You can use the mechanism on a CSV without a header row but it requires adding a MapCell attribute on each property or method needed for the conversion. Or you can use the optional second argument of TabularDataReader::getObjects to specify the diff --git a/src/Serializer/Denormalizer.php b/src/Serializer/Denormalizer.php index 14bab73d..17dff845 100644 --- a/src/Serializer/Denormalizer.php +++ b/src/Serializer/Denormalizer.php @@ -346,8 +346,12 @@ private function autoDiscoverPropertySetter(ReflectionMethod|ReflectionProperty * * @throws MappingFailed */ - private function findPropertySetter(MapCell $cell, ReflectionMethod|ReflectionProperty $accessor, array $propertyNames): PropertySetter + private function findPropertySetter(MapCell $cell, ReflectionMethod|ReflectionProperty $accessor, array $propertyNames): ?PropertySetter { + if ($cell->ignore) { + return null; + } + $typeCaster = $this->resolveTypeCaster($cell, $accessor); $offset = $cell->column ?? match (true) { diff --git a/src/Serializer/DenormalizerTest.php b/src/Serializer/DenormalizerTest.php index e98d92c8..0ef3a388 100644 --- a/src/Serializer/DenormalizerTest.php +++ b/src/Serializer/DenormalizerTest.php @@ -605,6 +605,40 @@ public function __construct( self::assertInstanceOf($class::class, $instance); self::assertSame('yamoussokro', $instance->str); } + + #[Test] + public function it_will_ignore_the_property_during_auto_discovery(): void + { + $classIgnoreMethod = new class () { + public DateTimeInterface $observedOn; + + #[MapCell(ignore: true)] + public function setObservedOn(DateTimeInterface $observedOn): void + { + $this->observedOn = DateTime::createFromInterface($observedOn); + } + }; + + $instance = Denormalizer::assign($classIgnoreMethod::class, ['observedOn' => '2023-10-01']); + + self::assertInstanceOf($classIgnoreMethod::class, $instance); + self::assertInstanceOf(DateTimeImmutable::class, $instance->observedOn); + + $classIgnoreProperty = new class () { + #[MapCell(ignore: true)] + public DateTimeInterface $observedOn; + + public function setObservedOn(DateTimeInterface $observedOn): void + { + $this->observedOn = DateTime::createFromInterface($observedOn); + } + }; + + $instance = Denormalizer::assign($classIgnoreProperty::class, ['observedOn' => '2023-10-01']); + + self::assertInstanceOf($classIgnoreProperty::class, $instance); + self::assertInstanceOf(DateTime::class, $instance->observedOn); + } } enum Place: string diff --git a/src/Serializer/MapCell.php b/src/Serializer/MapCell.php index fe84085b..4621b2c2 100644 --- a/src/Serializer/MapCell.php +++ b/src/Serializer/MapCell.php @@ -24,7 +24,8 @@ final class MapCell public function __construct( public readonly string|int|null $column = null, public readonly ?string $cast = null, - public readonly array $options = [] + public readonly array $options = [], + public readonly bool $ignore = false, ) { } }