Completed
Pull Request — master (#130)
by De Cramer
02:47
created

MenuContentFactory::createSubMenu()   C

Complexity

Conditions 8
Paths 25

Size

Total Lines 91
Code Lines 62

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 91
rs 5.574
c 0
b 0
f 0
cc 8
eloc 62
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\uiButton;
15
use eXpansion\Framework\Gui\Components\uiLabel;
16
use FML\Controls\Frame;
17
use FML\Controls\Label;
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 = 'admin';
40
41
    /**
42
     * MenuContentFactory constructor.
43
     *
44
<<<<<<< HEAD
45
     * @param $name
46
     * @param $sizeX
47
     * @param $sizeY
48
     * @param null $posX
49
     * @param null $posY
50
     * @param WidgetFactoryContext $context
51
     * @param ManiaScriptFactory $maniaScriptFactory
52
     * @param MenuItemProvider $menuItemProvider
53
     * @param MenuTabsFactory $menuTabsFactory
54
=======
55
     * @param                      $name
56
     * @param                      $sizeX
57
     * @param                      $sizeY
58
     * @param null $posX
59
     * @param null $posY
60
     * @param WidgetFactoryContext $context
61
     * @param MenuItemProvider $menuItemProvider *
62
>>>>>>> master
63
     */
64
    public function __construct(
65
        $name,
66
        $sizeX,
67
        $sizeY,
68
        $posX,
69
        $posY,
70
        WidgetFactoryContext $context,
71
        ManiaScriptFactory $maniaScriptFactory,
72
        MenuItemProvider $menuItemProvider,
73
        MenuTabsFactory $menuTabsFactory
74
    ) {
75
        parent::__construct($name, $sizeX, $sizeY, $posX, $posY, $context);
76
77
        $this->menuItemProvider = $menuItemProvider;
78
        $this->menuScriptFactory = $maniaScriptFactory;
79
        $this->menuTabsFactory = $menuTabsFactory;
80
    }
81
82
    /**
83
     * @inheritdoc
84
     */
85
    protected function createContent(ManialinkInterface $manialink)
86
    {
87
        parent::createContent($manialink);
88
89
        $tabsFrame = new Frame('tabs');
90
        $tabsFrame->setPosition(-144, 82);
91
        $manialink->getContentFrame()->setZ(101);
92
        $manialink->getContentFrame()->addChild($tabsFrame);
93
        $manialink->setData('tabs_frame', $tabsFrame);
94
95
        $contentFrame = new Frame('menu_content');
96
        $contentFrame->setPosition(0, 72);
97
        $manialink->getContentFrame()->addChild($contentFrame);
98
        $manialink->setData('menu_content_frame', $contentFrame);
99
100
        $backGroundFrame = new Frame('background');
101
        $manialink->getContentFrame()->addChild($backGroundFrame);
102
103
104
        /*
105
         * Adding background frame
106
         */
107
        $bgFrame = Frame::create("background");
108
109
        $quad = new Quad();
110
        $quad->addClass("bg")
111
            ->setId("mainBg")
112
            ->setPosition(0, 0)
113
            ->setSize(322, 182);
114
        $quad->setAlign("center", "center")
115
            ->setStyles("Bgs1", "BgDialogBlur");
116
        $bgFrame->addChild($quad);
117
118
        $manialink->getContentFrame()->addChild($bgFrame);
119
120
        /**
121
         * Adding script
122
         */
123
        $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...
124
    }
125
126
    /**
127
     * @inheritdoc
128
     */
129
    protected function updateContent(ManialinkInterface $manialink)
130
    {
131
        parent::updateContent($manialink);
132
133
        $currentPath = $manialink->getData('current_path');
134
        if (is_null($currentPath)) {
135
            $currentPath = $this->currentPath;
136
            $manialink->setData('current_path', $currentPath);
137
        }
138
        $currentPath = trim($currentPath, '/');
139
140
141
        $rootItem = $this->menuItemProvider->getRootItem();
142
        $pathParts = explode('/', $currentPath);
143
144
        $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...
145
146
        /** @var Frame $contentFrame */
147
        $contentFrame = $manialink->getData('menu_content_frame');
148
        $contentFrame->removeAllChildren();
149
150
        $displayLevel = 0;
151
        $breadcrumb = [];
152
        for ($i = count($pathParts) - 1; $i >= 0; $i--) {
153
            $path = implode('/', array_slice($pathParts, 0, $i + 1));
154
155
            /** @var ParentItem $parentItem */
156
            $parentItem = $rootItem->getChild($path);
157
158
            $action = $this->actionFactory->createManialinkAction(
159
                $manialink,
160
                [$this, 'callbackItemClick'],
161
                ['item' => $parentItem, 'ml' => $manialink]
162
            );
163
164
            $breadcrumb[] = [
165
                "label" => $parentItem->getLabelId(),
166
                "action" => $action,
167
            ];
168
169
            $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...
170
        }
171
172
        $contentFrame->addChild($this->createBreadcrumb($breadcrumb));
173
    }
174
175
    /**
176
     * Create tabs level menu.
177
     *
178
     * @param ManialinkInterface $manialink
179
     * @param ParentItem $rootItem
180
     * @param                    $openId
181
     */
182
    protected function createTabsMenu(ManialinkInterface $manialink, ParentItem $rootItem, $openId)
183
    {
184
        /** @var Frame $tabsFrame */
185
        $tabsFrame = $manialink->getData('tabs_frame');
186
        $tabsFrame->removeAllChildren();
187
188
        $this->menuTabsFactory->createTabsMenu($manialink, $tabsFrame, $rootItem, [$this, 'callbackItemClick'], $openId);
189
    }
190
191
    /**
192
     * Create content for sub menu.
193
     *
194
     * @param Manialink $manialink
195
     * @param Frame $frame
196
     * @param ParentItem $parentItem
197
     * @param            $displayLevel
198
     */
199
    protected function createSubMenu(Manialink $manialink, Frame $frame, ParentItem $parentItem, $displayLevel)
200
    {
201
202
        if ($displayLevel > 0) {
203
            return;
204
        }
205
206
        $posX = $displayLevel * (-160.0 / 3);
207
        $posY = ($displayLevel * (-100.0 / 3)) * 0.5;
208
        $scale = (0.5 / ($displayLevel + 1)) + 0.5;
209
210
        $contentFrame = new Frame();
211
        $contentFrame->setScale($scale);
212
        $contentFrame->setPosition($posX, $posY);
213
        $frame->addChild($contentFrame);
214
215
        if ($displayLevel > 0) {
216
            $overlay = new Quad();
217
            $overlay->setSize(60, 120);
218
            $overlay->setPosition(-30, 0);
219
            $overlay->setStyles("Bgs1", "BgDialogBlur");
220
221
            $action = $this->actionFactory->createManialinkAction(
222
                $manialink,
223
                [$this, 'callbackItemClick'],
224
                ['item' => $parentItem]
225
            );
226
227
228
            $contentFrame->addChild($overlay);
229
            $overlay->setAction($action);
230
        }
231
232
        /* TITLE */
233
        $titleLabel = $this->uiFactory->createLabel($parentItem->getLabelId(), uiLabel::TYPE_TITLE);
234
        $titleLabel->setTextSize(9)
235
            ->setSize(60, 12)
236
            ->setPosition(0, 0)
237
            ->setTranslate(true)
238
            ->setTextColor('fff')
239
            ->setHorizontalAlign("center");
240
241
        $contentFrame->addChild($titleLabel);
242
243
        $titleLine = $this->uiFactory->createLine(-60 * $scale, -12);
244
        $titleLine->setLength(120 * $scale);
245
        $titleLine->setStroke(0.33)->setColor('fff');
246
247
        $contentFrame->addChild($titleLine);
248
249
        $posY = -30;
250
        foreach ($parentItem->getChilds() as $item) {
251
            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...
252
                $button = $this->uiFactory->createLabel($item->getLabelId());
253
                $button->setPosition(0, $posY);
254
                $button->setSize(50, 8);
255
                $button->setTranslate(true);
256
                $button->setTextSize(4);
257
                $button->setAlign("center", "center2");
258
                $button->addClass('menuItem');
259
                if ($item instanceof $parentItem) {
260
                    $button->setTextPrefix("⏵ ");
261
                }
262
                if ($displayLevel == 0) {
263
                    $action = $this->actionFactory->createManialinkAction(
264
                        $manialink,
265
                        [$this, 'callbackItemClick'],
266
                        ['item' => $item, 'ml' => $manialink]
267
                    );
268
                    $button->setAction($action);
269
                }
270
271
                $contentFrame->addChild($button);
272
                $posY -= 12;
273
            }
274
        }
275
276
        if ($displayLevel == 0) {
277
278
            $button = $this->uiFactory->createButton('expansion_menu.menu_close', uiButton::TYPE_DECORATED);
279
            $button->setBorderColor(uiButton::COLOR_WARNING)->setFocusColor(uiButton::COLOR_WARNING);
280
            $button->setPosition(-25, $posY - 12);
281
            $button->setSize(50, 8);
282
            $button->setTranslate(true);
283
284
            $action = $this->actionFactory->createManialinkAction($manialink, [$this, 'callbackClose'],
285
                []);
286
            $button->setAction($action);
287
            $contentFrame->addChild($button);
288
        }
289
    }
