annotate vendor/symfony/serializer/Normalizer/GetSetMethodNormalizer.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents af1871eacc83
children
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 /*
Chris@0 4 * This file is part of the Symfony package.
Chris@0 5 *
Chris@0 6 * (c) Fabien Potencier <fabien@symfony.com>
Chris@0 7 *
Chris@0 8 * For the full copyright and license information, please view the LICENSE
Chris@0 9 * file that was distributed with this source code.
Chris@0 10 */
Chris@0 11
Chris@0 12 namespace Symfony\Component\Serializer\Normalizer;
Chris@0 13
Chris@0 14 /**
Chris@0 15 * Converts between objects with getter and setter methods and arrays.
Chris@0 16 *
Chris@0 17 * The normalization process looks at all public methods and calls the ones
Chris@0 18 * which have a name starting with get and take no parameters. The result is a
Chris@0 19 * map from property names (method name stripped of the get prefix and converted
Chris@0 20 * to lower case) to property values. Property values are normalized through the
Chris@0 21 * serializer.
Chris@0 22 *
Chris@0 23 * The denormalization first looks at the constructor of the given class to see
Chris@0 24 * if any of the parameters have the same name as one of the properties. The
Chris@0 25 * constructor is then called with all parameters or an exception is thrown if
Chris@0 26 * any required parameters were not present as properties. Then the denormalizer
Chris@0 27 * walks through the given map of property names to property values to see if a
Chris@0 28 * setter method exists for any of the properties. If a setter exists it is
Chris@0 29 * called with the property value. No automatic denormalization of the value
Chris@0 30 * takes place.
Chris@0 31 *
Chris@0 32 * @author Nils Adermann <naderman@naderman.de>
Chris@0 33 * @author Kévin Dunglas <dunglas@gmail.com>
Chris@0 34 */
Chris@0 35 class GetSetMethodNormalizer extends AbstractObjectNormalizer
Chris@0 36 {
Chris@17 37 private static $setterAccessibleCache = [];
Chris@17 38 private $cache = [];
Chris@0 39
Chris@0 40 /**
Chris@0 41 * {@inheritdoc}
Chris@0 42 */
Chris@0 43 public function supportsNormalization($data, $format = null)
Chris@0 44 {
Chris@14 45 return parent::supportsNormalization($data, $format) && (isset($this->cache[$type = \get_class($data)]) ? $this->cache[$type] : $this->cache[$type] = $this->supports($type));
Chris@0 46 }
Chris@0 47
Chris@0 48 /**
Chris@0 49 * {@inheritdoc}
Chris@0 50 */
Chris@0 51 public function supportsDenormalization($data, $type, $format = null)
Chris@0 52 {
Chris@14 53 return parent::supportsDenormalization($data, $type, $format) && (isset($this->cache[$type]) ? $this->cache[$type] : $this->cache[$type] = $this->supports($type));
Chris@0 54 }
Chris@0 55
Chris@0 56 /**
Chris@0 57 * Checks if the given class has any get{Property} method.
Chris@0 58 *
Chris@0 59 * @param string $class
Chris@0 60 *
Chris@0 61 * @return bool
Chris@0 62 */
Chris@0 63 private function supports($class)
Chris@0 64 {
Chris@0 65 $class = new \ReflectionClass($class);
Chris@0 66 $methods = $class->getMethods(\ReflectionMethod::IS_PUBLIC);
Chris@0 67 foreach ($methods as $method) {
Chris@0 68 if ($this->isGetMethod($method)) {
Chris@0 69 return true;
Chris@0 70 }
Chris@0 71 }
Chris@0 72
Chris@0 73 return false;
Chris@0 74 }
Chris@0 75
Chris@0 76 /**
Chris@0 77 * Checks if a method's name is get.* or is.*, and can be called without parameters.
Chris@0 78 *
Chris@0 79 * @return bool whether the method is a getter or boolean getter
Chris@0 80 */
Chris@0 81 private function isGetMethod(\ReflectionMethod $method)
Chris@0 82 {
Chris@14 83 $methodLength = \strlen($method->name);
Chris@0 84
Chris@0 85 return
Chris@0 86 !$method->isStatic() &&
Chris@0 87 (
Chris@0 88 ((0 === strpos($method->name, 'get') && 3 < $methodLength) ||
Chris@14 89 (0 === strpos($method->name, 'is') && 2 < $methodLength) ||
Chris@14 90 (0 === strpos($method->name, 'has') && 3 < $methodLength)) &&
Chris@0 91 0 === $method->getNumberOfRequiredParameters()
Chris@0 92 )
Chris@0 93 ;
Chris@0 94 }
Chris@0 95
Chris@0 96 /**
Chris@0 97 * {@inheritdoc}
Chris@0 98 */
Chris@17 99 protected function extractAttributes($object, $format = null, array $context = [])
Chris@0 100 {
Chris@0 101 $reflectionObject = new \ReflectionObject($object);
Chris@0 102 $reflectionMethods = $reflectionObject->getMethods(\ReflectionMethod::IS_PUBLIC);
Chris@0 103
Chris@17 104 $attributes = [];
Chris@0 105 foreach ($reflectionMethods as $method) {
Chris@0 106 if (!$this->isGetMethod($method)) {
Chris@0 107 continue;
Chris@0 108 }
Chris@0 109
Chris@0 110 $attributeName = lcfirst(substr($method->name, 0 === strpos($method->name, 'is') ? 2 : 3));
Chris@0 111
Chris@18 112 if ($this->isAllowedAttribute($object, $attributeName, $format, $context)) {
Chris@0 113 $attributes[] = $attributeName;
Chris@0 114 }
Chris@0 115 }
Chris@0 116
Chris@0 117 return $attributes;
Chris@0 118 }
Chris@0 119
Chris@0 120 /**
Chris@0 121 * {@inheritdoc}
Chris@0 122 */
Chris@17 123 protected function getAttributeValue($object, $attribute, $format = null, array $context = [])
Chris@0 124 {
Chris@0 125 $ucfirsted = ucfirst($attribute);
Chris@0 126
Chris@0 127 $getter = 'get'.$ucfirsted;
Chris@17 128 if (\is_callable([$object, $getter])) {
Chris@0 129 return $object->$getter();
Chris@0 130 }
Chris@0 131
Chris@0 132 $isser = 'is'.$ucfirsted;
Chris@17 133 if (\is_callable([$object, $isser])) {
Chris@0 134 return $object->$isser();
Chris@0 135 }
Chris@14 136
Chris@14 137 $haser = 'has'.$ucfirsted;
Chris@17 138 if (\is_callable([$object, $haser])) {
Chris@14 139 return $object->$haser();
Chris@14 140 }
Chris@0 141 }
Chris@0 142
Chris@0 143 /**
Chris@0 144 * {@inheritdoc}
Chris@0 145 */
Chris@17 146 protected function setAttributeValue($object, $attribute, $value, $format = null, array $context = [])
Chris@0 147 {
Chris@0 148 $setter = 'set'.ucfirst($attribute);
Chris@14 149 $key = \get_class($object).':'.$setter;
Chris@0 150
Chris@0 151 if (!isset(self::$setterAccessibleCache[$key])) {
Chris@17 152 self::$setterAccessibleCache[$key] = \is_callable([$object, $setter]) && !(new \ReflectionMethod($object, $setter))->isStatic();
Chris@0 153 }
Chris@0 154
Chris@0 155 if (self::$setterAccessibleCache[$key]) {
Chris@0 156 $object->$setter($value);
Chris@0 157 }
Chris@0 158 }
Chris@0 159 }