1<?php
2
3declare(strict_types=1);
4
5namespace JMS\Serializer\Metadata\Driver;
6
7use Doctrine\Common\Persistence\Mapping\ClassMetadata as DoctrineClassMetadata;
8use JMS\Serializer\Metadata\ClassMetadata;
9use JMS\Serializer\Metadata\PropertyMetadata;
10
11/**
12 * This class decorates any other driver. If the inner driver does not provide a
13 * a property type, the decorator will guess based on Doctrine 2 metadata.
14 */
15class DoctrineTypeDriver extends AbstractDoctrineTypeDriver
16{
17    protected function setDiscriminator(DoctrineClassMetadata $doctrineMetadata, ClassMetadata $classMetadata): void
18    {
19        if (empty($classMetadata->discriminatorMap) && !$classMetadata->discriminatorDisabled
20            && !empty($doctrineMetadata->discriminatorMap) && $doctrineMetadata->isRootEntity()
21        ) {
22            $classMetadata->setDiscriminator(
23                $doctrineMetadata->discriminatorColumn['name'],
24                $doctrineMetadata->discriminatorMap
25            );
26        }
27    }
28
29    protected function setPropertyType(DoctrineClassMetadata $doctrineMetadata, PropertyMetadata $propertyMetadata): void
30    {
31        $propertyName = $propertyMetadata->name;
32        if ($doctrineMetadata->hasField($propertyName)
33            && ($typeOfFiled = $doctrineMetadata->getTypeOfField($propertyName))
34            && ($fieldType = $this->normalizeFieldType($typeOfFiled))) {
35            $propertyMetadata->setType($this->typeParser->parse($fieldType));
36        } elseif ($doctrineMetadata->hasAssociation($propertyName)) {
37            $targetEntity = $doctrineMetadata->getAssociationTargetClass($propertyName);
38
39            if (null === $targetMetadata = $this->tryLoadingDoctrineMetadata($targetEntity)) {
40                return;
41            }
42
43            // For inheritance schemes, we cannot add any type as we would only add the super-type of the hierarchy.
44            // On serialization, this would lead to only the supertype being serialized, and properties of subtypes
45            // being ignored.
46            if ($targetMetadata instanceof DoctrineClassMetadata && !$targetMetadata->isInheritanceTypeNone()) {
47                return;
48            }
49
50            if (!$doctrineMetadata->isSingleValuedAssociation($propertyName)) {
51                $targetEntity = sprintf('ArrayCollection<%s>', $targetEntity);
52            }
53
54            $propertyMetadata->setType($this->typeParser->parse($targetEntity));
55        }
56    }
57}
58