I'm trying to use the "choice" functionality that Laravel/Symfony provide as part of the console and having issues when it comes to numeric indexes.
I'm trying to simulate the behaviour of a HTML select element in the sense that you show string values but actually get back an associated ID and not the string.
Example - Unfortunately $choice is always the name but I want the ID
<?php
namespace App\Console\Commands;
use App\User;
use Illuminate\Console\Command;
class DoSomethingCommand extends Command
{
protected $signature = 'company:dosomething';
public function __construct()
{
parent::__construct();
}
public function handle()
{
$choice = $this->choice("Choose person", [
1 => 'Dave',
2 => 'John',
3 => 'Roy'
]);
}
}
Workaround - If I prefix the person ID then it works, but was hoping there is another way or is this just a limitation of the library?
<?php
namespace App\Console\Commands;
use App\User;
use Illuminate\Console\Command;
class DoSomethingCommand extends Command
{
protected $signature = 'company:dosomething';
public function __construct()
{
parent::__construct();
}
public function handle()
{
$choice = $this->choice("Choose person", [
"partner-1" => 'Dave',
"partner-2" => 'John',
"partner-3" => 'Roy'
]);
}
}
I have had the same question. I'm listing entities as choices, with IDs as keys and labels as values. I thought this would be extremely common case, so was surprised to find not much information about this limitation.
The issue is that the console will decide if to use the key as a value or not based on if the $choices
array is an associative array. It determines this by checking if there is at least one string key in the choices array -- so throwing in one bogus choice is one strategy.
$choices = [
1 => 'Dave',
2 => 'John',
3 => 'Roy',
'_' => 'bogus'
];
Note: You can't cast the keys to string (i.e. use "1"
instead of 1
) because PHP will always cast the string representation of an int to a true int when used as an array key.
The work around I have adopted is to extend the ChoiceQuestion
class and add a property to it, $useKeyAsValue
, to force if a key to be used as a value, and then override the ChoiceQuestion::isAssoc()
method to honour this property.
class ChoiceQuestion extends \Symfony\Component\Console\Question\ChoiceQuestion
{
/**
* @var bool|null
*/
private $useKeyAsValue;
public function __construct($question, array $choices, $useKeyAsValue = null, $default = null)
{
$this->useKeyAsValue = $useKeyAsValue;
parent::__construct($question, $choices, $default);
}
protected function isAssoc($array)
{
return $this->useKeyAsValue !== null ? (bool)$this->useKeyAsValue : parent::isAssoc($array);
}
}
This solution is a little risky. It assumes that Question::isAssoc()
will only ever be used to determine how the array of choices will be handled.
I had the same issue. Seems there is no options for this in the library. I solved it by concatenating the index or id with the value in the array. e.g.
$choices = [
1 => 'Dave-1',
2 => 'John-2',
3 => 'Roy-3'
];
$choice = $this->choice('Choose',$choices);
And then getting the part after '-' like
$id = substr( strrchr($choice, '-'), 1);;
This may or may not the best option, but if you are doing something really simple then:
$options = [
1 => 'Dave',
2 => 'John',
3 => 'Roy',
];
$choice = array_search(
$this->choice('Choose person', $options),
$options
);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With