Security update for Core, with self-updated composer
[yaffs-website] / vendor / drupal / console / src / Command / Module / UninstallCommand.php
1 <?php
2
3 /**
4  * @file
5  * Contains \Drupal\Console\Command\Module\UninstallCommand.
6  */
7
8 namespace Drupal\Console\Command\Module;
9
10 use Drupal\Console\Extension\Manager;
11 use Symfony\Component\Console\Input\InputArgument;
12 use Symfony\Component\Console\Input\InputInterface;
13 use Symfony\Component\Console\Input\InputOption;
14 use Symfony\Component\Console\Output\OutputInterface;
15 use Drupal\Console\Core\Command\Command;
16 use Drupal\Console\Command\Shared\ProjectDownloadTrait;
17 use Drupal\Console\Utils\Site;
18 use Drupal\Core\Extension\ModuleInstallerInterface;
19 use Drupal\Console\Core\Utils\ChainQueue;
20 use Drupal\Core\Config\ConfigFactoryInterface;
21
22 class UninstallCommand extends Command
23 {
24     use ProjectDownloadTrait;
25
26     /**
27      * @var Site
28      */
29     protected $site;
30
31     /**
32      * @var ModuleInstaller
33      */
34     protected $moduleInstaller;
35
36     /**
37      * @var ChainQueue
38      */
39     protected $chainQueue;
40
41     /**
42      * @var ConfigFactory
43      */
44     protected $configFactory;
45
46     /**
47      * @var Manager
48      */
49     protected $extensionManager;
50
51     /**
52      * InstallCommand constructor.
53      *
54      * @param Site            $site
55      * @param ModuleInstaller $moduleInstaller
56      * @param ChainQueue      $chainQueue
57      * @param ConfigFactory   $configFactory
58      * @param Manager         $extensionManager
59      */
60     public function __construct(
61         Site $site,
62         ModuleInstallerInterface $moduleInstaller,
63         ChainQueue $chainQueue,
64         ConfigFactoryInterface $configFactory,
65         Manager $extensionManager
66     ) {
67         $this->site = $site;
68         $this->moduleInstaller = $moduleInstaller;
69         $this->chainQueue = $chainQueue;
70         $this->configFactory = $configFactory;
71         $this->extensionManager = $extensionManager;
72         parent::__construct();
73     }
74
75     /**
76      * {@inheritdoc}
77      */
78     protected function configure()
79     {
80         $this
81             ->setName('module:uninstall')
82             ->setDescription($this->trans('commands.module.uninstall.description'))
83             ->addArgument(
84                 'module',
85                 InputArgument::IS_ARRAY,
86                 $this->trans('commands.module.uninstall.questions.module')
87             )
88             ->addOption(
89                 'force',
90                 null,
91                 InputOption::VALUE_NONE,
92                 $this->trans('commands.module.uninstall.options.force')
93             )
94             ->addOption(
95                 'composer',
96                 null,
97                 InputOption::VALUE_NONE,
98                 $this->trans('commands.module.uninstall.options.composer')
99             )
100             ->setAliases(['mou']);
101     }
102     /**
103      * {@inheritdoc}
104      */
105     protected function interact(InputInterface $input, OutputInterface $output)
106     {
107         $module = $input->getArgument('module');
108
109         if (!$module) {
110             $module = $this->modulesUninstallQuestion();
111             $input->setArgument('module', $module);
112         }
113     }
114     /**
115      * {@inheritdoc}
116      */
117     protected function execute(InputInterface $input, OutputInterface $output)
118     {
119         $composer = $input->getOption('composer');
120         $module = $input->getArgument('module');
121
122         $this->site->loadLegacyFile('/core/modules/system/system.module');
123
124         $coreExtension = $this->configFactory->getEditable('core.extension');
125
126         // Get info about modules available
127         $moduleData = system_rebuild_module_data();
128         $moduleList = array_combine($module, $module);
129
130         if ($composer) {
131             //@TODO: check with Composer if the module is previously required in composer.json!
132             foreach ($module as $moduleItem) {
133                 $command = sprintf(
134                     'composer remove drupal/%s ',
135                     $moduleItem
136                 );
137
138                 $shellProcess = $this->get('shell_process');
139                 if ($shellProcess->exec($command)) {
140                     $this->getIo()->success(
141                         sprintf(
142                             $this->trans('commands.module.uninstall.messages.composer-success'),
143                             $moduleItem
144                         )
145                     );
146                 }
147             }
148         }
149
150         if ($missingModules = array_diff_key($moduleList, $moduleData)) {
151             $this->getIo()->error(
152                 sprintf(
153                     $this->trans('commands.module.uninstall.messages.missing'),
154                     implode(', ', $module),
155                     implode(', ', $missingModules)
156                 )
157             );
158
159             return 1;
160         }
161
162         $installedModules = $coreExtension->get('module') ?: [];
163         if (!$moduleList = array_intersect_key($moduleList, $installedModules)) {
164             $this->getIo()->info($this->trans('commands.module.uninstall.messages.nothing'));
165
166             return 0;
167         }
168
169         if (!$force = $input->getOption('force')) {
170
171             // Get a list of installed profiles that will be excluded when calculating
172             // the dependency tree.
173             if (\Drupal::hasService('profile_handler')) {
174                 // #1356276 adds the profile_handler service but it hasn't been committed
175                 // to core yet so we need to check if it exists.
176                 $profiles = \Drupal::service('profile_handler')->getProfileInheritance();
177             } else {
178                 $profiles[drupal_get_profile()] = [];
179             }
180
181             $dependencies = [];
182             while (list($module) = each($moduleList)) {
183                 foreach (array_keys($moduleData[$module]->required_by) as $dependency) {
184                     if (isset($installedModules[$dependency]) && !isset($moduleList[$dependency]) && (!array_key_exists($dependency, $profiles))) {
185                         $dependencies[] = $dependency;
186                     }
187                 }
188             }
189
190             if (!empty($dependencies)) {
191                 $this->getIo()->error(
192                     sprintf(
193                         $this->trans('commands.module.uninstall.messages.dependents'),
194                         implode('", "', $moduleList),
195                         implode(', ', $dependencies)
196                     )
197                 );
198
199                 return 1;
200             }
201         }
202
203         try {
204             $this->moduleInstaller->uninstall($moduleList);
205
206             $this->getIo()->info(
207                 sprintf(
208                     $this->trans('commands.module.uninstall.messages.success'),
209                     implode(', ', $moduleList)
210                 )
211             );
212
213             $this->getIo()->comment(
214                 sprintf(
215                     $this->trans('commands.module.uninstall.messages.composer-success'),
216                     implode(', ', $moduleList),
217                     false
218                 )
219             );
220         } catch (\Exception $e) {
221             $this->getIo()->error($e->getMessage());
222
223             return 1;
224         }
225
226         $this->site->removeCachedServicesFile();
227         $this->chainQueue->addCommand('cache:rebuild', ['cache' => 'all']);
228     }
229 }