MenuContentFactory::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 17
rs 9.7
c 0
b 0
f 0
cc 1
nc 1
nop 9

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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