290
291
    public function createBreadcrumb($items) {
292
        $items = array_reverse($items);
293
294
        $frame = $this->uiFactory->createLayoutLine(-60, -16, [], 2);
295
        $frame->setId("breadcrumb");
296
297
        foreach ($items as $i => $item) {
298
            $element = $this->uiFactory->createLabel($item['label'], uiLabel::TYPE_HEADER);
299
            $element->setTranslate(true);
300
            $element->setAlign("left", "center2");
301
            $element->setTextSize(4)
302
                ->addClass("item")
303
                ->setWidth(30);
304
305
            if ($i < sizeof($items) - 1) {
306
                $element->setAction($item['action'])
307
                    ->addClass("menuItem");
308
            } else {
309
                $element->setTextColor("aaa");
310
            }
311
            $frame->addChild($element);
312
313
            if ($i < sizeof($items) - 1) {
314
                $element = $this->uiFactory->createLabel("", uiLabel::TYPE_HEADER);
315
                $element->setAlign("left", "center2");
316
                $element->setTextSize(4);
317
                $element->setWidth(2)->addClass("item");
318
                $frame->addChild($element);
319
            }
320
        }
321
322
        return $frame;
323
    }
324
325
    /**
326
     * Callback when an item of the menu is clicked on.
327
     *
328
     * @param ManialinkInterface $manialink
329
     * @param $login
330
     * @param $params
331
     * @param $args
332
     */
333
334
    public function callbackItemClick(ManialinkInterface $manialink, $login, $params, $args)
335
    {
336
        /** @var ItemInterface $item */
337
        $item = $args['item'];
338
        $item->execute($this, $manialink, $login, $params, $args);
339
    }
340
341
    /**
342
     * Callback when the close button is clicked.
343
     *
344
     * @param $login
345
     * @param $params
346
     * @param $args
347
     */
348
349
    public function callbackClose(ManialinkInterface $manialink, $login, $params, $args)
0 ignored issues
show
Unused Code introduced by
The parameter $login is not used and could be removed.

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

Loading history...
Unused Code introduced by
The parameter $params is not used and could be removed.

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

Loading history...
Unused Code introduced by
The parameter $args is not used and could be removed.

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

Loading history...
350
    {
351
        $this->destroy($manialink->getUserGroup());
352
    }
353
}
354