Completed
Pull Request — master (#18)
by Paulo Rodrigues
02:34
created

ChoiceQuestion::getChoices()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
/**
4
 * This file was "backported" from symfony/console for compatibility with
5
 * Symfony versions < 2.5.
6
 *
7
 * You can view the license at https://github.com/symfony/symfony/blob/master/LICENSE
8
 */
9
10
/*
11
 * This file is part of the Symfony package.
12
 *
13
 * (c) Fabien Potencier <[email protected]>
14
 *
15
 * For the full copyright and license information, please view the LICENSE
16
 * file that was distributed with this source code.
17
 */
18
19
namespace Rj\FrontendBundle\Command\Options\Legacy;
20
21
use Symfony\Component\Console\Exception\InvalidArgumentException;
22
23
/**
24
 * Represents a choice question.
25
 *
26
 * @author Fabien Potencier <[email protected]>
27
 */
28
class ChoiceQuestion extends Question
29
{
30
    private $choices;
31
    private $multiselect = false;
32
    private $prompt = ' > ';
33
    private $errorMessage = 'Value "%s" is invalid';
34
35
    /**
36
     * Constructor.
37
     *
38
     * @param string $question The question to ask to the user
39
     * @param array  $choices  The list of available choices
40
     * @param mixed  $default  The default answer to return
41
     */
42
    public function __construct($question, array $choices, $default = null)
43
    {
44
        parent::__construct($question, $default);
45
46
        $this->choices = $choices;
47
        $this->setValidator($this->getDefaultValidator());
48
        $this->setAutocompleterValues($choices);
49
    }
50
51
    /**
52
     * Returns available choices.
53
     *
54
     * @return array
55
     */
56
    public function getChoices()
57
    {
58
        return $this->choices;
59
    }
60
61
    /**
62
     * Sets multiselect option.
63
     *
64
     * When multiselect is set to true, multiple choices can be answered.
65
     *
66
     * @param bool $multiselect
67
     *
68
     * @return ChoiceQuestion The current instance
69
     */
70
    public function setMultiselect($multiselect)
71
    {
72
        $this->multiselect = $multiselect;
73
        $this->setValidator($this->getDefaultValidator());
74
75
        return $this;
76
    }
77
78
    /**
79
     * Gets the prompt for choices.
80
     *
81
     * @return string
82
     */
83
    public function getPrompt()
84
    {
85
        return $this->prompt;
86
    }
87
88
    /**
89
     * Sets the prompt for choices.
90
     *
91
     * @param string $prompt
92
     *
93
     * @return ChoiceQuestion The current instance
94
     */
95
    public function setPrompt($prompt)
96
    {
97
        $this->prompt = $prompt;
98
99
        return $this;
100
    }
101
102
    /**
103
     * Sets the error message for invalid values.
104
     *
105
     * The error message has a string placeholder (%s) for the invalid value.
106
     *
107
     * @param string $errorMessage
108
     *
109
     * @return ChoiceQuestion The current instance
110
     */
111
    public function setErrorMessage($errorMessage)
112
    {
113
        $this->errorMessage = $errorMessage;
114
        $this->setValidator($this->getDefaultValidator());
115
116
        return $this;
117
    }
118
119
    /**
120
     * Returns the default answer validator.
121
     *
122
     * @return callable
123
     */
124
    private function getDefaultValidator()
125
    {
126
        $choices = $this->choices;
127
        $errorMessage = $this->errorMessage;
128
        $multiselect = $this->multiselect;
129
        $isAssoc = $this->isAssoc($choices);
130
131
        return function ($selected) use ($choices, $errorMessage, $multiselect, $isAssoc) {
132
            // Collapse all spaces.
133
            $selectedChoices = str_replace(' ', '', $selected);
134
135
            if ($multiselect) {
136
                // Check for a separated comma values
137
                if (!preg_match('/^[a-zA-Z0-9_-]+(?:,[a-zA-Z0-9_-]+)*$/', $selectedChoices, $matches)) {
138
                    throw new InvalidArgumentException(sprintf($errorMessage, $selected));
139
                }
140
                $selectedChoices = explode(',', $selectedChoices);
141
            } else {
142
                $selectedChoices = array($selected);
143
            }
144
145
            $multiselectChoices = array();
146
            foreach ($selectedChoices as $value) {
147
                $results = array();
148
                foreach ($choices as $key => $choice) {
149
                    if ($choice === $value) {
150
                        $results[] = $key;
151
                    }
152
                }
153
154
                if (count($results) > 1) {
155
                    throw new InvalidArgumentException(sprintf('The provided answer is ambiguous. Value should be one of %s.', implode(' or ', $results)));
156
                }
157
158
                $result = array_search($value, $choices);
159
160
                if (!$isAssoc) {
161
                    if (false !== $result) {
162
                        $result = $choices[$result];
163
                    } elseif (isset($choices[$value])) {
164
                        $result = $choices[$value];
165
                    }
166
                } elseif (false === $result && isset($choices[$value])) {
167
                    $result = $value;
168
                }
169
170
                if (false === $result) {
171
                    throw new InvalidArgumentException(sprintf($errorMessage, $value));
172
                }
173
174
                $multiselectChoices[] = (string) $result;
175
            }
176
177
            if ($multiselect) {
178
                return $multiselectChoices;
179
            }
180
181
            return current($multiselectChoices);
182
        };
183
    }
184
}
185