Completed
Pull Request — master (#125)
by
unknown
04:12 queued 02:15
created

SplitItem::canSelect()   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 CliMenuBuilder
23
     */
24
    private $parentBuilder;
25
26
    /**
27
     * @var int
28
     */
29
    private $selectedItemIndex;
30
31
    /**
32
     * @var bool
33
     */
34
    private $canBeSelected = true;
35
36
    /**
37
     * @var int
38
     */
39
    private $margin = 2;
40
41
42
    public function __construct(CliMenuBuilder $builder, array $items = [])
43
    {
44
        $this->parentBuilder = $builder;
45
        $this->items         = $items;
46
47
        $this->setDefaultSelectedItem();
48
    }
49
50
    /**
51
     * Select default item
52
     */
53
    private function setDefaultSelectedItem()
54
    {
55
        foreach ($this->items as $index => $item) {
56
            if ($item->canSelect()) {
57
                $this->canBeSelected = true;
58
                $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...
59
                return;
60
            }
61
        }
62
63
        $this->canBeSelected = false;
64
        $this->selectedItemIndex = null;
65
    }
66
67
    public function addItem(
68
        string $text,
69
        callable $itemCallable,
70
        bool $showItemExtra = false,
71
        bool $disabled = false
72
    ) : self {
73
        $this->items[] = new SelectableItem($text, $itemCallable, $showItemExtra, $disabled);
74
        $this->setDefaultSelectedItem();
75
76
        return $this;
77
    }
78
79
    public function addStaticItem(string $text) : self
80
    {
81
        $this->items[] = new StaticItem($text);
82
        $this->setDefaultSelectedItem();
83
84
        return $this;
85
    }
86
87
    public function end() : CliMenuBuilder
88
    {
89
        return $this->parentBuilder;
90
    }
91
92
    /**
93
     * The output text for the item
94
     */
95
    public function getRows(MenuStyle $style, bool $selected = false) : array
96
    {
97
        $numberOfItems = count($this->items);
98
99
        if (!$selected) {
100
            $this->setDefaultSelectedItem();
101
        }
102
103
        $length = $style->getDisplaysExtra()
104
            ? floor(($style->getContentWidth() - mb_strlen($style->getItemExtra()) + 2) / $numberOfItems) - $this->margin
105
            : floor($style->getContentWidth() / $numberOfItems) - $this->margin;
106
        $missingLength = $style->getContentWidth() % $numberOfItems;
107
108
        $lines = 0;
109
        $cells = [];
110
        foreach ($this->items as $index => $item) {
111
            $isSelected = $selected && $index === $this->selectedItemIndex;
112
            $marker = sprintf("%s ", $style->getMarker($isSelected));
113
            $content = StringUtil::wordwrap(
114
                sprintf('%s%s', $marker, $item->getText()),
115
                $length
116
            );
117
            $cell = array_map(function ($row) use ($index, $length, $style, $isSelected) {
118
                $invertedColoursSetCode = $isSelected
119
                    ? $style->getInvertedColoursSetCode()
120
                    : '';
121
                $invertedColoursUnsetCode = $isSelected
122
                    ? $style->getInvertedColoursUnsetCode()
123
                    : '';
124
125
                return sprintf(
126
                    "%s%s%s%s%s",
127
                    $invertedColoursSetCode,
128
                    $row,
129
                    str_repeat(' ', $length - mb_strlen($row)),
130
                    $invertedColoursUnsetCode,
131
                    str_repeat(' ', $this->margin)
132
                );
133
            }, explode("\n", $content));
134
            $lineCount = count($cell);
135
            if ($lineCount > $lines) {
136
                $lines = $lineCount;
137
            }
138
            $cells[] = $cell;
139
        }
140
141
        $rows = [];
142
        for ($i = 0; $i < $lines; $i++) {
143
            $row = "";
144
            if ($i > 0) {
145
                $row .= str_repeat(' ', 2);
146
            }
147
            foreach ($cells as $cell) {
148
                if (isset($cell[$i])) {
149
                    $row .= $cell[$i];
150
                } else {
151
                    $row .= str_repeat(' ', $length);
152
                }
153
            }
154
            if ($missingLength) {
155
                $row .= str_repeat(' ', $missingLength);
156
            }
157
            $rows[] = $row;
158
        }
159
160
        return $rows;
161
    }
162
163
    public function setSelectedItemIndex(int $index) : void
164
    {
165
        $this->selectedItemIndex = $index;
166
    }
167
168
    public function getSelectedItemIndex() : int
169
    {
170
        if ($this->selectedItemIndex === null) {
171
            return 0;
172
        }
173
        return $this->selectedItemIndex;
174
    }
175
176
    public function getSelectedItem() : MenuItem
177
    {
178
        return $this->items[$this->selectedItemIndex];
179
    }
180
181
    public function getItems() : array
182
    {
183
        return $this->items;
184
    }
185
186
    /**
187
     * Can the item be selected
188
     * Not really in this case but that's the trick
189
     */
190
    public function canSelect() : bool
191
    {
192
        return $this->canBeSelected;
193
    }
194
195
    /**
196
     * Execute the items callable if required
197
     */
198
    public function getSelectAction() : ?callable
199
    {
200
        return null;
201
    }
202
203
    /**
204
     * Whether or not the menu item is showing the menustyle extra value
205
     */
206
    public function showsItemExtra() : bool
207
    {
208
        return false;
209
    }
210
211
    /**
212
     * Enable showing item extra
213
     */
214
    public function showItemExtra() : void
215
    {
216
        //noop
217
    }
218
219
    /**
220
     * Disable showing item extra
221
     */
222
    public function hideItemExtra() : void
223
    {
224
        //noop
225
    }
226
227
    /**
228
     * Return the raw string of text
229
     */
230
    public function getText() : string
231
    {
232
        $text = [];
233
        foreach ($this->items as $item) {
234
            $text[] = $item->getText();
235
        }
236
        return explode(' - ', $text);
237
    }
238
}
239