From 8534505db5b80dafd1577abb876d39c3470e016b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Wed, 25 Feb 2015 23:32:01 +0100 Subject: [PATCH] [Serializer] Refactoring of metadata --- .../Serializer/Mapping/AttributeMetadata.php | 94 +++++++++++++++++++ .../Mapping/AttributeMetadataInterface.php | 50 ++++++++++ .../Serializer/Mapping/ClassMetadata.php | 66 +++++-------- .../Mapping/ClassMetadataInterface.php | 57 +++++++++++ .../Mapping/Factory/ClassMetadataFactory.php | 56 ++++------- .../Factory/ClassMetadataFactoryInterface.php | 53 +++++++++++ .../Mapping/Loader/AnnotationLoader.php | 37 ++++++-- .../Serializer/Mapping/Loader/FileLoader.php | 11 ++- .../Serializer/Mapping/Loader/LoaderChain.php | 16 ++-- .../Mapping/Loader/LoaderInterface.php | 8 +- .../Mapping/Loader/XmlFileLoader.php | 26 +++-- .../Mapping/Loader/YamlFileLoader.php | 21 +++-- .../Normalizer/AbstractNormalizer.php | 44 +++++++-- .../Normalizer/GetSetMethodNormalizer.php | 4 +- .../Normalizer/PropertyNormalizer.php | 4 +- .../Tests/Mapping/AttributeMetadataTest.php | 57 +++++++++++ .../Tests/Mapping/ClassMetadataTest.php | 65 +++++++++++++ .../Factory/ClassMetadataFactoryTest.php | 13 ++- .../Mapping/Loader/AnnotationLoaderTest.php | 43 +++++---- .../Mapping/Loader/XmlFileLoaderTest.php | 11 +++ .../Mapping/Loader/YamlFileLoaderTest.php | 11 +++ .../Mapping/TestClassMetadataFactory.php | 49 +++++++--- .../CamelCaseToSnakeCaseNameConverterTest.php | 6 ++ .../Tests/Normalizer/CustomNormalizerTest.php | 11 +++ .../Normalizer/GetSetMethodNormalizerTest.php | 6 ++ .../Serializer/Tests/SerializerTest.php | 11 +++ 26 files changed, 666 insertions(+), 164 deletions(-) create mode 100644 src/Symfony/Component/Serializer/Mapping/AttributeMetadata.php create mode 100644 src/Symfony/Component/Serializer/Mapping/AttributeMetadataInterface.php create mode 100644 src/Symfony/Component/Serializer/Mapping/ClassMetadataInterface.php create mode 100644 src/Symfony/Component/Serializer/Mapping/Factory/ClassMetadataFactoryInterface.php create mode 100644 src/Symfony/Component/Serializer/Tests/Mapping/AttributeMetadataTest.php create mode 100644 src/Symfony/Component/Serializer/Tests/Mapping/ClassMetadataTest.php diff --git a/src/Symfony/Component/Serializer/Mapping/AttributeMetadata.php b/src/Symfony/Component/Serializer/Mapping/AttributeMetadata.php new file mode 100644 index 0000000000..7a1d3db94a --- /dev/null +++ b/src/Symfony/Component/Serializer/Mapping/AttributeMetadata.php @@ -0,0 +1,94 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Mapping; + +/** + * {@inheritdoc} + * + * @author Kévin Dunglas + */ +class AttributeMetadata implements AttributeMetadataInterface +{ + /** + * @var string + * + * @internal This property is public in order to reduce the size of the + * class' serialized representation. Do not access it. Use + * {@link getName()} instead. + */ + public $name; + + /** + * @var array + * + * @internal This property is public in order to reduce the size of the + * class' serialized representation. Do not access it. Use + * {@link getGroups()} instead. + */ + public $groups = array(); + + /** + * Constructs a metadata for the given attribute. + * + * @param string $name + */ + public function __construct($name) + { + $this->name = $name; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return $this->name; + } + + /** + * {@inheritdoc} + */ + public function addGroup($group) + { + if (!in_array($group, $this->groups)) { + $this->groups[] = $group; + } + } + + /** + * {@inheritdoc} + */ + public function getGroups() + { + return $this->groups; + } + + /** + * {@inheritdoc} + */ + public function merge(AttributeMetadataInterface $attributeMetadata) + { + foreach ($attributeMetadata->getGroups() as $group) { + $this->addGroup($group); + } + } + + /** + * Returns the names of the properties that should be serialized. + * + * @return string[] + */ + public function __sleep() + { + return array('name', 'groups'); + } +} diff --git a/src/Symfony/Component/Serializer/Mapping/AttributeMetadataInterface.php b/src/Symfony/Component/Serializer/Mapping/AttributeMetadataInterface.php new file mode 100644 index 0000000000..0701a58b56 --- /dev/null +++ b/src/Symfony/Component/Serializer/Mapping/AttributeMetadataInterface.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Mapping; + +/** + * Stores metadata needed for serializing and deserializing attributes. + * + * Primarily, the metadata stores serialization groups. + * + * @author Kévin Dunglas + */ +interface AttributeMetadataInterface +{ + /** + * Gets the attribute name. + * + * @return string + */ + public function getName(); + + /** + * Adds this attribute to the given group. + * + * @param string $group + */ + public function addGroup($group); + + /** + * Gets groups of this attribute. + * + * @return string[] + */ + public function getGroups(); + + /** + * Merges an {@see AttributeMetadataInterface} with in the current one. + * + * @param AttributeMetadataInterface $attributeMetadata + */ + public function merge(AttributeMetadataInterface $attributeMetadata); +} diff --git a/src/Symfony/Component/Serializer/Mapping/ClassMetadata.php b/src/Symfony/Component/Serializer/Mapping/ClassMetadata.php index ff24c3cabc..3794a7451b 100644 --- a/src/Symfony/Component/Serializer/Mapping/ClassMetadata.php +++ b/src/Symfony/Component/Serializer/Mapping/ClassMetadata.php @@ -12,31 +12,29 @@ namespace Symfony\Component\Serializer\Mapping; /** - * Stores all metadata needed for serializing objects of specific class. - * - * Primarily, the metadata stores serialization groups. + * {@inheritdoc} * * @author Kévin Dunglas */ -class ClassMetadata +class ClassMetadata implements ClassMetadataInterface { /** * @var string * * @internal This property is public in order to reduce the size of the * class' serialized representation. Do not access it. Use - * {@link getClassName()} instead. + * {@link getName()} instead. */ public $name; /** - * @var array + * @var AttributeMetadataInterface[] * * @internal This property is public in order to reduce the size of the * class' serialized representation. Do not access it. Use - * {@link getGroups()} instead. + * {@link getAttributesMetadata()} instead. */ - public $attributesGroups = array(); + public $attributesMetadata = array(); /** * @var \ReflectionClass @@ -54,66 +52,50 @@ class ClassMetadata } /** - * Returns the name of the backing PHP class. - * - * @return string The name of the backing class. + * {@inheritdoc} */ - public function getClassName() + public function getName() { return $this->name; } /** - * Gets serialization groups. - * - * @return array + * {@inheritdoc} */ - public function getAttributesGroups() + public function addAttributeMetadata(AttributeMetadataInterface $attributeMetadata) { - return $this->attributesGroups; + $this->attributesMetadata[$attributeMetadata->getName()] = $attributeMetadata; } /** - * Adds an attribute to a serialization group - * - * @param string $attribute - * @param string $group - * @throws \InvalidArgumentException + * {@inheritdoc} */ - public function addAttributeGroup($attribute, $group) + public function getAttributesMetadata() { - if (!is_string($attribute) || !is_string($group)) { - throw new \InvalidArgumentException('Arguments must be strings.'); - } - - if (!isset($this->groups[$group]) || !in_array($attribute, $this->attributesGroups[$group])) { - $this->attributesGroups[$group][] = $attribute; - } + return $this->attributesMetadata; } /** - * Merges attributes' groups. - * - * @param ClassMetadata $classMetadata + * {@inheritdoc} */ - public function mergeAttributesGroups(ClassMetadata $classMetadata) + public function merge(ClassMetadataInterface $classMetadata) { - foreach ($classMetadata->getAttributesGroups() as $group => $attributes) { - foreach ($attributes as $attribute) { - $this->addAttributeGroup($attribute, $group); + foreach ($classMetadata->getAttributesMetadata() as $attributeMetadata) { + if (isset($this->attributesMetadata[$attributeMetadata->getName()])) { + $this->attributesMetadata[$attributeMetadata->getName()]->merge($attributeMetadata); + } else { + $this->addAttributeMetadata($attributeMetadata); } } } /** - * Returns a ReflectionClass instance for this class. - * - * @return \ReflectionClass + * {@inheritdoc} */ public function getReflectionClass() { if (!$this->reflClass) { - $this->reflClass = new \ReflectionClass($this->getClassName()); + $this->reflClass = new \ReflectionClass($this->getName()); } return $this->reflClass; @@ -128,7 +110,7 @@ class ClassMetadata { return array( 'name', - 'attributesGroups', + 'attributes', ); } } diff --git a/src/Symfony/Component/Serializer/Mapping/ClassMetadataInterface.php b/src/Symfony/Component/Serializer/Mapping/ClassMetadataInterface.php new file mode 100644 index 0000000000..c967666bd7 --- /dev/null +++ b/src/Symfony/Component/Serializer/Mapping/ClassMetadataInterface.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Mapping; + +/** + * Stores metadata needed for serializing and deserializing objects of specific class. + * + * Primarily, the metadata stores the list of attributes to serialize or deserialize. + * + * @author Kévin Dunglas + */ +interface ClassMetadataInterface +{ + /** + * Returns the name of the backing PHP class. + * + * @return string The name of the backing class. + */ + public function getName(); + + /** + * Adds an {@link AttributeMetadataInterface}. + * + * @param AttributeMetadataInterface $attributeMetadata + */ + public function addAttributeMetadata(AttributeMetadataInterface $attributeMetadata); + + /** + * Gets the list of {@link AttributeMetadataInterface}. + * + * @return AttributeMetadataInterface[] + */ + public function getAttributesMetadata(); + + /** + * Merges a {@link ClassMetadataInterface} in the current one. + * + * @param ClassMetadataInterface $classMetadata + */ + public function merge(ClassMetadataInterface $classMetadata); + + /** + * Returns a {@link \ReflectionClass} instance for this class. + * + * @return \ReflectionClass + */ + public function getReflectionClass(); +} diff --git a/src/Symfony/Component/Serializer/Mapping/Factory/ClassMetadataFactory.php b/src/Symfony/Component/Serializer/Mapping/Factory/ClassMetadataFactory.php index 7939015d51..344d633b26 100644 --- a/src/Symfony/Component/Serializer/Mapping/Factory/ClassMetadataFactory.php +++ b/src/Symfony/Component/Serializer/Mapping/Factory/ClassMetadataFactory.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Serializer\Mapping\Factory; use Doctrine\Common\Cache\Cache; +use Symfony\Component\Serializer\Exception\InvalidArgumentException; use Symfony\Component\Serializer\Mapping\ClassMetadata; use Symfony\Component\Serializer\Mapping\Loader\LoaderInterface; @@ -20,7 +21,7 @@ use Symfony\Component\Serializer\Mapping\Loader\LoaderInterface; * * @author Kévin Dunglas */ -class ClassMetadataFactory +class ClassMetadataFactory implements ClassMetadataFactoryInterface { /** * @var LoaderInterface @@ -46,29 +47,13 @@ class ClassMetadataFactory } /** - * If the method was called with the same class name (or an object of that - * class) before, the same metadata instance is returned. - * - * If the factory was configured with a cache, this method will first look - * for an existing metadata instance in the cache. If an existing instance - * is found, it will be returned without further ado. - * - * Otherwise, a new metadata instance is created. If the factory was - * configured with a loader, the metadata is passed to the - * {@link LoaderInterface::loadClassMetadata()} method for further - * configuration. At last, the new object is returned. - * - * @param string|object $value - * - * @return ClassMetadata - * - * @throws \InvalidArgumentException + * {@inheritdoc} */ public function getMetadataFor($value) { $class = $this->getClass($value); if (!$class) { - throw new \InvalidArgumentException(sprintf('Cannot create metadata for non-objects. Got: %s', gettype($value))); + throw new InvalidArgumentException(sprintf('Cannot create metadata for non-objects. Got: "%s"', gettype($value))); } if (isset($this->loadedClasses[$class])) { @@ -80,40 +65,33 @@ class ClassMetadataFactory } if (!class_exists($class) && !interface_exists($class)) { - throw new \InvalidArgumentException(sprintf('The class or interface "%s" does not exist.', $class)); + throw new InvalidArgumentException(sprintf('The class or interface "%s" does not exist.', $class)); } - $metadata = new ClassMetadata($class); + $classMetadata = new ClassMetadata($class); + $this->loader->loadClassMetadata($classMetadata); - $reflClass = $metadata->getReflectionClass(); + $reflectionClass = $classMetadata->getReflectionClass(); - // Include groups from the parent class - if ($parent = $reflClass->getParentClass()) { - $metadata->mergeAttributesGroups($this->getMetadataFor($parent->name)); + // Include metadata from the parent class + if ($parent = $reflectionClass->getParentClass()) { + $classMetadata->merge($this->getMetadataFor($parent->name)); } - // Include groups from all implemented interfaces - foreach ($reflClass->getInterfaces() as $interface) { - $metadata->mergeAttributesGroups($this->getMetadataFor($interface->name)); - } - - if ($this->loader) { - $this->loader->loadClassMetadata($metadata); + // Include metadata from all implemented interfaces + foreach ($reflectionClass->getInterfaces() as $interface) { + $classMetadata->merge($this->getMetadataFor($interface->name)); } if ($this->cache) { - $this->cache->save($class, $metadata); + $this->cache->save($class, $classMetadata); } - return $this->loadedClasses[$class] = $metadata; + return $this->loadedClasses[$class] = $classMetadata; } /** - * Checks if class has metadata. - * - * @param mixed $value - * - * @return bool + * {@inheritdoc} */ public function hasMetadataFor($value) { diff --git a/src/Symfony/Component/Serializer/Mapping/Factory/ClassMetadataFactoryInterface.php b/src/Symfony/Component/Serializer/Mapping/Factory/ClassMetadataFactoryInterface.php new file mode 100644 index 0000000000..a03298a06b --- /dev/null +++ b/src/Symfony/Component/Serializer/Mapping/Factory/ClassMetadataFactoryInterface.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Mapping\Factory; + +use Symfony\Component\Serializer\Exception\InvalidArgumentException; +use Symfony\Component\Serializer\Mapping\ClassMetadataInterface; + +/** + * Returns a {@see ClassMetadataInterface}. + * + * @author Kévin Dunglas + */ +interface ClassMetadataFactoryInterface +{ + /** + * If the method was called with the same class name (or an object of that + * class) before, the same metadata instance is returned. + * + * If the factory was configured with a cache, this method will first look + * for an existing metadata instance in the cache. If an existing instance + * is found, it will be returned without further ado. + * + * Otherwise, a new metadata instance is created. If the factory was + * configured with a loader, the metadata is passed to the + * {@link LoaderInterface::loadClassMetadata()} method for further + * configuration. At last, the new object is returned. + * + * @param string|object $value + * + * @return ClassMetadataInterface + * + * @throws InvalidArgumentException + */ + public function getMetadataFor($value); + + /** + * Checks if class has metadata. + * + * @param mixed $value + * + * @return bool + */ + public function hasMetadataFor($value); +} diff --git a/src/Symfony/Component/Serializer/Mapping/Loader/AnnotationLoader.php b/src/Symfony/Component/Serializer/Mapping/Loader/AnnotationLoader.php index cb59bfb3e1..2db9b9d3d3 100644 --- a/src/Symfony/Component/Serializer/Mapping/Loader/AnnotationLoader.php +++ b/src/Symfony/Component/Serializer/Mapping/Loader/AnnotationLoader.php @@ -14,7 +14,8 @@ namespace Symfony\Component\Serializer\Mapping\Loader; use Doctrine\Common\Annotations\Reader; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Serializer\Exception\MappingException; -use Symfony\Component\Serializer\Mapping\ClassMetadata; +use Symfony\Component\Serializer\Mapping\AttributeMetadata; +use Symfony\Component\Serializer\Mapping\ClassMetadataInterface; /** * Annotation loader. @@ -39,18 +40,25 @@ class AnnotationLoader implements LoaderInterface /** * {@inheritdoc} */ - public function loadClassMetadata(ClassMetadata $metadata) + public function loadClassMetadata(ClassMetadataInterface $classMetadata) { - $reflClass = $metadata->getReflectionClass(); - $className = $reflClass->name; + $reflectionClass = $classMetadata->getReflectionClass(); + $className = $reflectionClass->name; $loaded = false; - foreach ($reflClass->getProperties() as $property) { - if ($property->getDeclaringClass()->name === $className) { + $attributesMetadata = $classMetadata->getAttributesMetadata(); + + foreach ($reflectionClass->getProperties() as $property) { + if (!isset($attributeMetadata[$property->name])) { + $attributesMetadata[$property->name] = new AttributeMetadata($property->name); + $classMetadata->addAttributeMetadata($attributesMetadata[$property->name]); + } + + if ($property->getDeclaringClass()->name == $className) { foreach ($this->reader->getPropertyAnnotations($property) as $groups) { if ($groups instanceof Groups) { foreach ($groups->getGroups() as $group) { - $metadata->addAttributeGroup($property->name, $group); + $attributesMetadata[$property->name]->addGroup($group); } } @@ -59,13 +67,22 @@ class AnnotationLoader implements LoaderInterface } } - foreach ($reflClass->getMethods() as $method) { - if ($method->getDeclaringClass()->name === $className) { + foreach ($reflectionClass->getMethods() as $method) { + if ($method->getDeclaringClass()->name == $className) { foreach ($this->reader->getMethodAnnotations($method) as $groups) { if ($groups instanceof Groups) { if (preg_match('/^(get|is)(.+)$/i', $method->name, $matches)) { + $attributeName = lcfirst($matches[2]); + + if (isset($attributesMetadata[$attributeName])) { + $attributeMetadata = $attributesMetadata[$attributeName]; + } else { + $attributesMetadata[$attributeName] = $attributeMetadata = new AttributeMetadata($attributeName); + $classMetadata->addAttributeMetadata($attributeMetadata); + } + foreach ($groups->getGroups() as $group) { - $metadata->addAttributeGroup(lcfirst($matches[2]), $group); + $attributeMetadata->addGroup($group); } } else { throw new MappingException(sprintf('Groups on "%s::%s" cannot be added. Groups can only be added on methods beginning with "get" or "is".', $className, $method->name)); diff --git a/src/Symfony/Component/Serializer/Mapping/Loader/FileLoader.php b/src/Symfony/Component/Serializer/Mapping/Loader/FileLoader.php index a583757ba6..38bb59389a 100644 --- a/src/Symfony/Component/Serializer/Mapping/Loader/FileLoader.php +++ b/src/Symfony/Component/Serializer/Mapping/Loader/FileLoader.php @@ -13,8 +13,16 @@ namespace Symfony\Component\Serializer\Mapping\Loader; use Symfony\Component\Serializer\Exception\MappingException; +/** + * Base class for all file based loaders. + * + * @author Kévin Dunglas + */ abstract class FileLoader implements LoaderInterface { + /** + * @var string + */ protected $file; /** @@ -22,8 +30,7 @@ abstract class FileLoader implements LoaderInterface * * @param string $file The mapping file to load * - * @throws MappingException if the mapping file does not exist - * @throws MappingException if the mapping file is not readable + * @throws MappingException if the mapping file does not exist or is not readable */ public function __construct($file) { diff --git a/src/Symfony/Component/Serializer/Mapping/Loader/LoaderChain.php b/src/Symfony/Component/Serializer/Mapping/Loader/LoaderChain.php index 572d78aeca..8bf1c17da9 100644 --- a/src/Symfony/Component/Serializer/Mapping/Loader/LoaderChain.php +++ b/src/Symfony/Component/Serializer/Mapping/Loader/LoaderChain.php @@ -12,24 +12,28 @@ namespace Symfony\Component\Serializer\Mapping\Loader; use Symfony\Component\Serializer\Exception\MappingException; -use Symfony\Component\Serializer\Mapping\ClassMetadata; +use Symfony\Component\Serializer\Mapping\ClassMetadataInterface; /** - * Calls multiple LoaderInterface instances in a chain + * Calls multiple {@link LoaderInterface} instances in a chain. * * This class accepts multiple instances of LoaderInterface to be passed to the - * constructor. When loadClassMetadata() is called, the same method is called + * constructor. When {@link loadClassMetadata()} is called, the same method is called * in all of these loaders, regardless of whether any of them was * successful or not. * * @author Bernhard Schussek + * @author Kévin Dunglas */ class LoaderChain implements LoaderInterface { - protected $loaders; + /** + * @var LoaderInterface[] + */ + private $loaders; /** - * Accepts a list of LoaderInterface instances + * Accepts a list of LoaderInterface instances. * * @param LoaderInterface[] $loaders An array of LoaderInterface instances * @@ -49,7 +53,7 @@ class LoaderChain implements LoaderInterface /** * {@inheritdoc} */ - public function loadClassMetadata(ClassMetadata $metadata) + public function loadClassMetadata(ClassMetadataInterface $metadata) { $success = false; diff --git a/src/Symfony/Component/Serializer/Mapping/Loader/LoaderInterface.php b/src/Symfony/Component/Serializer/Mapping/Loader/LoaderInterface.php index d81f11e017..ebf84b6a96 100644 --- a/src/Symfony/Component/Serializer/Mapping/Loader/LoaderInterface.php +++ b/src/Symfony/Component/Serializer/Mapping/Loader/LoaderInterface.php @@ -11,10 +11,10 @@ namespace Symfony\Component\Serializer\Mapping\Loader; -use Symfony\Component\Serializer\Mapping\ClassMetadata; +use Symfony\Component\Serializer\Mapping\ClassMetadataInterface; /** - * Loads class metadata. + * Loads {@link ClassMetadataInterface}. * * @author Kévin Dunglas */ @@ -23,9 +23,9 @@ interface LoaderInterface /** * Load class metadata. * - * @param ClassMetadata $metadata A metadata + * @param ClassMetadataInterface $classMetadata A metadata * * @return bool */ - public function loadClassMetadata(ClassMetadata $metadata); + public function loadClassMetadata(ClassMetadataInterface $classMetadata); } diff --git a/src/Symfony/Component/Serializer/Mapping/Loader/XmlFileLoader.php b/src/Symfony/Component/Serializer/Mapping/Loader/XmlFileLoader.php index 6e47e99a63..0da2f7d690 100644 --- a/src/Symfony/Component/Serializer/Mapping/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/Serializer/Mapping/Loader/XmlFileLoader.php @@ -13,7 +13,8 @@ namespace Symfony\Component\Serializer\Mapping\Loader; use Symfony\Component\Config\Util\XmlUtils; use Symfony\Component\Serializer\Exception\MappingException; -use Symfony\Component\Serializer\Mapping\ClassMetadata; +use Symfony\Component\Serializer\Mapping\AttributeMetadata; +use Symfony\Component\Serializer\Mapping\ClassMetadataInterface; /** * Loads XML mapping files. @@ -23,7 +24,7 @@ use Symfony\Component\Serializer\Mapping\ClassMetadata; class XmlFileLoader extends FileLoader { /** - * An array of SimpleXMLElement instances. + * An array of {@class \SimpleXMLElement} instances. * * @var \SimpleXMLElement[]|null */ @@ -32,7 +33,7 @@ class XmlFileLoader extends FileLoader /** * {@inheritdoc} */ - public function loadClassMetadata(ClassMetadata $metadata) + public function loadClassMetadata(ClassMetadataInterface $classMetadata) { if (null === $this->classes) { $this->classes = array(); @@ -43,12 +44,23 @@ class XmlFileLoader extends FileLoader } } - if (isset($this->classes[$metadata->getClassName()])) { - $xml = $this->classes[$metadata->getClassName()]; + $attributesMetadata = $classMetadata->getAttributesMetadata(); + + if (isset($this->classes[$classMetadata->getName()])) { + $xml = $this->classes[$classMetadata->getName()]; foreach ($xml->attribute as $attribute) { + $attributeName = (string) $attribute['name']; + + if (isset($attributesMetadata[$attributeName])) { + $attributeMetadata = $attributesMetadata[$attributeName]; + } else { + $attributeMetadata = new AttributeMetadata($attributeName); + $classMetadata->addAttributeMetadata($attributeMetadata); + } + foreach ($attribute->group as $group) { - $metadata->addAttributeGroup((string) $attribute['name'], (string) $group); + $attributeMetadata->addGroup((string) $group); } } @@ -59,7 +71,7 @@ class XmlFileLoader extends FileLoader } /** - * Parse a XML File. + * Parses a XML File. * * @param string $file Path of file * diff --git a/src/Symfony/Component/Serializer/Mapping/Loader/YamlFileLoader.php b/src/Symfony/Component/Serializer/Mapping/Loader/YamlFileLoader.php index f72aa5a1d1..1c5d5e82e6 100644 --- a/src/Symfony/Component/Serializer/Mapping/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/Serializer/Mapping/Loader/YamlFileLoader.php @@ -12,11 +12,12 @@ namespace Symfony\Component\Serializer\Mapping\Loader; use Symfony\Component\Serializer\Exception\MappingException; -use Symfony\Component\Serializer\Mapping\ClassMetadata; +use Symfony\Component\Serializer\Mapping\AttributeMetadata; +use Symfony\Component\Serializer\Mapping\ClassMetadataInterface; use Symfony\Component\Yaml\Parser; /** - * YAML File Loader + * YAML File Loader. * * @author Kévin Dunglas */ @@ -34,7 +35,7 @@ class YamlFileLoader extends FileLoader /** * {@inheritdoc} */ - public function loadClassMetadata(ClassMetadata $metadata) + public function loadClassMetadata(ClassMetadataInterface $classMetadata) { if (null === $this->classes) { if (!stream_is_local($this->file)) { @@ -59,14 +60,22 @@ class YamlFileLoader extends FileLoader $this->classes = $classes; } - if (isset($this->classes[$metadata->getClassName()])) { - $yaml = $this->classes[$metadata->getClassName()]; + if (isset($this->classes[$classMetadata->getName()])) { + $yaml = $this->classes[$classMetadata->getName()]; if (isset($yaml['attributes']) && is_array($yaml['attributes'])) { + $attributesMetadata = $classMetadata->getAttributesMetadata(); foreach ($yaml['attributes'] as $attribute => $data) { + if (isset($attributesMetadata[$attribute])) { + $attributeMetadata = $attributesMetadata[$attribute]; + } else { + $attributeMetadata = new AttributeMetadata($attribute); + $classMetadata->addAttributeMetadata($attributeMetadata); + } + if (isset($data['groups'])) { foreach ($data['groups'] as $group) { - $metadata->addAttributeGroup($attribute, $group); + $attributeMetadata->addGroup($group); } } } diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php index 9ea4d374bf..dfd21b4644 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php @@ -15,7 +15,8 @@ use Symfony\Component\Serializer\Exception\CircularReferenceException; use Symfony\Component\Serializer\Exception\InvalidArgumentException; use Symfony\Component\Serializer\Exception\LogicException; use Symfony\Component\Serializer\Exception\RuntimeException; -use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; +use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface; +use Symfony\Component\Serializer\Mapping\AttributeMetadataInterface; use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter; use Symfony\Component\Serializer\NameConverter\NameConverterInterface; @@ -26,21 +27,42 @@ use Symfony\Component\Serializer\NameConverter\NameConverterInterface; */ abstract class AbstractNormalizer extends SerializerAwareNormalizer implements NormalizerInterface, DenormalizerInterface { + /** + * @var int + */ protected $circularReferenceLimit = 1; + /** + * @var callable + */ protected $circularReferenceHandler; + /** + * @var ClassMetadataFactoryInterface|null + */ protected $classMetadataFactory; + /** + * @var NameConverterInterface|null + */ protected $nameConverter; + /** + * @var array + */ protected $callbacks = array(); + /** + * @var array + */ protected $ignoredAttributes = array(); + /** + * @var array + */ protected $camelizedAttributes = array(); /** - * Sets the {@link ClassMetadataFactory} to use. + * Sets the {@link ClassMetadataFactoryInterface} to use. * - * @param ClassMetadataFactory|null $classMetadataFactory + * @param ClassMetadataFactoryInterface|null $classMetadataFactory * @param NameConverterInterface|null $nameConverter */ - public function __construct(ClassMetadataFactory $classMetadataFactory = null, NameConverterInterface $nameConverter = null) + public function __construct(ClassMetadataFactoryInterface $classMetadataFactory = null, NameConverterInterface $nameConverter = null) { $this->classMetadataFactory = $classMetadataFactory; $this->nameConverter = $nameConverter; @@ -219,19 +241,21 @@ abstract class AbstractNormalizer extends SerializerAwareNormalizer implements N * Gets attributes to normalize using groups. * * @param string|object $classOrObject - * @param array $context - * @return array|bool + * @param array $context + * @param bool $attributesAsString If false, return an array of {@link AttributeMetadataInterface} + * + * @return string[]|AttributeMetadataInterface[]|bool */ - protected function getAllowedAttributes($classOrObject, array $context) + protected function getAllowedAttributes($classOrObject, array $context, $attributesAsString = false) { if (!$this->classMetadataFactory || !isset($context['groups']) || !is_array($context['groups'])) { return false; } $allowedAttributes = array(); - foreach ($this->classMetadataFactory->getMetadataFor($classOrObject)->getAttributesGroups() as $group => $attributes) { - if (in_array($group, $context['groups'])) { - $allowedAttributes = array_merge($allowedAttributes, $attributes); + foreach ($this->classMetadataFactory->getMetadataFor($classOrObject)->getAttributesMetadata() as $attributeMetadata) { + if (count(array_intersect($attributeMetadata->getGroups(), $context['groups']))) { + $allowedAttributes[] = $attributesAsString ? $attributeMetadata->getName() : $attributeMetadata; } } diff --git a/src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php index b3111eaa18..6ccfb984b5 100644 --- a/src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php @@ -52,7 +52,7 @@ class GetSetMethodNormalizer extends AbstractNormalizer $reflectionObject = new \ReflectionObject($object); $reflectionMethods = $reflectionObject->getMethods(\ReflectionMethod::IS_PUBLIC); - $allowedAttributes = $this->getAllowedAttributes($object, $context); + $allowedAttributes = $this->getAllowedAttributes($object, $context, true); $attributes = array(); foreach ($reflectionMethods as $method) { @@ -97,7 +97,7 @@ class GetSetMethodNormalizer extends AbstractNormalizer */ public function denormalize($data, $class, $format = null, array $context = array()) { - $allowedAttributes = $this->getAllowedAttributes($class, $context); + $allowedAttributes = $this->getAllowedAttributes($class, $context, true); $normalizedData = $this->prepareForDenormalization($data); $reflectionClass = new \ReflectionClass($class); diff --git a/src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php index 5acadde2e7..970d0661cd 100644 --- a/src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php @@ -46,7 +46,7 @@ class PropertyNormalizer extends AbstractNormalizer $reflectionObject = new \ReflectionObject($object); $attributes = array(); - $allowedAttributes = $this->getAllowedAttributes($object, $context); + $allowedAttributes = $this->getAllowedAttributes($object, $context, true); foreach ($reflectionObject->getProperties() as $property) { if (in_array($property->name, $this->ignoredAttributes)) { @@ -89,7 +89,7 @@ class PropertyNormalizer extends AbstractNormalizer */ public function denormalize($data, $class, $format = null, array $context = array()) { - $allowedAttributes = $this->getAllowedAttributes($class, $context); + $allowedAttributes = $this->getAllowedAttributes($class, $context, true); $data = $this->prepareForDenormalization($data); $reflectionClass = new \ReflectionClass($class); diff --git a/src/Symfony/Component/Serializer/Tests/Mapping/AttributeMetadataTest.php b/src/Symfony/Component/Serializer/Tests/Mapping/AttributeMetadataTest.php new file mode 100644 index 0000000000..f22746bc5d --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Mapping/AttributeMetadataTest.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Mapping; + +use Symfony\Component\Serializer\Mapping\AttributeMetadata; + +/** + * @author Kévin Dunglas + */ +class AttributeMetadataTest extends \PHPUnit_Framework_TestCase +{ + public function testInterface() + { + $attributeMetadata = new AttributeMetadata('name'); + $this->assertInstanceOf('Symfony\Component\Serializer\Mapping\AttributeMetadataInterface', $attributeMetadata); + } + + public function testGetName() + { + $attributeMetadata = new AttributeMetadata('name'); + $this->assertEquals('name', $attributeMetadata->getName()); + } + + public function testGroups() + { + $attributeMetadata = new AttributeMetadata('group'); + $attributeMetadata->addGroup('a'); + $attributeMetadata->addGroup('a'); + $attributeMetadata->addGroup('b'); + + $this->assertEquals(array('a', 'b'), $attributeMetadata->getGroups()); + } + + public function testMerge() + { + $attributeMetadata1 = new AttributeMetadata('a1'); + $attributeMetadata1->addGroup('a'); + $attributeMetadata1->addGroup('b'); + + $attributeMetadata2 = new AttributeMetadata('a2'); + $attributeMetadata2->addGroup('a'); + $attributeMetadata2->addGroup('c'); + + $attributeMetadata1->merge($attributeMetadata2); + + $this->assertEquals(array('a', 'b', 'c'), $attributeMetadata1->getGroups()); + } +} diff --git a/src/Symfony/Component/Serializer/Tests/Mapping/ClassMetadataTest.php b/src/Symfony/Component/Serializer/Tests/Mapping/ClassMetadataTest.php new file mode 100644 index 0000000000..90017580ac --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Mapping/ClassMetadataTest.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Mapping; + +use Symfony\Component\Serializer\Mapping\ClassMetadata; + +/** + * @author Kévin Dunglas + */ +class ClassMetadataTest extends \PHPUnit_Framework_TestCase +{ + public function testInterface() + { + $classMetadata = new ClassMetadata('name'); + $this->assertInstanceOf('Symfony\Component\Serializer\Mapping\ClassMetadataInterface', $classMetadata); + } + + public function testAttributeMetadata() + { + $classMetadata = new ClassMetadata('c'); + + $a1 = $this->getMock('Symfony\Component\Serializer\Mapping\AttributeMetadataInterface'); + $a1->method('getName')->willReturn('a1'); + + $a2 = $this->getMock('Symfony\Component\Serializer\Mapping\AttributeMetadataInterface'); + $a2->method('getName')->willReturn('a2'); + + $classMetadata->addAttributeMetadata($a1); + $classMetadata->addAttributeMetadata($a2); + + $this->assertEquals(array('a1' => $a1, 'a2' => $a2), $classMetadata->getAttributesMetadata()); + } + + public function testMerge() + { + $classMetadata1 = new ClassMetadata('c1'); + $classMetadata2 = new ClassMetadata('c2'); + + $ac1 = $this->getMock('Symfony\Component\Serializer\Mapping\AttributeMetadataInterface'); + $ac1->method('getName')->willReturn('a1'); + $ac1->method('getGroups')->willReturn(array('a', 'b')); + + $ac2 = $this->getMock('Symfony\Component\Serializer\Mapping\AttributeMetadataInterface'); + $ac2->method('getName')->willReturn('a1'); + $ac2->method('getGroups')->willReturn(array('b', 'c')); + + $classMetadata1->addAttributeMetadata($ac1); + $classMetadata2->addAttributeMetadata($ac2); + + $classMetadata1->merge($classMetadata2); + + $ac1->method('getGroups')->willReturn('a', 'b', 'c'); + + $this->assertEquals(array('a1' => $ac1), $classMetadata2->getAttributesMetadata()); + } +} diff --git a/src/Symfony/Component/Serializer/Tests/Mapping/Factory/ClassMetadataFactoryTest.php b/src/Symfony/Component/Serializer/Tests/Mapping/Factory/ClassMetadataFactoryTest.php index 0573f2889a..2e2ba22dce 100644 --- a/src/Symfony/Component/Serializer/Tests/Mapping/Factory/ClassMetadataFactoryTest.php +++ b/src/Symfony/Component/Serializer/Tests/Mapping/Factory/ClassMetadataFactoryTest.php @@ -14,21 +14,26 @@ namespace Symfony\Component\Serializer\Tests\Mapping\Factory; use Doctrine\Common\Annotations\AnnotationReader; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader; +use Symfony\Component\Serializer\Mapping\Loader\LoaderChain; use Symfony\Component\Serializer\Tests\Mapping\TestClassMetadataFactory; -require_once __DIR__.'/../../../Annotation/Groups.php'; - /** * @author Kévin Dunglas */ class ClassMetadataFactoryTest extends \PHPUnit_Framework_TestCase { + public function testInterface() + { + $classMetadata = new ClassMetadataFactory(new LoaderChain(array())); + $this->assertInstanceOf('Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory', $classMetadata); + } + public function testGetMetadataFor() { $factory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); - $metadata = $factory->getMetadataFor('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy'); + $classMetadata = $factory->getMetadataFor('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy'); - $this->assertEquals(TestClassMetadataFactory::createClassMetadata(true, true), $metadata); + $this->assertEquals(TestClassMetadataFactory::createClassMetadata(true, true), $classMetadata); } public function testHasMetadataFor() diff --git a/src/Symfony/Component/Serializer/Tests/Mapping/Loader/AnnotationLoaderTest.php b/src/Symfony/Component/Serializer/Tests/Mapping/Loader/AnnotationLoaderTest.php index 8a34108cbd..484d062f22 100644 --- a/src/Symfony/Component/Serializer/Tests/Mapping/Loader/AnnotationLoaderTest.php +++ b/src/Symfony/Component/Serializer/Tests/Mapping/Loader/AnnotationLoaderTest.php @@ -16,42 +16,51 @@ use Symfony\Component\Serializer\Mapping\ClassMetadata; use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader; use Symfony\Component\Serializer\Tests\Mapping\TestClassMetadataFactory; -require_once __DIR__.'/../../../Annotation/Groups.php'; - /** * @author Kévin Dunglas */ class AnnotationLoaderTest extends \PHPUnit_Framework_TestCase { + /** + * @var AnnotationLoader + */ + private $loader; + + protected function setUp() + { + $this->loader = new AnnotationLoader(new AnnotationReader()); + } + + public function testInterface() + { + $this->assertInstanceOf('Symfony\Component\Serializer\Mapping\Loader\LoaderInterface', $this->loader); + } + public function testLoadClassMetadataReturnsTrueIfSuccessful() { - $loader = new AnnotationLoader(new AnnotationReader()); - $metadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy'); + $classMetadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy'); - $this->assertTrue($loader->loadClassMetadata($metadata)); + $this->assertTrue($this->loader->loadClassMetadata($classMetadata)); } public function testLoadClassMetadata() { - $loader = new AnnotationLoader(new AnnotationReader()); - $metadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy'); + $classMetadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy'); + $this->loader->loadClassMetadata($classMetadata); - $loader->loadClassMetadata($metadata); - - $this->assertEquals(TestClassMetadataFactory::createClassMetadata(), $metadata); + $this->assertEquals(TestClassMetadataFactory::createClassMetadata(), $classMetadata); } public function testLoadClassMetadataAndMerge() { - $loader = new AnnotationLoader(new AnnotationReader()); - $metadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy'); - $parentMetadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\GroupDummyParent'); + $classMetadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy'); + $parentClassMetadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\GroupDummyParent'); - $loader->loadClassMetadata($parentMetadata); - $metadata->mergeAttributesGroups($parentMetadata); + $this->loader->loadClassMetadata($parentClassMetadata); + $classMetadata->merge($parentClassMetadata); - $loader->loadClassMetadata($metadata); + $this->loader->loadClassMetadata($classMetadata); - $this->assertEquals(TestClassMetadataFactory::createClassMetadata(true), $metadata); + $this->assertEquals(TestClassMetadataFactory::createClassMetadata(true), $classMetadata); } } diff --git a/src/Symfony/Component/Serializer/Tests/Mapping/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/Serializer/Tests/Mapping/Loader/XmlFileLoaderTest.php index 35888626e0..418e6b1538 100644 --- a/src/Symfony/Component/Serializer/Tests/Mapping/Loader/XmlFileLoaderTest.php +++ b/src/Symfony/Component/Serializer/Tests/Mapping/Loader/XmlFileLoaderTest.php @@ -20,7 +20,13 @@ use Symfony\Component\Serializer\Tests\Mapping\TestClassMetadataFactory; */ class XmlFileLoaderTest extends \PHPUnit_Framework_TestCase { + /** + * @var XmlFileLoader + */ private $loader; + /** + * @var ClassMetadata + */ private $metadata; public function setUp() @@ -29,6 +35,11 @@ class XmlFileLoaderTest extends \PHPUnit_Framework_TestCase $this->metadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy'); } + public function testInterface() + { + $this->assertInstanceOf('Symfony\Component\Serializer\Mapping\Loader\LoaderInterface', $this->loader); + } + public function testLoadClassMetadataReturnsTrueIfSuccessful() { $this->assertTrue($this->loader->loadClassMetadata($this->metadata)); diff --git a/src/Symfony/Component/Serializer/Tests/Mapping/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/Serializer/Tests/Mapping/Loader/YamlFileLoaderTest.php index ec6434cf1d..37c9bcbdf9 100644 --- a/src/Symfony/Component/Serializer/Tests/Mapping/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/Serializer/Tests/Mapping/Loader/YamlFileLoaderTest.php @@ -20,7 +20,13 @@ use Symfony\Component\Serializer\Tests\Mapping\TestClassMetadataFactory; */ class YamlFileLoaderTest extends \PHPUnit_Framework_TestCase { + /** + * @var YamlFileLoader + */ private $loader; + /** + * @var ClassMetadata + */ private $metadata; public function setUp() @@ -29,6 +35,11 @@ class YamlFileLoaderTest extends \PHPUnit_Framework_TestCase $this->metadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy'); } + public function testInterface() + { + $this->assertInstanceOf('Symfony\Component\Serializer\Mapping\Loader\LoaderInterface', $this->loader); + } + public function testLoadClassMetadataReturnsTrueIfSuccessful() { $this->assertTrue($this->loader->loadClassMetadata($this->metadata)); diff --git a/src/Symfony/Component/Serializer/Tests/Mapping/TestClassMetadataFactory.php b/src/Symfony/Component/Serializer/Tests/Mapping/TestClassMetadataFactory.php index c253e72eaa..07b38c024b 100644 --- a/src/Symfony/Component/Serializer/Tests/Mapping/TestClassMetadataFactory.php +++ b/src/Symfony/Component/Serializer/Tests/Mapping/TestClassMetadataFactory.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Serializer\Tests\Mapping; +use Symfony\Component\Serializer\Mapping\AttributeMetadata; use Symfony\Component\Serializer\Mapping\ClassMetadata; /** @@ -22,22 +23,38 @@ class TestClassMetadataFactory { $expected = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy'); + $foo = new AttributeMetadata('foo'); + $foo->addGroup('a'); + $expected->addAttributeMetadata($foo); + + $bar = new AttributeMetadata('bar'); + $bar->addGroup('b'); + $bar->addGroup('c'); + $expected->addAttributeMetadata($bar); + + $fooBar = new AttributeMetadata('fooBar'); + $fooBar->addGroup('a'); + $fooBar->addGroup('b'); + $expected->addAttributeMetadata($fooBar); + + $symfony = new AttributeMetadata('symfony'); + $expected->addAttributeMetadata($symfony); + if ($withParent) { - $expected->addAttributeGroup('kevin', 'a'); - $expected->addAttributeGroup('coopTilleuls', 'a'); - $expected->addAttributeGroup('coopTilleuls', 'b'); + $kevin = new AttributeMetadata('kevin'); + $kevin->addGroup('a'); + $expected->addAttributeMetadata($kevin); + + $coopTilleuls = new AttributeMetadata('coopTilleuls'); + $coopTilleuls->addGroup('a'); + $coopTilleuls->addGroup('b'); + $expected->addAttributeMetadata($coopTilleuls); } if ($withInterface) { - $expected->addAttributeGroup('symfony', 'a'); + $symfony->addGroup('a'); } - $expected->addAttributeGroup('foo', 'a'); - $expected->addAttributeGroup('bar', 'b'); - $expected->addAttributeGroup('bar', 'c'); - $expected->addAttributeGroup('fooBar', 'a'); - $expected->addAttributeGroup('fooBar', 'b'); - // load reflection class so that the comparison passes $expected->getReflectionClass(); @@ -47,9 +64,15 @@ class TestClassMetadataFactory public static function createXmlCLassMetadata() { $expected = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy'); - $expected->addAttributeGroup('foo', 'group1'); - $expected->addAttributeGroup('foo', 'group2'); - $expected->addAttributeGroup('bar', 'group2'); + + $foo = new AttributeMetadata('foo'); + $foo->addGroup('group1'); + $foo->addGroup('group2'); + $expected->addAttributeMetadata($foo); + + $bar = new AttributeMetadata('bar'); + $bar->addGroup('group2'); + $expected->addAttributeMetadata($bar); return $expected; } diff --git a/src/Symfony/Component/Serializer/Tests/NameConverter/CamelCaseToSnakeCaseNameConverterTest.php b/src/Symfony/Component/Serializer/Tests/NameConverter/CamelCaseToSnakeCaseNameConverterTest.php index 7d677181b3..2d57017340 100644 --- a/src/Symfony/Component/Serializer/Tests/NameConverter/CamelCaseToSnakeCaseNameConverterTest.php +++ b/src/Symfony/Component/Serializer/Tests/NameConverter/CamelCaseToSnakeCaseNameConverterTest.php @@ -18,6 +18,12 @@ use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter */ class CamelCaseToSnakeCaseNameConverterTest extends \PHPUnit_Framework_TestCase { + public function testInterface() + { + $attributeMetadata = new CamelCaseToSnakeCaseNameConverter(); + $this->assertInstanceOf('Symfony\Component\Serializer\NameConverter\NameConverterInterface', $attributeMetadata); + } + /** * @dataProvider attributeProvider */ diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/CustomNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/CustomNormalizerTest.php index 0aeaba472a..86ae003120 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/CustomNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/CustomNormalizerTest.php @@ -17,12 +17,23 @@ use Symfony\Component\Serializer\Serializer; class CustomNormalizerTest extends \PHPUnit_Framework_TestCase { + /** + * @var CustomNormalizer + */ + private $normalizer; + protected function setUp() { $this->normalizer = new CustomNormalizer(); $this->normalizer->setSerializer(new Serializer()); } + public function testInterface() + { + $this->assertInstanceOf('Symfony\Component\Serializer\Normalizer\NormalizerInterface', $this->normalizer); + $this->assertInstanceOf('Symfony\Component\Serializer\Normalizer\DenormalizerInterface', $this->normalizer); + } + public function testSerialize() { $obj = new ScalarDummy(); diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php index b7be3b6fc8..82854fa0a7 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php @@ -40,6 +40,12 @@ class GetSetMethodNormalizerTest extends \PHPUnit_Framework_TestCase $this->normalizer->setSerializer($this->serializer); } + public function testInterface() + { + $this->assertInstanceOf('Symfony\Component\Serializer\Normalizer\NormalizerInterface', $this->normalizer); + $this->assertInstanceOf('Symfony\Component\Serializer\Normalizer\DenormalizerInterface', $this->normalizer); + } + public function testNormalize() { $obj = new GetSetDummy(); diff --git a/src/Symfony/Component/Serializer/Tests/SerializerTest.php b/src/Symfony/Component/Serializer/Tests/SerializerTest.php index 3a6b1ae4c5..68f70fcfe5 100644 --- a/src/Symfony/Component/Serializer/Tests/SerializerTest.php +++ b/src/Symfony/Component/Serializer/Tests/SerializerTest.php @@ -22,6 +22,17 @@ use Symfony\Component\Serializer\Tests\Normalizer\TestDenormalizer; class SerializerTest extends \PHPUnit_Framework_TestCase { + public function testInterface() + { + $serializer = new Serializer(); + + $this->assertInstanceOf('Symfony\Component\Serializer\SerializerInterface', $serializer); + $this->assertInstanceOf('Symfony\Component\Serializer\Normalizer\NormalizerInterface', $serializer); + $this->assertInstanceOf('Symfony\Component\Serializer\Normalizer\DenormalizerInterface', $serializer); + $this->assertInstanceOf('Symfony\Component\Serializer\Encoder\EncoderInterface', $serializer); + $this->assertInstanceOf('Symfony\Component\Serializer\Encoder\DecoderInterface', $serializer); + } + /** * @expectedException \Symfony\Component\Serializer\Exception\UnexpectedValueException */