Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like DynamicAggregate often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use DynamicAggregate, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
39 | class DynamicAggregate extends AbstractSingleRequestValueFilter implements |
||
|
|||
40 | FieldAwareInterface, |
||
41 | ViewDataFactoryInterface |
||
42 | { |
||
43 | use FieldAwareTrait; |
||
44 | |||
45 | /** |
||
46 | * @var array |
||
47 | */ |
||
48 | private $sortType; |
||
49 | |||
50 | /** |
||
51 | * @var string |
||
52 | */ |
||
53 | private $nameField; |
||
54 | |||
55 | /** |
||
56 | * @var bool |
||
57 | */ |
||
58 | private $showZeroChoices; |
||
59 | |||
60 | /** |
||
61 | * @param array $sortType |
||
62 | */ |
||
63 | public function setSortType($sortType) |
||
64 | { |
||
65 | $this->sortType = $sortType; |
||
66 | } |
||
67 | |||
68 | /** |
||
69 | * @return array |
||
70 | */ |
||
71 | public function getSortType() |
||
72 | { |
||
73 | return $this->sortType; |
||
74 | } |
||
75 | |||
76 | /** |
||
77 | * @return string |
||
78 | */ |
||
79 | public function getNameField() |
||
80 | { |
||
81 | return $this->nameField; |
||
82 | } |
||
83 | |||
84 | /** |
||
85 | * @param string $nameField |
||
86 | */ |
||
87 | public function setNameField($nameField) |
||
88 | { |
||
89 | $this->nameField = $nameField; |
||
90 | } |
||
91 | |||
92 | /** |
||
93 | * @return bool |
||
94 | */ |
||
95 | public function getShowZeroChoices() |
||
96 | { |
||
97 | return $this->showZeroChoices; |
||
98 | } |
||
99 | |||
100 | /** |
||
101 | * @param bool $showZeroChoices |
||
102 | */ |
||
103 | public function setShowZeroChoices($showZeroChoices) |
||
104 | { |
||
105 | $this->showZeroChoices = $showZeroChoices; |
||
106 | } |
||
107 | |||
108 | /** |
||
109 | * {@inheritdoc} |
||
110 | */ |
||
111 | public function getState(Request $request) |
||
112 | { |
||
113 | $state = new FilterState(); |
||
114 | $value = $request->get($this->getRequestField()); |
||
115 | |||
116 | if (isset($value) && is_array($value)) { |
||
117 | $state->setActive(true); |
||
118 | $state->setValue($value); |
||
119 | $state->setUrlParameters([$this->getRequestField() => $value]); |
||
120 | } |
||
121 | |||
122 | return $state; |
||
123 | } |
||
124 | |||
125 | /** |
||
126 | * {@inheritdoc} |
||
127 | */ |
||
128 | public function modifySearch(Search $search, FilterState $state = null, SearchRequest $request = null) |
||
129 | { |
||
130 | list($path, $field) = explode('>', $this->getField()); |
||
131 | |||
132 | if ($state && $state->isActive()) { |
||
133 | $boolQuery = new BoolQuery(); |
||
134 | foreach ($state->getValue() as $groupName => $value) { |
||
135 | $innerBoolQuery = new BoolQuery(); |
||
136 | $nestedQuery = new NestedQuery($path, $innerBoolQuery); |
||
137 | $innerBoolQuery->add( |
||
138 | new TermQuery($field, $value) |
||
139 | ); |
||
140 | $innerBoolQuery->add( |
||
141 | new TermQuery($this->getNameField(), $groupName) |
||
142 | ); |
||
143 | $boolQuery->add($nestedQuery); |
||
144 | } |
||
145 | $search->addPostFilter($boolQuery); |
||
146 | } |
||
147 | } |
||
148 | |||
149 | /** |
||
150 | * {@inheritdoc} |
||
151 | */ |
||
152 | public function preProcessSearch(Search $search, Search $relatedSearch, FilterState $state = null) |
||
153 | { |
||
154 | list($path, $field) = explode('>', $this->getField()); |
||
155 | $filter = !empty($filter = $relatedSearch->getPostFilters()) ? $filter : new MatchAllQuery(); |
||
156 | $aggregation = new NestedAggregation($state->getName(), $path); |
||
157 | $nameAggregation = new TermsAggregation('name', $this->getNameField()); |
||
158 | $valueAggregation = new TermsAggregation('value', $field); |
||
159 | $filterAggregation = new FilterAggregation($state->getName() . '-filter'); |
||
160 | $nameAggregation->addAggregation($valueAggregation); |
||
161 | $aggregation->addAggregation($nameAggregation); |
||
162 | $filterAggregation->setFilter($filter); |
||
163 | |||
164 | if ($this->getSortType()) { |
||
165 | $valueAggregation->addParameter('order', [$this->getSortType()['type'] => $this->getSortType()['order']]); |
||
166 | } |
||
167 | |||
168 | if ($state->isActive()) { |
||
169 | foreach ($state->getValue() as $key => $term) { |
||
170 | $terms = $state->getValue(); |
||
171 | unset($terms[$key]); |
||
172 | |||
173 | $this->addSubFilterAggregation( |
||
174 | $filterAggregation, |
||
175 | $aggregation, |
||
176 | $terms, |
||
177 | $key |
||
178 | ); |
||
179 | } |
||
180 | } |
||
181 | |||
182 | $this->addSubFilterAggregation( |
||
183 | $filterAggregation, |
||
184 | $aggregation, |
||
185 | $state->getValue() ? $state->getValue() : [], |
||
186 | 'all-selected' |
||
187 | ); |
||
188 | |||
189 | $search->addAggregation($filterAggregation); |
||
190 | |||
191 | if ($this->getShowZeroChoices()) { |
||
192 | $search->addAggregation($aggregation); |
||
193 | } |
||
194 | } |
||
195 | |||
196 | /** |
||
197 | * {@inheritdoc} |
||
198 | */ |
||
199 | public function createViewData() |
||
200 | { |
||
201 | return new AggregateViewData(); |
||
202 | } |
||
203 | |||
204 | /** |
||
205 | * {@inheritdoc} |
||
206 | */ |
||
207 | public function getViewData(DocumentIterator $result, ViewData $data) |
||
208 | { |
||
209 | $unsortedChoices = []; |
||
210 | $activeNames = $data->getState()->isActive() ? array_keys($data->getState()->getValue()) : []; |
||
211 | $filterAggregations = $this->fetchAggregation($result, $data->getName(), $data->getState()->getValue()); |
||
212 | |||
213 | if ($this->getShowZeroChoices()) { |
||
214 | $unsortedChoices = $this->formInitialUnsortedChoices($result, $data); |
||
215 | } |
||
216 | |||
217 | /** @var AggregationValue $bucket */ |
||
218 | foreach ($filterAggregations as $activeName => $filterAggregation) { |
||
219 | foreach ($filterAggregation as $nameAggregation) { |
||
220 | $name = $nameAggregation['key']; |
||
221 | |||
222 | if (($name != $activeName && $activeName != 'all-selected') || |
||
223 | ($activeName == 'all-selected' && in_array($name, $activeNames))) { |
||
224 | continue; |
||
225 | } |
||
226 | |||
227 | foreach ($nameAggregation['value']['buckets'] as $bucket) { |
||
228 | $choice = $this->createChoice($data, $name, $activeName, $bucket); |
||
229 | $unsortedChoices[$name][$bucket['key']] = $choice; |
||
230 | } |
||
231 | |||
232 | $this->addViewDataItem($data, $name, $unsortedChoices[$name]); |
||
233 | unset($unsortedChoices[$name]); |
||
234 | } |
||
235 | } |
||
236 | |||
237 | if ($this->getShowZeroChoices() && !empty($unsortedChoices)) { |
||
238 | foreach ($unsortedChoices as $name => $choices) { |
||
239 | $this->addViewDataItem($data, $name, $unsortedChoices[$name]); |
||
240 | } |
||
241 | } |
||
242 | |||
243 | /** @var AggregateViewData $data */ |
||
244 | $data->sortItems(); |
||
245 | |||
246 | return $data; |
||
247 | } |
||
248 | |||
249 | /** |
||
250 | * {@inheritdoc} |
||
251 | */ |
||
252 | public function isRelated() |
||
256 | |||
257 | /** |
||
258 | * Fetches buckets from search results. |
||
259 | * |
||
260 | * @param DocumentIterator $result Search results. |
||
261 | * @param string $filterName Filter name. |
||
262 | * @param array $values Values from the state object |
||
263 | * |
||
264 | * @return array Buckets. |
||
265 | */ |
||
266 | protected function fetchAggregation(DocumentIterator $result, $filterName, $values) |
||
267 | { |
||
280 | |||
281 | /** |
||
282 | * A method used to add an additional filter to the aggregations |
||
283 | * in preProcessSearch |
||
284 | * |
||
285 | * @param FilterAggregation $filterAggregation |
||
286 | * @param NestedAggregation $deepLevelAggregation |
||
287 | * @param array $terms Terms of additional filter |
||
288 | * @param string $aggName |
||
289 | * |
||
290 | * @return BuilderInterface |
||
291 | */ |
||
292 | protected function addSubFilterAggregation( |
||
313 | |||
314 | /** |
||
315 | * @param string $key |
||
316 | * @param string $name |
||
317 | * @param ViewData $data |
||
318 | * @param bool $active True when the choice is active |
||
319 | * |
||
320 | * @return array |
||
321 | */ |
||
322 | protected function getOptionUrlParameters($key, $name, ViewData $data, $active) |
||
342 | |||
343 | /** |
||
344 | * Returns whether choice with the specified key is active. |
||
345 | * |
||
346 | * @param string $key |
||
347 | * @param ViewData $data |
||
348 | * @param string $activeName |
||
349 | * |
||
350 | * @return bool |
||
351 | */ |
||
352 | View Code Duplication | protected function isChoiceActive($key, ViewData $data, $activeName) |
|
364 | |||
365 | /** |
||
366 | * Forms $unsortedChoices array with all possible choices. |
||
367 | * 0 is assigned to the document count of the choices. |
||
368 | * |
||
369 | * @param DocumentIterator $result |
||
370 | * @param ViewData $data |
||
371 | * |
||
372 | * @return array |
||
373 | */ |
||
374 | protected function formInitialUnsortedChoices($result, $data) |
||
394 | |||
395 | /** |
||
396 | * @param AggregateViewData $data |
||
397 | * @param string $name |
||
398 | * @param string $activeName |
||
399 | * @param AggregationValue $bucket |
||
400 | * @param array $urlParameters |
||
401 | * @return ViewData\Choice |
||
402 | */ |
||
403 | protected function createChoice($data, $name, $activeName, $bucket, $urlParameters = null) |
||
419 | |||
420 | /** |
||
421 | * @param AggregateViewData $data |
||
422 | * @param string $name |
||
423 | * @param ViewData\Choice[] $choices |
||
424 | */ |
||
425 | protected function addViewDataItem($data, $name, $choices) |
||
434 | } |
||
435 |
This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.