/**
  * @param AttributeMetadataInterface $attributeMetadata
  *
  * @return mixed
  */
 public function guess(AttributeMetadataInterface $attributeMetadata)
 {
     $value = null;
     $type = null;
     if (true === ($isDoctrine = isset($attributeMetadata->getTypes()[0]))) {
         $type = $attributeMetadata->getTypes()[0];
     }
     // Guess associations
     if ($isDoctrine && 'object' === $type->getType() && 'DateTime' !== $type->getClass()) {
         $class = $type->isCollection() ? $type->getCollectionType()->getClass() : $type->getClass();
         $resource = $this->resourceCollection->getResourceForEntity($class);
         $classMetadata = $this->classMetadataFactory->getMetadataFor($resource->getEntityClass(), $resource->getNormalizationGroups(), $resource->getDenormalizationGroups(), $resource->getValidationGroups());
         $id = $this->guess($classMetadata->getIdentifier());
         $value = $this->iriConverter->getIriFromResource($resource) . '/' . $id;
         if ($type->isCollection()) {
             $value = [$value];
         }
     }
     // Guess by faker
     if (null === $value) {
         try {
             $value = call_user_func([$this->generator, $attributeMetadata->getName()]);
         } catch (\InvalidArgumentException $e) {
         }
     }
     // Guess by field name
     if (null === $value) {
         $value = $this->guessFormat(Inflector::tableize($attributeMetadata->getName()));
     }
     // Guess by Doctrine type
     if (null === $value && $isDoctrine) {
         switch ($type->getType()) {
             case 'string':
                 $value = $this->generator->sentence;
                 break;
             case 'int':
                 $value = $this->generator->numberBetween;
                 break;
             case 'bool':
                 $value = $this->generator->boolean;
                 break;
             case 'object':
                 if ('DateTime' !== $type->getClass()) {
                     throw new \InvalidArgumentException(sprintf('Unknown Doctrine object type %s in field %s', $type->getClass(), $attributeMetadata->getName()));
                 }
                 $value = $this->generator->dateTime;
                 break;
         }
     }
     return $this->clean($value);
 }
 /**
  * Denormalizes a relation.
  *
  * @param ResourceInterface          $currentResource
  * @param AttributeMetadataInterface $attributeMetadata
  * @param string                     $class
  * @param mixed                      $value
  * @param array                      $context
  *
  * @return object|null
  *
  * @throws InvalidArgumentException
  */
 private function denormalizeRelation(ResourceInterface $currentResource, AttributeMetadataInterface $attributeMetadata, $class, $value, array $context)
 {
     if ('DateTime' === $class) {
         return $this->serializer->denormalize($value, $class ?: null, self::FORMAT, $context);
     }
     $attributeName = $attributeMetadata->getName();
     // Always allow IRI to be compliant with the Hydra spec
     if (is_string($value)) {
         $item = $this->iriConverter->getItemFromIri($value);
         if (null === $item) {
             throw new InvalidArgumentException(sprintf('IRI  not supported (found "%s" in "%s" of "%s")', $value, $attributeName, $currentResource->getEntityClass()));
         }
         return $item;
     }
     if (!($resource = $this->resourceCollection->getResourceForEntity($class))) {
         throw new InvalidArgumentException(sprintf('Type not supported (found "%s" in attribute "%s" of "%s")', $class, $attributeName, $currentResource->getEntityClass()));
     }
     if (!$attributeMetadata->isDenormalizationLink()) {
         return $this->serializer->denormalize($value, $class, self::FORMAT, $this->createRelationContext($resource, $context));
     }
     throw new InvalidArgumentException(sprintf('Nested objects for attribute "%s" of "%s" are not enabled. Use serialization groups to change that behavior.', $attributeName, $currentResource->getEntityClass()));
 }
 /**
  * Parses an attribute.
  *
  * @param ResourceInterface          $resource
  * @param AttributeMetadataInterface $attributeMetadata
  * @param string                     $io
  * @param Type|null                  $type
  *
  * @return array
  */
 private function parseAttribute(ResourceInterface $resource, AttributeMetadataInterface $attributeMetadata, $io, Type $type = null)
 {
     $data = array('dataType' => null, 'required' => $attributeMetadata->isRequired(), 'description' => $attributeMetadata->getDescription(), 'readonly' => !$attributeMetadata->isWritable());
     if (null == $type) {
         if (!isset($attributeMetadata->getTypes()[0])) {
             // Default to string
             $data['dataType'] = DataTypes::STRING;
             return $data;
         }
         // Use the first type found as primary
         $type = $attributeMetadata->getTypes()[0];
     }
     if ($type->isCollection()) {
         $data['actualType'] = DataTypes::COLLECTION;
         if ($collectionType = $type->getCollectionType()) {
             $subAttribute = $this->parseAttribute($resource, $attributeMetadata, $io, $collectionType);
             if (self::IRI === $subAttribute['dataType']) {
                 $data['dataType'] = 'array of IRIs';
                 $data['subType'] = DataTypes::STRING;
                 return $data;
             }
             $data['subType'] = $subAttribute['subType'];
             $data['children'] = $subAttribute['children'];
         }
         return $data;
     }
     $phpType = $type->getType();
     if ('object' === $phpType) {
         $class = $type->getClass();
         if ('DateTime' === $class) {
             $data['dataType'] = DataTypes::DATETIME;
             $data['format'] = sprintf('{DateTime %s}', \DateTime::ATOM);
             return $data;
         }
         if (self::OUT_PREFIX === $io && $attributeMetadata->isNormalizationLink() || self::IN_PREFIX === $io && $attributeMetadata->isDenormalizationLink()) {
             $data['dataType'] = self::IRI;
             $data['actualType'] = DataTypes::STRING;
             return $data;
         }
         $data['actualType'] = DataTypes::MODEL;
         $data['subType'] = $class;
         $data['children'] = $resource->getEntityClass() === $class ? [] : $this->parseClass($resource, $class, $io);
         return $data;
     }
     $data['dataType'] = isset(self::$typeMap[$type->getType()]) ? self::$typeMap[$type->getType()] : DataTypes::STRING;
     return $data;
 }
 /**
  * Gets the range of the property.
  *
  * @param AttributeMetadataInterface $attributeMetadata
  *
  * @return string|null
  */
 private function getRange(AttributeMetadataInterface $attributeMetadata)
 {
     if (isset($attributeMetadata->getTypes()[0])) {
         $type = $attributeMetadata->getTypes()[0];
         if ($type->isCollection() && ($collectionType = $type->getCollectionType())) {
             $type = $collectionType;
         }
         switch ($type->getType()) {
             case 'string':
                 return 'xmls:string';
             case 'int':
                 return 'xmls:integer';
             case 'float':
                 return 'xmls:double';
             case 'bool':
                 return 'xmls:boolean';
             case 'object':
                 $class = $type->getClass();
                 if ($class) {
                     if ('DateTime' === $class) {
                         return 'xmls:dateTime';
                     }
                     if ($resource = $this->resourceCollection->getResourceForEntity($type->getClass())) {
                         return sprintf('#%s', $resource->getShortName());
                     }
                 }
                 break;
         }
     }
 }
 /**
  * Populates normalization and denormalization links.
  *
  * @param ClassMetadataInterface     $classMetadata
  * @param string                     $attributeName
  * @param AttributeMetadataInterface $attributeMetadata
  * @param array|null                 $normalizationGroups
  * @param array|null                 $denormalizationGroups
  *
  * @return ClassMetadataInterface
  */
 private function populateNormalizationLinks(ClassMetadataInterface $classMetadata, $attributeName, AttributeMetadataInterface $attributeMetadata, array $normalizationGroups = null, array $denormalizationGroups = null)
 {
     if (!$classMetadata->hasAttributeMetadata($attributeName) || !$attributeMetadata->isLink() || $attributeMetadata->isNormalizationLink() && $attributeMetadata->isDenormalizationLink()) {
         return $classMetadata;
     }
     $relationSerializerMetadata = $this->serializerClassMetadataFactory->getMetadataFor($attributeMetadata->getLinkClass());
     if (!$relationSerializerMetadata) {
         $attributeMetadata = $attributeMetadata->withNormalizationLink(true)->withDenormalizationLink(true);
         return $classMetadata->withAttributeMetadata($attributeName, $attributeMetadata);
     }
     foreach ($relationSerializerMetadata->getAttributesMetadata() as $serializerAttributeMetadata) {
         $serializerAttributeGroups = $serializerAttributeMetadata->getGroups();
         if (null !== $normalizationGroups && 1 <= count(array_intersect($normalizationGroups, $serializerAttributeGroups))) {
             $normalizationLink = false;
         }
         if (null !== $denormalizationGroups && 1 <= count(array_intersect($denormalizationGroups, $serializerAttributeGroups))) {
             $denormalizationLink = false;
         }
         if (isset($normalizationLink) && isset($denormalizationLink)) {
             $classMetadata = $classMetadata->withAttributeMetadata($attributeName, $attributeMetadata);
         }
     }
     if (!isset($normalizationLink)) {
         $attributeMetadata = $attributeMetadata->withNormalizationLink(true);
     }
     if (!isset($denormalizationLink)) {
         $attributeMetadata = $attributeMetadata->withDenormalizationLink(true);
     }
     return $classMetadata->withAttributeMetadata($attributeName, $attributeMetadata);
 }