MenuGenerator::addLink()   F
last analyzed

Complexity

Conditions 25
Paths 4398

Size

Total Lines 102
Code Lines 60

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 1 Features 0
Metric Value
eloc 60
c 3
b 1
f 0
dl 0
loc 102
rs 0
cc 25
nc 4398
nop 4

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Uccello\Core\Support;
4
5
use Spatie\Menu\Laravel\Menu;
0 ignored issues
show
Bug introduced by
The type Spatie\Menu\Laravel\Menu was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
use Spatie\Menu\Laravel\Html;
0 ignored issues
show
Bug introduced by
The type Spatie\Menu\Laravel\Html was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
7
use Uccello\Core\Models\Domain;
8
use Uccello\Core\Models\Module;
9
10
class MenuGenerator
11
{
12
    /**
13
     * Current domain
14
     *
15
     * @var \Uccello\Core\Models\Domain
16
     */
17
    protected $domain;
18
19
    /**
20
     * Current module
21
     *
22
     * @var \Uccello\Core\Models\Module
23
     */
24
    protected $module;
25
26
    /**
27
     * Main menu
28
     *
29
     * @var \Spatie\Menu\Laravel\Menu
30
     */
31
    protected $menu;
32
33
    /**
34
     * All names of modules added in the menu
35
     *
36
     * @var array
37
     */
38
    protected $menuAddedModules;
39
40
    /**
41
     * Get menu generated
42
     *
43
     * @return \Spatie\Menu\Laravel\Menu
44
     */
45
    public function getMenu()
46
    {
47
        return $this->menu;
48
    }
49
50
    /**
51
     * Make the menu according to the environment (main or admin)
52
     *
53
     * @param Domain $domain
54
     * @param Module $module
55
     * @return \Uccello\Core\Support\MenuGenerator
56
     */
57
    public function makeMenu(Domain $domain, Module $module)
58
    {
59
        $this->domain = $domain;
60
61
        $this->module = $module;
62
63
        // Create menu
64
        $this->menu = Menu::new()
65
            ->withoutWrapperTag(); // Do not add <ul></ul>
66
67
        // Add links to menu
68
        $this->addLinksToMenu();
69
70
        return $this;
71
    }
72
73
    /**
74
     * Add all links to the menu
75
     *
76
     * @return void
77
     */
78
    protected function addLinksToMenu()
79
    {
80
        // Get the menu to display according to the environment (main or admin)
81
        $domainMenu = $this->getDomainMenuToDisplay();
82
83
        $this->menuAddedModules = [ ];
84
85
        // If a menu was created, use it
86
        if (!is_null($domainMenu)) {
87
            $this->addLinksToMenuFromDomainMenu($domainMenu);
88
        }
89
        // Else add links from the modules list
90
        else {
91
            $this->addLinksToMenuFromModulesList();
92
        }
93
94
        // If we are on a module not displayed in the menu, add it to the menu
95
        $this->addActiveModuleIfNotInMenu();
96
    }
97
98
    /**
99
     * If a menu was created, use it and add its links in the menu
100
     *
101
     * @param \Uccello\Core\Models\Menu $domainMenu
102
     * @return void
103
     */
104
    protected function addLinksToMenuFromDomainMenu($domainMenu)
105
    {
106
        if (empty($domainMenu->data)) {
107
            return;
108
        }
109
110
        foreach ($domainMenu->data as $menuLink) {
0 ignored issues
show
Bug introduced by
The property data does not seem to exist on Uccello\Core\Models\Menu. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
111
            $this->addLink($this->menu, $menuLink);
112
        }
113
114
        // Add links added after the creation of the menu
115
        $this->addLinksAddedAfterMenuCreation();
116
    }
117
118
    /**
119
     * If no menu was created we add all links available in the activated modules
120
     *
121
     * @return void
122
     */
123
    protected function addLinksToMenuFromModulesList()
124
    {
125
        $modules = $this->getModulesVisibleInMenu();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $modules is correct as $this->getModulesVisibleInMenu() targeting Uccello\Core\Support\Men...tModulesVisibleInMenu() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
126
127
        foreach ($modules as $module) {
0 ignored issues
show
Bug introduced by
The expression $modules of type void is not traversable.
Loading history...
128
            foreach ($module->menuLinks as $menuLink) {
129
                $menuLink->type = 'module';
130
                $menuLink->module = $module->name;
131
                $this->addLink($this->menu, $menuLink);
132
            }
133
        }
134
    }
135
136
    /**
137
     * If we are on a module not displayed in the menu, add it to the menu
138
     *
139
     * @return void
140
     */
141
    protected function addActiveModuleIfNotInMenu()
142
    {
143
        if (!in_array($this->module->name, $this->menuAddedModules)) {
0 ignored issues
show
Bug introduced by
The property name does not seem to exist on Uccello\Core\Models\Module. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
144
            $menuLink = new \StdClass;
145
            $menuLink->label = $this->module->name;
146
            $menuLink->icon = $this->module->icon ?? 'extension';
147
            $menuLink->type = 'module';
148
            $menuLink->module = $this->module->name; // Current module name
149
            $menuLink->route = request()->route()->getName(); // Current route
150
            $menuLink->url = 'javascript:void(0)'; // No link
151
            $this->addLink($this->menu, $menuLink, false, false);
152
        }
153
    }
154
155
    /**
156
     * Add to the menu, the links added after the creation of the menu
157
     * (e.g. new modules or modules activated after the creation)
158
     */
159
    protected function addLinksAddedAfterMenuCreation()
160
    {
161
        $modules = $this->getModulesVisibleInMenu();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $modules is correct as $this->getModulesVisibleInMenu() targeting Uccello\Core\Support\Men...tModulesVisibleInMenu() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
162
163
        foreach ($modules as $module) {
0 ignored issues
show
Bug introduced by
The expression $modules of type void is not traversable.
Loading history...
164
            if (!in_array($module->name, $this->menuAddedModules)) {
165
                foreach ($module->menuLinks as $menuLink) {
166
                    $menuLink->type = 'module';
167
                    $menuLink->module = $module->name;
168
                    $this->addLink($this->menu, $menuLink);
169
                }
170
            }
171
        }
172
    }
173
174
    /**
175
     * Recursive function to add a link to the menu with all its children
176
     *
177
     * @param \Spatie\Menu\Laravel\Menu $menu
178
     * @param \StdClass $menuLink
179
     * @param boolean $isInSubMenu
180
     * @param boolean $checkCapacity
181
     * @return void
182
     */
183
    protected function addLink($menu, $menuLink, $isInSubMenu = false, $checkCapacity = true)
0 ignored issues
show
Unused Code introduced by
The parameter $isInSubMenu is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

183
    protected function addLink($menu, $menuLink, /** @scrutinizer ignore-unused */ $isInSubMenu = false, $checkCapacity = true)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
184
    {
185
        // Retrieve module if defined
186
        $module = isset($menuLink->module) ? ucmodule($menuLink->module) : null;
187
188
        //TODO: Check needed capacity
189
        if ($menuLink->type === 'module' && !is_null($module)) {
190
            // Don't display domain module if multi domains is not activated
191
            if ($module->name === 'domain' && !env('UCCELLO_MULTI_DOMAINS', true)) {
0 ignored issues
show
Bug introduced by
The property name does not seem to exist on Uccello\Core\Models\Module. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
192
                return;
193
            }
194
195
            if (!$module->isActiveOnDomain($this->domain)) {
196
                return;
197
            }
198
            if ($checkCapacity && !auth()->user()->canRetrieve($this->domain, $module)) {
199
                return;
200
            }
201
        }
202
203
        if (!empty($menuLink->module)) {
204
            if (!in_array($menuLink->module, $this->menuAddedModules)) {
205
                $this->menuAddedModules[ ] = $menuLink->module;
206
            }
207
        }
208
209
        // Url
210
        if (!empty($menuLink->url)) { // Prioritary to be compatible with addActiveModuleIfNotInMenu()
211
            $url = $menuLink->url;
212
        } elseif (!empty($menuLink->route) && !is_null($module)) {
213
            $url = ucroute($menuLink->route, $this->domain, $module);
214
        } else {
215
            $url = 'javascript:void(0)';
216
        }
217
218
        // Label
219
        $label = $menuLink->type === 'module' ? uctrans($menuLink->label, $module) : uctrans($menuLink->label, $this->module);
220
        if (!is_string($label)) {
221
            return;
222
        }
223
224
        // Icon
225
        if ($menuLink->type === 'folder') {
226
            $fallbackIcon = 'folder';
227
        } elseif ($menuLink->type === 'link') {
228
            $fallbackIcon = 'link';
229
        } else {
230
            $fallbackIcon = 'extension';
231
        }
232
233
        $icon = $menuLink->icon ?? $fallbackIcon;
234
235
        // Is active. If the current route is in the menu, compare also the routes
236
        if ($menuLink->type === 'module' && !is_null($module)) {
237
            if ($this->isCurrentRouteInMenu($module)) {
238
                $isActive = $this->module->id === $module->id && request()->route()->getName() === $menuLink->route;
239
            } else {
240
                $isActive = $this->module->id === $module->id;
241
            }
242
        } else {
243
            $isActive = false;
244
        }
245
246
        // Add children
247
        if (!empty($menuLink->children)) {
248
249
            // Make a sub menu
250
            $subMenu = Menu::new();
251
252
            // Add all links in the sub menu
253
            foreach ($menuLink->children as $subMenuLink) {
254
                $this->addLink($subMenu, $subMenuLink, true); // Recursive
255
            }
256
257
            if ($subMenu->count() > 0) {
258
                $link = Html::raw(
259
                    '<ul class="collapsible collapsible-accordion">'.
260
                        '<li class="submenu">'.
261
                            '<a href="'.$url.'" class="collapsible-header waves-effect" tabindex="0">'.
262
                                '<i class="material-icons">'.$icon.'</i>'.
263
                                '<span>'.$label.'</span>'.
264
                            '</a>'.
265
                            '<div class="collapsible-body">'.
266
                                $subMenu->toHtml().
267
                            '</div>'.
268
                        '</li>'.
269
                    '</ul>'
270
                );
271
272
                $menu->add($link);
273
            }
274
275
        } else {
276
            $link = Html::raw(
277
                '<a href="'.$url.'">'.
278
                    '<i class="material-icons">'.$icon.'</i>'.
279
                    '<span>'.$label.'</span>'.
280
                '</a>'
281
            )->setActive($isActive);
282
283
            // Add link to menu
284
            $menu->add($link);
285
        }
286
    }
287
288
    /**
289
     * Return the menu to display according to the environment (main or admin)
290
     *
291
     * @return \Uccello\Core\Models\Menu
292
     */
293
    protected function getDomainMenuToDisplay()
294
    {
295
        if ($this->isAdminEnv()) {
296
            $menuToDisplay = $this->domain->adminMenu;
297
        } else {
298
            $menuToDisplay = $this->domain->mainMenu;
299
        }
300
301
        return $menuToDisplay;
302
    }
303
304
    /**
305
     * Return all modules visible in the menu according to the environment (main or admin)
306
     *
307
     * @return void
308
     */
309
    protected function getModulesVisibleInMenu()
310
    {
311
        // Detect what sort of link to add in the menu (admin or not admin) and load the related modules
312
        if ($this->isAdminEnv()) {
313
            $modules = $this->domain->adminModules;
314
        } else {
315
            $modules = $this->domain->notAdminModules;
316
        }
317
318
        return $modules;
319
    }
320
321
    /**
322
     * Check if we are in the admin environment
323
     *
324
     * @return boolean
325
     */
326
    protected function isAdminEnv()
327
    {
328
        return $this->module->isAdminModule();
329
    }
330
331
    /**
332
     * Check if the current route is present in the menu
333
     *
334
     * @param \Uccello\Core\Models\Module $module
335
     * @return boolean
336
     */
337
    protected function isCurrentRouteInMenu($module)
338
    {
339
        $currentRoute = request()->route()->getName();
340
341
        return $this->isRouteInMenu($module, $currentRoute);
342
    }
343
344
    /**
345
     * Check if a route is present in the menu
346
     *
347
     * @param \Uccello\Core\Models\Module $module
348
     * @param string $route
349
     * @return boolean
350
     */
351
    protected function isRouteInMenu($module, $route)
352
    {
353
        $found = false;
354
355
        $modules = $this->getModulesVisibleInMenu();
0 ignored issues
show
Unused Code introduced by
The assignment to $modules is dead and can be removed.
Loading history...
Bug introduced by
Are you sure the assignment to $modules is correct as $this->getModulesVisibleInMenu() targeting Uccello\Core\Support\Men...tModulesVisibleInMenu() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
356
357
        foreach ($module->menuLinks as $link) {
358
            if ($link->route === $route) {
359
                $found = true;
360
                break;
361
            }
362
        }
363
364
        return $found;
365
    }
366
}