MenuContentFactory::createSubMenu()   C
last analyzed

Complexity

Conditions 9
Paths 25

Size

Total Lines 120

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 120
rs 6.4444
c 0
b 0
f 0
cc 9
nc 25
nop 4

How to fix   Long Method   

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 eXpansion\Bundle\Menu\Plugins\Gui;
4
5
use eXpansion\Bundle\Menu\DataProviders\MenuItemProvider;
6
use eXpansion\Bundle\Menu\Gui\MenuTabsFactory;
7
use eXpansion\Bundle\Menu\Model\Menu\ItemInterface;
8
use eXpansion\Bundle\Menu\Model\Menu\ParentItem;
9
use eXpansion\Framework\Core\Model\Gui\Manialink;
10
use eXpansion\Framework\Core\Model\Gui\ManialinkInterface;
11
use eXpansion\Framework\Core\Model\Gui\ManiaScriptFactory;
12
use eXpansion\Framework\Core\Model\Gui\WidgetFactoryContext;
13
use eXpansion\Framework\Core\Plugins\Gui\WidgetFactory;
14
use eXpansion\Framework\Gui\Components\Animation;
15
use eXpansion\Framework\Gui\Components\Button;
16
use eXpansion\Framework\Gui\Components\Label;
17
use FML\Controls\Frame;
18
use FML\Controls\Quad;
19
20
21
/**
22
 * Class MenuContentFactory
23
 *
24
 * @package eXpansion\Bundle\Menu\Plugins\Gui;
25
 * @author  oliver de Cramer <[email protected]>
26
 */
