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\Filter\Widget\Dynamic; |
||
13 | |||
14 | use ONGR\ElasticsearchBundle\Result\Aggregation\AggregationValue; |
||
15 | use ONGR\ElasticsearchDSL\Aggregation\Bucketing\FilterAggregation; |
||
16 | use ONGR\ElasticsearchDSL\Aggregation\Bucketing\NestedAggregation; |
||
17 | use ONGR\ElasticsearchDSL\Aggregation\Bucketing\TermsAggregation; |
||
18 | use ONGR\ElasticsearchDSL\BuilderInterface; |
||
19 | use ONGR\ElasticsearchDSL\Query\Compound\BoolQuery; |
||
20 | use ONGR\ElasticsearchDSL\Query\MatchAllQuery; |
||
21 | use ONGR\ElasticsearchDSL\Query\Joining\NestedQuery; |
||
22 | use ONGR\ElasticsearchDSL\Query\TermLevel\TermQuery; |
||
23 | use ONGR\ElasticsearchDSL\Search; |
||
24 | use ONGR\ElasticsearchBundle\Result\DocumentIterator; |
||
25 | use ONGR\FilterManagerBundle\Filter\FilterState; |
||
26 | use ONGR\FilterManagerBundle\Filter\Helper\SortAwareTrait; |
||
27 | use ONGR\FilterManagerBundle\Filter\Helper\ViewDataFactoryInterface; |
||
28 | use ONGR\FilterManagerBundle\Filter\ViewData\AggregateViewData; |
||
29 | use ONGR\FilterManagerBundle\Filter\ViewData; |
||
30 | use ONGR\FilterManagerBundle\Filter\Widget\AbstractFilter; |
||
31 | use ONGR\FilterManagerBundle\Search\SearchRequest; |
||
32 | use Symfony\Component\HttpFoundation\Request; |
||
33 | |||
34 | /** |
||
35 | * This class provides single terms choice. |
||
36 | */ |
||
37 | class DynamicAggregate extends AbstractFilter implements ViewDataFactoryInterface |
||
38 | { |
||
39 | use SortAwareTrait; |
||
40 | |||
41 | /** |
||
42 | * @return string |
||
43 | */ |
||
44 | public function getNameField() |
||
45 | { |
||
46 | return $this->getOption('name_field', false); |
||
0 ignored issues
–
show
|
|||
47 | } |
||
48 | |||
49 | /** |
||
50 | * @return bool |
||
51 | */ |
||
52 | public function getShowZeroChoices() |
||
53 | { |
||
54 | return $this->getOption('show_zero_choices', false); |
||
0 ignored issues
–
show
false is of type boolean , but the function expects a string|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...
|
|||
55 | } |
||
56 | |||
57 | /** |
||
58 | * {@inheritdoc} |
||
59 | */ |
||
60 | public function getState(Request $request) |
||
61 | { |
||
62 | $state = new FilterState(); |
||
63 | $value = $request->get($this->getRequestField()); |
||
64 | |||
65 | if (isset($value) && is_array($value)) { |
||
66 | $state->setActive(true); |
||
67 | $state->setValue($value); |
||
68 | $state->setUrlParameters([$this->getRequestField() => $value]); |
||
69 | } |
||
70 | |||
71 | return $state; |
||
72 | } |
||
73 | |||
74 | /** |
||
75 | * {@inheritdoc} |
||
76 | */ |
||
77 | public function modifySearch(Search $search, FilterState $state = null, SearchRequest $request = null) |
||
78 | { |
||
79 | list($path, $field) = explode('>', $this->getDocumentField()); |
||
80 | |||
81 | if ($state && $state->isActive()) { |
||
82 | $boolQuery = new BoolQuery(); |
||
83 | foreach ($state->getValue() as $groupName => $value) { |
||
84 | $innerBoolQuery = new BoolQuery(); |
||
85 | $nestedQuery = new NestedQuery($path, $innerBoolQuery); |
||
86 | $innerBoolQuery->add( |
||
87 | new TermQuery($field, $value) |
||
88 | ); |
||
89 | $innerBoolQuery->add( |
||
90 | new TermQuery($this->getNameField(), $groupName) |
||
91 | ); |
||
92 | $boolQuery->add($nestedQuery); |
||
93 | } |
||
94 | $search->addPostFilter($boolQuery); |
||
95 | } |
||
96 | } |
||
97 | |||
98 | /** |
||
99 | * {@inheritdoc} |
||
100 | */ |
||
101 | public function preProcessSearch(Search $search, Search $relatedSearch, FilterState $state = null) |
||
102 | { |
||
103 | list($path, $field) = explode('>', $this->getDocumentField()); |
||
104 | $filter = !empty($filter = $relatedSearch->getPostFilters()) ? $filter : new MatchAllQuery(); |
||
105 | $aggregation = new NestedAggregation($state->getName(), $path); |
||
106 | $nameAggregation = new TermsAggregation('name', $this->getNameField()); |
||
107 | $valueAggregation = new TermsAggregation('value', $field); |
||
108 | $filterAggregation = new FilterAggregation($state->getName() . '-filter'); |
||
109 | $nameAggregation->addAggregation($valueAggregation); |
||
110 | $aggregation->addAggregation($nameAggregation); |
||
111 | $filterAggregation->setFilter($filter); |
||
112 | |||
113 | if ($this->getSortType()) { |
||
114 | $valueAggregation->addParameter('order', [$this->getSortType() => $this->getSortOrder()]); |
||
115 | } |
||
116 | |||
117 | if ($state->isActive()) { |
||
118 | foreach ($state->getValue() as $key => $term) { |
||
119 | $terms = $state->getValue(); |
||
120 | unset($terms[$key]); |
||
121 | |||
122 | $this->addSubFilterAggregation( |
||
123 | $filterAggregation, |
||
124 | $aggregation, |
||
125 | $terms, |
||
126 | $key |
||
127 | ); |
||
128 | } |
||
129 | } |
||
130 | |||
131 | $this->addSubFilterAggregation( |
||
132 | $filterAggregation, |
||
133 | $aggregation, |
||
134 | $state->getValue() ? $state->getValue() : [], |
||
135 | 'all-selected' |
||
136 | ); |
||
137 | |||
138 | $search->addAggregation($filterAggregation); |
||
139 | |||
140 | if ($this->getShowZeroChoices()) { |
||
141 | $search->addAggregation($aggregation); |
||
142 | } |
||
143 | } |
||
144 | |||
145 | /** |
||
146 | * {@inheritdoc} |
||
147 | */ |
||
148 | public function createViewData() |
||
149 | { |
||
150 | return new AggregateViewData(); |
||
151 | } |
||
152 | |||
153 | /** |
||
154 | * {@inheritdoc} |
||
155 | */ |
||
156 | public function getViewData(DocumentIterator $result, ViewData $data) |
||
157 | { |
||
158 | $unsortedChoices = []; |
||
159 | $activeNames = $data->getState()->isActive() ? array_keys($data->getState()->getValue()) : []; |
||
160 | $filterAggregations = $this->fetchAggregation($result, $data->getName(), $data->getState()->getValue()); |
||
161 | |||
162 | if ($this->getShowZeroChoices()) { |
||
163 | $unsortedChoices = $this->formInitialUnsortedChoices($result, $data); |
||
164 | } |
||
165 | |||
166 | /** @var AggregationValue $bucket */ |
||
167 | foreach ($filterAggregations as $activeName => $filterAggregation) { |
||
168 | foreach ($filterAggregation as $nameAggregation) { |
||
169 | $name = $nameAggregation['key']; |
||
170 | |||
171 | if (($name != $activeName && $activeName != 'all-selected') || |
||
172 | ($activeName == 'all-selected' && in_array($name, $activeNames))) { |
||
173 | continue; |
||
174 | } |
||
175 | |||
176 | foreach ($nameAggregation['value']['buckets'] as $bucket) { |
||
177 | $choice = $this->createChoice($data, $name, $activeName, $bucket); |
||
178 | $unsortedChoices[$name][$bucket['key']] = $choice; |
||
179 | } |
||
180 | |||
181 | $this->addViewDataItem($data, $name, $unsortedChoices[$name]); |
||
182 | unset($unsortedChoices[$name]); |
||
183 | } |
||
184 | } |
||
185 | |||
186 | if ($this->getShowZeroChoices() && !empty($unsortedChoices)) { |
||
187 | foreach ($unsortedChoices as $name => $choices) { |
||
188 | $this->addViewDataItem($data, $name, $unsortedChoices[$name]); |
||
189 | } |
||
190 | } |
||
191 | |||
192 | /** @var AggregateViewData $data */ |
||
193 | $data->sortItems(); |
||
194 | |||
195 | return $data; |
||
196 | } |
||
197 | |||
198 | /** |
||
199 | * {@inheritdoc} |
||
200 | */ |
||
201 | public function isRelated() |
||
202 | { |
||
203 | return true; |
||
204 | } |
||
205 | |||
206 | /** |
||
207 | * Fetches buckets from search results. |
||
208 | * |
||
209 | * @param DocumentIterator $result Search results. |
||
210 | * @param string $filterName Filter name. |
||
211 | * @param array $values Values from the state object |
||
212 | * |
||
213 | * @return array Buckets. |
||
214 | */ |
||
215 | protected function fetchAggregation(DocumentIterator $result, $filterName, $values) |
||
216 | { |
||
217 | $data = []; |
||
218 | $values = empty($values) ? [] : $values; |
||
219 | $aggregation = $result->getAggregation(sprintf('%s-filter', $filterName)); |
||
220 | |||
221 | foreach ($values as $name => $value) { |
||
222 | $data[$name] = $aggregation->find(sprintf('%s.%s.name', $name, $filterName)); |
||
223 | } |
||
224 | |||
225 | $data['all-selected'] = $aggregation->find(sprintf('all-selected.%s.name', $filterName)); |
||
226 | |||
227 | return $data; |
||
228 | } |
||
229 | |||
230 | /** |
||
231 | * A method used to add an additional filter to the aggregations |
||
232 | * in preProcessSearch |
||
233 | * |
||
234 | * @param FilterAggregation $filterAggregation |
||
235 | * @param NestedAggregation $deepLevelAggregation |
||
236 | * @param array $terms Terms of additional filter |
||
237 | * @param string $aggName |
||
238 | * |
||
239 | * @return BuilderInterface |
||
240 | */ |
||
241 | protected function addSubFilterAggregation( |
||
242 | $filterAggregation, |
||
243 | &$deepLevelAggregation, |
||
244 | $terms, |
||
245 | $aggName |
||
246 | ) { |
||
247 | list($path, $field) = explode('>', $this->getDocumentField()); |
||
248 | $boolQuery = new BoolQuery(); |
||
249 | |||
250 | View Code Duplication | foreach ($terms as $groupName => $term) { |
|
251 | $nestedBoolQuery = new BoolQuery(); |
||
252 | $nestedBoolQuery->add(new TermQuery($field, $term)); |
||
253 | $nestedBoolQuery->add(new TermQuery($this->getNameField(), $groupName)); |
||
254 | $boolQuery->add(new NestedQuery($path, $nestedBoolQuery)); |
||
255 | } |
||
256 | |||
257 | $boolQuery = !empty($boolQuery->getQueries()) ? $boolQuery : new MatchAllQuery(); |
||
258 | $innerFilterAggregation = new FilterAggregation($aggName, $boolQuery); |
||
259 | $innerFilterAggregation->addAggregation($deepLevelAggregation); |
||
260 | $filterAggregation->addAggregation($innerFilterAggregation); |
||
261 | } |
||
262 | |||
263 | /** |
||
264 | * @param string $key |
||
265 | * @param string $name |
||
266 | * @param ViewData $data |
||
267 | * @param bool $active True when the choice is active |
||
268 | * |
||
269 | * @return array |
||
270 | */ |
||
271 | protected function getOptionUrlParameters($key, $name, ViewData $data, $active) |
||
272 | { |
||
273 | $value = $data->getState()->getValue(); |
||
274 | $parameters = $data->getResetUrlParameters(); |
||
275 | |||
276 | View Code Duplication | if (!empty($value)) { |
|
277 | if ($active) { |
||
278 | unset($value[array_search($key, $value)]); |
||
279 | $parameters[$this->getRequestField()] = $value; |
||
280 | |||
281 | return $parameters; |
||
282 | } |
||
283 | |||
284 | $parameters[$this->getRequestField()] = $value; |
||
285 | } |
||
286 | |||
287 | $parameters[$this->getRequestField()][$name] = $key; |
||
288 | |||
289 | return $parameters; |
||
290 | } |
||
291 | |||
292 | /** |
||
293 | * Returns whether choice with the specified key is active. |
||
294 | * |
||
295 | * @param string $key |
||
296 | * @param ViewData $data |
||
297 | * @param string $activeName |
||
298 | * |
||
299 | * @return bool |
||
300 | */ |
||
301 | View Code Duplication | protected function isChoiceActive($key, ViewData $data, $activeName) |
|
302 | { |
||
303 | if ($data->getState()->isActive()) { |
||
304 | $value = $data->getState()->getValue(); |
||
305 | |||
306 | if (isset($value[$activeName]) && $key == $value[$activeName]) { |
||
307 | return true; |
||
308 | } |
||
309 | } |
||
310 | |||
311 | return false; |
||
312 | } |
||
313 | |||
314 | /** |
||
315 | * Forms $unsortedChoices array with all possible choices. |
||
316 | * 0 is assigned to the document count of the choices. |
||
317 | * |
||
318 | * @param DocumentIterator $result |
||
319 | * @param ViewData $data |
||
320 | * |
||
321 | * @return array |
||
322 | */ |
||
323 | protected function formInitialUnsortedChoices($result, $data) |
||
324 | { |
||
325 | $unsortedChoices = []; |
||
326 | $urlParameters = array_merge( |
||
327 | $data->getResetUrlParameters(), |
||
328 | $data->getState()->getUrlParameters() |
||
329 | ); |
||
330 | |||
331 | foreach ($result->getAggregation($data->getName())->getAggregation('name') as $nameBucket) { |
||
332 | $groupName = $nameBucket['key']; |
||
333 | |||
334 | foreach ($nameBucket->getAggregation('value') as $bucket) { |
||
335 | $bucketArray = ['key' => $bucket['key'], 'doc_count' => 0]; |
||
336 | $choice = $this->createChoice($data, $bucket['key'], '', $bucketArray, $urlParameters); |
||
0 ignored issues
–
show
$bucketArray is of type array<string,?,{"key":"?","doc_count":"integer"}> , but the function expects a object<ONGR\Elasticsearc...ation\AggregationValue> .
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...
|
|||
337 | $unsortedChoices[$groupName][$bucket['key']] = $choice; |
||
338 | } |
||
339 | } |
||
340 | |||
341 | return $unsortedChoices; |
||
342 | } |
||
343 | |||
344 | /** |
||
345 | * @param AggregateViewData $data |
||
346 | * @param string $name |
||
347 | * @param string $activeName |
||
348 | * @param AggregationValue $bucket |
||
349 | * @param array $urlParameters |
||
350 | * |
||
351 | * @return ViewData\ChoiceAwareViewData |
||
352 | */ |
||
353 | protected function createChoice($data, $name, $activeName, $bucket, $urlParameters = null) |
||
354 | { |
||
355 | $active = $this->isChoiceActive($bucket['key'], $data, $activeName); |
||
356 | |||
357 | if (empty($urlParameters)) { |
||
358 | $urlParameters = $this->getOptionUrlParameters($bucket['key'], $name, $data, $active); |
||
359 | } |
||
360 | |||
361 | $choice = new ViewData\ChoiceAwareViewData(); |
||
362 | $choice->setLabel($bucket['key']); |
||
363 | $choice->setCount($bucket['doc_count']); |
||
364 | $choice->setActive($active); |
||
365 | $choice->setUrlParameters($urlParameters); |
||
366 | |||
367 | return $choice; |
||
368 | } |
||
369 | |||
370 | /** |
||
371 | * @param AggregateViewData $data |
||
372 | * @param string $name |
||
373 | * @param ViewData\ChoiceAwareViewData[] $choices |
||
374 | */ |
||
375 | protected function addViewDataItem($data, $name, $choices) |
||
376 | { |
||
377 | $choiceViewData = new ViewData\ChoicesAwareViewData(); |
||
378 | $choiceViewData->setName($name); |
||
379 | $choiceViewData->setChoices($choices); |
||
380 | $choiceViewData->setUrlParameters([]); |
||
381 | $choiceViewData->setResetUrlParameters($data->getResetUrlParameters()); |
||
382 | $data->addItem($choiceViewData); |
||
383 | } |
||
384 | } |
||
385 |
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: