Completed
Pull Request — master (#120)
by De Cramer
02:35
created

MenuContentFactory::createTabsMenu()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 46
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 46
rs 8.6315
c 0
b 0
f 0
cc 4
eloc 33
nc 4
nop 3
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*
0 ignored issues
show
Documentation introduced by
There is no parameter named $menuItemProvider*. Did you maybe mean $menuItemProvider?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
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
        for ($i = count($pathParts) - 1; $i >= 0; $i--) {
134
            $path = implode('/', array_slice($pathParts, 0, $i + 1));
135
136
            /** @var ParentItem $parentItem */
137
            $parentItem = $rootItem->getChild($path);
138
139
            $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...
140
        }
141
    }
142
143
    /**
144
     * Create tabs level menu.
145
     *
146
     * @param ManialinkInterface $manialink
147
     * @param ParentItem         $rootItem
148
     * @param                    $openId
149
     */
150
    protected function createTabsMenu(ManialinkInterface $manialink, ParentItem $rootItem, $openId)
151
    {
152
        /** @var Frame $tabsFrame */
153
        $tabsFrame = $manialink->getData('tabs_frame');
154
        $tabsFrame->removeAllChildren();
155
156
157
        $label = $this->uiFactory->createLabel("expansion_menu.menu");
158
        $label->setPosition(0, 0);
159
        $label->setSize(30, 5);
160
        $label->setTextSize(4);
161
        $label->setTextColor('FFFFFF');
162
        $label->setHorizontalAlign(Label::CENTER);
163
        $label->setTranslate(true);
164
        $tabsFrame->addChild($label);
165
166
        $posX = 28;
167
        foreach ($rootItem->getChilds() as $item) {
168
            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...
169
                $action = $this->actionFactory->createManialinkAction(
170
                    $manialink,
171
                    [$this, 'callbackItemClick'],
172
                    ['item' => $item, 'ml' => $manialink]
173
                );
174
                $label = $this->uiFactory->createLabel($item->getLabelId());
175
176
                $label->setPosition($posX, 0);
177
                $label->setSize(24, 5);
178
                $label->setAction($action);
179
                $label->setTextSize(3);
180
                $label->setTextColor('FFFFFF');
181
                $label->setHorizontalAlign(Label::CENTER);
182
                $label->setTranslate(true);
183
184
                if ($item->getId() == $openId) {
185
                    $underline = $this->uiFactory->createLine($posX - 13, -5);
186
                    $underline->to($posX + 13, -5);
187
                    $underline->setColor('FFFFFF');
188
                    $tabsFrame->addChild($underline);
189
                }
190
191
                $tabsFrame->addChild($label);
192
                $posX += 26;
193
            }
194
        }
195
    }
196
197
    /**
198
     * Create content for sub menu.
199
     *
200
     * @param Manialink  $manialink
201
     * @param Frame      $frame
202
     * @param ParentItem $parentItem
203
     * @param            $displayLevel
204
     */
205
    protected function createSubMenu(Manialink $manialink, Frame $frame, ParentItem $parentItem, $displayLevel)
206
    {
207
        $posX = $displayLevel * (-160.0/3);
208
        $posY = ($displayLevel * (-100.0/3)) * 0.5;
209
        $scale = (0.5 / ($displayLevel + 1)) + 0.5;
210
211
        $contentFrame = new Frame();
212
        $contentFrame->setScale($scale);
213
        $contentFrame->setPosition($posX, $posY);
214
        $frame->addChild($contentFrame);
215
216
        if ($displayLevel > 0) {
217
            $overlay = new Quad();
218
            $overlay->setSize(60, 120);
219
            $overlay->setPosition(-30, 0);
220
            $overlay->setStyles("Bgs1", "BgDialogBlur");
221
222
            $action = $this->actionFactory->createManialinkAction(
223
                $manialink,
224
                [$this, 'callbackItemClick'],
225
                ['item' => $parentItem, 'ml' => $manialink]
226
            );
227
228
229
            $contentFrame->addChild($overlay);
230
            $overlay->setAction($action);
231
        }
232
233
        /* TITLE */
234
        $titleLabel = $this->uiFactory->createLabel($parentItem->getLabelId(), uiLabel::TYPE_TITLE);
235
        $titleLabel->setSize(60, 8);
236
        $titleLabel->setPosition(-30, 0);
237
        $titleLabel->setTranslate(true);
238
        $contentFrame->addChild($titleLabel);
239
240
        $titleLine = $this->uiFactory->createLine(-30, -8);
241
        $titleLine->to(30, -8);
242
        $contentFrame->addChild($titleLine);
243
244
        $posY = -12;
245
        foreach ($parentItem->getChilds() as $item) {
246
            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...
247
                $button = $this->uiFactory->createButton($item->getLabelId());
248
                $button->setPosition(-25, $posY);
249
                $button->setSize(50, 8);
250
                $button->setTranslate(true);
251
252
                if ($displayLevel == 0) {
253
                    $action = $this->actionFactory->createManialinkAction(
254
                        $manialink,
255
                        [$this, 'callbackItemClick'],
256
                        ['item' => $item, 'ml' => $manialink]
257
                    );
258
                    $button->setAction($action);
259
                }
260
261
                $contentFrame->addChild($button);
262
                $posY -= 12;
263
            }
264
        }
265
266
        if ($displayLevel == 0) {
267
268
            $button = $this->uiFactory->createButton('expansion_menu.menu_close', uiButton::TYPE_DECORATED);
269
            $button->setBackgroundColor(uiButton::COLOR_WARNING);
270
            $button->setPosition(-25, $posY - 12);
271
            $button->setSize(50, 8);
272
            $button->setTranslate(true);
273
            $action = $this->actionFactory->createManialinkAction($manialink, [$this, 'callbackClose'], ['ml' =>$manialink]);
274
            $button->setAction($action);
275
            $contentFrame->addChild($button);
276
        }
277
    }
278
279
    /**
280
     * Callback when an item of the menu is clicked on.
281
     *
282
     * @param $login
283
     * @param $params
284
     * @param $args
285
     */
286
    public function callbackItemClick($login, $params, $args)
287
    {
288
        /** @var ItemInterface $item */
289
        $item = $args['item'];
290
        $item->execute($this, $args['ml'], $login, $params, $args);
291
    }
292
293
    /**
294
     * Callback when the close button is clicked.
295
     *
296
     * @param $login
297
     * @param $params
298
     * @param $args
299
     */
300
    public function callbackClose($login, $params, $args)
301
    {
302
        $this->destroy($args['ml']->getUserGroup());
303
    }
304
}