@param DataInterface $object
@param string        $attribute
@param string        $format
@param array         $context

@throws \Symfony\Component\PropertyAccess\Exception\ExceptionInterface

@return mixed
332442
protected function getAttributeValue(
        DataInterface $object,
        $attribute,
        $format = null,
        array $context = []
    ) {
        $rawValue = $this->propertyAccessor->getValue($object, $attribute);
        $subContext = $this->getAttributeContext($object, $attribute, $rawValue, $context);

        return $this->normalizer->normalize($rawValue, $format, $subContext);
    }
991862
protected function denormalizeRelation(string $attributeName, PropertyMetadata $propertyMetadata, string $className, $value, ?string $format, array $context)
    {
        if (\is_string($value)) {
            try {
                return $this->iriConverter->getItemFromIri($value, $context + ['fetch_data' => true]);
            } catch (ItemNotFoundException $e) {
                throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
            } catch (InvalidArgumentException $e) {
                // Give a chance to other normalizers (e.g.: DateTimeNormalizer)
            }
        }

        if (
            !$this->resourceClassResolver->isResourceClass($className) ||
            $propertyMetadata->isWritableLink()
        ) {
            $context['resource_class'] = $className;
            $context['api_allow_update'] = true;

            try {
                if (!$this->serializer instanceof DenormalizerInterface) {
                    throw new LogicException(sprintf('The injected serializer must be an instance of "%s".', DenormalizerInterface::class));
                }

                return $this->serializer->denormalize($value, $className, $format, $context);
            } catch (InvalidValueException $e) {
                if (!$this->allowPlainIdentifiers || null === $this->itemDataProvider) {
                    throw $e;
                }
            }
        }

        if (!\is_array($value)) {
            // repeat the code so that IRIs keep working with the json format
            if (true === $this->allowPlainIdentifiers && $this->itemDataProvider) {
                $item = $this->itemDataProvider->getItem($className, $value, null, $context + ['fetch_data' => true]);
                if (null === $item) {
                    throw new ItemNotFoundException(sprintf('Item not found for "%s".', $value));
                }

                return $item;
            }

            throw new UnexpectedValueException(sprintf(
                'Expected IRI or nested document for attribute "%s", "%s" given.', $attributeName, \gettype($value)
            ));
        }

        throw new UnexpectedValueException(sprintf('Nested documents for attribute "%s" are not allowed. Use IRIs instead.', $attributeName));
    }
795600
private function processSerializeTypeCollectionObject($objectType, $object, array $data, string $attribute): array
    {
        $subData = $object->{$objectType->getter()}();
        if ($this->checkNullForAttribute($subData, $attribute) === true) {
            return $data;
        }

        foreach ($subData as $key => $subObject) {
            $data = $this->setArrayAndCheckNullWithKey($data, $subObject, $key, $attribute);
        }

        return $data;
    }
1061457
protected function getAttributeValue($object, $attribute, $format = null, array $context = [])
    {
        $context['api_attribute'] = $attribute;
        $propertyMetadata = $this->propertyMetadataFactory->create($context['resource_class'], $attribute, $this->getFactoryOptions($context));

        try {
            $attributeValue = $this->propertyAccessor->getValue($object, $attribute);
        } catch (NoSuchPropertyException $e) {
            if (!$propertyMetadata->hasChildInherited()) {
                throw $e;
            }

            $attributeValue = null;
        }

        $type = $propertyMetadata->getType();

        if (
            is_iterable($attributeValue) &&
            $type &&
            $type->isCollection() &&
            ($collectionValueType = $type->getCollectionValueType()) &&
            ($className = $collectionValueType->getClassName()) &&
            $this->resourceClassResolver->isResourceClass($className)
        ) {
            return $this->normalizeCollectionOfRelations($propertyMetadata, $attributeValue, $className, $format, $this->createChildContext($context, $attribute));
        }

        if (
            $type &&
            ($className = $type->getClassName()) &&
            $this->resourceClassResolver->isResourceClass($className)
        ) {
            return $this->normalizeRelation($propertyMetadata, $attributeValue, $className, $format, $this->createChildContext($context, $attribute));
        }

        unset($context['resource_class']);

        if (!$this->serializer instanceof NormalizerInterface) {
            throw new LogicException(sprintf('The injected serializer must be an instance of "%s".', NormalizerInterface::class));
        }

        return $this->serializer->normalize($attributeValue, $format, $context);
    }
