diff --git a/features/main/operation.feature b/features/main/operation.feature index 2e2cc094b49..b81805498ea 100644 --- a/features/main/operation.feature +++ b/features/main/operation.feature @@ -4,7 +4,6 @@ Feature: Operation support I need to be able to add custom operations and remove built-in ones @createSchema - @dropSchema Scenario: Can not write readonly property When I add "Content-Type" header equal to "application/ld+json" And I send a "POST" request to "/readable_only_properties" with body: diff --git a/features/main/relation.feature b/features/main/relation.feature index 0ba6404f8bd..25a99ebff12 100644 --- a/features/main/relation.feature +++ b/features/main/relation.feature @@ -491,7 +491,7 @@ Feature: Relations support Given there are people having pets When I add "Content-Type" header equal to "application/ld+json" And I send a "GET" request to "/people" - And the response status code should be 200 + Then the response status code should be 200 And the response should be in JSON And the JSON should be equal to: """ @@ -621,8 +621,6 @@ Feature: Relations support } """ - - @dropSchema Scenario: Passing an invalid IRI to a relation When I add "Content-Type" header equal to "application/ld+json" And I send a "POST" request to "/relation_embedders" with body: @@ -634,7 +632,7 @@ Feature: Relations support Then the response status code should be 400 And the response should be in JSON And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8" - And the JSON node "hydra:description" should contain "Invalid value provided (invalid IRI?)." + And the JSON node "hydra:description" should contain 'Invalid IRI "certainly not an iri and not a plain identifier".' Scenario: Passing an invalid type to a relation When I add "Content-Type" header equal to "application/ld+json" @@ -647,4 +645,4 @@ Feature: Relations support Then the response status code should be 400 And the response should be in JSON And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8" - And the JSON node "hydra:description" should contain "Invalid value provided (invalid IRI?)." + And the JSON node "hydra:description" should contain 'Invalid IRI "8".' diff --git a/features/serializer/vo_relations.feature b/features/serializer/vo_relations.feature index 1f4759460d3..9d35d328a1e 100644 --- a/features/serializer/vo_relations.feature +++ b/features/serializer/vo_relations.feature @@ -26,28 +26,28 @@ Feature: Value object as ApiResource Then the response status code should be 201 And the JSON should be equal to: """ - { - "@context": "/contexts/VoDummyCar", - "@id": "/vo_dummy_cars/1", - "@type": "VoDummyCar", - "mileage": 1500, - "bodyType": "suv", - "inspections": [], - "make": "CustomCar", - "insuranceCompany": { - "@id": "/vo_dummy_insurance_companies/1", - "@type": "VoDummyInsuranceCompany", - "name": "Safe Drive Company" - }, - "drivers": [ - { - "@id": "/vo_dummy_drivers/1", - "@type": "VoDummyDriver", - "firstName": "John", - "lastName": "Doe" - } - ] - } + { + "@context": "/contexts/VoDummyCar", + "@id": "/vo_dummy_cars/1", + "@type": "VoDummyCar", + "mileage": 1500, + "bodyType": "suv", + "inspections": [], + "make": "CustomCar", + "insuranceCompany": { + "@id": "/vo_dummy_insurance_companies/1", + "@type": "VoDummyInsuranceCompany", + "name": "Safe Drive Company" + }, + "drivers": [ + { + "@id": "/vo_dummy_drivers/1", + "@type": "VoDummyDriver", + "firstName": "John", + "lastName": "Doe" + } + ] + } """ And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8" @@ -60,6 +60,7 @@ Feature: Value object as ApiResource "car": "/vo_dummy_cars/1" } """ + Then print last JSON response Then the response status code should be 201 And the JSON should be valid according to this schema: """ @@ -98,8 +99,7 @@ Feature: Value object as ApiResource "@type": "VoDummyInspection", "accepted": true, "car": "/vo_dummy_cars/1", - "performed": "2018-08-24T00:00:00+00:00", - "id": 1 + "performed": "2018-08-24T00:00:00+00:00" } """ diff --git a/src/Api/IdentifiersExtractor.php b/src/Api/IdentifiersExtractor.php index cd630ec5975..7cc338858e9 100644 --- a/src/Api/IdentifiersExtractor.php +++ b/src/Api/IdentifiersExtractor.php @@ -67,7 +67,8 @@ public function getIdentifiersFromResourceClass(string $resourceClass): array public function getIdentifiersFromItem($item): array { $identifiers = []; - $resourceClass = $this->getObjectClass($item); + $resourceClass = null !== $this->resourceClassResolver ? $this->resourceClassResolver->getResourceClass($item) : $this->getObjectClass($item); + foreach ($this->propertyNameCollectionFactory->create($resourceClass) as $propertyName) { $propertyMetadata = $this->propertyMetadataFactory->create($resourceClass, $propertyName); $identifier = $propertyMetadata->isIdentifier(); diff --git a/src/Api/ResourceClassResolver.php b/src/Api/ResourceClassResolver.php index f75f58227d1..d6d8165c759 100644 --- a/src/Api/ResourceClassResolver.php +++ b/src/Api/ResourceClassResolver.php @@ -40,33 +40,43 @@ public function __construct(ResourceNameCollectionFactoryInterface $resourceName */ public function getResourceClass($value, string $resourceClass = null, bool $strict = false): string { - $type = \is_object($value) && !$value instanceof \Traversable ? $this->getObjectClass($value) : $resourceClass; - $resourceClass = $resourceClass ?? $type; + if ($strict && null === $resourceClass) { + throw new InvalidArgumentException('Strict checking is only possible when resource class is specified.'); + } + + $actualClass = \is_object($value) && !$value instanceof \Traversable ? $this->getObjectClass($value) : null; + + if (null === $actualClass && null === $resourceClass) { + throw new InvalidArgumentException('Resource type could not be determined. Resource class must be specified.'); + } - if (null === $resourceClass) { - throw new InvalidArgumentException(sprintf('No resource class found.')); + if (null !== $resourceClass && !$this->isResourceClass($resourceClass)) { + throw new InvalidArgumentException(sprintf('Specified class "%s" is not a resource class.', $resourceClass)); } - if ( - null === $type - || ((!$strict || $resourceClass === $type) && $isResourceClass = $this->isResourceClass($type)) - ) { + if (null === $actualClass) { return $resourceClass; } - // The Resource is an interface - if ($value instanceof $resourceClass && $type !== $resourceClass && interface_exists($resourceClass)) { - throw new InvalidArgumentException(sprintf('The given object\'s resource is the interface "%s", finding a class is not possible.', $resourceClass)); + if ($strict && !($typesMatch = is_a($actualClass, $resourceClass, true))) { + throw new InvalidArgumentException(sprintf('Object of type "%s" does not match "%s" resource class.', $actualClass, $resourceClass)); + } + + $mostSpecificResourceClass = null; + + foreach ($this->resourceNameCollectionFactory->create() as $resourceClassName) { + if (is_a($actualClass, $resourceClassName, true)) { + if (null === $mostSpecificResourceClass || is_subclass_of($resourceClassName, $mostSpecificResourceClass, true)) { + $mostSpecificResourceClass = $resourceClassName; + } + } } - if ( - ($isResourceClass ?? $this->isResourceClass($type)) - || (is_subclass_of($type, $resourceClass) && $this->isResourceClass($resourceClass)) - ) { - return $type; + if (null === $mostSpecificResourceClass) { + throw new InvalidArgumentException(sprintf('No resource class found for object of type "%s".', $actualClass)); } - throw new InvalidArgumentException(sprintf('No resource class found for object of type "%s".', $type)); + return $mostSpecificResourceClass; } /** @@ -79,7 +89,7 @@ public function isResourceClass(string $type): bool } foreach ($this->resourceNameCollectionFactory->create() as $resourceClass) { - if ($type === $resourceClass) { + if (is_a($type, $resourceClass, true)) { return $this->localIsResourceClassCache[$type] = true; } } diff --git a/src/Bridge/Doctrine/Orm/Extension/EagerLoadingExtension.php b/src/Bridge/Doctrine/Orm/Extension/EagerLoadingExtension.php index d2a40199b14..82d63abad47 100644 --- a/src/Bridge/Doctrine/Orm/Extension/EagerLoadingExtension.php +++ b/src/Bridge/Doctrine/Orm/Extension/EagerLoadingExtension.php @@ -81,6 +81,8 @@ public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGenerator } /** + * {@inheritdoc} + * * The context may contain serialization groups which helps defining joined entities that are readable. */ public function applyToItem(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, array $identifiers, string $operationName = null, array $context = []) @@ -111,6 +113,10 @@ private function apply(bool $collection, QueryBuilder $queryBuilder, QueryNameGe return; } + if (!empty($context[AbstractNormalizer::GROUPS])) { + $options['serializer_groups'] = $context[AbstractNormalizer::GROUPS]; + } + $this->joinRelations($queryBuilder, $queryNameGenerator, $resourceClass, $forceEager, $fetchPartial, $queryBuilder->getRootAliases()[0], $options, $context); } @@ -134,10 +140,6 @@ private function joinRelations(QueryBuilder $queryBuilder, QueryNameGeneratorInt $classMetadata = $entityManager->getClassMetadata($resourceClass); $attributesMetadata = $this->classMetadataFactory ? $this->classMetadataFactory->getMetadataFor($resourceClass)->getAttributesMetadata() : null; - if (!empty($normalizationContext[AbstractNormalizer::GROUPS])) { - $options['serializer_groups'] = $normalizationContext[AbstractNormalizer::GROUPS]; - } - foreach ($classMetadata->associationMappings as $association => $mapping) { //Don't join if max depth is enabled and the current depth limit is reached if (0 === $currentDepth && ($normalizationContext[AbstractObjectNormalizer::ENABLE_MAX_DEPTH] ?? false)) { diff --git a/src/Bridge/Symfony/Bundle/Resources/config/api.xml b/src/Bridge/Symfony/Bundle/Resources/config/api.xml index 47e1aa9f81d..67473b6fc91 100644 --- a/src/Bridge/Symfony/Bundle/Resources/config/api.xml +++ b/src/Bridge/Symfony/Bundle/Resources/config/api.xml @@ -61,6 +61,7 @@ + diff --git a/src/Bridge/Symfony/Routing/IriConverter.php b/src/Bridge/Symfony/Routing/IriConverter.php index 83f378cdae0..7fb4413ff9f 100644 --- a/src/Bridge/Symfony/Routing/IriConverter.php +++ b/src/Bridge/Symfony/Routing/IriConverter.php @@ -17,6 +17,7 @@ use ApiPlatform\Core\Api\IdentifiersExtractorInterface; use ApiPlatform\Core\Api\IriConverterInterface; use ApiPlatform\Core\Api\OperationType; +use ApiPlatform\Core\Api\ResourceClassResolverInterface; use ApiPlatform\Core\Api\UrlGeneratorInterface; use ApiPlatform\Core\DataProvider\ItemDataProviderInterface; use ApiPlatform\Core\DataProvider\OperationDataProviderTrait; @@ -48,8 +49,9 @@ final class IriConverter implements IriConverterInterface private $routeNameResolver; private $router; private $identifiersExtractor; + private $resourceClassResolver; - public function __construct(PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, ItemDataProviderInterface $itemDataProvider, RouteNameResolverInterface $routeNameResolver, RouterInterface $router, PropertyAccessorInterface $propertyAccessor = null, IdentifiersExtractorInterface $identifiersExtractor = null, SubresourceDataProviderInterface $subresourceDataProvider = null, IdentifierConverterInterface $identifierConverter = null) + public function __construct(PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, ItemDataProviderInterface $itemDataProvider, RouteNameResolverInterface $routeNameResolver, RouterInterface $router, PropertyAccessorInterface $propertyAccessor = null, IdentifiersExtractorInterface $identifiersExtractor = null, SubresourceDataProviderInterface $subresourceDataProvider = null, IdentifierConverterInterface $identifierConverter = null, ResourceClassResolverInterface $resourceClassResolver = null) { $this->itemDataProvider = $itemDataProvider; $this->routeNameResolver = $routeNameResolver; @@ -57,6 +59,7 @@ public function __construct(PropertyNameCollectionFactoryInterface $propertyName $this->identifiersExtractor = $identifiersExtractor; $this->subresourceDataProvider = $subresourceDataProvider; $this->identifierConverter = $identifierConverter; + $this->resourceClassResolver = $resourceClassResolver; if (null === $identifiersExtractor) { @trigger_error(sprintf('Not injecting "%s" is deprecated since API Platform 2.1 and will not be possible anymore in API Platform 3', IdentifiersExtractorInterface::class), E_USER_DEPRECATED); @@ -115,7 +118,7 @@ public function getItemFromIri(string $iri, array $context = []) */ public function getIriFromItem($item, int $referenceType = UrlGeneratorInterface::ABS_PATH): string { - $resourceClass = $this->getObjectClass($item); + $resourceClass = null !== $this->resourceClassResolver ? $this->resourceClassResolver->getResourceClass($item) : $this->getObjectClass($item); $routeName = $this->routeNameResolver->getRouteName($resourceClass, OperationType::ITEM); try { diff --git a/src/GraphQl/Resolver/Factory/CollectionResolverFactory.php b/src/GraphQl/Resolver/Factory/CollectionResolverFactory.php index 17de6afd06e..40d3d9d77cf 100644 --- a/src/GraphQl/Resolver/Factory/CollectionResolverFactory.php +++ b/src/GraphQl/Resolver/Factory/CollectionResolverFactory.php @@ -77,10 +77,12 @@ public function __invoke(string $resourceClass = null, string $rootClass = null, } $resourceMetadata = $this->resourceMetadataFactory->create($resourceClass); - $dataProviderContext = $resourceMetadata->getGraphqlAttribute($operationName ?? 'query', 'normalization_context', [], true); - $dataProviderContext['attributes'] = $this->fieldsToAttributes($info); + $normalizationContext = $resourceMetadata->getGraphqlAttribute($operationName ?? 'query', 'normalization_context', [], true); + $normalizationContext['attributes'] = $this->fieldsToAttributes($info); + $dataProviderContext = $normalizationContext; $dataProviderContext['filters'] = $this->getNormalizedFilters($args); $dataProviderContext['graphql'] = true; + $normalizationContext['resource_class'] = $resourceClass; if (isset($rootClass, $source[$rootProperty = $info->fieldName], $source[ItemNormalizer::ITEM_KEY])) { $rootResolvedFields = $this->identifiersExtractor->getIdentifiersFromItem(unserialize($source[ItemNormalizer::ITEM_KEY])); @@ -95,7 +97,7 @@ public function __invoke(string $resourceClass = null, string $rootClass = null, if (!$this->paginationEnabled) { $data = []; foreach ($collection as $index => $object) { - $data[$index] = $this->normalizer->normalize($object, ItemNormalizer::FORMAT, $dataProviderContext); + $data[$index] = $this->normalizer->normalize($object, ItemNormalizer::FORMAT, $normalizationContext); } return $data; @@ -120,7 +122,7 @@ public function __invoke(string $resourceClass = null, string $rootClass = null, foreach ($collection as $index => $object) { $data['edges'][$index] = [ - 'node' => $this->normalizer->normalize($object, ItemNormalizer::FORMAT, $dataProviderContext), + 'node' => $this->normalizer->normalize($object, ItemNormalizer::FORMAT, $normalizationContext), 'cursor' => base64_encode((string) ($index + $offset)), ]; } diff --git a/src/GraphQl/Resolver/Factory/ItemMutationResolverFactory.php b/src/GraphQl/Resolver/Factory/ItemMutationResolverFactory.php index 705a26d7a94..43e3f5521b2 100644 --- a/src/GraphQl/Resolver/Factory/ItemMutationResolverFactory.php +++ b/src/GraphQl/Resolver/Factory/ItemMutationResolverFactory.php @@ -77,12 +77,14 @@ public function __invoke(string $resourceClass = null, string $rootClass = null, $resourceMetadata = $this->resourceMetadataFactory->create($resourceClass); $wrapFieldName = lcfirst($resourceMetadata->getShortName()); - $normalizationContext = $resourceMetadata->getGraphqlAttribute($operationName ?? '', 'normalization_context', [], true); - $normalizationContext['attributes'] = $this->fieldsToAttributes($info)[$wrapFieldName] ?? []; + $baseNormalizationContext = $resourceMetadata->getGraphqlAttribute($operationName ?? '', 'normalization_context', [], true); + $baseNormalizationContext['attributes'] = $this->fieldsToAttributes($info)[$wrapFieldName] ?? []; + $normalizationContext = $baseNormalizationContext; + $normalizationContext['resource_class'] = $resourceClass; if (isset($args['input']['id'])) { try { - $item = $this->iriConverter->getItemFromIri($args['input']['id'], $normalizationContext); + $item = $this->iriConverter->getItemFromIri($args['input']['id'], $baseNormalizationContext); } catch (ItemNotFoundException $e) { throw Error::createLocatedError(sprintf('Item "%s" not found.', $args['input']['id']), $info->fieldNodes, $info->path); } diff --git a/src/GraphQl/Resolver/ItemResolver.php b/src/GraphQl/Resolver/ItemResolver.php index a06dbb05192..94935b61b67 100644 --- a/src/GraphQl/Resolver/ItemResolver.php +++ b/src/GraphQl/Resolver/ItemResolver.php @@ -72,6 +72,7 @@ public function __invoke($source, $args, $context, ResolveInfo $info) $this->canAccess($this->resourceAccessChecker, $resourceMetadata, $resourceClass, $info, $item, 'query'); $normalizationContext = $resourceMetadata->getGraphqlAttribute('query', 'normalization_context', [], true); + $normalizationContext['resource_class'] = $resourceClass; return $this->normalizer->normalize($item, ItemNormalizer::FORMAT, $normalizationContext + $baseNormalizationContext); } diff --git a/src/Hal/Serializer/ItemNormalizer.php b/src/Hal/Serializer/ItemNormalizer.php index 32094c77b95..3ade32c3b2e 100644 --- a/src/Hal/Serializer/ItemNormalizer.php +++ b/src/Hal/Serializer/ItemNormalizer.php @@ -56,8 +56,7 @@ public function normalize($object, $format = null, array $context = []) $context['cache_key'] = $this->getHalCacheKey($format, $context); } - // Use resolved resource class instead of given resource class to support multiple inheritance child types - $resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class'] ?? null, true); + $resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class'] ?? null, isset($context['resource_class'])); $context = $this->initContext($resourceClass, $context); $iri = $this->iriConverter->getIriFromItem($object); $context['iri'] = $iri; diff --git a/src/Hydra/Serializer/CollectionFiltersNormalizer.php b/src/Hydra/Serializer/CollectionFiltersNormalizer.php index ff5d750484d..9f23e0a15d5 100644 --- a/src/Hydra/Serializer/CollectionFiltersNormalizer.php +++ b/src/Hydra/Serializer/CollectionFiltersNormalizer.php @@ -17,7 +17,6 @@ use ApiPlatform\Core\Api\FilterInterface; use ApiPlatform\Core\Api\FilterLocatorTrait; use ApiPlatform\Core\Api\ResourceClassResolverInterface; -use ApiPlatform\Core\Exception\InvalidArgumentException; use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface; use Psr\Container\ContainerInterface; use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface; @@ -71,19 +70,12 @@ public function hasCacheableSupportsMethod(): bool public function normalize($object, $format = null, array $context = []) { $data = $this->collectionNormalizer->normalize($object, $format, $context); - if (isset($context['api_sub_level'])) { + + if (!isset($context['resource_class']) || isset($context['api_sub_level'])) { return $data; } - try { - $resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class'] ?? null, true); - } catch (InvalidArgumentException $e) { - if (!isset($context['resource_class'])) { - return $data; - } - - throw $e; - } + $resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class']); $resourceMetadata = $this->resourceMetadataFactory->create($resourceClass); $operationName = $context['collection_operation_name'] ?? null; diff --git a/src/Hydra/Serializer/CollectionNormalizer.php b/src/Hydra/Serializer/CollectionNormalizer.php index 391fb3b73ed..c7ac9d13f6c 100644 --- a/src/Hydra/Serializer/CollectionNormalizer.php +++ b/src/Hydra/Serializer/CollectionNormalizer.php @@ -18,7 +18,6 @@ use ApiPlatform\Core\Api\ResourceClassResolverInterface; use ApiPlatform\Core\DataProvider\PaginatorInterface; use ApiPlatform\Core\DataProvider\PartialPaginatorInterface; -use ApiPlatform\Core\Exception\InvalidArgumentException; use ApiPlatform\Core\JsonLd\ContextBuilderInterface; use ApiPlatform\Core\JsonLd\Serializer\JsonLdContextTrait; use ApiPlatform\Core\Serializer\ContextTrait; @@ -67,21 +66,13 @@ public function supportsNormalization($data, $format = null) */ public function normalize($object, $format = null, array $context = []) { - if (isset($context['api_sub_level'])) { + if (!isset($context['resource_class']) || isset($context['api_sub_level'])) { return $this->normalizeRawCollection($object, $format, $context); } - try { - $resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class'] ?? null, true); - } catch (InvalidArgumentException $e) { - if (!isset($context['resource_class'])) { - return $this->normalizeRawCollection($object, $format, $context); - } - - throw $e; - } - $data = $this->addJsonLdContext($this->contextBuilder, $resourceClass, $context); + $resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class']); $context = $this->initContext($resourceClass, $context); + $data = $this->addJsonLdContext($this->contextBuilder, $resourceClass, $context); if (isset($context['operation_type']) && OperationType::SUBRESOURCE === $context['operation_type']) { $data['@id'] = $this->iriConverter->getSubresourceIriFromResourceClass($resourceClass, $context); diff --git a/src/JsonApi/Serializer/ItemNormalizer.php b/src/JsonApi/Serializer/ItemNormalizer.php index 58bd954a0bd..24573e931fc 100644 --- a/src/JsonApi/Serializer/ItemNormalizer.php +++ b/src/JsonApi/Serializer/ItemNormalizer.php @@ -75,8 +75,7 @@ public function normalize($object, $format = null, array $context = []) $context['cache_key'] = $this->getJsonApiCacheKey($format, $context); } - // Use resolved resource class instead of given resource class to support multiple inheritance child types - $resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class'] ?? null, true); + $resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class'] ?? null, isset($context['resource_class'])); $context = $this->initContext($resourceClass, $context); $iri = $this->iriConverter->getIriFromItem($object); $context['iri'] = $iri; @@ -187,8 +186,6 @@ protected function denormalizeRelation(string $attributeName, PropertyMetadata $ { // 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); } @@ -219,8 +216,6 @@ protected function normalizeRelation(PropertyMetadata $propertyMetadata, $relate if (isset($context['operation_type'], $context['subresource_resources'][$resourceClass]) && OperationType::SUBRESOURCE === $context['operation_type']) { $iri = $this->iriConverter->getItemIriFromResourceClass($resourceClass, $context['subresource_resources'][$resourceClass]); } else { - unset($context['resource_class']); - if ($this->serializer instanceof NormalizerInterface) { return $this->serializer->normalize($relatedObject, $format, $context); } diff --git a/src/JsonApi/Serializer/ObjectNormalizer.php b/src/JsonApi/Serializer/ObjectNormalizer.php index 5066b8429fd..6b0c778a5c8 100644 --- a/src/JsonApi/Serializer/ObjectNormalizer.php +++ b/src/JsonApi/Serializer/ObjectNormalizer.php @@ -75,7 +75,7 @@ public function normalize($object, $format = null, array $context = []) } if (isset($originalResource)) { - $resourceClass = $this->resourceClassResolver->getResourceClass($originalResource, $context['resource_class'] ?? null, true); + $resourceClass = $this->resourceClassResolver->getResourceClass($originalResource); $resourceMetadata = $this->resourceMetadataFactory->create($resourceClass); $resourceData = [ diff --git a/src/JsonLd/Serializer/ItemNormalizer.php b/src/JsonLd/Serializer/ItemNormalizer.php index 211789ff286..f27aa11d9f9 100644 --- a/src/JsonLd/Serializer/ItemNormalizer.php +++ b/src/JsonLd/Serializer/ItemNormalizer.php @@ -69,8 +69,7 @@ public function normalize($object, $format = null, array $context = []) return parent::normalize($object, $format, $context); } - // Use resolved resource class instead of given resource class to support multiple inheritance child types - $resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class'] ?? null, true); + $resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class'] ?? null, isset($context['resource_class'])); $context = $this->initContext($resourceClass, $context); $iri = $this->iriConverter->getIriFromItem($object); $context['iri'] = $iri; diff --git a/src/Serializer/AbstractCollectionNormalizer.php b/src/Serializer/AbstractCollectionNormalizer.php index bc9711a0119..59268475747 100644 --- a/src/Serializer/AbstractCollectionNormalizer.php +++ b/src/Serializer/AbstractCollectionNormalizer.php @@ -16,7 +16,6 @@ use ApiPlatform\Core\Api\ResourceClassResolverInterface; use ApiPlatform\Core\DataProvider\PaginatorInterface; use ApiPlatform\Core\DataProvider\PartialPaginatorInterface; -use ApiPlatform\Core\Exception\InvalidArgumentException; use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface; use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface; use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait; @@ -71,21 +70,13 @@ public function hasCacheableSupportsMethod(): bool */ public function normalize($object, $format = null, array $context = []) { - if (isset($context['api_sub_level'])) { + if (!isset($context['resource_class']) || isset($context['api_sub_level'])) { return $this->normalizeRawCollection($object, $format, $context); } - try { - $resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class'] ?? null, true); - } catch (InvalidArgumentException $e) { - if (!isset($context['resource_class'])) { - return $this->normalizeRawCollection($object, $format, $context); - } - - throw $e; - } - $data = []; + $resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class']); $context = $this->initContext($resourceClass, $context); + $data = []; return array_merge_recursive( $data, diff --git a/src/Serializer/AbstractItemNormalizer.php b/src/Serializer/AbstractItemNormalizer.php index 3fde229d47d..9b3fa31b7e8 100644 --- a/src/Serializer/AbstractItemNormalizer.php +++ b/src/Serializer/AbstractItemNormalizer.php @@ -116,18 +116,18 @@ public function normalize($object, $format = null, array $context = []) { if ($object !== $transformed = $this->transformOutput($object, $context)) { if (!$this->serializer instanceof NormalizerInterface) { - throw new LogicException('Cannot normalize the transformed value because the injected serializer is not a normalizer'); + throw new LogicException('Cannot normalize the output because the injected serializer is not a normalizer'); } $context['api_normalize'] = true; $context['api_resource'] = $object; unset($context['output']); + unset($context['resource_class']); return $this->serializer->normalize($transformed, $format, $context); } - // Use resolved resource class instead of given resource class to support multiple inheritance child types - $resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class'] ?? null, true); + $resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class'] ?? null, isset($context['resource_class'])); $context = $this->initContext($resourceClass, $context); $iri = $context['iri'] ?? $this->iriConverter->getIriFromItem($object); $context['iri'] = $iri; @@ -173,14 +173,33 @@ public function denormalize($data, $class, $format = null, array $context = []) { $context['api_denormalize'] = true; $context['resource_class'] = $class; - $inputClass = $this->getInputClass($class, $context); - if (null !== $inputClass && null !== $dataTransformer = $this->getDataTransformer($data, $class, $context)) { - return $dataTransformer->transform( - parent::denormalize($data, $inputClass, $format, ['resource_class' => $inputClass] + $context), - $class, - $context - ); + if (null !== ($inputClass = $this->getInputClass($class, $context)) && null !== ($dataTransformer = $this->getDataTransformer($data, $class, $context))) { + $dataTransformerContext = $context; + + unset($context['input']); + unset($context['resource_class']); + + if (!$this->serializer instanceof DenormalizerInterface) { + throw new LogicException('Cannot denormalize the input because the injected serializer is not a denormalizer'); + } + $denormalizedInput = $this->serializer->denormalize($data, $inputClass, $format, $context); + + return $dataTransformer->transform($denormalizedInput, $class, $dataTransformerContext); + } + + if (is_scalar($data) && !\is_string($data)) { + throw new UnexpectedValueException(sprintf('Invalid IRI "%s".', $data)); + } + + if (\is_string($data)) { + try { + return $this->iriConverter->getItemFromIri($data, $context + ['fetch_data' => true]); + } catch (ItemNotFoundException $e) { + throw new UnexpectedValueException($e->getMessage(), 0, $e); + } catch (InvalidArgumentException $e) { + throw new UnexpectedValueException(sprintf('Invalid IRI "%s".', $data), 0, $e); + } } return parent::denormalize($data, $class, $format, $context); @@ -319,10 +338,6 @@ protected function setAttributeValue($object, $attribute, $value, $format = null private function createAttributeValue($attribute, $value, $format = null, array $context = []) { - if (!\is_string($attribute)) { - throw new InvalidValueException('Invalid value provided (invalid IRI?).'); - } - $propertyMetadata = $this->propertyMetadataFactory->create($context['resource_class'], $attribute, $this->getFactoryOptions($context)); $type = $propertyMetadata->getType(); @@ -340,11 +355,16 @@ private function createAttributeValue($attribute, $value, $format = null, array null !== ($collectionValueType = $type->getCollectionValueType()) && null !== $className = $collectionValueType->getClassName() ) { + $context['resource_class'] = $className; + return $this->denormalizeCollection($attribute, $propertyMetadata, $type, $className, $value, $format, $context); } if (null !== $className = $type->getClassName()) { - return $this->denormalizeRelation($attribute, $propertyMetadata, $className, $value, $format, $this->createChildContext($context, $attribute)); + $childContext = $this->createChildContext($context, $attribute); + $childContext['resource_class'] = $className; + + return $this->denormalizeRelation($attribute, $propertyMetadata, $className, $value, $format, $childContext); } if ($context[static::DISABLE_TYPE_ENFORCEMENT] ?? false) { @@ -428,18 +448,22 @@ protected function denormalizeRelation(string $attributeName, PropertyMetadata $ } } - if ( - !$this->resourceClassResolver->isResourceClass($className) || - $propertyMetadata->isWritableLink() - ) { - $context['resource_class'] = $className; + if (!$this->resourceClassResolver->isResourceClass($className)) { + 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); + } + + if ($propertyMetadata->isWritableLink()) { $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)); - } + if (!$this->serializer instanceof DenormalizerInterface) { + throw new LogicException(sprintf('The injected serializer must be an instance of "%s".', DenormalizerInterface::class)); + } + try { return $this->serializer->denormalize($value, $className, $format, $context); } catch (InvalidValueException $e) { if (!$this->allowPlainIdentifiers || null === $this->itemDataProvider) { @@ -548,7 +572,11 @@ protected function getAttributeValue($object, $attribute, $format = null, array ($className = $collectionValueType->getClassName()) && $this->resourceClassResolver->isResourceClass($className) ) { - return $this->normalizeCollectionOfRelations($propertyMetadata, $attributeValue, $className, $format, $this->createChildContext($context, $attribute)); + $resourceClass = $this->resourceClassResolver->getResourceClass($attributeValue, $className); + $childContext = $this->createChildContext($context, $attribute); + $childContext['resource_class'] = $resourceClass; + + return $this->normalizeCollectionOfRelations($propertyMetadata, $attributeValue, $resourceClass, $format, $childContext); } if ( @@ -556,15 +584,19 @@ protected function getAttributeValue($object, $attribute, $format = null, array ($className = $type->getClassName()) && $this->resourceClassResolver->isResourceClass($className) ) { - return $this->normalizeRelation($propertyMetadata, $attributeValue, $className, $format, $this->createChildContext($context, $attribute)); - } + $resourceClass = $this->resourceClassResolver->getResourceClass($attributeValue, $className, true); + $childContext = $this->createChildContext($context, $attribute); + $childContext['resource_class'] = $resourceClass; - unset($context['resource_class']); + return $this->normalizeRelation($propertyMetadata, $attributeValue, $resourceClass, $format, $childContext); + } if (!$this->serializer instanceof NormalizerInterface) { throw new LogicException(sprintf('The injected serializer must be an instance of "%s".', NormalizerInterface::class)); } + unset($context['resource_class']); + return $this->serializer->normalize($attributeValue, $format, $context); } @@ -593,12 +625,6 @@ protected function normalizeCollectionOfRelations(PropertyMetadata $propertyMeta protected function normalizeRelation(PropertyMetadata $propertyMetadata, $relatedObject, string $resourceClass, ?string $format, array $context) { if (null === $relatedObject || !empty($context['attributes']) || $propertyMetadata->isReadableLink()) { - if (null === $relatedObject) { - unset($context['resource_class']); - } else { - $context['resource_class'] = $resourceClass; - } - if (!$this->serializer instanceof NormalizerInterface) { throw new LogicException(sprintf('The injected serializer must be an instance of "%s".', NormalizerInterface::class)); } diff --git a/tests/Api/IdentifiersExtractorTest.php b/tests/Api/IdentifiersExtractorTest.php index d83eee6d6b8..abd06e233e9 100644 --- a/tests/Api/IdentifiersExtractorTest.php +++ b/tests/Api/IdentifiersExtractorTest.php @@ -23,6 +23,8 @@ use ApiPlatform\Core\Tests\Fixtures\TestBundle\Doctrine\Generator\Uuid; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Dummy; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\RelatedDummy; +use ApiPlatform\Core\Tests\Fixtures\TestBundle\OtherResources\ResourceInterface; +use ApiPlatform\Core\Tests\Fixtures\TestBundle\OtherResources\ResourceInterfaceImplementation; use PHPUnit\Framework\TestCase; use Prophecy\Argument; @@ -31,32 +33,13 @@ */ class IdentifiersExtractorTest extends TestCase { - private function getMetadataFactoryProphecies($class, $identifiers, array $prophecies = null) - { - //adds a random property that is not an identifier - $properties = array_merge(['foo'], $identifiers); - - if (!$prophecies) { - $prophecies = [$this->prophesize(PropertyNameCollectionFactoryInterface::class), $this->prophesize(PropertyMetadataFactoryInterface::class)]; - } - - [$propertyNameCollectionFactoryProphecy, $propertyMetadataFactoryProphecy] = $prophecies; - - $propertyNameCollectionFactoryProphecy->create($class)->shouldBeCalled()->willReturn(new PropertyNameCollection($properties)); - - foreach ($properties as $prop) { - $metadata = new PropertyMetadata(); - $propertyMetadataFactoryProphecy->create($class, $prop)->shouldBeCalled()->willReturn($metadata->withIdentifier(\in_array($prop, $identifiers, true))); - } - - return [$propertyNameCollectionFactoryProphecy, $propertyMetadataFactoryProphecy]; - } - public function testGetIdentifiersFromResourceClass() { [$propertyNameCollectionFactoryProphecy, $propertyMetadataFactoryProphecy] = $this->getMetadataFactoryProphecies(Dummy::class, ['id']); - $identifiersExtractor = new IdentifiersExtractor($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), null, $this->getResourceClassResolver()); + $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); + + $identifiersExtractor = new IdentifiersExtractor($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), null, $resourceClassResolverProphecy->reveal()); $this->assertSame(['id'], $identifiersExtractor->getIdentifiersFromResourceClass(Dummy::class)); } @@ -65,7 +48,9 @@ public function testGetCompositeIdentifiersFromResourceClass() { [$propertyNameCollectionFactoryProphecy, $propertyMetadataFactoryProphecy] = $this->getMetadataFactoryProphecies(Dummy::class, ['id', 'name']); - $identifiersExtractor = new IdentifiersExtractor($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), null, $this->getResourceClassResolver()); + $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); + + $identifiersExtractor = new IdentifiersExtractor($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), null, $resourceClassResolverProphecy->reveal()); $this->assertSame(['id', 'name'], $identifiersExtractor->getIdentifiersFromResourceClass(Dummy::class)); } @@ -89,7 +74,11 @@ public function testGetIdentifiersFromItem($item, $expected) { [$propertyNameCollectionFactoryProphecy, $propertyMetadataFactoryProphecy] = $this->getMetadataFactoryProphecies(Dummy::class, ['id']); - $identifiersExtractor = new IdentifiersExtractor($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), null, $this->getResourceClassResolver()); + $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); + $resourceClassResolverProphecy->getResourceClass($item)->willReturn(Dummy::class); + $resourceClassResolverProphecy->isResourceClass(Uuid::class)->willReturn(false); + + $identifiersExtractor = new IdentifiersExtractor($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), null, $resourceClassResolverProphecy->reveal()); $this->assertSame($expected, $identifiersExtractor->getIdentifiersFromItem($item)); } @@ -114,7 +103,11 @@ public function testGetCompositeIdentifiersFromItem($item, $expected) { [$propertyNameCollectionFactoryProphecy, $propertyMetadataFactoryProphecy] = $this->getMetadataFactoryProphecies(Dummy::class, ['id', 'name']); - $identifiersExtractor = new IdentifiersExtractor($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), null, $this->getResourceClassResolver()); + $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); + $resourceClassResolverProphecy->getResourceClass($item)->willReturn(Dummy::class); + $resourceClassResolverProphecy->isResourceClass(Uuid::class)->willReturn(false); + + $identifiersExtractor = new IdentifiersExtractor($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), null, $resourceClassResolverProphecy->reveal()); $this->assertSame($expected, $identifiersExtractor->getIdentifiersFromItem($item)); } @@ -148,7 +141,12 @@ public function testGetRelatedIdentifiersFromItem($item, $expected) $prophecies = $this->getMetadataFactoryProphecies(Dummy::class, ['id', 'relatedDummy']); [$propertyNameCollectionFactoryProphecy, $propertyMetadataFactoryProphecy] = $this->getMetadataFactoryProphecies(RelatedDummy::class, ['id'], $prophecies); - $identifiersExtractor = new IdentifiersExtractor($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), null, $this->getResourceClassResolver()); + $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); + $resourceClassResolverProphecy->getResourceClass($item)->willReturn(Dummy::class); + $resourceClassResolverProphecy->isResourceClass(RelatedDummy::class)->willReturn(true); + $resourceClassResolverProphecy->isResourceClass(Uuid::class)->willReturn(false); + + $identifiersExtractor = new IdentifiersExtractor($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), null, $resourceClassResolverProphecy->reveal()); $this->assertSame($expected, $identifiersExtractor->getIdentifiersFromItem($item)); } @@ -158,11 +156,6 @@ public function testThrowNoIdentifierFromItem() $this->expectException(RuntimeException::class); $this->expectExceptionMessage('No identifier found in "ApiPlatform\\Core\\Tests\\Fixtures\\TestBundle\\Entity\\RelatedDummy" through relation "relatedDummy" of "ApiPlatform\\Core\\Tests\\Fixtures\\TestBundle\\Entity\\Dummy" used as identifier'); - $prophecies = $this->getMetadataFactoryProphecies(Dummy::class, ['id', 'relatedDummy']); - [$propertyNameCollectionFactoryProphecy, $propertyMetadataFactoryProphecy] = $this->getMetadataFactoryProphecies(RelatedDummy::class, [], $prophecies); - - $identifiersExtractor = new IdentifiersExtractor($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), null, $this->getResourceClassResolver()); - $related = new RelatedDummy(); $related->setId(2); @@ -170,17 +163,38 @@ public function testThrowNoIdentifierFromItem() $dummy->setId(1); $dummy->setRelatedDummy($related); + $prophecies = $this->getMetadataFactoryProphecies(Dummy::class, ['id', 'relatedDummy']); + [$propertyNameCollectionFactoryProphecy, $propertyMetadataFactoryProphecy] = $this->getMetadataFactoryProphecies(RelatedDummy::class, [], $prophecies); + + $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); + $resourceClassResolverProphecy->getResourceClass($dummy)->willReturn(Dummy::class); + $resourceClassResolverProphecy->isResourceClass(RelatedDummy::class)->willReturn(true); + + $identifiersExtractor = new IdentifiersExtractor($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), null, $resourceClassResolverProphecy->reveal()); + $identifiersExtractor->getIdentifiersFromItem($dummy); } - private function getResourceClassResolver() + public function testGetsIdentifiersFromCorrectResourceClass(): void { - $resourceClassResolver = $this->prophesize(ResourceClassResolverInterface::class); - $resourceClassResolver->isResourceClass(Argument::type('string'))->will(function ($args) { - return !(Uuid::class === $args[0]); - }); + $item = new ResourceInterfaceImplementation(); + $item->setFoo('woot'); + + $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class); + $propertyNameCollectionFactoryProphecy->create(ResourceInterface::class)->willReturn(new PropertyNameCollection(['foo', 'fooz'])); + + $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class); + $propertyMetadataFactoryProphecy->create(ResourceInterface::class, 'foo')->willReturn((new PropertyMetadata)->withIdentifier(true)); + $propertyMetadataFactoryProphecy->create(ResourceInterface::class, 'fooz')->willReturn(new PropertyMetadata()); + + $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); + $resourceClassResolverProphecy->getResourceClass($item)->willReturn(ResourceInterface::class); - return $resourceClassResolver->reveal(); + $identifiersExtractor = new IdentifiersExtractor($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), null, $resourceClassResolverProphecy->reveal()); + + $identifiersExtractor->getIdentifiersFromItem($item); + + $this->assertSame(['foo' => 'woot'], $identifiersExtractor->getIdentifiersFromItem($item)); } /** @@ -198,4 +212,25 @@ public function testLegacyGetIdentifiersFromItem() $this->assertSame(['id' => 1], $identifiersExtractor->getIdentifiersFromItem($dummy)); } + + private function getMetadataFactoryProphecies($class, $identifiers, array $prophecies = null) + { + //adds a random property that is not an identifier + $properties = array_merge(['foo'], $identifiers); + + if (!$prophecies) { + $prophecies = [$this->prophesize(PropertyNameCollectionFactoryInterface::class), $this->prophesize(PropertyMetadataFactoryInterface::class)]; + } + + [$propertyNameCollectionFactoryProphecy, $propertyMetadataFactoryProphecy] = $prophecies; + + $propertyNameCollectionFactoryProphecy->create($class)->willReturn(new PropertyNameCollection($properties)); + + foreach ($properties as $prop) { + $metadata = new PropertyMetadata(); + $propertyMetadataFactoryProphecy->create($class, $prop)->willReturn($metadata->withIdentifier(\in_array($prop, $identifiers, true))); + } + + return [$propertyNameCollectionFactoryProphecy, $propertyMetadataFactoryProphecy]; + } } diff --git a/tests/Api/ResourceClassResolverTest.php b/tests/Api/ResourceClassResolverTest.php index 0e8d6c5c492..16ccc9eab1f 100644 --- a/tests/Api/ResourceClassResolverTest.php +++ b/tests/Api/ResourceClassResolverTest.php @@ -33,67 +33,71 @@ class ResourceClassResolverTest extends TestCase { public function testGetResourceClassWithIntendedClassName() { + $resourceNameCollectionFactoryProphecy = $this->prophesize(ResourceNameCollectionFactoryInterface::class); + $resourceNameCollectionFactoryProphecy->create()->willReturn(new ResourceNameCollection([Dummy::class])); + $dummy = new Dummy(); $dummy->setName('Smail'); - $resourceNameCollectionFactoryProphecy = $this->prophesize(ResourceNameCollectionFactoryInterface::class); - $resourceNameCollectionFactoryProphecy->create()->willReturn(new ResourceNameCollection([Dummy::class]))->shouldBeCalled(); $resourceClassResolver = new ResourceClassResolver($resourceNameCollectionFactoryProphecy->reveal()); - $resourceClass = $resourceClassResolver->getResourceClass($dummy, Dummy::class); - $this->assertEquals($resourceClass, Dummy::class); + + $this->assertEquals(Dummy::class, $resourceClassResolver->getResourceClass($dummy, Dummy::class)); } - public function testGetResourceClassWithOtherClassName() + public function testGetResourceClassWithNonResourceClassName() { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Specified class "ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\DummyCar" is not a resource class.'); + + $resourceNameCollectionFactoryProphecy = $this->prophesize(ResourceNameCollectionFactoryInterface::class); + $resourceNameCollectionFactoryProphecy->create()->willReturn(new ResourceNameCollection([Dummy::class])); + $dummy = new Dummy(); $dummy->setName('Smail'); - $resourceNameCollectionFactoryProphecy = $this->prophesize(ResourceNameCollectionFactoryInterface::class); - $resourceNameCollectionFactoryProphecy->create()->willReturn(new ResourceNameCollection([Dummy::class]))->shouldBeCalled(); $resourceClassResolver = new ResourceClassResolver($resourceNameCollectionFactoryProphecy->reveal()); - $resourceClass = $resourceClassResolver->getResourceClass($dummy, DummyCar::class, true); - $this->assertEquals($resourceClass, Dummy::class); + + $resourceClassResolver->getResourceClass($dummy, DummyCar::class, true); } public function testGetResourceClassWithNoClassName() { + $resourceNameCollectionFactoryProphecy = $this->prophesize(ResourceNameCollectionFactoryInterface::class); + $resourceNameCollectionFactoryProphecy->create()->willReturn(new ResourceNameCollection([Dummy::class])); + $dummy = new Dummy(); $dummy->setName('Smail'); - $resourceNameCollectionFactoryProphecy = $this->prophesize(ResourceNameCollectionFactoryInterface::class); - $resourceNameCollectionFactoryProphecy->create()->willReturn(new ResourceNameCollection([Dummy::class]))->shouldBeCalled(); $resourceClassResolver = new ResourceClassResolver($resourceNameCollectionFactoryProphecy->reveal()); - $resourceClass = $resourceClassResolver->getResourceClass($dummy); - $this->assertEquals($resourceClass, Dummy::class); + + $this->assertEquals(Dummy::class, $resourceClassResolver->getResourceClass($dummy)); } public function testGetResourceClassWithTraversableAsValue() { + $resourceNameCollectionFactoryProphecy = $this->prophesize(ResourceNameCollectionFactoryInterface::class); + $resourceNameCollectionFactoryProphecy->create()->willReturn(new ResourceNameCollection([Dummy::class])); + $dummy = new Dummy(); $dummy->setName('JLM'); $dummies = new \ArrayIterator([$dummy]); - $resourceNameCollectionFactoryProphecy = $this->prophesize(ResourceNameCollectionFactoryInterface::class); - $resourceNameCollectionFactoryProphecy->create()->willReturn(new ResourceNameCollection([Dummy::class]))->shouldBeCalled(); - $resourceClassResolver = new ResourceClassResolver($resourceNameCollectionFactoryProphecy->reveal()); - $resourceClass = $resourceClassResolver->getResourceClass($dummies, Dummy::class); - $this->assertEquals($resourceClass, Dummy::class); + $this->assertEquals(Dummy::class, $resourceClassResolver->getResourceClass($dummies, Dummy::class)); } public function testGetResourceClassWithPaginatorInterfaceAsValue() { - $paginatorProphecy = $this->prophesize(PaginatorInterface::class); - $resourceNameCollectionFactoryProphecy = $this->prophesize(ResourceNameCollectionFactoryInterface::class); $resourceNameCollectionFactoryProphecy->create()->willReturn(new ResourceNameCollection([Dummy::class]))->shouldBeCalled(); + $paginatorProphecy = $this->prophesize(PaginatorInterface::class); + $resourceClassResolver = new ResourceClassResolver($resourceNameCollectionFactoryProphecy->reveal()); - $resourceClass = $resourceClassResolver->getResourceClass($paginatorProphecy->reveal(), Dummy::class); - $this->assertEquals($resourceClass, Dummy::class); + $this->assertEquals(Dummy::class, $resourceClassResolver->getResourceClass($paginatorProphecy->reveal(), Dummy::class)); } public function testGetResourceClassWithWrongClassName() @@ -105,82 +109,85 @@ public function testGetResourceClassWithWrongClassName() $resourceNameCollectionFactoryProphecy->create()->willReturn(new ResourceNameCollection([Dummy::class]))->shouldBeCalled(); $resourceClassResolver = new ResourceClassResolver($resourceNameCollectionFactoryProphecy->reveal()); + $resourceClassResolver->getResourceClass(new \stdClass()); } public function testGetResourceClassWithNoResourceClassName() { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('No resource class found.'); + $this->expectExceptionMessage('Resource type could not be determined. Resource class must be specified.'); $resourceNameCollectionFactoryProphecy = $this->prophesize(ResourceNameCollectionFactoryInterface::class); $resourceClassResolver = new ResourceClassResolver($resourceNameCollectionFactoryProphecy->reveal()); + $resourceClassResolver->getResourceClass(new \ArrayIterator([])); } public function testIsResourceClassWithIntendedClassName() { - $dummy = new Dummy(); - $dummy->setName('Smail'); $resourceNameCollectionFactoryProphecy = $this->prophesize(ResourceNameCollectionFactoryInterface::class); - $resourceNameCollectionFactoryProphecy->create()->willReturn(new ResourceNameCollection([Dummy::class]))->shouldBeCalled(); + $resourceNameCollectionFactoryProphecy->create()->willReturn(new ResourceNameCollection([Dummy::class])); $resourceClassResolver = new ResourceClassResolver($resourceNameCollectionFactoryProphecy->reveal()); - $resourceClass = $resourceClassResolver->isResourceClass(Dummy::class); - $this->assertTrue($resourceClass); + + $this->assertTrue($resourceClassResolver->isResourceClass(Dummy::class)); } public function testIsResourceClassWithWrongClassName() { $resourceNameCollectionFactoryProphecy = $this->prophesize(ResourceNameCollectionFactoryInterface::class); - $resourceNameCollectionFactoryProphecy->create()->willReturn(new ResourceNameCollection([\ArrayIterator::class]))->shouldBeCalled(); + $resourceNameCollectionFactoryProphecy->create()->willReturn(new ResourceNameCollection([\ArrayIterator::class])); $resourceClassResolver = new ResourceClassResolver($resourceNameCollectionFactoryProphecy->reveal()); - $resourceClass = $resourceClassResolver->isResourceClass(''); - $this->assertFalse($resourceClass); + + $this->assertFalse($resourceClassResolver->isResourceClass('')); } public function testGetResourceClassWithNoResourceClassNameAndNoObject() { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('No resource class found.'); + $this->expectExceptionMessage('Resource type could not be determined. Resource class must be specified.'); $resourceNameCollectionFactoryProphecy = $this->prophesize(ResourceNameCollectionFactoryInterface::class); $resourceClassResolver = new ResourceClassResolver($resourceNameCollectionFactoryProphecy->reveal()); + $resourceClassResolver->getResourceClass(false); } public function testGetResourceClassWithResourceClassNameAndNoObject() { $resourceNameCollectionFactoryProphecy = $this->prophesize(ResourceNameCollectionFactoryInterface::class); - $resourceNameCollectionFactoryProphecy->create()->willReturn(new ResourceNameCollection([Dummy::class]))->shouldBeCalled(); + $resourceNameCollectionFactoryProphecy->create()->willReturn(new ResourceNameCollection([Dummy::class])); $resourceClassResolver = new ResourceClassResolver($resourceNameCollectionFactoryProphecy->reveal()); - $this->assertEquals($resourceClassResolver->getResourceClass(false, Dummy::class), Dummy::class); + + $this->assertEquals(Dummy::class, $resourceClassResolver->getResourceClass(false, Dummy::class)); } public function testGetResourceClassWithChildResource() { $resourceNameCollectionFactoryProphecy = $this->prophesize(ResourceNameCollectionFactoryInterface::class); - $resourceNameCollectionFactoryProphecy->create()->willReturn(new ResourceNameCollection([DummyTableInheritance::class]))->shouldBeCalled(); + $resourceNameCollectionFactoryProphecy->create()->willReturn(new ResourceNameCollection([DummyTableInheritance::class])); - $t = new DummyTableInheritanceChild(); + $dummy = new DummyTableInheritanceChild(); $resourceClassResolver = new ResourceClassResolver($resourceNameCollectionFactoryProphecy->reveal()); - $this->assertEquals(DummyTableInheritanceChild::class, $resourceClassResolver->getResourceClass($t, DummyTableInheritance::class)); + $this->assertEquals(DummyTableInheritanceChild::class, $resourceClassResolver->getResourceClass($dummy, DummyTableInheritance::class)); } public function testGetResourceClassWithInterfaceResource() { - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage("The given object's resource is the interface \"ApiPlatform\Core\Tests\Fixtures\DummyResourceInterface\", finding a class is not possible."); - $dummy = new DummyResourceImplementation(); $resourceNameCollectionFactoryProphecy = $this->prophesize(ResourceNameCollectionFactoryInterface::class); + $resourceNameCollectionFactoryProphecy->create()->willReturn(new ResourceNameCollection([DummyResourceInterface::class])); + + $dummy = new DummyResourceImplementation(); $resourceClassResolver = new ResourceClassResolver($resourceNameCollectionFactoryProphecy->reveal()); - $resourceClassResolver->getResourceClass($dummy, DummyResourceInterface::class, true); + + $this->assertEquals(DummyResourceImplementation::class, $resourceClassResolver->getResourceClass($dummy, DummyResourceInterface::class, true)); } } diff --git a/tests/Fixtures/TestBundle/Entity/VoDummyCar.php b/tests/Fixtures/TestBundle/Entity/VoDummyCar.php index 693727d54f1..a1f11c2edca 100644 --- a/tests/Fixtures/TestBundle/Entity/VoDummyCar.php +++ b/tests/Fixtures/TestBundle/Entity/VoDummyCar.php @@ -21,8 +21,8 @@ /** * @ApiResource(attributes={ - * "normalization_context"={"groups"={"read", "write"}}, - * "denormalization_context"={"groups"={"write"}} + * "normalization_context"={"groups"={"car_read"}}, + * "denormalization_context"={"groups"={"car_write"}} * }) * @ORM\Entity */ @@ -32,7 +32,7 @@ class VoDummyCar extends VoDummyVehicle * @var int * * @ORM\Column(type="integer") - * @Groups({"write"}) + * @Groups({"car_read", "car_write"}) */ private $mileage; @@ -40,7 +40,7 @@ class VoDummyCar extends VoDummyVehicle * @var string * * @ORM\Column - * @Groups({"write"}) + * @Groups({"car_read", "car_write"}) */ private $bodyType; @@ -48,7 +48,7 @@ class VoDummyCar extends VoDummyVehicle * @var VoDummyInspection[]|Collection * * @ORM\OneToMany(targetEntity="VoDummyInspection", mappedBy="car", cascade={"persist"}) - * @Groups({"write"}) + * @Groups({"car_read", "car_write"}) */ private $inspections; diff --git a/tests/Fixtures/TestBundle/Entity/VoDummyDriver.php b/tests/Fixtures/TestBundle/Entity/VoDummyDriver.php index edb06b37a6e..f71722046f1 100644 --- a/tests/Fixtures/TestBundle/Entity/VoDummyDriver.php +++ b/tests/Fixtures/TestBundle/Entity/VoDummyDriver.php @@ -29,7 +29,7 @@ class VoDummyDriver * @var string * * @ORM\Column - * @Groups({"write"}) + * @Groups({"car_read", "car_write"}) */ private $firstName; @@ -37,7 +37,7 @@ class VoDummyDriver * @var string * * @ORM\Column - * @Groups({"write"}) + * @Groups({"car_read", "car_write"}) */ private $lastName; diff --git a/tests/Fixtures/TestBundle/Entity/VoDummyInspection.php b/tests/Fixtures/TestBundle/Entity/VoDummyInspection.php index 816147a4b19..a0aca6022a6 100644 --- a/tests/Fixtures/TestBundle/Entity/VoDummyInspection.php +++ b/tests/Fixtures/TestBundle/Entity/VoDummyInspection.php @@ -19,7 +19,10 @@ use Symfony\Component\Serializer\Annotation\Groups; /** - * @ApiResource + * @ApiResource(attributes={ + * "normalization_context"={"groups"={"inspection_read"}}, + * "denormalization_context"={"groups"={"inspection_write"}} + * }) * @ORM\Entity */ class VoDummyInspection @@ -30,7 +33,7 @@ class VoDummyInspection * @var bool * * @ORM\Column(type="boolean") - * @Groups({"write"}) + * @Groups({"car_read", "car_write", "inspection_read", "inspection_write"}) */ private $accepted; @@ -38,7 +41,7 @@ class VoDummyInspection * @var VoDummyCar * * @ORM\ManyToOne(targetEntity="VoDummyCar", inversedBy="inspections") - * @Groups({"write"}) + * @Groups({"inspection_read", "inspection_write"}) */ private $car; @@ -46,7 +49,7 @@ class VoDummyInspection * @var DateTime * * @ORM\Column(type="datetime") - * @Groups({"write"}) + * @Groups({"car_read", "car_write", "inspection_read", "inspection_write"}) */ private $performed; diff --git a/tests/Fixtures/TestBundle/Entity/VoDummyInsuranceCompany.php b/tests/Fixtures/TestBundle/Entity/VoDummyInsuranceCompany.php index e25a44e08bf..d1a6626ebe8 100644 --- a/tests/Fixtures/TestBundle/Entity/VoDummyInsuranceCompany.php +++ b/tests/Fixtures/TestBundle/Entity/VoDummyInsuranceCompany.php @@ -29,7 +29,7 @@ class VoDummyInsuranceCompany * @var string * * @ORM\Column - * @Groups({"write"}) + * @Groups({"car_read", "car_write"}) */ private $name; diff --git a/tests/Fixtures/TestBundle/Entity/VoDummyVehicle.php b/tests/Fixtures/TestBundle/Entity/VoDummyVehicle.php index 5fc72d4e2eb..14e03216652 100644 --- a/tests/Fixtures/TestBundle/Entity/VoDummyVehicle.php +++ b/tests/Fixtures/TestBundle/Entity/VoDummyVehicle.php @@ -29,7 +29,7 @@ abstract class VoDummyVehicle * @var string * * @ORM\Column - * @Groups({"write"}) + * @Groups({"car_read", "car_write"}) */ private $make; @@ -37,7 +37,7 @@ abstract class VoDummyVehicle * @var VoDummyInsuranceCompany * * @ORM\ManyToOne(targetEntity="VoDummyInsuranceCompany", cascade={"persist"}) - * @Groups({"write"}) + * @Groups({"car_read", "car_write"}) */ private $insuranceCompany; @@ -45,7 +45,7 @@ abstract class VoDummyVehicle * @var VoDummyDriver[]|Collection * * @ORM\ManyToMany(targetEntity="VoDummyDriver", cascade={"persist"}) - * @Groups({"write"}) + * @Groups({"car_read", "car_write"}) */ private $drivers; diff --git a/tests/GraphQl/Serializer/ItemNormalizerTest.php b/tests/GraphQl/Serializer/ItemNormalizerTest.php index d8d1c9e9293..6cabd959109 100644 --- a/tests/GraphQl/Serializer/ItemNormalizerTest.php +++ b/tests/GraphQl/Serializer/ItemNormalizerTest.php @@ -72,21 +72,21 @@ public function testNormalize() $propertyNameCollection = new PropertyNameCollection(['name']); $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class); - $propertyNameCollectionFactoryProphecy->create(Dummy::class, [])->willReturn($propertyNameCollection)->shouldBeCalled(); + $propertyNameCollectionFactoryProphecy->create(Dummy::class, [])->willReturn($propertyNameCollection); $propertyMetadata = new PropertyMetadata(null, null, true); $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class); - $propertyMetadataFactoryProphecy->create(Dummy::class, 'name', [])->willReturn($propertyMetadata)->shouldBeCalled(); + $propertyMetadataFactoryProphecy->create(Dummy::class, 'name', [])->willReturn($propertyMetadata); $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); - $iriConverterProphecy->getIriFromItem($dummy)->willReturn('/dummies/1')->shouldBeCalled(); + $iriConverterProphecy->getIriFromItem($dummy)->willReturn('/dummies/1'); $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); - $resourceClassResolverProphecy->getResourceClass($dummy, null, true)->willReturn(Dummy::class)->shouldBeCalled(); + $resourceClassResolverProphecy->getResourceClass($dummy, null, false)->willReturn(Dummy::class); $serializerProphecy = $this->prophesize(SerializerInterface::class); $serializerProphecy->willImplement(NormalizerInterface::class); - $serializerProphecy->normalize('hello', ItemNormalizer::FORMAT, Argument::type('array'))->willReturn('hello')->shouldBeCalled(); + $serializerProphecy->normalize('hello', ItemNormalizer::FORMAT, Argument::type('array'))->willReturn('hello'); $normalizer = new ItemNormalizer( $propertyNameCollectionFactoryProphecy->reveal(), @@ -104,7 +104,13 @@ public function testNormalize() ); $normalizer->setSerializer($serializerProphecy->reveal()); - $this->assertEquals(['name' => 'hello', ItemNormalizer::ITEM_KEY => serialize($dummy)], $normalizer->normalize($dummy, ItemNormalizer::FORMAT, ['resources' => []])); + $expected = [ + 'name' => 'hello', + ItemNormalizer::ITEM_KEY => serialize($dummy), + ]; + $this->assertEquals($expected, $normalizer->normalize($dummy, ItemNormalizer::FORMAT, [ + 'resources' => [], + ])); } public function testDenormalize() diff --git a/tests/Hal/Serializer/CollectionNormalizerTest.php b/tests/Hal/Serializer/CollectionNormalizerTest.php index cf67c4cfe1f..96d2e1fe7ce 100644 --- a/tests/Hal/Serializer/CollectionNormalizerTest.php +++ b/tests/Hal/Serializer/CollectionNormalizerTest.php @@ -113,31 +113,34 @@ public function testNormalizePartialPaginator() private function normalizePaginator($partial = false) { $paginatorProphecy = $this->prophesize($partial ? PartialPaginatorInterface::class : PaginatorInterface::class); - $paginatorProphecy->getCurrentPage()->willReturn(3)->shouldBeCalled(); - $paginatorProphecy->getItemsPerPage()->willReturn(12)->shouldBeCalled(); - $paginatorProphecy->rewind()->shouldBeCalled(); - $paginatorProphecy->valid()->willReturn(true, false)->shouldBeCalled(); - $paginatorProphecy->current()->willReturn('foo')->shouldBeCalled(); - $paginatorProphecy->next()->willReturn()->shouldBeCalled(); + $paginatorProphecy->getCurrentPage()->willReturn(3); + $paginatorProphecy->getItemsPerPage()->willReturn(12); + $paginatorProphecy->rewind()->will(function () {}); + $paginatorProphecy->valid()->willReturn(true, false); + $paginatorProphecy->current()->willReturn('foo'); + $paginatorProphecy->next()->will(function () {}); if (!$partial) { - $paginatorProphecy->getLastPage()->willReturn(7)->shouldBeCalled(); - $paginatorProphecy->getTotalItems()->willReturn(1312)->shouldBeCalled(); + $paginatorProphecy->getLastPage()->willReturn(7); + $paginatorProphecy->getTotalItems()->willReturn(1312); } else { - $paginatorProphecy->count()->willReturn(12)->shouldBeCalled(); + $paginatorProphecy->count()->willReturn(12); } - $paginator = $paginatorProphecy->reveal(); - $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); - $resourceClassResolverProphecy->getResourceClass($paginator, null, true)->willReturn('Foo')->shouldBeCalled(); + $resourceClassResolverProphecy->getResourceClass($paginatorProphecy, 'Foo')->willReturn('Foo'); $itemNormalizer = $this->prophesize(NormalizerInterface::class); - $itemNormalizer->normalize('foo', null, ['api_sub_level' => true, 'resource_class' => 'Foo'])->willReturn(['_links' => ['self' => '/me'], 'name' => 'Kévin']); + $itemNormalizer->normalize('foo', CollectionNormalizer::FORMAT, [ + 'api_sub_level' => true, + 'resource_class' => 'Foo', + ])->willReturn(['_links' => ['self' => '/me'], 'name' => 'Kévin']); $normalizer = new CollectionNormalizer($resourceClassResolverProphecy->reveal(), 'page'); $normalizer->setNormalizer($itemNormalizer->reveal()); - return $normalizer->normalize($paginator); + return $normalizer->normalize($paginatorProphecy->reveal(), CollectionNormalizer::FORMAT, [ + 'resource_class' => 'Foo', + ]); } } diff --git a/tests/Hal/Serializer/ItemNormalizerTest.php b/tests/Hal/Serializer/ItemNormalizerTest.php index 3ac060292f0..0c68d249832 100644 --- a/tests/Hal/Serializer/ItemNormalizerTest.php +++ b/tests/Hal/Serializer/ItemNormalizerTest.php @@ -82,8 +82,8 @@ public function testSupportsNormalization() $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); - $resourceClassResolverProphecy->isResourceClass(Dummy::class)->willReturn(true)->shouldBeCalled(); - $resourceClassResolverProphecy->isResourceClass(\stdClass::class)->willReturn(false)->shouldBeCalled(); + $resourceClassResolverProphecy->isResourceClass(Dummy::class)->willReturn(true); + $resourceClassResolverProphecy->isResourceClass(\stdClass::class)->willReturn(false); $nameConverter = $this->prophesize(NameConverterInterface::class); @@ -111,32 +111,33 @@ public function testNormalize() $propertyNameCollection = new PropertyNameCollection(['name', 'relatedDummy']); $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class); - $propertyNameCollectionFactoryProphecy->create(Dummy::class, [])->willReturn($propertyNameCollection)->shouldBeCalled(); + $propertyNameCollectionFactoryProphecy->create(Dummy::class, [])->willReturn($propertyNameCollection); $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class); $propertyMetadataFactoryProphecy->create(Dummy::class, 'name', [])->willReturn( new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), '', true) - )->shouldBeCalled(); + ); $propertyMetadataFactoryProphecy->create(Dummy::class, 'relatedDummy', [])->willReturn( new PropertyMetadata(new Type(Type::BUILTIN_TYPE_OBJECT, false, RelatedDummy::class), '', true, false, false) - )->shouldBeCalled(); + ); $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); - $iriConverterProphecy->getIriFromItem($dummy)->willReturn('/dummies/1')->shouldBeCalled(); - $iriConverterProphecy->getIriFromItem($relatedDummy)->willReturn('/related-dummies/2')->shouldBeCalled(); + $iriConverterProphecy->getIriFromItem($dummy)->willReturn('/dummies/1'); + $iriConverterProphecy->getIriFromItem($relatedDummy)->willReturn('/related-dummies/2'); $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); - $resourceClassResolverProphecy->getResourceClass($dummy, null, true)->willReturn(Dummy::class)->shouldBeCalled(); - $resourceClassResolverProphecy->getResourceClass($dummy, Dummy::class, true)->willReturn(Dummy::class)->shouldBeCalled(); - $resourceClassResolverProphecy->isResourceClass(RelatedDummy::class)->willReturn(true)->shouldBeCalled(); + $resourceClassResolverProphecy->getResourceClass($dummy, null, false)->willReturn(Dummy::class); + $resourceClassResolverProphecy->getResourceClass($dummy, Dummy::class, true)->willReturn(Dummy::class); + $resourceClassResolverProphecy->getResourceClass($relatedDummy, RelatedDummy::class, true)->willReturn(RelatedDummy::class); + $resourceClassResolverProphecy->isResourceClass(RelatedDummy::class)->willReturn(true); $serializerProphecy = $this->prophesize(SerializerInterface::class); $serializerProphecy->willImplement(NormalizerInterface::class); - $serializerProphecy->normalize('hello', null, Argument::type('array'))->willReturn('hello')->shouldBeCalled(); + $serializerProphecy->normalize('hello', null, Argument::type('array'))->willReturn('hello'); $nameConverter = $this->prophesize(NameConverterInterface::class); - $nameConverter->normalize('name', Argument::any(), Argument::any(), Argument::any())->shouldBeCalled()->willReturn('name'); - $nameConverter->normalize('relatedDummy', Argument::any(), Argument::any(), Argument::any())->shouldBeCalled()->willReturn('related_dummy'); + $nameConverter->normalize('name', Argument::any(), Argument::any(), Argument::any())->willReturn('name'); + $nameConverter->normalize('relatedDummy', Argument::any(), Argument::any(), Argument::any())->willReturn('related_dummy'); $normalizer = new ItemNormalizer( $propertyNameCollectionFactoryProphecy->reveal(), @@ -177,32 +178,33 @@ public function testNormalizeWithoutCache() $propertyNameCollection = new PropertyNameCollection(['name', 'relatedDummy']); $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class); - $propertyNameCollectionFactoryProphecy->create(Dummy::class, [])->willReturn($propertyNameCollection)->shouldBeCalled(); + $propertyNameCollectionFactoryProphecy->create(Dummy::class, [])->willReturn($propertyNameCollection); $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class); $propertyMetadataFactoryProphecy->create(Dummy::class, 'name', [])->willReturn( new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), '', true) - )->shouldBeCalled(); + ); $propertyMetadataFactoryProphecy->create(Dummy::class, 'relatedDummy', [])->willReturn( new PropertyMetadata(new Type(Type::BUILTIN_TYPE_OBJECT, false, RelatedDummy::class), '', true, false, false) - )->shouldBeCalled(); + ); $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); - $iriConverterProphecy->getIriFromItem($dummy)->willReturn('/dummies/1')->shouldBeCalled(); - $iriConverterProphecy->getIriFromItem($relatedDummy)->willReturn('/related-dummies/2')->shouldBeCalled(); + $iriConverterProphecy->getIriFromItem($dummy)->willReturn('/dummies/1'); + $iriConverterProphecy->getIriFromItem($relatedDummy)->willReturn('/related-dummies/2'); $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); - $resourceClassResolverProphecy->getResourceClass($dummy, null, true)->willReturn(Dummy::class)->shouldBeCalled(); - $resourceClassResolverProphecy->getResourceClass($dummy, Dummy::class, true)->willReturn(Dummy::class)->shouldBeCalled(); - $resourceClassResolverProphecy->isResourceClass(RelatedDummy::class)->willReturn(true)->shouldBeCalled(); + $resourceClassResolverProphecy->getResourceClass($dummy, null, false)->willReturn(Dummy::class); + $resourceClassResolverProphecy->getResourceClass($dummy, Dummy::class, true)->willReturn(Dummy::class); + $resourceClassResolverProphecy->getResourceClass($relatedDummy, RelatedDummy::class, true)->willReturn(RelatedDummy::class); + $resourceClassResolverProphecy->isResourceClass(RelatedDummy::class)->willReturn(true); $serializerProphecy = $this->prophesize(SerializerInterface::class); $serializerProphecy->willImplement(NormalizerInterface::class); - $serializerProphecy->normalize('hello', null, Argument::type('array'))->willReturn('hello')->shouldBeCalled(); + $serializerProphecy->normalize('hello', null, Argument::type('array'))->willReturn('hello'); $nameConverter = $this->prophesize(NameConverterInterface::class); - $nameConverter->normalize('name', Argument::any(), Argument::any(), Argument::any())->shouldBeCalled()->willReturn('name'); - $nameConverter->normalize('relatedDummy', Argument::any(), Argument::any(), Argument::any())->shouldBeCalled()->willReturn('related_dummy'); + $nameConverter->normalize('name', Argument::any(), Argument::any(), Argument::any())->willReturn('name'); + $nameConverter->normalize('relatedDummy', Argument::any(), Argument::any(), Argument::any())->willReturn('related_dummy'); $normalizer = new ItemNormalizer( $propertyNameCollectionFactoryProphecy->reveal(), @@ -258,30 +260,31 @@ public function testMaxDepth() $propertyNameCollection = new PropertyNameCollection(['id', 'name', 'child']); $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class); - $propertyNameCollectionFactoryProphecy->create(MaxDepthDummy::class, [])->willReturn($propertyNameCollection)->shouldBeCalled(); + $propertyNameCollectionFactoryProphecy->create(MaxDepthDummy::class, [])->willReturn($propertyNameCollection); $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class); $propertyMetadataFactoryProphecy->create(MaxDepthDummy::class, 'id', [])->willReturn( new PropertyMetadata(new Type(Type::BUILTIN_TYPE_INT), '', true) - )->shouldBeCalled(); + ); $propertyMetadataFactoryProphecy->create(MaxDepthDummy::class, 'name', [])->willReturn( new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), '', true) - )->shouldBeCalled(); + ); $propertyMetadataFactoryProphecy->create(MaxDepthDummy::class, 'child', [])->willReturn( new PropertyMetadata(new Type(Type::BUILTIN_TYPE_OBJECT, false, MaxDepthDummy::class), '', true, false, true) - )->shouldBeCalled(); + ); $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); - $iriConverterProphecy->getIriFromItem($level1)->willReturn('/max_depth_dummies/1')->shouldBeCalled(); - $iriConverterProphecy->getIriFromItem($level2)->willReturn('/max_depth_dummies/2')->shouldBeCalled(); - $iriConverterProphecy->getIriFromItem($level3)->willReturn('/max_depth_dummies/3')->shouldBeCalled(); + $iriConverterProphecy->getIriFromItem($level1)->willReturn('/max_depth_dummies/1'); + $iriConverterProphecy->getIriFromItem($level2)->willReturn('/max_depth_dummies/2'); + $iriConverterProphecy->getIriFromItem($level3)->willReturn('/max_depth_dummies/3'); $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); - $resourceClassResolverProphecy->getResourceClass($level1, null, true)->willReturn(MaxDepthDummy::class)->shouldBeCalled(); - $resourceClassResolverProphecy->getResourceClass($level1, MaxDepthDummy::class, true)->willReturn(MaxDepthDummy::class)->shouldBeCalled(); - $resourceClassResolverProphecy->getResourceClass($level2, MaxDepthDummy::class, true)->willReturn(MaxDepthDummy::class)->shouldBeCalled(); - $resourceClassResolverProphecy->getResourceClass($level3, MaxDepthDummy::class, true)->willReturn(MaxDepthDummy::class)->shouldBeCalled(); - $resourceClassResolverProphecy->isResourceClass(MaxDepthDummy::class)->willReturn(true)->shouldBeCalled(); + $resourceClassResolverProphecy->getResourceClass($level1, null, false)->willReturn(MaxDepthDummy::class); + $resourceClassResolverProphecy->getResourceClass($level1, MaxDepthDummy::class, true)->willReturn(MaxDepthDummy::class); + $resourceClassResolverProphecy->getResourceClass($level2, MaxDepthDummy::class, true)->willReturn(MaxDepthDummy::class); + $resourceClassResolverProphecy->getResourceClass($level3, MaxDepthDummy::class, true)->willReturn(MaxDepthDummy::class); + $resourceClassResolverProphecy->getResourceClass(null, MaxDepthDummy::class, true)->willReturn(MaxDepthDummy::class); + $resourceClassResolverProphecy->isResourceClass(MaxDepthDummy::class)->willReturn(true); $normalizer = new ItemNormalizer( $propertyNameCollectionFactoryProphecy->reveal(), diff --git a/tests/Hydra/Serializer/CollectionFiltersNormalizerTest.php b/tests/Hydra/Serializer/CollectionFiltersNormalizerTest.php index e6a3ab95d9a..6f48636b200 100644 --- a/tests/Hydra/Serializer/CollectionFiltersNormalizerTest.php +++ b/tests/Hydra/Serializer/CollectionFiltersNormalizerTest.php @@ -196,13 +196,16 @@ public function testDoNothingIfNoFilter() $dummy = new Dummy(); $decoratedProphecy = $this->prophesize(NormalizerInterface::class); - $decoratedProphecy->normalize($dummy, null, ['collection_operation_name' => 'get'])->willReturn(['name' => 'foo'])->shouldBeCalled(); + $decoratedProphecy->normalize($dummy, CollectionNormalizer::FORMAT, [ + 'collection_operation_name' => 'get', + 'resource_class' => Dummy::class, + ])->willReturn(['name' => 'foo']); $resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class); $resourceMetadataFactoryProphecy->create(Dummy::class)->willReturn(new ResourceMetadata('foo', '', null, [], ['get' => []])); $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); - $resourceClassResolverProphecy->getResourceClass($dummy, null, true)->willReturn(Dummy::class)->shouldBeCalled(); + $resourceClassResolverProphecy->getResourceClass($dummy, Dummy::class)->willReturn(Dummy::class); $normalizer = new CollectionFiltersNormalizer( $decoratedProphecy->reveal(), @@ -211,7 +214,10 @@ public function testDoNothingIfNoFilter() $this->prophesize(ContainerInterface::class)->reveal() ); - $this->assertEquals(['name' => 'foo'], $normalizer->normalize($dummy, null, ['collection_operation_name' => 'get'])); + $this->assertEquals(['name' => 'foo'], $normalizer->normalize($dummy, CollectionNormalizer::FORMAT, [ + 'collection_operation_name' => 'get', + 'resource_class' => Dummy::class, + ])); } public function testDoNothingIfNoRequestUri() @@ -219,13 +225,15 @@ public function testDoNothingIfNoRequestUri() $dummy = new Dummy(); $decoratedProphecy = $this->prophesize(NormalizerInterface::class); - $decoratedProphecy->normalize($dummy, null, [])->willReturn(['name' => 'foo'])->shouldBeCalled(); + $decoratedProphecy->normalize($dummy, CollectionNormalizer::FORMAT, [ + 'resource_class' => Dummy::class, + ])->willReturn(['name' => 'foo']); $resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class); $resourceMetadataFactoryProphecy->create(Dummy::class)->willReturn(new ResourceMetadata('foo', '', null, [], [], ['filters' => ['foo']])); $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); - $resourceClassResolverProphecy->getResourceClass($dummy, null, true)->willReturn(Dummy::class)->shouldBeCalled(); + $resourceClassResolverProphecy->getResourceClass($dummy, Dummy::class)->willReturn(Dummy::class); $normalizer = new CollectionFiltersNormalizer( $decoratedProphecy->reveal(), @@ -234,7 +242,9 @@ public function testDoNothingIfNoRequestUri() $this->prophesize(ContainerInterface::class)->reveal() ); - $this->assertEquals(['name' => 'foo'], $normalizer->normalize($dummy)); + $this->assertEquals(['name' => 'foo'], $normalizer->normalize($dummy, CollectionNormalizer::FORMAT, [ + 'resource_class' => Dummy::class, + ])); } public function testNormalize() @@ -282,13 +292,16 @@ private function normalize($filterLocator) $dummy = new Dummy(); $decoratedProphecy = $this->prophesize(NormalizerInterface::class); - $decoratedProphecy->normalize($dummy, null, ['request_uri' => '/foo?bar=baz'])->willReturn(['name' => 'foo'])->shouldBeCalled(); + $decoratedProphecy->normalize($dummy, CollectionNormalizer::FORMAT, [ + 'request_uri' => '/foo?bar=baz', + 'resource_class' => Dummy::class, + ])->willReturn(['name' => 'foo']); $resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class); $resourceMetadataFactoryProphecy->create(Dummy::class)->willReturn(new ResourceMetadata('foo', '', null, [], [], ['filters' => ['foo']])); $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); - $resourceClassResolverProphecy->getResourceClass($dummy, null, true)->willReturn(Dummy::class)->shouldBeCalled(); + $resourceClassResolverProphecy->getResourceClass($dummy, Dummy::class)->willReturn(Dummy::class); $normalizer = new CollectionFiltersNormalizer( $decoratedProphecy->reveal(), @@ -312,6 +325,9 @@ private function normalize($filterLocator) ], ], ], - ], $normalizer->normalize($dummy, null, ['request_uri' => '/foo?bar=baz'])); + ], $normalizer->normalize($dummy, CollectionNormalizer::FORMAT, [ + 'request_uri' => '/foo?bar=baz', + 'resource_class' => Dummy::class, + ])); } } diff --git a/tests/Hydra/Serializer/CollectionNormalizerTest.php b/tests/Hydra/Serializer/CollectionNormalizerTest.php index 6b91d9030c1..2cbf75637f1 100644 --- a/tests/Hydra/Serializer/CollectionNormalizerTest.php +++ b/tests/Hydra/Serializer/CollectionNormalizerTest.php @@ -80,7 +80,7 @@ public function testNormalizeResourceCollection() $contextBuilderProphecy->getResourceContextUri(Foo::class)->willReturn('/contexts/Foo'); $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); - $resourceClassResolverProphecy->getResourceClass($data, Foo::class, true)->willReturn(Foo::class); + $resourceClassResolverProphecy->getResourceClass($data, Foo::class)->willReturn(Foo::class); $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); $iriConverterProphecy->getIriFromResourceClass(Foo::class)->willReturn('/foos'); @@ -294,21 +294,19 @@ private function normalizePaginator($partial = false) $paginatorProphecy = $this->prophesize($partial ? PartialPaginatorInterface::class : PaginatorInterface::class); if (!$partial) { - $paginatorProphecy->getTotalItems()->willReturn(1312)->shouldBeCalled(); + $paginatorProphecy->getTotalItems()->willReturn(1312); } - $paginatorProphecy->rewind()->shouldBeCalled(); - $paginatorProphecy->valid()->willReturn(true, false)->shouldBeCalled(); - $paginatorProphecy->current()->willReturn('foo')->shouldBeCalled(); - $paginatorProphecy->next()->willReturn()->shouldBeCalled(); - - $paginator = $paginatorProphecy->reveal(); + $paginatorProphecy->rewind()->will(function () {}); + $paginatorProphecy->valid()->willReturn(true, false); + $paginatorProphecy->current()->willReturn('foo'); + $paginatorProphecy->next()->will(function () {}); $serializer = $this->prophesize(SerializerInterface::class); $serializer->willImplement(NormalizerInterface::class); $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); - $resourceClassResolverProphecy->getResourceClass($paginator, null, true)->willReturn('Foo')->shouldBeCalled(); + $resourceClassResolverProphecy->getResourceClass($paginatorProphecy, 'Foo')->willReturn('Foo'); $iriConvert = $this->prophesize(IriConverterInterface::class); $iriConvert->getIriFromResourceClass('Foo')->willReturn('/foo/1'); @@ -317,11 +315,17 @@ private function normalizePaginator($partial = false) $contextBuilder->getResourceContextUri('Foo')->willReturn('/contexts/Foo'); $itemNormalizer = $this->prophesize(AbstractItemNormalizer::class); - $itemNormalizer->normalize('foo', null, ['jsonld_has_context' => true, 'api_sub_level' => true, 'resource_class' => 'Foo'])->willReturn(['name' => 'Kévin', 'friend' => 'Smail']); + $itemNormalizer->normalize('foo', CollectionNormalizer::FORMAT, [ + 'jsonld_has_context' => true, + 'api_sub_level' => true, + 'resource_class' => 'Foo', + ])->willReturn(['name' => 'Kévin', 'friend' => 'Smail']); $normalizer = new CollectionNormalizer($contextBuilder->reveal(), $resourceClassResolverProphecy->reveal(), $iriConvert->reveal()); $normalizer->setNormalizer($itemNormalizer->reveal()); - return $normalizer->normalize($paginator); + return $normalizer->normalize($paginatorProphecy->reveal(), CollectionNormalizer::FORMAT, [ + 'resource_class' => 'Foo', + ]); } } diff --git a/tests/JsonApi/Serializer/CollectionNormalizerTest.php b/tests/JsonApi/Serializer/CollectionNormalizerTest.php index e062e7d11a3..7096379e25d 100644 --- a/tests/JsonApi/Serializer/CollectionNormalizerTest.php +++ b/tests/JsonApi/Serializer/CollectionNormalizerTest.php @@ -42,41 +42,35 @@ public function testSupportsNormalize() public function testNormalizePaginator() { $paginatorProphecy = $this->prophesize(PaginatorInterface::class); - $paginatorProphecy->getCurrentPage()->willReturn(3.)->shouldBeCalled(); - $paginatorProphecy->getLastPage()->willReturn(7.)->shouldBeCalled(); - $paginatorProphecy->getItemsPerPage()->willReturn(12.)->shouldBeCalled(); - $paginatorProphecy->getTotalItems()->willReturn(1312.)->shouldBeCalled(); - $paginatorProphecy->rewind()->shouldBeCalled(); - $paginatorProphecy->next()->willReturn()->shouldBeCalled(); - $paginatorProphecy->current()->willReturn('foo')->shouldBeCalled(); - $paginatorProphecy->valid()->willReturn(true, false)->shouldBeCalled(); + $paginatorProphecy->getCurrentPage()->willReturn(3.); + $paginatorProphecy->getLastPage()->willReturn(7.); + $paginatorProphecy->getItemsPerPage()->willReturn(12.); + $paginatorProphecy->getTotalItems()->willReturn(1312.); + $paginatorProphecy->rewind()->will(function () {}); + $paginatorProphecy->next()->will(function () {}); + $paginatorProphecy->current()->willReturn('foo'); + $paginatorProphecy->valid()->willReturn(true, false); $paginator = $paginatorProphecy->reveal(); $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); - $resourceClassResolverProphecy->getResourceClass($paginator, null, true)->willReturn('Foo')->shouldBeCalled(); + $resourceClassResolverProphecy->getResourceClass($paginator, 'Foo')->willReturn('Foo'); $itemNormalizer = $this->prophesize(NormalizerInterface::class); - $itemNormalizer - ->normalize( - 'foo', - CollectionNormalizer::FORMAT, - [ - 'request_uri' => '/foos?page=3', - 'api_sub_level' => true, - 'resource_class' => 'Foo', - ] - ) - ->willReturn([ - 'data' => [ - 'type' => 'Foo', + $itemNormalizer->normalize('foo', CollectionNormalizer::FORMAT, [ + 'request_uri' => '/foos?page=3', + 'api_sub_level' => true, + 'resource_class' => 'Foo', + ])->willReturn([ + 'data' => [ + 'type' => 'Foo', + 'id' => 1, + 'attributes' => [ 'id' => 1, - 'attributes' => [ - 'id' => 1, - 'name' => 'Kévin', - ], + 'name' => 'Kévin', ], - ]); + ], + ]); $normalizer = new CollectionNormalizer($resourceClassResolverProphecy->reveal(), 'page'); $normalizer->setNormalizer($itemNormalizer->reveal()); @@ -106,46 +100,43 @@ public function testNormalizePaginator() ], ]; - $this->assertEquals($expected, $normalizer->normalize($paginator, CollectionNormalizer::FORMAT, ['request_uri' => '/foos?page=3'])); + $this->assertEquals($expected, $normalizer->normalize($paginator, CollectionNormalizer::FORMAT, [ + 'request_uri' => '/foos?page=3', + 'resource_class' => 'Foo', + ])); } public function testNormalizePartialPaginator() { $paginatorProphecy = $this->prophesize(PartialPaginatorInterface::class); - $paginatorProphecy->getCurrentPage()->willReturn(3.)->shouldBeCalled(); - $paginatorProphecy->getItemsPerPage()->willReturn(12.)->shouldBeCalled(); - $paginatorProphecy->rewind()->shouldBeCalled(); - $paginatorProphecy->next()->willReturn()->shouldBeCalled(); - $paginatorProphecy->current()->willReturn('foo')->shouldBeCalled(); - $paginatorProphecy->valid()->willReturn(true, false)->shouldBeCalled(); - $paginatorProphecy->count()->willReturn(1312)->shouldBeCalled(); + $paginatorProphecy->getCurrentPage()->willReturn(3.); + $paginatorProphecy->getItemsPerPage()->willReturn(12.); + $paginatorProphecy->rewind()->will(function () {}); + $paginatorProphecy->next()->will(function () {}); + $paginatorProphecy->current()->willReturn('foo'); + $paginatorProphecy->valid()->willReturn(true, false); + $paginatorProphecy->count()->willReturn(1312); $paginator = $paginatorProphecy->reveal(); $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); - $resourceClassResolverProphecy->getResourceClass($paginator, null, true)->willReturn('Foo')->shouldBeCalled(); + $resourceClassResolverProphecy->getResourceClass($paginator, 'Foo')->willReturn('Foo'); $itemNormalizer = $this->prophesize(NormalizerInterface::class); - $itemNormalizer - ->normalize( - 'foo', - CollectionNormalizer::FORMAT, - [ - 'request_uri' => '/foos?page=3', - 'api_sub_level' => true, - 'resource_class' => 'Foo', - ] - ) - ->willReturn([ - 'data' => [ - 'type' => 'Foo', + $itemNormalizer->normalize('foo', CollectionNormalizer::FORMAT, [ + 'request_uri' => '/foos?page=3', + 'api_sub_level' => true, + 'resource_class' => 'Foo', + ])->willReturn([ + 'data' => [ + 'type' => 'Foo', + 'id' => 1, + 'attributes' => [ 'id' => 1, - 'attributes' => [ - 'id' => 1, - 'name' => 'Kévin', - ], + 'name' => 'Kévin', ], - ]); + ], + ]); $normalizer = new CollectionNormalizer($resourceClassResolverProphecy->reveal(), 'page'); $normalizer->setNormalizer($itemNormalizer->reveal()); @@ -172,7 +163,10 @@ public function testNormalizePartialPaginator() ], ]; - $this->assertEquals($expected, $normalizer->normalize($paginator, CollectionNormalizer::FORMAT, ['request_uri' => '/foos?page=3'])); + $this->assertEquals($expected, $normalizer->normalize($paginator, CollectionNormalizer::FORMAT, [ + 'request_uri' => '/foos?page=3', + 'resource_class' => 'Foo', + ])); } public function testNormalizeArray() @@ -180,29 +174,23 @@ public function testNormalizeArray() $data = ['foo']; $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); - $resourceClassResolverProphecy->getResourceClass($data, null, true)->willReturn('Foo')->shouldBeCalled(); + $resourceClassResolverProphecy->getResourceClass($data, 'Foo')->willReturn('Foo'); $itemNormalizer = $this->prophesize(NormalizerInterface::class); - $itemNormalizer - ->normalize( - 'foo', - CollectionNormalizer::FORMAT, - [ - 'request_uri' => '/foos', - 'api_sub_level' => true, - 'resource_class' => 'Foo', - ] - ) - ->willReturn([ - 'data' => [ - 'type' => 'Foo', + $itemNormalizer->normalize('foo', CollectionNormalizer::FORMAT, [ + 'request_uri' => '/foos', + 'api_sub_level' => true, + 'resource_class' => 'Foo', + ])->willReturn([ + 'data' => [ + 'type' => 'Foo', + 'id' => 1, + 'attributes' => [ 'id' => 1, - 'attributes' => [ - 'id' => 1, - 'name' => 'Baptiste', - ], + 'name' => 'Baptiste', ], - ]); + ], + ]); $normalizer = new CollectionNormalizer($resourceClassResolverProphecy->reveal(), 'page'); $normalizer->setNormalizer($itemNormalizer->reveal()); @@ -222,7 +210,10 @@ public function testNormalizeArray() 'meta' => ['totalItems' => 1], ]; - $this->assertEquals($expected, $normalizer->normalize($data, CollectionNormalizer::FORMAT, ['request_uri' => '/foos'])); + $this->assertEquals($expected, $normalizer->normalize($data, CollectionNormalizer::FORMAT, [ + 'request_uri' => '/foos', + 'resource_class' => 'Foo', + ])); } public function testNormalizeIncludedData() @@ -230,39 +221,33 @@ public function testNormalizeIncludedData() $data = ['foo']; $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); - $resourceClassResolverProphecy->getResourceClass($data, null, true)->willReturn('Foo')->shouldBeCalled(); + $resourceClassResolverProphecy->getResourceClass($data, 'Foo')->willReturn('Foo'); $itemNormalizer = $this->prophesize(NormalizerInterface::class); - $itemNormalizer - ->normalize( - 'foo', - CollectionNormalizer::FORMAT, + $itemNormalizer->normalize('foo', CollectionNormalizer::FORMAT, [ + 'request_uri' => '/foos', + 'api_sub_level' => true, + 'resource_class' => 'Foo', + ])->willReturn([ + 'data' => [ + 'type' => 'Foo', + 'id' => 1, + 'attributes' => [ + 'id' => 1, + 'name' => 'Baptiste', + ], + ], + 'included' => [ [ - 'request_uri' => '/foos', - 'api_sub_level' => true, - 'resource_class' => 'Foo', - ] - ) - ->willReturn([ - 'data' => [ - 'type' => 'Foo', + 'type' => 'Bar', 'id' => 1, 'attributes' => [ 'id' => 1, - 'name' => 'Baptiste', - ], - ], - 'included' => [ - [ - 'type' => 'Bar', - 'id' => 1, - 'attributes' => [ - 'id' => 1, - 'name' => 'Anto', - ], + 'name' => 'Anto', ], ], - ]); + ], + ]); $normalizer = new CollectionNormalizer($resourceClassResolverProphecy->reveal(), 'page'); $normalizer->setNormalizer($itemNormalizer->reveal()); @@ -292,7 +277,10 @@ public function testNormalizeIncludedData() ], ]; - $this->assertEquals($expected, $normalizer->normalize($data, CollectionNormalizer::FORMAT, ['request_uri' => '/foos'])); + $this->assertEquals($expected, $normalizer->normalize($data, CollectionNormalizer::FORMAT, [ + 'request_uri' => '/foos', + 'resource_class' => 'Foo', + ])); } public function testNormalizeWithoutDataKey() @@ -303,24 +291,21 @@ public function testNormalizeWithoutDataKey() $data = ['foo']; $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); - $resourceClassResolverProphecy->getResourceClass($data, null, true)->willReturn('Foo')->shouldBeCalled(); + $resourceClassResolverProphecy->getResourceClass($data, 'Foo')->willReturn('Foo'); $itemNormalizer = $this->prophesize(NormalizerInterface::class); - $itemNormalizer - ->normalize( - 'foo', - CollectionNormalizer::FORMAT, - [ - 'request_uri' => '/foos', - 'api_sub_level' => true, - 'resource_class' => 'Foo', - ] - ) - ->willReturn([]); + $itemNormalizer->normalize('foo', CollectionNormalizer::FORMAT, [ + 'request_uri' => '/foos', + 'api_sub_level' => true, + 'resource_class' => 'Foo', + ])->willReturn([]); $normalizer = new CollectionNormalizer($resourceClassResolverProphecy->reveal(), 'page'); $normalizer->setNormalizer($itemNormalizer->reveal()); - $normalizer->normalize($data, CollectionNormalizer::FORMAT, ['request_uri' => '/foos']); + $normalizer->normalize($data, CollectionNormalizer::FORMAT, [ + 'request_uri' => '/foos', + 'resource_class' => 'Foo', + ]); } } diff --git a/tests/JsonApi/Serializer/ItemNormalizerTest.php b/tests/JsonApi/Serializer/ItemNormalizerTest.php index 24fbd80ad3a..bf5306bf5c8 100644 --- a/tests/JsonApi/Serializer/ItemNormalizerTest.php +++ b/tests/JsonApi/Serializer/ItemNormalizerTest.php @@ -114,7 +114,7 @@ public function testNormalize() $iriConverterProphecy->getIriFromItem($dummy)->willReturn('/dummies/10'); $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); - $resourceClassResolverProphecy->getResourceClass($dummy, null, true)->willReturn(Dummy::class); + $resourceClassResolverProphecy->getResourceClass($dummy, null, false)->willReturn(Dummy::class); $resourceClassResolverProphecy->getResourceClass($dummy, Dummy::class, true)->willReturn(Dummy::class); $propertyAccessorProphecy = $this->prophesize(PropertyAccessorInterface::class); @@ -170,7 +170,7 @@ public function testNormalizeCircularReference() $iriConverterProphecy->getIriFromItem($circularReferenceEntity)->willReturn('/circular_references/1'); $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); - $resourceClassResolverProphecy->getResourceClass($circularReferenceEntity, null, true)->willReturn(CircularReference::class); + $resourceClassResolverProphecy->getResourceClass($circularReferenceEntity, null, false)->willReturn(CircularReference::class); $resourceClassResolverProphecy->getResourceClass($circularReferenceEntity, CircularReference::class, true)->willReturn(CircularReference::class); $resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class); @@ -226,7 +226,7 @@ public function testNormalizeNonExistentProperty() $iriConverterProphecy->getIriFromItem($dummy)->willReturn('/dummies/1'); $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); - $resourceClassResolverProphecy->getResourceClass($dummy, null, true)->willReturn(Dummy::class); + $resourceClassResolverProphecy->getResourceClass($dummy, null, false)->willReturn(Dummy::class); $resourceClassResolverProphecy->getResourceClass($dummy, Dummy::class, true)->willReturn(Dummy::class); $propertyAccessorProphecy = $this->prophesize(PropertyAccessorInterface::class); diff --git a/tests/JsonLd/Serializer/ItemNormalizerTest.php b/tests/JsonLd/Serializer/ItemNormalizerTest.php index fb5b1bf984f..fbea14f6392 100644 --- a/tests/JsonLd/Serializer/ItemNormalizerTest.php +++ b/tests/JsonLd/Serializer/ItemNormalizerTest.php @@ -97,22 +97,22 @@ public function testNormalize() $resourceMetadataFactoryProphecy->create(Dummy::class)->willReturn(new ResourceMetadata('Dummy')); $propertyNameCollection = new PropertyNameCollection(['name']); $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class); - $propertyNameCollectionFactoryProphecy->create(Dummy::class, [])->willReturn($propertyNameCollection)->shouldBeCalled(); + $propertyNameCollectionFactoryProphecy->create(Dummy::class, [])->willReturn($propertyNameCollection); $propertyMetadata = new PropertyMetadata(null, null, true); $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class); - $propertyMetadataFactoryProphecy->create(Dummy::class, 'name', [])->willReturn($propertyMetadata)->shouldBeCalled(); + $propertyMetadataFactoryProphecy->create(Dummy::class, 'name', [])->willReturn($propertyMetadata); $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); - $iriConverterProphecy->getIriFromItem($dummy)->willReturn('/dummies/1988')->shouldBeCalled(); + $iriConverterProphecy->getIriFromItem($dummy)->willReturn('/dummies/1988'); $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); - $resourceClassResolverProphecy->getResourceClass($dummy, null, true)->willReturn(Dummy::class)->shouldBeCalled(); - $resourceClassResolverProphecy->getResourceClass($dummy, Dummy::class, true)->willReturn(Dummy::class)->shouldBeCalled(); + $resourceClassResolverProphecy->getResourceClass($dummy, null, false)->willReturn(Dummy::class); + $resourceClassResolverProphecy->getResourceClass($dummy, Dummy::class, true)->willReturn(Dummy::class); $serializerProphecy = $this->prophesize(SerializerInterface::class); $serializerProphecy->willImplement(NormalizerInterface::class); - $serializerProphecy->normalize('hello', null, Argument::type('array'))->willReturn('hello')->shouldBeCalled(); + $serializerProphecy->normalize('hello', null, Argument::type('array'))->willReturn('hello'); $contextBuilderProphecy = $this->prophesize(ContextBuilderInterface::class); $contextBuilderProphecy->getResourceContextUri(Dummy::class)->willReturn('/contexts/Dummy'); @@ -131,7 +131,8 @@ public function testNormalize() ); $normalizer->setSerializer($serializerProphecy->reveal()); - $expected = ['@context' => '/contexts/Dummy', + $expected = [ + '@context' => '/contexts/Dummy', '@id' => '/dummies/1988', '@type' => 'Dummy', 'name' => 'hello', diff --git a/tests/Serializer/AbstractItemNormalizerTest.php b/tests/Serializer/AbstractItemNormalizerTest.php index f38d04bdd18..dd8b8f39473 100644 --- a/tests/Serializer/AbstractItemNormalizerTest.php +++ b/tests/Serializer/AbstractItemNormalizerTest.php @@ -130,56 +130,39 @@ public function testNormalize() $dummy->setRelatedDummy($relatedDummy); $dummy->relatedDummies->add(new RelatedDummy()); + $relatedDummies = new ArrayCollection([$relatedDummy]); + $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class); - $propertyNameCollectionFactoryProphecy->create(Dummy::class, [])->willReturn( - new PropertyNameCollection(['name', 'alias', 'relatedDummy', 'relatedDummies']) - )->shouldBeCalled(); + $propertyNameCollectionFactoryProphecy->create(Dummy::class, [])->willReturn(new PropertyNameCollection(['name', 'alias', 'relatedDummy', 'relatedDummies'])); + + $relatedDummyType = new Type(Type::BUILTIN_TYPE_OBJECT, false, RelatedDummy::class); + $relatedDummiesType = new Type(Type::BUILTIN_TYPE_OBJECT, false, ArrayCollection::class, true, new Type(Type::BUILTIN_TYPE_INT), $relatedDummyType); $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class); - $propertyMetadataFactoryProphecy->create(Dummy::class, 'name', [])->willReturn( - new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), '', true) - )->shouldBeCalled(); - $propertyMetadataFactoryProphecy->create(Dummy::class, 'alias', [])->willReturn( - new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), '', true) - )->shouldBeCalled(); - $propertyMetadataFactoryProphecy->create(Dummy::class, 'relatedDummy', [])->willReturn( - new PropertyMetadata(new Type(Type::BUILTIN_TYPE_OBJECT, false, RelatedDummy::class), '', true, false, false) - )->shouldBeCalled(); - $propertyMetadataFactoryProphecy->create(Dummy::class, 'relatedDummies', [])->willReturn( - new PropertyMetadata( - new Type(Type::BUILTIN_TYPE_OBJECT, - false, - ArrayCollection::class, - true, - new Type(Type::BUILTIN_TYPE_INT), - new Type(Type::BUILTIN_TYPE_OBJECT, false, RelatedDummy::class) - ), - '', - true, - false, - false - ) - )->shouldBeCalled(); + $propertyMetadataFactoryProphecy->create(Dummy::class, 'name', [])->willReturn(new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), '', true)); + $propertyMetadataFactoryProphecy->create(Dummy::class, 'alias', [])->willReturn(new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), '', true)); + $propertyMetadataFactoryProphecy->create(Dummy::class, 'relatedDummy', [])->willReturn(new PropertyMetadata($relatedDummyType, '', true, false, false)); + $propertyMetadataFactoryProphecy->create(Dummy::class, 'relatedDummies', [])->willReturn(new PropertyMetadata($relatedDummiesType, '', true, false, false)); $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); - $iriConverterProphecy->getIriFromItem($dummy)->willReturn('/dummies/1')->shouldBeCalled(); - $iriConverterProphecy->getIriFromItem($relatedDummy)->willReturn('/dummies/2')->shouldBeCalled(); + $iriConverterProphecy->getIriFromItem($dummy)->willReturn('/dummies/1'); + $iriConverterProphecy->getIriFromItem($relatedDummy)->willReturn('/dummies/2'); $propertyAccessorProphecy = $this->prophesize(PropertyAccessorInterface::class); - $propertyAccessorProphecy->getValue($dummy, 'name')->willReturn('foo')->shouldBeCalled(); - $propertyAccessorProphecy->getValue($dummy, 'relatedDummy')->willReturn($relatedDummy)->shouldBeCalled(); - $propertyAccessorProphecy->getValue($dummy, 'relatedDummies')->willReturn( - new ArrayCollection([$relatedDummy]) - )->shouldBeCalled(); + $propertyAccessorProphecy->getValue($dummy, 'name')->willReturn('foo'); + $propertyAccessorProphecy->getValue($dummy, 'relatedDummy')->willReturn($relatedDummy); + $propertyAccessorProphecy->getValue($dummy, 'relatedDummies')->willReturn($relatedDummies); $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); - $resourceClassResolverProphecy->getResourceClass($dummy, null, true)->willReturn(Dummy::class)->shouldBeCalled(); - $resourceClassResolverProphecy->isResourceClass(RelatedDummy::class)->willReturn(RelatedDummy::class)->shouldBeCalled(); + $resourceClassResolverProphecy->getResourceClass($dummy, null, false)->willReturn(Dummy::class); + $resourceClassResolverProphecy->getResourceClass($relatedDummy, RelatedDummy::class, true)->willReturn(RelatedDummy::class); + $resourceClassResolverProphecy->getResourceClass($relatedDummies, RelatedDummy::class)->willReturn(RelatedDummy::class); + $resourceClassResolverProphecy->isResourceClass(RelatedDummy::class)->willReturn(RelatedDummy::class); $serializerProphecy = $this->prophesize(SerializerInterface::class); $serializerProphecy->willImplement(NormalizerInterface::class); - $serializerProphecy->normalize('foo', null, Argument::type('array'))->willReturn('foo')->shouldBeCalled(); - $serializerProphecy->normalize(['/dummies/2'], null, Argument::type('array'))->willReturn(['/dummies/2'])->shouldBeCalled(); + $serializerProphecy->normalize('foo', null, Argument::type('array'))->willReturn('foo'); + $serializerProphecy->normalize(['/dummies/2'], null, Argument::type('array'))->willReturn(['/dummies/2']); $normalizer = $this->getMockForAbstractClass(AbstractItemNormalizer::class, [ $propertyNameCollectionFactoryProphecy->reveal(), @@ -202,11 +185,15 @@ public function testNormalize() $normalizer->setIgnoredAttributes(['alias']); } - $this->assertEquals([ + $expected = [ 'name' => 'foo', 'relatedDummy' => '/dummies/2', 'relatedDummies' => ['/dummies/2'], - ], $normalizer->normalize($dummy, null, ['resources' => [], 'ignored_attributes' => ['alias']])); + ]; + $this->assertEquals($expected, $normalizer->normalize($dummy, null, [ + 'resources' => [], + 'ignored_attributes' => ['alias'], + ])); } public function testNormalizeReadableLinks() @@ -217,48 +204,36 @@ public function testNormalizeReadableLinks() $dummy->setRelatedDummy($relatedDummy); $dummy->relatedDummies->add(new RelatedDummy()); + $relatedDummies = new ArrayCollection([$relatedDummy]); + $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class); - $propertyNameCollectionFactoryProphecy->create(Dummy::class, [])->willReturn( - new PropertyNameCollection(['relatedDummy', 'relatedDummies']) - )->shouldBeCalled(); + $propertyNameCollectionFactoryProphecy->create(Dummy::class, [])->willReturn(new PropertyNameCollection(['relatedDummy', 'relatedDummies'])); + + $relatedDummyType = new Type(Type::BUILTIN_TYPE_OBJECT, false, RelatedDummy::class); + $relatedDummiesType = new Type(Type::BUILTIN_TYPE_OBJECT, false, ArrayCollection::class, true, new Type(Type::BUILTIN_TYPE_INT), $relatedDummyType); $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class); - $propertyMetadataFactoryProphecy->create(Dummy::class, 'relatedDummy', [])->willReturn( - new PropertyMetadata(new Type(Type::BUILTIN_TYPE_OBJECT, false, RelatedDummy::class), '', true, false, true) - )->shouldBeCalled(); - $propertyMetadataFactoryProphecy->create(Dummy::class, 'relatedDummies', [])->willReturn( - new PropertyMetadata( - new Type( - Type::BUILTIN_TYPE_OBJECT, - false, - ArrayCollection::class, - true, - new Type(Type::BUILTIN_TYPE_INT), - new Type(Type::BUILTIN_TYPE_OBJECT, false, RelatedDummy::class) - ), - '', - true, - false, - true - ) - )->shouldBeCalled(); + $propertyMetadataFactoryProphecy->create(Dummy::class, 'relatedDummy', [])->willReturn(new PropertyMetadata($relatedDummyType, '', true, false, true)); + $propertyMetadataFactoryProphecy->create(Dummy::class, 'relatedDummies', [])->willReturn(new PropertyMetadata($relatedDummiesType, '', true, false, true)); $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); - $iriConverterProphecy->getIriFromItem($dummy)->willReturn('/dummies/1')->shouldBeCalled(); + $iriConverterProphecy->getIriFromItem($dummy)->willReturn('/dummies/1'); $propertyAccessorProphecy = $this->prophesize(PropertyAccessorInterface::class); - $propertyAccessorProphecy->getValue($dummy, 'relatedDummy')->willReturn($relatedDummy)->shouldBeCalled(); - $propertyAccessorProphecy->getValue($dummy, 'relatedDummies')->willReturn(new ArrayCollection([$relatedDummy]))->shouldBeCalled(); + $propertyAccessorProphecy->getValue($dummy, 'relatedDummy')->willReturn($relatedDummy); + $propertyAccessorProphecy->getValue($dummy, 'relatedDummies')->willReturn($relatedDummies); $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); - $resourceClassResolverProphecy->getResourceClass($dummy, null, true)->willReturn(Dummy::class)->shouldBeCalled(); - $resourceClassResolverProphecy->isResourceClass(RelatedDummy::class)->willReturn(RelatedDummy::class)->shouldBeCalled(); + $resourceClassResolverProphecy->getResourceClass($dummy, null, false)->willReturn(Dummy::class); + $resourceClassResolverProphecy->getResourceClass($relatedDummy, RelatedDummy::class, true)->willReturn(RelatedDummy::class); + $resourceClassResolverProphecy->getResourceClass($relatedDummies, RelatedDummy::class)->willReturn(RelatedDummy::class); + $resourceClassResolverProphecy->isResourceClass(RelatedDummy::class)->willReturn(RelatedDummy::class); $serializerProphecy = $this->prophesize(SerializerInterface::class); $serializerProphecy->willImplement(NormalizerInterface::class); - $serializerProphecy->normalize($relatedDummy, null, Argument::type('array'))->willReturn(['foo' => 'hello'])->shouldBeCalled(); - $serializerProphecy->normalize(['foo' => 'hello'], null, Argument::type('array'))->willReturn(['foo' => 'hello'])->shouldBeCalled(); - $serializerProphecy->normalize([['foo' => 'hello']], null, Argument::type('array'))->willReturn([['foo' => 'hello']])->shouldBeCalled(); + $serializerProphecy->normalize($relatedDummy, null, Argument::type('array'))->willReturn(['foo' => 'hello']); + $serializerProphecy->normalize(['foo' => 'hello'], null, Argument::type('array'))->willReturn(['foo' => 'hello']); + $serializerProphecy->normalize([['foo' => 'hello']], null, Argument::type('array'))->willReturn([['foo' => 'hello']]); $normalizer = $this->getMockForAbstractClass(AbstractItemNormalizer::class, [ $propertyNameCollectionFactoryProphecy->reveal(), @@ -277,10 +252,13 @@ public function testNormalizeReadableLinks() ]); $normalizer->setSerializer($serializerProphecy->reveal()); - $this->assertEquals([ + $expected = [ 'relatedDummy' => ['foo' => 'hello'], 'relatedDummies' => [['foo' => 'hello']], - ], $normalizer->normalize($dummy, null, ['resources' => []])); + ]; + $this->assertEquals($expected, $normalizer->normalize($dummy, null, [ + 'resources' => [], + ])); } public function testDenormalize() @@ -1037,35 +1015,25 @@ public function testDoNotDenormalizeRelationWithPlainIdWhenPlainIdentifiersAreNo public function testNormalizationWithDataTransformer() { $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class); - $propertyNameCollectionFactoryProphecy->create(InputDto::class, Argument::any())->willReturn( - new PropertyNameCollection() - )->shouldBeCalled(); - $propertyNameCollectionFactoryProphecy->create(Dummy::class, Argument::any())->willReturn( - new PropertyNameCollection(['name']) - )->shouldBeCalled(); + // $propertyNameCollectionFactoryProphecy->create(InputDto::class, Argument::any())->willReturn(new PropertyNameCollection()); + $propertyNameCollectionFactoryProphecy->create(Dummy::class, Argument::any())->willReturn(new PropertyNameCollection(['name'])); $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class); - $propertyMetadataFactoryProphecy->create(Dummy::class, 'name', Argument::any())->willReturn( - new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), '', false, true) - )->shouldBeCalled(); + $propertyMetadataFactoryProphecy->create(Dummy::class, 'name', Argument::any())->willReturn(new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), '', false, true)); $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); + $propertyAccessorProphecy = $this->prophesize(PropertyAccessorInterface::class); - $propertyAccessorProphecy->setValue(Argument::type(Dummy::class), 'name', 'Dummy')->shouldBeCalled(); + $propertyAccessorProphecy->setValue(Argument::type(Dummy::class), 'name', 'Dummy'); $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); - $serializerProphecy = $this->prophesize(SerializerInterface::class); - $serializerProphecy->willImplement(DenormalizerInterface::class); - $itemDataProviderProphecy = $this->prophesize(ItemDataProviderInterface::class); - $resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class); - $resourceMetadataFactoryProphecy->create(Dummy::class)->willReturn(new ResourceMetadata( - 'dummy', '', '', null, null, ['input' => ['class' => InputDto::class]] - )); - - $jsonInput = ['foo' => 'f', 'bar' => 'b']; + $jsonInput = ['foo' => 'f', 'bar' => 8]; + $inputDto = new InputDto(); + $inputDto->foo = 'f'; + $inputDto->bar = 8; $transformed = new Dummy(); - $requestContext = [ + $context = [ 'operation_type' => 'collection', 'collection_operation_name' => 'post', 'resource_class' => Dummy::class, @@ -1076,21 +1044,32 @@ public function testNormalizationWithDataTransformer() 'output' => ['class' => 'null'], 'api_denormalize' => true, // this is added by the normalizer ]; + $cleanedContext = array_diff_key($context, [ + 'input' => null, + 'resource_class' => null, + ]); $secondJsonInput = ['name' => 'Dummy']; $secondContext = ['api_denormalize' => true, 'resource_class' => Dummy::class]; $secondTransformed = new Dummy(); $secondTransformed->setName('Dummy'); + $serializerProphecy = $this->prophesize(SerializerInterface::class); + $serializerProphecy->willImplement(DenormalizerInterface::class); + $serializerProphecy->denormalize($jsonInput, InputDto::class, 'jsonld', $cleanedContext)->willReturn($inputDto); + + $itemDataProviderProphecy = $this->prophesize(ItemDataProviderInterface::class); + + $resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class); + $resourceMetadataFactoryProphecy->create(Dummy::class)->willReturn(new ResourceMetadata('dummy', '', '', null, null, ['input' => ['class' => InputDto::class]])); + $dataTransformerProphecy = $this->prophesize(DataTransformerInterface::class); - $dataTransformerProphecy->supportsTransformation($jsonInput, Dummy::class, $requestContext)->shouldBeCalled()->willReturn(true); - $dataTransformerProphecy->supportsTransformation($secondJsonInput, Dummy::class, $secondContext)->shouldBeCalled()->willReturn(false); - $dataTransformerProphecy->transform(Argument::that(function ($arg) { - return $arg instanceof InputDto; - }), Dummy::class, $requestContext)->shouldBeCalled()->willReturn($transformed); + $dataTransformerProphecy->supportsTransformation($jsonInput, Dummy::class, $context)->willReturn(true); + $dataTransformerProphecy->supportsTransformation($secondJsonInput, Dummy::class, $secondContext)->willReturn(false); + $dataTransformerProphecy->transform($inputDto, Dummy::class, $context)->willReturn($transformed); $secondDataTransformerProphecy = $this->prophesize(DataTransformerInterface::class); - $secondDataTransformerProphecy->supportsTransformation(Argument::any(), Dummy::class, Argument::any())->shouldBeCalled()->willReturn(false); + $secondDataTransformerProphecy->supportsTransformation(Argument::any(), Dummy::class, Argument::any())->willReturn(false); $normalizer = $this->getMockForAbstractClass(AbstractItemNormalizer::class, [ $propertyNameCollectionFactoryProphecy->reveal(), @@ -1110,7 +1089,7 @@ public function testNormalizationWithDataTransformer() $normalizer->setSerializer($serializerProphecy->reveal()); // This is step 1-3, {InputDto} to Dummy - $this->assertEquals($transformed, $normalizer->denormalize($jsonInput, Dummy::class, 'jsonld', $requestContext)); + $this->assertEquals($transformed, $normalizer->denormalize($jsonInput, Dummy::class, 'jsonld', $context)); // Messenger sends {InputDto} $this->assertInstanceOf(Dummy::class, $normalizer->denormalize($secondJsonInput, Dummy::class, 'jsonld')); } diff --git a/tests/Serializer/ItemNormalizerTest.php b/tests/Serializer/ItemNormalizerTest.php index 9aa8b4e3efe..a65cd8fdcf0 100644 --- a/tests/Serializer/ItemNormalizerTest.php +++ b/tests/Serializer/ItemNormalizerTest.php @@ -50,8 +50,8 @@ public function testSupportNormalization() $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); - $resourceClassResolverProphecy->isResourceClass(Dummy::class)->willReturn(true)->shouldBeCalled(); - $resourceClassResolverProphecy->isResourceClass(\stdClass::class)->willReturn(false)->shouldBeCalled(); + $resourceClassResolverProphecy->isResourceClass(Dummy::class)->willReturn(true); + $resourceClassResolverProphecy->isResourceClass(\stdClass::class)->willReturn(false); $normalizer = new ItemNormalizer( $propertyNameCollectionFactoryProphecy->reveal(), @@ -77,21 +77,21 @@ public function testNormalize() $propertyNameCollection = new PropertyNameCollection(['name']); $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class); - $propertyNameCollectionFactoryProphecy->create(Dummy::class, [])->willReturn($propertyNameCollection)->shouldBeCalled(); + $propertyNameCollectionFactoryProphecy->create(Dummy::class, [])->willReturn($propertyNameCollection); $propertyMetadata = new PropertyMetadata(null, null, true); $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class); - $propertyMetadataFactoryProphecy->create(Dummy::class, 'name', [])->willReturn($propertyMetadata)->shouldBeCalled(); + $propertyMetadataFactoryProphecy->create(Dummy::class, 'name', [])->willReturn($propertyMetadata); $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); - $iriConverterProphecy->getIriFromItem($dummy)->willReturn('/dummies/1')->shouldBeCalled(); + $iriConverterProphecy->getIriFromItem($dummy)->willReturn('/dummies/1'); $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); - $resourceClassResolverProphecy->getResourceClass($dummy, null, true)->willReturn(Dummy::class)->shouldBeCalled(); + $resourceClassResolverProphecy->getResourceClass($dummy, null, false)->willReturn(Dummy::class); $serializerProphecy = $this->prophesize(SerializerInterface::class); $serializerProphecy->willImplement(NormalizerInterface::class); - $serializerProphecy->normalize('hello', null, Argument::type('array'))->willReturn('hello')->shouldBeCalled(); + $serializerProphecy->normalize('hello', null, Argument::type('array'))->willReturn('hello'); $normalizer = new ItemNormalizer( $propertyNameCollectionFactoryProphecy->reveal(),