Completed
Pull Request — master (#127)
by Aydin
01:59
created

SplitItem::getItems()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
namespace PhpSchool\CliMenu\MenuItem;
4
5
use Assert\Assertion;
6
use PhpSchool\CliMenu\CliMenu;
7
use PhpSchool\CliMenu\CliMenuBuilder;
8
use PhpSchool\CliMenu\MenuStyle;
9
use PhpSchool\CliMenu\Util\StringUtil;
10
11
/**
12
 * @author Michael Woodward <[email protected]>
13
 */
14
class SplitItem implements MenuItemInterface
15
{
16
    /**
17
     * @var array
18
     */
19
    private $items;
20
21
    /**
22
     * @var int
23
     */
24
    private $selectedItemIndex;
25
26
    /**
27
     * @var bool
28
     */
29
    private $canBeSelected = true;
30
31
    /**
32
     * @var int
33
     */
34
    private $margin = 2;
35
36
    /**
37
     * @var array
38
     */
39
    private static $blacklistedItems = [
40
        \PhpSchool\CliMenu\MenuItem\AsciiArtItem::class,
41
        \PhpSchool\CliMenu\MenuItem\LineBreakItem::class,
42
        \PhpSchool\CliMenu\MenuItem\SplitItem::class,
43
    ];
44
45
    public function __construct(array $items = [])
46
    {
47
        $this->items = $items;
48
49
        $this->setDefaultSelectedItem();
50
    }
51
52
    public function addMenuItem(MenuItemInterface $item) : self
53
    {
54
        foreach (self::$blacklistedItems as $bl) {
55
            if ($item instanceof $bl) {
56
                throw new \InvalidArgumentException("Cannot add a $bl to a SplitItem");
57
            }
58
        }
59
        $this->items[] = $item;
60
        $this->setDefaultSelectedItem();
61
        return $this;
62
    }
63
64
    public function addMenuItems(array $items) : self
65
    {
66
        foreach ($items as $item) {
67
            $this->addMenuItem($item);
68
        }
69
        return $this;
70
    }
71
    
72
    public function setItems(array $items) : self
73
    {
74
        $this->items = [];
75
        $this->addMenuItems($items);
76
        return $this;
77
    }
78
79
    /**
80
     * Select default item
81
     */
82
    private function setDefaultSelectedItem() : void
83
    {
84
        foreach ($this->items as $index => $item) {
85
            if ($item->canSelect()) {
86
                $this->canBeSelected = true;
87
                $this->selectedItemIndex = $index;
0 ignored issues
show
Documentation Bug introduced by
It seems like $index can also be of type string. However, the property $selectedItemIndex 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...
88
                return;
89
            }
90
        }
91
92
        $this->canBeSelected = false;
93
        $this->selectedItemIndex = null;
94
    }
95
96
    /**
97
     * The output text for the item
98
     */
99
    public function getRows(MenuStyle $style, bool $selected = false) : array
100
    {
101
        $numberOfItems = count($this->items);
102
103
        if (!$selected) {
104
            $this->setDefaultSelectedItem();
105
        }
106
107
        $length = $style->getDisplaysExtra()
108
            ? floor(($style->getContentWidth() - mb_strlen($style->getItemExtra()) + 2) / $numberOfItems)
109
            : floor($style->getContentWidth() / $numberOfItems);
110
            
111
        $length -= $this->margin;
112
        
113
        $missingLength = $style->getContentWidth() % $numberOfItems;
114
115
        $lines = 0;
116
        $cells = [];
117
        foreach ($this->items as $index => $item) {
118
            $isSelected = $selected && $index === $this->selectedItemIndex;
119
            $marker = sprintf("%s ", $style->getMarker($isSelected));
120
            $content = StringUtil::wordwrap(
121
                sprintf('%s%s', $marker, $item->getText()),
122
                $length
123
            );
124
            $cell = array_map(function ($row) use ($length, $style, $isSelected) {
125
                $invertedColoursSetCode = $isSelected
126
                    ? $style->getInvertedColoursSetCode()
127
                    : '';
128
                $invertedColoursUnsetCode = $isSelected
129
                    ? $style->getInvertedColoursUnsetCode()
130
                    : '';
131
132
                return sprintf(
133
                    "%s%s%s%s%s",
134
                    $invertedColoursSetCode,
135
                    $row,
136
                    str_repeat(' ', $length - mb_strlen($row)),
137
                    $invertedColoursUnsetCode,
138
                    str_repeat(' ', $this->margin)
139
                );
140
            }, explode("\n", $content));
141
            $lineCount = count($cell);
142
            if ($lineCount > $lines) {
143
                $lines = $lineCount;
144
            }
145
            $cells[] = $cell;
146
        }
147
148
        $rows = [];
149
        for ($i = 0; $i < $lines; $i++) {
150
            $row = "";
151
            if ($i > 0) {
152
                $row .= str_repeat(' ', 2);
153
            }
154
            foreach ($cells as $cell) {
155
                if (isset($cell[$i])) {
156
                    $row .= $cell[$i];
157
                } else {
158
                    $row .= str_repeat(' ', $length);
159
                }
160
            }
161
            if ($missingLength) {
162
                $row .= str_repeat(' ', $missingLength);
163
            }
164
            $rows[] = $row;
165
        }
166
167
        return $rows;
168
    }
169
170
    public function setSelectedItemIndex(int $index) : void
171
    {
172
        $this->selectedItemIndex = $index;
173
    }
174
175
    public function getSelectedItemIndex() : int
176
    {
177
        if ($this->selectedItemIndex === null) {
178
            return 0;
179
        }
180
        return $this->selectedItemIndex;
181
    }
182
183
    public function getSelectedItem() : MenuItemInterface
184
    {
185
        return $this->items[$this->selectedItemIndex];
186
    }
187
188
    public function getItems() : array
189
    {
190
        return $this->items;
191
    }
192
193
    /**
194
     * Can the item be selected
195
     * Not really in this case but that's the trick
196
     */
197
    public function canSelect() : bool
198
    {
199
        return $this->canBeSelected;
200
    }
201
202
    /**
203
     * Execute the items callable if required
204
     */
205
    public function getSelectAction() : ?callable
206
    {
207
        return null;
208
    }
209
210
    /**
211
     * Whether or not the menu item is showing the menustyle extra value
212
     */
213
    public function showsItemExtra() : bool
214
    {
215
        return false;
216
    }
217
218
    /**
219
     * Enable showing item extra
220
     */
221
    public function showItemExtra() : void
222
    {
223
        //noop
224
    }
225
226
    /**
227
     * Disable showing item extra
228
     */
229
    public function hideItemExtra() : void
230
    {
231
        //noop
232
    }
233
234
    /**
235
     * Return the raw string of text
236
     */
237
    public function getText() : string
238
    {
239
        $text = [];
240
        foreach ($this->items as $item) {
241
            $text[] = $item->getText();
242
        }
243
        return explode(' - ', $text);
244
    }
245
}
246