267765
protected function isAllowedEAVAttribute(
        DataInterface $object,
        AttributeInterface $attribute,
        /** @noinspection PhpUnusedParameterInspection */
        $format = null,
        array $context = []
    ) {
        $options = $attribute->getOption(static::SERIALIZER_OPTIONS, []);

        // Ignore attributes set as serializer: expose: false
        if (array_key_exists(static::EXPOSE_KEY, $options) && !$options[static::EXPOSE_KEY]) {
            return false;
        }

        // If normalizing by reference, we just check if it's among the allowed attributes
        if ($this->byReferenceHandler->isByReference($context)) {
            return \in_array($attribute->getCode(), $this->referenceAttributes, true);
        }

        // Also check ignored attributes
        if (\in_array($attribute->getCode(), $this->ignoredAttributes, true)) {
            return false;
        }

        return $this->isEAVGroupAllowed($object, $attribute, $context);
    }
1284403
private function populateRelation(array $data, $object, ?string $format, array $context, array $components, string $type): array
    {
        $class = $this->getObjectClass($object);

        $attributesMetadata = \array_key_exists($class, $this->attributesMetadataCache) ?
            $this->attributesMetadataCache[$class] :
            $this->attributesMetadataCache[$class] = $this->classMetadataFactory ? $this->classMetadataFactory->getMetadataFor($class)->getAttributesMetadata() : null;

        $key = '_'.$type;
        foreach ($components[$type] as $relation) {
            if (null !== $attributesMetadata && $this->isMaxDepthReached($attributesMetadata, $class, $relation['name'], $context)) {
                continue;
            }

            $attributeValue = $this->getAttributeValue($object, $relation['name'], $format, $context);
            if (empty($attributeValue)) {
                continue;
            }

            $relationName = $relation['name'];
            if ($this->nameConverter) {
                $relationName = $this->nameConverter->normalize($relationName, $class, $format, $context);
            }

            if ('one' === $relation['cardinality']) {
                if ('links' === $type) {
                    $data[$key][$relationName]['href'] = $this->getRelationIri($attributeValue);
                    continue;
                }

                $data[$key][$relationName] = $attributeValue;
                continue;
            }

            // many
            $data[$key][$relationName] = [];
            foreach ($attributeValue as $rel) {
                if ('links' === $type) {
                    $rel = ['href' => $this->getRelationIri($rel)];
                }

                $data[$key][$relationName][] = $rel;
            }
        }

        return $data;
    }
293136
protected function isEAVGroupAllowed(/** @noinspection PhpUnusedParameterInspection */
        DataInterface $object,
        AttributeInterface $attribute,
        array $context
    ) {
        if (!isset($context[static::GROUPS]) || !\is_array($context[static::GROUPS])) {
            return true;
        }

        $serializerOptions = $attribute->getOption(static::SERIALIZER_OPTIONS, []);
        if (!array_key_exists(static::GROUPS, $serializerOptions)) {
            return false;
        }

        $groups = $serializerOptions[static::GROUPS];
        if (!\is_array($groups)) {
            throw new InvalidArgumentException(
                "Invalid 'serializer.groups' option for attribute {$attribute->getCode()} : should be an array"
            );
        }

        return 0 < \count(array_intersect($groups, $context[static::GROUPS]));
    }
486747
private function processSerializeForType(Configuration\TypeInterface $type, $object, array $data, $attribute): array
    {
        if ($type instanceof Type\Method) {
            $data = $this->processSerializeTypeMethod($type, $object, $data, $attribute);
        } elseif ($type instanceof Type\Object) {
            $data = $this->processSerializeTypeObject($type, $object, $data, $attribute);
        } elseif ($type instanceof Type\Collection\Object) {
            $data = $this->processSerializeTypeCollectionObject($type, $object, $data, $attribute);
        } elseif ($type instanceof Type\IdentifiedObject) {
            $data = $this->processSerializeTypeIdentifiedObject($type, $object, $data, $attribute);
        } elseif ($type instanceof Type\Collection\IdentifiedObject) {
            $data = $this->processSerializeTypeCollectionObject($type, $object, $data, $attribute);
        } elseif ($type instanceof Type\Handler) {
            $data = $this->processSerializeTypeHandler($type, $object, $data, $attribute);
        }

        return $data;
    }
