Chris@0: Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: namespace Symfony\Component\Serializer\Normalizer; Chris@0: Chris@0: /** Chris@0: * Converts between objects and arrays by mapping properties. Chris@0: * Chris@0: * The normalization process looks for all the object's properties (public and private). Chris@0: * The result is a map from property names to property values. Property values Chris@0: * are normalized through the serializer. Chris@0: * Chris@0: * The denormalization first looks at the constructor of the given class to see Chris@0: * if any of the parameters have the same name as one of the properties. The Chris@0: * constructor is then called with all parameters or an exception is thrown if Chris@0: * any required parameters were not present as properties. Then the denormalizer Chris@0: * walks through the given map of property names to property values to see if a Chris@0: * property with the corresponding name exists. If found, the property gets the value. Chris@0: * Chris@0: * @author Matthieu Napoli Chris@0: * @author Kévin Dunglas Chris@0: */ Chris@0: class PropertyNormalizer extends AbstractObjectNormalizer Chris@0: { Chris@17: private $cache = []; Chris@14: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function supportsNormalization($data, $format = null) Chris@0: { Chris@14: return parent::supportsNormalization($data, $format) && (isset($this->cache[$type = \get_class($data)]) ? $this->cache[$type] : $this->cache[$type] = $this->supports($type)); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function supportsDenormalization($data, $type, $format = null) Chris@0: { Chris@14: return parent::supportsDenormalization($data, $type, $format) && (isset($this->cache[$type]) ? $this->cache[$type] : $this->cache[$type] = $this->supports($type)); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Checks if the given class has any non-static property. Chris@0: * Chris@0: * @param string $class Chris@0: * Chris@0: * @return bool Chris@0: */ Chris@0: private function supports($class) Chris@0: { Chris@0: $class = new \ReflectionClass($class); Chris@0: Chris@0: // We look for at least one non-static property Chris@14: do { Chris@14: foreach ($class->getProperties() as $property) { Chris@14: if (!$property->isStatic()) { Chris@14: return true; Chris@14: } Chris@0: } Chris@14: } while ($class = $class->getParentClass()); Chris@0: Chris@0: return false; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@17: protected function isAllowedAttribute($classOrObject, $attribute, $format = null, array $context = []) Chris@0: { Chris@0: if (!parent::isAllowedAttribute($classOrObject, $attribute, $format, $context)) { Chris@0: return false; Chris@0: } Chris@0: Chris@0: try { Chris@14: $reflectionProperty = $this->getReflectionProperty($classOrObject, $attribute); Chris@0: if ($reflectionProperty->isStatic()) { Chris@0: return false; Chris@0: } Chris@0: } catch (\ReflectionException $reflectionException) { Chris@0: return false; Chris@0: } Chris@0: Chris@0: return true; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@17: protected function extractAttributes($object, $format = null, array $context = []) Chris@0: { Chris@0: $reflectionObject = new \ReflectionObject($object); Chris@17: $attributes = []; Chris@0: Chris@14: do { Chris@14: foreach ($reflectionObject->getProperties() as $property) { Chris@18: if (!$this->isAllowedAttribute($reflectionObject->getName(), $property->name, $format, $context)) { Chris@14: continue; Chris@14: } Chris@14: Chris@14: $attributes[] = $property->name; Chris@0: } Chris@14: } while ($reflectionObject = $reflectionObject->getParentClass()); Chris@0: Chris@0: return $attributes; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@17: protected function getAttributeValue($object, $attribute, $format = null, array $context = []) Chris@0: { Chris@0: try { Chris@14: $reflectionProperty = $this->getReflectionProperty($object, $attribute); Chris@0: } catch (\ReflectionException $reflectionException) { Chris@0: return; Chris@0: } Chris@0: Chris@0: // Override visibility Chris@0: if (!$reflectionProperty->isPublic()) { Chris@0: $reflectionProperty->setAccessible(true); Chris@0: } Chris@0: Chris@0: return $reflectionProperty->getValue($object); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@17: protected function setAttributeValue($object, $attribute, $value, $format = null, array $context = []) Chris@0: { Chris@0: try { Chris@14: $reflectionProperty = $this->getReflectionProperty($object, $attribute); Chris@0: } catch (\ReflectionException $reflectionException) { Chris@0: return; Chris@0: } Chris@0: Chris@0: if ($reflectionProperty->isStatic()) { Chris@0: return; Chris@0: } Chris@0: Chris@0: // Override visibility Chris@0: if (!$reflectionProperty->isPublic()) { Chris@0: $reflectionProperty->setAccessible(true); Chris@0: } Chris@0: Chris@0: $reflectionProperty->setValue($object, $value); Chris@0: } Chris@14: Chris@14: /** Chris@14: * @param string|object $classOrObject Chris@14: * @param string $attribute Chris@14: * Chris@14: * @return \ReflectionProperty Chris@14: * Chris@14: * @throws \ReflectionException Chris@14: */ Chris@14: private function getReflectionProperty($classOrObject, $attribute) Chris@14: { Chris@14: $reflectionClass = new \ReflectionClass($classOrObject); Chris@14: while (true) { Chris@14: try { Chris@14: return $reflectionClass->getProperty($attribute); Chris@14: } catch (\ReflectionException $e) { Chris@14: if (!$reflectionClass = $reflectionClass->getParentClass()) { Chris@14: throw $e; Chris@14: } Chris@14: } Chris@14: } Chris@14: } Chris@0: }