Chris@0: Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: namespace Symfony\Component\Console\Question; Chris@0: Chris@0: use Symfony\Component\Console\Exception\InvalidArgumentException; Chris@0: Chris@0: /** Chris@0: * Represents a choice question. Chris@0: * Chris@0: * @author Fabien Potencier Chris@0: */ Chris@0: class ChoiceQuestion extends Question Chris@0: { Chris@0: private $choices; Chris@0: private $multiselect = false; Chris@0: private $prompt = ' > '; Chris@0: private $errorMessage = 'Value "%s" is invalid'; Chris@0: Chris@0: /** Chris@0: * @param string $question The question to ask to the user Chris@0: * @param array $choices The list of available choices Chris@0: * @param mixed $default The default answer to return Chris@0: */ Chris@0: public function __construct($question, array $choices, $default = null) Chris@0: { Chris@12: if (!$choices) { Chris@12: throw new \LogicException('Choice question must have at least 1 choice available.'); Chris@12: } Chris@12: Chris@0: parent::__construct($question, $default); Chris@0: Chris@0: $this->choices = $choices; Chris@0: $this->setValidator($this->getDefaultValidator()); Chris@0: $this->setAutocompleterValues($choices); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns available choices. Chris@0: * Chris@0: * @return array Chris@0: */ Chris@0: public function getChoices() Chris@0: { Chris@0: return $this->choices; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Sets multiselect option. Chris@0: * Chris@0: * When multiselect is set to true, multiple choices can be answered. Chris@0: * Chris@0: * @param bool $multiselect Chris@0: * Chris@0: * @return $this Chris@0: */ Chris@0: public function setMultiselect($multiselect) Chris@0: { Chris@0: $this->multiselect = $multiselect; Chris@0: $this->setValidator($this->getDefaultValidator()); Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns whether the choices are multiselect. Chris@0: * Chris@0: * @return bool Chris@0: */ Chris@0: public function isMultiselect() Chris@0: { Chris@0: return $this->multiselect; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Gets the prompt for choices. Chris@0: * Chris@0: * @return string Chris@0: */ Chris@0: public function getPrompt() Chris@0: { Chris@0: return $this->prompt; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Sets the prompt for choices. Chris@0: * Chris@0: * @param string $prompt Chris@0: * Chris@0: * @return $this Chris@0: */ Chris@0: public function setPrompt($prompt) Chris@0: { Chris@0: $this->prompt = $prompt; Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Sets the error message for invalid values. Chris@0: * Chris@0: * The error message has a string placeholder (%s) for the invalid value. Chris@0: * Chris@0: * @param string $errorMessage Chris@0: * Chris@0: * @return $this Chris@0: */ Chris@0: public function setErrorMessage($errorMessage) Chris@0: { Chris@0: $this->errorMessage = $errorMessage; Chris@0: $this->setValidator($this->getDefaultValidator()); Chris@0: Chris@0: return $this; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns the default answer validator. Chris@0: * Chris@0: * @return callable Chris@0: */ Chris@0: private function getDefaultValidator() Chris@0: { Chris@0: $choices = $this->choices; Chris@0: $errorMessage = $this->errorMessage; Chris@0: $multiselect = $this->multiselect; Chris@0: $isAssoc = $this->isAssoc($choices); Chris@0: Chris@0: return function ($selected) use ($choices, $errorMessage, $multiselect, $isAssoc) { Chris@0: // Collapse all spaces. Chris@0: $selectedChoices = str_replace(' ', '', $selected); Chris@0: Chris@0: if ($multiselect) { Chris@0: // Check for a separated comma values Chris@12: if (!preg_match('/^[^,]+(?:,[^,]+)*$/', $selectedChoices, $matches)) { Chris@0: throw new InvalidArgumentException(sprintf($errorMessage, $selected)); Chris@0: } Chris@0: $selectedChoices = explode(',', $selectedChoices); Chris@0: } else { Chris@17: $selectedChoices = [$selected]; Chris@0: } Chris@0: Chris@17: $multiselectChoices = []; Chris@0: foreach ($selectedChoices as $value) { Chris@17: $results = []; Chris@0: foreach ($choices as $key => $choice) { Chris@0: if ($choice === $value) { Chris@0: $results[] = $key; Chris@0: } Chris@0: } Chris@0: Chris@17: if (\count($results) > 1) { Chris@0: throw new InvalidArgumentException(sprintf('The provided answer is ambiguous. Value should be one of %s.', implode(' or ', $results))); Chris@0: } Chris@0: Chris@0: $result = array_search($value, $choices); Chris@0: Chris@0: if (!$isAssoc) { Chris@0: if (false !== $result) { Chris@0: $result = $choices[$result]; Chris@0: } elseif (isset($choices[$value])) { Chris@0: $result = $choices[$value]; Chris@0: } Chris@0: } elseif (false === $result && isset($choices[$value])) { Chris@0: $result = $value; Chris@0: } Chris@0: Chris@0: if (false === $result) { Chris@0: throw new InvalidArgumentException(sprintf($errorMessage, $value)); Chris@0: } Chris@0: Chris@0: $multiselectChoices[] = (string) $result; Chris@0: } Chris@0: Chris@0: if ($multiselect) { Chris@0: return $multiselectChoices; Chris@0: } Chris@0: Chris@0: return current($multiselectChoices); Chris@0: }; Chris@0: } Chris@0: }