From be03a29ee6813646f18c19a236c740728aa3bb73 Mon Sep 17 00:00:00 2001
From: ignace nyamagana butera
Date: Sat, 11 Nov 2023 07:03:09 +0100
Subject: [PATCH] Improve Serializer performance with collection
---
CHANGELOG.md | 1 +
docs/9.0/reader/record-mapping.md | 35 ++++----
src/MapIterator.php | 9 ++
src/Reader.php | 11 +--
src/ResultSet.php | 31 ++++---
src/Serializer.php | 95 +++++++++++-----------
src/Serializer/CastToArray.php | 18 ++--
src/Serializer/CastToBool.php | 6 +-
src/Serializer/CastToDate.php | 6 +-
src/Serializer/CastToEnum.php | 6 +-
src/Serializer/CastToFloat.php | 6 +-
src/Serializer/CastToInt.php | 6 +-
src/Serializer/CastToString.php | 4 +-
src/Serializer/PropertySetter.php | 2 +-
src/Serializer/{BasicType.php => Type.php} | 4 +-
src/SerializerTest.php | 8 +-
16 files changed, 134 insertions(+), 114 deletions(-)
rename src/Serializer/{BasicType.php => Type.php} (97%)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d0e918b0..8a447599 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -31,6 +31,7 @@ It's usage will trigger a `E_USER_DEPRECATED` call.
- The internal `Stream` object it will throw a `RuntimeException` if the rewind action fails
- if calls to `fseek` fails (returns `-1` ) a new `RuntimeException` will be thrown too.
- `Stream` can iterate and return the full line respecting `SplFielObject` flags. Previously it only returned the CSV records.
+- `MapIterator::fromIterable` to instantiate a `MapIterator` object from any iterable structure.
### Removed
diff --git a/docs/9.0/reader/record-mapping.md b/docs/9.0/reader/record-mapping.md
index e47c8180..5939d2aa 100644
--- a/docs/9.0/reader/record-mapping.md
+++ b/docs/9.0/reader/record-mapping.md
@@ -38,7 +38,7 @@ foreach ($serializer->deserializeAll($collection) as $weather) {
If you are working with a class which implements the `TabularDataReader` interface you can use this functionality
directly by calling the `TabularDataReader::getObjects` method.
-Here's an example using the `Reader` class:
+Here's an example using the `Reader` class which implements the `TabularDataReader` interface:
```php
use League\Csv\Reader;
@@ -65,7 +65,7 @@ the mechanism may either fail or produced unexpected results.
To work as intended the mechanism expects the following:
- A target class where the array will be deserialized in;
-- information on how to convert cell value into object properties using dedicated attributes;
+- information on how to convert cell values into object properties;
As an example if we assume we have the following CSV document:
@@ -79,7 +79,7 @@ date,temperature,place
2011-01-03,5,Berkeley
```
-We can define a PHP DTO using the following class and the attributes.
+We can define a PHP DTO using the following properties.
```php
deserializeAll($csv) as $weather) {
}
```
+The code above is similar to using TabularDataReader::getObject
method.
+
## Defining the mapping rules
By default, the deserialization engine will convert public properties using their name. In other words,
-if there is a class property, which name is the same as a column name, the column value will be assigned
-to this property. The appropriate type used for the record cell value is a `string` or `null` and
-the object public properties ares typed with
+if there is a public class property, which name is the same as a column name, the column
+value will be assigned to that property. The appropriate type used for the record
+cell value is a `string` or `null` and the object public properties must be typed with
- a scalar type (`string`, `int`, `float`, `bool`)
- any `Enum` object (backed or not)
- `DateTime`, `DateTimeImmuntable` or any class that extends those two classes.
- an `array`
-the `nullable` aspect of the property is also handled.
+the `nullable` aspect of the property is also automatically handled.
-To fine tune the conversion you are require to use the `Cell` attribute. This attribute will
+It is possible to improve the conversion using the `Cell` attribute. This attribute will
override the automatic resolution and enable fine-tuning type casting on the property level.
The `Cell` attribute can be used on class properties and methods regardless of their visibility.
The attribute can take up to three (3) arguments which are all optional:
-- The `offset` argument tells the engine which cell to use via its numeric or name offset. 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 cell value.
-- The `castArguments` which enable controlling typecasting by providing extra arguments to the `TypeCasting` class constructor
+- The `offset` argument tells the engine which cell to use via its numeric or name offset. 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 cell value.
+- The `castArguments` argument enables controlling typecasting by providing extra arguments to the `TypeCasting` class constructor
-In any cases, if type casting fails, an exception will be thrown.
+In any case, if type casting fails, an exception will be thrown.
Here's an example of how the attribute could be used:
@@ -169,9 +168,9 @@ The above rule can be translated in plain english like this:
> using the date format `!Y-m-d` and the `Africa/Nairobi` timezone. Once created,
> inject the date instance into the `observedOn` property of the class.
-## Type casting the record value
+## Type casting
-The library comes bundles with seven (7) type casting classes which relies on the property type information. All the
+The library comes bundled with seven (7) type casting classes which relies on the property type information. All the
built-in methods support the `nullable` and the `mixed` types.
- They will return `null` or a specified default value, if the cell value is `null` and the type is `nullable`
@@ -198,7 +197,7 @@ optional argument `default` which is the default `int` or `float` value to retur
### CastToEnum
-Convert the array value to a PHP `Enum` it supports both "real" and backed enumeration. The class takes on
+Convert the array value to a PHP `Enum`, it supports both "real" and backed enumeration. The class takes on
optional argument `default` which is the default Enum value to return if the value is `null`.
If the `Enum` is backed the cell value will be considered as one of the Enum value; otherwise it will be used
as one the `Enum` name. Likewise, the `default` value will also be considered the same way. If the default value
diff --git a/src/MapIterator.php b/src/MapIterator.php
index 05347c09..058dfdd2 100644
--- a/src/MapIterator.php
+++ b/src/MapIterator.php
@@ -13,6 +13,7 @@
namespace League\Csv;
+use ArrayIterator;
use IteratorIterator;
use Traversable;
@@ -32,6 +33,14 @@ public function __construct(Traversable $iterator, callable $callable)
$this->callable = $callable;
}
+ public static function fromIterable(iterable $iterator, callable $callable): self
+ {
+ return match (true) {
+ is_array($iterator) => new self(new ArrayIterator($iterator), $callable),
+ default => new self($iterator, $callable),
+ };
+ }
+
public function current(): mixed
{
return ($this->callable)(parent::current(), parent::key());
diff --git a/src/Reader.php b/src/Reader.php
index edfd18a2..f68f1a0a 100644
--- a/src/Reader.php
+++ b/src/Reader.php
@@ -80,7 +80,7 @@ public function getHeaderOffset(): ?int
}
/**
- * @throws Exception
+ * @throws SyntaxError
*
* Returns the header record.
*/
@@ -96,7 +96,7 @@ public function getHeader(): array
/**
* Determines the CSV record header.
*
- * @throws Exception If the header offset is set and no record is found or is the empty array
+ * @throws SyntaxError If the header offset is set and no record is found or is the empty array
*
* @return array
*/
@@ -424,11 +424,12 @@ public function getRecords(array $header = []): Iterator
/**
* @param class-string $className
+ * @param array $header
*
- * @throws TypeCastingFailed
- * @throws MappingFailed
* @throws Exception
+ * @throws MappingFailed
* @throws ReflectionException
+ * @throws TypeCastingFailed
*/
public function getObjects(string $className, array $header = []): Iterator
{
@@ -448,7 +449,7 @@ public function getObjects(string $className, array $header = []): Iterator
*
* @param array $header
*
- * @throws Exception If the header contains non unique column name
+ * @throws SyntaxError If the header contains non unique column name
*
* @return array
*/
diff --git a/src/ResultSet.php b/src/ResultSet.php
index e42f76f3..d0599a46 100644
--- a/src/ResultSet.php
+++ b/src/ResultSet.php
@@ -22,6 +22,7 @@
use League\Csv\Serializer\MappingFailed;
use League\Csv\Serializer\TypeCastingFailed;
use LimitIterator;
+use ReflectionException;
use function array_filter;
use function array_flip;
@@ -235,25 +236,34 @@ public function matchingFirstOrFail(string $expression): TabularDataReader
*/
public function getRecords(array $header = []): Iterator
{
- if ($header !== array_filter($header, is_string(...))) {
- throw SyntaxError::dueToInvalidHeaderColumnNames();
- }
-
- $header = $this->validateHeader($header);
- if ([] === $header) {
- $header = $this->header;
- }
+ $header = $this->prepareHeader($header);
return $this->combineHeader($header);
}
/**
* @param class-string $className
+ * @param array $header
*
- * @throws TypeCastingFailed
+ * @throws Exception
* @throws MappingFailed
+ * @throws ReflectionException
+ * @throws TypeCastingFailed
*/
public function getObjects(string $className, array $header = []): Iterator
+ {
+ $header = $this->prepareHeader($header);
+
+ return (new Serializer($className, $header))->deserializeAll($this->combineHeader($header));
+ }
+
+ /**
+ * @param array $header
+ *
+ * @throws SyntaxError
+ * @return array
+ */
+ protected function prepareHeader(array $header): array
{
if ($header !== array_filter($header, is_string(...))) {
throw SyntaxError::dueToInvalidHeaderColumnNames();
@@ -263,8 +273,7 @@ public function getObjects(string $className, array $header = []): Iterator
if ([] === $header) {
$header = $this->header;
}
-
- return (new Serializer($className, $header))->deserializeAll($this->combineHeader($header));
+ return $header;
}
/**
diff --git a/src/Serializer.php b/src/Serializer.php
index 791402d0..ba30ec0e 100644
--- a/src/Serializer.php
+++ b/src/Serializer.php
@@ -13,9 +13,7 @@
namespace League\Csv;
-use ArrayIterator;
use Iterator;
-use League\Csv\Serializer\BasicType;
use League\Csv\Serializer\CastToArray;
use League\Csv\Serializer\CastToBool;
use League\Csv\Serializer\CastToDate;
@@ -26,22 +24,21 @@
use League\Csv\Serializer\Cell;
use League\Csv\Serializer\MappingFailed;
use League\Csv\Serializer\PropertySetter;
+use League\Csv\Serializer\Type;
use League\Csv\Serializer\TypeCasting;
use League\Csv\Serializer\TypeCastingFailed;
use ReflectionAttribute;
use ReflectionClass;
+use ReflectionException;
use ReflectionMethod;
use ReflectionNamedType;
use ReflectionProperty;
use ReflectionType;
-use RuntimeException;
use Throwable;
-use TypeError;
use function array_reduce;
use function array_search;
use function array_values;
-use function is_array;
use function is_int;
final class Serializer
@@ -57,8 +54,7 @@ final class Serializer
* @param array $propertyNames
*
* @throws MappingFailed
- * @throws RuntimeException
- * @throws TypeError
+ * @throws ReflectionException
*/
public function __construct(string $className, array $propertyNames = [])
{
@@ -67,56 +63,68 @@ public function __construct(string $className, array $propertyNames = [])
$this->propertySetters = $this->findPropertySetters($propertyNames);
//if converters is empty it means the Serializer
- //was unable to detect properties to map
+ //was unable to detect properties to assign
if ([] === $this->propertySetters) {
throw new MappingFailed('No properties or method setters were found eligible on the class `'.$className.'` to be used for type casting.');
}
}
/**
+ * @param class-string $className
+ * @param array $record
+ *
* @throws MappingFailed
+ * @throws ReflectionException
* @throws TypeCastingFailed
*/
+ public static function assign(string $className, array $record): object
+ {
+ return (new self($className, array_keys($record)))->deserialize($record);
+ }
+
public function deserializeAll(iterable $records): Iterator
{
- $threshold = 50;
- $deserialize = fn (array $record, int $offset): object => match (0) {
- $offset % $threshold => $this->deserialize($record),
- default => $this->createInstance($record),
+ $check = true;
+ $assign = function (array $record) use (&$check) {
+ $object = $this->class->newInstanceWithoutConstructor();
+ $this->hydrate($object, $record);
+
+ if ($check) {
+ $check = false;
+ $this->assertObjectIsInValidState($object);
+ }
+
+ return $object;
};
- return new MapIterator(
- is_array($records) ? new ArrayIterator($records) : $records,
- $deserialize
- );
+ return MapIterator::fromIterable($records, $assign);
}
/**
- * @throws MappingFailed
+ * @throws ReflectionException
* @throws TypeCastingFailed
*/
public function deserialize(array $record): object
{
- $object = $this->createInstance($record);
+ $object = $this->class->newInstanceWithoutConstructor();
+ $this->hydrate($object, $record);
$this->assertObjectIsInValidState($object);
return $object;
}
- private function createInstance(array $record): object
+ /**
+ * @param array $record
+ */
+ private function hydrate(object $object, array $record): void
{
- $object = $this->class->newInstanceWithoutConstructor();
-
$record = array_values($record);
foreach ($this->propertySetters as $propertySetter) {
- $propertySetter->setValue($object, $record[$propertySetter->offset]);
+ $propertySetter($object, $record[$propertySetter->offset]);
}
-
- return $object;
}
-
/**
* @throws TypeCastingFailed
*/
@@ -129,17 +137,6 @@ private function assertObjectIsInValidState(object $object): void
}
}
- /**
- * @param class-string $className
- *
- * @throws MappingFailed
- * @throws TypeCastingFailed
- */
- public static function map(string $className, array $record): object
- {
- return (new self($className, array_keys($record)))->deserialize($record);
- }
-
/**
* @param array $propertyNames
*
@@ -152,6 +149,10 @@ private function findPropertySetters(array $propertyNames): array
$check = [];
$propertySetters = [];
foreach ($this->class->getProperties(ReflectionProperty::IS_PUBLIC) as $property) {
+ if ($property->isStatic()) {
+ continue;
+ }
+
$propertyName = $property->getName();
/** @var int|false $offset */
@@ -279,17 +280,17 @@ private function resolveTypeCasting(ReflectionType $reflectionType, array $argum
}
try {
- return match (BasicType::tryFromPropertyType($type)) {
- BasicType::Mixed,
- BasicType::String => new CastToString($type, ...$arguments), /* @phpstan-ignore-line */
- BasicType::Iterable,
- BasicType::Array => new CastToArray($type, ...$arguments), /* @phpstan-ignore-line */
- BasicType::Float => new CastToFloat($type, ...$arguments), /* @phpstan-ignore-line */
- BasicType::Int => new CastToInt($type, ...$arguments), /* @phpstan-ignore-line */
- BasicType::Bool => new CastToBool($type, ...$arguments), /* @phpstan-ignore-line */
- BasicType::Date => new CastToDate($type, ...$arguments), /* @phpstan-ignore-line */
- BasicType::Enum => new CastToEnum($type, ...$arguments), /* @phpstan-ignore-line */
- default => null,
+ return match (Type::tryFromPropertyType($type)) {
+ Type::Mixed,
+ Type::String => new CastToString($type, ...$arguments), /* @phpstan-ignore-line */
+ Type::Iterable,
+ Type::Array => new CastToArray($type, ...$arguments), /* @phpstan-ignore-line */
+ Type::Float => new CastToFloat($type, ...$arguments), /* @phpstan-ignore-line */
+ Type::Int => new CastToInt($type, ...$arguments), /* @phpstan-ignore-line */
+ Type::Bool => new CastToBool($type, ...$arguments), /* @phpstan-ignore-line */
+ Type::Date => new CastToDate($type, ...$arguments), /* @phpstan-ignore-line */
+ Type::Enum => new CastToEnum($type, ...$arguments), /* @phpstan-ignore-line */
+ null => null,
};
} catch (Throwable $exception) {
if ($exception instanceof MappingFailed) {
diff --git a/src/Serializer/CastToArray.php b/src/Serializer/CastToArray.php
index e0c9f2ac..3e5e23c6 100644
--- a/src/Serializer/CastToArray.php
+++ b/src/Serializer/CastToArray.php
@@ -50,10 +50,10 @@ public function __construct(
private readonly string $enclosure = '"',
private readonly int $jsonDepth = 512,
private readonly int $jsonFlags = 0,
- BasicType|string $type = BasicType::String,
+ Type|string $type = Type::String,
) {
- $baseType = BasicType::tryFromPropertyType($propertyType);
- if (null === $baseType || !$baseType->isOneOf(BasicType::Mixed, BasicType::Array, BasicType::Iterable)) {
+ $baseType = Type::tryFromPropertyType($propertyType);
+ if (null === $baseType || !$baseType->isOneOf(Type::Mixed, Type::Array, Type::Iterable)) {
throw new MappingFailed('The property type `'.$propertyType.'` is not supported; an `array` or an `iterable` structure is required.');
}
@@ -79,7 +79,7 @@ public function toVariable(?string $value): ?array
if (null === $value) {
return match (true) {
$this->isNullable,
- BasicType::tryFrom($this->class)?->equals(BasicType::Mixed) => $this->default,
+ Type::tryFrom($this->class)?->equals(Type::Mixed) => $this->default,
default => throw new TypeCastingFailed('The `null` value can not be cast to an `array`; the property type is not nullable.'),
};
}
@@ -109,18 +109,18 @@ public function toVariable(?string $value): ?array
/**
* @throws MappingFailed if the type is not supported
*/
- private function resolveFilterFlag(BasicType|string $type): int
+ private function resolveFilterFlag(Type|string $type): int
{
if ($this->shape->equals(ArrayShape::Json)) {
- return BasicType::String->filterFlag();
+ return Type::String->filterFlag();
}
- if (!$type instanceof BasicType) {
- $type = BasicType::tryFrom($type);
+ if (!$type instanceof Type) {
+ $type = Type::tryFrom($type);
}
return match (true) {
- !$type instanceof BasicType,
+ !$type instanceof Type,
!$type->isScalar() => throw new MappingFailed('Only scalar type are supported for `array` value casting.'),
default => $type->filterFlag(),
};
diff --git a/src/Serializer/CastToBool.php b/src/Serializer/CastToBool.php
index d7d3cf76..a9e85c1f 100644
--- a/src/Serializer/CastToBool.php
+++ b/src/Serializer/CastToBool.php
@@ -24,8 +24,8 @@ public function __construct(
string $propertyType,
private readonly ?bool $default = null
) {
- $baseType = BasicType::tryFromPropertyType($propertyType);
- if (null === $baseType || !$baseType->isOneOf(BasicType::Mixed, BasicType::Bool)) {
+ $baseType = Type::tryFromPropertyType($propertyType);
+ if (null === $baseType || !$baseType->isOneOf(Type::Mixed, Type::Bool)) {
throw new MappingFailed('The property type `'.$propertyType.'` is not supported; a `bool` type is required.');
}
@@ -38,7 +38,7 @@ public function __construct(
public function toVariable(?string $value): ?bool
{
return match(true) {
- null !== $value => filter_var($value, BasicType::Bool->filterFlag()),
+ null !== $value => filter_var($value, Type::Bool->filterFlag()),
$this->isNullable => $this->default,
default => throw new TypeCastingFailed('The `null` value can not be cast to a boolean value.'),
};
diff --git a/src/Serializer/CastToDate.php b/src/Serializer/CastToDate.php
index 4c61eb9e..5dea6235 100644
--- a/src/Serializer/CastToDate.php
+++ b/src/Serializer/CastToDate.php
@@ -42,13 +42,13 @@ public function __construct(
private readonly ?string $format = null,
DateTimeZone|string|null $timezone = null,
) {
- $baseType = BasicType::tryFromPropertyType($propertyType);
- if (null === $baseType || !$baseType->isOneOf(BasicType::Mixed, BasicType::Date)) {
+ $baseType = Type::tryFromPropertyType($propertyType);
+ if (null === $baseType || !$baseType->isOneOf(Type::Mixed, Type::Date)) {
throw new MappingFailed('The property type `'.$propertyType.'` is not supported; an class implementing the `'.DateTimeInterface::class.'` interface is required.');
}
$class = ltrim($propertyType, '?');
- if (BasicType::Mixed->equals($baseType) || DateTimeInterface::class === $class) {
+ if (Type::Mixed->equals($baseType) || DateTimeInterface::class === $class) {
$class = DateTimeImmutable::class;
}
diff --git a/src/Serializer/CastToEnum.php b/src/Serializer/CastToEnum.php
index 9f85c2fe..ccd9059f 100644
--- a/src/Serializer/CastToEnum.php
+++ b/src/Serializer/CastToEnum.php
@@ -37,8 +37,8 @@ public function __construct(
string $propertyType,
?string $default = null,
) {
- $baseType = BasicType::tryFromPropertyType($propertyType);
- if (null === $baseType || !$baseType->isOneOf(BasicType::Mixed, BasicType::Enum)) {
+ $baseType = Type::tryFromPropertyType($propertyType);
+ if (null === $baseType || !$baseType->isOneOf(Type::Mixed, Type::Enum)) {
throw new MappingFailed('The property type `'.$propertyType.'` is not supported; an `Enum` is required.');
}
@@ -74,7 +74,7 @@ private function cast(string $value): BackedEnum|UnitEnum
return $enum->getCase($value)->getValue();
}
- $backedValue = 'int' === $enum->getBackingType()?->getName() ? filter_var($value, BasicType::Int->filterFlag()) : $value;
+ $backedValue = 'int' === $enum->getBackingType()?->getName() ? filter_var($value, Type::Int->filterFlag()) : $value;
return $this->class::from($backedValue);
} catch (Throwable $exception) {
diff --git a/src/Serializer/CastToFloat.php b/src/Serializer/CastToFloat.php
index b22ffc1c..12cb5129 100644
--- a/src/Serializer/CastToFloat.php
+++ b/src/Serializer/CastToFloat.php
@@ -27,8 +27,8 @@ public function __construct(
string $propertyType,
private readonly ?float $default = null,
) {
- $baseType = BasicType::tryFromPropertyType($propertyType);
- if (null === $baseType || !$baseType->isOneOf(BasicType::Mixed, BasicType::Float)) {
+ $baseType = Type::tryFromPropertyType($propertyType);
+ if (null === $baseType || !$baseType->isOneOf(Type::Mixed, Type::Float)) {
throw new MappingFailed('The property type `'.$propertyType.'` is not supported; a `float` type is required.');
}
@@ -47,7 +47,7 @@ public function toVariable(?string $value): ?float
};
}
- $float = filter_var($value, BasicType::Float->filterFlag());
+ $float = filter_var($value, Type::Float->filterFlag());
return match ($float) {
false => throw new TypeCastingFailed('The `'.$value.'` value can not be cast to a float.'),
diff --git a/src/Serializer/CastToInt.php b/src/Serializer/CastToInt.php
index 4892b21c..f6b49879 100644
--- a/src/Serializer/CastToInt.php
+++ b/src/Serializer/CastToInt.php
@@ -27,8 +27,8 @@ public function __construct(
string $propertyType,
private readonly ?int $default = null,
) {
- $baseType = BasicType::tryFromPropertyType($propertyType);
- if (null === $baseType || !$baseType->isOneOf(BasicType::Mixed, BasicType::Int, BasicType::Float)) {
+ $baseType = Type::tryFromPropertyType($propertyType);
+ if (null === $baseType || !$baseType->isOneOf(Type::Mixed, Type::Int, Type::Float)) {
throw new MappingFailed('The property type `'.$propertyType.'` is not supported; a `int` type is required.');
}
@@ -47,7 +47,7 @@ public function toVariable(?string $value): ?int
};
}
- $int = filter_var($value, BasicType::Int->filterFlag());
+ $int = filter_var($value, Type::Int->filterFlag());
return match ($int) {
false => throw new TypeCastingFailed('The `'.$value.'` value can not be cast to an integer.'),
diff --git a/src/Serializer/CastToString.php b/src/Serializer/CastToString.php
index ea4f95cb..221984da 100644
--- a/src/Serializer/CastToString.php
+++ b/src/Serializer/CastToString.php
@@ -26,8 +26,8 @@ public function __construct(
string $propertyType,
private readonly ?string $default = null
) {
- $baseType = BasicType::tryFromPropertyType($propertyType);
- if (null === $baseType || !$baseType->isOneOf(BasicType::Mixed, BasicType::String)) {
+ $baseType = Type::tryFromPropertyType($propertyType);
+ if (null === $baseType || !$baseType->isOneOf(Type::Mixed, Type::String)) {
throw new MappingFailed('The property type `'.$propertyType.'` is not supported; a `string` type is required.');
}
diff --git a/src/Serializer/PropertySetter.php b/src/Serializer/PropertySetter.php
index 8e6ab29c..b67dc1dc 100644
--- a/src/Serializer/PropertySetter.php
+++ b/src/Serializer/PropertySetter.php
@@ -28,7 +28,7 @@ public function __construct(
) {
}
- public function setValue(object $object, ?string $value): void
+ public function __invoke(object $object, ?string $value): void
{
$value = $this->cast->toVariable($value);
diff --git a/src/Serializer/BasicType.php b/src/Serializer/Type.php
similarity index 97%
rename from src/Serializer/BasicType.php
rename to src/Serializer/Type.php
index 82c16451..d9446b69 100644
--- a/src/Serializer/BasicType.php
+++ b/src/Serializer/Type.php
@@ -25,10 +25,10 @@
use const FILTER_VALIDATE_FLOAT;
use const FILTER_VALIDATE_INT;
-enum BasicType: string
+enum Type: string
{
case Bool = 'bool';
- case Int = 'int';
+ case Int = 'int';
case Float = 'float';
case String = 'string';
case Mixed = 'mixed';
diff --git a/src/SerializerTest.php b/src/SerializerTest.php
index 58e3121c..596bd3a9 100644
--- a/src/SerializerTest.php
+++ b/src/SerializerTest.php
@@ -57,7 +57,7 @@ public function testItConvertsARecordsToAnObjectUsingRecordAttribute(): void
'place' => 'Berkeley',
];
- $weather = Serializer::map(WeatherWithRecordAttribute::class, $record);
+ $weather = Serializer::assign(WeatherWithRecordAttribute::class, $record);
self::assertInstanceOf(WeatherWithRecordAttribute::class, $weather);
self::assertInstanceOf(DateTimeImmutable::class, $weather->observedOn);
@@ -73,7 +73,7 @@ public function testItConvertsARecordsToAnObjectUsingProperties(): void
'place' => 'Berkeley',
];
- $weather = Serializer::map(WeatherProperty::class, $record);
+ $weather = Serializer::assign(WeatherProperty::class, $record);
self::assertInstanceOf(WeatherProperty::class, $weather);
self::assertInstanceOf(DateTimeImmutable::class, $weather->observedOn);
@@ -89,7 +89,7 @@ public function testItConvertsARecordsToAnObjectUsingMethods(): void
'place' => 'Berkeley',
];
- $weather = Serializer::map(WeatherSetterGetter::class, $record);
+ $weather = Serializer::assign(WeatherSetterGetter::class, $record);
self::assertInstanceOf(WeatherSetterGetter::class, $weather);
self::assertSame('2023-10-30', $weather->getObservedOn()->format('Y-m-d'));
@@ -102,7 +102,7 @@ public function testMapingFailBecauseTheRecordAttributeIsMissing(): void
$this->expectException(MappingFailed::class);
$this->expectExceptionMessage('No properties or method setters were found eligible on the class `stdClass` to be used for type casting.');
- Serializer::map(stdClass::class, ['foo' => 'bar']);
+ Serializer::assign(stdClass::class, ['foo' => 'bar']);
}
public function testItWillThrowIfTheHeaderIsMissingAndTheColumnOffsetIsAString(): void