396306
protected function instantiateObject(
        array &$data,
        $class,
        array &$context,
        \ReflectionClass $reflectionClass,
        $allowedAttributes,
        string $format = null
    ): object {
        return $reflectionClass->newInstanceWithoutConstructor();
    }
664061
protected function denormalizeRelation(string $attributeName, PropertyMetadata $propertyMetadata, string $className, $value, ?string $format, array $context)
    {
        // Give a chance to other normalizers (e.g.: DateTimeNormalizer)
        if (!$this->resourceClassResolver->isResourceClass($className)) {
            $context['resource_class'] = $className;

            if ($this->serializer instanceof DenormalizerInterface) {
                return $this->serializer->denormalize($value, $className, $format, $context);
            }
            throw new LogicException(sprintf('The injected serializer must be an instance of "%s".', DenormalizerInterface::class));
        }

        if (!\is_array($value) || !isset($value['id'], $value['type'])) {
            throw new NotNormalizableValueException('Only resource linkage supported currently, see: http://jsonapi.org/format/#document-resource-object-linkage.');
        }

        try {
            return $this->iriConverter->getItemFromIri($value['id'], $context + ['fetch_data' => true]);
        } catch (ItemNotFoundException $e) {
            throw new RuntimeException($e->getMessage(), $e->getCode(), $e);
        }
    }
1033091
protected function createChildContext(array $parentContext, $attribute/*, string $format = null */)
    {
        if (\func_num_args() >= 3) {
            $format = \func_get_arg(2);
        } else {
            // will be deprecated in version 4
            $format = null;
        }

        $context = parent::createChildContext($parentContext, $attribute, $format);
        // format is already included in the cache_key of the parent.
        $context['cache_key'] = $this->getCacheKey($format, $context);

        return $context;
    }
164787
private function processSerializeTypeObject(Type\Object $objectType, $object, array $data, string $attribute): array
    {
        return $this->setArrayAndCheckNull($data, $object->{$objectType->getter()}(), $attribute);
    }
120930
public function normalize($object, $format = null, array $context = [])
    {
        $this->maxDepthHandler->handleMaxDepth($context);

        if ($this->byReferenceHandler->isByShortReference($context)) {
            return $this->getShortReference($object, $format, $context);
        }

        if ($this->byReferenceHandler->isByReference($context)) {
            return $this->getReference($object, $format, $context);
        }

        try {
            return parent::normalize($object, $format, $context);
        } catch (CircularReferenceException $e) {
            return $this->getShortReference($object, $format, $context);
        }
    }
638116
protected function denormalizeObject($data, $class, $format, array $context)
    {
        if (!$this->serializer instanceof DenormalizerInterface) {
            throw new LogicException(
                'Cannot denormalize object because the injected serializer is not a denormalizer'
            );
        }

        return $this->serializer->denormalize($data, $class, $format, $context);
    }
1090793
public function normalize($object, $format = null, array $context = [])
    {
        /** @var object $normalized */
        $normalized = parent::normalize($object, $format, $context);
        $normalized->type = RatePlanInterface::TYPE_DEVELOPER;

        return $normalized;
    }
482730
protected function getAttributeContext(
        DataInterface $object,
        $attribute,
        /** @noinspection PhpUnusedParameterInspection */
        $rawValue,
        array $context
    ) {
        return array_merge(
            $context,
            [
                'parent' => $object,
                'attribute' => $attribute,
            ]
        );
    }
530709
public function execute(object $object, array $properties, array $methodPrefixes = ['set', 'add']): object
    {
        try {
            foreach ($properties as $property => $value) {
                if (false === $this->assignValueWithSetterMethod($object, [$property, $value], $methodPrefixes)) {
                    $object->$property = $value;
                }
            }

            return $object;
        } catch (\Throwable $t) {
            throw new PropertyNotAccessibleException($t->getMessage());
        }
    }