diff --git a/src/Hydra/Serializer/CollectionFiltersNormalizer.php b/src/Hydra/Serializer/CollectionFiltersNormalizer.php index c527a32f544..1f348cd6894 100644 --- a/src/Hydra/Serializer/CollectionFiltersNormalizer.php +++ b/src/Hydra/Serializer/CollectionFiltersNormalizer.php @@ -110,12 +110,15 @@ public function normalize(mixed $object, ?string $format = null, array $context if ($currentFilters || ($parameters && \count($parameters))) { $hydraPrefix = $this->getHydraPrefix($context + $this->defaultContext); ['mapping' => $mapping, 'keys' => $keys] = $this->getSearchMappingAndKeys($operation, $resourceClass, $currentFilters, $parameters, [$this, 'getFilter']); - $data[$hydraPrefix.'search'] = [ - '@type' => $hydraPrefix.'IriTemplate', - $hydraPrefix.'template' => \sprintf('%s{?%s}', $requestParts['path'], implode(',', $keys)), - $hydraPrefix.'variableRepresentation' => 'BasicRepresentation', - $hydraPrefix.'mapping' => $this->convertMappingToArray($mapping), - ]; + + if ($keys || $mapping) { + $data[$hydraPrefix.'search'] = [ + '@type' => $hydraPrefix.'IriTemplate', + $hydraPrefix.'template' => \sprintf('%s{?%s}', $requestParts['path'], implode(',', $keys)), + $hydraPrefix.'variableRepresentation' => 'BasicRepresentation', + $hydraPrefix.'mapping' => $this->convertMappingToArray($mapping), + ]; + } } return $data; diff --git a/src/Hydra/Tests/Serializer/CollectionFiltersNormalizerTest.php b/src/Hydra/Tests/Serializer/CollectionFiltersNormalizerTest.php index 6943b8db13c..35c3c551625 100644 --- a/src/Hydra/Tests/Serializer/CollectionFiltersNormalizerTest.php +++ b/src/Hydra/Tests/Serializer/CollectionFiltersNormalizerTest.php @@ -23,6 +23,7 @@ use ApiPlatform\Metadata\Exception\InvalidArgumentException; use ApiPlatform\Metadata\GetCollection; use ApiPlatform\Metadata\Operations; +use ApiPlatform\Metadata\QueryParameter; use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface; use ApiPlatform\Metadata\Resource\ResourceMetadataCollection; use ApiPlatform\Metadata\ResourceClassResolverInterface; @@ -323,6 +324,106 @@ public function testNormalize(): void ])); } + public function testNormalizeParametersWithFilter(): void + { + $dummy = new Dummy(); + + $decoratedProphecy = $this->prophesize(NormalizerInterface::class); + $decoratedProphecy->normalize($dummy, CollectionNormalizer::FORMAT, [ + 'request_uri' => '/foo?bar=baz', + 'resource_class' => Dummy::class, + 'operation_name' => 'get', + ])->willReturn(['name' => 'foo']); + + $filterProphecy = $this->prophesize(FilterInterface::class); + $filterProphecy->getDescription(Dummy::class)->willReturn(['a' => ['property' => 'name', 'required' => true]])->shouldBeCalled(); + + $filterLocatorProphecy = $this->prophesize(ContainerInterface::class); + $filterLocatorProphecy->has('foo')->willReturn(true)->shouldBeCalled(); + $filterLocatorProphecy->get('foo')->willReturn($filterProphecy->reveal())->shouldBeCalled(); + + $resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataCollectionFactoryInterface::class); + $resourceMetadataFactoryProphecy->create(Dummy::class)->willReturn(new ResourceMetadataCollection(Dummy::class, [ + (new ApiResource(Dummy::class)) + ->withShortName('Dummy') + ->withOperations(new Operations([ + 'get' => (new GetCollection())->withShortName('Dummy')->withParameters([new QueryParameter(filter: 'foo')])->withFilters([]), + ])), + ])); + + $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); + $resourceClassResolverProphecy->getResourceClass($dummy, Dummy::class)->willReturn(Dummy::class); + + $normalizer = new CollectionFiltersNormalizer( + $decoratedProphecy->reveal(), + $resourceMetadataFactoryProphecy->reveal(), + $resourceClassResolverProphecy->reveal(), + $filterLocatorProphecy->reveal(), + ); + + $this->assertEquals([ + 'name' => 'foo', + 'hydra:search' => [ + '@type' => 'hydra:IriTemplate', + 'hydra:template' => '/foo{?a}', + 'hydra:variableRepresentation' => 'BasicRepresentation', + 'hydra:mapping' => [ + [ + '@type' => 'IriTemplateMapping', + 'variable' => 'a', + 'property' => 'name', + 'required' => true, + ], + ], + ], + ], $normalizer->normalize($dummy, CollectionNormalizer::FORMAT, [ + 'request_uri' => '/foo?bar=baz', + 'resource_class' => Dummy::class, + 'operation_name' => 'get', + ])); + } + + public function testNormalizeParametersWithoutFilter(): void + { + $dummy = new Dummy(); + + $decoratedProphecy = $this->prophesize(NormalizerInterface::class); + $decoratedProphecy->normalize($dummy, CollectionNormalizer::FORMAT, [ + 'request_uri' => '/foo?bar=baz', + 'resource_class' => Dummy::class, + 'operation_name' => 'get', + ])->willReturn(['name' => 'foo']); + + $filterLocatorProphecy = $this->prophesize(ContainerInterface::class); + + $resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataCollectionFactoryInterface::class); + $resourceMetadataFactoryProphecy->create(Dummy::class)->willReturn(new ResourceMetadataCollection(Dummy::class, [ + (new ApiResource(Dummy::class)) + ->withShortName('Dummy') + ->withOperations(new Operations([ + 'get' => (new GetCollection())->withShortName('Dummy')->withParameters([new QueryParameter(hydra: false)])->withFilters([]), + ])), + ])); + + $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); + $resourceClassResolverProphecy->getResourceClass($dummy, Dummy::class)->willReturn(Dummy::class); + + $normalizer = new CollectionFiltersNormalizer( + $decoratedProphecy->reveal(), + $resourceMetadataFactoryProphecy->reveal(), + $resourceClassResolverProphecy->reveal(), + $filterLocatorProphecy->reveal(), + ); + + $this->assertEquals([ + 'name' => 'foo', + ], $normalizer->normalize($dummy, CollectionNormalizer::FORMAT, [ + 'request_uri' => '/foo?bar=baz', + 'resource_class' => Dummy::class, + 'operation_name' => 'get', + ])); + } + public function testGetSupportedTypes(): void { if (!method_exists(Serializer::class, 'getSupportedTypes')) { diff --git a/tests/Functional/Parameters/HydraTest.php b/tests/Functional/Parameters/HydraTest.php index b12c115cab8..f2a29361ca9 100644 --- a/tests/Functional/Parameters/HydraTest.php +++ b/tests/Functional/Parameters/HydraTest.php @@ -45,10 +45,6 @@ public function testHydraTemplate(): void public function testNoPropertyDescription(): void { $response = self::createClient()->request('GET', 'with_parameters_filter_without_property.jsonld'); - $this->assertArraySubset(['hydra:search' => [ - 'hydra:template' => '/with_parameters_filter_without_property.jsonld{?}', - 'hydra:mapping' => [ - ], - ]], $response->toArray()); + static::assertResponseStatusCodeSame(200); } }