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