FilterUriManager::getAppliedFilters()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace BenTools\OpenCubes\Component\Filter;
4
5
use BenTools\OpenCubes\Component\Filter\Model\CollectionFilter;
6
use BenTools\OpenCubes\Component\Filter\Model\CompositeFilter;
7
use BenTools\OpenCubes\Component\Filter\Model\Filter;
8
use BenTools\OpenCubes\Component\Filter\Model\RangeFilter;
9
use BenTools\OpenCubes\Component\Filter\Model\SimpleFilter;
10
use BenTools\OpenCubes\Component\Filter\Model\StringMatchFilter;
11
use BenTools\OpenCubes\Component\Pager\PagerUriManager;
12
use BenTools\OpenCubes\Component\Pager\PagerUriManagerInterface;
13
use BenTools\OpenCubes\OptionsTrait;
14
use Psr\Http\Message\UriInterface;
15
use Symfony\Component\OptionsResolver\Exception\NoSuchOptionException;
16
use Symfony\Component\OptionsResolver\OptionsResolver;
17
use function BenTools\QueryString\query_string;
18
use function BenTools\QueryString\withoutNumericIndices;
19
20
final class FilterUriManager implements FilterUriManagerInterface
21
{
22
    use OptionsTrait;
23
24
    public const OPT_FILTER_QUERY_PARAM = 'query_param';
25
    public const OPT_DEFAULT_COLLECTION_SATISFIED_BY = 'default_collection_satisfied_by';
26
    public const OPT_DEFAULT_COMPOSITE_SATISFIED_BY = 'default_composite_satisfied_by';
27
28
    /**
29
     * @var PagerUriManager
30
     */
31
    private $pagerUriManager;
32
33
    /**
34
     * SortUriManager constructor.
35
     * @param array $options
36
     * @throws \Symfony\Component\OptionsResolver\Exception\AccessException
37
     * @throws \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
38
     * @throws \Symfony\Component\OptionsResolver\Exception\MissingOptionsException
39
     * @throws \Symfony\Component\OptionsResolver\Exception\NoSuchOptionException
40
     * @throws \Symfony\Component\OptionsResolver\Exception\OptionDefinitionException
41
     * @throws \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException
42
     */
43
    public function __construct(array $options = [], PagerUriManagerInterface $pagerUriManager = null)
44
    {
45
        $optionsResolver = new OptionsResolver();
46
        $optionsResolver->setDefaults([
47
            self::OPT_FILTER_QUERY_PARAM              => 'filters',
48
            self::OPT_DEFAULT_COLLECTION_SATISFIED_BY => CollectionFilter::SATISFIED_BY_ANY,
49
            self::OPT_DEFAULT_COMPOSITE_SATISFIED_BY  => CompositeFilter::SATISFIED_BY_ALL,
50
        ]);
51
52
        $this->options = $optionsResolver->resolve($options);
53
        $this->pagerUriManager = $pagerUriManager ?? new PagerUriManager();
0 ignored issues
show
Documentation Bug introduced by
$pagerUriManager ?? new ...Pager\PagerUriManager() is of type object<BenTools\OpenCube...gerUriManagerInterface>, but the property $pagerUriManager was declared to be of type object<BenTools\OpenCube...\Pager\PagerUriManager>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
54
    }
55
56
    /**
57
     * @inheritDoc
58
     */
59
    public function getAppliedFilters(UriInterface $uri): array
60
    {
61
        $qs = query_string($uri);
62
63
        return (array) $qs->getParam($this->getOption(self::OPT_FILTER_QUERY_PARAM));
64
    }
65
66
    /**
67
     * @inheritDoc
68
     */
69
    public function buildApplyFilterUrl(UriInterface $uri, Filter $filter, $value = null): UriInterface
70
    {
71
        $uri = $this->pagerUriManager->buildPageUri($uri, 1);
72
        $qs = query_string($uri);
73
        $currentFilters = $qs->getParam($this->getOption(self::OPT_FILTER_QUERY_PARAM)) ?? [];
74
75
        if ($filter instanceof CollectionFilter) {
76
            $values = func_num_args() > 2 ? (array) $value : $filter->getValues();
77
            if ($filter->getSatisfiedBy() !== $this->getOption(self::OPT_DEFAULT_COLLECTION_SATISFIED_BY)) {
78
                $values = [$filter->getSatisfiedBy() => $values];
79
            }
80
            $values = $filter->isNegated() ? ['NOT' => $values] : $values;
81
            $currentFilters[$filter->getField()] = $values;
82
        }
83
84
        if ($filter instanceof SimpleFilter) {
85
            $value = func_num_args() > 2 ? $value : $filter->getValue();
86
            $currentFilters[$filter->getField()] = $filter->isNegated() ? ['NOT' => $value] : $value;
87
        }
88
89
        if ($filter instanceof RangeFilter) {
90
            $value = func_num_args() > 2 ? (array) $value : [$filter->getLeft(), $filter->getRight()];
91
            $normalizedvalue = sprintf('[%s TO %s]', $value[0] ?? '*', $value[1] ?? '*');
92
            $currentFilters[$filter->getField()] = $filter->isNegated() ? ['NOT' => $normalizedvalue] : $normalizedvalue;
93
        }
94
95
        if ($filter instanceof StringMatchFilter) {
96
            $value = func_num_args() > 2 ? $value : $filter->getValue();
97
            $normalizedvalue = [$filter->getOperator() => $value];
98
            $currentFilters[$filter->getField()] = $filter->isNegated() ? ['NOT' => $normalizedvalue] : $normalizedvalue;
99
        }
100
101
        if ($filter instanceof CompositeFilter) {
102
            $parts = [$currentFilters[$filter->getField()] ?? []];
103
            foreach ($filter->getFilters() as $subFilter) {
104
                $subFilterValue = (array) (query_string($this->buildApplyFilterUrl($uri, $subFilter))->getParam($this->getOption(self::OPT_FILTER_QUERY_PARAM), $subFilter->getField()) ?? []);
105
                $subFilterValue = [$filter->getSatisfiedBy() => $subFilterValue];
106
                if ($filter->isNegated()) {
107
                    $subFilterValue = ['NOT' => $subFilterValue];
108
                }
109
                $parts[] = $subFilterValue;
110
            }
111
112
            $currentFilters[$filter->getField()] = array_merge_recursive(...$parts);
113
        }
114
115
        $qs = $qs->withParam($this->getOption(self::OPT_FILTER_QUERY_PARAM), $currentFilters);
116
117
        return $uri->withQuery((string) $qs->withRenderer(withoutNumericIndices()));
118
    }
119
120
    /**
121
     * @inheritDoc
122
     */
123
    public function buildRemoveFilterUrl(UriInterface $uri, Filter $filter, $valueToRemove = null): UriInterface
124
    {
125
        $uri = $this->pagerUriManager->buildPageUri($uri, 1);
126
        $qs = query_string($uri);
127
        $currentFilters = $qs->getParam($this->getOption(self::OPT_FILTER_QUERY_PARAM)) ?? [];
128
129
        if (3 === func_num_args() && $filter instanceof CollectionFilter) {
130
            $filter = $filter->withoutValue($valueToRemove);
131
132
            if ([] === $filter->getValues()) {
133
                $qs = $qs->withoutParam($this->getOption(self::OPT_FILTER_QUERY_PARAM), $filter->getField());
134
            } else {
135
                $currentFilters[$filter->getField()] = $filter->isNegated() ? ['NOT' => $filter->getValues()] : $filter->getValues();
136
                $qs = $qs->withParam($this->getOption(self::OPT_FILTER_QUERY_PARAM), $currentFilters);
137
            }
138
        }
139
        $qs = $qs->withoutParam($this->getOption(self::OPT_FILTER_QUERY_PARAM), $filter->getField());
140
141
        return $uri->withQuery((string) $qs->withRenderer(withoutNumericIndices()));
142
    }
143
}
144