Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 namespace DrupalCodeGenerator\Helper;
|
Chris@0
|
4
|
Chris@0
|
5 use DrupalCodeGenerator\Utils;
|
Chris@0
|
6 use Symfony\Component\Console\Exception\InvalidOptionException;
|
Chris@0
|
7 use Symfony\Component\Console\Helper\Helper;
|
Chris@0
|
8 use Symfony\Component\Console\Input\InputInterface;
|
Chris@0
|
9 use Symfony\Component\Console\Output\OutputInterface;
|
Chris@0
|
10 use Symfony\Component\Console\Question\ChoiceQuestion;
|
Chris@0
|
11 use Symfony\Component\Console\Question\ConfirmationQuestion;
|
Chris@0
|
12 use Symfony\Component\Console\Question\Question;
|
Chris@0
|
13
|
Chris@0
|
14 /**
|
Chris@0
|
15 * Generator input handler.
|
Chris@0
|
16 */
|
Chris@0
|
17 class InputHandler extends Helper {
|
Chris@0
|
18
|
Chris@0
|
19 use QuestionSettersTrait;
|
Chris@0
|
20
|
Chris@0
|
21 /**
|
Chris@0
|
22 * {@inheritdoc}
|
Chris@0
|
23 */
|
Chris@0
|
24 public function getName() {
|
Chris@0
|
25 return 'dcg_input_handler';
|
Chris@0
|
26 }
|
Chris@0
|
27
|
Chris@5
|
28 protected $askedQuestions = [];
|
Chris@5
|
29
|
Chris@0
|
30 /**
|
Chris@0
|
31 * Interacts with the user and returns variables for templates.
|
Chris@0
|
32 *
|
Chris@0
|
33 * @param \Symfony\Component\Console\Input\InputInterface $input
|
Chris@0
|
34 * Input instance.
|
Chris@0
|
35 * @param \Symfony\Component\Console\Output\OutputInterface $output
|
Chris@0
|
36 * Output instance.
|
Chris@0
|
37 * @param \Symfony\Component\Console\Question\Question[] $questions
|
Chris@0
|
38 * List of questions that the user should answer.
|
Chris@0
|
39 * @param array $vars
|
Chris@0
|
40 * Array of predefined template variables.
|
Chris@0
|
41 *
|
Chris@0
|
42 * @return array
|
Chris@0
|
43 * Template variables.
|
Chris@0
|
44 */
|
Chris@0
|
45 public function collectVars(InputInterface $input, OutputInterface $output, array $questions, array $vars = []) {
|
Chris@0
|
46
|
Chris@0
|
47 // A user can pass answers through the command line option.
|
Chris@0
|
48 $answers = NULL;
|
Chris@0
|
49 if ($answers_raw = $input->getOption('answers')) {
|
Chris@0
|
50 $answers = json_decode($answers_raw, TRUE);
|
Chris@0
|
51 if (!is_array($answers)) {
|
Chris@0
|
52 throw new InvalidOptionException('Answers should be encoded in JSON format.');
|
Chris@0
|
53 }
|
Chris@0
|
54 }
|
Chris@0
|
55
|
Chris@0
|
56 /** @var \Symfony\Component\Console\Helper\QuestionHelper $question_helper */
|
Chris@0
|
57 $question_helper = $this->getHelperSet()->get('question');
|
Chris@0
|
58
|
Chris@0
|
59 /** @var \DrupalCodeGenerator\Command\GeneratorInterface $command */
|
Chris@0
|
60 $command = $this->getHelperSet()->getCommand();
|
Chris@0
|
61 $directory = $command->getDirectory();
|
Chris@0
|
62
|
Chris@0
|
63 foreach ($questions as $name => $question) {
|
Chris@5
|
64
|
Chris@5
|
65 if (in_array($name, $this->askedQuestions)) {
|
Chris@5
|
66 continue;
|
Chris@5
|
67 }
|
Chris@5
|
68 $this->askedQuestions[] = $name;
|
Chris@5
|
69
|
Chris@0
|
70 /** @var \Symfony\Component\Console\Question\Question $question */
|
Chris@0
|
71 $default_value = $question->getDefault();
|
Chris@0
|
72
|
Chris@0
|
73 // Make some assumptions based on question name.
|
Chris@0
|
74 if ($default_value === NULL) {
|
Chris@0
|
75 switch ($name) {
|
Chris@0
|
76 case 'name':
|
Chris@0
|
77 $root_directory = basename(Utils::getExtensionRoot($directory) ?: $directory);
|
Chris@0
|
78 $default_value = Utils::machine2human($root_directory);
|
Chris@0
|
79 break;
|
Chris@0
|
80
|
Chris@0
|
81 case 'machine_name':
|
Chris@0
|
82 $default_value = function (array $vars) use ($directory) {
|
Chris@0
|
83 return Utils::human2machine(isset($vars['name']) ? $vars['name'] : basename($directory));
|
Chris@0
|
84 };
|
Chris@0
|
85 break;
|
Chris@0
|
86 }
|
Chris@0
|
87 }
|
Chris@0
|
88
|
Chris@0
|
89 // Turn the callback into a value acceptable for Symfony question helper.
|
Chris@0
|
90 if (is_callable($default_value)) {
|
Chris@0
|
91 // Do not treat simple strings as callable because they may match PHP
|
Chris@0
|
92 // builtin functions.
|
Chris@0
|
93 if (!is_string($default_value) || strpos('::', $default_value) !== FALSE) {
|
Chris@0
|
94 $default_value = call_user_func($default_value, $vars);
|
Chris@0
|
95 }
|
Chris@0
|
96 }
|
Chris@0
|
97 // Default value may have tokens.
|
Chris@0
|
98 $default_value = Utils::tokenReplace($default_value, $vars);
|
Chris@0
|
99 $this->setQuestionDefault($question, $default_value);
|
Chris@0
|
100
|
Chris@0
|
101 if ($answers) {
|
Chris@0
|
102 if (array_key_exists($name, $answers)) {
|
Chris@0
|
103 $answer = $answers[$name];
|
Chris@4
|
104 // Validate provided answer.
|
Chris@4
|
105 if ($validator = $question->getValidator()) {
|
Chris@4
|
106 $validator($answer);
|
Chris@4
|
107 }
|
Chris@0
|
108 // Turn 'yes/no' string into boolean.
|
Chris@0
|
109 if ($question instanceof ConfirmationQuestion && !is_bool($answer)) {
|
Chris@0
|
110 $answer = strcasecmp($answer, 'yes') == 0;
|
Chris@0
|
111 }
|
Chris@0
|
112 }
|
Chris@0
|
113 else {
|
Chris@0
|
114 $answer = $default_value;
|
Chris@0
|
115 }
|
Chris@0
|
116 }
|
Chris@0
|
117 else {
|
Chris@0
|
118 $this->formatQuestionText($question);
|
Chris@0
|
119 $answer = $question_helper->ask($input, $output, $question);
|
Chris@0
|
120 }
|
Chris@0
|
121
|
Chris@0
|
122 $vars[$name] = $answer;
|
Chris@0
|
123 }
|
Chris@0
|
124
|
Chris@0
|
125 return $vars;
|
Chris@0
|
126 }
|
Chris@0
|
127
|
Chris@0
|
128 /**
|
Chris@0
|
129 * Formats question text.
|
Chris@0
|
130 *
|
Chris@0
|
131 * @param \Symfony\Component\Console\Question\Question $question
|
Chris@0
|
132 * The question.
|
Chris@0
|
133 */
|
Chris@0
|
134 protected function formatQuestionText(Question $question) {
|
Chris@0
|
135 $question_text = $question->getQuestion();
|
Chris@0
|
136 $default_value = $question->getDefault();
|
Chris@0
|
137
|
Chris@0
|
138 $question_text = "\n <info>$question_text</info>";
|
Chris@0
|
139 if (is_bool($default_value)) {
|
Chris@0
|
140 $default_value = $default_value ? 'Yes' : 'No';
|
Chris@0
|
141 }
|
Chris@0
|
142 if ($default_value) {
|
Chris@0
|
143 $question_text .= " [<comment>$default_value</comment>]";
|
Chris@0
|
144 }
|
Chris@0
|
145 $question_text .= ":";
|
Chris@0
|
146 if ($question instanceof ChoiceQuestion) {
|
Chris@0
|
147 $question->setPrompt(' ➤➤➤ ');
|
Chris@0
|
148 }
|
Chris@0
|
149 else {
|
Chris@0
|
150 $question_text .= "\n ➤ ";
|
Chris@0
|
151 }
|
Chris@0
|
152
|
Chris@0
|
153 $this->setQuestionText($question, $question_text);
|
Chris@0
|
154 }
|
Chris@0
|
155
|
Chris@0
|
156 /**
|
Chris@0
|
157 * Normalizes questions.
|
Chris@0
|
158 *
|
Chris@0
|
159 * @param \Symfony\Component\Console\Question\Question[] $questions
|
Chris@0
|
160 * Questions to normalize.
|
Chris@0
|
161 *
|
Chris@0
|
162 * @return \Symfony\Component\Console\Question\Question[]
|
Chris@0
|
163 * Normalized questions
|
Chris@0
|
164 *
|
Chris@0
|
165 * @deprecated
|
Chris@0
|
166 * Use Symfony\Component\Console\Question\Question to define questions.
|
Chris@0
|
167 *
|
Chris@0
|
168 * @codeCoverageIgnore
|
Chris@0
|
169 */
|
Chris@0
|
170 protected function normalizeQuestions(array $questions) {
|
Chris@0
|
171 return array_map(function ($question) {
|
Chris@0
|
172 // Support array syntax.
|
Chris@0
|
173 if (is_array($question)) {
|
Chris@0
|
174 if (count($question) > 2) {
|
Chris@0
|
175 throw new \OutOfBoundsException('The question array is too long.');
|
Chris@0
|
176 }
|
Chris@0
|
177 list($question_text, $default_value) = array_pad($question, 2, NULL);
|
Chris@0
|
178 $question = new Question($question_text, $default_value);
|
Chris@0
|
179 }
|
Chris@0
|
180 return $question;
|
Chris@0
|
181 }, $questions);
|
Chris@0
|
182 }
|
Chris@0
|
183
|
Chris@0
|
184 }
|