comparison vendor/symfony/serializer/Normalizer/AbstractNormalizer.php @ 14:1fec387a4317

Update Drupal core to 8.5.2 via Composer
author Chris Cannam
date Mon, 23 Apr 2018 09:46:53 +0100
parents 7a779792577d
children c2387f117808
comparison
equal deleted inserted replaced
13:5fb285c0d0e3 14:1fec387a4317
25 * 25 *
26 * @author Kévin Dunglas <dunglas@gmail.com> 26 * @author Kévin Dunglas <dunglas@gmail.com>
27 */ 27 */
28 abstract class AbstractNormalizer extends SerializerAwareNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface 28 abstract class AbstractNormalizer extends SerializerAwareNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface
29 { 29 {
30 use ObjectToPopulateTrait;
31
30 const CIRCULAR_REFERENCE_LIMIT = 'circular_reference_limit'; 32 const CIRCULAR_REFERENCE_LIMIT = 'circular_reference_limit';
31 const OBJECT_TO_POPULATE = 'object_to_populate'; 33 const OBJECT_TO_POPULATE = 'object_to_populate';
32 const GROUPS = 'groups'; 34 const GROUPS = 'groups';
35 const ATTRIBUTES = 'attributes';
36 const ALLOW_EXTRA_ATTRIBUTES = 'allow_extra_attributes';
33 37
34 /** 38 /**
35 * @var int 39 * @var int
36 */ 40 */
37 protected $circularReferenceLimit = 1; 41 protected $circularReferenceLimit = 1;
66 */ 70 */
67 protected $camelizedAttributes = array(); 71 protected $camelizedAttributes = array();
68 72
69 /** 73 /**
70 * Sets the {@link ClassMetadataFactoryInterface} to use. 74 * Sets the {@link ClassMetadataFactoryInterface} to use.
71 *
72 * @param ClassMetadataFactoryInterface|null $classMetadataFactory
73 * @param NameConverterInterface|null $nameConverter
74 */ 75 */
75 public function __construct(ClassMetadataFactoryInterface $classMetadataFactory = null, NameConverterInterface $nameConverter = null) 76 public function __construct(ClassMetadataFactoryInterface $classMetadataFactory = null, NameConverterInterface $nameConverter = null)
76 { 77 {
77 $this->classMetadataFactory = $classMetadataFactory; 78 $this->classMetadataFactory = $classMetadataFactory;
78 $this->nameConverter = $nameConverter; 79 $this->nameConverter = $nameConverter;
79 } 80 }
80 81
81 /** 82 /**
82 * Set circular reference limit. 83 * Set circular reference limit.
83 * 84 *
84 * @param int $circularReferenceLimit limit of iterations for the same object 85 * @param int $circularReferenceLimit Limit of iterations for the same object
85 * 86 *
86 * @return self 87 * @return self
87 */ 88 */
88 public function setCircularReferenceLimit($circularReferenceLimit) 89 public function setCircularReferenceLimit($circularReferenceLimit)
89 { 90 {
107 } 108 }
108 109
109 /** 110 /**
110 * Set normalization callbacks. 111 * Set normalization callbacks.
111 * 112 *
112 * @param callable[] $callbacks help normalize the result 113 * @param callable[] $callbacks Help normalize the result
113 * 114 *
114 * @return self 115 * @return self
115 * 116 *
116 * @throws InvalidArgumentException if a non-callable callback is set 117 * @throws InvalidArgumentException if a non-callable callback is set
117 */ 118 */
118 public function setCallbacks(array $callbacks) 119 public function setCallbacks(array $callbacks)
119 { 120 {
120 foreach ($callbacks as $attribute => $callback) { 121 foreach ($callbacks as $attribute => $callback) {
121 if (!is_callable($callback)) { 122 if (!\is_callable($callback)) {
122 throw new InvalidArgumentException(sprintf( 123 throw new InvalidArgumentException(sprintf(
123 'The given callback for attribute "%s" is not callable.', 124 'The given callback for attribute "%s" is not callable.',
124 $attribute 125 $attribute
125 )); 126 ));
126 } 127 }
131 } 132 }
132 133
133 /** 134 /**
134 * Set ignored attributes for normalization and denormalization. 135 * Set ignored attributes for normalization and denormalization.
135 * 136 *
136 * @param array $ignoredAttributes
137 *
138 * @return self 137 * @return self
139 */ 138 */
140 public function setIgnoredAttributes(array $ignoredAttributes) 139 public function setIgnoredAttributes(array $ignoredAttributes)
141 { 140 {
142 $this->ignoredAttributes = $ignoredAttributes; 141 $this->ignoredAttributes = $ignoredAttributes;
186 * @throws CircularReferenceException 185 * @throws CircularReferenceException
187 */ 186 */
188 protected function handleCircularReference($object) 187 protected function handleCircularReference($object)
189 { 188 {
190 if ($this->circularReferenceHandler) { 189 if ($this->circularReferenceHandler) {
191 return call_user_func($this->circularReferenceHandler, $object); 190 return \call_user_func($this->circularReferenceHandler, $object);
192 } 191 }
193 192
194 throw new CircularReferenceException(sprintf('A circular reference has been detected when serializing the object of class "%s" (configured limit: %d)', get_class($object), $this->circularReferenceLimit)); 193 throw new CircularReferenceException(sprintf('A circular reference has been detected when serializing the object of class "%s" (configured limit: %d)', \get_class($object), $this->circularReferenceLimit));
195 } 194 }
196 195
197 /** 196 /**
198 * Gets attributes to normalize using groups. 197 * Gets attributes to normalize using groups.
199 * 198 *
203 * 202 *
204 * @return string[]|AttributeMetadataInterface[]|bool 203 * @return string[]|AttributeMetadataInterface[]|bool
205 */ 204 */
206 protected function getAllowedAttributes($classOrObject, array $context, $attributesAsString = false) 205 protected function getAllowedAttributes($classOrObject, array $context, $attributesAsString = false)
207 { 206 {
208 if (!$this->classMetadataFactory || !isset($context[static::GROUPS]) || !is_array($context[static::GROUPS])) { 207 if (!$this->classMetadataFactory) {
208 return false;
209 }
210
211 $groups = false;
212 if (isset($context[static::GROUPS]) && \is_array($context[static::GROUPS])) {
213 $groups = $context[static::GROUPS];
214 } elseif (!isset($context[static::ALLOW_EXTRA_ATTRIBUTES]) || $context[static::ALLOW_EXTRA_ATTRIBUTES]) {
209 return false; 215 return false;
210 } 216 }
211 217
212 $allowedAttributes = array(); 218 $allowedAttributes = array();
213 foreach ($this->classMetadataFactory->getMetadataFor($classOrObject)->getAttributesMetadata() as $attributeMetadata) { 219 foreach ($this->classMetadataFactory->getMetadataFor($classOrObject)->getAttributesMetadata() as $attributeMetadata) {
214 $name = $attributeMetadata->getName(); 220 $name = $attributeMetadata->getName();
215 221
216 if ( 222 if (
217 count(array_intersect($attributeMetadata->getGroups(), $context[static::GROUPS])) && 223 (false === $groups || array_intersect($attributeMetadata->getGroups(), $groups)) &&
218 $this->isAllowedAttribute($classOrObject, $name, null, $context) 224 $this->isAllowedAttribute($classOrObject, $name, null, $context)
219 ) { 225 ) {
220 $allowedAttributes[] = $attributesAsString ? $name : $attributeMetadata; 226 $allowedAttributes[] = $attributesAsString ? $name : $attributeMetadata;
221 } 227 }
222 } 228 }
234 * 240 *
235 * @return bool 241 * @return bool
236 */ 242 */
237 protected function isAllowedAttribute($classOrObject, $attribute, $format = null, array $context = array()) 243 protected function isAllowedAttribute($classOrObject, $attribute, $format = null, array $context = array())
238 { 244 {
239 return !in_array($attribute, $this->ignoredAttributes); 245 if (in_array($attribute, $this->ignoredAttributes)) {
246 return false;
247 }
248
249 if (isset($context[self::ATTRIBUTES][$attribute])) {
250 // Nested attributes
251 return true;
252 }
253
254 if (isset($context[self::ATTRIBUTES]) && is_array($context[self::ATTRIBUTES])) {
255 return in_array($attribute, $context[self::ATTRIBUTES], true);
256 }
257
258 return true;
240 } 259 }
241 260
242 /** 261 /**
243 * Normalizes the given data to an array. It's particularly useful during 262 * Normalizes the given data to an array. It's particularly useful during
244 * the denormalization process. 263 * the denormalization process.
286 * 305 *
287 * @return object 306 * @return object
288 * 307 *
289 * @throws RuntimeException 308 * @throws RuntimeException
290 */ 309 */
291 protected function instantiateObject(array &$data, $class, array &$context, \ReflectionClass $reflectionClass, $allowedAttributes/*, $format = null*/) 310 protected function instantiateObject(array &$data, $class, array &$context, \ReflectionClass $reflectionClass, $allowedAttributes/*, string $format = null*/)
292 { 311 {
293 if (func_num_args() >= 6) { 312 if (\func_num_args() >= 6) {
294 $format = func_get_arg(5); 313 $format = \func_get_arg(5);
295 } else { 314 } else {
296 if (__CLASS__ !== get_class($this)) { 315 if (__CLASS__ !== \get_class($this)) {
297 $r = new \ReflectionMethod($this, __FUNCTION__); 316 $r = new \ReflectionMethod($this, __FUNCTION__);
298 if (__CLASS__ !== $r->getDeclaringClass()->getName()) { 317 if (__CLASS__ !== $r->getDeclaringClass()->getName()) {
299 @trigger_error(sprintf('Method %s::%s() will have a 6th `$format = null` argument in version 4.0. Not defining it is deprecated since 3.2.', get_class($this), __FUNCTION__), E_USER_DEPRECATED); 318 @trigger_error(sprintf('Method %s::%s() will have a 6th `string $format = null` argument in version 4.0. Not defining it is deprecated since Symfony 3.2.', get_class($this), __FUNCTION__), E_USER_DEPRECATED);
300 } 319 }
301 } 320 }
302 321
303 $format = null; 322 $format = null;
304 } 323 }
305 324
306 if ( 325 if (null !== $object = $this->extractObjectToPopulate($class, $context, static::OBJECT_TO_POPULATE)) {
307 isset($context[static::OBJECT_TO_POPULATE]) &&
308 is_object($context[static::OBJECT_TO_POPULATE]) &&
309 $context[static::OBJECT_TO_POPULATE] instanceof $class
310 ) {
311 $object = $context[static::OBJECT_TO_POPULATE];
312 unset($context[static::OBJECT_TO_POPULATE]); 326 unset($context[static::OBJECT_TO_POPULATE]);
313 327
314 return $object; 328 return $object;
315 } 329 }
316 330
321 $params = array(); 335 $params = array();
322 foreach ($constructorParameters as $constructorParameter) { 336 foreach ($constructorParameters as $constructorParameter) {
323 $paramName = $constructorParameter->name; 337 $paramName = $constructorParameter->name;
324 $key = $this->nameConverter ? $this->nameConverter->normalize($paramName) : $paramName; 338 $key = $this->nameConverter ? $this->nameConverter->normalize($paramName) : $paramName;
325 339
326 $allowed = $allowedAttributes === false || in_array($paramName, $allowedAttributes); 340 $allowed = false === $allowedAttributes || \in_array($paramName, $allowedAttributes);
327 $ignored = in_array($paramName, $this->ignoredAttributes); 341 $ignored = !$this->isAllowedAttribute($class, $paramName, $format, $context);
328 if (method_exists($constructorParameter, 'isVariadic') && $constructorParameter->isVariadic()) { 342 if (method_exists($constructorParameter, 'isVariadic') && $constructorParameter->isVariadic()) {
329 if ($allowed && !$ignored && (isset($data[$key]) || array_key_exists($key, $data))) { 343 if ($allowed && !$ignored && (isset($data[$key]) || array_key_exists($key, $data))) {
330 if (!is_array($data[$paramName])) { 344 if (!\is_array($data[$paramName])) {
331 throw new RuntimeException(sprintf('Cannot create an instance of %s from serialized data because the variadic parameter %s can only accept an array.', $class, $constructorParameter->name)); 345 throw new RuntimeException(sprintf('Cannot create an instance of %s from serialized data because the variadic parameter %s can only accept an array.', $class, $constructorParameter->name));
332 } 346 }
333 347
334 $params = array_merge($params, $data[$paramName]); 348 $params = array_merge($params, $data[$paramName]);
335 } 349 }
339 if (null !== $constructorParameter->getClass()) { 353 if (null !== $constructorParameter->getClass()) {
340 if (!$this->serializer instanceof DenormalizerInterface) { 354 if (!$this->serializer instanceof DenormalizerInterface) {
341 throw new LogicException(sprintf('Cannot create an instance of %s from serialized data because the serializer inject in "%s" is not a denormalizer', $constructorParameter->getClass(), static::class)); 355 throw new LogicException(sprintf('Cannot create an instance of %s from serialized data because the serializer inject in "%s" is not a denormalizer', $constructorParameter->getClass(), static::class));
342 } 356 }
343 $parameterClass = $constructorParameter->getClass()->getName(); 357 $parameterClass = $constructorParameter->getClass()->getName();
344 $parameterData = $this->serializer->denormalize($parameterData, $parameterClass, $format, $context); 358 $parameterData = $this->serializer->denormalize($parameterData, $parameterClass, $format, $this->createChildContext($context, $paramName));
345 } 359 }
346 } catch (\ReflectionException $e) { 360 } catch (\ReflectionException $e) {
347 throw new RuntimeException(sprintf('Could not determine the class of the parameter "%s".', $key), 0, $e); 361 throw new RuntimeException(sprintf('Could not determine the class of the parameter "%s".', $key), 0, $e);
348 } 362 }
349 363
370 } 384 }
371 } 385 }
372 386
373 return new $class(); 387 return new $class();
374 } 388 }
389
390 /**
391 * @param array $parentContext
392 * @param string $attribute
393 *
394 * @return array
395 *
396 * @internal
397 */
398 protected function createChildContext(array $parentContext, $attribute)
399 {
400 if (isset($parentContext[self::ATTRIBUTES][$attribute])) {
401 $parentContext[self::ATTRIBUTES] = $parentContext[self::ATTRIBUTES][$attribute];
402 } else {
403 unset($parentContext[self::ATTRIBUTES]);
404 }
405
406 return $parentContext;
407 }
375 } 408 }