1127bcefe375b54d223489256e97dbe4641cfbb7
[yaffs-website] / vendor / drupal / console / src / Command / Generate / ModuleCommand.php
1 <?php
2
3 /**
4  * @file
5  * Contains \Drupal\Console\Command\Generate\ModuleCommand.
6  */
7
8 namespace Drupal\Console\Command\Generate;
9
10 use Symfony\Component\Config\Definition\Exception\Exception;
11 use Symfony\Component\Console\Input\InputInterface;
12 use Symfony\Component\Console\Input\InputOption;
13 use Symfony\Component\Console\Output\OutputInterface;
14 use Drupal\Console\Generator\ModuleGenerator;
15 use Drupal\Console\Command\Shared\ConfirmationTrait;
16 use Symfony\Component\Console\Command\Command;
17 use Drupal\Console\Core\Style\DrupalStyle;
18 use Drupal\Console\Utils\Validator;
19 use Drupal\Console\Core\Command\Shared\CommandTrait;
20 use Drupal\Console\Core\Utils\StringConverter;
21 use Drupal\Console\Utils\DrupalApi;
22 use GuzzleHttp\Client;
23 use Drupal\Console\Utils\Site;
24 use GuzzleHttp\Exception\ClientException;
25
26 class ModuleCommand extends Command
27 {
28     use ConfirmationTrait;
29     use CommandTrait;
30
31     /**
32  * @var ModuleGenerator
33 */
34     protected $generator;
35
36     /**
37  * @var Validator
38 */
39     protected $validator;
40
41     /**
42      * @var string
43      */
44     protected $appRoot;
45
46     /**
47      * @var StringConverter
48      */
49     protected $stringConverter;
50
51     /**
52      * @var DrupalApi
53      */
54     protected $drupalApi;
55
56     /**
57      * @var Client
58      */
59     protected $httpClient;
60
61     /**
62      * @var Site
63      */
64     protected $site;
65
66     /**
67      * @var string
68      */
69     protected $twigtemplate;
70
71
72     /**
73      * ModuleCommand constructor.
74      *
75      * @param ModuleGenerator $generator
76      * @param Validator       $validator
77      * @param $appRoot
78      * @param StringConverter $stringConverter
79      * @param DrupalApi       $drupalApi
80      * @param Client          $httpClient
81      * @param Site            $site
82      * @param $twigtemplate
83      */
84     public function __construct(
85         ModuleGenerator $generator,
86         Validator $validator,
87         $appRoot,
88         StringConverter $stringConverter,
89         DrupalApi $drupalApi,
90         Client $httpClient,
91         Site $site,
92         $twigtemplate = null
93     ) {
94         $this->generator = $generator;
95         $this->validator = $validator;
96         $this->appRoot = $appRoot;
97         $this->stringConverter = $stringConverter;
98         $this->drupalApi = $drupalApi;
99         $this->httpClient = $httpClient;
100         $this->site = $site;
101         $this->twigtemplate = $twigtemplate;
102         parent::__construct();
103     }
104
105     /**
106      * {@inheritdoc}
107      */
108     protected function configure()
109     {
110         $this
111             ->setName('generate:module')
112             ->setDescription($this->trans('commands.generate.module.description'))
113             ->setHelp($this->trans('commands.generate.module.help'))
114             ->addOption(
115                 'module',
116                 '',
117                 InputOption::VALUE_REQUIRED,
118                 $this->trans('commands.generate.module.options.module')
119             )
120             ->addOption(
121                 'machine-name',
122                 '',
123                 InputOption::VALUE_REQUIRED,
124                 $this->trans('commands.generate.module.options.machine-name')
125             )
126             ->addOption(
127                 'module-path',
128                 '',
129                 InputOption::VALUE_REQUIRED,
130                 $this->trans('commands.generate.module.options.module-path')
131             )
132             ->addOption(
133                 'description',
134                 '',
135                 InputOption::VALUE_OPTIONAL,
136                 $this->trans('commands.generate.module.options.description')
137             )
138             ->addOption(
139                 'core',
140                 '',
141                 InputOption::VALUE_OPTIONAL,
142                 $this->trans('commands.generate.module.options.core')
143             )
144             ->addOption(
145                 'package',
146                 '',
147                 InputOption::VALUE_OPTIONAL,
148                 $this->trans('commands.generate.module.options.package')
149             )
150             ->addOption(
151                 'module-file',
152                 '',
153                 InputOption::VALUE_NONE,
154                 $this->trans('commands.generate.module.options.module-file')
155             )
156             ->addOption(
157                 'features-bundle',
158                 '',
159                 InputOption::VALUE_REQUIRED,
160                 $this->trans('commands.generate.module.options.features-bundle')
161             )
162             ->addOption(
163                 'composer',
164                 '',
165                 InputOption::VALUE_NONE,
166                 $this->trans('commands.generate.module.options.composer')
167             )
168             ->addOption(
169                 'dependencies',
170                 '',
171                 InputOption::VALUE_OPTIONAL,
172                 $this->trans('commands.generate.module.options.dependencies')
173             )
174             ->addOption(
175                 'test',
176                 '',
177                 InputOption::VALUE_OPTIONAL,
178                 $this->trans('commands.generate.module.options.test')
179             )
180             ->addOption(
181                 'twigtemplate',
182                 '',
183                 InputOption::VALUE_OPTIONAL,
184                 $this->trans('commands.generate.module.options.twigtemplate')
185             );
186     }
187
188     /**
189      * {@inheritdoc}
190      */
191     protected function execute(InputInterface $input, OutputInterface $output)
192     {
193         $io = new DrupalStyle($input, $output);
194         $yes = $input->hasOption('yes')?$input->getOption('yes'):false;
195
196         // @see use Drupal\Console\Command\Shared\ConfirmationTrait::confirmGeneration
197         if (!$this->confirmGeneration($io, $yes)) {
198             return;
199         }
200
201         $module = $this->validator->validateModuleName($input->getOption('module'));
202
203         $modulePath = $this->appRoot . $input->getOption('module-path');
204         $modulePath = $this->validator->validateModulePath($modulePath, true);
205
206         $machineName = $this->validator->validateMachineName($input->getOption('machine-name'));
207         $description = $input->getOption('description');
208         $core = $input->getOption('core');
209         $package = $input->getOption('package');
210         $moduleFile = $input->getOption('module-file');
211         $featuresBundle = $input->getOption('features-bundle');
212         $composer = $input->getOption('composer');
213         $test = $input->getOption('test');
214         $twigtemplate = $input->getOption('twigtemplate');
215
216          // Modules Dependencies, re-factor and share with other commands
217         $dependencies = $this->validator->validateModuleDependencies($input->getOption('dependencies'));
218         // Check if all module dependencies are available
219         if ($dependencies) {
220             $checked_dependencies = $this->checkDependencies($dependencies['success'], $io);
221             if (!empty($checked_dependencies['no_modules'])) {
222                 $io->warning(
223                     sprintf(
224                         $this->trans('commands.generate.module.warnings.module-unavailable'),
225                         implode(', ', $checked_dependencies['no_modules'])
226                     )
227                 );
228             }
229             $dependencies = $dependencies['success'];
230         }
231
232         $this->generator->generate(
233             $module,
234             $machineName,
235             $modulePath,
236             $description,
237             $core,
238             $package,
239             $moduleFile,
240             $featuresBundle,
241             $composer,
242             $dependencies,
243             $test,
244             $twigtemplate
245         );
246     }
247
248     /**
249      * @param  array $dependencies
250      * @return array
251      */
252     private function checkDependencies(array $dependencies, DrupalStyle $io)
253     {
254         $this->site->loadLegacyFile('/core/modules/system/system.module');
255         $localModules = [];
256
257         $modules = system_rebuild_module_data();
258         foreach ($modules as $module_id => $module) {
259             array_push($localModules, basename($module->subpath));
260         }
261
262         $checkDependencies = [
263           'local_modules' => [],
264           'drupal_modules' => [],
265           'no_modules' => [],
266         ];
267
268         foreach ($dependencies as $module) {
269             if (in_array($module, $localModules)) {
270                 $checkDependencies['local_modules'][] = $module;
271             } else {
272                 try {
273                     $response = $this->httpClient->head('https://www.drupal.org/project/' . $module);
274                     $header_link = explode(';', $response->getHeader('link'));
275                     if (empty($header_link[0])) {
276                         $checkDependencies['no_modules'][] = $module;
277                     } else {
278                         $checkDependencies['drupal_modules'][] = $module;
279                     }
280                 } catch (ClientException $e) {
281                     $checkDependencies['no_modules'][] = $module;
282                 }
283             }
284         }
285
286         return $checkDependencies;
287     }
288
289     /**
290      * {@inheritdoc}
291      */
292     protected function interact(InputInterface $input, OutputInterface $output)
293     {
294         $io = new DrupalStyle($input, $output);
295
296         $validator = $this->validator;
297
298         try {
299             $module = $input->getOption('module') ?
300               $this->validator->validateModuleName(
301                   $input->getOption('module')
302               ) : null;
303         } catch (\Exception $error) {
304             $io->error($error->getMessage());
305
306             return;
307         }
308
309         if (!$module) {
310             $module = $io->ask(
311                 $this->trans('commands.generate.module.questions.module'),
312                 null,
313                 function ($module) use ($validator) {
314                     return $validator->validateModuleName($module);
315                 }
316             );
317             $input->setOption('module', $module);
318         }
319
320         try {
321             $machineName = $input->getOption('machine-name') ?
322               $this->validator->validateModuleName(
323                   $input->getOption('machine-name')
324               ) : null;
325         } catch (\Exception $error) {
326             $io->error($error->getMessage());
327         }
328
329         if (!$machineName) {
330             $machineName = $io->ask(
331                 $this->trans('commands.generate.module.questions.machine-name'),
332                 $this->stringConverter->createMachineName($module),
333                 function ($machine_name) use ($validator) {
334                     return $validator->validateMachineName($machine_name);
335                 }
336             );
337             $input->setOption('machine-name', $machineName);
338         }
339
340         $modulePath = $input->getOption('module-path');
341         if (!$modulePath) {
342             $drupalRoot = $this->appRoot;
343             $modulePath = $io->ask(
344                 $this->trans('commands.generate.module.questions.module-path'),
345                 '/modules/custom',
346                 function ($modulePath) use ($drupalRoot, $machineName) {
347                     $modulePath = ($modulePath[0] != '/' ? '/' : '').$modulePath;
348                     $fullPath = $drupalRoot.$modulePath.'/'.$machineName;
349                     if (file_exists($fullPath)) {
350                         throw new \InvalidArgumentException(
351                             sprintf(
352                                 $this->trans('commands.generate.module.errors.directory-exists'),
353                                 $fullPath
354                             )
355                         );
356                     }
357
358                     return $modulePath;
359                 }
360             );
361         }
362         $input->setOption('module-path', $modulePath);
363
364         $description = $input->getOption('description');
365         if (!$description) {
366             $description = $io->ask(
367                 $this->trans('commands.generate.module.questions.description'),
368                 'My Awesome Module'
369             );
370         }
371         $input->setOption('description', $description);
372
373         $package = $input->getOption('package');
374         if (!$package) {
375             $package = $io->ask(
376                 $this->trans('commands.generate.module.questions.package'),
377                 'Custom'
378             );
379         }
380         $input->setOption('package', $package);
381
382         $core = $input->getOption('core');
383         if (!$core) {
384             $core = $io->ask(
385                 $this->trans('commands.generate.module.questions.core'), '8.x',
386                 function ($core) {
387                     // Only allow 8.x and higher as core version.
388                     if (!preg_match('/^([0-9]+)\.x$/', $core, $matches) || ($matches[1] < 8)) {
389                         throw new \InvalidArgumentException(
390                             sprintf(
391                                 $this->trans('commands.generate.module.errors.invalid-core'),
392                                 $core
393                             )
394                         );
395                     }
396
397                     return $core;
398                 }
399             );
400             $input->setOption('core', $core);
401         }
402
403         $moduleFile = $input->getOption('module-file');
404         if (!$moduleFile) {
405             $moduleFile = $io->confirm(
406                 $this->trans('commands.generate.module.questions.module-file'),
407                 true
408             );
409             $input->setOption('module-file', $moduleFile);
410         }
411
412         $featuresBundle = $input->getOption('features-bundle');
413         if (!$featuresBundle) {
414             $featuresSupport = $io->confirm(
415                 $this->trans('commands.generate.module.questions.features-support'),
416                 false
417             );
418             if ($featuresSupport) {
419                 $featuresBundle = $io->ask(
420                     $this->trans('commands.generate.module.questions.features-bundle'),
421                     'default'
422                 );
423             }
424             $input->setOption('features-bundle', $featuresBundle);
425         }
426
427         $composer = $input->getOption('composer');
428         if (!$composer) {
429             $composer = $io->confirm(
430                 $this->trans('commands.generate.module.questions.composer'),
431                 true
432             );
433             $input->setOption('composer', $composer);
434         }
435
436         $dependencies = $input->getOption('dependencies');
437         if (!$dependencies) {
438             $addDependencies = $io->confirm(
439                 $this->trans('commands.generate.module.questions.dependencies'),
440                 false
441             );
442             if ($addDependencies) {
443                 $dependencies = $io->ask(
444                     $this->trans('commands.generate.module.options.dependencies')
445                 );
446             }
447             $input->setOption('dependencies', $dependencies);
448         }
449
450         $test = $input->getOption('test');
451         if (!$test) {
452             $test = $io->confirm(
453                 $this->trans('commands.generate.module.questions.test'),
454                 true
455             );
456             $input->setOption('test', $test);
457         }
458
459         $twigtemplate = $input->getOption('twigtemplate');
460         if (!$twigtemplate) {
461             $twigtemplate = $io->confirm(
462                 $this->trans('commands.generate.module.questions.twigtemplate'),
463                 true
464             );
465             $input->setOption('twigtemplate', $twigtemplate);
466         }
467     }
468
469     /**
470      * @return ModuleGenerator
471      */
472     protected function createGenerator()
473     {
474         return new ModuleGenerator();
475     }
476 }