Total Complexity | 63 |
Total Lines | 468 |
Duplicated Lines | 0 % |
Changes | 0 |
Complex classes like ModuleThemeTrait 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 ModuleThemeTrait, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
56 | trait ModuleThemeTrait |
||
57 | { |
||
58 | /** |
||
59 | * How should this module be identified in the control panel, etc.? |
||
60 | * |
||
61 | * @return string |
||
62 | */ |
||
63 | abstract public function title(): string; |
||
64 | |||
65 | /** |
||
66 | * A sentence describing what this module does. |
||
67 | * |
||
68 | * @return string |
||
69 | */ |
||
70 | public function description(): string |
||
71 | { |
||
72 | return I18N::translate('Theme') . ' — ' . $this->title(); |
||
73 | } |
||
74 | |||
75 | /** |
||
76 | * Generate the facts, for display in charts. |
||
77 | * |
||
78 | * @param Individual $individual |
||
79 | * |
||
80 | * @return string |
||
81 | */ |
||
82 | public function individualBoxFacts(Individual $individual): string |
||
127 | } |
||
128 | |||
129 | /** |
||
130 | * Links, to show in chart boxes; |
||
131 | * |
||
132 | * @param Individual $individual |
||
133 | * |
||
134 | * @return array<Menu> |
||
135 | */ |
||
136 | public function individualBoxMenu(Individual $individual): array |
||
137 | { |
||
138 | return array_merge( |
||
139 | $this->individualBoxMenuCharts($individual), |
||
140 | $this->individualBoxMenuFamilyLinks($individual) |
||
141 | ); |
||
142 | } |
||
143 | |||
144 | /** |
||
145 | * Chart links, to show in chart boxes; |
||
146 | * |
||
147 | * @param Individual $individual |
||
148 | * |
||
149 | * @return array<Menu> |
||
150 | */ |
||
151 | public function individualBoxMenuCharts(Individual $individual): array |
||
152 | { |
||
153 | $menus = []; |
||
154 | |||
155 | $module_service = Registry::container()->get(ModuleService::class); |
||
156 | |||
157 | foreach ($module_service->findByComponent(ModuleChartInterface::class, $individual->tree(), Auth::user()) as $chart) { |
||
158 | $menu = $chart->chartBoxMenu($individual); |
||
159 | if ($menu) { |
||
160 | $menus[] = $menu; |
||
161 | } |
||
162 | } |
||
163 | |||
164 | usort($menus, static fn (Menu $x, Menu $y): int => I18N::comparator()($x->getLabel(), $y->getLabel())); |
||
165 | |||
166 | return $menus; |
||
167 | } |
||
168 | |||
169 | /** |
||
170 | * Family links, to show in chart boxes. |
||
171 | * |
||
172 | * @param Individual $individual |
||
173 | * |
||
174 | * @return array<Menu> |
||
175 | */ |
||
176 | public function individualBoxMenuFamilyLinks(Individual $individual): array |
||
177 | { |
||
178 | $menus = []; |
||
179 | |||
180 | foreach ($individual->spouseFamilies() as $family) { |
||
181 | $menus[] = new Menu('<strong>' . I18N::translate('Family with spouse') . '</strong>', $family->url()); |
||
182 | $spouse = $family->spouse($individual); |
||
183 | if ($spouse && $spouse->canShowName()) { |
||
184 | $menus[] = new Menu($spouse->fullName(), $spouse->url()); |
||
185 | } |
||
186 | foreach ($family->children() as $child) { |
||
187 | if ($child->canShowName()) { |
||
188 | $menus[] = new Menu($child->fullName(), $child->url()); |
||
189 | } |
||
190 | } |
||
191 | } |
||
192 | |||
193 | return $menus; |
||
194 | } |
||
195 | |||
196 | /** |
||
197 | * Generate a menu item to change the blocks on the current tree/user page. |
||
198 | * |
||
199 | * @param Tree $tree |
||
200 | * |
||
201 | * @return Menu|null |
||
202 | */ |
||
203 | public function menuChangeBlocks(Tree $tree): Menu|null |
||
204 | { |
||
205 | $request = Registry::container()->get(ServerRequestInterface::class); |
||
206 | $route = Validator::attributes($request)->route(); |
||
207 | |||
208 | if (Auth::check() && $route->name === UserPage::class) { |
||
209 | return new Menu(I18N::translate('Customize this page'), route(UserPageEdit::class, ['tree' => $tree->name()]), 'menu-change-blocks'); |
||
210 | } |
||
211 | |||
212 | if (Auth::isManager($tree) && $route->name === TreePage::class) { |
||
213 | return new Menu(I18N::translate('Customize this page'), route(TreePageEdit::class, ['tree' => $tree->name()]), 'menu-change-blocks'); |
||
214 | } |
||
215 | |||
216 | return null; |
||
217 | } |
||
218 | |||
219 | /** |
||
220 | * Generate a menu item for the control panel. |
||
221 | * |
||
222 | * @param Tree $tree |
||
223 | * |
||
224 | * @return Menu|null |
||
225 | */ |
||
226 | public function menuControlPanel(Tree $tree): Menu|null |
||
227 | { |
||
228 | if (Auth::isAdmin()) { |
||
229 | return new Menu(I18N::translate('Control panel'), route(ControlPanel::class), 'menu-admin'); |
||
230 | } |
||
231 | |||
232 | if (Auth::isManager($tree)) { |
||
233 | return new Menu(I18N::translate('Control panel'), route(ManageTrees::class, ['tree' => $tree->name()]), 'menu-admin'); |
||
234 | } |
||
235 | |||
236 | return null; |
||
237 | } |
||
238 | |||
239 | /** |
||
240 | * A menu to show a list of available languages. |
||
241 | * |
||
242 | * @return Menu|null |
||
243 | */ |
||
244 | public function menuLanguages(): Menu|null |
||
245 | { |
||
246 | $menu = new Menu(I18N::translate('Language'), '#', 'menu-language'); |
||
247 | |||
248 | foreach (I18N::activeLocales() as $active_locale) { |
||
249 | $language_tag = $active_locale->languageTag(); |
||
250 | $class = 'menu-language-' . $language_tag . (I18N::languageTag() === $language_tag ? ' active' : ''); |
||
251 | $menu->addSubmenu(new Menu($active_locale->endonym(), '#', $class, [ |
||
252 | 'data-wt-post-url' => route(SelectLanguage::class, ['language' => $language_tag]), |
||
253 | ])); |
||
254 | } |
||
255 | |||
256 | if (count($menu->getSubmenus()) > 1) { |
||
257 | return $menu; |
||
258 | } |
||
259 | |||
260 | return null; |
||
261 | } |
||
262 | |||
263 | /** |
||
264 | * A login menu option (or null if we are already logged in). |
||
265 | * |
||
266 | * @return Menu|null |
||
267 | */ |
||
268 | public function menuLogin(): Menu|null |
||
269 | { |
||
270 | if (Auth::check()) { |
||
271 | return null; |
||
272 | } |
||
273 | |||
274 | $request = Registry::container()->get(ServerRequestInterface::class); |
||
275 | |||
276 | // Return to this page after login... |
||
277 | $redirect = Validator::queryParams($request)->string('url', (string) $request->getUri()); |
||
278 | $tree = Validator::attributes($request)->treeOptional(); |
||
279 | $route = Validator::attributes($request)->route(); |
||
280 | |||
281 | // ...but switch from the tree-page to the user-page |
||
282 | if ($route->name === TreePage::class) { |
||
283 | $redirect = route(UserPage::class, ['tree' => $tree?->name()]); |
||
284 | } |
||
285 | |||
286 | // Stay on the same tree page |
||
287 | $url = route(LoginPage::class, ['tree' => $tree?->name(), 'url' => $redirect]); |
||
288 | |||
289 | return new Menu(I18N::translate('Sign in'), $url, 'menu-login', ['rel' => 'nofollow']); |
||
290 | } |
||
291 | |||
292 | /** |
||
293 | * A logout menu option (or null if we are already logged out). |
||
294 | * |
||
295 | * @return Menu|null |
||
296 | */ |
||
297 | public function menuLogout(): Menu|null |
||
298 | { |
||
299 | if (Auth::check()) { |
||
300 | $parameters = [ |
||
301 | 'data-wt-post-url' => route(Logout::class), |
||
302 | 'data-wt-reload-url' => route(HomePage::class) |
||
303 | ]; |
||
304 | |||
305 | return new Menu(I18N::translate('Sign out'), '#', 'menu-logout', $parameters); |
||
306 | } |
||
307 | |||
308 | return null; |
||
309 | } |
||
310 | |||
311 | /** |
||
312 | * A link to allow users to edit their account settings. |
||
313 | * |
||
314 | * @param Tree|null $tree |
||
315 | * |
||
316 | * @return Menu |
||
317 | */ |
||
318 | public function menuMyAccount(Tree|null $tree): Menu |
||
319 | { |
||
320 | $url = route(AccountEdit::class, ['tree' => $tree?->name()]); |
||
321 | |||
322 | return new Menu(I18N::translate('My account'), $url, 'menu-myaccount'); |
||
323 | } |
||
324 | |||
325 | /** |
||
326 | * A link to the user's individual record (individual.php). |
||
327 | * |
||
328 | * @param Tree $tree |
||
329 | * |
||
330 | * @return Menu|null |
||
331 | */ |
||
332 | public function menuMyIndividualRecord(Tree $tree): Menu|null |
||
333 | { |
||
334 | $record = Registry::individualFactory()->make($tree->getUserPreference(Auth::user(), UserInterface::PREF_TREE_ACCOUNT_XREF), $tree); |
||
335 | |||
336 | if ($record instanceof Individual) { |
||
337 | return new Menu(I18N::translate('My individual record'), $record->url(), 'menu-myrecord'); |
||
338 | } |
||
339 | |||
340 | return null; |
||
341 | } |
||
342 | |||
343 | /** |
||
344 | * A link to the user's personal home page. |
||
345 | * |
||
346 | * @param Tree $tree |
||
347 | * |
||
348 | * @return Menu |
||
349 | */ |
||
350 | public function menuMyPage(Tree $tree): Menu |
||
351 | { |
||
352 | return new Menu(I18N::translate('My page'), route(UserPage::class, ['tree' => $tree->name()]), 'menu-mypage'); |
||
353 | } |
||
354 | |||
355 | /** |
||
356 | * A menu for the user's personal pages. |
||
357 | * |
||
358 | * @param Tree|null $tree |
||
359 | * |
||
360 | * @return Menu|null |
||
361 | */ |
||
362 | public function menuMyPages(Tree|null $tree): Menu|null |
||
363 | { |
||
364 | if (Auth::check()) { |
||
365 | if ($tree instanceof Tree) { |
||
366 | return new Menu(I18N::translate('My pages'), '#', 'menu-mymenu', [], array_filter([ |
||
367 | $this->menuMyPage($tree), |
||
368 | $this->menuMyIndividualRecord($tree), |
||
369 | $this->menuMyPedigree($tree), |
||
370 | $this->menuMyAccount($tree), |
||
371 | $this->menuControlPanel($tree), |
||
372 | $this->menuChangeBlocks($tree), |
||
373 | ])); |
||
374 | } |
||
375 | |||
376 | return $this->menuMyAccount($tree); |
||
377 | } |
||
378 | |||
379 | return null; |
||
380 | } |
||
381 | |||
382 | /** |
||
383 | * A link to the user's individual record. |
||
384 | * |
||
385 | * @param Tree $tree |
||
386 | * |
||
387 | * @return Menu|null |
||
388 | */ |
||
389 | public function menuMyPedigree(Tree $tree): Menu|null |
||
390 | { |
||
391 | $my_xref = $tree->getUserPreference(Auth::user(), UserInterface::PREF_TREE_ACCOUNT_XREF); |
||
392 | |||
393 | $module_service = Registry::container()->get(ModuleService::class); |
||
394 | $pedigree_chart = $module_service |
||
395 | ->findByComponent(ModuleChartInterface::class, $tree, Auth::user()) |
||
396 | ->first(static fn (ModuleInterface $module): bool => $module instanceof PedigreeChartModule); |
||
397 | |||
398 | if ($my_xref !== '' && $pedigree_chart instanceof PedigreeChartModule) { |
||
399 | $individual = Registry::individualFactory()->make($my_xref, $tree); |
||
400 | |||
401 | if ($individual instanceof Individual) { |
||
402 | return new Menu( |
||
403 | I18N::translate('My pedigree'), |
||
404 | $pedigree_chart->chartUrl($individual), |
||
405 | 'menu-mypedigree' |
||
406 | ); |
||
407 | } |
||
408 | } |
||
409 | |||
410 | return null; |
||
411 | } |
||
412 | |||
413 | /** |
||
414 | * Create a pending changes menu. |
||
415 | * |
||
416 | * @param Tree|null $tree |
||
417 | * |
||
418 | * @return Menu|null |
||
419 | */ |
||
420 | public function menuPendingChanges(Tree|null $tree): Menu|null |
||
421 | { |
||
422 | if ($tree instanceof Tree && $tree->hasPendingEdit() && Auth::isModerator($tree)) { |
||
423 | $request = Registry::container()->get(ServerRequestInterface::class); |
||
424 | |||
425 | $url = route(PendingChanges::class, [ |
||
426 | 'tree' => $tree->name(), |
||
427 | 'url' => (string) $request->getUri(), |
||
428 | ]); |
||
429 | |||
430 | return new Menu(I18N::translate('Pending changes'), $url, 'menu-pending'); |
||
431 | } |
||
432 | |||
433 | return null; |
||
434 | } |
||
435 | |||
436 | /** |
||
437 | * Themes menu. |
||
438 | * |
||
439 | * @return Menu|null |
||
440 | */ |
||
441 | public function menuThemes(): Menu|null |
||
442 | { |
||
443 | $module_service = Registry::container()->get(ModuleService::class); |
||
444 | $themes = $module_service->findByInterface(ModuleThemeInterface::class, false, true); |
||
445 | $current_theme = Registry::container()->get(ModuleThemeInterface::class); |
||
446 | |||
447 | if ($themes->count() > 1) { |
||
448 | $submenus = $themes->map(static function (ModuleThemeInterface $theme) use ($current_theme): Menu { |
||
449 | $active = $theme->name() === $current_theme->name(); |
||
450 | $class = 'menu-theme-' . $theme->name() . ($active ? ' active' : ''); |
||
451 | |||
452 | return new Menu($theme->title(), '#', $class, [ |
||
453 | 'data-wt-post-url' => route(SelectTheme::class, ['theme' => $theme->name()]), |
||
454 | ]); |
||
455 | }); |
||
456 | |||
457 | return new Menu(I18N::translate('Theme'), '#', 'menu-theme', [], $submenus->all()); |
||
458 | } |
||
459 | |||
460 | return null; |
||
461 | } |
||
462 | |||
463 | /** |
||
464 | * Generate a list of items for the main menu. |
||
465 | * |
||
466 | * @param Tree|null $tree |
||
467 | * |
||
468 | * @return array<Menu> |
||
469 | */ |
||
470 | public function genealogyMenu(Tree|null $tree): array |
||
471 | { |
||
472 | if ($tree === null) { |
||
473 | return []; |
||
474 | } |
||
475 | |||
476 | $module_service = Registry::container()->get(ModuleService::class); |
||
477 | |||
478 | return $module_service |
||
479 | ->findByComponent(ModuleMenuInterface::class, $tree, Auth::user()) |
||
480 | ->map(static fn (ModuleMenuInterface $menu): Menu|null => $menu->getMenu($tree)) |
||
481 | ->filter() |
||
482 | ->all(); |
||
483 | } |
||
484 | |||
485 | /** |
||
486 | * Create the genealogy menu. |
||
487 | * |
||
488 | * @param array<Menu> $menus |
||
489 | * |
||
490 | * @return string |
||
491 | */ |
||
492 | public function genealogyMenuContent(array $menus): string |
||
493 | { |
||
494 | return implode('', array_map(static fn (Menu $menu): string => view('components/menu-item', ['menu' => $menu]), $menus)); |
||
495 | } |
||
496 | |||
497 | /** |
||
498 | * Generate a list of items for the user menu. |
||
499 | * |
||
500 | * @param Tree|null $tree |
||
501 | * |
||
502 | * @return array<Menu> |
||
503 | */ |
||
504 | public function userMenu(Tree|null $tree): array |
||
513 | ]); |
||
514 | } |
||
515 | |||
516 | /** |
||
517 | * A list of CSS files to include for this page. |
||
518 | * |
||
519 | * @return array<string> |
||
520 | */ |
||
521 | public function stylesheets(): array |
||
524 | } |
||
525 | } |
||
526 |