Skip to content

Commit 596747f

Browse files
committed
refactor 2
1 parent 893b91e commit 596747f

File tree

5 files changed

+134
-38
lines changed

5 files changed

+134
-38
lines changed

src/Hydra/IriTemplate.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@
1414
namespace ApiPlatform\Hydra;
1515

1616
use Symfony\Component\JsonStreamer\Attribute\StreamedName;
17+
use Symfony\Component\Serializer\Annotation\SerializedName;
1718

1819
final class IriTemplate
1920
{
2021
#[StreamedName('@type')]
22+
#[SerializedName('@type')]
2123
public string $type = 'IriTemplate';
2224

2325
public function __construct(

src/Hydra/IriTemplateMapping.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,17 @@
1414
namespace ApiPlatform\Hydra;
1515

1616
use Symfony\Component\JsonStreamer\Attribute\StreamedName;
17+
use Symfony\Component\Serializer\Annotation\SerializedName;
1718

1819
class IriTemplateMapping
1920
{
2021
#[StreamedName('@type')]
22+
#[SerializedName('@type')]
2123
public string $type = 'IriTemplateMapping';
2224

2325
public function __construct(
2426
public string $variable,
25-
public string $property,
27+
public ?string $property,
2628
public bool $required = false,
2729
) {
2830
}

src/Hydra/Serializer/CollectionFiltersNormalizer.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
2121
use ApiPlatform\Metadata\ResourceClassResolverInterface;
2222
use ApiPlatform\State\Util\StateOptionsTrait;
23+
use ApiPlatform\Hydra\State\Util\SearchHelperTrait;
2324
use Psr\Container\ContainerInterface;
2425
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
2526
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
@@ -35,6 +36,7 @@ final class CollectionFiltersNormalizer implements NormalizerInterface, Normaliz
3536
{
3637
use HydraPrefixTrait;
3738
use StateOptionsTrait;
39+
use SearchHelperTrait;
3840
private ?ContainerInterface $filterLocator = null;
3941

4042
/**
@@ -105,7 +107,7 @@ public function normalize(mixed $object, ?string $format = null, array $context
105107

106108
if ($currentFilters || ($parameters && \count($parameters))) {
107109
$hydraPrefix = $this->getHydraPrefix($context + $this->defaultContext);
108-
$data[$hydraPrefix.'search'] = $this->getSearch($resourceClass, $requestParts, $currentFilters, $parameters, $hydraPrefix);
110+
$data[$hydraPrefix.'search'] = $this->getSearch(path: $requestParts['path'], resourceClass: $resourceClass, filters: $currentFilters, parameters: $parameters);
109111
}
110112

111113
return $data;

src/Hydra/State/JsonStreamerProcessor.php

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,15 @@
2626
use ApiPlatform\Metadata\ResourceClassResolverInterface;
2727
use ApiPlatform\Metadata\UrlGeneratorInterface;
2828
use ApiPlatform\Metadata\Util\IriHelper;
29+
use ApiPlatform\State\Util\HttpResponseStatusTrait;
2930
use ApiPlatform\State\Pagination\PaginatorInterface;
3031
use ApiPlatform\State\ProcessorInterface;
3132
use ApiPlatform\State\Util\HttpResponseHeadersTrait;
32-
use ApiPlatform\State\Util\HttpResponseStatusTrait;
3333
use Symfony\Component\HttpFoundation\Response;
3434
use Symfony\Component\HttpFoundation\StreamedResponse;
3535
use Symfony\Component\JsonStreamer\StreamWriterInterface;
3636
use ApiPlatform\Hydra\State\Util\PaginationHelperTrait;
37+
use ApiPlatform\Hydra\State\Util\SearchHelperTrait;
3738
use Symfony\Component\TypeInfo\Type;
3839

3940
/**
@@ -44,6 +45,7 @@ final class JsonStreamerProcessor implements ProcessorInterface
4445
use HttpResponseHeadersTrait;
4546
use HttpResponseStatusTrait;
4647
use PaginationHelperTrait;
48+
use SearchHelperTrait;
4749

4850
/**
4951
* @param ProcessorInterface<mixed,mixed> $processor
@@ -86,7 +88,8 @@ public function process(mixed $data, Operation $operation, array $uriVariables =
8688
$collection->view = $this->getView($data, $requestUri, $operation);
8789

8890
if ($operation->getParameters()) {
89-
$collection->search = $this->getSearch($operation, $requestUri);
91+
$parts = parse_url($requestUri);
92+
$collection->search = $this->getSearch($parts['path'] ?? '', $operation);
9093
}
9194

9295
if ($data instanceof PaginatorInterface) {
@@ -119,40 +122,6 @@ public function process(mixed $data, Operation $operation, array $uriVariables =
119122
return $this->processor->process($response, $operation, $uriVariables, $context);
120123
}
121124

122-
// TODO: These come from our Hydra collection normalizer, try to share the logic
123-
private function getSearch(Operation $operation, string $requestUri): IriTemplate
124-
{
125-
/** @var list<IriTemplateMapping> */
126-
$mapping = [];
127-
$keys = [];
128-
129-
foreach ($operation->getParameters() ?? [] as $key => $parameter) {
130-
if (!$parameter instanceof QueryParameterInterface || false === $parameter->getHydra()) {
131-
continue;
132-
}
133-
134-
if (!($property = $parameter->getProperty())) {
135-
continue;
136-
}
137-
138-
$keys[] = $key;
139-
$m = new IriTemplateMapping(
140-
variable: $key,
141-
property: $property,
142-
required: $parameter->getRequired() ?? false
143-
);
144-
$mapping[] = $m;
145-
}
146-
147-
$parts = parse_url($requestUri);
148-
149-
return new IriTemplate(
150-
variableRepresentation: 'BasicRepresentation',
151-
mapping: $mapping,
152-
template: \sprintf('%s{?%s}', $parts['path'] ?? '', implode(',', $keys)),
153-
);
154-
}
155-
156125
private function getView(mixed $object, string $requestUri, Operation $operation): PartialCollectionView
157126
{
158127
return $this->getPartialCollectionView($object, $requestUri, $this->pageParameterName, $this->enabledParameterName, $operation->getUrlGenerationStrategy() ?? $this->urlGenerationStrategy);
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Hydra\State\Util;
15+
16+
use ApiPlatform\Hydra\IriTemplate;
17+
use ApiPlatform\Hydra\IriTemplateMapping;
18+
use ApiPlatform\Metadata\FilterInterface;
19+
use ApiPlatform\Metadata\Operation;
20+
use ApiPlatform\Metadata\Parameters;
21+
use ApiPlatform\Metadata\QueryParameterInterface;
22+
23+
trait SearchHelperTrait
24+
{
25+
/**
26+
* @param FilterInterface[] $filters
27+
*/
28+
private function getSearch(string $path, ?Operation $operation = null, ?string $resourceClass = null, ?array $filters = [], ?Parameters $parameters = null): IriTemplate
29+
{
30+
['mapping' => $mapping, 'keys' => $keys] = $this->getSearchMappingAndKeys($operation, $resourceClass, $filters, $parameters);
31+
32+
return new IriTemplate(
33+
variableRepresentation: 'BasicRepresentation',
34+
mapping: $mapping,
35+
template: \sprintf('%s{?%s}', $path, implode(',', $keys)),
36+
);
37+
}
38+
39+
/**
40+
* @param FilterInterface[] $filters
41+
*
42+
* @return array{mapping: list<IriTemplateMapping>, keys: list<string>}
43+
*/
44+
private function getSearchMappingAndKeys(?Operation $operation = null, ?string $resourceClass = null, ?array $filters = [], ?Parameters $parameters = null): array
45+
{
46+
$mapping = [];
47+
$keys = [];
48+
49+
if ($filters) {
50+
foreach ($filters as $filter) {
51+
foreach ($filter->getDescription($resourceClass) as $variable => $data) {
52+
$keys[] = $variable;
53+
$mapping[] = new IriTemplateMapping(variable: $variable, property: $data['property'] ?? null, required: $data['required'] ?? false);
54+
}
55+
}
56+
}
57+
58+
$params = $operation ? ($operation->getParameters() ?? []) : ($parameters ?? []);
59+
60+
foreach ($params as $key => $parameter) {
61+
if (!$parameter instanceof QueryParameterInterface || false === $parameter->getHydra()) {
62+
continue;
63+
}
64+
65+
if (($filterId = $parameter->getFilter()) && \is_string($filterId) && ($filter = $this->getFilter($filterId))) {
66+
$filterDescription = $filter->getDescription($resourceClass);
67+
68+
foreach ($filterDescription as $variable => $description) {
69+
if (str_ends_with((string) $variable, '[]')) {
70+
continue;
71+
}
72+
73+
if (($prop = $parameter->getProperty()) && ($description['property'] ?? null) !== $prop) {
74+
continue;
75+
}
76+
77+
$k = str_replace(':property', $description['property'], $key);
78+
$variable = str_replace($description['property'], $k, $variable);
79+
$keys[] = $variable;
80+
$m = new IriTemplateMapping(variable: $variable, property: $description['property'], required: $description['required']);
81+
if (null !== ($required = $parameter->getRequired())) {
82+
$m->required = $required;
83+
}
84+
$mapping[] = $m;
85+
}
86+
87+
if ($filterDescription) {
88+
continue;
89+
}
90+
}
91+
92+
if (str_contains($key, ':property') && $parameter->getProperties()) {
93+
$required = $parameter->getRequired();
94+
foreach ($parameter->getProperties() as $prop) {
95+
$k = str_replace(':property', $prop, $key);
96+
$m = new IriTemplateMapping(variable: $k, property: $prop);
97+
$keys[] = $k;
98+
if (null !== $required) {
99+
$m->required = $required;
100+
}
101+
$mapping[] = $m;
102+
}
103+
104+
continue;
105+
}
106+
107+
if (!($property = $parameter->getProperty())) {
108+
continue;
109+
}
110+
111+
$m = new IriTemplateMapping(variable: $key, property: $property);
112+
$keys[] = $key;
113+
if (null !== ($required = $parameter->getRequired())) {
114+
$m->required = $required;
115+
}
116+
$mapping[] = $m;
117+
}
118+
119+
return ['mapping' => $mapping, 'keys' => $keys];
120+
}
121+
}

0 commit comments

Comments
 (0)