Skip to content

Commit 62a9cc8

Browse files
committed
fix(state)!: parameter default value overrides falsy value
1 parent 9bdbe83 commit 62a9cc8

File tree

5 files changed

+113
-128
lines changed

5 files changed

+113
-128
lines changed

features/doctrine/order_filter.feature

Lines changed: 0 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -241,65 +241,6 @@ Feature: Order filter on collections
241241
}
242242
"""
243243

244-
Scenario: Get collection ordered by default configured order on a string property and on which order filter has been enabled in whitelist mode with default descending order
245-
When I send a "GET" request to "/dummies?order[name]"
246-
Then the response status code should be 200
247-
And the response should be in JSON
248-
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
249-
And the JSON should be valid according to this schema:
250-
"""
251-
{
252-
"type": "object",
253-
"properties": {
254-
"@context": {"pattern": "^/contexts/Dummy$"},
255-
"@id": {"pattern": "^/dummies$"},
256-
"@type": {"pattern": "^hydra:Collection$"},
257-
"hydra:member": {
258-
"type": "array",
259-
"items": [
260-
{
261-
"type": "object",
262-
"properties": {
263-
"@id": {
264-
"type": "string",
265-
"pattern": "^/dummies/9$"
266-
}
267-
}
268-
},
269-
{
270-
"type": "object",
271-
"properties": {
272-
"@id": {
273-
"type": "string",
274-
"pattern": "^/dummies/8$"
275-
}
276-
}
277-
},
278-
{
279-
"type": "object",
280-
"properties": {
281-
"@id": {
282-
"type": "string",
283-
"pattern": "^/dummies/7$"
284-
}
285-
}
286-
}
287-
],
288-
"additionalItems": false,
289-
"maxItems": 3,
290-
"minItems": 3
291-
},
292-
"hydra:view": {
293-
"type": "object",
294-
"properties": {
295-
"@id": {"pattern": "^/dummies\\?order%5Bname%5D="},
296-
"@type": {"pattern": "^hydra:PartialCollectionView$"}
297-
}
298-
}
299-
}
300-
}
301-
"""
302-
303244
Scenario: Get collection ordered collection on several property keep the order
304245
# Adding 30 more data with the same name
305246
Given there are 30 dummy objects
@@ -539,65 +480,6 @@ Feature: Order filter on collections
539480
}
540481
"""
541482

542-
Scenario: Get a collection even if the order parameter is not well-formed
543-
When I send a "GET" request to "/dummies?sort=id&order=asc"
544-
Then the response status code should be 200
545-
And the response should be in JSON
546-
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
547-
And the JSON should be valid according to this schema:
548-
"""
549-
{
550-
"type": "object",
551-
"properties": {
552-
"@context": {"pattern": "^/contexts/Dummy$"},
553-
"@id": {"pattern": "^/dummies$"},
554-
"@type": {"pattern": "^hydra:Collection$"},
555-
"hydra:member": {
556-
"type": "array",
557-
"items": [
558-
{
559-
"type": "object",
560-
"properties": {
561-
"@id": {
562-
"type": "string",
563-
"pattern": "^/dummies/1$"
564-
}
565-
}
566-
},
567-
{
568-
"type": "object",
569-
"properties": {
570-
"@id": {
571-
"type": "string",
572-
"pattern": "^/dummies/2$"
573-
}
574-
}
575-
},
576-
{
577-
"type": "object",
578-
"properties": {
579-
"@id": {
580-
"type": "string",
581-
"pattern": "^/dummies/3$"
582-
}
583-
}
584-
}
585-
],
586-
"additionalItems": false,
587-
"maxItems": 3,
588-
"minItems": 3
589-
},
590-
"hydra:view": {
591-
"type": "object",
592-
"properties": {
593-
"@id": {"pattern": "^/dummies"},
594-
"@type": {"pattern": "^hydra:PartialCollectionView$"}
595-
}
596-
}
597-
}
598-
}
599-
"""
600-
601483
Scenario: Get collection ordered by a non valid properties and on which order filter has been enabled in whitelist mode
602484
When I send a "GET" request to "/dummies?order[alias]=asc"
603485
Then the response status code should be 200

