public function testSetAccessorOrderAlphabetical() { $metadata = new ClassMetadata('JMS\\Serializer\\Tests\\Metadata\\PropertyMetadataOrder'); $metadata->addPropertyMetadata(new PropertyMetadata('JMS\\Serializer\\Tests\\Metadata\\PropertyMetadataOrder', 'b')); $metadata->addPropertyMetadata(new PropertyMetadata('JMS\\Serializer\\Tests\\Metadata\\PropertyMetadataOrder', 'a')); $this->assertEquals(array('b', 'a'), array_keys($metadata->propertyMetadata)); $metadata->setAccessorOrder(ClassMetadata::ACCESSOR_ORDER_ALPHABETICAL); $this->assertEquals(array('a', 'b'), array_keys($metadata->propertyMetadata)); }
/** * @dataProvider setAccessorOrderDataProvider */ public function testSetAccessorOrder($order, array $customOrder, $expected, $message) { $class = 'JMS\\Serializer\\Tests\\Metadata\\PropertyMetadataOrder'; // Note: defined in this file below ClassMetadataTest $metadata = new ClassMetadata($class); $metadata->addPropertyMetadata(new PropertyMetadata($class, 'z')); $metadata->addPropertyMetadata(new PropertyMetadata($class, 'a')); $metadata->addPropertyMetadata(new PropertyMetadata($class, 'b')); $metadata->addPropertyMetadata(new PropertyMetadata($class, 'c')); if ($order) { $metadata->setAccessorOrder($order, $customOrder); } $this->assertEquals($expected, array_keys($metadata->propertyMetadata), $message); }
public function testSetAccessorOrder() { $metadata = new ClassMetadata('JMS\\Serializer\\Tests\\Metadata\\PropertyMetadataOrder'); $metadata->addPropertyMetadata(new PropertyMetadata('JMS\\Serializer\\Tests\\Metadata\\PropertyMetadataOrder', 'b')); $metadata->addPropertyMetadata(new PropertyMetadata('JMS\\Serializer\\Tests\\Metadata\\PropertyMetadataOrder', 'a')); $this->assertEquals(array('b', 'a'), array_keys($metadata->propertyMetadata)); $metadata->setAccessorOrder(ClassMetadata::ACCESSOR_ORDER_ALPHABETICAL); $this->assertEquals(array('a', 'b'), array_keys($metadata->propertyMetadata)); $metadata->setAccessorOrder(ClassMetadata::ACCESSOR_ORDER_CUSTOM, array('b', 'a')); $this->assertEquals(array('b', 'a'), array_keys($metadata->propertyMetadata)); $metadata->setAccessorOrder(ClassMetadata::ACCESSOR_ORDER_CUSTOM, array('a', 'b')); $this->assertEquals(array('a', 'b'), array_keys($metadata->propertyMetadata)); $metadata->setAccessorOrder(ClassMetadata::ACCESSOR_ORDER_CUSTOM, array('b')); $this->assertEquals(array('b', 'a'), array_keys($metadata->propertyMetadata)); $metadata->setAccessorOrder(ClassMetadata::ACCESSOR_ORDER_CUSTOM, array('a')); $this->assertEquals(array('a', 'b'), array_keys($metadata->propertyMetadata)); //We're not sure, in which order array will be sorted. //We only know, that it should contain both properties $metadata->setAccessorOrder(ClassMetadata::ACCESSOR_ORDER_CUSTOM, array('foo', 'bar')); $this->assertArrayHasKey('a', $metadata->propertyMetadata); $this->assertArrayHasKey('b', $metadata->propertyMetadata); $this->assertCount(2, $metadata->propertyMetadata); }
private function addClassProperties(ClassMetadata $metadata, array $config) { if (isset($config['custom_accessor_order']) && !isset($config['accessor_order'])) { $config['accessor_order'] = 'custom'; } if (isset($config['accessor_order'])) { $metadata->setAccessorOrder($config['accessor_order'], isset($config['custom_accessor_order']) ? $config['custom_accessor_order'] : array()); } if (isset($config['xml_root_name'])) { $metadata->xmlRootName = (string) $config['xml_root_name']; } if (isset($config['xml_root_namespace'])) { $metadata->xmlRootNamespace = (string) $config['xml_root_namespace']; } if (array_key_exists('xml_namespaces', $config)) { foreach ($config['xml_namespaces'] as $prefix => $uri) { $metadata->registerNamespace($uri, $prefix); } } if (isset($config['discriminator'])) { if (isset($config['discriminator']['disabled']) && true === $config['discriminator']['disabled']) { $metadata->discriminatorDisabled = true; } else { if (!isset($config['discriminator']['field_name'])) { throw new RuntimeException('The "field_name" attribute must be set for discriminators.'); } if (!isset($config['discriminator']['map']) || !is_array($config['discriminator']['map'])) { throw new RuntimeException('The "map" attribute must be set, and be an array for discriminators.'); } $metadata->setDiscriminator($config['discriminator']['field_name'], $config['discriminator']['map']); } } }
public function loadMetadataForClass(\ReflectionClass $class) { $classMetadata = new ClassMetadata($name = $class->name); $classMetadata->fileResources[] = $class->getFilename(); $propertiesMetadata = array(); $propertiesAnnotations = array(); $exclusionPolicy = 'NONE'; $excludeAll = false; $classAccessType = PropertyMetadata::ACCESS_TYPE_PROPERTY; foreach ($this->reader->getClassAnnotations($class) as $annot) { if ($annot instanceof ExclusionPolicy) { $exclusionPolicy = $annot->policy; } elseif ($annot instanceof XmlRoot) { $classMetadata->xmlRootName = $annot->name; } elseif ($annot instanceof Exclude) { $excludeAll = true; } elseif ($annot instanceof AccessType) { $classAccessType = $annot->type; } 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); } } } 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; } elseif ($annot instanceof HandlerCallback) { $classMetadata->addHandlerCallback(GraphNavigator::parseDirection($annot->direction), $annot->format, $method->name); continue 2; } } } if (!$excludeAll) { foreach ($class->getProperties() as $property) { if ($property->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; $accessType = $classAccessType; $accessor = array(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 Expose) { $isExpose = true; } elseif ($annot instanceof Exclude) { $isExclude = true; } elseif ($annot instanceof Type) { $propertyMetadata->setType($annot->name); } elseif ($annot instanceof XmlList) { $propertyMetadata->xmlCollection = true; $propertyMetadata->xmlCollectionInline = $annot->inline; $propertyMetadata->xmlEntryName = $annot->entry; } elseif ($annot instanceof XmlMap) { $propertyMetadata->xmlCollection = true; $propertyMetadata->xmlCollectionInline = $annot->inline; $propertyMetadata->xmlEntryName = $annot->entry; $propertyMetadata->xmlKeyAttribute = $annot->keyAttribute; } elseif ($annot instanceof XmlKeyValuePairs) { $propertyMetadata->xmlKeyValuePairs = true; } elseif ($annot instanceof XmlAttribute) { $propertyMetadata->xmlAttribute = true; } 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 = true; } elseif ($annot instanceof Accessor) { $accessor = array($annot->getter, $annot->setter); } elseif ($annot instanceof Groups) { $propertyMetadata->groups = $annot->groups; foreach ((array) $propertyMetadata->groups as $groupName) { if (false !== strpos($groupName, ',')) { throw new InvalidArgumentException(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; } } $propertyMetadata->setAccessor($accessType, $accessor[0], $accessor[1]); if (ExclusionPolicy::NONE === $exclusionPolicy && !$isExclude || ExclusionPolicy::ALL === $exclusionPolicy && $isExpose) { $classMetadata->addPropertyMetadata($propertyMetadata); } } } return $classMetadata; }
protected function loadMetadataFromFile(\ReflectionClass $class, $path) { $previous = libxml_use_internal_errors(true); $elem = simplexml_load_file($path); libxml_use_internal_errors($previous); if (false === $elem) { throw new XmlErrorException(libxml_get_last_error()); } $metadata = new ClassMetadata($name = $class->name); if (!($elems = $elem->xpath("./class[@name = '" . $name . "']"))) { throw new RuntimeException(sprintf('Could not find class %s inside XML element.', $name)); } $elem = reset($elems); $metadata->fileResources[] = $path; $metadata->fileResources[] = $class->getFileName(); $exclusionPolicy = strtoupper($elem->attributes()->{'exclusion-policy'}) ?: 'NONE'; $excludeAll = null !== ($exclude = $elem->attributes()->exclude) ? 'true' === strtolower($exclude) : false; $classAccessType = (string) ($elem->attributes()->{'access-type'} ?: PropertyMetadata::ACCESS_TYPE_PROPERTY); $propertiesMetadata = array(); $propertiesNodes = array(); if (null !== ($accessorOrder = $elem->attributes()->{'accessor-order'})) { $metadata->setAccessorOrder((string) $accessorOrder, preg_split('/\\s*,\\s*/', (string) $elem->attributes()->{'custom-accessor-order'})); } if (null !== ($xmlRootName = $elem->attributes()->{'xml-root-name'})) { $metadata->xmlRootName = (string) $xmlRootName; } $discriminatorFieldName = (string) $elem->attributes()->{'discriminator-field-name'}; $discriminatorMap = array(); foreach ($elem->xpath('./discriminator-class') as $entry) { if (!isset($entry->attributes()->value)) { throw new RuntimeException('Each discriminator-class element must have a "value" attribute.'); } $discriminatorMap[(string) $entry->attributes()->value] = (string) $entry; } if ('true' === (string) $elem->attributes()->{'discriminator-disabled'}) { $metadata->discriminatorDisabled = true; } elseif (!empty($discriminatorFieldName) || !empty($discriminatorMap)) { $metadata->setDiscriminator($discriminatorFieldName, $discriminatorMap); } foreach ($elem->xpath('./virtual-property') as $method) { if (!isset($method->attributes()->method)) { throw new RuntimeException('The method attribute must be set for all virtual-property elements.'); } $virtualPropertyMetadata = new VirtualPropertyMetadata($name, (string) $method->attributes()->method); $propertiesMetadata[] = $virtualPropertyMetadata; $propertiesNodes[] = $method; } if (!$excludeAll) { foreach ($class->getProperties() as $property) { if ($name !== $property->class) { continue; } $propertiesMetadata[] = new PropertyMetadata($name, $pName = $property->getName()); $pElems = $elem->xpath("./property[@name = '" . $pName . "']"); $propertiesNodes[] = $pElems ? reset($pElems) : null; } foreach ($propertiesMetadata as $propertyKey => $pMetadata) { $isExclude = false; $isExpose = $pMetadata instanceof VirtualPropertyMetadata; $pElem = $propertiesNodes[$propertyKey]; if (!empty($pElem)) { if (null !== ($exclude = $pElem->attributes()->exclude)) { $isExclude = 'true' === strtolower($exclude); } if (null !== ($expose = $pElem->attributes()->expose)) { $isExpose = 'true' === strtolower($expose); } if (null !== ($version = $pElem->attributes()->{'since-version'})) { $pMetadata->sinceVersion = (string) $version; } if (null !== ($version = $pElem->attributes()->{'until-version'})) { $pMetadata->untilVersion = (string) $version; } if (null !== ($serializedName = $pElem->attributes()->{'serialized-name'})) { $pMetadata->serializedName = (string) $serializedName; } if (null !== ($type = $pElem->attributes()->type)) { $pMetadata->setType((string) $type); } elseif (isset($pElem->type)) { $pMetadata->setType((string) $pElem->type); } if (null !== ($groups = $pElem->attributes()->groups)) { $pMetadata->groups = preg_split('/\\s*,\\s*/', (string) $groups); } if (isset($pElem->{'xml-list'})) { $pMetadata->xmlCollection = true; $colConfig = $pElem->{'xml-list'}; if (isset($colConfig->attributes()->inline)) { $pMetadata->xmlCollectionInline = 'true' === (string) $colConfig->attributes()->inline; } if (isset($colConfig->attributes()->{'entry-name'})) { $pMetadata->xmlEntryName = (string) $colConfig->attributes()->{'entry-name'}; } } if (isset($pElem->{'xml-map'})) { $pMetadata->xmlCollection = true; $colConfig = $pElem->{'xml-map'}; if (isset($colConfig->attributes()->inline)) { $pMetadata->xmlCollectionInline = 'true' === (string) $colConfig->attributes()->inline; } if (isset($colConfig->attributes()->{'entry-name'})) { $pMetadata->xmlEntryName = (string) $colConfig->attributes()->{'entry-name'}; } if (isset($colConfig->attributes()->{'key-attribute-name'})) { $pMetadata->xmlKeyAttribute = (string) $colConfig->attributes()->{'key-attribute-name'}; } } if (isset($pElem->attributes()->{'xml-attribute'})) { $pMetadata->xmlAttribute = 'true' === (string) $pElem->attributes()->{'xml-attribute'}; } if (isset($pElem->attributes()->{'xml-attribute-map'})) { $pMetadata->xmlAttribute = 'true' === (string) $pElem->attributes()->{'xml-attribute-map'}; } if (isset($pElem->attributes()->{'xml-value'})) { $pMetadata->xmlValue = 'true' === (string) $pElem->attributes()->{'xml-value'}; } if (isset($pElem->attributes()->{'xml-key-value-pairs'})) { $pMetadata->xmlKeyValuePairs = 'true' === (string) $pElem->attributes()->{'xml-key-value-pairs'}; } //we need read-only before setter and getter set, because that method depends on flag being set if (null !== ($readOnly = $pElem->attributes()->{'read-only'})) { $pMetadata->readOnly = 'true' === strtolower($readOnly); } $getter = $pElem->attributes()->{'accessor-getter'}; $setter = $pElem->attributes()->{'accessor-setter'}; $pMetadata->setAccessor((string) ($pElem->attributes()->{'access-type'} ?: $classAccessType), $getter ? (string) $getter : null, $setter ? (string) $setter : null); if (null !== ($inline = $pElem->attributes()->inline)) { $pMetadata->inline = 'true' === strtolower($inline); } } if (ExclusionPolicy::NONE === (string) $exclusionPolicy && !$isExclude || ExclusionPolicy::ALL === (string) $exclusionPolicy && $isExpose) { $metadata->addPropertyMetadata($pMetadata); } } } foreach ($elem->xpath('./callback-method') as $method) { if (!isset($method->attributes()->type)) { throw new RuntimeException('The type attribute must be set for all callback-method elements.'); } if (!isset($method->attributes()->name)) { throw new RuntimeException('The name attribute must be set for all callback-method elements.'); } switch ((string) $method->attributes()->type) { case 'pre-serialize': $metadata->addPreSerializeMethod(new MethodMetadata($name, (string) $method->attributes()->name)); break; case 'post-serialize': $metadata->addPostSerializeMethod(new MethodMetadata($name, (string) $method->attributes()->name)); break; case 'post-deserialize': $metadata->addPostDeserializeMethod(new MethodMetadata($name, (string) $method->attributes()->name)); break; case 'handler': if (!isset($method->attributes()->format)) { throw new RuntimeException('The format attribute must be set for "handler" callback methods.'); } if (!isset($method->attributes()->direction)) { throw new RuntimeException('The direction attribute must be set for "handler" callback methods.'); } $direction = GraphNavigator::parseDirection((string) $method->attributes()->direction); $format = (string) $method->attributes()->format; $metadata->addHandlerCallback($direction, $format, (string) $method->attributes()->name); break; default: throw new RuntimeException(sprintf('The type "%s" is not supported.', $method->attributes()->name)); } } return $metadata; }
protected function loadMetadataFromFile(\ReflectionClass $class, $file) { $config = Yaml::parse(file_get_contents($file)); if (!isset($config[$name = $class->name])) { throw new RuntimeException(sprintf('Expected metadata for class %s to be defined in %s.', $class->name, $file)); } $config = $config[$name]; $metadata = new ClassMetadata($name); $metadata->fileResources[] = $file; $metadata->fileResources[] = $class->getFileName(); $exclusionPolicy = isset($config['exclusion_policy']) ? strtoupper($config['exclusion_policy']) : 'NONE'; $excludeAll = isset($config['exclude']) ? (bool) $config['exclude'] : false; $classAccessType = isset($config['access_type']) ? $config['access_type'] : PropertyMetadata::ACCESS_TYPE_PROPERTY; $propertiesMetadata = array(); if (isset($config['accessor_order'])) { $metadata->setAccessorOrder($config['accessor_order'], isset($config['custom_accessor_order']) ? $config['custom_accessor_order'] : array()); } if (isset($config['xml_root_name'])) { $metadata->xmlRootName = (string) $config['xml_root_name']; } if (isset($config['discriminator'])) { if (isset($config['discriminator']['disabled']) && true === $config['discriminator']['disabled']) { $metadata->discriminatorDisabled = true; } else { if (!isset($config['discriminator']['field_name'])) { throw new RuntimeException('The "field_name" attribute must be set for discriminators.'); } if (!isset($config['discriminator']['map']) || !is_array($config['discriminator']['map'])) { throw new RuntimeException('The "map" attribute must be set, and be an array for discriminators.'); } $metadata->setDiscriminator($config['discriminator']['field_name'], $config['discriminator']['map']); } } if (array_key_exists('virtual_properties', $config)) { foreach ($config['virtual_properties'] as $methodName => $propertySettings) { if (!$class->hasMethod($methodName)) { throw new RuntimeException('The method ' . $methodName . ' not found in class ' . $class->name); } $virtualPropertyMetadata = new VirtualPropertyMetadata($name, $methodName); $propertiesMetadata[$methodName] = $virtualPropertyMetadata; $config['properties'][$methodName] = $propertySettings; } } if (!$excludeAll) { foreach ($class->getProperties() as $property) { if ($name !== $property->class) { continue; } $pName = $property->getName(); $propertiesMetadata[$pName] = new PropertyMetadata($name, $pName); } foreach ($propertiesMetadata as $pName => $pMetadata) { $isExclude = false; $isExpose = $pMetadata instanceof VirtualPropertyMetadata; if (isset($config['properties'][$pName])) { $pConfig = $config['properties'][$pName]; if (isset($pConfig['exclude'])) { $isExclude = (bool) $pConfig['exclude']; } if (isset($pConfig['expose'])) { $isExpose = (bool) $pConfig['expose']; } if (isset($pConfig['since_version'])) { $pMetadata->sinceVersion = (string) $pConfig['since_version']; } if (isset($pConfig['until_version'])) { $pMetadata->untilVersion = (string) $pConfig['until_version']; } if (isset($pConfig['serialized_name'])) { $pMetadata->serializedName = (string) $pConfig['serialized_name']; } if (isset($pConfig['type'])) { $pMetadata->setType((string) $pConfig['type']); } if (isset($pConfig['groups'])) { $pMetadata->groups = $pConfig['groups']; } if (isset($pConfig['xml_list'])) { $pMetadata->xmlCollection = true; $colConfig = $pConfig['xml_list']; if (isset($colConfig['inline'])) { $pMetadata->xmlCollectionInline = (bool) $colConfig['inline']; } if (isset($colConfig['entry_name'])) { $pMetadata->xmlEntryName = (string) $colConfig['entry_name']; } } if (isset($pConfig['xml_map'])) { $pMetadata->xmlCollection = true; $colConfig = $pConfig['xml_map']; if (isset($colConfig['inline'])) { $pMetadata->xmlCollectionInline = (bool) $colConfig['inline']; } if (isset($colConfig['entry_name'])) { $pMetadata->xmlEntryName = (string) $colConfig['entry_name']; } if (isset($colConfig['key_attribute_name'])) { $pMetadata->xmlKeyAttribute = $colConfig['key_attribute_name']; } } if (isset($pConfig['xml_attribute'])) { $pMetadata->xmlAttribute = (bool) $pConfig['xml_attribute']; } if (isset($pConfig['xml_attribute_map'])) { $pMetadata->xmlAttribute = (bool) $pConfig['xml_attribute_map']; } if (isset($pConfig['xml_value'])) { $pMetadata->xmlValue = (bool) $pConfig['xml_value']; } if (isset($pConfig['xml_key_value_pairs'])) { $pMetadata->xmlKeyValuePairs = (bool) $pConfig['xml_key_value_pairs']; } //we need read_only before setter and getter set, because that method depends on flag being set if (isset($pConfig['read_only'])) { $pMetadata->readOnly = (bool) $pConfig['read_only']; } $pMetadata->setAccessor(isset($pConfig['access_type']) ? $pConfig['access_type'] : $classAccessType, isset($pConfig['accessor']['getter']) ? $pConfig['accessor']['getter'] : null, isset($pConfig['accessor']['setter']) ? $pConfig['accessor']['setter'] : null); if (isset($pConfig['inline'])) { $pMetadata->inline = (bool) $pConfig['inline']; } } if (ExclusionPolicy::NONE === $exclusionPolicy && !$isExclude || ExclusionPolicy::ALL === $exclusionPolicy && $isExpose) { $metadata->addPropertyMetadata($pMetadata); } } } if (isset($config['handler_callbacks'])) { foreach ($config['handler_callbacks'] as $direction => $formats) { foreach ($formats as $format => $methodName) { $direction = GraphNavigator::parseDirection($direction); $metadata->addHandlerCallback($direction, $format, $methodName); } } } if (isset($config['callback_methods'])) { $cConfig = $config['callback_methods']; if (isset($cConfig['pre_serialize'])) { $metadata->preSerializeMethods = $this->getCallbackMetadata($class, $cConfig['pre_serialize']); } if (isset($cConfig['post_serialize'])) { $metadata->postSerializeMethods = $this->getCallbackMetadata($class, $cConfig['post_serialize']); } if (isset($cConfig['post_deserialize'])) { $metadata->postDeserializeMethods = $this->getCallbackMetadata($class, $cConfig['post_deserialize']); } } return $metadata; }