From ffb3d0f0d1bd43f09e84bb716a84fb416d077111 Mon Sep 17 00:00:00 2001 From: christian Date: Tue, 10 Oct 2017 16:42:57 +0700 Subject: [PATCH 01/11] Use object_to_populate constant in normalizers --- src/EventListener/DeserializeListener.php | 3 ++- src/JsonLd/Serializer/ItemNormalizer.php | 4 ++-- src/Serializer/ItemNormalizer.php | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/EventListener/DeserializeListener.php b/src/EventListener/DeserializeListener.php index 563a27b5540..c9e92bb6ee1 100644 --- a/src/EventListener/DeserializeListener.php +++ b/src/EventListener/DeserializeListener.php @@ -18,6 +18,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\Exception\NotAcceptableHttpException; +use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; use Symfony\Component\Serializer\SerializerInterface; /** @@ -61,7 +62,7 @@ public function onKernelRequest(GetResponseEvent $event) $data = $request->attributes->get('data'); if (null !== $data) { - $context['object_to_populate'] = $data; + $context[AbstractNormalizer::OBJECT_TO_POPULATE] = $data; } $request->attributes->set( diff --git a/src/JsonLd/Serializer/ItemNormalizer.php b/src/JsonLd/Serializer/ItemNormalizer.php index c096ae27faa..41548e95b66 100644 --- a/src/JsonLd/Serializer/ItemNormalizer.php +++ b/src/JsonLd/Serializer/ItemNormalizer.php @@ -97,12 +97,12 @@ public function supportsDenormalization($data, $type, $format = null) public function denormalize($data, $class, $format = null, array $context = []) { // Avoid issues with proxies if we populated the object - if (isset($data['@id']) && !isset($context['object_to_populate'])) { + if (isset($data['@id']) && !isset($context[self::OBJECT_TO_POPULATE])) { if (isset($context['api_allow_update']) && true !== $context['api_allow_update']) { throw new InvalidArgumentException('Update is not allowed for this operation.'); } - $context['object_to_populate'] = $this->iriConverter->getItemFromIri($data['@id'], $context + ['fetch_data' => true]); + $context[self::OBJECT_TO_POPULATE] = $this->iriConverter->getItemFromIri($data['@id'], $context + ['fetch_data' => true]); } return parent::denormalize($data, $class, $format, $context); diff --git a/src/Serializer/ItemNormalizer.php b/src/Serializer/ItemNormalizer.php index b0ea4b8b56f..fe4b2a5b257 100644 --- a/src/Serializer/ItemNormalizer.php +++ b/src/Serializer/ItemNormalizer.php @@ -30,7 +30,7 @@ final class ItemNormalizer extends AbstractItemNormalizer public function denormalize($data, $class, $format = null, array $context = []) { // Avoid issues with proxies if we populated the object - if (isset($data['id']) && !isset($context['object_to_populate'])) { + if (isset($data['id']) && !isset($context[self::OBJECT_TO_POPULATE])) { if (isset($context['api_allow_update']) && true !== $context['api_allow_update']) { throw new InvalidArgumentException('Update is not allowed for this operation.'); } @@ -44,7 +44,7 @@ public function denormalize($data, $class, $format = null, array $context = []) private function updateObjectToPopulate(array $data, array &$context) { try { - $context['object_to_populate'] = $this->iriConverter->getItemFromIri((string) $data['id'], $context + ['fetch_data' => true]); + $context[self::OBJECT_TO_POPULATE] = $this->iriConverter->getItemFromIri((string) $data['id'], $context + ['fetch_data' => true]); } catch (InvalidArgumentException $e) { $identifier = null; foreach ($this->propertyNameCollectionFactory->create($context['resource_class'], $context) as $propertyName) { @@ -58,7 +58,7 @@ private function updateObjectToPopulate(array $data, array &$context) throw $e; } - $context['object_to_populate'] = $this->iriConverter->getItemFromIri(sprintf('%s/%s', $this->iriConverter->getIriFromResourceClass($context['resource_class']), $data[$identifier]), $context + ['fetch_data' => true]); + $context[self::OBJECT_TO_POPULATE] = $this->iriConverter->getItemFromIri(sprintf('%s/%s', $this->iriConverter->getIriFromResourceClass($context['resource_class']), $data[$identifier]), $context + ['fetch_data' => true]); } } } From 2d32ef9d784cd374827ec4caa9c7e701de76a89f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 24 Oct 2017 14:56:24 +0200 Subject: [PATCH 02/11] Don't use dynamic values in service keys --- .../ApiPlatformExtension.php | 13 ++++------ .../ApiPlatformExtensionTest.php | 24 +++++-------------- 2 files changed, 11 insertions(+), 26 deletions(-) diff --git a/src/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php b/src/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php index 12c3faae7e0..264a9109351 100644 --- a/src/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php +++ b/src/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php @@ -28,7 +28,6 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; -use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\Finder\Finder; use Symfony\Component\HttpKernel\DependencyInjection\Extension; use Symfony\Component\Validator\Validator\ValidatorInterface; @@ -426,17 +425,15 @@ private function registerHttpCache(ContainerBuilder $container, array $config, X $loader->load('http_cache_tags.xml'); - $references = []; - foreach ($config['http_cache']['invalidation']['varnish_urls'] as $url) { - $id = sprintf('api_platform.http_cache.purger.varnish_client.%s', $url); - $references[] = new Reference($id); - + $definitions = []; + foreach ($config['http_cache']['invalidation']['varnish_urls'] as $key => $url) { $definition = new ChildDefinition('api_platform.http_cache.purger.varnish_client'); $definition->addArgument(['base_uri' => $url]); - $container->setDefinition($id, $definition); + + $definitions[] = $definition; } - $container->getDefinition('api_platform.http_cache.purger.varnish')->addArgument($references); + $container->getDefinition('api_platform.http_cache.purger.varnish')->addArgument($definitions); $container->setAlias('api_platform.http_cache.purger', 'api_platform.http_cache.purger.varnish'); } diff --git a/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php b/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php index a2053950fb5..133a5a69565 100644 --- a/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php +++ b/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php @@ -157,7 +157,7 @@ public function testNotPrependWhenNameConverterIsNotConfigured() public function testLoadDefaultConfig() { - $containerBuilderProphecy = $this->getDefaultContainerBuilderProphecy(); + $containerBuilderProphecy = $this->getBaseContainerBuilderProphecy(); $containerBuilder = $containerBuilderProphecy->reveal(); $this->extension->load(self::DEFAULT_CONFIG, $containerBuilder); @@ -167,7 +167,7 @@ public function testSetNameConverter() { $nameConverterId = 'test.name_converter'; - $containerBuilderProphecy = $this->getDefaultContainerBuilderProphecy(); + $containerBuilderProphecy = $this->getBaseContainerBuilderProphecy(); $containerBuilderProphecy->setAlias('api_platform.name_converter', $nameConverterId)->shouldBeCalled(); $containerBuilder = $containerBuilderProphecy->reveal(); @@ -176,7 +176,7 @@ public function testSetNameConverter() public function testEnableFosUser() { - $containerBuilderProphecy = $this->getDefaultContainerBuilderProphecy(); + $containerBuilderProphecy = $this->getBaseContainerBuilderProphecy(); $containerBuilderProphecy->getParameter('kernel.bundles')->willReturn([ 'DoctrineBundle' => DoctrineBundle::class, 'FOSUserBundle' => FOSUserBundle::class, @@ -208,7 +208,7 @@ public function testFosUserPriority() public function testEnableNelmioApiDoc() { - $containerBuilderProphecy = $this->getDefaultContainerBuilderProphecy(); + $containerBuilderProphecy = $this->getBaseContainerBuilderProphecy(); $containerBuilderProphecy->getParameter('kernel.bundles')->willReturn([ 'DoctrineBundle' => DoctrineBundle::class, 'NelmioApiDocBundle' => NelmioApiDocBundle::class, @@ -222,7 +222,7 @@ public function testEnableNelmioApiDoc() public function testEnableSecurity() { - $containerBuilderProphecy = $this->getDefaultContainerBuilderProphecy(); + $containerBuilderProphecy = $this->getBaseContainerBuilderProphecy(); $containerBuilderProphecy->getParameter('kernel.bundles')->willReturn([ 'DoctrineBundle' => DoctrineBundle::class, 'SecurityBundle' => SecurityBundle::class, @@ -260,7 +260,7 @@ public function testResourcesToWatchWithNonExistentFile() public function testDisableEagerLoadingExtension() { - $containerBuilderProphecy = $this->getDefaultContainerBuilderProphecy(); + $containerBuilderProphecy = $this->getBaseContainerBuilderProphecy(); $containerBuilderProphecy->setParameter('api_platform.eager_loading.enabled', false)->shouldBeCalled(); $containerBuilderProphecy->removeDefinition('api_platform.doctrine.orm.query_extension.eager_loading')->shouldBeCalled(); $containerBuilderProphecy->removeDefinition('api_platform.doctrine.orm.query_extension.filter_eager_loading')->shouldBeCalled(); @@ -572,16 +572,4 @@ private function getBaseContainerBuilderProphecy() return $containerBuilderProphecy; } - - private function getDefaultContainerBuilderProphecy() - { - $containerBuilderProphecy = $this->getBaseContainerBuilderProphecy(); - - $containerBuilderProphecy - ->setDefinition('api_platform.http_cache.purger.varnish_client.test', Argument::type(Definition::class)) - ->shouldBeCalled() - ; - - return $containerBuilderProphecy; - } } From 7fc53b93c65a417d846f047cdd15346a7681e94a Mon Sep 17 00:00:00 2001 From: soyuka Date: Fri, 13 Oct 2017 22:02:05 +0200 Subject: [PATCH 03/11] Use serializer AbstractItemNormalizer constants when related --- .../Orm/Extension/EagerLoadingExtension.php | 12 ++++---- .../NelmioApiDoc/Parser/ApiPlatformParser.php | 21 +++++++------- .../Serializer/DocumentationNormalizer.php | 11 +++---- src/Serializer/AbstractItemNormalizer.php | 4 +-- src/Serializer/Filter/GroupFilter.php | 7 +++-- src/Serializer/Filter/PropertyFilter.php | 7 +++-- .../Serializer/DocumentationNormalizer.php | 5 ++-- .../Extension/EagerLoadingExtensionTest.php | 7 +++-- .../Parser/ApiPlatformParserTest.php | 11 +++---- .../EventListener/DeserializeListenerTest.php | 3 +- .../SerializerPropertyMetadataFactoryTest.php | 5 ++-- ...leConfigurationMetadataFactoryProvider.php | 5 ++-- tests/Serializer/Filter/GroupFilterTest.php | 29 ++++++++++--------- .../DocumentationNormalizerTest.php | 9 +++--- 14 files changed, 75 insertions(+), 61 deletions(-) diff --git a/src/Bridge/Doctrine/Orm/Extension/EagerLoadingExtension.php b/src/Bridge/Doctrine/Orm/Extension/EagerLoadingExtension.php index 3cad4436831..d7aa1819269 100644 --- a/src/Bridge/Doctrine/Orm/Extension/EagerLoadingExtension.php +++ b/src/Bridge/Doctrine/Orm/Extension/EagerLoadingExtension.php @@ -26,6 +26,8 @@ use Doctrine\ORM\QueryBuilder; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface; +use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; +use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer; /** * Eager loads relations. @@ -99,8 +101,8 @@ public function applyToItem(QueryBuilder $queryBuilder, QueryNameGeneratorInterf $contextType = isset($context['api_denormalize']) ? 'denormalization_context' : 'normalization_context'; $serializerContext = $this->getSerializerContext($context['resource_class'] ?? $resourceClass, $contextType, $options); - if (isset($context['groups'])) { - $groups = ['serializer_groups' => $context['groups']]; + if (isset($context[AbstractNormalizer::GROUPS])) { + $groups = ['serializer_groups' => $context[AbstractNormalizer::GROUPS]]; } else { $groups = $this->getSerializerGroups($options, $serializerContext); } @@ -137,7 +139,7 @@ private function joinRelations(QueryBuilder $queryBuilder, QueryNameGeneratorInt foreach ($classMetadata->associationMappings as $association => $mapping) { //Don't join if max depth is enabled and the current depth limit is reached - if (isset($context['enable_max_depth']) && 0 === $currentDepth) { + if (isset($context[AbstractObjectNormalizer::ENABLE_MAX_DEPTH]) && 0 === $currentDepth) { continue; } @@ -280,10 +282,10 @@ private function getSerializerContext(string $resourceClass, string $contextType */ private function getSerializerGroups(array $options, array $context): array { - if (empty($context['groups'])) { + if (empty($context[AbstractNormalizer::GROUPS])) { return $options; } - return ['serializer_groups' => $context['groups']]; + return ['serializer_groups' => $context[AbstractNormalizer::GROUPS]]; } } diff --git a/src/Bridge/NelmioApiDoc/Parser/ApiPlatformParser.php b/src/Bridge/NelmioApiDoc/Parser/ApiPlatformParser.php index 628c8c0b960..cd2db88a7f0 100644 --- a/src/Bridge/NelmioApiDoc/Parser/ApiPlatformParser.php +++ b/src/Bridge/NelmioApiDoc/Parser/ApiPlatformParser.php @@ -23,6 +23,7 @@ use Nelmio\ApiDocBundle\Parser\ParserInterface; use Symfony\Component\PropertyInfo\Type; use Symfony\Component\Serializer\NameConverter\NameConverterInterface; +use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; /** * Extract input and output information for the NelmioApiDocBundle. @@ -113,15 +114,15 @@ private function parseResource(ResourceMetadata $resourceMetadata, string $resou $options = []; $attributes = $resourceMetadata->getAttributes(); - if (isset($attributes['normalization_context']['groups'])) { - $options['serializer_groups'] = $attributes['normalization_context']['groups']; + if (isset($attributes['normalization_context'][AbstractNormalizer::GROUPS])) { + $options['serializer_groups'] = $attributes['normalization_context'][AbstractNormalizer::GROUPS]; } - if (isset($attributes['denormalization_context']['groups'])) { + if (isset($attributes['denormalization_context'][AbstractNormalizer::GROUPS])) { if (isset($options['serializer_groups'])) { - $options['serializer_groups'] += $attributes['denormalization_context']['groups']; + $options['serializer_groups'] += $attributes['denormalization_context'][AbstractNormalizer::GROUPS]; } else { - $options['serializer_groups'] = $attributes['denormalization_context']['groups']; + $options['serializer_groups'] = $attributes['denormalization_context'][AbstractNormalizer::GROUPS]; } } @@ -131,12 +132,12 @@ private function parseResource(ResourceMetadata $resourceMetadata, string $resou private function getGroupsContext(ResourceMetadata $resourceMetadata, string $operationName, bool $isNormalization) { $groupsContext = $isNormalization ? 'normalization_context' : 'denormalization_context'; - $itemOperationAttribute = $resourceMetadata->getItemOperationAttribute($operationName, $groupsContext, ['groups' => []], true)['groups']; - $collectionOperationAttribute = $resourceMetadata->getCollectionOperationAttribute($operationName, $groupsContext, ['groups' => []], true)['groups']; + $itemOperationAttribute = $resourceMetadata->getItemOperationAttribute($operationName, $groupsContext, [AbstractNormalizer::GROUPS => []], true)[AbstractNormalizer::GROUPS]; + $collectionOperationAttribute = $resourceMetadata->getCollectionOperationAttribute($operationName, $groupsContext, [AbstractNormalizer::GROUPS => []], true)[AbstractNormalizer::GROUPS]; return [ $groupsContext => [ - 'groups' => array_merge($itemOperationAttribute ?? [], $collectionOperationAttribute ?? []), + AbstractNormalizer::GROUPS => array_merge($itemOperationAttribute ?? [], $collectionOperationAttribute ?? []), ], ]; } @@ -157,13 +158,13 @@ private function getGroupsForItemAndCollectionOperation(ResourceMetadata $resour if (self::OUT_PREFIX === $io) { return [ - 'serializer_groups' => !empty($operation['normalization_context']) ? $operation['normalization_context']['groups'] : [], + 'serializer_groups' => !empty($operation['normalization_context']) ? $operation['normalization_context'][AbstractNormalizer::GROUPS] : [], ]; } if (self::IN_PREFIX === $io) { return [ - 'serializer_groups' => !empty($operation['denormalization_context']) ? $operation['denormalization_context']['groups'] : [], + 'serializer_groups' => !empty($operation['denormalization_context']) ? $operation['denormalization_context'][AbstractNormalizer::GROUPS] : [], ]; } diff --git a/src/Hydra/Serializer/DocumentationNormalizer.php b/src/Hydra/Serializer/DocumentationNormalizer.php index dbce911dadc..9c9f89d0786 100644 --- a/src/Hydra/Serializer/DocumentationNormalizer.php +++ b/src/Hydra/Serializer/DocumentationNormalizer.php @@ -26,6 +26,7 @@ use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface; use ApiPlatform\Core\Metadata\Resource\ResourceMetadata; use Symfony\Component\PropertyInfo\Type; +use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; /** @@ -154,17 +155,17 @@ private function getPropertyNameCollectionFactoryContext(ResourceMetadata $resou $attributes = $resourceMetadata->getAttributes(); $context = []; - if (isset($attributes['normalization_context']['groups'])) { - $context['serializer_groups'] = $attributes['normalization_context']['groups']; + if (isset($attributes['normalization_context'][AbstractNormalizer::GROUPS])) { + $context['serializer_groups'] = $attributes['normalization_context'][AbstractNormalizer::GROUPS]; } - if (isset($attributes['denormalization_context']['groups'])) { + if (isset($attributes['denormalization_context'][AbstractNormalizer::GROUPS])) { if (isset($context['serializer_groups'])) { - foreach ($attributes['denormalization_context']['groups'] as $groupName) { + foreach ($attributes['denormalization_context'][AbstractNormalizer::GROUPS] as $groupName) { $context['serializer_groups'][] = $groupName; } } else { - $context['serializer_groups'] = $attributes['denormalization_context']['groups']; + $context['serializer_groups'] = $attributes['denormalization_context'][AbstractNormalizer::GROUPS]; } } diff --git a/src/Serializer/AbstractItemNormalizer.php b/src/Serializer/AbstractItemNormalizer.php index 90ea14edf03..57d88b01424 100644 --- a/src/Serializer/AbstractItemNormalizer.php +++ b/src/Serializer/AbstractItemNormalizer.php @@ -336,8 +336,8 @@ protected function getFactoryOptions(array $context): array { $options = []; - if (isset($context['groups'])) { - $options['serializer_groups'] = $context['groups']; + if (isset($context[self::GROUPS])) { + $options['serializer_groups'] = $context[self::GROUPS]; } if (isset($context['collection_operation_name'])) { diff --git a/src/Serializer/Filter/GroupFilter.php b/src/Serializer/Filter/GroupFilter.php index 8d77b1448ca..c03382aa1b5 100644 --- a/src/Serializer/Filter/GroupFilter.php +++ b/src/Serializer/Filter/GroupFilter.php @@ -14,6 +14,7 @@ namespace ApiPlatform\Core\Serializer\Filter; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; /** * Group filter. @@ -44,11 +45,11 @@ public function apply(Request $request, bool $normalization, array $attributes, if (null !== $this->whitelist) { $groups = array_intersect($this->whitelist, $groups); } - if (!$this->overrideDefaultGroups && isset($context['groups'])) { - $groups = array_merge((array) $context['groups'], $groups); + if (!$this->overrideDefaultGroups && isset($context[AbstractNormalizer::GROUPS])) { + $groups = array_merge((array) $context[AbstractNormalizer::GROUPS], $groups); } - $context['groups'] = $groups; + $context[AbstractNormalizer::GROUPS] = $groups; } /** diff --git a/src/Serializer/Filter/PropertyFilter.php b/src/Serializer/Filter/PropertyFilter.php index 49ba01d73ca..9c7359e7c2b 100644 --- a/src/Serializer/Filter/PropertyFilter.php +++ b/src/Serializer/Filter/PropertyFilter.php @@ -14,6 +14,7 @@ namespace ApiPlatform\Core\Serializer\Filter; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; /** * Property filter. @@ -46,11 +47,11 @@ public function apply(Request $request, bool $normalization, array $attributes, $properties = $this->getProperties($properties, $this->whitelist); } - if (!$this->overrideDefaultProperties && isset($context['attributes'])) { - $properties = array_merge_recursive((array) $context['attributes'], $properties); + if (!$this->overrideDefaultProperties && isset($context[AbstractNormalizer::ATTRIBUTES])) { + $properties = array_merge_recursive((array) $context[AbstractNormalizer::ATTRIBUTES], $properties); } - $context['attributes'] = $properties; + $context[AbstractNormalizer::ATTRIBUTES] = $properties; } /** diff --git a/src/Swagger/Serializer/DocumentationNormalizer.php b/src/Swagger/Serializer/DocumentationNormalizer.php index b69c0cd5983..9a701d90e8b 100644 --- a/src/Swagger/Serializer/DocumentationNormalizer.php +++ b/src/Swagger/Serializer/DocumentationNormalizer.php @@ -30,6 +30,7 @@ use Psr\Container\ContainerInterface; use Symfony\Component\PropertyInfo\Type; use Symfony\Component\Serializer\NameConverter\NameConverterInterface; +use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; /** @@ -441,7 +442,7 @@ private function updateDeleteOperation(\ArrayObject $pathOperation, string $reso */ private function getDefinition(\ArrayObject $definitions, ResourceMetadata $resourceMetadata, string $resourceClass, array $serializerContext = null): string { - $definitionKey = $this->getDefinitionKey($resourceMetadata->getShortName(), (array) ($serializerContext['groups'] ?? [])); + $definitionKey = $this->getDefinitionKey($resourceMetadata->getShortName(), (array) ($serializerContext[AbstractNormalizer::GROUPS] ?? [])); if (!isset($definitions[$definitionKey])) { $definitions[$definitionKey] = []; // Initialize first to prevent infinite loop @@ -480,7 +481,7 @@ private function getDefinitionSchema(string $resourceClass, ResourceMetadata $re $definitionSchema['externalDocs'] = ['url' => $iri]; } - $options = isset($serializerContext['groups']) ? ['serializer_groups' => $serializerContext['groups']] : []; + $options = isset($serializerContext[AbstractNormalizer::GROUPS]) ? ['serializer_groups' => $serializerContext[AbstractNormalizer::GROUPS]] : []; foreach ($this->propertyNameCollectionFactory->create($resourceClass, $options) as $propertyName) { $propertyMetadata = $this->propertyMetadataFactory->create($resourceClass, $propertyName); $normalizedPropertyName = $this->nameConverter ? $this->nameConverter->normalize($propertyName) : $propertyName; diff --git a/tests/Bridge/Doctrine/Orm/Extension/EagerLoadingExtensionTest.php b/tests/Bridge/Doctrine/Orm/Extension/EagerLoadingExtensionTest.php index 29fd42ba5ac..c326621ecf2 100644 --- a/tests/Bridge/Doctrine/Orm/Extension/EagerLoadingExtensionTest.php +++ b/tests/Bridge/Doctrine/Orm/Extension/EagerLoadingExtensionTest.php @@ -40,6 +40,7 @@ use Symfony\Component\Serializer\Mapping\AttributeMetadata; use Symfony\Component\Serializer\Mapping\ClassMetadataInterface; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface; +use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; /** * @author Amrouche Hamza @@ -315,7 +316,7 @@ public function testDenormalizeItemWithExistingGroups() $queryBuilderProphecy->getEntityManager()->willReturn($emProphecy); $eagerExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false, null, null, true); - $eagerExtensionTest->applyToItem($queryBuilderProphecy->reveal(), new QueryNameGenerator(), RelatedDummy::class, ['id' => 1], 'item_operation', ['groups' => 'some_groups']); + $eagerExtensionTest->applyToItem($queryBuilderProphecy->reveal(), new QueryNameGenerator(), RelatedDummy::class, ['id' => 1], 'item_operation', [AbstractNormalizer::GROUPS => 'some_groups']); } /** @@ -442,7 +443,7 @@ public function testMaxDepth() public function testForceEager() { $resourceMetadata = new ResourceMetadata(); - $resourceMetadata = $resourceMetadata->withAttributes(['normalization_context' => ['groups' => 'foobar']]); + $resourceMetadata = $resourceMetadata->withAttributes(['normalization_context' => [AbstractNormalizer::GROUPS => 'foobar']]); $resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class); $resourceMetadataFactoryProphecy->create(Dummy::class)->willReturn($resourceMetadata); @@ -617,7 +618,7 @@ public function testApplyToCollectionWithSerializerContextBuilder() $requestStack->push($request); $serializerContextBuilderProphecy = $this->prophesize(SerializerContextBuilderInterface::class); - $serializerContextBuilderProphecy->createFromRequest($request, true)->shouldBeCalled()->willReturn(['groups' => ['foo']]); + $serializerContextBuilderProphecy->createFromRequest($request, true)->shouldBeCalled()->willReturn([AbstractNormalizer::GROUPS => ['foo']]); $queryBuilder = $queryBuilderProphecy->reveal(); $eagerExtensionTest = new EagerLoadingExtension($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), 30, false, $requestStack, $serializerContextBuilderProphecy->reveal(), true); diff --git a/tests/Bridge/NelmioApiDoc/Parser/ApiPlatformParserTest.php b/tests/Bridge/NelmioApiDoc/Parser/ApiPlatformParserTest.php index 9a2553c0446..0feca0baae3 100644 --- a/tests/Bridge/NelmioApiDoc/Parser/ApiPlatformParserTest.php +++ b/tests/Bridge/NelmioApiDoc/Parser/ApiPlatformParserTest.php @@ -30,6 +30,7 @@ use Prophecy\Argument; use Symfony\Component\PropertyInfo\Type; use Symfony\Component\Serializer\NameConverter\NameConverterInterface; +use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; /** * @author Teoh Han Hui @@ -94,8 +95,8 @@ public function testSupportsAttributeNormalization() { $resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class); $resourceMetadataFactoryProphecy->create('Acme\CustomAttributeDummy')->willReturn(new ResourceMetadata('dummy', 'dummy', null, [ - 'get' => ['method' => 'GET', 'normalization_context' => ['groups' => ['custom_attr_dummy_get']]], - 'put' => ['method' => 'PUT', 'denormalization_context' => ['groups' => ['custom_attr_dummy_put']]], + 'get' => ['method' => 'GET', 'normalization_context' => [AbstractNormalizer::GROUPS => ['custom_attr_dummy_get']]], + 'put' => ['method' => 'PUT', 'denormalization_context' => [AbstractNormalizer::GROUPS => ['custom_attr_dummy_put']]], 'delete' => ['method' => 'DELETE'], ], []))->shouldBeCalled(); $resourceMetadataFactory = $resourceMetadataFactoryProphecy->reveal(); @@ -189,9 +190,9 @@ public function testParse() { $resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class); $resourceMetadataFactoryProphecy->create(Dummy::class)->willReturn(new ResourceMetadata('dummy', 'dummy', null, [ - 'get' => ['method' => 'GET', 'normalization_context' => ['groups' => ['custom_attr_dummy_get']]], - 'put' => ['method' => 'PUT', 'denormalization_context' => ['groups' => ['custom_attr_dummy_put']]], - 'gerard' => ['method' => 'get', 'path' => '/gerard', 'denormalization_context' => ['groups' => ['custom_attr_dummy_put']]], + 'get' => ['method' => 'GET', 'normalization_context' => [AbstractNormalizer::GROUPS => ['custom_attr_dummy_get']]], + 'put' => ['method' => 'PUT', 'denormalization_context' => [AbstractNormalizer::GROUPS => ['custom_attr_dummy_put']]], + 'gerard' => ['method' => 'get', 'path' => '/gerard', 'denormalization_context' => [AbstractNormalizer::GROUPS => ['custom_attr_dummy_put']]], 'delete' => ['method' => 'DELETE'], ], []))->shouldBeCalled(); $resourceMetadataFactory = $resourceMetadataFactoryProphecy->reveal(); diff --git a/tests/EventListener/DeserializeListenerTest.php b/tests/EventListener/DeserializeListenerTest.php index c3d4d357cad..670ed8c1cb3 100644 --- a/tests/EventListener/DeserializeListenerTest.php +++ b/tests/EventListener/DeserializeListenerTest.php @@ -19,6 +19,7 @@ use Prophecy\Argument; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; use Symfony\Component\Serializer\SerializerInterface; /** @@ -115,7 +116,7 @@ public function testDeserialize(string $method, bool $populateObject) $eventProphecy->getRequest()->willReturn($request)->shouldBeCalled(); $serializerProphecy = $this->prophesize(SerializerInterface::class); - $context = $populateObject ? ['object_to_populate' => $populateObject] : []; + $context = $populateObject ? [AbstractNormalizer::OBJECT_TO_POPULATE => $populateObject] : []; $serializerProphecy->deserialize('{}', 'Foo', 'json', $context)->willReturn($result)->shouldBeCalled(); $serializerContextBuilderProphecy = $this->prophesize(SerializerContextBuilderInterface::class); diff --git a/tests/Metadata/Property/Factory/SerializerPropertyMetadataFactoryTest.php b/tests/Metadata/Property/Factory/SerializerPropertyMetadataFactoryTest.php index 80423c1ff1d..b500e863cf3 100644 --- a/tests/Metadata/Property/Factory/SerializerPropertyMetadataFactoryTest.php +++ b/tests/Metadata/Property/Factory/SerializerPropertyMetadataFactoryTest.php @@ -27,6 +27,7 @@ use Symfony\Component\Serializer\Mapping\AttributeMetadata as SerializerAttributeMetadata; use Symfony\Component\Serializer\Mapping\ClassMetadata as SerializerClassMetadata; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface as SerializerClassMetadataFactoryInterface; +use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; /** * @author Teoh Han Hui @@ -55,10 +56,10 @@ public function testCreate() $dummyResourceMetadata = (new ResourceMetadata()) ->withAttributes([ 'normalization_context' => [ - 'groups' => ['dummy_read'], + AbstractNormalizer::GROUPS => ['dummy_read'], ], 'denormalization_context' => [ - 'groups' => ['dummy_write'], + AbstractNormalizer::GROUPS => ['dummy_write'], ], ]); $resourceMetadataFactoryProphecy->create(Dummy::class)->willReturn($dummyResourceMetadata)->shouldBeCalled(); diff --git a/tests/Metadata/Resource/Factory/FileConfigurationMetadataFactoryProvider.php b/tests/Metadata/Resource/Factory/FileConfigurationMetadataFactoryProvider.php index 52c265e5193..3146114aea1 100644 --- a/tests/Metadata/Resource/Factory/FileConfigurationMetadataFactoryProvider.php +++ b/tests/Metadata/Resource/Factory/FileConfigurationMetadataFactoryProvider.php @@ -15,6 +15,7 @@ use ApiPlatform\Core\Metadata\Resource\ResourceMetadata; use PHPUnit\Framework\TestCase; +use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; /** * Resource metadata provider for file configured factories tests. @@ -40,10 +41,10 @@ public function resourceMetadataProvider() 'iri' => 'someirischema', 'attributes' => [ 'normalization_context' => [ - 'groups' => ['default'], + AbstractNormalizer::GROUPS => ['default'], ], 'denormalization_context' => [ - 'groups' => ['default'], + AbstractNormalizer::GROUPS => ['default'], ], 'hydra_context' => [ '@type' => 'hydra:Operation', diff --git a/tests/Serializer/Filter/GroupFilterTest.php b/tests/Serializer/Filter/GroupFilterTest.php index 30495379317..b2bbd5ad391 100644 --- a/tests/Serializer/Filter/GroupFilterTest.php +++ b/tests/Serializer/Filter/GroupFilterTest.php @@ -17,6 +17,7 @@ use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\DummyGroup; use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; /** * @author Baptiste Meyer @@ -26,77 +27,77 @@ class GroupFilterTest extends TestCase public function testApply() { $request = new Request(['groups' => ['foo', 'bar', 'baz']]); - $context = ['groups' => ['foo', 'qux']]; + $context = [AbstractNormalizer::GROUPS => ['foo', 'qux']]; $groupFilter = new GroupFilter(); $groupFilter->apply($request, true, [], $context); - $this->assertEquals(['groups' => ['foo', 'qux', 'foo', 'bar', 'baz']], $context); + $this->assertEquals([AbstractNormalizer::GROUPS => ['foo', 'qux', 'foo', 'bar', 'baz']], $context); } public function testApplyWithOverriding() { $request = new Request(['custom_groups' => ['foo', 'bar', 'baz']]); - $context = ['groups' => ['foo', 'qux']]; + $context = [AbstractNormalizer::GROUPS => ['foo', 'qux']]; $groupFilter = new GroupFilter('custom_groups', true); $groupFilter->apply($request, false, [], $context); - $this->assertEquals(['groups' => ['foo', 'bar', 'baz']], $context); + $this->assertEquals([AbstractNormalizer::GROUPS => ['foo', 'bar', 'baz']], $context); } public function testApplyWithoutGroupsInRequest() { - $context = ['groups' => ['foo', 'bar']]; + $context = [AbstractNormalizer::GROUPS => ['foo', 'bar']]; $groupFilter = new GroupFilter(); $groupFilter->apply(new Request(), false, [], $context); - $this->assertEquals(['groups' => ['foo', 'bar']], $context); + $this->assertEquals([AbstractNormalizer::GROUPS => ['foo', 'bar']], $context); } public function testApplyWithGroupsWhitelist() { $request = new Request(['groups' => ['foo', 'bar', 'baz']]); - $context = ['groups' => 'qux']; + $context = [AbstractNormalizer::GROUPS => 'qux']; $groupFilter = new GroupFilter('groups', false, ['foo', 'baz']); $groupFilter->apply($request, true, [], $context); - $this->assertEquals(['groups' => ['qux', 'foo', 'baz']], $context); + $this->assertEquals([AbstractNormalizer::GROUPS => ['qux', 'foo', 'baz']], $context); } public function testApplyWithGroupsWhitelistWithOverriding() { $request = new Request(['groups' => ['foo', 'bar', 'baz']]); - $context = ['groups' => 'qux']; + $context = [AbstractNormalizer::GROUPS => 'qux']; $groupFilter = new GroupFilter('groups', true, ['foo', 'baz']); $groupFilter->apply($request, true, [], $context); - $this->assertEquals(['groups' => ['foo', 'baz']], $context); + $this->assertEquals([AbstractNormalizer::GROUPS => ['foo', 'baz']], $context); } public function testApplyWithInvalidGroupsInRequest() { $request = new Request(['groups' => 'foo,bar,baz']); - $context = ['groups' => ['foo', 'bar']]; + $context = [AbstractNormalizer::GROUPS => ['foo', 'bar']]; $groupFilter = new GroupFilter(); $groupFilter->apply($request, true, [], $context); - $this->assertEquals(['groups' => ['foo', 'bar']], $context); + $this->assertEquals([AbstractNormalizer::GROUPS => ['foo', 'bar']], $context); } public function testApplyWithInvalidGroupsInContext() { $request = new Request(['custom_groups' => ['foo', 'bar', 'baz']]); - $context = ['groups' => 'qux']; + $context = [AbstractNormalizer::GROUPS => 'qux']; $groupFilter = new GroupFilter('custom_groups'); $groupFilter->apply($request, true, [], $context); - $this->assertEquals(['groups' => ['qux', 'foo', 'bar', 'baz']], $context); + $this->assertEquals([AbstractNormalizer::GROUPS => ['qux', 'foo', 'bar', 'baz']], $context); } public function testGetDescription() diff --git a/tests/Swagger/Serializer/DocumentationNormalizerTest.php b/tests/Swagger/Serializer/DocumentationNormalizerTest.php index a4e4f5217f6..8289caaee0c 100644 --- a/tests/Swagger/Serializer/DocumentationNormalizerTest.php +++ b/tests/Swagger/Serializer/DocumentationNormalizerTest.php @@ -46,6 +46,7 @@ use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\RouterInterface; use Symfony\Component\Serializer\NameConverter\NameConverterInterface; +use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; /** * @author Amrouche Hamza @@ -558,7 +559,7 @@ public function testNormalizeWithOnlyNormalizationGroups() 'http://schema.example.com/Dummy', [ 'get' => ['method' => 'GET'], - 'put' => ['method' => 'PUT', 'normalization_context' => ['groups' => $groups]], + 'put' => ['method' => 'PUT', 'normalization_context' => [AbstractNormalizer::GROUPS => $groups]], ], [ 'get' => ['method' => 'GET'], @@ -749,7 +750,7 @@ public function testNormalizeWithOnlyDenormalizationGroups() 'http://schema.example.com/Dummy', [ 'get' => ['method' => 'GET'], - 'put' => ['method' => 'PUT', 'denormalization_context' => ['groups' => 'dummy']], + 'put' => ['method' => 'PUT', 'denormalization_context' => [AbstractNormalizer::GROUPS => 'dummy']], ], [ 'get' => ['method' => 'GET'], @@ -942,7 +943,7 @@ public function testNormalizeWithNormalizationAndDenormalizationGroups() 'get' => ['method' => 'GET'], 'put' => [ 'method' => 'PUT', - 'normalization_context' => ['groups' => 'dummy'], 'denormalization_context' => ['groups' => 'dummy'], + 'normalization_context' => [AbstractNormalizer::GROUPS => 'dummy'], 'denormalization_context' => [AbstractNormalizer::GROUPS => 'dummy'], ], ], [ @@ -1340,7 +1341,7 @@ public function testNormalizeWithNestedNormalizationGroups() 'http://schema.example.com/Dummy', [ 'get' => ['method' => 'GET'], - 'put' => ['method' => 'PUT', 'normalization_context' => ['groups' => $groups]], + 'put' => ['method' => 'PUT', 'normalization_context' => [AbstractNormalizer::GROUPS => $groups]], ], [ 'get' => ['method' => 'GET'], From e6b302ec4bf2561525df698a081e87174da8e4dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Mon, 30 Oct 2017 16:22:35 +0100 Subject: [PATCH 04/11] Hydra: fix owl:allValuesFrom --- .../Serializer/DocumentationNormalizer.php | 6 +-- .../DocumentationNormalizerTest.php | 40 +++++++++---------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/Hydra/Serializer/DocumentationNormalizer.php b/src/Hydra/Serializer/DocumentationNormalizer.php index 81ddaf17e4d..a9993656e17 100644 --- a/src/Hydra/Serializer/DocumentationNormalizer.php +++ b/src/Hydra/Serializer/DocumentationNormalizer.php @@ -101,11 +101,11 @@ private function populateEntrypointProperties(string $resourceClass, ResourceMet 'domain' => '#Entrypoint', 'rdfs:label' => "The collection of $shortName resources", 'rdfs:range' => [ - 'hydra:Collection', + ['@id' => 'hydra:Collection'], [ 'owl:equivalentClass' => [ - 'owl:onProperty' => 'hydra:member', - 'owl:allValuesFrom' => "#$shortName", + 'owl:onProperty' => ['@id' => 'hydra:member'], + 'owl:allValuesFrom' => ['@id' => $prefixedShortName], ], ], ], diff --git a/tests/Hydra/Serializer/DocumentationNormalizerTest.php b/tests/Hydra/Serializer/DocumentationNormalizerTest.php index 2a9314432aa..d043081df54 100644 --- a/tests/Hydra/Serializer/DocumentationNormalizerTest.php +++ b/tests/Hydra/Serializer/DocumentationNormalizerTest.php @@ -131,14 +131,14 @@ public function testNormalize() 'hydra:title' => 'Test Api', 'hydra:description' => 'test ApiGerard', 'hydra:supportedClass' => [ - 0 => [ + [ '@id' => '#dummy', '@type' => 'hydra:Class', 'rdfs:label' => 'dummy', 'hydra:title' => 'dummy', 'hydra:description' => 'dummy', 'hydra:supportedProperty' => [ - 0 => [ + [ '@type' => 'hydra:SupportedProperty', 'hydra:property' => [ '@id' => '#dummy/name', @@ -153,7 +153,7 @@ public function testNormalize() 'hydra:writable' => true, 'hydra:description' => 'name', ], - 1 => [ + [ '@type' => 'hydra:SupportedProperty', 'hydra:property' => [ '@id' => '#dummy/description', @@ -168,7 +168,7 @@ public function testNormalize() 'hydra:writable' => true, 'hydra:description' => 'description', ], - 2 => [ + [ '@type' => 'hydra:SupportedProperty', 'hydra:property' => [ '@id' => '#dummy/relatedDummy', @@ -185,7 +185,7 @@ public function testNormalize() ], ], 'hydra:supportedOperation' => [ - 0 => [ + [ '@type' => ['hydra:Operation', 'schema:FindAction'], 'hydra:method' => 'GET', 'hydra:title' => 'foobar', @@ -193,7 +193,7 @@ public function testNormalize() 'returns' => '#dummy', 'hydra:foo' => 'bar', ], - 1 => [ + [ '@type' => ['hydra:Operation', 'schema:ReplaceAction'], 'expects' => '#dummy', 'hydra:method' => 'PUT', @@ -201,7 +201,7 @@ public function testNormalize() 'rdfs:label' => 'Replaces the dummy resource.', 'returns' => '#dummy', ], - 2 => [ + [ '@type' => ['hydra:Operation', 'schema:FindAction'], 'hydra:method' => 'GET', 'hydra:title' => 'Retrieves a relatedDummy resource.', @@ -210,12 +210,12 @@ public function testNormalize() ], ], ], - 1 => [ + [ '@id' => '#Entrypoint', '@type' => 'hydra:Class', 'hydra:title' => 'The API entrypoint', 'hydra:supportedProperty' => [ - 0 => [ + [ '@type' => 'hydra:SupportedProperty', 'hydra:property' => [ '@id' => '#Entrypoint/dummy', @@ -223,23 +223,23 @@ public function testNormalize() 'rdfs:label' => 'The collection of dummy resources', 'domain' => '#Entrypoint', 'rdfs:range' => [ - 'hydra:Collection', + ['@id' => 'hydra:Collection'], [ 'owl:equivalentClass' => [ - 'owl:onProperty' => 'hydra:member', - 'owl:allValuesFrom' => '#dummy', + 'owl:onProperty' => ['@id' => 'hydra:member'], + 'owl:allValuesFrom' => ['@id' => '#dummy'], ], ], ], 'hydra:supportedOperation' => [ - 0 => [ + [ '@type' => ['hydra:Operation', 'schema:FindAction'], 'hydra:method' => 'GET', 'hydra:title' => 'Retrieves the collection of dummy resources.', 'rdfs:label' => 'Retrieves the collection of dummy resources.', 'returns' => 'hydra:Collection', ], - 1 => [ + [ '@type' => ['hydra:Operation', 'schema:CreateAction'], 'expects' => '#dummy', 'hydra:method' => 'POST', @@ -247,7 +247,7 @@ public function testNormalize() 'rdfs:label' => 'Creates a dummy resource.', 'returns' => '#dummy', ], - 2 => [ + [ '@type' => ['hydra:Operation', 'schema:FindAction'], 'hydra:method' => 'GET', 'hydra:title' => 'Retrieves a relatedDummy resource.', @@ -268,12 +268,12 @@ public function testNormalize() 'returns' => '#EntryPoint', ], ], - 2 => [ + [ '@id' => '#ConstraintViolation', '@type' => 'hydra:Class', 'hydra:title' => 'A constraint violation', 'hydra:supportedProperty' => [ - 0 => [ + [ '@type' => 'hydra:SupportedProperty', 'hydra:property' => [ '@id' => '#ConstraintViolation/propertyPath', @@ -287,7 +287,7 @@ public function testNormalize() 'hydra:readable' => true, 'hydra:writable' => false, ], - 1 => [ + [ '@type' => 'hydra:SupportedProperty', 'hydra:property' => [ '@id' => '#ConstraintViolation/message', @@ -303,13 +303,13 @@ public function testNormalize() ], ], ], - 3 => [ + [ '@id' => '#ConstraintViolationList', '@type' => 'hydra:Class', 'subClassOf' => 'hydra:Error', 'hydra:title' => 'A constraint violation list', 'hydra:supportedProperty' => [ - 0 => [ + [ '@type' => 'hydra:SupportedProperty', 'hydra:property' => [ '@id' => '#ConstraintViolationList/violations', From 0e221ff273ea7be4e110993c019be43372d84c81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Mon, 30 Oct 2017 14:50:27 +0100 Subject: [PATCH 05/11] Include swagger context even when type is null I do not know when the type is supposed to be null, but I am using the YamlExtractor and it always seems to be the case with that metadata specification method. --- src/Swagger/Serializer/DocumentationNormalizer.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Swagger/Serializer/DocumentationNormalizer.php b/src/Swagger/Serializer/DocumentationNormalizer.php index b69c0cd5983..7c9ff4daff9 100644 --- a/src/Swagger/Serializer/DocumentationNormalizer.php +++ b/src/Swagger/Serializer/DocumentationNormalizer.php @@ -508,7 +508,7 @@ private function getDefinitionSchema(string $resourceClass, ResourceMetadata $re */ private function getPropertySchema(PropertyMetadata $propertyMetadata, \ArrayObject $definitions, array $serializerContext = null): \ArrayObject { - $propertySchema = new \ArrayObject(); + $propertySchema = new \ArrayObject($propertyMetadata->getAttributes()['swagger_context'] ?? []); if (false === $propertyMetadata->isWritable()) { $propertySchema['readOnly'] = true; @@ -533,7 +533,7 @@ private function getPropertySchema(PropertyMetadata $propertyMetadata, \ArrayObj $valueSchema = $this->getType($builtinType, $isCollection, $className, $propertyMetadata->isReadableLink(), $definitions, $serializerContext); - return new \ArrayObject((array) $propertySchema + $valueSchema + ($propertyMetadata->getAttributes()['swagger_context'] ?? [])); + return new \ArrayObject((array) $propertySchema + $valueSchema); } /** From 32f65b7a0c9a7d58c75e79d8d5011082149658ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Thu, 2 Nov 2017 16:02:44 +0100 Subject: [PATCH 06/11] Document what count() is supposed to return (#1468) --- src/DataProvider/PaginatorInterface.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/DataProvider/PaginatorInterface.php b/src/DataProvider/PaginatorInterface.php index 11e8760eb7d..715e588c374 100644 --- a/src/DataProvider/PaginatorInterface.php +++ b/src/DataProvider/PaginatorInterface.php @@ -14,7 +14,8 @@ namespace ApiPlatform\Core\DataProvider; /** - * Paginator Interface. + * The \Countable implementation should return the number of items on the + * current page, as an integer. * * @author Kévin Dunglas */ From ee306666c1d8ac4571cca0266937deeb7a54776b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Thu, 2 Nov 2017 16:04:38 +0100 Subject: [PATCH 07/11] Update the changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dccfb036c7..a2964659754 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 2.1.3 + +* Don't use dynamic values in Varnish-related service keys (improves Symfony 3.3 compatibility) +* Hydra: Fix the value of `owl:allValuesFrom` in the API documentation +* Swagger: Include the context even when the type is `null` +* Minor code and PHPDoc cleanups + ## 2.1.2 * PHP 7.2 compatibility From 140ba7ab4379ae4f39f003db188c04843efbe5f5 Mon Sep 17 00:00:00 2001 From: abluchet Date: Thu, 2 Nov 2017 17:19:12 +0100 Subject: [PATCH 08/11] fix eager loading filter with non-association composite identifier --- .../Extension/FilterEagerLoadingExtension.php | 6 +- .../Doctrine/Orm/Util/EagerLoadingTrait.php | 2 +- .../FilterEagerLoadingExtensionTest.php | 67 ++++++++++++++++++- 3 files changed, 71 insertions(+), 4 deletions(-) diff --git a/src/Bridge/Doctrine/Orm/Extension/FilterEagerLoadingExtension.php b/src/Bridge/Doctrine/Orm/Extension/FilterEagerLoadingExtension.php index 04823600b1b..91f674f4c8b 100644 --- a/src/Bridge/Doctrine/Orm/Extension/FilterEagerLoadingExtension.php +++ b/src/Bridge/Doctrine/Orm/Extension/FilterEagerLoadingExtension.php @@ -69,7 +69,11 @@ public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGenerator $queryBuilderClone->andWhere($queryBuilderClone->expr()->in($originAlias, $in->getDQL())); } else { // Because Doctrine doesn't support WHERE ( foo, bar ) IN () (https://github.com/doctrine/doctrine2/issues/5238), we are building as many subqueries as they are identifiers - foreach ($classMetadata->identifier as $identifier) { + foreach ($classMetadata->getIdentifier() as $identifier) { + if (!$classMetadata->hasAssociation($identifier)) { + continue; + } + $replacementAlias = $queryNameGenerator->generateJoinAlias($originAlias); $in = $this->getQueryBuilderWithNewAliases($queryBuilder, $queryNameGenerator, $originAlias, $replacementAlias); $in->select("IDENTITY($replacementAlias.$identifier)"); diff --git a/src/Bridge/Doctrine/Orm/Util/EagerLoadingTrait.php b/src/Bridge/Doctrine/Orm/Util/EagerLoadingTrait.php index d9aed58b920..006c04b7683 100644 --- a/src/Bridge/Doctrine/Orm/Util/EagerLoadingTrait.php +++ b/src/Bridge/Doctrine/Orm/Util/EagerLoadingTrait.php @@ -91,7 +91,7 @@ private function hasFetchEagerAssociation(EntityManager $em, ClassMetadataInfo $ { $checked[] = $classMetadata->name; - foreach ($classMetadata->associationMappings as $mapping) { + foreach ($classMetadata->getAssociationMappings() as $mapping) { if (ClassMetadataInfo::FETCH_EAGER === $mapping['fetch']) { return true; } diff --git a/tests/Bridge/Doctrine/Orm/Extension/FilterEagerLoadingExtensionTest.php b/tests/Bridge/Doctrine/Orm/Extension/FilterEagerLoadingExtensionTest.php index 32318afbe9f..906b3154471 100644 --- a/tests/Bridge/Doctrine/Orm/Extension/FilterEagerLoadingExtensionTest.php +++ b/tests/Bridge/Doctrine/Orm/Extension/FilterEagerLoadingExtensionTest.php @@ -246,9 +246,14 @@ public function testCompositeIdentifiers() $resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class); $resourceMetadataFactoryProphecy->create(CompositeRelation::class)->willReturn(new ResourceMetadata(CompositeRelation::class)); - $classMetadata = new ClassMetadataInfo(CompositeRelation::class); + $classMetadataProphecy = $this->prophesize(ClassMetadataInfo::class); + $classMetadataProphecy->getIdentifier()->willReturn(['item', 'label']); + $classMetadataProphecy->getAssociationMappings()->willReturn(['item' => ['fetch' => ClassMetadataInfo::FETCH_EAGER]]); + $classMetadataProphecy->hasAssociation('item')->shouldBeCalled()->willReturn(true); + $classMetadataProphecy->hasAssociation('label')->shouldBeCalled()->willReturn(true); + + $classMetadata = $classMetadataProphecy->reveal(); $classMetadata->isIdentifierComposite = true; - $classMetadata->identifier = ['item', 'label']; $em = $this->prophesize(EntityManager::class); $em->getExpressionBuilder()->shouldBeCalled()->willReturn(new Expr()); @@ -353,6 +358,64 @@ public function testFetchEagerWithNoForceEager() $this->assertEquals($this->toDQLString($expected), $qb->getDQL()); } + public function testCompositeIdentifiersWithoutAssociation() + { + $resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class); + $resourceMetadataFactoryProphecy->create(CompositeRelation::class)->willReturn(new ResourceMetadata(CompositeRelation::class)); + + $classMetadataProphecy = $this->prophesize(ClassMetadataInfo::class); + $classMetadataProphecy->getIdentifier()->willReturn(['item', 'label', 'bar']); + $classMetadataProphecy->getAssociationMappings()->willReturn(['item' => ['fetch' => ClassMetadataInfo::FETCH_EAGER]]); + $classMetadataProphecy->hasAssociation('item')->shouldBeCalled()->willReturn(true); + $classMetadataProphecy->hasAssociation('label')->shouldBeCalled()->willReturn(true); + $classMetadataProphecy->hasAssociation('bar')->shouldBeCalled()->willReturn(false); + + $classMetadata = $classMetadataProphecy->reveal(); + $classMetadata->isIdentifierComposite = true; + + $em = $this->prophesize(EntityManager::class); + $em->getExpressionBuilder()->shouldBeCalled()->willReturn(new Expr()); + $em->getClassMetadata(CompositeRelation::class)->shouldBeCalled()->willReturn($classMetadata); + + $qb = new QueryBuilder($em->reveal()); + + $qb->select('o') + ->from(CompositeRelation::class, 'o') + ->innerJoin('o.compositeItem', 'item') + ->innerJoin('o.compositeLabel', 'label') + ->where('item.field1 = :foo AND o.bar = :bar') + ->setParameter('foo', 1) + ->setParameter('bar', 2); + + $queryNameGenerator = $this->prophesize(QueryNameGeneratorInterface::class); + $queryNameGenerator->generateJoinAlias('item')->shouldBeCalled()->willReturn('item_2'); + $queryNameGenerator->generateJoinAlias('label')->shouldBeCalled()->willReturn('label_2'); + $queryNameGenerator->generateJoinAlias('o')->shouldBeCalled()->willReturn('o_2'); + + $filterEagerLoadingExtension = new FilterEagerLoadingExtension($resourceMetadataFactoryProphecy->reveal(), true); + $filterEagerLoadingExtension->applyToCollection($qb, $queryNameGenerator->reveal(), CompositeRelation::class, 'get'); + + $expected = <<assertEquals($this->toDQLString($expected), $qb->getDQL()); + } + private function toDQLString(string $dql): string { return preg_replace(['/\s+/', '/\(\s/', '/\s\)/'], [' ', '(', ')'], $dql); From de2c31e6dbd5941e0cc96af747a79176f25b0585 Mon Sep 17 00:00:00 2001 From: Ambroise Maupate Date: Tue, 10 Oct 2017 17:49:42 +0200 Subject: [PATCH 09/11] [#1313] LIMIT and ORDER BY on a column from a fetch joined to-many association --- src/Bridge/Doctrine/Orm/Util/QueryChecker.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Bridge/Doctrine/Orm/Util/QueryChecker.php b/src/Bridge/Doctrine/Orm/Util/QueryChecker.php index 17b9beb5ca4..44c137c1cc5 100644 --- a/src/Bridge/Doctrine/Orm/Util/QueryChecker.php +++ b/src/Bridge/Doctrine/Orm/Util/QueryChecker.php @@ -150,8 +150,14 @@ public static function hasOrderByOnToManyJoin(QueryBuilder $queryBuilder, Manage $relationship = QueryJoinParser::getJoinRelationship($join); if (false !== strpos($relationship, '.')) { - $metadata = QueryJoinParser::getClassMetadataFromJoinAlias($alias, $queryBuilder, $managerRegistry); - if ($metadata->isCollectionValuedAssociation($relationship)) { + /* + * (Cannot select distinct identifiers from query with LIMIT and ORDER BY on a column from a fetch joined to-many association. Use output walkers) + * + * @see https://github.com/api-platform/core/issues/1313 + */ + list($parentAlias, $association) = explode('.', $relationship); + $metadata = QueryJoinParser::getClassMetadataFromJoinAlias($parentAlias, $queryBuilder, $managerRegistry); + if ($metadata->isCollectionValuedAssociation($association)) { return true; } } else { From 526edc507fddf75defa5eb7f9c46c97b8f6135a2 Mon Sep 17 00:00:00 2001 From: abluchet Date: Thu, 2 Nov 2017 17:56:42 +0100 Subject: [PATCH 10/11] Add test on #1449 query checker order by toMany --- src/Bridge/Doctrine/Orm/Util/QueryChecker.php | 8 +++---- .../Doctrine/Orm/Util/QueryCheckerTest.php | 21 +++++++++++++++++++ .../Doctrine/Orm/Util/QueryJoinParserTest.php | 2 +- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/Bridge/Doctrine/Orm/Util/QueryChecker.php b/src/Bridge/Doctrine/Orm/Util/QueryChecker.php index 44c137c1cc5..5e9af9100dc 100644 --- a/src/Bridge/Doctrine/Orm/Util/QueryChecker.php +++ b/src/Bridge/Doctrine/Orm/Util/QueryChecker.php @@ -146,17 +146,15 @@ public static function hasOrderByOnToManyJoin(QueryBuilder $queryBuilder, Manage if (!isset($orderByAliases[$alias])) { continue; } - $relationship = QueryJoinParser::getJoinRelationship($join); if (false !== strpos($relationship, '.')) { /* - * (Cannot select distinct identifiers from query with LIMIT and ORDER BY on a column from a fetch joined to-many association. Use output walkers) - * + * We select the parent alias because it may differ from the origin alias given above * @see https://github.com/api-platform/core/issues/1313 */ - list($parentAlias, $association) = explode('.', $relationship); - $metadata = QueryJoinParser::getClassMetadataFromJoinAlias($parentAlias, $queryBuilder, $managerRegistry); + list($relationAlias, $association) = explode('.', $relationship); + $metadata = QueryJoinParser::getClassMetadataFromJoinAlias($relationAlias, $queryBuilder, $managerRegistry); if ($metadata->isCollectionValuedAssociation($association)) { return true; } diff --git a/tests/Bridge/Doctrine/Orm/Util/QueryCheckerTest.php b/tests/Bridge/Doctrine/Orm/Util/QueryCheckerTest.php index b26eac487dd..9d78a523f0b 100644 --- a/tests/Bridge/Doctrine/Orm/Util/QueryCheckerTest.php +++ b/tests/Bridge/Doctrine/Orm/Util/QueryCheckerTest.php @@ -176,4 +176,25 @@ public function testHasOrderByOnToManyJoinWithClassLeftJoin() $this->assertTrue(QueryChecker::hasOrderByOnToManyJoin($queryBuilder->reveal(), $managerRegistry->reveal())); } + + /** + * Adds a test on the fix referenced in https://github.com/api-platform/core/pull/1449. + */ + public function testOrderByOnToManyWithRelationAsBasis() + { + $queryBuilder = $this->prophesize(QueryBuilder::class); + $queryBuilder->getRootEntities()->willReturn(['Dummy']); + $queryBuilder->getRootAliases()->willReturn(['d']); + $queryBuilder->getDQLPart('join')->willReturn(['d' => [new Join('LEFT_JOIN', 'd.relatedDummy', 'a_1')]]); + $queryBuilder->getDQLPart('orderBy')->willReturn(['a_1.name' => new OrderBy('a_1.name', 'asc')]); + $classMetadata = $this->prophesize(ClassMetadata::class); + $classMetadata = $this->prophesize(ClassMetadata::class); + $classMetadata->isCollectionValuedAssociation('relatedDummy')->willReturn(true); + $objectManager = $this->prophesize(ObjectManager::class); + $objectManager->getClassMetadata('Dummy')->willReturn($classMetadata->reveal()); + $managerRegistry = $this->prophesize(ManagerRegistry::class); + $managerRegistry->getManagerForClass('Dummy')->willReturn($objectManager->reveal()); + + $this->assertTrue(QueryChecker::hasOrderByOnToManyJoin($queryBuilder->reveal(), $managerRegistry->reveal())); + } } diff --git a/tests/Bridge/Doctrine/Orm/Util/QueryJoinParserTest.php b/tests/Bridge/Doctrine/Orm/Util/QueryJoinParserTest.php index 7d017b01db4..b85507e8e7b 100644 --- a/tests/Bridge/Doctrine/Orm/Util/QueryJoinParserTest.php +++ b/tests/Bridge/Doctrine/Orm/Util/QueryJoinParserTest.php @@ -33,7 +33,7 @@ public function testGetClassMetadataFromJoinAlias() $queryBuilder = $this->prophesize(QueryBuilder::class); $queryBuilder->getRootEntities()->willReturn(['Dummy']); $queryBuilder->getRootAliases()->willReturn(['d']); - $queryBuilder->getDQLPart('join')->willReturn(['a_1' => new Join('INNER_JOIN', 'relatedDummy', 'a_1', null, 'a_1.name = r.name')]); + $queryBuilder->getDQLPart('join')->willReturn(['a_1' => [new Join('INNER_JOIN', 'relatedDummy', 'a_1', null, 'a_1.name = r.name')]]); $classMetadata = $this->prophesize(ClassMetadata::class); $objectManager = $this->prophesize(ObjectManager::class); $objectManager->getClassMetadata('Dummy')->willReturn($classMetadata->reveal()); From 80c88f9cdd54873963d7dd6163f0fa814c066933 Mon Sep 17 00:00:00 2001 From: abluchet Date: Fri, 3 Nov 2017 10:43:14 +0100 Subject: [PATCH 11/11] Fix Extension Test getDefaultContainer => getBaseContainer --- .../Bundle/DependencyInjection/ApiPlatformExtensionTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php b/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php index 4317f835423..c39dd4e5820 100644 --- a/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php +++ b/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php @@ -227,7 +227,7 @@ public function testEnableNelmioApiDoc() public function testDisableGraphql() { - $containerBuilderProphecy = $this->getDefaultContainerBuilderProphecy(); + $containerBuilderProphecy = $this->getBaseContainerBuilderProphecy(); $containerBuilderProphecy->setDefinition('api_platform.action.graphql_entrypoint')->shouldNotBeCalled(); $containerBuilderProphecy->setDefinition('api_platform.graphql.collection_resolver_factory')->shouldNotBeCalled(); $containerBuilderProphecy->setDefinition('api_platform.graphql.executor')->shouldNotBeCalled();