Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / vendor / chi-teck / drupal-code-generator / src / Command / BaseGenerator.php
1 <?php
2
3 namespace DrupalCodeGenerator\Command;
4
5 use DrupalCodeGenerator\ApplicationFactory;
6 use DrupalCodeGenerator\Asset;
7 use DrupalCodeGenerator\Utils;
8 use Symfony\Component\Console\Command\Command;
9 use Symfony\Component\Console\Input\InputInterface;
10 use Symfony\Component\Console\Input\InputOption;
11 use Symfony\Component\Console\Output\OutputInterface;
12 use Symfony\Component\Console\Question\Question;
13
14 /**
15  * Base class for all generators.
16  */
17 abstract class BaseGenerator extends Command implements GeneratorInterface {
18
19   /**
20    * The command name.
21    *
22    * @var string
23    */
24   protected $name;
25
26   /**
27    * The command description.
28    *
29    * @var string
30    */
31   protected $description;
32
33   /**
34    * The command alias.
35    *
36    * @var string
37    */
38   protected $alias;
39
40   /**
41    * Command label.
42    *
43    * @var string
44    */
45   protected $label;
46
47   /**
48    * A path where templates are stored.
49    *
50    * @var string
51    */
52   protected $templatePath;
53
54   /**
55    * The working directory.
56    *
57    * @var string
58    */
59   protected $directory;
60
61   /**
62    * The destination.
63    *
64    * @var mixed
65    */
66   protected $destination = 'modules/%';
67
68   /**
69    * Files to create.
70    *
71    * The key of the each item in the array is the path to the file and
72    * the value is the generated content of it.
73    *
74    * @var array
75    *
76    * @deprecated Use self::$assets.
77    */
78   protected $files = [];
79
80   /**
81    * Assets to create.
82    *
83    * @var \DrupalCodeGenerator\Asset[]
84    */
85   protected $assets = [];
86
87   /**
88    * Twig template variables.
89    *
90    * @var array
91    */
92   protected $vars = [];
93
94   /**
95    * {@inheritdoc}
96    */
97   protected function configure() {
98     $this
99       ->setName($this->name)
100       ->setDescription($this->description)
101       ->addOption(
102         'directory',
103         '-d',
104         InputOption::VALUE_OPTIONAL,
105         'Working directory'
106       )
107       ->addOption(
108         'answers',
109         '-a',
110         InputOption::VALUE_OPTIONAL,
111         'Default JSON formatted answers'
112       );
113
114     if ($this->alias) {
115       $this->setAliases([$this->alias]);
116     }
117
118     if (!$this->templatePath) {
119       $this->templatePath = ApplicationFactory::getRoot() . '/templates';
120     }
121   }
122
123   /**
124    * {@inheritdoc}
125    */
126   protected function initialize(InputInterface $input, OutputInterface $output) {
127     $this->getHelperSet()->setCommand($this);
128     $this->getHelper('dcg_renderer')->addPath($this->templatePath);
129
130     $directory = $input->getOption('directory') ?: getcwd();
131     // No need to look up for extension root when generating an extension.
132     $extension_destinations = ['modules', 'profiles', 'themes'];
133     $is_extension = in_array($this->destination, $extension_destinations);
134     $this->directory = $is_extension
135       ? $directory : (Utils::getExtensionRoot($directory) ?: $directory);
136
137     // Display welcome message.
138     $header = sprintf(
139       "\n Welcome to %s generator!",
140       $this->getName()
141     );
142     $output->writeln($header);
143     $header_length = strlen(trim(strip_tags($header)));
144     $output->writeln('<fg=cyan;options=bold>–' . str_repeat('–', $header_length) . '–</>');
145   }
146
147   /**
148    * {@inheritdoc}
149    */
150   protected function execute(InputInterface $input, OutputInterface $output) {
151
152     // Render all assets.
153     $renderer = $this->getHelper('dcg_renderer');
154     foreach ($this->getAssets() as $asset) {
155       // Supply the asset with all collected variables if it has no local ones.
156       if (!$asset->getVars()) {
157         $asset->vars($this->vars);
158       }
159       $asset->render($renderer);
160     }
161
162     $dumped_files = $this->getHelper('dcg_dumper')->dump($input, $output);
163     $this->getHelper('dcg_output_handler')->printSummary($output, $dumped_files);
164     return 0;
165   }
166
167   /**
168    * {@inheritdoc}
169    */
170   public function getLabel() {
171     return $this->label;
172   }
173
174   /**
175    * Returns list of rendered files.
176    *
177    * @return array
178    *   An associative array where each key is path to a file and value is
179    *   rendered content.
180    *
181    * @deprecated.
182    */
183   public function getFiles() {
184     return $this->files;
185   }
186
187   /**
188    * {@inheritdoc}
189    */
190   public function getAssets() {
191     if ($this->files) {
192       // Convert files into assets for legacy commands.
193       $assets = [];
194       foreach ($this->getFiles() as $path => $file) {
195         $asset = new Asset();
196         $asset->path($path);
197         if (!is_array($file)) {
198           $file = ['content' => $file];
199         }
200         if (isset($file['content'])) {
201           $asset->content($file['content']);
202         }
203         else {
204           $asset->type('directory');
205         }
206         if (isset($file['action'])) {
207           $asset->action($file['action']);
208         }
209         if (isset($file['header_size'])) {
210           $asset->headerSize($file['header_size']);
211         }
212         if (isset($file['mode'])) {
213           $asset->mode($file['mode']);
214         }
215         $assets[] = $asset;
216       }
217       return array_merge($assets, $this->assets);
218     }
219
220     return $this->assets;
221   }
222
223   /**
224    * {@inheritdoc}
225    */
226   public function setDirectory($directory) {
227     $this->directory = $directory;
228   }
229
230   /**
231    * {@inheritdoc}
232    */
233   public function getDirectory() {
234     return $this->directory;
235   }
236
237   /**
238    * {@inheritdoc}
239    */
240   public function setDestination($destination) {
241     $this->destination = $destination;
242   }
243
244   /**
245    * {@inheritdoc}
246    */
247   public function getDestination() {
248     return $this->destination;
249   }
250
251   /**
252    * Renders a template.
253    *
254    * @param string $template
255    *   Twig template.
256    * @param array $vars
257    *   Template variables.
258    *
259    * @return string
260    *   A string representing the rendered output.
261    */
262   protected function render($template, array $vars) {
263     return $this->getHelper('dcg_renderer')->render($template, $vars);
264   }
265
266   /**
267    * Asks the user for template variables.
268    *
269    * @param \Symfony\Component\Console\Input\InputInterface $input
270    *   Input instance.
271    * @param \Symfony\Component\Console\Output\OutputInterface $output
272    *   Output instance.
273    * @param array $questions
274    *   List of questions that the user should answer.
275    * @param array $vars
276    *   Array of predefined template variables.
277    *
278    * @return array
279    *   Template variables.
280    *
281    * @see \DrupalCodeGenerator\InputHandler::collectVars()
282    */
283   protected function &collectVars(InputInterface $input, OutputInterface $output, array $questions, array $vars = []) {
284     $this->vars += $this->getHelper('dcg_input_handler')->collectVars($input, $output, $questions, $vars);
285     return $this->vars;
286   }
287
288   /**
289    * Asks the user a single question and returns the answer.
290    *
291    * @param \Symfony\Component\Console\Input\InputInterface $input
292    *   Input instance.
293    * @param \Symfony\Component\Console\Output\OutputInterface $output
294    *   Output instance.
295    * @param \Symfony\Component\Console\Question\Question $question
296    *   A question to ask.
297    * @param array $vars
298    *   Array of predefined template variables.
299    *
300    * @return string
301    *   The answer.
302    *
303    * @see \DrupalCodeGenerator\InputHandler::collectVars()
304    */
305   protected function ask(InputInterface $input, OutputInterface $output, Question $question, array $vars = []) {
306     $answers = $this->getHelper('dcg_input_handler')->collectVars($input, $output, ['key' => $question], $vars);
307     return $answers['key'];
308   }
309
310   /**
311    * Creates an asset.
312    *
313    * @param string $type
314    *   Asset type.
315    *
316    * @return \DrupalCodeGenerator\Asset
317    *   The asset.
318    */
319   protected function addAsset($type) {
320     $asset = (new Asset())->type($type);
321     $this->assets[] = $asset;
322     return $asset;
323   }
324
325   /**
326    * Creates file asset.
327    *
328    * @return \DrupalCodeGenerator\Asset
329    *   The asset.
330    */
331   protected function addFile() {
332     return $this->addAsset('file');
333   }
334
335   /**
336    * Creates directory asset.
337    *
338    * @return \DrupalCodeGenerator\Asset
339    *   The asset.
340    */
341   protected function addDirectory() {
342     return $this->addAsset('directory');
343   }
344
345   /**
346    * Creates service file asset.
347    *
348    * @return \DrupalCodeGenerator\Asset
349    *   The asset.
350    */
351   protected function addServicesFile() {
352     return $this->addFile()
353       ->path('{machine_name}.services.yml')
354       ->action('append')
355       ->headerSize(1);
356   }
357
358   /**
359    * Creates file asset.
360    *
361    * @param string $path
362    *   Path to the file.
363    * @param string $template
364    *   Twig template to render.
365    * @param array $vars
366    *   Twig variables.
367    *
368    * @deprecated Use self::addFile() or self::addDirectory().
369    */
370   protected function setFile($path = NULL, $template = NULL, array $vars = []) {
371     $this->addFile()
372       ->path($path)
373       ->template($template)
374       ->vars($vars);
375   }
376
377   /**
378    * Creates service file asset.
379    *
380    * @param string $path
381    *   Path to the file.
382    * @param string $template
383    *   Twig template to render.
384    * @param array $vars
385    *   Twig variables.
386    *
387    * @deprecated Use self::addServiceFile().
388    */
389   protected function setServicesFile($path, $template, array $vars) {
390     $this->addServicesFile()
391       ->path($path)
392       ->template($template)
393       ->vars($vars);
394   }
395
396   /**
397    * Collects services.
398    *
399    * @param \Symfony\Component\Console\Input\InputInterface $input
400    *   Input instance.
401    * @param \Symfony\Component\Console\Output\OutputInterface $output
402    *   Output instance.
403    *
404    * @return array
405    *   List of collected services.
406    */
407   protected function collectServices(InputInterface $input, OutputInterface $output) {
408
409     $service_definitions = self::getServiceDefinitions();
410     $service_ids = array_keys($service_definitions);
411
412     $services = [];
413     while (TRUE) {
414       $question = new Question('Type the service name or use arrows up/down. Press enter to continue');
415       $question->setValidator([Utils::class, 'validateServiceName']);
416       $question->setAutocompleterValues($service_ids);
417       $service = $this->ask($input, $output, $question);
418       if (!$service) {
419         break;
420       }
421       $services[] = $service;
422     }
423
424     $this->vars['services'] = [];
425     foreach (array_unique($services) as $service_id) {
426       if (isset($service_definitions[$service_id])) {
427         $definition = $service_definitions[$service_id];
428       }
429       else {
430         // Build the definition if the service is unknown.
431         $definition = [
432           'type' => 'Drupal\example\ExampleInterface',
433           'name' => str_replace('.', '_', $service_id),
434           'description' => "The $service_id service.",
435         ];
436       }
437       $type_parts = explode('\\', $definition['type']);
438       $definition['short_type'] = end($type_parts);
439       $this->vars['services'][$service_id] = $definition;
440     }
441     return $this->vars['services'];
442   }
443
444   /**
445    * Gets service definitions.
446    *
447    * @return array
448    *   List of service definitions keyed by service ID.
449    */
450   protected static function getServiceDefinitions() {
451     $data_encoded = file_get_contents(ApplicationFactory::getRoot() . '/resources/service-definitions.json');
452     return json_decode($data_encoded, TRUE);
453   }
454
455 }