vendor/jms/serializer/src/Metadata/Driver/AnnotationOrAttributeDriver.php line 163

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace JMS\Serializer\Metadata\Driver;
  4. use JMS\Serializer\Annotation\Accessor;
  5. use JMS\Serializer\Annotation\AccessorOrder;
  6. use JMS\Serializer\Annotation\AccessType;
  7. use JMS\Serializer\Annotation\Discriminator;
  8. use JMS\Serializer\Annotation\Exclude;
  9. use JMS\Serializer\Annotation\ExclusionPolicy;
  10. use JMS\Serializer\Annotation\Expose;
  11. use JMS\Serializer\Annotation\Groups;
  12. use JMS\Serializer\Annotation\Inline;
  13. use JMS\Serializer\Annotation\MaxDepth;
  14. use JMS\Serializer\Annotation\PostDeserialize;
  15. use JMS\Serializer\Annotation\PostSerialize;
  16. use JMS\Serializer\Annotation\PreSerialize;
  17. use JMS\Serializer\Annotation\ReadOnlyProperty;
  18. use JMS\Serializer\Annotation\SerializedName;
  19. use JMS\Serializer\Annotation\Since;
  20. use JMS\Serializer\Annotation\SkipWhenEmpty;
  21. use JMS\Serializer\Annotation\Type;
  22. use JMS\Serializer\Annotation\Until;
  23. use JMS\Serializer\Annotation\VirtualProperty;
  24. use JMS\Serializer\Annotation\XmlAttribute;
  25. use JMS\Serializer\Annotation\XmlAttributeMap;
  26. use JMS\Serializer\Annotation\XmlDiscriminator;
  27. use JMS\Serializer\Annotation\XmlElement;
  28. use JMS\Serializer\Annotation\XmlKeyValuePairs;
  29. use JMS\Serializer\Annotation\XmlList;
  30. use JMS\Serializer\Annotation\XmlMap;
  31. use JMS\Serializer\Annotation\XmlNamespace;
  32. use JMS\Serializer\Annotation\XmlRoot;
  33. use JMS\Serializer\Annotation\XmlValue;
  34. use JMS\Serializer\Exception\InvalidMetadataException;
  35. use JMS\Serializer\Expression\CompilableExpressionEvaluatorInterface;
  36. use JMS\Serializer\Metadata\ClassMetadata;
  37. use JMS\Serializer\Metadata\ExpressionPropertyMetadata;
  38. use JMS\Serializer\Metadata\PropertyMetadata;
  39. use JMS\Serializer\Metadata\VirtualPropertyMetadata;
  40. use JMS\Serializer\Naming\PropertyNamingStrategyInterface;
  41. use JMS\Serializer\Type\Parser;
  42. use JMS\Serializer\Type\ParserInterface;
  43. use Metadata\ClassMetadata as BaseClassMetadata;
  44. use Metadata\Driver\DriverInterface;
  45. use Metadata\MethodMetadata;
  46. abstract class AnnotationOrAttributeDriver implements DriverInterface
  47. {
  48.     use ExpressionMetadataTrait;
  49.     /**
  50.      * @var ParserInterface
  51.      */
  52.     private $typeParser;
  53.     /**
  54.      * @var PropertyNamingStrategyInterface
  55.      */
  56.     private $namingStrategy;
  57.     public function __construct(PropertyNamingStrategyInterface $namingStrategy, ?ParserInterface $typeParser null, ?CompilableExpressionEvaluatorInterface $expressionEvaluator null)
  58.     {
  59.         $this->typeParser $typeParser ?: new Parser();
  60.         $this->namingStrategy $namingStrategy;
  61.         $this->expressionEvaluator $expressionEvaluator;
  62.     }
  63.     public function loadMetadataForClass(\ReflectionClass $class): ?BaseClassMetadata
  64.     {
  65.         $classMetadata = new ClassMetadata($name $class->name);
  66.         $fileResource =  $class->getFilename();
  67.         if (false !== $fileResource) {
  68.             $classMetadata->fileResources[] = $fileResource;
  69.         }
  70.         $propertiesMetadata = [];
  71.         $propertiesAnnotations = [];
  72.         $exclusionPolicy ExclusionPolicy::NONE;
  73.         $excludeAll false;
  74.         $classAccessType PropertyMetadata::ACCESS_TYPE_PROPERTY;
  75.         $readOnlyClass false;
  76.         foreach ($this->getClassAnnotations($class) as $annot) {
  77.             if ($annot instanceof ExclusionPolicy) {
  78.                 $exclusionPolicy $annot->policy;
  79.             } elseif ($annot instanceof XmlRoot) {
  80.                 $classMetadata->xmlRootName $annot->name;
  81.                 $classMetadata->xmlRootNamespace $annot->namespace;
  82.                 $classMetadata->xmlRootPrefix $annot->prefix;
  83.             } elseif ($annot instanceof XmlNamespace) {
  84.                 $classMetadata->registerNamespace($annot->uri$annot->prefix);
  85.             } elseif ($annot instanceof Exclude) {
  86.                 if (null !== $annot->if) {
  87.                     $classMetadata->excludeIf $this->parseExpression($annot->if);
  88.                 } else {
  89.                     $excludeAll true;
  90.                 }
  91.             } elseif ($annot instanceof AccessType) {
  92.                 $classAccessType $annot->type;
  93.             } elseif ($annot instanceof ReadOnlyProperty) {
  94.                 $readOnlyClass true;
  95.             } elseif ($annot instanceof AccessorOrder) {
  96.                 $classMetadata->setAccessorOrder($annot->order$annot->custom);
  97.             } elseif ($annot instanceof Discriminator) {
  98.                 if ($annot->disabled) {
  99.                     $classMetadata->discriminatorDisabled true;
  100.                 } else {
  101.                     $classMetadata->setDiscriminator($annot->field$annot->map$annot->groups);
  102.                 }
  103.             } elseif ($annot instanceof XmlDiscriminator) {
  104.                 $classMetadata->xmlDiscriminatorAttribute = (bool) $annot->attribute;
  105.                 $classMetadata->xmlDiscriminatorCData = (bool) $annot->cdata;
  106.                 $classMetadata->xmlDiscriminatorNamespace $annot->namespace ? (string) $annot->namespace null;
  107.             } elseif ($annot instanceof VirtualProperty) {
  108.                 $virtualPropertyMetadata = new ExpressionPropertyMetadata(
  109.                     $name,
  110.                     $annot->name,
  111.                     $this->parseExpression($annot->exp)
  112.                 );
  113.                 $propertiesMetadata[] = $virtualPropertyMetadata;
  114.                 $propertiesAnnotations[] = $annot->options;
  115.             }
  116.         }
  117.         foreach ($class->getMethods() as $method) {
  118.             if ($method->class !== $name) {
  119.                 continue;
  120.             }
  121.             $methodAnnotations $this->getMethodAnnotations($method);
  122.             foreach ($methodAnnotations as $annot) {
  123.                 if ($annot instanceof PreSerialize) {
  124.                     $classMetadata->addPreSerializeMethod(new MethodMetadata($name$method->name));
  125.                     continue 2;
  126.                 } elseif ($annot instanceof PostDeserialize) {
  127.                     $classMetadata->addPostDeserializeMethod(new MethodMetadata($name$method->name));
  128.                     continue 2;
  129.                 } elseif ($annot instanceof PostSerialize) {
  130.                     $classMetadata->addPostSerializeMethod(new MethodMetadata($name$method->name));
  131.                     continue 2;
  132.                 } elseif ($annot instanceof VirtualProperty) {
  133.                     $virtualPropertyMetadata = new VirtualPropertyMetadata($name$method->name);
  134.                     $propertiesMetadata[] = $virtualPropertyMetadata;
  135.                     $propertiesAnnotations[] = $methodAnnotations;
  136.                     continue 2;
  137.                 }
  138.             }
  139.         }
  140.         if (!$excludeAll) {
  141.             foreach ($class->getProperties() as $property) {
  142.                 if ($property->class !== $name || (isset($property->info) && $property->info['class'] !== $name)) {
  143.                     continue;
  144.                 }
  145.                 $propertiesMetadata[] = new PropertyMetadata($name$property->getName());
  146.                 $propertiesAnnotations[] = $this->getPropertyAnnotations($property);
  147.             }
  148.             foreach ($propertiesMetadata as $propertyKey => $propertyMetadata) {
  149.                 $isExclude false;
  150.                 $isExpose $propertyMetadata instanceof VirtualPropertyMetadata
  151.                     || $propertyMetadata instanceof ExpressionPropertyMetadata;
  152.                 $propertyMetadata->readOnly $propertyMetadata->readOnly || $readOnlyClass;
  153.                 $accessType $classAccessType;
  154.                 $accessor = [nullnull];
  155.                 $propertyAnnotations $propertiesAnnotations[$propertyKey];
  156.                 foreach ($propertyAnnotations as $annot) {
  157.                     if ($annot instanceof Since) {
  158.                         $propertyMetadata->sinceVersion $annot->version;
  159.                     } elseif ($annot instanceof Until) {
  160.                         $propertyMetadata->untilVersion $annot->version;
  161.                     } elseif ($annot instanceof SerializedName) {
  162.                         $propertyMetadata->serializedName $annot->name;
  163.                     } elseif ($annot instanceof SkipWhenEmpty) {
  164.                         $propertyMetadata->skipWhenEmpty true;
  165.                     } elseif ($annot instanceof Expose) {
  166.                         $isExpose true;
  167.                         if (null !== $annot->if) {
  168.                             $propertyMetadata->excludeIf $this->parseExpression('!(' $annot->if ')');
  169.                         }
  170.                     } elseif ($annot instanceof Exclude) {
  171.                         if (null !== $annot->if) {
  172.                             $propertyMetadata->excludeIf $this->parseExpression($annot->if);
  173.                         } else {
  174.                             $isExclude true;
  175.                         }
  176.                     } elseif ($annot instanceof Type) {
  177.                         $propertyMetadata->setType($this->typeParser->parse($annot->name));
  178.                     } elseif ($annot instanceof XmlElement) {
  179.                         $propertyMetadata->xmlAttribute false;
  180.                         $propertyMetadata->xmlElementCData $annot->cdata;
  181.                         $propertyMetadata->xmlNamespace $annot->namespace;
  182.                     } elseif ($annot instanceof XmlList) {
  183.                         $propertyMetadata->xmlCollection true;
  184.                         $propertyMetadata->xmlCollectionInline $annot->inline;
  185.                         $propertyMetadata->xmlEntryName $annot->entry;
  186.                         $propertyMetadata->xmlEntryNamespace $annot->namespace;
  187.                         $propertyMetadata->xmlCollectionSkipWhenEmpty $annot->skipWhenEmpty;
  188.                     } elseif ($annot instanceof XmlMap) {
  189.                         $propertyMetadata->xmlCollection true;
  190.                         $propertyMetadata->xmlCollectionInline $annot->inline;
  191.                         $propertyMetadata->xmlEntryName $annot->entry;
  192.                         $propertyMetadata->xmlEntryNamespace $annot->namespace;
  193.                         $propertyMetadata->xmlKeyAttribute $annot->keyAttribute;
  194.                     } elseif ($annot instanceof XmlKeyValuePairs) {
  195.                         $propertyMetadata->xmlKeyValuePairs true;
  196.                     } elseif ($annot instanceof XmlAttribute) {
  197.                         $propertyMetadata->xmlAttribute true;
  198.                         $propertyMetadata->xmlNamespace $annot->namespace;
  199.                     } elseif ($annot instanceof XmlValue) {
  200.                         $propertyMetadata->xmlValue true;
  201.                         $propertyMetadata->xmlElementCData $annot->cdata;
  202.                     } elseif ($annot instanceof AccessType) {
  203.                         $accessType $annot->type;
  204.                     } elseif ($annot instanceof ReadOnlyProperty) {
  205.                         $propertyMetadata->readOnly $annot->readOnly;
  206.                     } elseif ($annot instanceof Accessor) {
  207.                         $accessor = [$annot->getter$annot->setter];
  208.                     } elseif ($annot instanceof Groups) {
  209.                         $propertyMetadata->groups $annot->groups;
  210.                         foreach ((array) $propertyMetadata->groups as $groupName) {
  211.                             if (false !== strpos($groupName',')) {
  212.                                 throw new InvalidMetadataException(sprintf(
  213.                                     'Invalid group name "%s" on "%s", did you mean to create multiple groups?',
  214.                                     implode(', '$propertyMetadata->groups),
  215.                                     $propertyMetadata->class '->' $propertyMetadata->name
  216.                                 ));
  217.                             }
  218.                         }
  219.                     } elseif ($annot instanceof Inline) {
  220.                         $propertyMetadata->inline true;
  221.                     } elseif ($annot instanceof XmlAttributeMap) {
  222.                         $propertyMetadata->xmlAttributeMap true;
  223.                     } elseif ($annot instanceof MaxDepth) {
  224.                         $propertyMetadata->maxDepth $annot->depth;
  225.                     }
  226.                 }
  227.                 if ($propertyMetadata->inline) {
  228.                     $classMetadata->isList $classMetadata->isList || PropertyMetadata::isCollectionList($propertyMetadata->type);
  229.                     $classMetadata->isMap $classMetadata->isMap || PropertyMetadata::isCollectionMap($propertyMetadata->type);
  230.                     if ($classMetadata->isMap && $classMetadata->isList) {
  231.                         throw new InvalidMetadataException('Can not have an inline map and and inline map on the same class');
  232.                     }
  233.                 }
  234.                 if (!$propertyMetadata->serializedName) {
  235.                     $propertyMetadata->serializedName $this->namingStrategy->translateName($propertyMetadata);
  236.                 }
  237.                 foreach ($propertyAnnotations as $annot) {
  238.                     if ($annot instanceof VirtualProperty && null !== $annot->name) {
  239.                         $propertyMetadata->name $annot->name;
  240.                     }
  241.                 }
  242.                 if (
  243.                     (ExclusionPolicy::NONE === $exclusionPolicy && !$isExclude)
  244.                     || (ExclusionPolicy::ALL === $exclusionPolicy && $isExpose)
  245.                 ) {
  246.                     $propertyMetadata->setAccessor($accessType$accessor[0], $accessor[1]);
  247.                     $classMetadata->addPropertyMetadata($propertyMetadata);
  248.                 }
  249.             }
  250.         }
  251.         return $classMetadata;
  252.     }
  253.     /**
  254.      * @return list<object>
  255.      */
  256.     abstract protected function getClassAnnotations(\ReflectionClass $class): array;
  257.     /**
  258.      * @return list<object>
  259.      */
  260.     abstract protected function getMethodAnnotations(\ReflectionMethod $method): array;
  261.     /**
  262.      * @return list<object>
  263.      */
  264.     abstract protected function getPropertyAnnotations(\ReflectionProperty $property): array;
  265. }