4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\Serializer\Normalizer;
15 * Converts between objects with getter and setter methods and arrays.
17 * The normalization process looks at all public methods and calls the ones
18 * which have a name starting with get and take no parameters. The result is a
19 * map from property names (method name stripped of the get prefix and converted
20 * to lower case) to property values. Property values are normalized through the
23 * The denormalization first looks at the constructor of the given class to see
24 * if any of the parameters have the same name as one of the properties. The
25 * constructor is then called with all parameters or an exception is thrown if
26 * any required parameters were not present as properties. Then the denormalizer
27 * walks through the given map of property names to property values to see if a
28 * setter method exists for any of the properties. If a setter exists it is
29 * called with the property value. No automatic denormalization of the value
32 * @author Nils Adermann <naderman@naderman.de>
33 * @author Kévin Dunglas <dunglas@gmail.com>
35 class GetSetMethodNormalizer extends AbstractObjectNormalizer
37 private static $setterAccessibleCache = array();
38 private $cache = array();
43 public function supportsNormalization($data, $format = null)
45 return parent::supportsNormalization($data, $format) && (isset($this->cache[$type = \get_class($data)]) ? $this->cache[$type] : $this->cache[$type] = $this->supports($type));
51 public function supportsDenormalization($data, $type, $format = null)
53 return parent::supportsDenormalization($data, $type, $format) && (isset($this->cache[$type]) ? $this->cache[$type] : $this->cache[$type] = $this->supports($type));
57 * Checks if the given class has any get{Property} method.
59 * @param string $class
63 private function supports($class)
65 $class = new \ReflectionClass($class);
66 $methods = $class->getMethods(\ReflectionMethod::IS_PUBLIC);
67 foreach ($methods as $method) {
68 if ($this->isGetMethod($method)) {
77 * Checks if a method's name is get.* or is.*, and can be called without parameters.
79 * @return bool whether the method is a getter or boolean getter
81 private function isGetMethod(\ReflectionMethod $method)
83 $methodLength = \strlen($method->name);
86 !$method->isStatic() &&
88 ((0 === strpos($method->name, 'get') && 3 < $methodLength) ||
89 (0 === strpos($method->name, 'is') && 2 < $methodLength) ||
90 (0 === strpos($method->name, 'has') && 3 < $methodLength)) &&
91 0 === $method->getNumberOfRequiredParameters()
99 protected function extractAttributes($object, $format = null, array $context = array())
101 $reflectionObject = new \ReflectionObject($object);
102 $reflectionMethods = $reflectionObject->getMethods(\ReflectionMethod::IS_PUBLIC);
104 $attributes = array();
105 foreach ($reflectionMethods as $method) {
106 if (!$this->isGetMethod($method)) {
110 $attributeName = lcfirst(substr($method->name, 0 === strpos($method->name, 'is') ? 2 : 3));
112 if ($this->isAllowedAttribute($object, $attributeName)) {
113 $attributes[] = $attributeName;
123 protected function getAttributeValue($object, $attribute, $format = null, array $context = array())
125 $ucfirsted = ucfirst($attribute);
127 $getter = 'get'.$ucfirsted;
128 if (\is_callable(array($object, $getter))) {
129 return $object->$getter();
132 $isser = 'is'.$ucfirsted;
133 if (\is_callable(array($object, $isser))) {
134 return $object->$isser();
137 $haser = 'has'.$ucfirsted;
138 if (\is_callable(array($object, $haser))) {
139 return $object->$haser();
146 protected function setAttributeValue($object, $attribute, $value, $format = null, array $context = array())
148 $setter = 'set'.ucfirst($attribute);
149 $key = \get_class($object).':'.$setter;
151 if (!isset(self::$setterAccessibleCache[$key])) {
152 self::$setterAccessibleCache[$key] = \is_callable(array($object, $setter)) && !(new \ReflectionMethod($object, $setter))->isStatic();
155 if (self::$setterAccessibleCache[$key]) {
156 $object->$setter($value);