1818use ApiPlatform \Metadata \Parameter ;
1919use ApiPlatform \Metadata \Parameters ;
2020use ApiPlatform \Metadata \Resource \ResourceMetadataCollection ;
21- use ApiPlatform \OpenApi ;
21+ use ApiPlatform \OpenApi \ Model \ Parameter as OpenApiParameter ;
2222use ApiPlatform \Serializer \Filter \FilterInterface as SerializerFilterInterface ;
2323use Psr \Container \ContainerInterface ;
24+ use Symfony \Component \Validator \Constraints \Choice ;
25+ use Symfony \Component \Validator \Constraints \Count ;
26+ use Symfony \Component \Validator \Constraints \DivisibleBy ;
27+ use Symfony \Component \Validator \Constraints \GreaterThan ;
28+ use Symfony \Component \Validator \Constraints \GreaterThanOrEqual ;
29+ use Symfony \Component \Validator \Constraints \Length ;
30+ use Symfony \Component \Validator \Constraints \LessThan ;
31+ use Symfony \Component \Validator \Constraints \LessThanOrEqual ;
32+ use Symfony \Component \Validator \Constraints \NotBlank ;
33+ use Symfony \Component \Validator \Constraints \NotNull ;
34+ use Symfony \Component \Validator \Constraints \Regex ;
35+ use Symfony \Component \Validator \Constraints \Unique ;
36+ use Symfony \Component \Validator \Validator \ValidatorInterface ;
2437
2538/**
2639 * Prepares Parameters documentation by reading its filter details and declaring an OpenApi parameter.
@@ -96,20 +109,28 @@ private function setDefaults(string $key, Parameter $parameter, string $resource
96109 $ parameter = $ parameter ->withSchema ($ schema );
97110 }
98111
112+ if (null === $ parameter ->getProperty () && ($ property = $ description [$ key ]['property ' ] ?? null )) {
113+ $ parameter = $ parameter ->withProperty ($ property );
114+ }
115+
116+ if (null === $ parameter ->getRequired () && ($ required = $ description [$ key ]['required ' ] ?? null )) {
117+ $ parameter = $ parameter ->withRequired ($ required );
118+ }
119+
99120 if (null === $ parameter ->getOpenApi () && $ openApi = $ description [$ key ]['openapi ' ] ?? null ) {
100- if ($ openApi instanceof OpenApi \ Model \Parameter ) {
121+ if ($ openApi instanceof OpenApiParameter ) {
101122 $ parameter = $ parameter ->withOpenApi ($ openApi );
102- }
103-
104- if ( \is_array ( $ openApi )) {
105- $ parameter = $ parameter ->withOpenApi (new OpenApi \ Model \ Parameter (
123+ } elseif ( \is_array ( $ openApi )) {
124+ // @phpstan-ignore-next-line
125+ $ schema = $ schema ?? $ openapi [ ' schema ' ] ?? [];
126+ $ parameter = $ parameter ->withOpenApi (new OpenApiParameter (
106127 $ key ,
107128 $ parameter instanceof HeaderParameterInterface ? 'header ' : 'query ' ,
108129 $ description [$ key ]['description ' ] ?? '' ,
109130 $ description [$ key ]['required ' ] ?? $ openApi ['required ' ] ?? false ,
110131 $ openApi ['deprecated ' ] ?? false ,
111132 $ openApi ['allowEmptyValue ' ] ?? true ,
112- $ schema ?? $ openApi [ ' schema ' ] ?? [] ,
133+ $ schema ,
113134 $ openApi ['style ' ] ?? null ,
114135 $ openApi ['explode ' ] ?? ('array ' === ($ schema ['type ' ] ?? null )),
115136 $ openApi ['allowReserved ' ] ?? false ,
@@ -121,6 +142,76 @@ private function setDefaults(string $key, Parameter $parameter, string $resource
121142 }
122143 }
123144
145+ $ schema = $ parameter ->getSchema () ?? $ parameter ->getOpenApi ()?->getSchema();
146+
147+ // Only add validation if the Symfony Validator is installed
148+ if (interface_exists (ValidatorInterface::class) && !$ parameter ->getConstraints ()) {
149+ $ parameter = $ this ->addSchemaValidation ($ parameter , $ schema , $ parameter ->getRequired () ?? $ description ['required ' ] ?? false , $ parameter ->getOpenApi ());
150+ }
151+
124152 return $ parameter ;
125153 }
154+
155+ private function addSchemaValidation (Parameter $ parameter , ?array $ schema = null , bool $ required = false , ?OpenApiParameter $ openApi = null ): Parameter
156+ {
157+ $ assertions = [];
158+
159+ if ($ required ) {
160+ $ assertions [] = new NotNull (message: sprintf ('The parameter "%s" is required. ' , $ parameter ->getKey ()));
161+ }
162+
163+ if (isset ($ schema ['exclusiveMinimum ' ])) {
164+ $ assertions [] = new GreaterThan (value: $ schema ['exclusiveMinimum ' ]);
165+ }
166+
167+ if (isset ($ schema ['exclusiveMaximum ' ])) {
168+ $ assertions [] = new LessThan (value: $ schema ['exclusiveMaximum ' ]);
169+ }
170+
171+ if (isset ($ schema ['minimum ' ])) {
172+ $ assertions [] = new GreaterThanOrEqual (value: $ schema ['minimum ' ]);
173+ }
174+
175+ if (isset ($ schema ['maximum ' ])) {
176+ $ assertions [] = new LessThanOrEqual (value: $ schema ['maximum ' ]);
177+ }
178+
179+ if (isset ($ schema ['pattern ' ])) {
180+ $ assertions [] = new Regex ($ schema ['pattern ' ]);
181+ }
182+
183+ if (isset ($ schema ['maxLength ' ]) || isset ($ schema ['minLength ' ])) {
184+ $ assertions [] = new Length (min: $ schema ['minLength ' ] ?? null , max: $ schema ['maxLength ' ] ?? null );
185+ }
186+
187+ if (isset ($ schema ['minItems ' ]) || isset ($ schema ['maxItems ' ])) {
188+ $ assertions [] = new Count (min: $ schema ['minItems ' ] ?? null , max: $ schema ['maxItems ' ] ?? null );
189+ }
190+
191+ if (isset ($ schema ['multipleOf ' ])) {
192+ $ assertions [] = new DivisibleBy (value: $ schema ['multipleOf ' ]);
193+ }
194+
195+ if ($ schema ['uniqueItems ' ] ?? false ) {
196+ $ assertions [] = new Unique ();
197+ }
198+
199+ if (isset ($ schema ['enum ' ])) {
200+ $ assertions [] = new Choice (choices: $ schema ['enum ' ]);
201+ }
202+
203+ if (false === $ openApi ?->getAllowEmptyValue()) {
204+ $ assertions [] = new NotBlank (allowNull: !$ required );
205+ }
206+
207+ if (!$ assertions ) {
208+ return $ parameter ;
209+ }
210+
211+ if (1 === \count ($ assertions )) {
212+ return $ parameter ->withConstraints ($ assertions [0 ]);
213+ }
214+
215+ return $ parameter ->withConstraints ($ assertions );
216+ }
126217}
0 commit comments