@@ -283,6 +283,47 @@ public function testParameterFactoryWithLimitedProperties(): void
283283 $ this ->assertSame (['name ' ], $ param ->getProperties ());
284284 }
285285
286+ public function testQueryParameterFromPropertyAttributes (): void
287+ {
288+ $ nameCollection = $ this ->createStub (PropertyNameCollectionFactoryInterface::class);
289+ $ nameCollection ->method ('create ' )->willReturn (new PropertyNameCollection (['id ' , 'name ' , 'isActive ' ]));
290+
291+ $ propertyMetadata = $ this ->createStub (PropertyMetadataFactoryInterface::class);
292+ $ propertyMetadata ->method ('create ' )->willReturn (
293+ new ApiProperty (readable: true ),
294+ );
295+
296+ $ filterLocator = $ this ->createStub (ContainerInterface::class);
297+ $ filterLocator ->method ('has ' )->willReturn (false );
298+
299+ $ parameterFactory = new ParameterResourceMetadataCollectionFactory (
300+ $ nameCollection ,
301+ $ propertyMetadata ,
302+ new AttributesResourceMetadataCollectionFactory (),
303+ $ filterLocator
304+ );
305+
306+ $ resourceMetadataCollection = $ parameterFactory ->create (ParameterOnProperties::class);
307+ $ operation = $ resourceMetadataCollection ->getOperation (forceCollection: true );
308+ $ parameters = $ operation ->getParameters ();
309+
310+ $ this ->assertInstanceOf (Parameters::class, $ parameters );
311+
312+ $ this ->assertTrue ($ parameters ->has ('search ' ));
313+ $ searchParam = $ parameters ->get ('search ' , QueryParameter::class);
314+ $ this ->assertInstanceOf (QueryParameter::class, $ searchParam );
315+ $ this ->assertSame ('search ' , $ searchParam ->getKey ());
316+ $ this ->assertSame ('name ' , $ searchParam ->getProperty ());
317+ $ this ->assertSame ('Search by name ' , $ searchParam ->getDescription ());
318+
319+ $ this ->assertTrue ($ parameters ->has ('filter_active ' ));
320+ $ filterParam = $ parameters ->get ('filter_active ' , QueryParameter::class);
321+ $ this ->assertInstanceOf (QueryParameter::class, $ filterParam );
322+ $ this ->assertSame ('filter_active ' , $ filterParam ->getKey ());
323+ $ this ->assertSame ('isActive ' , $ filterParam ->getProperty ());
324+ $ this ->assertSame ('Filter by active status ' , $ filterParam ->getDescription ());
325+ }
326+
286327 public function testQueryParameterFromPropertyAttributeThrowsExceptionWhenPropertyMismatch (): void
287328 {
288329 $ this ->expectException (RuntimeException::class);
@@ -565,6 +606,16 @@ class NestedTestVariation
565606 public ?string $ variantName = null ;
566607}
567608
609+ #[ApiResource]
610+ class ParameterOnProperties
611+ {
612+ #[QueryParameter(key: 'search ' , description: 'Search by name ' )]
613+ public string $ name = '' ;
614+
615+ #[QueryParameter(key: 'filter_active ' , description: 'Filter by active status ' )]
616+ public bool $ isActive = true ;
617+ }
618+
568619#[ApiResource]
569620class ParameterOnPropertiesMismatchException
570621{
0 commit comments