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();
42 public function supportsNormalization($data, $format = null)
44 return parent::supportsNormalization($data, $format) && $this->supports(get_class($data));
50 public function supportsDenormalization($data, $type, $format = null)
52 return parent::supportsDenormalization($data, $type, $format) && $this->supports($type);
56 * Checks if the given class has any get{Property} method.
58 * @param string $class
62 private function supports($class)
64 $class = new \ReflectionClass($class);
65 $methods = $class->getMethods(\ReflectionMethod::IS_PUBLIC);
66 foreach ($methods as $method) {
67 if ($this->isGetMethod($method)) {
76 * Checks if a method's name is get.* or is.*, and can be called without parameters.
78 * @param \ReflectionMethod $method the method to check
80 * @return bool whether the method is a getter or boolean getter
82 private function isGetMethod(\ReflectionMethod $method)
84 $methodLength = strlen($method->name);
87 !$method->isStatic() &&
89 ((0 === strpos($method->name, 'get') && 3 < $methodLength) ||
90 (0 === strpos($method->name, 'is') && 2 < $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();
141 protected function setAttributeValue($object, $attribute, $value, $format = null, array $context = array())
143 $setter = 'set'.ucfirst($attribute);
144 $key = get_class($object).':'.$setter;
146 if (!isset(self::$setterAccessibleCache[$key])) {
147 self::$setterAccessibleCache[$key] = is_callable(array($object, $setter)) && !(new \ReflectionMethod($object, $setter))->isStatic();
150 if (self::$setterAccessibleCache[$key]) {
151 $object->$setter($value);