Completed
Push — master ( 29b346...1faa7f )
by Amrouche
19s
created

src/Bridge/Doctrine/Orm/Filter/RangeFilter.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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\Core\Bridge\Doctrine\Orm\Filter;
15
16
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
17
use ApiPlatform\Core\Exception\InvalidArgumentException;
18
use Doctrine\ORM\QueryBuilder;
19
20
/**
21
 * Filters the collection by range.
22
 *
23
 * @author Lee Siong Chan <[email protected]>
24
 */
25
class RangeFilter extends AbstractFilter
26
{
27
    const PARAMETER_BETWEEN = 'between';
28
    const PARAMETER_GREATER_THAN = 'gt';
29
    const PARAMETER_GREATER_THAN_OR_EQUAL = 'gte';
30
    const PARAMETER_LESS_THAN = 'lt';
31
    const PARAMETER_LESS_THAN_OR_EQUAL = 'lte';
32
33
    /**
34
     * {@inheritdoc}
35
     */
36 View Code Duplication
    public function getDescription(string $resourceClass): array
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
37
    {
38
        $description = [];
39
40
        $properties = $this->properties;
41
        if (null === $properties) {
42
            $properties = array_fill_keys($this->getClassMetadata($resourceClass)->getFieldNames(), null);
43
        }
44
45
        foreach ($properties as $property => $unused) {
46
            if (!$this->isPropertyMapped($property, $resourceClass)) {
47
                continue;
48
            }
49
50
            $description += $this->getFilterDescription($property, self::PARAMETER_BETWEEN);
51
            $description += $this->getFilterDescription($property, self::PARAMETER_GREATER_THAN);
52
            $description += $this->getFilterDescription($property, self::PARAMETER_GREATER_THAN_OR_EQUAL);
53
            $description += $this->getFilterDescription($property, self::PARAMETER_LESS_THAN);
54
            $description += $this->getFilterDescription($property, self::PARAMETER_LESS_THAN_OR_EQUAL);
55
        }
56
57
        return $description;
58
    }
59
60
    /**
61
     * {@inheritdoc}
62
     */
63
    protected function filterProperty(string $property, $values, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null)
64
    {
65 View Code Duplication
        if (
66
            !is_array($values) ||
67
            !$this->isPropertyEnabled($property, $resourceClass) ||
68
            !$this->isPropertyMapped($property, $resourceClass)
69
        ) {
70
            return;
71
        }
72
73
        $alias = 'o';
74
        $field = $property;
75
76 View Code Duplication
        if ($this->isPropertyNested($property, $resourceClass)) {
77
            list($alias, $field) = $this->addJoinsForNestedProperty($property, $alias, $queryBuilder, $queryNameGenerator, $resourceClass);
78
        }
79
80
        foreach ($values as $operator => $value) {
81
            $this->addWhere(
82
                $queryBuilder,
83
                $queryNameGenerator,
84
                $alias,
85
                $field,
86
                $operator,
87
                $value
88
            );
89
        }
90
    }
91
92
    /**
93
     * Adds the where clause according to the operator.
94
     *
95
     * @param QueryBuilder                $queryBuilder
96
     * @param QueryNameGeneratorInterface $queryNameGenerator
97
     * @param string                      $alias
98
     * @param string                      $field
99
     * @param string                      $operator
100
     * @param string                      $value
101
     */
102
    protected function addWhere(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, $alias, $field, $operator, $value)
103
    {
104
        $valueParameter = $queryNameGenerator->generateParameterName($field);
105
106
        switch ($operator) {
107
            case self::PARAMETER_BETWEEN:
108
                $rangeValue = explode('..', $value);
109
110
                if (2 !== count($rangeValue)) {
111
                    $this->logger->notice('Invalid filter ignored', [
112
                        'exception' => new InvalidArgumentException(sprintf('Invalid format for "[%s]", expected "<min>..<max>"', $operator)),
113
                    ]);
114
115
                    return;
116
                }
117
118
                if (!is_numeric($rangeValue[0]) || !is_numeric($rangeValue[1])) {
119
                    $this->logger->notice('Invalid filter ignored', [
120
                        'exception' => new InvalidArgumentException(sprintf('Invalid values for "[%s]" range, expected numbers', $operator)),
121
                    ]);
122
123
                    return;
124
                }
125
126
                $queryBuilder
127
                    ->andWhere(sprintf('%1$s.%2$s BETWEEN :%3$s_1 AND :%3$s_2', $alias, $field, $valueParameter))
128
                    ->setParameter(sprintf('%s_1', $valueParameter), $rangeValue[0])
129
                    ->setParameter(sprintf('%s_2', $valueParameter), $rangeValue[1]);
130
131
                break;
132 View Code Duplication
            case self::PARAMETER_GREATER_THAN:
133
                if (!is_numeric($value)) {
134
                    $this->logger->notice('Invalid filter ignored', [
135
                        'exception' => new InvalidArgumentException(sprintf('Invalid value for "[%s]", expected number', $operator)),
136
                    ]);
137
138
                    return;
139
                }
140
141
                $queryBuilder
142
                    ->andWhere(sprintf('%s.%s > :%s', $alias, $field, $valueParameter))
143
                    ->setParameter($valueParameter, $value);
144
145
                break;
146 View Code Duplication
            case self::PARAMETER_GREATER_THAN_OR_EQUAL:
147
                if (!is_numeric($value)) {
148
                    $this->logger->notice('Invalid filter ignored', [
149
                        'exception' => new InvalidArgumentException(sprintf('Invalid value for "[%s]", expected number', $operator)),
150
                    ]);
151
152
                    return;
153
                }
154
155
                $queryBuilder
156
                    ->andWhere(sprintf('%s.%s >= :%s', $alias, $field, $valueParameter))
157
                    ->setParameter($valueParameter, $value);
158
159
                break;
160 View Code Duplication
            case self::PARAMETER_LESS_THAN:
161
                if (!is_numeric($value)) {
162
                    $this->logger->notice('Invalid filter ignored', [
163
                        'exception' => new InvalidArgumentException(sprintf('Invalid value for "[%s]", expected number', $operator)),
164
                    ]);
165
166
                    return;
167
                }
168
169
                $queryBuilder
170
                    ->andWhere(sprintf('%s.%s < :%s', $alias, $field, $valueParameter))
171
                    ->setParameter($valueParameter, $value);
172
173
                break;
174 View Code Duplication
            case self::PARAMETER_LESS_THAN_OR_EQUAL:
175
                if (!is_numeric($value)) {
176
                    $this->logger->notice('Invalid filter ignored', [
177
                        'exception' => new InvalidArgumentException(sprintf('Invalid value for "[%s]", expected number', $operator)),
178
                    ]);
179
180
                    return;
181
                }
182
183
                $queryBuilder
184
                    ->andWhere(sprintf('%s.%s <= :%s', $alias, $field, $valueParameter))
185
                    ->setParameter($valueParameter, $value);
186
187
                break;
188
        }
189
    }
190
191
    /**
192
     * Gets filter description.
193
     *
194
     * @param string $fieldName
195
     * @param string $operator
196
     *
197
     * @return array
198
     */
199
    protected function getFilterDescription(string $fieldName, string $operator): array
200
    {
201
        return [
202
            sprintf('%s[%s]', $fieldName, $operator) => [
203
                'property' => $fieldName,
204
                'type' => 'string',
205
                'required' => false,
206
            ],
207
        ];
208
    }
209
}
210