Completed
Pull Request — master (#129)
by
unknown
03:00
created

MenuContentFactory::updateContent()   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 45
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

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