Skip to content

getSelectedItem() makes it impossible to group split items / Radio items #188

@jtreminio

Description

@jtreminio

public function getSelectedItem() : MenuItemInterface

If you have a group of MenuItem in a SplitItem calling CliMenu::getSelectedItem() returns the actual MenuItem, not the SplitItem group. This is fine.

However, there is currently no way of fetching the SplitItem group from within a callback:

<?php

use PhpSchool\CliMenu\Builder\SplitItemBuilder;
use PhpSchool\CliMenu\CliMenu;
use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\MenuItem\CheckableItem;

require_once(__DIR__ . '/../vendor/autoload.php');

$itemCallable = function (CliMenu $menu) {
    /** @var CheckableItem $item */
    $item = $menu->getSelectedItem();

    // Unable to access SplitItem from here
};

$menu = (new CliMenuBuilder)
    ->setTitle('Select a Language')
    ->addSplitItem(function (SplitItemBuilder $b) use ($itemCallable) {
        $b->setGutter(5)
            ->addCheckableItem('Rust', $itemCallable)
            ->addCheckableItem('C++', $itemCallable)
            ->addCheckableItem('Go', $itemCallable)
            ->addCheckableItem('Java', $itemCallable)
            ->addCheckableItem('C', $itemCallable)
        ;
    })
    ->build();

$menu->open();

If we add the following to CliMenu we can work around this problem:

    public function getSelectedSplitItem() : MenuItemInterface
    {
        if (null === $this->selectedItem) {
            throw new \RuntimeException('No selected item');
        }

        return $this->items[$this->selectedItem];
    }

and changing our code to reflect this:

<?php

use PhpSchool\CliMenu\Builder\SplitItemBuilder;
use PhpSchool\CliMenu\CliMenu;
use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\MenuItem\CheckableItem;
use PhpSchool\CliMenu\MenuItem\SplitItem;

require_once(__DIR__ . '/../vendor/autoload.php');

$itemCallable = function (CliMenu $menu) {
    /** @var CheckableItem $selected */
    $selected = $menu->getSelectedItem();

    /** @var SplitItem $splitGroup */
    $splitGroup = $menu->getSelectedSplitItem();

    $selected->toggle();

    /** @var CheckableItem $item */
    foreach ($splitGroup->getItems() as $item) {
        if (!is_a($item, CheckableItem::class)) {
            continue;
        }

        if ($item === $selected) {
            continue;
        }

        $item->setUnchecked();
    }

    $menu->redraw();
};

$menu = (new CliMenuBuilder)
    ->setTitle('Select a Language')
    ->addSplitItem(function (SplitItemBuilder $b) use ($itemCallable) {
        $b->setGutter(5)
            ->addCheckableItem('Rust', $itemCallable)
            ->addCheckableItem('C++', $itemCallable)
            ->addCheckableItem('Go', $itemCallable)
            ->addCheckableItem('Java', $itemCallable)
            ->addCheckableItem('C', $itemCallable)
        ;
    })
    ->build();

$menu->open();

results in radio-style elements:

Peek 2019-12-16 12-48

Thoughts?

edit: Adding CheckableItem via SplitItemBuilder is part of PR #189.

This issue that you are reading now deals with being able to group items together by fetching SplitItem from CliMenu. It can also be applied to normal SelectableItem.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions