Completed
Pull Request — master (#104)
by
unknown
07:24
created

MenuStyle::generateColoursSetCode()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 10
nc 4
nop 0
1
<?php
2
3
namespace PhpSchool\CliMenu;
4
5
use PhpSchool\CliMenu\Exception\InvalidInstantiationException;
6
use PhpSchool\CliMenu\Terminal\TerminalFactory;
7
use PhpSchool\CliMenu\Util\ColourUtil;
8
use PhpSchool\Terminal\Terminal;
9
10
//TODO: B/W fallback
11
12
/**
13
 * @author Michael Woodward <[email protected]>
14
 */
15
class MenuStyle
16
{
17
    /**
18
     * @var Terminal
19
     */
20
    protected $terminal;
21
22
    /**
23
     * @var int|string
24
     */
25
    protected $fg;
26
27
    /**
28
     * @var int|string
29
     */
30
    protected $bg;
31
32
    /**
33
     * @var int
34
     */
35
    protected $width;
36
37
    /**
38
     * @var int
39
     */
40
    protected $padding;
41
42
    /**
43
     * @var int
44
     */
45
    protected $margin;
46
47
    /**
48
     * @var int
49
     */
50
    protected $contentWidth;
51
52
    /**
53
     * @var string
54
     */
55
    private $selectedMarker;
56
57
    /**
58
     * @var string
59
     */
60
    private $unselectedMarker;
61
62
    /**
63
     * @var string
64
     */
65
    private $itemExtra;
66
67
    /**
68
     * @var bool
69
     */
70
    private $displaysExtra;
71
72
    /**
73
     * @var string
74
     */
75
    private $titleSeparator;
76
77
    /**
78
     * @var string
79
     */
80
    private $coloursSetCode;
81
82
    /**
83
     * @var string
84
     */
85
    private $invertedColoursSetCode = "\033[7m";
86
87
    /**
88
     * @var string
89
     */
90
    private $invertedColoursUnsetCode = "\033[27m";
91
92
    /**
93
     * @var string
94
     */
95
    private $coloursResetCode = "\033[0m";
96
97
    /**
98
     * Default Values
99
     *
100
     * @var array
101
     */
102
    private static $defaultStyleValues = [
103
        'fg' => 'white',
104
        'bg' => 'blue',
105
        'width' => 100,
106
        'padding' => 2,
107
        'margin' => 2,
108
        'selectedMarker' => '●',
109
        'unselectedMarker' => '○',
110
        'itemExtra' => '✔',
111
        'displaysExtra' => false,
112
        'titleSeparator' => '=',
113
    ];
114
115
    public static function getDefaultStyleValues() : array
116
    {
117
        return static::$defaultStyleValues;
0 ignored issues
show
Bug introduced by
Since $defaultStyleValues is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $defaultStyleValues to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
118
    }
119
120
    /**
121
     * @var array
122
     */
123
    private static $availableForegroundColors = array(
124
        'black'   => 30,
125
        'red'     => 31,
126
        'green'   => 32,
127
        'yellow'  => 33,
128
        'blue'    => 34,
129
        'magenta' => 35,
130
        'cyan'    => 36,
131
        'white'   => 37,
132
        'default' => 39,
133
    );
134
135
    /**
136
     * @var array
137
     */
138
    private static $availableBackgroundColors = array(
139
        'black'   => 40,
140
        'red'     => 41,
141
        'green'   => 42,
142
        'yellow'  => 43,
143
        'blue'    => 44,
144
        'magenta' => 45,
145
        'cyan'    => 46,
146
        'white'   => 47,
147
        'default' => 49,
148
    );
149
150
    /**
151
     * @var array
152
     */
153
    private static $availableOptions = array(
154
        'bold'       => array('set' => 1, 'unset' => 22),
155
        'dim'        => array('set' => 2, 'unset' => 22),
156
        'underscore' => array('set' => 4, 'unset' => 24),
157
        'blink'      => array('set' => 5, 'unset' => 25),
158
        'reverse'    => array('set' => 7, 'unset' => 27),
159
        'conceal'    => array('set' => 8, 'unset' => 28)
160
    );
161
162
    /**
163
     * Initialise style
164
     */
165
    public function __construct(Terminal $terminal = null)
166
    {
167
        $this->terminal = $terminal ?: TerminalFactory::fromSystem();
168
169
        $this->setFg(static::$defaultStyleValues['fg']);
0 ignored issues
show
Bug introduced by
Since $defaultStyleValues is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $defaultStyleValues to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
170
        $this->setBg(static::$defaultStyleValues['bg']);
0 ignored issues
show
Bug introduced by
Since $defaultStyleValues is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $defaultStyleValues to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
171
        $this->setWidth(static::$defaultStyleValues['width']);
0 ignored issues
show
Bug introduced by
Since $defaultStyleValues is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $defaultStyleValues to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
172
        $this->setPadding(static::$defaultStyleValues['padding']);
0 ignored issues
show
Bug introduced by
Since $defaultStyleValues is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $defaultStyleValues to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
173
        $this->setMargin(static::$defaultStyleValues['margin']);
0 ignored issues
show
Bug introduced by
Since $defaultStyleValues is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $defaultStyleValues to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
174
        $this->setSelectedMarker(static::$defaultStyleValues['selectedMarker']);
0 ignored issues
show
Bug introduced by
Since $defaultStyleValues is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $defaultStyleValues to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
175
        $this->setUnselectedMarker(static::$defaultStyleValues['unselectedMarker']);
0 ignored issues
show
Bug introduced by
Since $defaultStyleValues is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $defaultStyleValues to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
176
        $this->setItemExtra(static::$defaultStyleValues['itemExtra']);
0 ignored issues
show
Bug introduced by
Since $defaultStyleValues is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $defaultStyleValues to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
177
        $this->setDisplaysExtra(static::$defaultStyleValues['displaysExtra']);
0 ignored issues
show
Bug introduced by
Since $defaultStyleValues is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $defaultStyleValues to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
178
        $this->setTitleSeparator(static::$defaultStyleValues['titleSeparator']);
0 ignored issues
show
Bug introduced by
Since $defaultStyleValues is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $defaultStyleValues to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
179
    }
180
181
    public function getDisabledItemText(string $text) : string
182
    {
183
        return sprintf(
184
            "\033[%sm%s\033[%sm",
185
            self::$availableOptions['dim']['set'],
186
            $text,
187
            self::$availableOptions['dim']['unset']
188
        );
189
    }
190
191
    /**
192
     * Generates the ansi escape sequence to set the colours
193
     */
194
    private function generateColoursSetCode() : void
195
    {
196
        if (is_string($this->fg)) {
197
            $fgCode = self::$availableForegroundColors[$this->fg];
198
        } else {
199
            $fgCode = sprintf("38;5;%s", $this->fg);
200
        }
201
202
        if (is_string($this->bg)) {
203
            $bgCode = self::$availableBackgroundColors[$this->bg];
204
        } else {
205
            $bgCode = sprintf("48;5;%s", $this->bg);
206
        }
207
208
        $this->coloursSetCode = sprintf("\033[%s;%sm", $fgCode, $bgCode);
209
    }
210
211
    /**
212
     * Get the colour code for Bg and Fg
213
     */
214
    public function getColoursSetCode() : string
215
    {
216
        return $this->coloursSetCode;
217
    }
218
219
    /**
220
     * Get the inverted escape sequence (used for selected elements)
221
     */
222
    public function getInvertedColoursSetCode() : string
223
    {
224
        return $this->invertedColoursSetCode;
225
    }
226
227
    /**
228
     * Get the inverted escape sequence (used for selected elements)
229
     */
230
    public function getInvertedColoursUnsetCode() : string
231
    {
232
        return $this->invertedColoursUnsetCode;
233
    }
234
235
    /**
236
     * Get the escape sequence used to reset colours to default
237
     */
238
    public function getColoursResetCode() : string
239
    {
240
        return $this->coloursResetCode;
241
    }
242
243
    /**
244
     * Calculate the contents width
245
     */
246
    protected function calculateContentWidth() : void
247
    {
248
        $this->contentWidth = $this->width - ($this->padding*2) - ($this->margin*2);
249
    }
250
251
    public function getFg()
252
    {
253
        return $this->fg;
254
    }
255
256 View Code Duplication
    public function setFg($fg, string $fallback = null) : self
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...
257
    {
258
        $this->fg = ColourUtil::validateColour(
259
            $this->terminal,
260
            $fg,
261
            $fallback
262
        );
263
        $this->generateColoursSetCode();
264
265
        return $this;
266
    }
267
268
    public function getBg()
269
    {
270
        return $this->bg;
271
    }
272
273 View Code Duplication
    public function setBg($bg, string $fallback = null) : self
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...
274
    {
275
        $this->bg = ColourUtil::validateColour(
276
            $this->terminal,
277
            $bg,
278
            $fallback
279
        );
280
        $this->generateColoursSetCode();
281
282
        return $this;
283
    }
284
285
    public function getWidth() : int
286
    {
287
        return $this->width;
288
    }
289
290
    public function setWidth(int $width) : self
291
    {
292
        $availableWidth = $this->terminal->getWidth() - ($this->margin * 2) - ($this->padding * 2);
293
294
        if ($width >= $availableWidth) {
295
            $width = $availableWidth;
296
        }
297
298
        $this->width = $width;
0 ignored issues
show
Documentation Bug introduced by
It seems like $width can also be of type double. However, the property $width is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
299
        $this->calculateContentWidth();
300
301
        return $this;
302
    }
303
304
    public function getPadding() : int
305
    {
306
        return $this->padding;
307
    }
308
309
    public function setPadding(int $padding) : self
310
    {
311
        $this->padding = $padding;
312
313
        $this->calculateContentWidth();
314
315
        return $this;
316
    }
317
318
    public function getMargin() : int
319
    {
320
        return $this->margin;
321
    }
322
323
    public function setMargin(int $margin) : self
324
    {
325
        $this->margin = $margin;
326
327
        $this->calculateContentWidth();
328
329
        return $this;
330
    }
331
332
    public function getContentWidth() : int
333
    {
334
        return $this->contentWidth;
335
    }
336
337
    /**
338
     * Get padding for right had side of content
339
     */
340
    public function getRightHandPadding(int $contentLength) : int
341
    {
342
        return $this->getContentWidth() - $contentLength + $this->getPadding();
343
    }
344
345
    public function getSelectedMarker() : string
346
    {
347
        return $this->selectedMarker;
348
    }
349
350
    public function setSelectedMarker(string $marker) : self
351
    {
352
        $this->selectedMarker = mb_substr($marker, 0, 1);
353
354
        return $this;
355
    }
356
357
    public function getUnselectedMarker() : string
358
    {
359
        return $this->unselectedMarker;
360
    }
361
362
    public function setUnselectedMarker(string $marker) : self
363
    {
364
        $this->unselectedMarker = mb_substr($marker, 0, 1);
365
366
        return $this;
367
    }
368
369
    /**
370
     * Get the correct marker for the item
371
     */
372
    public function getMarker(bool $selected) : string
373
    {
374
        return $selected ? $this->selectedMarker : $this->unselectedMarker;
375
    }
376
377
    public function setItemExtra(string $itemExtra) : self
378
    {
379
        $this->itemExtra = $itemExtra;
380
381
        return $this;
382
    }
383
384
    public function getItemExtra() : string
385
    {
386
        return $this->itemExtra;
387
    }
388
389
    public function getDisplaysExtra() : bool
390
    {
391
        return $this->displaysExtra;
392
    }
393
394
    public function setDisplaysExtra(bool $displaysExtra) : self
395
    {
396
        $this->displaysExtra = $displaysExtra;
397
398
        return $this;
399
    }
400
401
    public function getTitleSeparator() : string
402
    {
403
        return $this->titleSeparator;
404
    }
405
406
    public function setTitleSeparator(string $actionSeparator) : self
407
    {
408
        $this->titleSeparator = $actionSeparator;
409
410
        return $this;
411
    }
412
}
413