• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

api-platform / core / 3713134090

pending completion
3713134090

Pull #5254

github

GitHub
Merge b2ec54b3c into ac711530f
Pull Request #5254: [OpenApi] Add ApiResource::openapi and deprecate openapiContext

197 of 197 new or added lines in 5 files covered. (100.0%)

10372 of 12438 relevant lines covered (83.39%)

11.97 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.51
/src/Serializer/Filter/PropertyFilter.php
1
<?php
2

3
/*
4
 * This file is part of the API Platform project.
5
 *
6
 * (c) Kévin Dunglas <dunglas@gmail.com>
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\Serializer\Filter;
15

16
use Symfony\Component\HttpFoundation\Request;
17
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
18
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
19

20
/**
21
 * Property filter.
22
 *
23
 * @author Baptiste Meyer <baptiste.meyer@gmail.com>
24
 */
25
final class PropertyFilter implements FilterInterface
26
{
27
    private ?array $whitelist;
28

29
    public function __construct(private readonly string $parameterName = 'properties', private readonly bool $overrideDefaultProperties = false, array $whitelist = null, private readonly ?NameConverterInterface $nameConverter = null)
30
    {
31
        $this->whitelist = null === $whitelist ? null : $this->formatWhitelist($whitelist);
26✔
32
    }
33

34
    /**
35
     * {@inheritdoc}
36
     */
37
    public function apply(Request $request, bool $normalization, array $attributes, array &$context): void
38
    {
39
        if (null !== $propertyAttribute = $request->attributes->get('_api_filter_property')) {
22✔
40
            $properties = $propertyAttribute;
×
41
        } elseif (\array_key_exists($this->parameterName, $commonAttribute = $request->attributes->get('_api_filters', []))) {
22✔
42
            $properties = $commonAttribute[$this->parameterName];
2✔
43
        } else {
44
            $properties = $request->query->all()[$this->parameterName] ?? null;
20✔
45
        }
46

47
        if (!\is_array($properties)) {
22✔
48
            return;
8✔
49
        }
50

51
        $properties = $this->denormalizeProperties($properties);
14✔
52

53
        if (null !== $this->whitelist) {
14✔
54
            $properties = $this->getProperties($properties, $this->whitelist);
8✔
55
        }
56

57
        if (!$this->overrideDefaultProperties && isset($context[AbstractNormalizer::ATTRIBUTES])) {
14✔
58
            $properties = array_merge_recursive((array) $context[AbstractNormalizer::ATTRIBUTES], $properties);
10✔
59
        }
60

61
        $context[AbstractNormalizer::ATTRIBUTES] = $properties;
14✔
62
    }
63

64
    /**
65
     * {@inheritdoc}
66
     */
67
    public function getDescription(string $resourceClass): array
68
    {
69
        $example = sprintf('%1$s[]={propertyName}&%1$s[]={anotherPropertyName}&%1$s[{nestedPropertyParent}][]={nestedProperty}',
6✔
70
            $this->parameterName
6✔
71
        );
6✔
72

73
        return [
6✔
74
            "$this->parameterName[]" => [
6✔
75
                'property' => null,
6✔
76
                'type' => 'string',
6✔
77
                'is_collection' => true,
6✔
78
                'required' => false,
6✔
79
                'swagger' => [
6✔
80
                    'description' => 'Allows you to reduce the response to contain only the properties you need. If your desired property is nested, you can address it using nested arrays. Example: '.$example,
6✔
81
                    'name' => "$this->parameterName[]",
6✔
82
                    'type' => 'array',
6✔
83
                    'items' => [
6✔
84
                        'type' => 'string',
6✔
85
                    ],
6✔
86
                ],
6✔
87
                'openapi' => [
6✔
88
                    'description' => 'Allows you to reduce the response to contain only the properties you need. If your desired property is nested, you can address it using nested arrays. Example: '.$example,
6✔
89
                    'name' => "$this->parameterName[]",
6✔
90
                    'schema' => [
6✔
91
                        'type' => 'array',
6✔
92
                        'items' => [
6✔
93
                            'type' => 'string',
6✔
94
                        ],
6✔
95
                    ],
6✔
96
                ],
6✔
97
            ],
6✔
98
        ];
6✔
99
    }
100

101
    /**
102
     * Generate an array of whitelist properties to match the format that properties
103
     * will have in the request.
104
     *
105
     * @param array $whitelist the whitelist to format
106
     *
107
     * @return array An array containing the whitelist ready to match request parameters
108
     */
109
    private function formatWhitelist(array $whitelist): array
110
    {
111
        if (array_values($whitelist) === $whitelist) {
11✔
112
            return $whitelist;
9✔
113
        }
114
        foreach ($whitelist as $name => $value) {
5✔
115
            if (null === $value) {
5✔
116
                unset($whitelist[$name]);
5✔
117
                $whitelist[] = $name;
5✔
118
            }
119
        }
120

121
        return $whitelist;
5✔
122
    }
123

124
    private function getProperties(array $properties, array $whitelist = null): array
125
    {
126
        $whitelist ??= $this->whitelist;
8✔
127
        $result = [];
8✔
128

129
        foreach ($properties as $key => $value) {
8✔
130
            if (is_numeric($key)) {
8✔
131
                if (\in_array($propertyName = $this->denormalizePropertyName($value), $whitelist, true)) {
8✔
132
                    $result[] = $propertyName;
6✔
133
                }
134

135
                continue;
8✔
136
            }
137

138
            if (\is_array($value) && isset($whitelist[$key]) && $recursiveResult = $this->getProperties($value, $whitelist[$key])) {
4✔
139
                $result[$this->denormalizePropertyName($key)] = $recursiveResult;
2✔
140
            }
141
        }
142

143
        return $result;
8✔
144
    }
145

146
    private function denormalizeProperties(array $properties): array
147
    {
148
        if (null === $this->nameConverter || !$properties) {
14✔
149
            return $properties;
7✔
150
        }
151

152
        $result = [];
7✔
153
        foreach ($properties as $key => $value) {
7✔
154
            $result[$this->denormalizePropertyName((string) $key)] = \is_array($value) ? $this->denormalizeProperties($value) : $this->denormalizePropertyName($value);
7✔
155
        }
156

157
        return $result;
7✔
158
    }
159

160
    private function denormalizePropertyName($property): string
161
    {
162
        return null !== $this->nameConverter ? $this->nameConverter->denormalize($property) : $property;
11✔
163
    }
164
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc