Completed
Pull Request — master (#129)
by De Cramer
02:40
created

MenuContentFactory::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 15
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 12
nc 1
nop 8

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\Model\Menu\ItemInterface;
7
use eXpansion\Bundle\Menu\Model\Menu\ParentItem;
8
use eXpansion\Framework\Core\Model\Gui\Manialink;
9
use eXpansion\Framework\Core\Model\Gui\ManialinkInterface;
10
use eXpansion\Framework\Core\Model\Gui\ManiaScriptFactory;
11
use eXpansion\Framework\Core\Model\Gui\WidgetFactoryContext;
12
use eXpansion\Framework\Core\Plugins\Gui\WidgetFactory;
13
use eXpansion\Framework\Gui\Components\uiButton;
14
use eXpansion\Framework\Gui\Components\uiLabel;
15
use FML\Controls\Frame;
16
use FML\Controls\Label;
17
use FML\Controls\Quad;
18
19
20
/**
21
 * Class MenuContentFactory
22
 *
23
 * @package eXpansion\Bundle\Menu\Plugins\Gui;
24
 * @author  oliver de Cramer <[email protected]>
25
 */
26
class MenuContentFactory extends WidgetFactory
27
{
28
    /** @var  MenuItemProvider */
29
    protected $menuItemProvider;
30
31
    /** @var  ManiaScriptFactory */
32
    protected $menuScriptFactory;
33
34
    /** @var string */
35
    protected $currentPath = 'admin';
36
37
    /**
38
     * MenuContentFactory constructor.
39
     *
40
     * @param                      $name
41
     * @param                      $sizeX
42
     * @param                      $sizeY
43
     * @param null $posX
44
     * @param null $posY
45
     * @param WidgetFactoryContext $context
46
     * @param MenuItemProvider $menuItemProvider *
47
     */
48
    public function __construct(
49
        $name,
50
        $sizeX,
51
        $sizeY,
52
        $posX,
53
        $posY,
54
        WidgetFactoryContext $context,
55
        ManiaScriptFactory $maniaScriptFactory,
56
        MenuItemProvider $menuItemProvider
57
    ) {
58
        parent::__construct($name, $sizeX, $sizeY, $posX, $posY, $context);
59
60
        $this->menuItemProvider = $menuItemProvider;
61
        $this->menuScriptFactory = $maniaScriptFactory;
62
    }
63
64
    /**
65
     * @inheritdoc
66
     */
67
    protected function createContent(ManialinkInterface $manialink)
68
    {
69
        parent::createContent($manialink);
70
71
        $tabsFrame = new Frame('tabs');
72
        $tabsFrame->setPosition(-144, 82);
73
        $manialink->getContentFrame()->setZ(101);
74
        $manialink->getContentFrame()->addChild($tabsFrame);
75
        $manialink->setData('tabs_frame', $tabsFrame);
76
77
        $contentFrame = new Frame('menu_content');
78
        $contentFrame->setPosition(0, 72);
79
        $manialink->getContentFrame()->addChild($contentFrame);
80
        $manialink->setData('menu_content_frame', $contentFrame);
81
82
        $backGroundFrame = new Frame('background');
83
        $manialink->getContentFrame()->addChild($backGroundFrame);
84
85
86
        /*
87
         * Adding background frame
88
         */
89
        $bgFrame = Frame::create("background");
90
91
        $quad = new Quad();
92
        $quad->addClass("bg")
93
            ->setId("mainBg")
94
            ->setPosition(0, 0)
95
            ->setSize(322, 182);
96
        $quad->setAlign("center", "center")
97
            ->setStyles("Bgs1", "BgDialogBlur");
98
        $bgFrame->addChild($quad);
99
100
        $manialink->getContentFrame()->addChild($bgFrame);
101
102
        /**
103
         * Adding script
104
         */
105
        $manialink->getFmlManialink()->addChild($this->menuScriptFactory->createScript([]));
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface eXpansion\Framework\Core...\Gui\ManialinkInterface as the method getFmlManialink() does only exist in the following implementations of said interface: eXpansion\Framework\Core\Model\Gui\Widget, eXpansion\Framework\Core\Model\Gui\Window.

Let’s take a look at an example:

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

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
106
    }
107
108
    /**
109
     * @inheritdoc
110
     */
111
    protected function updateContent(ManialinkInterface $manialink)
112
    {
113
        parent::updateContent($manialink);
114
115
        $currentPath = $manialink->getData('current_path');
116
        if (is_null($currentPath)) {
117
            $currentPath = $this->currentPath;
118
            $manialink->setData('current_path', $currentPath);
119
        }
120
        $currentPath = trim($currentPath, '/');
121
122
123
        $rootItem = $this->menuItemProvider->getRootItem();
124
        $pathParts = explode('/', $currentPath);
125
126
        $this->createTabsMenu($manialink, $rootItem, $pathParts[0]);
0 ignored issues
show
Documentation introduced by
$rootItem is of type object<eXpansion\Bundle\...enu\ItemInterface>|null, but the function expects a object<eXpansion\Bundle\...\Model\Menu\ParentItem>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
127
128
        /** @var Frame $contentFrame */
129
        $contentFrame = $manialink->getData('menu_content_frame');
130
        $contentFrame->removeAllChildren();
131
132
        $displayLevel = 0;
133
        $breadcrumb = [];
134
        for ($i = count($pathParts) - 1; $i >= 0; $i--) {
135
            $path = implode('/', array_slice($pathParts, 0, $i + 1));
136
137
            /** @var ParentItem $parentItem */
138
            $parentItem = $rootItem->getChild($path);
139
140
            $action = $this->actionFactory->createManialinkAction(
141
                $manialink,
142
                [$this, 'callbackItemClick'],
143
                ['item' => $parentItem, 'ml' => $manialink]
144
            );
145
146
            $breadcrumb[] = [
147
                "label" => $parentItem->getLabelId(),
148
                "action" => $action,
149
            ];
150
151
            $this->createSubMenu($manialink, $contentFrame, $parentItem, $displayLevel++);
0 ignored issues
show
Compatibility introduced by
$manialink of type object<eXpansion\Framewo...Gui\ManialinkInterface> is not a sub-type of object<eXpansion\Framewo...re\Model\Gui\Manialink>. It seems like you assume a concrete implementation of the interface eXpansion\Framework\Core...\Gui\ManialinkInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
152
        }
153
154
        $contentFrame->addChild($this->createBreadcrumb($breadcrumb));
155
    }
156
157
    /**
158
     * Create tabs level menu.
159
     *
160
     * @param ManialinkInterface $manialink
161
     * @param ParentItem $rootItem
162
     * @param                    $openId
163
     */
164
    protected function createTabsMenu(ManialinkInterface $manialink, ParentItem $rootItem, $openId)
165
    {
166
        /** @var Frame $tabsFrame */
167
        $tabsFrame = $manialink->getData('tabs_frame');
168
        $tabsFrame->removeAllChildren();
169
170
171
        $label = $this->uiFactory->createLabel("expansion_menu.menu");
172
        $label->setPosition(0, 0);
173
        $label->setSize(30, 5);
174
        $label->setTextSize(4);
175
        $label->setTextColor('FFFFFF');
176
        $label->setHorizontalAlign(Label::CENTER);
177
        $label->setTranslate(true);
178
        $tabsFrame->addChild($label);
179
180
        $posX = 28;
181
        foreach ($rootItem->getChilds() as $item) {
182
            if ($rootItem->isVisibleFor($manialink->getUserGroup())) {
0 ignored issues
show
Documentation introduced by
$manialink->getUserGroup() is of type object<eXpansion\Framewo...Model\UserGroups\Group>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
183
                $action = $this->actionFactory->createManialinkAction(
184
                    $manialink,
185
                    [$this, 'callbackItemClick'],
186
                    ['item' => $item, 'ml' => $manialink]
187
                );
188
                $label = $this->uiFactory->createLabel($item->getLabelId());
189
190
                $label->setPosition($posX, 0);
191
                $label->setSize(24, 5);
192
                $label->setAction($action);
193
                $label->setTextSize(3);
194
                $label->setTextColor('FFFFFF');
195
                $label->setHorizontalAlign(Label::CENTER);
196
                $label->setTranslate(true);
197
198
                if ($item->getId() == $openId) {
199
                    $underline = $this->uiFactory->createLine($posX - 7, -5);
200
                    $underline->to($posX + 7, -5);
201
                    $underline->setStroke(0.33);
202
                    $underline->setColor('fff');
203
                    $tabsFrame->addChild($underline);
204
                }
205
206
                $tabsFrame->addChild($label);
207
                $posX += 26;
208
            }
209
        }
210
    }
211
212
    /**
213
     * Create content for sub menu.
214
     *
215
     * @param Manialink $manialink
216
     * @param Frame $frame
217
     * @param ParentItem $parentItem
218
     * @param            $displayLevel
219
     */
220
    protected function createSubMenu(Manialink $manialink, Frame $frame, ParentItem $parentItem, $displayLevel)
221
    {
222
        if ($displayLevel > 0) {
223
            return;
224
        }
225
226
        $posX = $displayLevel * (-160.0 / 3);
227
        $posY = ($displayLevel * (-100.0 / 3)) * 0.5;
228
        $scale = (0.5 / ($displayLevel + 1)) + 0.5;
229
230
        $contentFrame = new Frame();
231
        $contentFrame->setScale($scale);
232
        $contentFrame->setPosition($posX, $posY);
233
        $frame->addChild($contentFrame);
234
235
        if ($displayLevel > 0) {
236
            $overlay = new Quad();
237
            $overlay->setSize(60, 120);
238
            $overlay->setPosition(-30, 0);
239
            $overlay->setStyles("Bgs1", "BgDialogBlur");
240
241
            $action = $this->actionFactory->createManialinkAction(
242
                $manialink,
243
                [$this, 'callbackItemClick'],
244
                ['item' => $parentItem, 'ml' => $manialink]
245
            );
246
247
248
            $contentFrame->addChild($overlay);
249
            $overlay->setAction($action);
250
        }
251
252
        /* TITLE */
253
        $titleLabel = $this->uiFactory->createLabel($parentItem->getLabelId(), uiLabel::TYPE_TITLE);
254
        $titleLabel->setTextSize(9)
255
            ->setSize(60, 12)
256
            ->setPosition(0, 0)
257
            ->setTranslate(true)
258
            ->setTextColor('fff')
259
            ->setHorizontalAlign("center");
260
261
        $contentFrame->addChild($titleLabel);
262
263
        $titleLine = $this->uiFactory->createLine(-60 * $scale, -12);
264
        $titleLine->setLength(120 * $scale);
265
        $titleLine->setStroke(0.33)->setColor('fff');
266
267
        $contentFrame->addChild($titleLine);
268
269
        $posY = -30;
270
        foreach ($parentItem->getChilds() as $item) {
271
            if ($item->isVisibleFor($manialink->getUserGroup())) {
0 ignored issues
show
Documentation introduced by
$manialink->getUserGroup() is of type object<eXpansion\Framewo...Model\UserGroups\Group>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
272
                $button = $this->uiFactory->createLabel($item->getLabelId());
273
                $button->setPosition(0, $posY);
274
                $button->setSize(50, 8);
275
                $button->setTranslate(true);
276
                $button->setTextSize(4);
277
                $button->setAlign("center", "center2");
278
                $button->addClass('menuItem');
279
280
                if ($displayLevel == 0) {
281
                    $action = $this->actionFactory->createManialinkAction(
282
                        $manialink,
283
                        [$this, 'callbackItemClick'],
284
                        ['item' => $item, 'ml' => $manialink]
285
                    );
286
                    $button->setAction($action);
287
                }
288
289
                $contentFrame->addChild($button);
290
                $posY -= 12;
291
            }
292
        }
293
294
        if ($displayLevel == 0) {
295
296
            $button = $this->uiFactory->createButton('expansion_menu.menu_close', uiButton::TYPE_DECORATED);
297
            $button->setBorderColor(uiButton::COLOR_WARNING)->setFocusColor(uiButton::COLOR_WARNING);
298
            $button->setPosition(-25, $posY - 12);
299
            $button->setSize(50, 8);
300
            $button->setTranslate(true);
301
            $action = $this->actionFactory->createManialinkAction($manialink, [$this, 'callbackClose'],
302
                ['ml' => $manialink]);
303
            $button->setAction($action);
304
            $contentFrame->addChild($button);
305
        }
306
    }
307
308
    public function createBreadcrumb($items)
309
    {
310
        $items = array_reverse($items);
311
312
        $frame = $this->uiFactory->createLayoutLine(-60, -16, [], 2);
313
        $frame->setId("breadcrumb");
314
315
        foreach ($items as $i => $item) {
316
            $element = $this->uiFactory->createLabel($item['label'], uiLabel::TYPE_HEADER);
317
            $element->setTranslate(true);
318
            $element->setAlign("left", "center2");
319
            $element->setTextSize(4)
320
                ->addClass("item")
321
                ->setWidth(30);
322
323
            if ($i < sizeof($items) - 1) {
324
                $element->setAction($item['action'])
325
                    ->addClass("menuItem");
326
            } else {
327
                $element->setTextColor("aaa");
328
            }
329
            $frame->addChild($element);
330
331
            if ($i < sizeof($items) - 1) {
332
                $element = $this->uiFactory->createLabel("", uiLabel::TYPE_HEADER);
333
                $element->setAlign("left", "center2");
334
                $element->setTextSize(4);
335
                $element->setWidth(2)->addClass("item");
336
                $frame->addChild($element);
337
            }
338
        }
339
340
        return $frame;
341
    }
342
343
344
    /**
345
     * Callback when an item of the menu is clicked on.
346
     *
347
     * @param $login
348
     * @param $params
349
     * @param $args
350
     */
351
    public function callbackItemClick(
352
        $login,
353
        $params,
354
        $args
355
    ) {
356
        /** @var ItemInterface $item */
357
        $item = $args['item'];
358
        $item->execute($this, $args['ml'], $login, $params, $args);
359
    }
360
361
    /**
362
     * Callback when the close button is clicked.
363
     *
364
     * @param $login
365
     * @param $params
366
     * @param $args
367
     */
368
    public function callbackClose(
369
        $login,
370
        $params,
371
        $args
372
    ) {
373
        $this->destroy($args['ml']->getUserGroup());
374
    }
375
}
376