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

api-platform / core / 6067528200

04 Sep 2023 12:12AM UTC coverage: 36.875% (-21.9%) from 58.794%
6067528200

Pull #5791

github

web-flow
Merge 64157e578 into d09cfc9d2
Pull Request #5791: fix: strip down any sql function name

3096 of 3096 new or added lines in 205 files covered. (100.0%)

9926 of 26918 relevant lines covered (36.87%)

6.5 hits per line

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

0.0
/src/Elasticsearch/Filter/OrderFilter.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\Elasticsearch\Filter;
15

16
use ApiPlatform\Metadata\Operation;
17
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
18
use ApiPlatform\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
19
use ApiPlatform\Metadata\ResourceClassResolverInterface;
20
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
21

22
/**
23
 * The order filter allows to [sort](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-sort.html) a collection against the given properties.
24
 *
25
 * Syntax: `?order[property]=<asc|desc>`.
26
 *
27
 * <CodeSelector>
28
 * ```php
29
 * <?php
30
 * // api/src/Entity/Book.php
31
 * use ApiPlatform\Metadata\ApiFilter;
32
 * use ApiPlatform\Metadata\ApiResource;
33
 * use ApiPlatform\Elasticsearch\Filter\OrderFilter;
34
 *
35
 * #[ApiResource]
36
 * #[ApiFilter(OrderFilter::class, properties: ['id', 'date'])]
37
 * class Book
38
 * {
39
 *     // ...
40
 * }
41
 * ```
42
 *
43
 * ```yaml
44
 * # config/services.yaml
45
 * services:
46
 *     book.order_filter:
47
 *         parent: 'api_platform.elasticsearch.order_filter'
48
 *         arguments: [ { id: ~, date: ~ } ]
49
 *         tags:  [ 'api_platform.filter' ]
50
 *         # The following are mandatory only if a _defaults section is defined with inverted values.
51
 *         # You may want to isolate filters in a dedicated file to avoid adding the following lines (by adding them in the defaults section)
52
 *         autowire: false
53
 *         autoconfigure: false
54
 *         public: false
55
 *
56
 * # api/config/api_platform/resources.yaml
57
 * resources:
58
 *     App\Entity\Book:
59
 *         - operations:
60
 *               ApiPlatform\Metadata\GetCollection:
61
 *                   filters: ['book.order_filter']
62
 * ```
63
 *
64
 * ```xml
65
 * <?xml version="1.0" encoding="UTF-8" ?>
66
 * <!-- api/config/services.xml -->
67
 * <?xml version="1.0" encoding="UTF-8" ?>
68
 * <container
69
 *         xmlns="http://symfony.com/schema/dic/services"
70
 *         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
71
 *         xsi:schemaLocation="http://symfony.com/schema/dic/services
72
 *         https://symfony.com/schema/dic/services/services-1.0.xsd">
73
 *     <services>
74
 *         <service id="book.order_filter" parent="api_platform.elasticsearch.order_filter">
75
 *             <argument type="collection">
76
 *                 <argument key="id"/>
77
 *                 <argument key="date"/>
78
 *             </argument>
79
 *             <tag name="api_platform.filter"/>
80
 *         </service>
81
 *     </services>
82
 * </container>
83
 * <!-- api/config/api_platform/resources.xml -->
84
 * <resources
85
 *         xmlns="https://api-platform.com/schema/metadata/resources-3.0"
86
 *         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
87
 *         xsi:schemaLocation="https://api-platform.com/schema/metadata/resources-3.0
88
 *         https://api-platform.com/schema/metadata/resources-3.0.xsd">
89
 *     <resource class="App\Entity\Book">
90
 *         <operations>
91
 *             <operation class="ApiPlatform\Metadata\GetCollection">
92
 *                 <filters>
93
 *                     <filter>book.order_filter</filter>
94
 *                 </filters>
95
 *             </operation>
96
 *         </operations>
97
 *     </resource>
98
 * </resources>
99
 * ```
100
 * </CodeSelector>
101
 *
102
 * Given that the collection endpoint is `/books`, you can filter books by ID and date in ascending or descending order: `/books?order[id]=asc&order[date]=desc`.
103
 *
104
 * @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-sort.html
105
 *
106
 * @experimental
107
 *
108
 * @author Baptiste Meyer <baptiste.meyer@gmail.com>
109
 */
110
final class OrderFilter extends AbstractFilter implements SortFilterInterface
111
{
112
    /**
113
     * {@inheritdoc}
114
     */
115
    public function __construct(PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, ResourceClassResolverInterface $resourceClassResolver, NameConverterInterface $nameConverter = null, private readonly string $orderParameterName = 'order', array $properties = null)
116
    {
117
        parent::__construct($propertyNameCollectionFactory, $propertyMetadataFactory, $resourceClassResolver, $nameConverter, $properties);
×
118
    }
119

120
    /**
121
     * {@inheritdoc}
122
     */
123
    public function apply(array $clauseBody, string $resourceClass, Operation $operation = null, array $context = []): array
124
    {
125
        if (!\is_array($properties = $context['filters'][$this->orderParameterName] ?? [])) {
×
126
            return $clauseBody;
×
127
        }
128

129
        $orders = [];
×
130

131
        foreach ($properties as $property => $direction) {
×
132
            [$type] = $this->getMetadata($resourceClass, $property);
×
133

134
            if (!$type) {
×
135
                continue;
×
136
            }
137

138
            if (empty($direction) && null !== $defaultDirection = $this->properties[$property] ?? null) {
×
139
                $direction = $defaultDirection;
×
140
            }
141

142
            if (!\in_array($direction = strtolower($direction), ['asc', 'desc'], true)) {
×
143
                continue;
×
144
            }
145

146
            $order = ['order' => $direction];
×
147

148
            if (null !== $nestedPath = $this->getNestedFieldPath($resourceClass, $property)) {
×
149
                $nestedPath = null === $this->nameConverter ? $nestedPath : $this->nameConverter->normalize($nestedPath, $resourceClass, null, $context);
×
150
                $order['nested'] = ['path' => $nestedPath];
×
151
            }
152

153
            $property = null === $this->nameConverter ? $property : $this->nameConverter->normalize($property, $resourceClass, null, $context);
×
154
            $orders[] = [$property => $order];
×
155
        }
156

157
        if (!$orders) {
×
158
            return $clauseBody;
×
159
        }
160

161
        return array_merge_recursive($clauseBody, $orders);
×
162
    }
163

164
    /**
165
     * {@inheritdoc}
166
     */
167
    public function getDescription(string $resourceClass): array
168
    {
169
        $description = [];
×
170

171
        foreach ($this->getProperties($resourceClass) as $property) {
×
172
            [$type] = $this->getMetadata($resourceClass, $property);
×
173

174
            if (!$type) {
×
175
                continue;
×
176
            }
177

178
            $description["$this->orderParameterName[$property]"] = [
×
179
                'property' => $property,
×
180
                'type' => 'string',
×
181
                'required' => false,
×
182
            ];
×
183
        }
184

185
        return $description;
×
186
    }
187
}
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