Total Complexity | 58 |
Total Lines | 331 |
Duplicated Lines | 0 % |
Changes | 11 | ||
Bugs | 1 | Features | 0 |
Complex classes like TableOfContentsController 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.
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 TableOfContentsController, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
27 | class TableOfContentsController extends AbstractController |
||
28 | { |
||
29 | /** |
||
30 | * This holds the active entries according to the currently selected page |
||
31 | * |
||
32 | * @var array |
||
33 | * @access protected |
||
34 | */ |
||
35 | protected $activeEntries = []; |
||
36 | |||
37 | /** |
||
38 | * @var array $this->filterParams: The current filter parameter |
||
39 | * @access protected |
||
40 | */ |
||
41 | protected $filterParams; |
||
42 | |||
43 | /** |
||
44 | * Filter Action |
||
45 | * |
||
46 | * @return void |
||
47 | */ |
||
48 | public function filterAction() |
||
49 | { |
||
50 | // if filter was triggered, get filter parameters from POST variables |
||
51 | $this->filterParams = $this->getParametersSafely('filterParameter'); |
||
|
|||
52 | |||
53 | // output is done by main action |
||
54 | $this->forward('main', null, null, ['filterParameter' => $this->filterParams]); |
||
55 | } |
||
56 | |||
57 | /** |
||
58 | * The main method of the plugin |
||
59 | * |
||
60 | * @return void |
||
61 | */ |
||
62 | public function mainAction() |
||
63 | { |
||
64 | // Load current document. |
||
65 | $this->loadDocument($this->requestData); |
||
66 | if ( |
||
67 | $this->document === null |
||
68 | || $this->document->getDoc() === null |
||
69 | ) { |
||
70 | // Quit without doing anything if required variables are not set. |
||
71 | return; |
||
72 | } else { |
||
73 | if (!empty($this->requestData['logicalPage'])) { |
||
74 | $this->requestData['page'] = $this->document->getDoc()->getPhysicalPage($this->requestData['logicalPage']); |
||
75 | // The logical page parameter should not appear again |
||
76 | unset($this->requestData['logicalPage']); |
||
77 | } |
||
78 | if ($this->document->getDoc()->tableOfContents[0]['type'] == 'collection') { |
||
79 | $this->view->assign('type', 'collection'); |
||
80 | $this->view->assign('toc', $this->makeMenuFor3DObjects()); |
||
81 | } else { |
||
82 | $this->view->assign('type', 'other'); |
||
83 | $this->view->assign('toc', $this->makeMenuArray()); |
||
84 | } |
||
85 | } |
||
86 | } |
||
87 | |||
88 | /** |
||
89 | * This builds a menu array for HMENU |
||
90 | * |
||
91 | * @access protected |
||
92 | * @return array HMENU array |
||
93 | */ |
||
94 | protected function makeMenuArray() |
||
159 | } |
||
160 | |||
161 | /** |
||
162 | * This builds a menu for list of 3D objects |
||
163 | * |
||
164 | * @access protected |
||
165 | * |
||
166 | * @param string $content: The PlugIn content |
||
167 | * @param array $conf: The PlugIn configuration |
||
168 | * |
||
169 | * @return array HMENU array |
||
170 | */ |
||
171 | protected function makeMenuFor3DObjects() |
||
172 | { |
||
173 | $menuArray = []; |
||
174 | |||
175 | // Go through table of contents and create all menu entries. |
||
176 | foreach ($this->document->getDoc()->tableOfContents as $entry) { |
||
177 | $menuEntry = $this->getMenuEntryWithImage($entry, true); |
||
178 | if (!empty($menuEntry)) { |
||
179 | $menuArray[] = $menuEntry; |
||
180 | } |
||
181 | } |
||
182 | return $menuArray; |
||
183 | } |
||
184 | |||
185 | /** |
||
186 | * This builds an array for one menu entry |
||
187 | * |
||
188 | * @access protected |
||
189 | * |
||
190 | * @param array $entry : The entry's array from \Kitodo\Dlf\Common\Doc->getLogicalStructure |
||
191 | * @param bool $recursive : Whether to include the child entries |
||
192 | * |
||
193 | * @return array HMENU array for menu entry |
||
194 | */ |
||
195 | protected function getMenuEntry(array $entry, $recursive = false) |
||
196 | { |
||
197 | $entry = $this->resolveMenuEntry($entry); |
||
198 | |||
199 | $entryArray = []; |
||
200 | // Set "title", "volume", "type" and "pagination" from $entry array. |
||
201 | $entryArray['title'] = !empty($entry['label']) ? $entry['label'] : $entry['orderlabel']; |
||
202 | $entryArray['volume'] = $entry['volume']; |
||
203 | $entryArray['orderlabel'] = $entry['orderlabel']; |
||
204 | $entryArray['type'] = Helper::translate($entry['type'], 'tx_dlf_structures', $this->settings['storagePid']); |
||
205 | $entryArray['pagination'] = htmlspecialchars($entry['pagination']); |
||
206 | $entryArray['_OVERRIDE_HREF'] = ''; |
||
207 | $entryArray['doNotLinkIt'] = 1; |
||
208 | $entryArray['ITEM_STATE'] = 'NO'; |
||
209 | // Build menu links based on the $entry['points'] array. |
||
210 | if ( |
||
211 | !empty($entry['points']) |
||
212 | && MathUtility::canBeInterpretedAsInteger($entry['points']) |
||
213 | ) { |
||
214 | $entryArray['page'] = $entry['points']; |
||
215 | |||
216 | $entryArray['doNotLinkIt'] = 0; |
||
217 | if ($this->settings['basketButton']) { |
||
218 | $entryArray['basketButton'] = [ |
||
219 | 'logId' => $entry['id'], |
||
220 | 'startpage' => $entry['points'] |
||
221 | ]; |
||
222 | } |
||
223 | } elseif ( |
||
224 | !empty($entry['points']) |
||
225 | && is_string($entry['points']) |
||
226 | ) { |
||
227 | $entryArray['id'] = $entry['points']; |
||
228 | $entryArray['page'] = 1; |
||
229 | $entryArray['doNotLinkIt'] = 0; |
||
230 | if ($this->settings['basketButton']) { |
||
231 | $entryArray['basketButton'] = [ |
||
232 | 'logId' => $entry['id'], |
||
233 | 'startpage' => $entry['points'] |
||
234 | ]; |
||
235 | } |
||
236 | } elseif (!empty($entry['targetUid'])) { |
||
237 | $entryArray['id'] = $entry['targetUid']; |
||
238 | $entryArray['page'] = 1; |
||
239 | $entryArray['doNotLinkIt'] = 0; |
||
240 | if ($this->settings['basketButton']) { |
||
241 | $entryArray['basketButton'] = [ |
||
242 | 'logId' => $entry['id'], |
||
243 | 'startpage' => $entry['targetUid'] |
||
244 | ]; |
||
245 | } |
||
246 | } |
||
247 | // Set "ITEM_STATE" to "CUR" if this entry points to current page. |
||
248 | if (in_array($entry['id'], $this->activeEntries)) { |
||
249 | $entryArray['ITEM_STATE'] = 'CUR'; |
||
250 | } |
||
251 | // Build sub-menu if available and called recursively. |
||
252 | if ( |
||
253 | $recursive === true |
||
254 | && !empty($entry['children']) |
||
255 | ) { |
||
256 | // Build sub-menu only if one of the following conditions apply: |
||
257 | // 1. Current menu node is in rootline |
||
258 | // 2. Current menu node points to another file |
||
259 | // 3. Current menu node has no corresponding images |
||
260 | if ( |
||
261 | $entryArray['ITEM_STATE'] == 'CUR' |
||
262 | || is_string($entry['points']) |
||
263 | || empty($this->document->getDoc()->smLinks['l2p'][$entry['id']]) |
||
264 | ) { |
||
265 | $entryArray['_SUB_MENU'] = []; |
||
266 | foreach ($entry['children'] as $child) { |
||
267 | // Set "ITEM_STATE" to "ACT" if this entry points to current page and has sub-entries pointing to the same page. |
||
268 | if (in_array($child['id'], $this->activeEntries)) { |
||
269 | $entryArray['ITEM_STATE'] = 'ACT'; |
||
270 | } |
||
271 | $entryArray['_SUB_MENU'][] = $this->getMenuEntry($child, true); |
||
272 | } |
||
273 | } |
||
274 | // Append "IFSUB" to "ITEM_STATE" if this entry has sub-entries. |
||
275 | $entryArray['ITEM_STATE'] = ($entryArray['ITEM_STATE'] == 'NO' ? 'IFSUB' : $entryArray['ITEM_STATE'] . 'IFSUB'); |
||
276 | } |
||
277 | return $entryArray; |
||
278 | } |
||
279 | |||
280 | /** |
||
281 | * If $entry references an external METS file (as mptr), |
||
282 | * try to resolve its database UID and return an updated $entry. |
||
283 | * |
||
284 | * This is so that when linking from a child document back to its parent, |
||
285 | * that link is via UID, so that subsequently the parent's TOC is built from database. |
||
286 | * |
||
287 | * @param array $entry |
||
288 | * @return array |
||
289 | */ |
||
290 | protected function resolveMenuEntry($entry) |
||
291 | { |
||
292 | // If the menu entry points to the parent document, |
||
293 | // resolve to the parent UID set on indexation. |
||
294 | $doc = $this->document->getDoc(); |
||
295 | if ( |
||
296 | $doc instanceof MetsDocument |
||
297 | && $entry['points'] === $doc->parentHref |
||
298 | && !empty($this->document->getPartof()) |
||
299 | ) { |
||
300 | unset($entry['points']); |
||
301 | $entry['targetUid'] = $this->document->getPartof(); |
||
302 | } |
||
303 | |||
304 | return $entry; |
||
305 | } |
||
306 | |||
307 | protected function getMenuEntryWithImage(array $entry, $recursive = false) |
||
358 | } |
||
359 | } |
||
360 |
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 mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.