-
-
Notifications
You must be signed in to change notification settings - Fork 9.7k
Closed as duplicate
Closed as duplicate
Copy link
Description
Description
When you have a DTO with an array you want to map on an entity with a doctrine Collection (or the other way around), right now it's not handled, I found a workaround but it would be super nice to add this feature...
Workaround array to collection:
/** @var Collection<int, Contact> */
#[Map(target: 'contacts', transform: ArrayTransformer::class)]
#[ORM\OneToMany(mappedBy: 'utilisateur', targetEntity: Contact::class, cascade: ['persist', 'remove'])]
private Collection $contacts;
+
<?php
declare(strict_types=1);
namespace App\Common\ObjectMapper;
use Doctrine\Common\Collections\Collection;
use LogicException;
use ReflectionClass;
use Symfony\Component\ObjectMapper\Attribute\Map;
use Symfony\Component\ObjectMapper\ObjectMapperInterface;
use Symfony\Component\ObjectMapper\TransformCallableInterface;
/**
* @template T of object
*
* @template-implements TransformCallableInterface<T, T[]>
*
* @phpstan-ignore-next-line
*/
class ArrayTransformer implements TransformCallableInterface
{
public function __construct(
private readonly ObjectMapperInterface $objectMapper,
) {
}
/**
* @param Collection<T>|mixed $value
*
* @return T[]|mixed
*/
public function __invoke(mixed $value, object $source, ?object $target): mixed
{
if (!$value instanceof Collection || $value->isEmpty()) {
return $value;
}
$firstItem = $value->first();
if (!is_object($firstItem)) {
throw new LogicException("La collection ne contient pas d'objets transformables.");
}
$targetClass = $this->getTargetClass($firstItem);
if (null === $targetClass) {
throw new LogicException("La collection ne contient pas d'objets transformables.");
}
/** @var T[] $items */
$items = $value->toArray();
return array_map(
fn ($item): object => $this->objectMapper->map($item, $targetClass),
$items
);
}
/**
* @return class-string<T>|null
*/
private function getTargetClass(object $object): ?string
{
$reflectionClass = new ReflectionClass($object);
$mapAttribute = $reflectionClass->getAttributes(Map::class)[0] ?? null;
if (null === $mapAttribute) {
return null;
}
$arguments = $mapAttribute->getArguments();
/** @var class-string<T>|null $targetClass */
$targetClass = $arguments['target'] ?? null;
return $targetClass;
}
}
Workaround collection to array:
#[Map(target: 'contacts', transform: CollectionTransformer::class)]
public readonly ?array $contacts = [],
+
<?php
declare(strict_types=1);
namespace App\Common\ObjectMapper;
use Doctrine\Common\Collections\ArrayCollection;
use LogicException;
use ReflectionClass;
use Symfony\Component\ObjectMapper\Attribute\Map;
use Symfony\Component\ObjectMapper\ObjectMapperInterface;
use Symfony\Component\ObjectMapper\TransformCallableInterface;
/**
* @template T of object
*
* @template-implements TransformCallableInterface<T, ArrayCollection<int, T>>
*/
class CollectionTransformer implements TransformCallableInterface
{
public function __construct(
private readonly ObjectMapperInterface $objectMapper,
) {
}
/**
* @param T[]|mixed $value
*
* @return ArrayCollection<int, T>|mixed
*/
public function __invoke(mixed $value, object $source, ?object $target): mixed
{
if (!is_array($value) || [] === $value) {
return $value;
}
$firstItem = $value[0];
if (!is_object($firstItem)) {
throw new LogicException("Le tableau ne contient pas d'objets transformables.");
}
$targetClass = $this->getTargetClass($firstItem);
if (null === $targetClass) {
throw new LogicException("Le tableau ne contient pas d'objets transformables.");
}
/** @var T[] $items */
$items = $value;
return new ArrayCollection(
array_map(
fn (object $item): object => $this->objectMapper->map($item, $targetClass),
$items
)
);
}
/**
* @return class-string<T>|null
*/
private function getTargetClass(object $object): ?string
{
$reflectionClass = new ReflectionClass($object);
$mapAttribute = $reflectionClass->getAttributes(Map::class)[0] ?? null;
if (null === $mapAttribute) {
return null;
}
$arguments = $mapAttribute->getArguments();
/** @var class-string<T>|null $targetClass */
$targetClass = $arguments['target'] ?? null;
return $targetClass;
}
}
Example
No response