/** * Builds default context. * * @param ContextBuilderEvent $event */ public function onContextBuilder(ContextBuilderEvent $event) { $resource = $event->getResource(); if (null === $resource) { return; } $context = $event->getContext(); $prefixedShortName = sprintf('#%s', $resource->getShortName()); $attributes = $this->classMetadataFactory->getMetadataFor($resource->getEntityClass(), $resource->getNormalizationGroups(), $resource->getDenormalizationGroups(), $resource->getValidationGroups())->getAttributes(); foreach ($attributes as $attributeName => $attribute) { if ($attribute->isIdentifier()) { continue; } $convertedName = $this->nameConverter ? $this->nameConverter->normalize($attributeName) : $attributeName; if (!($id = $attribute->getIri())) { $id = sprintf('%s/%s', $prefixedShortName, $convertedName); } if ($attribute->isNormalizationLink()) { $context[$convertedName] = ['@id' => $id, '@type' => '@id']; } else { $context[$convertedName] = $id; } } $event->setContext($context); }
/** * {@inheritdoc} */ public function getResourceContext(string $resourceClass, int $referenceType = UrlGeneratorInterface::ABS_PATH) : array { $context = $this->getBaseContext($referenceType); $resourceMetadata = $this->resourceMetadataFactory->create($resourceClass); $prefixedShortName = sprintf('#%s', $resourceMetadata->getShortName()); foreach ($this->propertyNameCollectionFactory->create($resourceClass) as $propertyName) { $propertyMetadata = $this->propertyMetadataFactory->create($resourceClass, $propertyName); if ($propertyMetadata->isIdentifier() && true !== $propertyMetadata->isWritable()) { continue; } $convertedName = $this->nameConverter ? $this->nameConverter->normalize($propertyName) : $propertyName; $jsonldContext = $propertyMetadata->getAttributes()['jsonld_context'] ?? []; if (!($id = $propertyMetadata->getIri())) { $id = sprintf('%s/%s', $prefixedShortName, $convertedName); } if (true !== $propertyMetadata->isReadableLink()) { $jsonldContext += ['@id' => $id, '@type' => '@id']; } if (empty($jsonldContext)) { $context[$convertedName] = $id; } else { $context[$convertedName] = $jsonldContext + ['@id' => $id]; } } return $context; }
/** * Instantiates an object using constructor parameters when needed. * * This method also allows to denormalize data into an existing object if * it is present in the context with the object_to_populate key. * * @param array $data * @param string $class * @param array $context * @param \ReflectionClass $reflectionClass * @param array|bool $allowedAttributes * * @return object * * @throws RuntimeException */ protected function instantiateObject(array $data, $class, array &$context, \ReflectionClass $reflectionClass, $allowedAttributes) { if (isset($context['object_to_populate']) && is_object($context['object_to_populate']) && $class === get_class($context['object_to_populate'])) { return $context['object_to_populate']; } $constructor = $reflectionClass->getConstructor(); if ($constructor) { $constructorParameters = $constructor->getParameters(); $params = array(); foreach ($constructorParameters as $constructorParameter) { $paramName = $constructorParameter->name; $key = $this->nameConverter ? $this->nameConverter->normalize($paramName) : $paramName; $allowed = $allowedAttributes === false || in_array($paramName, $allowedAttributes); $ignored = in_array($paramName, $this->ignoredAttributes); if ($allowed && !$ignored && array_key_exists($key, $data)) { $params[] = $data[$key]; // don't run set for a parameter passed to the constructor unset($data[$key]); } elseif ($constructorParameter->isDefaultValueAvailable()) { $params[] = $constructorParameter->getDefaultValue(); } else { throw new RuntimeException(sprintf('Cannot create an instance of %s from serialized data because its constructor requires parameter "%s" to be present.', $class, $constructorParameter->name)); } } return $reflectionClass->newInstanceArgs($params); } return new $class(); }
/** * Builds the JSON-LD context for the given resource. * * @param ResourceInterface|null $resource * * @return array */ public function getContext(ResourceInterface $resource = null) { $context = $this->getBaseContext(); if ($resource) { $prefixedShortName = sprintf('#%s', $resource->getShortName()); $attributes = $this->classMetadataFactory->getMetadataFor($resource->getEntityClass(), $resource->getNormalizationGroups(), $resource->getDenormalizationGroups(), $resource->getValidationGroups())->getAttributes(); foreach ($attributes as $attributeName => $attribute) { $convertedName = $this->nameConverter ? $this->nameConverter->normalize($attributeName) : $attributeName; if (!($id = $attribute->getIri())) { $id = sprintf('%s/%s', $prefixedShortName, $convertedName); } if ($attribute->isNormalizationLink()) { $context[$convertedName] = ['@id' => $id, '@type' => '@id']; } else { $context[$convertedName] = $id; } } } return $context; }
/** * Instantiates an object using constructor parameters when needed. * * This method also allows to denormalize data into an existing object if * it is present in the context with the object_to_populate. This object * is removed from the context before being returned to avoid side effects * when recursively normalizing an object graph. * * @param array $data * @param string $class * @param array $context * @param \ReflectionClass $reflectionClass * @param array|bool $allowedAttributes * @param string|null $format * * @return object * * @throws RuntimeException */ protected function instantiateObject(array &$data, $class, array &$context, \ReflectionClass $reflectionClass, $allowedAttributes) { $format = func_num_args() >= 6 ? func_get_arg(5) : null; if (isset($context[static::OBJECT_TO_POPULATE]) && is_object($context[static::OBJECT_TO_POPULATE]) && $context[static::OBJECT_TO_POPULATE] instanceof $class) { $object = $context[static::OBJECT_TO_POPULATE]; unset($context[static::OBJECT_TO_POPULATE]); return $object; } $constructor = $this->getConstructor($data, $class, $context, $reflectionClass, $allowedAttributes); if ($constructor) { $constructorParameters = $constructor->getParameters(); $params = array(); foreach ($constructorParameters as $constructorParameter) { $paramName = $constructorParameter->name; $key = $this->nameConverter ? $this->nameConverter->normalize($paramName) : $paramName; $allowed = $allowedAttributes === false || in_array($paramName, $allowedAttributes); $ignored = in_array($paramName, $this->ignoredAttributes); if (method_exists($constructorParameter, 'isVariadic') && $constructorParameter->isVariadic()) { if ($allowed && !$ignored && (isset($data[$key]) || array_key_exists($key, $data))) { if (!is_array($data[$paramName])) { 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)); } $params = array_merge($params, $data[$paramName]); } } elseif ($allowed && !$ignored && (isset($data[$key]) || array_key_exists($key, $data))) { $parameterData = $data[$key]; try { if (null !== $constructorParameter->getClass()) { $parameterClass = $constructorParameter->getClass()->getName(); $parameterData = $this->serializer->deserialize($parameterData, $parameterClass, $format, $context); } } catch (\ReflectionException $e) { throw new RuntimeException(sprintf('Could not determine the class of the parameter "%s".', $key), 0, $e); } // Don't run set for a parameter passed to the constructor $params[] = $parameterData; unset($data[$key]); } elseif ($constructorParameter->isDefaultValueAvailable()) { $params[] = $constructorParameter->getDefaultValue(); } else { throw new RuntimeException(sprintf('Cannot create an instance of %s from serialized data because its constructor requires parameter "%s" to be present.', $class, $constructorParameter->name)); } } if ($constructor->isConstructor()) { return $reflectionClass->newInstanceArgs($params); } else { return $constructor->invokeArgs(null, $params); } } return new $class(); }
/** * Instantiates an object using constructor parameters when needed. * * This method also allows to denormalize data into an existing object if * it is present in the context with the object_to_populate. This object * is removed from the context before being returned to avoid side effects * when recursively normalizing an object graph. * * @param array $data * @param string $class * @param array $context * @param \ReflectionClass $reflectionClass * @param array|bool $allowedAttributes * @param string|null $format * * @return object * * @throws RuntimeException */ protected function instantiateObject(array &$data, $class, array &$context, \ReflectionClass $reflectionClass, $allowedAttributes) { if (func_num_args() >= 6) { $format = func_get_arg(5); } else { if (__CLASS__ !== get_class($this)) { $r = new \ReflectionMethod($this, __FUNCTION__); if (__CLASS__ !== $r->getDeclaringClass()->getName()) { @trigger_error(sprintf('Method %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); } } $format = null; } if (isset($context[static::OBJECT_TO_POPULATE]) && is_object($context[static::OBJECT_TO_POPULATE]) && $context[static::OBJECT_TO_POPULATE] instanceof $class) { $object = $context[static::OBJECT_TO_POPULATE]; unset($context[static::OBJECT_TO_POPULATE]); return $object; } $constructor = $this->getConstructor($data, $class, $context, $reflectionClass, $allowedAttributes); if ($constructor) { $constructorParameters = $constructor->getParameters(); $params = array(); foreach ($constructorParameters as $constructorParameter) { $paramName = $constructorParameter->name; $key = $this->nameConverter ? $this->nameConverter->normalize($paramName) : $paramName; $allowed = $allowedAttributes === false || in_array($paramName, $allowedAttributes); $ignored = in_array($paramName, $this->ignoredAttributes); if (method_exists($constructorParameter, 'isVariadic') && $constructorParameter->isVariadic()) { if ($allowed && !$ignored && (isset($data[$key]) || array_key_exists($key, $data))) { if (!is_array($data[$paramName])) { 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)); } $params = array_merge($params, $data[$paramName]); } } elseif ($allowed && !$ignored && (isset($data[$key]) || array_key_exists($key, $data))) { $parameterData = $data[$key]; try { if (null !== $constructorParameter->getClass()) { if (!$this->serializer instanceof DenormalizerInterface) { 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)); } $parameterClass = $constructorParameter->getClass()->getName(); $parameterData = $this->serializer->denormalize($parameterData, $parameterClass, $format, $context); } } catch (\ReflectionException $e) { throw new RuntimeException(sprintf('Could not determine the class of the parameter "%s".', $key), 0, $e); } // Don't run set for a parameter passed to the constructor $params[] = $parameterData; unset($data[$key]); } elseif ($constructorParameter->isDefaultValueAvailable()) { $params[] = $constructorParameter->getDefaultValue(); } else { throw new RuntimeException(sprintf('Cannot create an instance of %s from serialized data because its constructor requires parameter "%s" to be present.', $class, $constructorParameter->name)); } } if ($constructor->isConstructor()) { return $reflectionClass->newInstanceArgs($params); } else { return $constructor->invokeArgs(null, $params); } } return new $class(); }