3 namespace DrupalCodeGenerator\Helper;
5 use DrupalCodeGenerator\Utils;
6 use Symfony\Component\Console\Exception\InvalidOptionException;
7 use Symfony\Component\Console\Helper\Helper;
8 use Symfony\Component\Console\Input\InputInterface;
9 use Symfony\Component\Console\Output\OutputInterface;
10 use Symfony\Component\Console\Question\ChoiceQuestion;
11 use Symfony\Component\Console\Question\ConfirmationQuestion;
12 use Symfony\Component\Console\Question\Question;
15 * Generator input handler.
17 class InputHandler extends Helper {
19 use QuestionSettersTrait;
24 public function getName() {
25 return 'dcg_input_handler';
29 * Interacts with the user and returns variables for templates.
31 * @param \Symfony\Component\Console\Input\InputInterface $input
33 * @param \Symfony\Component\Console\Output\OutputInterface $output
35 * @param \Symfony\Component\Console\Question\Question[] $questions
36 * List of questions that the user should answer.
38 * Array of predefined template variables.
43 public function collectVars(InputInterface $input, OutputInterface $output, array $questions, array $vars = []) {
45 // A user can pass answers through command line option.
46 if ($answers_raw = $input->getOption('answers')) {
47 $answers = json_decode($answers_raw, TRUE);
48 if (!is_array($answers)) {
49 throw new InvalidOptionException('Answers should be encoded in JSON format.');
56 /** @var \DrupalCodeGenerator\Command\GeneratorInterface $command */
57 $command = $this->getHelperSet()->getCommand();
58 $directory = $command->getDirectory();
60 foreach ($questions as $name => $question) {
61 /** @var \Symfony\Component\Console\Question\Question $question */
62 $default_value = $question->getDefault();
64 // Make some assumptions based on question name.
65 if ($default_value === NULL) {
68 $root_directory = basename(Utils::getExtensionRoot($directory) ?: $directory);
69 $default_value = Utils::machine2human($root_directory);
73 $default_value = function (array $vars) use ($directory) {
74 return Utils::human2machine(isset($vars['name']) ? $vars['name'] : basename($directory));
80 // Turn the callback into a value acceptable for Symfony question helper.
81 if (is_callable($default_value)) {
82 // Do not treat simple strings as callable because they may match PHP
84 if (!is_string($default_value) || strpos('::', $default_value) !== FALSE) {
85 $default_value = call_user_func($default_value, $vars);
89 // Default value may have tokens.
90 $default_value = Utils::tokenReplace($default_value, $vars);
92 $this->setQuestionDefault($question, $default_value);
94 if (array_key_exists($name, $answers)) {
95 $answer = $answers[$name];
96 // Null stands for default value.
97 if ($answer === NULL) {
98 $answer = $default_value;
100 // Turn 'yes/no' string into boolean.
101 elseif ($question instanceof ConfirmationQuestion && !is_bool($answer)) {
102 $answer = strcasecmp($answer, 'yes') == 0;
106 $this->formatQuestionText($question);
107 /** @var \Symfony\Component\Console\Helper\QuestionHelper $question_helper */
108 $question_helper = $this->getHelperSet()->get('question');
109 $answer = $question_helper->ask($input, $output, $question);
112 $vars[$name] = $answer;
119 * Formats question text.
121 * @param \Symfony\Component\Console\Question\Question $question
124 protected function formatQuestionText(Question $question) {
125 $question_text = $question->getQuestion();
126 $default_value = $question->getDefault();
128 $question_text = "\n <info>$question_text</info>";
129 if (is_bool($default_value)) {
130 $default_value = $default_value ? 'Yes' : 'No';
132 if ($default_value) {
133 $question_text .= " [<comment>$default_value</comment>]";
135 $question_text .= ":";
136 if ($question instanceof ChoiceQuestion) {
137 $question->setPrompt(' ➤➤➤ ');
140 $question_text .= "\n ➤ ";
143 $this->setQuestionText($question, $question_text);
147 * Normalizes questions.
149 * @param \Symfony\Component\Console\Question\Question[] $questions
150 * Questions to normalize.
152 * @return \Symfony\Component\Console\Question\Question[]
153 * Normalized questions
156 * Use Symfony\Component\Console\Question\Question to define questions.
158 * @codeCoverageIgnore
160 protected function normalizeQuestions(array $questions) {
161 return array_map(function ($question) {
162 // Support array syntax.
163 if (is_array($question)) {
164 if (count($question) > 2) {
165 throw new \OutOfBoundsException('The question array is too long.');
167 list($question_text, $default_value) = array_pad($question, 2, NULL);
168 $question = new Question($question_text, $default_value);