diff --git a/src/Populator/ArrayPropertyMappingPopulator.php b/src/Populator/ArrayPropertyMappingPopulator.php index 7f4cc4a..1e6d93e 100644 --- a/src/Populator/ArrayPropertyMappingPopulator.php +++ b/src/Populator/ArrayPropertyMappingPopulator.php @@ -18,25 +18,33 @@ */ final class ArrayPropertyMappingPopulator implements Populator { - /** @var \Closure(mixed, TContext=):mixed */ - private \Closure $mapper; + private ?string $sourceArrayItemProperty; + /** @var \Closure(mixed, TContext=):mixed|null */ + private ?\Closure $mapper; private PropertyAccessorInterface $arrayItemAccessor; - private PropertyAccessorInterface $accessor; + private PropertyMappingPopulator $populator; /** * @param \Closure(mixed, TContext=):mixed|null $mapper */ public function __construct( - private string $targetProperty, - private string $sourceArrayProperty, - private ?string $sourceArrayItemProperty = null, + string $targetProperty, + string $sourceArrayProperty, + ?string $sourceArrayItemProperty = null, ?\Closure $mapper = null, ?PropertyAccessorInterface $arrayItemAccessor = null, ?PropertyAccessorInterface $accessor = null, ) { - $this->mapper = $mapper ?? static fn ($v) => $v; + $this->sourceArrayItemProperty = $sourceArrayItemProperty; + $this->mapper = $mapper; $this->arrayItemAccessor = $arrayItemAccessor ?? PropertyAccess::createPropertyAccessor(); - $this->accessor = $accessor ?? PropertyAccess::createPropertyAccessor(); + $this->populator = new PropertyMappingPopulator( + $targetProperty, + $sourceArrayProperty, + null, + $this->unwrapAndMap(...), + $accessor, + ); } /** @@ -44,26 +52,30 @@ public function __construct( */ public function populate(object $target, object $source, ?object $ctx = null): void { - try { - $sourceArrayPropertyValues = $this->accessor->getValue($source, $this->sourceArrayProperty); + $this->populator->populate($target, $source, $ctx); + } - $unwrappedArray = []; - if (\is_array($sourceArrayPropertyValues) && [] !== $sourceArrayPropertyValues) { - $unwrappedArray = array_map( - fn ($item) => null !== $this->sourceArrayItemProperty - ? $this->arrayItemAccessor->getValue($item, $this->sourceArrayItemProperty) - : $item, - $sourceArrayPropertyValues, - ); - } + /** + * @param TContext $ctx + * + * @return array + */ + private function unwrapAndMap(mixed $values, ?object $ctx = null): array + { + if (!\is_array($values) || [] === $values) { + return []; + } - $this->accessor->setValue( - $target, - $this->targetProperty, - array_map(fn ($item) => ($this->mapper)($item, $ctx), $unwrappedArray), - ); - } catch (\Throwable $exception) { - throw new PopulationException($this->sourceArrayProperty, $this->targetProperty, $exception); + if (null === $this->sourceArrayItemProperty) { + return $this->mapper ? array_map(fn ($item) => ($this->mapper)($item, $ctx), $values) : $values; } + + $mapper = fn ($item) => $this->arrayItemAccessor->getValue($item, $this->sourceArrayItemProperty); + + if ($this->mapper) { + $mapper = fn ($item) => ($this->mapper)($mapper($item), $ctx); + } + + return array_map($mapper, $values); } }