Skip to content

Commit 7dfdf75

Browse files
authored
Merge pull request #156 from php-school/selected-item-bugs
Selected item bugs
2 parents c2adaff + 94c1df9 commit 7dfdf75

File tree

2 files changed

+97
-11
lines changed

2 files changed

+97
-11
lines changed

src/CliMenu.php

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class CliMenu
5151
protected $items = [];
5252

5353
/**
54-
* @var int
54+
* @var int|null
5555
*/
5656
protected $selectedItem;
5757

@@ -164,9 +164,7 @@ public function addItem(MenuItemInterface $item) : void
164164
{
165165
$this->items[] = $item;
166166

167-
if (count($this->items) === 1) {
168-
$this->selectFirstItem();
169-
}
167+
$this->selectFirstItem();
170168
}
171169

172170
/**
@@ -178,16 +176,15 @@ public function addItems(array $items) : void
178176
$this->items[] = $item;
179177
}
180178

181-
if (count($this->items) === count($items)) {
182-
$this->selectFirstItem();
183-
}
179+
$this->selectFirstItem();
184180
}
185181

186182
/**
187183
* Set Items of the menu
188184
*/
189185
public function setItems(array $items) : void
190186
{
187+
$this->selectedItem = null;
191188
$this->items = $items;
192189

193190
$this->selectFirstItem();
@@ -198,10 +195,12 @@ public function setItems(array $items) : void
198195
*/
199196
private function selectFirstItem() : void
200197
{
201-
foreach ($this->items as $key => $item) {
202-
if ($item->canSelect()) {
203-
$this->selectedItem = $key;
204-
break;
198+
if (null === $this->selectedItem) {
199+
foreach ($this->items as $key => $item) {
200+
if ($item->canSelect()) {
201+
$this->selectedItem = $key;
202+
break;
203+
}
205204
}
206205
}
207206
}
@@ -348,6 +347,10 @@ private function canSelect() : bool
348347
*/
349348
public function getSelectedItem() : MenuItemInterface
350349
{
350+
if (null === $this->selectedItem) {
351+
throw new \RuntimeException('No selected item');
352+
}
353+
351354
$item = $this->items[$this->selectedItem];
352355
return $item instanceof SplitItem
353356
? $item->getSelectedItem()
@@ -543,6 +546,11 @@ public function removeItem(MenuItemInterface $item) : void
543546

544547
unset($this->items[$key]);
545548
$this->items = array_values($this->items);
549+
550+
if ($this->selectedItem === $key) {
551+
$this->selectedItem = null;
552+
$this->selectFirstItem();
553+
}
546554
}
547555

548556
public function getStyle() : MenuStyle

test/CliMenuTest.php

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -842,6 +842,84 @@ public function testSelectableCallableReceivesSelectableAndNotSplitItem() : void
842842
self::assertSame($expectedSelectedItem, $actualSelectedItem);
843843
}
844844

845+
public function testAddItemSelectsFirstSelectableItemWhenItemsExistButNoneAreSelectable() : void
846+
{
847+
$menu = new CliMenu('PHP School FTW', [], $this->terminal);
848+
$menu->addItem(new StaticItem('No Selectable'));
849+
850+
self::assertNull(self::readAttribute($menu, 'selectedItem'));
851+
852+
$menu->addItem($item = new SelectableItem('Selectable', function () {
853+
}));
854+
855+
self::assertEquals($item, $menu->getSelectedItem());
856+
}
857+
858+
public function testAddItemsSelectsFirstSelectableItemWhenItemsExistButNoneAreSelectable() : void
859+
{
860+
$menu = new CliMenu('PHP School FTW', [], $this->terminal);
861+
$menu->addItem(new StaticItem('No Selectable'));
862+
863+
self::assertNull(self::readAttribute($menu, 'selectedItem'));
864+
865+
$menu->addItems([$item = new SelectableItem('Selectable', function () {
866+
})]);
867+
868+
self::assertEquals($item, $menu->getSelectedItem());
869+
}
870+
871+
public function testSetItemsReSelectsFirstSelectableItem() : void
872+
{
873+
$menu = new CliMenu('PHP School FTW', [], $this->terminal);
874+
$menu->addItem(new StaticItem('No Selectable'));
875+
$menu->addItem($item = new SelectableItem('Selectable', function () {
876+
}));
877+
878+
self::assertEquals($item, $menu->getSelectedItem());
879+
880+
$menu->setItems([$item2 = new SelectableItem('Selectable', function () {
881+
})]);
882+
883+
self::assertEquals($item2, $menu->getSelectedItem());
884+
}
885+
886+
public function testRemoveItemReSelectsFirstSelectableItemIfSelectedItemRemoved() : void
887+
{
888+
$menu = new CliMenu('PHP School FTW', [], $this->terminal);
889+
$menu->addItem(new StaticItem('No Selectable'));
890+
$menu->addItem($item = new SelectableItem('Selectable', function () {
891+
}));
892+
893+
self::assertEquals($item, $menu->getSelectedItem());
894+
895+
$menu->removeItem($item);
896+
897+
self::assertNull(self::readAttribute($menu, 'selectedItem'));
898+
899+
$menu = new CliMenu('PHP School FTW', [], $this->terminal);
900+
$menu->addItem(new StaticItem('No Selectable'));
901+
$menu->addItem($item1 = new SelectableItem('Selectable', function () {
902+
}));
903+
$menu->addItem($item2 = new SelectableItem('Selectable', function () {
904+
}));
905+
906+
self::assertEquals($item1, $menu->getSelectedItem());
907+
908+
$menu->removeItem($item1);
909+
910+
self::assertEquals($item2, $menu->getSelectedItem());
911+
}
912+
913+
public function testGetSelectedItemThrowsExceptionIfNoSelectedItem() : void
914+
{
915+
self::expectException(\RuntimeException::class);
916+
self::expectExceptionMessage('No selected item');
917+
918+
$menu = new CliMenu('PHP School FTW', [], $this->terminal);
919+
$menu->addItem(new StaticItem('No Selectable'));
920+
$menu->getSelectedItem();
921+
}
922+
845923
private function getTestFile() : string
846924
{
847925
return sprintf('%s/res/%s.txt', __DIR__, $this->getName());

0 commit comments

Comments
 (0)