Completed
Pull Request — master (#100)
by
unknown
02:35
created

layoutLine::getChildren()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
rs 10
ccs 0
cts 4
cp 0
cc 1
eloc 2
nc 1
nop 0
crap 2
1
<?php
2
3
namespace eXpansion\Framework\Gui\Layouts;
4
5
use FML\Controls\Control;
6
use FML\Controls\Frame;
7
use FML\Elements\Format;
8
use FML\Script\Features\ScriptFeature;
9
use FML\Types\Container;
10
use FML\Types\Renderable;
11
use FML\Types\ScriptFeatureable;
12
13
class layoutLine implements Renderable, ScriptFeatureable, Container
14
{
15
    protected $frameClasses = [];
16
17
    /** @var float */
18
    protected $width = 0.;
19
20
    /** @var float */
21
    protected $height = 0.;
22
23
    /** @var Control[] */
24
    protected $elements = [];
25
26
    /** @var float */
27
    protected $margin = 2.;
28
    /**
29
     * @var float
30
     */
31
    protected $startX = 0.;
32
    /**
33
     * @var float
34
     */
35
    protected $startY = 0.;
36
37
    /**
38
     * layoutLine constructor.
39
     * @param float $startX
40
     * @param float $startY
41
     * @param object[] $elements
42
     * @param float $margin
43
     * @throws \Exception
44
     */
45
    public function __construct($startX, $startY, $elements = [], $margin = 0.)
46
    {
47
        if (!is_array($elements)) {
48
            throw new \Exception('not an array');
49
        }
50
        $this->margin = $margin;
51
        $this->elements = $elements;
52
        $this->startX = $startX;
53
        $this->startY = $startY;
54
        foreach ($this->elements as $idx => $element) {
55
            $this->width += $element->getWidth() + $this->margin;
56
            $this->height += $element->getHeight();
57
        }
58
59
    }
60
61
    /**
62
     * Render the XML element
63
     *
64
     * @param \DOMDocument $domDocument DOMDocument for which the XML element should be rendered
65
     * @return \DOMElement
66
     */
67
    public function render(\DOMDocument $domDocument)
68
    {
69
        $frame = new Frame();
70
        $frame->setPosition($this->startX, $this->startY);
71
        $frame->addClasses($this->frameClasses);
72
73
        $startX = 0;
74
        $sizeY = 0;
75
        foreach ($this->elements as $idx => $element) {
76
            $pos = $element->getX();
77
            $element->setX($startX + $pos);
78
            $startX += $pos + $element->getWidth() + $this->margin;
79
            if ($element->getY() + $element->getHeight() > $sizeY) {
80
                $sizeY = $element->getHeight();
81
            }
82
            $frame->addChild($element);
83
        }
84
        $frame->setSize($startX, $sizeY);
85
86
        return $frame->render($domDocument);
87
    }
88
89
    /**
90
     * Get the Script Features
91
     *
92
     * @return ScriptFeature[]
93
     */
94 View Code Duplication
    public function getScriptFeatures()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
95
    {
96
        $features = [];
97
        foreach ($this->elements as $element) {
98
            if ($element instanceof ScriptFeatureable) {
99
                $features[] = $element->getScriptFeatures();
100
            }
101
        }
102
103
        return ScriptFeature::collect($features);
104
    }
105
106
    /**
107
     * @param mixed $startX
108
     * @return layoutLine
109
     */
110
    public function setX($startX)
111
    {
112
        $this->startX = $startX;
113
114
        return $this;
115
    }
116
117
    /**
118
     * @param mixed $startY
119
     * @return layoutLine
120
     */
121
    public function setY($startY)
122
    {
123
        $this->startY = $startY;
124
125
        return $this;
126
    }
127
128
    /**
129
     * @return float
130
     */
131
    public function getX()
132
    {
133
        return $this->startX;
134
    }
135
136
    /**
137
     * @return mixed
138
     */
139
    public function getY()
140
    {
141
        return $this->startY;
142
    }
143
144
    /**
145
     * @return float
146
     */
147
    public function getWidth()
148
    {
149
        return $this->width;
150
    }
151
152
    /**
153
     * @param float $width
154
     */
155
    public function setWidth($width)
156
    {
157
        $this->width = $width;
158
    }
159
160
    /**
161
     * @return float
162
     */
163
    public function getHeight()
164
    {
165
        return $this->height;
166
    }
167
168
    /**
169
     * @param float $height
170
     */
171
    public function setHeight($height)
172
    {
173
        $this->height = $height;
174
    }
175
176
    /**
177
     * @param object $element
178
     */
179
    public function addChild(Renderable $element)
180
    {
181
        $this->elements[] = $element;
182
        $this->width += $element->getWidth() + $this->margin;
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface FML\Types\Renderable as the method getWidth() does only exist in the following implementations of said interface: ControlStub, FML\Controls\Audio, FML\Controls\Control, FML\Controls\Entry, FML\Controls\FileEntry, FML\Controls\Frame, FML\Controls\Frame3d, FML\Controls\FrameInstance, FML\Controls\Gauge, FML\Controls\Graph, 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, eXpansion\Framework\Gui\...nents\abstractUiElement, eXpansion\Framework\Gui\Components\uiButton, eXpansion\Framework\Gui\Components\uiCheckbox, eXpansion\Framework\Gui\Components\uiDropdown, eXpansion\Framework\Gui\Components\uiInput, eXpansion\Framework\Gui\Components\uiLabel, eXpansion\Framework\Gui\Components\uiLine, eXpansion\Framework\Gui\Components\uiScrollbar, eXpansion\Framework\Gui\Components\uiTextbox, eXpansion\Framework\Gui\Components\uiTooltip, eXpansion\Framework\Gui\Layouts\layoutLine, eXpansion\Framework\Gui\Layouts\layoutRow, eXpansion\Framework\Gui\Layouts\layoutScrollable.

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...
183
        $this->height += $element->getHeight();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface FML\Types\Renderable as the method getHeight() does only exist in the following implementations of said interface: ControlStub, FML\Controls\Audio, FML\Controls\Control, FML\Controls\Entry, FML\Controls\FileEntry, FML\Controls\Frame, FML\Controls\Frame3d, FML\Controls\FrameInstance, FML\Controls\Gauge, FML\Controls\Graph, 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, eXpansion\Framework\Gui\...nents\abstractUiElement, eXpansion\Framework\Gui\Components\uiButton, eXpansion\Framework\Gui\Components\uiCheckbox, eXpansion\Framework\Gui\Components\uiDropdown, eXpansion\Framework\Gui\Components\uiInput, eXpansion\Framework\Gui\Components\uiLabel, eXpansion\Framework\Gui\Components\uiLine, eXpansion\Framework\Gui\Components\uiScrollbar, eXpansion\Framework\Gui\Components\uiTextbox, eXpansion\Framework\Gui\Components\uiTooltip, eXpansion\Framework\Gui\Layouts\layoutLine, eXpansion\Framework\Gui\Layouts\layoutRow, eXpansion\Framework\Gui\Layouts\layoutScrollable.

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...
184
    }
185
186
    public function getChildren()
187
    {
188
        return $this->elements;
189
    }
190
191
192
    public function addClass($class)
193
    {
194
        $this->frameClasses [] = $class;
195
    }
196
197
    /**
198
     * Add a new child
199
     *
200
     * @api
201
     * @param Renderable $child Child Control to add
202
     * @return static
203
     * @deprecated Use addChild()
204
     * @see        Container::addChild()
205
     */
206
    public function add(Renderable $child)
207
    {
208
        // TODO: Implement add() method.
209
    }
210
211
    /**
212
     * Add new children
213
     *
214
     * @api
215
     * @param Renderable[] $children Child Controls to add
216
     * @return static
217
     */
218
    public function addChildren(array $children)
219
    {
220
        // TODO: Implement addChildren() method.
221
    }
222
223
    /**
224
     * Remove all children
225
     *
226
     * @api
227
     * @return static
228
     */
229
    public function removeAllChildren()
230
    {
231
        // TODO: Implement removeAllChildren() method.
232
    }
233
234
    /**
235
     * Remove all children
236
     *
237
     * @api
238
     * @return static
239
     * @deprecated Use removeAllChildren()
240
     * @see        Container::removeAllChildren()
241
     */
242
    public function removeChildren()
243
    {
244
        // TODO: Implement removeChildren() method.
245
    }
246
247
    /**
248
     * Get the Format
249
     *
250
     * @api
251
     * @param bool $createIfEmpty If the format should be created if it doesn't exist yet
252
     * @return Format
253
     * @deprecated Use Style
254
     * @see        Style
255
     */
256
    public function getFormat($createIfEmpty = true)
257
    {
258
        // TODO: Implement getFormat() method.
259
    }
260
261
    /**
262
     * Set the Format
263
     *
264
     * @api
265
     * @param Format $format New Format
266
     * @return static
267
     * @deprecated Use Style
268
     * @see        Style
269
     */
270
    public function setFormat(Format $format = null)
271
    {
272
        // TODO: Implement setFormat() method.
273
    }
274
}
275