27
class MenuContentFactory extends WidgetFactory
28
{
29
    /** @var  MenuItemProvider */
30
    protected $menuItemProvider;
31
32
    /** @var  ManiaScriptFactory */
33
    protected $menuScriptFactory;
34
35
    /** @var  MenuTabsFactory */
36
    protected $menuTabsFactory;
37
38
    /** @var string */
39
    protected $currentPath = 'general';
40
41
    /** @var Animation */
42
    protected $animation;
43
44
    /**
45
     * MenuContentFactory constructor.
46
     * @param                      $name
47
     * @param                      $sizeX
48
     * @param                      $sizeY
49
     * @param null                 $posX
50
     * @param null                 $posY
51
     * @param WidgetFactoryContext $context
52
     * @param ManiaScriptFactory   $maniaScriptFactory
53
     * @param MenuItemProvider     $menuItemProvider
54
     * @param MenuTabsFactory      $menuTabsFactory
55
     */
56
    public function __construct(
57
        $name,
58
        $sizeX,
59
        $sizeY,
60
        $posX,
61
        $posY,
62
        WidgetFactoryContext $context,
63
        ManiaScriptFactory $maniaScriptFactory,
64
        MenuItemProvider $menuItemProvider,
65
        MenuTabsFactory $menuTabsFactory
66
    ) {
67
        parent::__construct($name, $sizeX, $sizeY, $posX, $posY, $context);
68
69
        $this->menuItemProvider = $menuItemProvider;
70
        $this->menuScriptFactory = $maniaScriptFactory;
71
        $this->menuTabsFactory = $menuTabsFactory;
72
    }
73
74
    /**
75
     * @inheritdoc
76
     */
77
    protected function createContent(ManialinkInterface $manialink)
78
    {
79
        parent::createContent($manialink);
80
81
        $this->animation = $this->uiFactory->createAnimation();
82
        $manialink->addChild($this->animation);
83
84
        $tabsFrame = $this->uiFactory->createLayoutLine(0, 56, [], 0);
85
        $manialink->getContentFrame()->setZ(101);
86
        $manialink->getContentFrame()->addChild($tabsFrame);
87
        $manialink->setData('tabs_frame', $tabsFrame);
88
89
        $contentFrame = new Frame('menu_content');
90
        $contentFrame->setPosition(0, 72);
91
        $manialink->getContentFrame()->addChild($contentFrame);
92
        $manialink->setData('menu_content_frame', $contentFrame);
93
94
        $backGroundFrame = new Frame('background');
95
        $manialink->getContentFrame()->addChild($backGroundFrame);
96
97
98
        /*
99
         * Adding background frame
100
         */
101
        $bgFrame = Frame::create("background");
102
        $quad = new Quad();
103
        $quad->addClass("bg")
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class FML\Controls\Control as the method setStyles() does only exist in the following sub-classes of FML\Controls\Control: FML\Controls\Quad, FML\Controls\Quads\Quad_321Go, FML\Controls\Quads\Quad_BgRaceScore2, FML\Controls\Quads\Quad_Bgs1, FML\Controls\Quads\Quad_Bgs1InRace, FML\Controls\Quads\Quad_BgsButtons, FML\Controls\Quads\Quad_BgsChallengeMedals, FML\Controls\Quads\Quad_BgsPlayerCard, FML\Controls\Quads\Quad_Copilot, FML\Controls\Quads\Quad_Emblems, FML\Controls\Quads\Quad_EnergyBar, FML\Controls\Quads\Quad_Hud3dEchelons, FML\Controls\Quads\Quad_Hud3dIcons, FML\Controls\Quads\Quad_Icons128x128_1, FML\Controls\Quads\Quad_Icons128x128_Blink, FML\Controls\Quads\Quad_Icons128x32_1, FML\Controls\Quads\Quad_Icons64x64_1, FML\Controls\Quads\Quad_Icons64x64_2, FML\Controls\Quads\Quad_ManiaPlanetLogos, FML\Controls\Quads\Quad_ManiaPlanetMainMenu, FML\Controls\Quads\Quad_ManiaplanetSystem, FML\Controls\Quads\Quad_MedalsBig, FML\Controls\Quads\Quad_TitleLogos, FML\Controls\Quads\Quad_...structionBullet_Buttons, FML\Controls\Quads\Quad_UIConstruction_Buttons, FML\Controls\Quads\Quad_UIConstruction_Buttons2, FML\Controls\Quads\Quad_UiSMSpectatorScoreBig. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
104
            ->setId("mainBg")
105
            ->setPosition(0, 0)
106
            ->setSize(322, 182)
107
            ->setAlign("center", "center")
108
            ->setStyles("Bgs1", "BgDialogBlur");
109
        $bgFrame->addChild($quad);
110
111
        $manialink->getContentFrame()->addChild($bgFrame);
112
113
        /**
114
         * Adding script
115
         */
116
        $manialink->getFmlManialink()->addChild($this->menuScriptFactory->createScript([]));
117
118
    }
119
120
    /**
121
     * @inheritdoc
122
     */
123
    protected function updateContent(ManialinkInterface $manialink)
124
    {
125
        parent::updateContent($manialink);
126
127
        $currentPath = $manialink->getData('current_path');
128
        if (is_null($currentPath)) {
129
            $currentPath = $this->currentPath;
130
            $manialink->setData('current_path', $currentPath);
131
        }
132
        $currentPath = trim($currentPath, '/');
133
134
135
        $rootItem = $this->menuItemProvider->getRootItem();
136
        $pathParts = explode('/', $currentPath);
137
138
        $this->createTabsMenu($manialink, $rootItem, $pathParts[0]);
139
140
        /** @var Frame $contentFrame */
141
        $contentFrame = $manialink->getData('menu_content_frame');
142
        $contentFrame->removeAllChildren();
143
144
        $displayLevel = 0;
145
        $breadcrumb = [];
146
147
        for ($i = count($pathParts) - 1; $i >= 0; $i--) {
148
            $path = implode('/', array_slice($pathParts, 0, $i + 1));
149
150
            /** @var ParentItem $parentItem */
151
            $parentItem = $rootItem->getChild($path);
152
153
            $action = $this->actionFactory->createManialinkAction(
154
                $manialink,
155
                [$this, 'callbackItemClick'],
156
                ['item' => $parentItem, 'ml' => $manialink]
157
            );
158
159
            $breadcrumb[] = [
160
                "label" => $parentItem->getLabelId(),
161
                "action" => $action,
162
            ];
163
164
            $this->createSubMenu($manialink, $contentFrame, $parentItem, $displayLevel++);
165
166
167
        }
168
169
        $contentFrame->addChild($this->createButtons($manialink, $breadcrumb));
170
    }
171
172
    /**
173
     * Create tabs level menu.
174
     *
175
     * @param ManialinkInterface $manialink
176
     * @param ItemInterface|null $rootItem
177
     * @param                    $openId
178
     */
179
    protected function createTabsMenu(ManialinkInterface $manialink, ParentItem $rootItem, $openId)
180
    {
181
        /** @var Frame $tabsFrame */
182
        $tabsFrame = $manialink->getData('tabs_frame');
183
        $tabsFrame->removeAllChildren();
184
185
        $this->menuTabsFactory->createTabsMenu($manialink, $tabsFrame, $rootItem, [$this, 'callbackItemClick'],
186
            $openId);
187
    }
188
189
    /**
190
     * Create content for sub menu.
191
     *
192
     * @param Manialink          $manialink
193
     * @param Frame              $frame
194
     * @param ParentItem         $parentItem
195
     * @param            integer $displayLevel
196
     */
197
    protected function createSubMenu(Manialink $manialink, Frame $frame, ParentItem $parentItem, $displayLevel)
198
    {
199
200
        if ($displayLevel > 0) {
201
            return;
202
        }
203
204
        $posX = $displayLevel * (-160.0 / 3);
205
        $posY = ($displayLevel * (-100.0 / 3)) * 0.5;
206
        $scale = (0.5 / ($displayLevel + 1)) + 0.5;
207
208
        $contentFrame = new Frame();
209
        $contentFrame->setScale($scale);
210
        $contentFrame->setPosition($posX, $posY);
211
212
213
        if ($displayLevel > 0) {
214
            $overlay = new Quad();
215
            $overlay->setSize(60, 120);
216
            $overlay->setPosition(-30, 0);
217
            $overlay->setStyles("Bgs1", "BgDialogBlur");
218
219
            $action = $this->actionFactory->createManialinkAction(
220
                $manialink,
221
                [$this, 'callbackItemClick'],
222
                ['item' => $parentItem]
223
            );
224
225
226
            $contentFrame->addChild($overlay);
227
            $overlay->setAction($action);
228
        }
229
230
        /* TITLE */
231
        $titleLabel = $this->uiFactory->createLabel($parentItem->getLabelId(), Label::TYPE_TITLE);
232
        $titleLabel->setTextSize(9)
233
            ->setSize(60, 12)
234
            ->setPosition(0, 0)
235
            ->setTranslate(true)
236
            ->setTextColor('fff')
237
            ->setHorizontalAlign("center");
238
239
        $contentFrame->addChild($titleLabel);
240
241
        $titleLine = $this->uiFactory->createLine(-60 * $scale, -12);
242
        $titleLine->setLength(120 * $scale);
243
        $titleLine->setStroke(0.33)->setColor('fff');
244
245
        $contentFrame->addChild($titleLine);
246
247
        $posY = -30;
248
        $delay = 0;
249
250
        // generate back button
251
        $path = explode("/", $parentItem->getPath());
252
        array_shift($path);
253
254
        $path = array_reverse($path);
255
        array_shift($path);
256
        $path = array_reverse($path);
257
        
258
        if ($path && count($path) >= 0) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $path of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
259
            $rootItem = $this->menuItemProvider->getRootItem();
260
            $backItem = $rootItem->getChild(implode("/", $path));
261
262
            $button = $this->uiFactory->createLabel("expansion_menu.menu_back");
263
            $button->setScale(1.5);
264
            $this->animation->addAnimation($button, 'scale="1"', 300, $delay, Animation::ElasticOut);
265
            $delay += 50;
266
267
            $button->setPosition(0, $posY);
268
            $button->setSize(50, 8);
269
            $button->setTranslate(true);
270
            $button->setTextSize(4);
271
            $button->setAlign("center", "center2");
272
            $button->addClass('menuItem');
273
            $button->setTextColor("aaa");
274
            $button->setTextPrefix("⏴ ");
275
            $action = $this->actionFactory->createManialinkAction(
276
                $manialink,
277
                [$this, 'callbackItemClick'],
278
                ['item' => $backItem, 'ml' => $manialink]
279
            );
280
            $button->setAction($action);
281
            $contentFrame->addChild($button);
282
            $posY -= 12;
283
        }
284
285
286
        foreach ($parentItem->getChilds() as $item) {
287
            if ($item->isVisibleFor($manialink->getUserGroup())) {
288
                $button = $this->uiFactory->createLabel($item->getLabelId());
289
                $button->setScale(1.5);
290
                $this->animation->addAnimation($button, 'scale="1"', 300, $delay, Animation::ElasticOut);
291
                $delay += 50;
292
293
                $button->setPosition(0, $posY);
294
                $button->setSize(50, 8);
295
                $button->setTranslate(true);
296
                $button->setTextSize(4);
297
                $button->setAlign("center", "center2");
298
                $button->addClass('menuItem');
299
                if ($item instanceof $parentItem) {
300
                    $button->setTextPrefix("⏵ ");
301
                }
302
                if ($displayLevel == 0) {
303
                    $action = $this->actionFactory->createManialinkAction(
304
                        $manialink,
305
                        [$this, 'callbackItemClick'],
306
                        ['item' => $item, 'ml' => $manialink]
307
                    );
308
                    $button->setAction($action);
309
                }
310
311
                $contentFrame->addChild($button);
312
                $posY -= 12;
313
            }
314
        }
315
        $frame->addChild($contentFrame);
316
    }
