Completed
Pull Request — master (#18)
by Paulo Rodrigues
06:47
created

ChoiceQuestion::setPrompt()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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