Completed
Push — master ( a8e426...cdcd92 )
by Simonas
62:46
created

Search/FilterManager.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 ONGR package.
5
 *
6
 * (c) NFQ Technologies UAB <[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
namespace ONGR\FilterManagerBundle\Search;
13
14
use ONGR\ElasticsearchDSL\Search;
15
use ONGR\ElasticsearchBundle\Service\Repository;
16
use ONGR\ElasticsearchBundle\Result\DocumentIterator;
17
use ONGR\FilterManagerBundle\Event\PreProcessSearchEvent;
18
use ONGR\FilterManagerBundle\Event\PreSearchEvent;
19
use ONGR\FilterManagerBundle\Event\SearchResponseEvent;
20
use ONGR\FilterManagerBundle\Filter\FilterInterface;
21
use ONGR\FilterManagerBundle\Filter\FilterState;
22
use ONGR\FilterManagerBundle\Filter\Helper\ViewDataFactoryInterface;
23
use ONGR\FilterManagerBundle\Filter\ViewData;
24
use ONGR\FilterManagerBundle\ONGRFilterManagerEvents;
25
use ONGR\FilterManagerBundle\Relation\ExcludeRelation;
26
use ONGR\FilterManagerBundle\Relation\FilterIterator;
27
use ONGR\FilterManagerBundle\Relation\LogicalJoin\AndRelation;
28
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
29
use Symfony\Component\HttpFoundation\Request;
30
31
/**
32
 * This class is entry point for search request execution.
33
 */
34
class FilterManager implements FilterManagerInterface
35
{
36
    /**
37
     * @var FilterContainer
38
     */
39
    private $container;
40
41
    /**
42
     * @var Repository
43
     */
44
    private $repository;
45
46
    /**
47
     * @var EventDispatcherInterface
48
     */
49
    private $eventDispatcher;
50
    
51
    /**
52
     * @param FilterContainer          $container
53
     * @param Repository               $repository
54
     * @param EventDispatcherInterface $eventDispatcher
55
     */
56
    public function __construct(
57
        FilterContainer $container,
58
        Repository $repository,
59
        EventDispatcherInterface $eventDispatcher
60
    ) {
61
        $this->container = $container;
62
        $this->repository = $repository;
63
        $this->eventDispatcher = $eventDispatcher;
64
    }
65
66
    /**
67
     * {@inheritdoc}
68
     */
69
    public function handleRequest(Request $request)
70
    {
71
        return $this->search($this->container->buildSearchRequest($request));
72
    }
73
74
    /**
75
     * Executes search.
76
     *
77
     * @param SearchRequest $request
78
     *
79
     * @return SearchResponse
80
     */
81
    public function search(SearchRequest $request)
82
    {
83
        $this->eventDispatcher->dispatch(ONGRFilterManagerEvents::PRE_SEARCH, new PreSearchEvent($request));
84
85
        $search = $this->container->buildSearch($request);
86
87
        /** @var FilterInterface $filter */
88
        foreach ($this->container->all() as $name => $filter) {
89
            $relatedSearch = new Search();
90
91
            if ($filter->isRelated()) {
92
                // We simply exclude not related filters and current filter itself.
93
                $relatedFilters = $this->container->getFiltersByRelation(
94
                    new AndRelation([$filter->getSearchRelation(), new ExcludeRelation([$name])])
95
                );
96
                $relatedSearch = $this->container->buildSearch($request, $relatedFilters);
0 ignored issues
show
$relatedFilters is of type array<integer,object<ONG...elation\FilterIterator>, but the function expects a object<ArrayIterator>|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
97
            }
98
99
            $this->eventDispatcher->dispatch(
100
                ONGRFilterManagerEvents::PRE_PROCESS_SEARCH,
101
                new PreProcessSearchEvent($request->get($name), $relatedSearch)
102
            );
103
104
            $filter->preProcessSearch(
105
                $search,
106
                $relatedSearch,
107
                $request->get($name)
108
            );
109
        }
110
111
        $result = $this->repository->findDocuments($search);
112
        $this->eventDispatcher->dispatch(ONGRFilterManagerEvents::SEARCH_RESPONSE, new SearchResponseEvent($result));
113
114
        return new SearchResponse(
115
            $this->getFiltersViewData($result, $request),
116
            $result,
117
            $this->composeUrlParameters($request)
118
        );
119
    }
120
121
    /**
122
     * Composes url parameters related to given filter.
123
     *
124
     * @param SearchRequest   $request Search request.
125
     * @param FilterInterface $filter  Filter.
126
     * @param array           $exclude Additional names of filters to exclude.
127
     *
128
     * @return array
129
     */
130
    protected function composeUrlParameters(SearchRequest $request, FilterInterface $filter = null, $exclude = [])
131
    {
132
        $out = [];
133
134
        $and = [];
135
136
        if ($filter) {
137
            $and[] = $filter->getResetRelation();
138
        }
139
140
        if (!empty($exclude)) {
141
            $and[] = new ExcludeRelation($exclude);
142
        }
143
144
        /** @var FilterState[] $states */
145
        $states = new FilterIterator(new \IteratorIterator($request), new AndRelation($and));
146
147
        foreach ($states as $state) {
148
            $out = array_merge($out, $state->getUrlParameters());
149
        }
150
151
        return $out;
152
    }
153
154
    /**
155
     * Creates view data for each filter.
156
     *
157
     * @param DocumentIterator $result
158
     * @param SearchRequest    $request
159
     *
160
     * @return ViewData[]
161
     */
162
    protected function getFiltersViewData(DocumentIterator $result, SearchRequest $request)
163
    {
164
        $out = [];
165
166
        /** @var FilterInterface[] $filters */
167
        $filters = $this->container->all();
168
169
        foreach ($filters as $name => $filter) {
170
            if ($filter instanceof ViewDataFactoryInterface) {
171
                $viewData = $filter->createViewData();
172
            } else {
173
                $viewData = new ViewData();
174
            }
175
            $viewData->setName($name);
176
            $viewData->setUrlParameters($this->composeUrlParameters($request, $filter));
177
            $viewData->setState($request->get($name));
178
            $viewData->setTags($filter->getTags());
179
            $viewData->setResetUrlParameters($this->composeUrlParameters($request, $filter, [$name]));
180
            $out[$name] = $filter->getViewData($result, $viewData);
181
        }
182
183
        return $out;
184
    }
185
}
186