Completed
Pull Request — master (#84)
by
unknown
05:28
created

SplitItem::hideItemExtra()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 1

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