317
318
    public function createButtons($manialink, $items)
319
    {
320
        $frame = $this->uiFactory->createLayoutLine(100, 0, [], 5);
321
322
        $button = $this->uiFactory->createButton('expansion_menu.menu_close', Button::TYPE_DECORATED);
323
        $button->setBorderColor(Button::COLOR_WARNING)->setFocusColor(Button::COLOR_WARNING);
324
        $button->setPosition(100, 0);
325
        $button->setSize(25, 8);
326
        $button->setTranslate(true);
327
        $action = $this->actionFactory->createManialinkAction($manialink, [$this, 'callbackClose'],
328
            []);
329
        $button->setAction($action);
330
331
        $frame->addChild($button);
332
333
        return $frame;
334
    }
335
336
337
    public function createBreadcrumb($items)
338
    {
339
        $items = array_reverse($items);
340
341
        $frame = $this->uiFactory->createLayoutLine(0, 0, [], 2);
342
        $frame->setHorizontalAlign("center");
343
        $frame->setId("breadcrumb");
344
345
        foreach ($items as $i => $item) {
346
            $element = $this->uiFactory->createLabel($item['label'], Label::TYPE_HEADER);
347
            $element->setTranslate(true);
348
            $element->setAlign("left", "center2");
349
            $element->setTextSize(4)
350
                ->addClass("item")
351
                ->setWidth(30);
352
353
            if ($i < sizeof($items) - 1) {
354
                $element->setAction($item['action'])
355
                    ->addClass("menuItem");
356
            } else {
357
                $element->setTextColor("aaa");
358
            }
359
            $frame->addChild($element);
360
361
            if ($i < sizeof($items) - 1) {
362
                $element = $this->uiFactory->createLabel("", Label::TYPE_HEADER);
363
                $element->setAlign("left", "center2");
364
                $element->setTextSize(4);
365
                $element->setWidth(2)->addClass("item");
366
                $frame->addChild($element);
367
            }
368
        }
369
370
        return $frame;
371
    }
372
373
    /**
374
     * Callback when an item of the menu is clicked on.
375
     *
376
     * @param ManialinkInterface $manialink
377
     * @param                    $login
378
     * @param                    $params
379
     * @param                    $args
380
     */
381
382
    public function callbackItemClick(
383
        ManialinkInterface $manialink,
384
        $login,
385
        $params,
386
        $args
387
    ) {
388
        /** @var ItemInterface $item */
389
        $item = $args['item'];
390
        $item->execute($this, $manialink, $login, $params, $args);
391
    }
392
393
    /**
394
     * Callback when the close button is clicked.
395
     *
396
     * @param $login
397
     * @param $params
398
     * @param $args
399
     */
400
401
    public function callbackClose(
402
        ManialinkInterface $manialink,
403
        $login,
404
        $params,
405
        $args
406
    ) {
407
        $this->destroy($manialink->getUserGroup());
408
    }
409
}
410