reader = $reader; $this->typeParser = $typeParser ?: new Parser(); $this->namingStrategy = $namingStrategy; $this->expressionEvaluator = $expressionEvaluator; } public function loadMetadataForClass(\ReflectionClass $class): ?BaseClassMetadata { $classMetadata = new ClassMetadata($name = $class->name); $fileResource = $class->getFilename(); if (false !== $fileResource) { $classMetadata->fileResources[] = $fileResource; } $propertiesMetadata = []; $propertiesAnnotations = []; $exclusionPolicy = 'NONE'; $excludeAll = false; $classAccessType = PropertyMetadata::ACCESS_TYPE_PROPERTY; $readOnlyClass = false; foreach ($this->reader->getClassAnnotations($class) as $annot) { if ($annot instanceof ExclusionPolicy) { $exclusionPolicy = $annot->policy; } elseif ($annot instanceof XmlRoot) { $classMetadata->xmlRootName = $annot->name; $classMetadata->xmlRootNamespace = $annot->namespace; $classMetadata->xmlRootPrefix = $annot->prefix; } elseif ($annot instanceof XmlNamespace) { $classMetadata->registerNamespace($annot->uri, $annot->prefix); } elseif ($annot instanceof Exclude) { $excludeAll = true; } elseif ($annot instanceof AccessType) { $classAccessType = $annot->type; } elseif ($annot instanceof ReadOnly) { $readOnlyClass = true; } elseif ($annot instanceof AccessorOrder) { $classMetadata->setAccessorOrder($annot->order, $annot->custom); } elseif ($annot instanceof Discriminator) { if ($annot->disabled) { $classMetadata->discriminatorDisabled = true; } else { $classMetadata->setDiscriminator($annot->field, $annot->map, $annot->groups); } } elseif ($annot instanceof XmlDiscriminator) { $classMetadata->xmlDiscriminatorAttribute = (bool) $annot->attribute; $classMetadata->xmlDiscriminatorCData = (bool) $annot->cdata; $classMetadata->xmlDiscriminatorNamespace = $annot->namespace ? (string) $annot->namespace : null; } elseif ($annot instanceof VirtualProperty) { $virtualPropertyMetadata = new ExpressionPropertyMetadata( $name, $annot->name, $this->parseExpression($annot->exp) ); $propertiesMetadata[] = $virtualPropertyMetadata; $propertiesAnnotations[] = $annot->options; } } foreach ($class->getMethods() as $method) { if ($method->class !== $name) { continue; } $methodAnnotations = $this->reader->getMethodAnnotations($method); foreach ($methodAnnotations as $annot) { if ($annot instanceof PreSerialize) { $classMetadata->addPreSerializeMethod(new MethodMetadata($name, $method->name)); continue 2; } elseif ($annot instanceof PostDeserialize) { $classMetadata->addPostDeserializeMethod(new MethodMetadata($name, $method->name)); continue 2; } elseif ($annot instanceof PostSerialize) { $classMetadata->addPostSerializeMethod(new MethodMetadata($name, $method->name)); continue 2; } elseif ($annot instanceof VirtualProperty) { $virtualPropertyMetadata = new VirtualPropertyMetadata($name, $method->name); $propertiesMetadata[] = $virtualPropertyMetadata; $propertiesAnnotations[] = $methodAnnotations; continue 2; } } } if (!$excludeAll) { foreach ($class->getProperties() as $property) { if ($property->class !== $name || (isset($property->info) && $property->info['class'] !== $name)) { continue; } $propertiesMetadata[] = new PropertyMetadata($name, $property->getName()); $propertiesAnnotations[] = $this->reader->getPropertyAnnotations($property); } foreach ($propertiesMetadata as $propertyKey => $propertyMetadata) { $isExclude = false; $isExpose = $propertyMetadata instanceof VirtualPropertyMetadata || $propertyMetadata instanceof ExpressionPropertyMetadata; $propertyMetadata->readOnly = $propertyMetadata->readOnly || $readOnlyClass; $accessType = $classAccessType; $accessor = [null, null]; $propertyAnnotations = $propertiesAnnotations[$propertyKey]; foreach ($propertyAnnotations as $annot) { if ($annot instanceof Since) { $propertyMetadata->sinceVersion = $annot->version; } elseif ($annot instanceof Until) { $propertyMetadata->untilVersion = $annot->version; } elseif ($annot instanceof SerializedName) { $propertyMetadata->serializedName = $annot->name; } elseif ($annot instanceof SkipWhenEmpty) { $propertyMetadata->skipWhenEmpty = true; } elseif ($annot instanceof Expose) { $isExpose = true; if (null !== $annot->if) { $propertyMetadata->excludeIf = $this->parseExpression('!(' . $annot->if . ')'); } } elseif ($annot instanceof Exclude) { if (null !== $annot->if) { $propertyMetadata->excludeIf = $this->parseExpression($annot->if); } else { $isExclude = true; } } elseif ($annot instanceof Type) { $propertyMetadata->setType($this->typeParser->parse($annot->name)); } elseif ($annot instanceof XmlElement) { $propertyMetadata->xmlAttribute = false; $propertyMetadata->xmlElementCData = $annot->cdata; $propertyMetadata->xmlNamespace = $annot->namespace; } elseif ($annot instanceof XmlList) { $propertyMetadata->xmlCollection = true; $propertyMetadata->xmlCollectionInline = $annot->inline; $propertyMetadata->xmlEntryName = $annot->entry; $propertyMetadata->xmlEntryNamespace = $annot->namespace; $propertyMetadata->xmlCollectionSkipWhenEmpty = $annot->skipWhenEmpty; } elseif ($annot instanceof XmlMap) { $propertyMetadata->xmlCollection = true; $propertyMetadata->xmlCollectionInline = $annot->inline; $propertyMetadata->xmlEntryName = $annot->entry; $propertyMetadata->xmlEntryNamespace = $annot->namespace; $propertyMetadata->xmlKeyAttribute = $annot->keyAttribute; } elseif ($annot instanceof XmlKeyValuePairs) { $propertyMetadata->xmlKeyValuePairs = true; } elseif ($annot instanceof XmlAttribute) { $propertyMetadata->xmlAttribute = true; $propertyMetadata->xmlNamespace = $annot->namespace; } elseif ($annot instanceof XmlValue) { $propertyMetadata->xmlValue = true; $propertyMetadata->xmlElementCData = $annot->cdata; } elseif ($annot instanceof XmlElement) { $propertyMetadata->xmlElementCData = $annot->cdata; } elseif ($annot instanceof AccessType) { $accessType = $annot->type; } elseif ($annot instanceof ReadOnly) { $propertyMetadata->readOnly = $annot->readOnly; } elseif ($annot instanceof Accessor) { $accessor = [$annot->getter, $annot->setter]; } elseif ($annot instanceof Groups) { $propertyMetadata->groups = $annot->groups; foreach ((array) $propertyMetadata->groups as $groupName) { if (false !== strpos($groupName, ',')) { throw new InvalidMetadataException(sprintf( 'Invalid group name "%s" on "%s", did you mean to create multiple groups?', implode(', ', $propertyMetadata->groups), $propertyMetadata->class . '->' . $propertyMetadata->name )); } } } elseif ($annot instanceof Inline) { $propertyMetadata->inline = true; } elseif ($annot instanceof XmlAttributeMap) { $propertyMetadata->xmlAttributeMap = true; } elseif ($annot instanceof MaxDepth) { $propertyMetadata->maxDepth = $annot->depth; } } if ($propertyMetadata->inline) { $classMetadata->isList = $classMetadata->isList || PropertyMetadata::isCollectionList($propertyMetadata->type); $classMetadata->isMap = $classMetadata->isMap || PropertyMetadata::isCollectionMap($propertyMetadata->type); if ($classMetadata->isMap && $classMetadata->isList) { throw new InvalidMetadataException('Can not have an inline map and and inline map on the same class'); } } if (!$propertyMetadata->serializedName) { $propertyMetadata->serializedName = $this->namingStrategy->translateName($propertyMetadata); } foreach ($propertyAnnotations as $annot) { if ($annot instanceof VirtualProperty && null !== $annot->name) { $propertyMetadata->name = $annot->name; } } if ((ExclusionPolicy::NONE === $exclusionPolicy && !$isExclude) || (ExclusionPolicy::ALL === $exclusionPolicy && $isExpose) ) { $propertyMetadata->setAccessor($accessType, $accessor[0], $accessor[1]); $classMetadata->addPropertyMetadata($propertyMetadata); } } } return $classMetadata; } }