Passed
Push — master ( 8bd912...d93388 )
by Alan
06:58 queued 02:20
created

Bridge/Doctrine/Common/Filter/RangeFilterTrait.php (11 issues)

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\Common\Filter;
15
16
use ApiPlatform\Core\Bridge\Doctrine\Common\PropertyHelperTrait;
17
use ApiPlatform\Core\Exception\InvalidArgumentException;
18
use Psr\Log\LoggerInterface;
19
20
/**
21
 * Trait for filtering the collection by range.
22
 *
23
 * @author Lee Siong Chan <[email protected]>
24
 * @author Alan Poulain <[email protected]>
25
 */
26
trait RangeFilterTrait
27
{
28
    use PropertyHelperTrait;
29
30
    /**
31
     * {@inheritdoc}
32
     */
33
    public function getDescription(string $resourceClass): array
34
    {
35
        $description = [];
36
37
        $properties = $this->getProperties();
38
        if (null === $properties) {
39
            $properties = array_fill_keys($this->getClassMetadata($resourceClass)->getFieldNames(), null);
40
        }
41
42
        foreach ($properties as $property => $unused) {
43
            if (!$this->isPropertyMapped($property, $resourceClass)) {
44
                continue;
45
            }
46
47
            $description += $this->getFilterDescription($property, self::PARAMETER_BETWEEN);
0 ignored issues
show
The constant ApiPlatform\Core\Bridge\...rait::PARAMETER_BETWEEN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
48
            $description += $this->getFilterDescription($property, self::PARAMETER_GREATER_THAN);
0 ignored issues
show
The constant ApiPlatform\Core\Bridge\...:PARAMETER_GREATER_THAN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
49
            $description += $this->getFilterDescription($property, self::PARAMETER_GREATER_THAN_OR_EQUAL);
0 ignored issues
show
The constant ApiPlatform\Core\Bridge\...R_GREATER_THAN_OR_EQUAL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
50
            $description += $this->getFilterDescription($property, self::PARAMETER_LESS_THAN);
0 ignored issues
show
The constant ApiPlatform\Core\Bridge\...it::PARAMETER_LESS_THAN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
51
            $description += $this->getFilterDescription($property, self::PARAMETER_LESS_THAN_OR_EQUAL);
0 ignored issues
show
The constant ApiPlatform\Core\Bridge\...ETER_LESS_THAN_OR_EQUAL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
52
        }
53
54
        return $description;
55
    }
56
57
    abstract protected function getProperties(): ?array;
58
59
    abstract protected function getLogger(): LoggerInterface;
60
61
    abstract protected function normalizePropertyName($property);
62
63
    /**
64
     * Gets filter description.
65
     */
66
    protected function getFilterDescription(string $fieldName, string $operator): array
67
    {
68
        $propertyName = $this->normalizePropertyName($fieldName);
69
70
        return [
71
            sprintf('%s[%s]', $propertyName, $operator) => [
72
                'property' => $propertyName,
73
                'type' => 'string',
74
                'required' => false,
75
            ],
76
        ];
77
    }
78
79
    private function normalizeValues(array $values, string $property): ?array
80
    {
81
        $operators = [self::PARAMETER_BETWEEN, self::PARAMETER_GREATER_THAN, self::PARAMETER_GREATER_THAN_OR_EQUAL, self::PARAMETER_LESS_THAN, self::PARAMETER_LESS_THAN_OR_EQUAL];
0 ignored issues
show
The constant ApiPlatform\Core\Bridge\...R_GREATER_THAN_OR_EQUAL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant ApiPlatform\Core\Bridge\...ETER_LESS_THAN_OR_EQUAL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant ApiPlatform\Core\Bridge\...:PARAMETER_GREATER_THAN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant ApiPlatform\Core\Bridge\...rait::PARAMETER_BETWEEN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The constant ApiPlatform\Core\Bridge\...it::PARAMETER_LESS_THAN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
82
83
        foreach ($values as $operator => $value) {
84
            if (!\in_array($operator, $operators, true)) {
85
                unset($values[$operator]);
86
            }
87
        }
88
89
        if (empty($values)) {
90
            $this->getLogger()->notice('Invalid filter ignored', [
91
                'exception' => new InvalidArgumentException(sprintf('At least one valid operator ("%s") is required for "%s" property', implode('", "', $operators), $property)),
92
            ]);
93
94
            return null;
95
        }
96
97
        return $values;
98
    }
99
100
    /**
101
     * Normalize the values array for between operator.
102
     */
103
    private function normalizeBetweenValues(array $values): ?array
104
    {
105
        if (2 !== \count($values)) {
106
            $this->getLogger()->notice('Invalid filter ignored', [
107
                'exception' => new InvalidArgumentException(sprintf('Invalid format for "[%s]", expected "<min>..<max>"', self::PARAMETER_BETWEEN)),
0 ignored issues
show
The constant ApiPlatform\Core\Bridge\...rait::PARAMETER_BETWEEN was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
108
            ]);
109
110
            return null;
111
        }
112
113
        if (!is_numeric($values[0]) || !is_numeric($values[1])) {
114
            $this->getLogger()->notice('Invalid filter ignored', [
115
                'exception' => new InvalidArgumentException(sprintf('Invalid values for "[%s]" range, expected numbers', self::PARAMETER_BETWEEN)),
116
            ]);
117
118
            return null;
119
        }
120
121
        return [$values[0] + 0, $values[1] + 0]; // coerce to the right types.
122
    }
123
124
    /**
125
     * Normalize the value.
126
     *
127
     * @return int|float|null
128
     */
129
    private function normalizeValue(string $value, string $operator)
130
    {
131
        if (!is_numeric($value)) {
132
            $this->getLogger()->notice('Invalid filter ignored', [
133
                'exception' => new InvalidArgumentException(sprintf('Invalid value for "[%s]", expected number', $operator)),
134
            ]);
135
136
            return null;
137
        }
138
139
        return $value + 0; // coerce $value to the right type.
140
    }
141
}
142