src/Metadata/Parameter.php

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@
2121
abstract class Parameter
2222
{
2323
/**
24-
* @param (array<string, mixed>&array{type?: string, default?: string})|null $schema
25-
* @param array<string, mixed> $extraProperties
26-
* @param ParameterProviderInterface|callable|string|null $provider
27-
* @param list<string> $properties a list of properties this parameter applies to (works with the :property placeholder)
28-
* @param FilterInterface|string|null $filter
29-
* @param mixed $constraints an array of Symfony constraints, or an array of Laravel rules
30-
* @param Type $nativeType the PHP native type, we cast values to an array if its a CollectionType, if not and it's an array with a single value we use it (eg: HTTP Header)
31-
* @param ?bool $castToNativeType whether API Platform should cast your parameter to the nativeType declared
32-
* @param ?callable(mixed): mixed $castFn the closure used to cast your parameter, this gets called only when $castToNativeType is set
24+
* @param (array<string, mixed>&array{type?: string, default?: mixed})|null $schema
25+
* @param array<string, mixed> $extraProperties
26+
* @param ParameterProviderInterface|callable|string|null $provider
27+
* @param list<string> $properties a list of properties this parameter applies to (works with the :property placeholder)
28+
* @param FilterInterface|string|null $filter
29+
* @param mixed $constraints an array of Symfony constraints, or an array of Laravel rules
30+
* @param Type $nativeType the PHP native type, we cast values to an array if its a CollectionType, if not and it's an array with a single value we use it (eg: HTTP Header)
31+
* @param ?bool $castToNativeType whether API Platform should cast your parameter to the nativeType declared
32+
* @param ?callable(mixed): mixed $castFn the closure used to cast your parameter, this gets called only when $castToNativeType is set
3333
*/
3434
public function __construct(
3535
protected ?string $key = null,

src/State/Provider/ParameterProvider.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public function provide(Operation $operation, array $uriVariables = [], array $c
7979
unset($parameter->getExtraProperties()['_api_values']);
8080
}
8181

82-
if (($default = $parameter->getSchema()['default'] ?? false) && ($value instanceof ParameterNotFound || !$value)) {
82+
if (null !== ($default = $parameter->getSchema()['default'] ?? null) && $value instanceof ParameterNotFound) {
8383
$value = $default;
8484
}
8585

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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\Tests\Fixtures\TestBundle\ApiResource\Issue7354;
15+
16+
use ApiPlatform\Metadata\ApiResource;
17+
use ApiPlatform\Metadata\Get;
18+
use ApiPlatform\Metadata\Operation;
19+
use ApiPlatform\Metadata\QueryParameter;
20+
21+
#[ApiResource(
22+
operations: [
23+
new Get(
24+
normalizationContext: ['hydra_prefix' => false],
25+
uriTemplate: '/issue7354_boolean_query_parameters',
26+
parameters: [
27+
'booleanParameter' => new QueryParameter(
28+
schema: [
29+
'type' => 'boolean',
30+
'default' => true,
31+
],
32+
castToNativeType: true,
33+
),
34+
],
35+
provider: [self::class, 'provide'],
36+
),
37+
]
38+
)]
39+
class BooleanQueryParameter
40+
{
41+
public function __construct(public bool $booleanParameter)
42+
{
43+
}
44+
45+
public static function provide(Operation $operation): self
46+
{
47+
return new self($operation->getParameters()->get('booleanParameter')->getValue());
48+
}
49+
}

tests/Functional/Issue7354Test.php

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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\Tests\Functional;
15+
16+
use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
17+
use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\Issue7354\BooleanQueryParameter;
18+
use ApiPlatform\Tests\SetupClassResourcesTrait;
19+
20+
final class Issue7354Test extends ApiTestCase
21+
{
22+
use SetupClassResourcesTrait;
23+
24+
protected static ?bool $alwaysBootKernel = false;
25+
26+
/**
27+
* @return class-string[]
28+
*/
29+
public static function getResources(): array
30+
{
31+
return [BooleanQueryParameter::class];
32+
}
33+
34+
public function testBooleanQueryParameterDefaultOverride(): void
35+
{
36+
self::createClient()->request('GET', '/issue7354_boolean_query_parameters?booleanParameter=false');
37+
$this->assertResponseIsSuccessful();
38+
$this->assertJsonContains(['booleanParameter' => false]);
39+
}
40+
41+
public function testBooleanQueryParameterDefaultNotOverride(): void
42+
{
43+
self::createClient()->request('GET', '/issue7354_boolean_query_parameters?booleanParameter=true');
44+
$this->assertResponseIsSuccessful();
45+
$this->assertJsonContains(['booleanParameter' => true]);
46+
}
47+
48+
public function testBooleanQueryParameterDefaultValue(): void
49+
{
50+
self::createClient()->request('GET', '/issue7354_boolean_query_parameters');
51+
$this->assertResponseIsSuccessful();
52+
$this->assertJsonContains(['booleanParameter' => true]);
53+
}
54+
}

0 commit comments

Comments
 (0)