20
20
use ApiPlatform \Metadata \Resource \Factory \ResourceMetadataCollectionFactoryInterface ;
21
21
use ApiPlatform \Metadata \ResourceClassResolverInterface ;
22
22
use ApiPlatform \State \Util \StateOptionsTrait ;
23
+ use ApiPlatform \Hydra \State \Util \SearchHelperTrait ;
24
+ use ApiPlatform \Hydra \IriTemplate \IriTemplateMapping ;
23
25
use Psr \Container \ContainerInterface ;
24
26
use Symfony \Component \Serializer \Exception \UnexpectedValueException ;
25
27
use Symfony \Component \Serializer \Normalizer \AbstractObjectNormalizer ;
@@ -35,6 +37,7 @@ final class CollectionFiltersNormalizer implements NormalizerInterface, Normaliz
35
37
{
36
38
use HydraPrefixTrait;
37
39
use StateOptionsTrait;
40
+ use SearchHelperTrait;
38
41
private ?ContainerInterface $ filterLocator = null ;
39
42
40
43
/**
@@ -105,7 +108,13 @@ public function normalize(mixed $object, ?string $format = null, array $context
105
108
106
109
if ($ currentFilters || ($ parameters && \count ($ parameters ))) {
107
110
$ hydraPrefix = $ this ->getHydraPrefix ($ context + $ this ->defaultContext );
108
- $ data [$ hydraPrefix .'search ' ] = $ this ->getSearch ($ resourceClass , $ requestParts , $ currentFilters , $ parameters , $ hydraPrefix );
111
+ ['mapping ' => $ mapping , 'keys ' => $ keys ] = $ this ->getSearchMappingAndKeys ($ operation , $ resourceClass , $ currentFilters , $ parameters , [$ this , 'getFilter ' ]);
112
+ $ data [$ hydraPrefix .'search ' ] = [
113
+ '@type ' => $ hydraPrefix .'IriTemplate ' ,
114
+ $ hydraPrefix .'template ' => \sprintf ('%s{?%s} ' , $ requestParts ['path ' ], implode (', ' , $ keys )),
115
+ $ hydraPrefix .'variableRepresentation ' => 'BasicRepresentation ' ,
116
+ $ hydraPrefix .'mapping ' => $ this ->convertMappingToArray ($ mapping ),
117
+ ];
109
118
}
110
119
111
120
return $ data ;
@@ -122,88 +131,28 @@ public function setNormalizer(NormalizerInterface $normalizer): void
122
131
}
123
132
124
133
/**
125
- * Returns the content of the Hydra search property.
134
+ * @param IriTemplateMapping[] $mapping
126
135
*
127
- * @param FilterInterface[] $filters
136
+ * @return array<array<string, mixed>>
128
137
*/
129
- private function getSearch ( string $ resourceClass , array $ parts , array $ filters , ? Parameters $ parameters , string $ hydraPrefix ): array
138
+ private function convertMappingToArray ( array $ mapping ): array
130
139
{
131
- $ variables = [];
132
- $ mapping = [];
133
- foreach ($ filters as $ filter ) {
134
- foreach ($ filter ->getDescription ($ resourceClass ) as $ variable => $ data ) {
135
- $ variables [] = $ variable ;
136
- $ mapping [] = ['@type ' => 'IriTemplateMapping ' , 'variable ' => $ variable , 'property ' => $ data ['property ' ] ?? null , 'required ' => $ data ['required ' ] ?? false ];
137
- }
138
- }
139
-
140
- foreach ($ parameters ?? [] as $ key => $ parameter ) {
141
- // Each IriTemplateMapping maps a variable used in the template to a property
142
- if (!$ parameter instanceof QueryParameterInterface || false === $ parameter ->getHydra ()) {
143
- continue ;
144
- }
145
-
146
- if (($ filterId = $ parameter ->getFilter ()) && \is_string ($ filterId ) && ($ filter = $ this ->getFilter ($ filterId ))) {
147
- $ filterDescription = $ filter ->getDescription ($ resourceClass );
148
-
149
- foreach ($ filterDescription as $ variable => $ description ) {
150
- // // This is a practice induced by PHP and is not necessary when implementing URI template
151
- if (str_ends_with ((string ) $ variable , '[] ' )) {
152
- continue ;
153
- }
154
-
155
- if (!($ descriptionProperty = $ description ['property ' ] ?? null )) {
156
- continue ;
157
- }
158
-
159
- if (($ prop = $ parameter ->getProperty ()) && $ descriptionProperty !== $ prop ) {
160
- continue ;
161
- }
162
-
163
- // :property is a pattern allowed when defining parameters
164
- $ k = str_replace (':property ' , $ descriptionProperty , $ key );
165
- $ variable = str_replace ($ descriptionProperty , $ k , $ variable );
166
- $ variables [] = $ variable ;
167
- $ m = ['@type ' => 'IriTemplateMapping ' , 'variable ' => $ variable , 'property ' => $ descriptionProperty ];
168
- if (null !== ($ required = $ parameter ->getRequired () ?? $ description ['required ' ] ?? null )) {
169
- $ m ['required ' ] = $ required ;
170
- }
171
- $ mapping [] = $ m ;
172
- }
173
-
174
- if ($ filterDescription ) {
175
- continue ;
176
- }
140
+ $ convertedMapping = [];
141
+ foreach ($ mapping as $ m ) {
142
+ $ converted = [
143
+ '@type ' => 'IriTemplateMapping ' ,
144
+ 'variable ' => $ m ->getVariable (),
145
+ 'property ' => $ m ->getProperty (),
146
+ ];
147
+
148
+ if (null !== $ m ->isRequired ()) {
149
+ $ converted ['required ' ] = $ m ->isRequired ();
177
150
}
178
151
179
- if (str_contains ($ key , ':property ' ) && $ parameter ->getProperties ()) {
180
- $ required = $ parameter ->getRequired ();
181
- foreach ($ parameter ->getProperties () as $ prop ) {
182
- $ k = str_replace (':property ' , $ prop , $ key );
183
- $ m = ['@type ' => 'IriTemplateMapping ' , 'variable ' => $ k , 'property ' => $ prop ];
184
- $ variables [] = $ k ;
185
- if (null !== $ required ) {
186
- $ m ['required ' ] = $ required ;
187
- }
188
- $ mapping [] = $ m ;
189
- }
190
-
191
- continue ;
192
- }
193
-
194
- if (!($ property = $ parameter ->getProperty ())) {
195
- continue ;
196
- }
197
-
198
- $ m = ['@type ' => 'IriTemplateMapping ' , 'variable ' => $ key , 'property ' => $ property ];
199
- $ variables [] = $ key ;
200
- if (null !== ($ required = $ parameter ->getRequired ())) {
201
- $ m ['required ' ] = $ required ;
202
- }
203
- $ mapping [] = $ m ;
152
+ $ convertedMapping [] = $ converted ;
204
153
}
205
154
206
- return [ ' @type ' => $ hydraPrefix . ' IriTemplate ' , $ hydraPrefix . ' template ' => \sprintf ( ' %s{?%s} ' , $ parts [ ' path ' ], implode ( ' , ' , $ variables )), $ hydraPrefix . ' variableRepresentation ' => ' BasicRepresentation ' , $ hydraPrefix . ' mapping ' => $ mapping ] ;
155
+ return $ convertedMapping ;
207
156
}
208
157
209
158
/**
0 commit comments