Completed
Pull Request — master (#51)
by De Cramer
02:42
created

Window::getXml()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 10
ccs 0
cts 5
cp 0
rs 9.4285
cc 2
eloc 5
nc 2
nop 0
crap 6
1
<?php
2
3
namespace eXpansion\Framework\Core\Model\Gui;
4
5
use eXpansion\Framework\Core\Exceptions\Gui\MissingCloseActionException;
6
use eXpansion\Framework\Core\Helpers\Translations;
7
use eXpansion\Framework\Core\Model\UserGroups\Group;
8
use FML\Controls\Frame;
9
use FML\Controls\Label;
10
use FML\Controls\Quad;
11
use FML\Controls\Quads\Quad_Bgs1;
12
use FML\Controls\Quads\Quad_Bgs1InRace;
13
use FML\Elements\Dico;
14
use FML\Elements\Format;
15
use FML\Types\Container;
16
use FML\Types\Renderable;
17
18
class Window extends Manialink implements Container
19
{
20
    /** @var Translations */
21
    protected $translationHelper;
22
23
    /** @var \FML\ManiaLink */
24
    protected $manialink;
25
26
    /** @var Dico */
27
    protected $dictionary;
28
29
    /** @var Label */
30
    protected $closeButton;
31
32
    /** @var Frame */
33
    protected $contentFrame;
34
35
    public function __construct(
36
        Group $group,
37
        ManiaScriptFactory $windowManiaScriptFactory,
38
        Translations $translationHelper,
39
        $name,
40
        $sizeX,
41
        $sizeY,
42
        $posX = null,
43
        $posY = null
44
    )
45
    {
46
        parent::__construct($group, $name, $sizeX, $sizeY, $posX, $posY);
47
48
        $this->translationHelper = $translationHelper;
49
50
        $titleHeight = 5.5;
51
        $closeButtonWidth = 9.5;
52
        $titlebarColor = "3afe";
53
54
        // Manialink containing everything
55
        $this->manialink = new \FML\ManiaLink();
56
        $this->manialink->setId($this->getId())
57
            ->setName($name)
58
            ->setVersion(\FML\ManiaLink::VERSION_3);
59
60
        $this->dictionary = new Dico();
61
        $this->manialink->setDico($this->dictionary);
62
63
        $windowFrame = new Frame('Window');
64
        $windowFrame->setPosition($posX, $posY);
65
        $this->manialink->addChild($windowFrame);
66
67
        // Frame to handle the content of the window.
68
        $this->contentFrame = new Frame();
69
        $this->contentFrame->setPosition(2, -$titleHeight - 2);
70
        $this->contentFrame->setSize($sizeX - 4, $sizeY - $titleHeight - 4);
71
        $windowFrame->addChild($this->contentFrame);
72
73
        // Title bar & title.
74
        $titleLabel = new Label();
75
        $titleLabel->setPosition(3, -$titleHeight / 3 - 1)
76
            ->setAlign(Label::LEFT, Label::CENTER2)
77
            ->setTextId($name)
78
            ->setTextColor('fff')
79
            ->setTextSize(2)
80
            ->setTranslate(true)
81
            ->setTextFont('RajdhaniMono')
82
            ->setId("TitleText");
83
        $windowFrame->addChild($titleLabel);
84
85
        $titleBar = new Quad();
86
        $titleBar->setSize($sizeX, 0.33)
87
            ->setPosition(0, -$titleHeight)
88
            ->setBackgroundColor('fff');
89
        $windowFrame->addChild($titleBar);
90
91
        $titleBar = new Quad();
92
        $titleBar->setSize($sizeX / 4, 0.5)
93
            ->setPosition(0, -$titleHeight)
94
            ->setBackgroundColor('fff');
95
        $windowFrame->addChild($titleBar);
96
97
        $titleBar = new Quad('Title');
98
        $titleBar->setSize($sizeX - $closeButtonWidth, $titleHeight)
99
            ->setBackgroundColor($titlebarColor)
100
            ->setScriptEvents(true);
101
        $windowFrame->addChild($titleBar);
102
103
        $this->closeButton = new Label('Close');
104
        $this->closeButton->setSize($closeButtonWidth, $titleHeight)
105
            ->setPosition($sizeX - $closeButtonWidth + ($closeButtonWidth / 2), -$titleHeight / 2)
106
            ->setAlign(Label::CENTER, Label::CENTER2)
107
            ->setText("✖")
108
            ->setTextColor('fff')
109
            ->setTextSize(2)
110
            ->setTextFont('OswaldMono')
111
            ->setScriptEvents(true)
112
            ->setAreaColor('d00')
113
            ->setAreaFocusColor('f22');
114
        $windowFrame->addChild($this->closeButton);
115
116
        //body
117
        $body = new Quad_Bgs1();
118
        $body->setSize($sizeX, $sizeY - $titleHeight)
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 setScriptEvents() does only exist in the following sub-classes of FML\Controls\Control: FML\Controls\Audio, FML\Controls\Entry, FML\Controls\FileEntry, FML\Controls\Frame3d, FML\Controls\Label, FML\Controls\Labels\Label_Button, FML\Controls\Labels\Label_Text, 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, FML\Controls\TextEdit, FML\Controls\Video. 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...
119
            ->setPosition(0, -$titleHeight)
120
            ->setSubStyle(Quad_Bgs1::SUBSTYLE_BgWindow3)
121
            ->setId('WindowBg')
122
            ->setScriptEvents(true);
123
        $windowFrame->addChild($body);
124
125
        $body = new Quad_Bgs1InRace();
126
        $body->setSize($sizeX + 10, $sizeY + 10)
127
            ->setPosition(-5, 5)
128
            ->setSubStyle(Quad_Bgs1InRace::SUBSTYLE_BgButtonShadow);
129
        $windowFrame->addChild($body);
130
131
        // Add maniascript for window handling.
132
        $this->manialink->addChild($windowManiaScriptFactory->createScript(['']));
133
    }
134
135
    /**
136
     * Set action to close the window.
137
     *
138
     * @param $actionId
139
     */
140
    public function setCloseAction($actionId)
141
    {
142
        $this->closeButton->setDataAttributes(['action' => $actionId]);
143
    }
144
145
    /**
146
     * @inheritdoc
147
     */
148
    public function getXml()
149
    {
150
        $this->addDictionaryInformation();
151
152
        if (empty($this->closeButton->getDataAttribute('action'))) {
153
            throw new MissingCloseActionException("Close action is missing for window. Check if you are using the proper factory.");
154
        }
155
156
        return $this->manialink->__toString();
157
    }
158
159
    /**
160
     * Add translations to dictionary.
161
     */
162
    protected function addDictionaryInformation()
163
    {
164
        $translations = array();
165
        $this->getDictionaryInformation($this->manialink, $translations);
166
        $this->dictionary->removeAllEntries();
167
168
        foreach ($translations as $msgId => $messages) {
169
            foreach ($messages as $message) {
170
                $this->dictionary->setEntry($message['Lang'], $msgId, htmlspecialchars ($message['Text']));
171
            }
172
        }
173
    }
174
175
    /**
176
     * Recursive search all dome tree in order to find all translatable labels.
177
     *
178
     * @param $frame
179
     * @param $translations
180
     */
181
    protected function getDictionaryInformation($frame, &$translations)
182
    {
183
        foreach ($frame->getChildren() as $child) {
184
            if ($child instanceof Label && $child->getTranslate()) {
185
                $textId = 'exp_' . md5($child->getTextId());
186
                $translations[$textId] = $this->translationHelper->getTranslations($child->getTextId(), []);
187
188
                // Replaces with text id that can be used in the xml.
189
                $child->setTextId($textId);
190
            } else if ($child instanceof Frame) {
191
                $this->getDictionaryInformation($child, $translations);
192
            }
193
        }
194
    }
195
196
    /**
197
     * Get the children
198
     *
199
     * @api
200
     * @return Renderable[]
201
     */
202
    public function getChildren()
203
    {
204
        return $this->contentFrame->getChildren();
205
    }
206
207
    /**
208
     * Add a new child
209
     *
210
     * @api
211
     *
212
     * @param Renderable $child Child Control to add
213
     *
214
     * @return static
215
     */
216
    public function addChild(Renderable $child)
217
    {
218
        $this->contentFrame->addChild($child);
219
220
        return $this;
221
    }
222
223
    /**
224
     * Add a new child
225
     *
226
     * @api
227
     *
228
     * @param Renderable $child Child Control to add
229
     *
230
     * @return static
231
     * @deprecated Use addChild()
232
     * @see        Container::addChild()
233
     */
234
    public function add(Renderable $child)
235
    {
236
        $this->contentFrame->addChild($child);
237
238
        return $this;
239
    }
240
241
    /**
242
     * Add new children
243
     *
244
     * @api
245
     *
246
     * @param Renderable[] $children Child Controls to add
247
     *
248
     * @return static
249
     */
250
    public function addChildren(array $children)
251
    {
252
        $this->contentFrame->addChildren($children);
253
254
        return $this;
255
    }
256
257
    /**
258
     * Remove all children
259
     *
260
     * @api
261
     * @return static
262
     */
263
    public function removeAllChildren()
264
    {
265
        $this->contentFrame->removeAllChildren();
266
267
        return $this;
268
    }
269
270
    /**
271
     * Remove all children
272
     *
273
     * @api
274
     * @return static
275
     * @deprecated Use removeAllChildren()
276
     * @see        Container::removeAllChildren()
277
     */
278
    public function removeChildren()
279
    {
280
        $this->contentFrame->removeAllChildren();
281
282
        return $this;
283
    }
284
285
    /**
286
     * Get the Format
287
     *
288
     * @api
289
     *
290
     * @param bool $createIfEmpty If the format should be created if it doesn't exist yet
291
     *
292
     * @return Format
293
     * @deprecated Use Style
294
     * @see        Style
295
     */
296
    public function getFormat($createIfEmpty = true)
297
    {
298
        return $this->contentFrame->getFormat($createIfEmpty);
0 ignored issues
show
Deprecated Code introduced by
The method FML\Controls\Frame::getFormat() has been deprecated with message: Use Style

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
299
    }
300
301
    /**
302
     * Set the Format
303
     *
304
     * @api
305
     *
306
     * @param Format $format New Format
307
     *
308
     * @return static
309
     * @deprecated Use Style
310
     * @see        Style
311
     */
312
    public function setFormat(Format $format = null)
313
    {
314
        return $this->contentFrame->setFormat($format);
0 ignored issues
show
Deprecated Code introduced by
The method FML\Controls\Frame::setFormat() has been deprecated with message: Use Style

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
315
    }
316
317
    /**
318
     * @return Frame
319
     */
320
    public function getContentFrame()
321
    {
322
        return $this->contentFrame;
323
    }
324
}
325