/** * @param array $definition * @param string $entityClass * * @return bool */ protected function updateRelations(array &$definition, $entityClass) { $hasChanges = false; $metadata = $this->doctrineHelper->getEntityMetadataForClass($entityClass); foreach ($definition[ConfigUtil::FIELDS] as $fieldName => &$fieldConfig) { if (!is_array($fieldConfig) || empty($fieldConfig[ConfigUtil::DEFINITION][ConfigUtil::FIELDS])) { continue; } $fieldDefinition = $fieldConfig[ConfigUtil::DEFINITION]; if (ConfigUtil::isExclude($fieldDefinition)) { continue; } $propertyPath = ConfigUtil::getPropertyPath($fieldDefinition, $fieldName); if (!$metadata->hasAssociation($propertyPath)) { continue; } $mapping = $metadata->getAssociationMapping($propertyPath); $targetMetadata = $this->doctrineHelper->getEntityMetadataForClass($mapping['targetEntity']); if ($this->isResourceForRelatedEntityAccessible($targetMetadata)) { continue; } $fieldDefinition[ConfigUtil::EXCLUDE] = true; $fieldConfig[ConfigUtil::DEFINITION] = $fieldDefinition; $hasChanges = true; } return $hasChanges; }
/** * {@inheritdoc} */ public function process(ContextInterface $context) { /** @var MetadataContext $context */ if ($context->hasResult()) { // metadata is already loaded return; } $entityClass = $context->getClassName(); if (!$this->doctrineHelper->isManageableEntityClass($entityClass)) { // only manageable entities are supported return; } // filter excluded fields on this stage though there is another processor doing the same // it is done due to performance reasons $allowedFields = $this->getAllowedFields($context->getConfig()); $classMetadata = $this->doctrineHelper->getEntityMetadataForClass($entityClass); $entityMetadata = $this->entityMetadataFactory->createEntityMetadata($classMetadata); $fields = $classMetadata->getFieldNames(); foreach ($fields as $fieldName) { if (!isset($allowedFields[$fieldName])) { continue; } $entityMetadata->addField($this->entityMetadataFactory->createFieldMetadata($classMetadata, $fieldName)); } $associations = $classMetadata->getAssociationNames(); foreach ($associations as $associationName) { if (!isset($allowedFields[$associationName])) { continue; } $entityMetadata->addAssociation($this->entityMetadataFactory->createAssociationMetadata($classMetadata, $associationName)); } $context->setResult($entityMetadata); }
/** * @param array $definition * @param string $entityClass * @param string $version * @param string[] $requestType * @param array $extras * * @return array */ protected function completeDefinition(array $definition, $entityClass, $version, array $requestType, array $extras) { $metadata = $this->doctrineHelper->getEntityMetadataForClass($entityClass); $definition = $this->getFields($definition, $metadata, $version, $requestType, $extras); $definition = $this->getAssociations($definition, $metadata, $version, $requestType, $extras); return $definition; }
/** * @param array $definition * @param string $entityClass * * @return bool */ protected function updateRelations(array &$definition, $entityClass) { $hasChanges = false; $metadata = $this->doctrineHelper->getEntityMetadataForClass($entityClass); foreach ($definition[ConfigUtil::FIELDS] as $fieldName => &$fieldConfig) { if (!is_array($fieldConfig) || empty($fieldConfig[ConfigUtil::DEFINITION][ConfigUtil::FIELDS])) { continue; } $fieldDefinition = $fieldConfig[ConfigUtil::DEFINITION]; $propertyPath = ConfigUtil::getPropertyPath($fieldDefinition, $fieldName); if (!$metadata->hasAssociation($propertyPath)) { continue; } $mapping = $metadata->getAssociationMapping($propertyPath); $targetMetadata = $this->doctrineHelper->getEntityMetadataForClass($mapping['targetEntity']); if ($targetMetadata->inheritanceType === ClassMetadata::INHERITANCE_TYPE_NONE) { continue; } if (!is_array($fieldDefinition[ConfigUtil::FIELDS])) { $fieldDefinition[ConfigUtil::FIELDS] = [$fieldDefinition[ConfigUtil::FIELDS] => null]; } $fieldDefinition[ConfigUtil::FIELDS][ConfigUtil::CLASS_NAME] = null; $fieldConfig[ConfigUtil::DEFINITION] = $fieldDefinition; $hasChanges = true; } return $hasChanges; }
/** * Checks whether the given field is an identifier of the given entity * * @param string $entityClass * @param string $fieldName * * @return bool */ protected function isIdentifierField($entityClass, $fieldName) { $metadata = $this->doctrineHelper->getEntityMetadataForClass($entityClass, false); if (null === $metadata) { return false; } $idFieldNames = $metadata->getIdentifierFieldNames(); return count($idFieldNames) === 1 && reset($idFieldNames) === $fieldName; }
/** * {@inheritdoc} */ public function reverseTransform($entityClass, $value) { if ($this->doctrineHelper->isManageableEntityClass($entityClass)) { $metadata = $this->doctrineHelper->getEntityMetadataForClass($entityClass); $idFields = $metadata->getIdentifierFieldNames(); $value = count($idFields) === 1 ? $this->reverseTransformSingleId($value, $metadata->getTypeOfField(reset($idFields))) : $this->reverseTransformCombinedEntityId($value, $idFields, $metadata); } return $value; }
/** * @param array $definition * @param ConfigContext $context */ protected function setCustomizationHandler(array &$definition, ConfigContext $context) { $entityClass = $context->getClassName(); $definition[ConfigUtil::POST_SERIALIZE] = $this->getRootCustomizationHandler($context, $entityClass, isset($definition[ConfigUtil::POST_SERIALIZE]) ? $definition[ConfigUtil::POST_SERIALIZE] : null); if (!$this->doctrineHelper->isManageableEntityClass($entityClass)) { // we can set customization handlers for associations only for manageable entity, // because for other types of entities we do not have metadata return; } if (isset($definition[ConfigUtil::FIELDS]) && is_array($definition[ConfigUtil::FIELDS])) { $this->processFields($context, $definition[ConfigUtil::FIELDS], $entityClass, $this->doctrineHelper->getEntityMetadataForClass($entityClass)); } }
/** * @param array $filters * @param string $entityClass * @param array|null $config * * @return array */ protected function completeFilters(array $filters, $entityClass, $config) { $metadata = $this->doctrineHelper->getEntityMetadataForClass($entityClass); $filters = $this->getFieldFilters($filters, $metadata); $filters = $this->getAssociationFilters($filters, $metadata); if (!empty($config)) { foreach ($filters as $fieldName => &$fieldConfig) { if (ConfigUtil::isExcludedField($config, $fieldName)) { $fieldConfig[ConfigUtil::EXCLUDE] = true; } } } return $filters; }
/** * @param ClassMetadata $classMetadata * @param string $associationName * * @return AssociationMetadata */ public function createAssociationMetadata(ClassMetadata $classMetadata, $associationName) { $targetClass = $classMetadata->getAssociationTargetClass($associationName); $associationMetadata = new AssociationMetadata(); $associationMetadata->setName($associationName); $associationMetadata->setTargetClassName($targetClass); $associationMetadata->setIsCollection($classMetadata->isCollectionValuedAssociation($associationName)); $targetMetadata = $this->doctrineHelper->getEntityMetadataForClass($targetClass); $targetIdFields = $targetMetadata->getIdentifierFieldNames(); if (count($targetIdFields) === 1) { $associationMetadata->setDataType($targetMetadata->getTypeOfField(reset($targetIdFields))); } else { $associationMetadata->setDataType(DataType::STRING); } return $associationMetadata; }
/** * @param ApiDoc $annotation * @param string $entityClass * @param string $requirement */ protected function addIdRequirement(ApiDoc $annotation, $entityClass, $requirement) { $metadata = $this->doctrineHelper->getEntityMetadataForClass($entityClass); $idFields = $metadata->getIdentifierFieldNames(); $dataType = count($idFields) === 1 ? $metadata->getTypeOfField(reset($idFields)) : DataType::STRING; $annotation->addRequirement(RestRouteOptionsResolver::ID_ATTRIBUTE, ['dataType' => ApiDocDataTypeConverter::convertToApiDocDataType($dataType), 'requirement' => $requirement, 'description' => self::ID_DESCRIPTION]); }
/** * @param array $sorters * @param string $entityClass * @param array|null $config * * @return array */ protected function completeSorters(array $sorters, $entityClass, $config) { $metadata = $this->doctrineHelper->getEntityMetadataForClass($entityClass); $fields = array_merge(array_keys($this->doctrineHelper->getIndexedFields($metadata)), array_keys($this->doctrineHelper->getIndexedAssociations($metadata))); foreach ($fields as $fieldName) { if (array_key_exists($fieldName, $sorters)) { // already defined continue; } $sorters[$fieldName] = null; } if (!empty($config)) { foreach ($sorters as $fieldName => &$fieldConfig) { if (ConfigUtil::isExcludedField($config, $fieldName)) { $fieldConfig[ConfigUtil::EXCLUDE] = true; } } } return $sorters; }
/** * @param ClassMetadata $classMetadata * @param string $associationName * * @return AssociationMetadata */ public function createAssociationMetadata(ClassMetadata $classMetadata, $associationName) { $targetClass = $classMetadata->getAssociationTargetClass($associationName); $associationMetadata = new AssociationMetadata(); $associationMetadata->setName($associationName); $associationMetadata->setTargetClassName($targetClass); $associationMetadata->setIsCollection($classMetadata->isCollectionValuedAssociation($associationName)); $targetMetadata = $this->doctrineHelper->getEntityMetadataForClass($targetClass); $targetIdFields = $targetMetadata->getIdentifierFieldNames(); if (count($targetIdFields) === 1) { $associationMetadata->setDataType($targetMetadata->getTypeOfField(reset($targetIdFields))); } else { $associationMetadata->setDataType(DataType::STRING); } if ($targetMetadata->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) { $associationMetadata->setAcceptableTargetClassNames($targetMetadata->subClasses); } else { $associationMetadata->addAcceptableTargetClassName($targetClass); } return $associationMetadata; }
/** * @param array $definition * @param string $entityClass * @param int $limit */ protected function setLimits(array &$definition, $entityClass, $limit) { if (isset($definition[ConfigUtil::FIELDS]) && is_array($definition[ConfigUtil::FIELDS])) { $metadata = $this->doctrineHelper->getEntityMetadataForClass($entityClass); foreach ($definition[ConfigUtil::FIELDS] as $fieldName => &$fieldConfig) { if (is_array($fieldConfig)) { $propertyPath = ConfigUtil::getPropertyPath($fieldConfig, $fieldName); $path = ConfigUtil::explodePropertyPath($propertyPath); if (count($path) === 1) { $this->setFieldLimit($fieldConfig, $metadata, $propertyPath, $limit); } else { $linkedField = array_pop($path); $linkedMetadata = $this->doctrineHelper->findEntityMetadataByPath($entityClass, $path); if (null !== $linkedMetadata) { $this->setFieldLimit($fieldConfig, $linkedMetadata, $linkedField, $limit); } } } } } }
/** * {@inheritdoc} */ public function process(ContextInterface $context) { /** @var MetadataContext $context */ if ($context->hasResult()) { // metadata is already loaded return; } $entityClass = $context->getClassName(); if (!$this->doctrineHelper->isManageableEntityClass($entityClass)) { // only manageable entities are supported return; } $classMetadata = $this->doctrineHelper->getEntityMetadataForClass($entityClass); $entityMetadata = $this->entityMetadataFactory->createEntityMetadata($classMetadata); $fields = $classMetadata->getFieldNames(); foreach ($fields as $fieldName) { $entityMetadata->addField($this->entityMetadataFactory->createFieldMetadata($classMetadata, $fieldName)); } $associations = $classMetadata->getAssociationNames(); foreach ($associations as $associationName) { $entityMetadata->addAssociation($this->entityMetadataFactory->createAssociationMetadata($classMetadata, $associationName)); } $context->setResult($entityMetadata); }
/** * @param Route $route * @param string $entityClass */ protected function setIdRequirement(Route $route, $entityClass) { $metadata = $this->doctrineHelper->getEntityMetadataForClass($entityClass); $idFields = $metadata->getIdentifierFieldNames(); $idFieldCount = count($idFields); if ($idFieldCount === 1) { // single identifier $route->setRequirement(self::ID_ATTRIBUTE, $this->valueNormalizer->getRequirement($metadata->getTypeOfField(reset($idFields)), [RequestType::REST, RequestType::JSON_API])); } elseif ($idFieldCount > 1) { // combined identifier $requirements = []; foreach ($idFields as $field) { $requirements[] = $field . '=' . $this->valueNormalizer->getRequirement($metadata->getTypeOfField($field), [RequestType::REST, RequestType::JSON_API]); } $route->setRequirement(self::ID_ATTRIBUTE, implode(RestRequest::ARRAY_DELIMITER, $requirements)); } }