diff --git a/composer.json b/composer.json index fa2e460..8302c64 100644 --- a/composer.json +++ b/composer.json @@ -10,5 +10,12 @@ "require-dev": { "drupal/paragraphs": "^1.1.0" }, + "extra": { + "drush": { + "services": { + "drush.services.yml": "^9" + } + } + }, "license": "GPL-2.0+" } diff --git a/drush.services.yml b/drush.services.yml new file mode 100644 index 0000000..d53e5a0 --- /dev/null +++ b/drush.services.yml @@ -0,0 +1,10 @@ +services: + multiversion.commands: + class: \Drupal\multiversion\Commands\MultiversionCommands + arguments: + - '@config.factory' + - '@entity_type.manager' + - '@multiversion.manager' + - '@module_installer' + tags: + - { name: drush.command } diff --git a/src/Commands/MultiversionCommands.php b/src/Commands/MultiversionCommands.php new file mode 100644 index 0000000..61d6360 --- /dev/null +++ b/src/Commands/MultiversionCommands.php @@ -0,0 +1,252 @@ +configFactory = $config_factory; + $this->entityTypeManager = $entity_type_manager; + $this->workspaceManager = $workspace_manager; + $this->moduleInstaller = $module_installer; + } + + /** + * Uninstall Multiversion. + * + * @command multiversion:uninstall + * @aliases mun,multiversion-uninstall + */ + public function uninstall() { + $extension = 'workspace'; + $uninstall = TRUE; + $extension_info = system_rebuild_module_data(); + + $info = $extension_info[$extension]->info; + if ($info['required']) { + $explanation = ''; + if (!empty($info['explanation'])) { + $explanation = ' ' . dt('Reason: !explanation.', [ + '!explanation' => strip_tags($info['explanation']), + ]); + } + $this->logger()->info(dt('!extension is a required extension and can\'t be uninstalled.', [ + '!extension' => $extension, + ]) . $explanation); + $uninstall = FALSE; + } + elseif (!$extension_info[$extension]->status) { + $this->logger()->info(dt('!extension is already uninstalled.', [ + '!extension' => $extension, + ])); + $uninstall = FALSE; + } + elseif ($extension_info[$extension]->getType() == 'module') { + $dependents = []; + foreach (array_keys($extension_info[$extension]->required_by) as $dependent) { + $dependent_info = $extension_info[$dependent]; + if (!$dependent_info->required && $dependent_info->status) { + $dependents[] = $dependent; + } + } + if (count($dependents)) { + $this->logger()->error(dt('To uninstall !extension, the following extensions must be uninstalled first: !required', [ + '!extension' => $extension, + '!required' => implode(', ', $dependents), + ])); + $uninstall = FALSE; + } + } + + if ($uninstall) { + $this->output()->writeln(dt('Multiversion will be uninstalled.')); + if (!$this->io()->confirm(dt('Do you really want to continue?'))) { + throw new UserAbortException(); + } + $this->logger()->warning('*** ' . dt('The uninstall process can take a few minutes, it depends by the number of entities on the site. Please be patient.')); + + try { + $this->workspaceManager->disableEntityTypes(); + // Delete workspace entities before uninstall. + $storage = $this->entityTypeManager->getStorage('workspace'); + $entities = $storage->loadMultiple(); + $storage->delete($entities); + $this->moduleInstaller->uninstall([$extension]); + } + catch (\Exception $e) { + $this->logger()->error($e->getMessage()); + } + } + } + + /** + * Enable entity types (make them multiversionable). + * + * @param array $entity_types + * The list of entity types, comma or space separated. + * + * @usage drush multiversion-enable-entity-types my_et + * Makes my_et entity type multiversionable. + * @usage drush multiversion-enable-entity-types my_et my_et2 + * Makes my_et and my_et2 entity types multiversionable. + * @usage drush met my_et + * Makes my_et entity type multiversionable. + * @usage drush met my_et my_et2 + * Makes my_et and my_et2 entity types multiversionable. + * + * @command multiversion:enable-entity-types + * @aliases met,multiversion-enable-entity-types + */ + public function enableEntityTypes(array $entity_types) { + $list = StringUtils::csvToArray($entity_types); + if (!count($list)) { + $this->logger()->error(dt('Entity types list argument is missing.')); + } + elseif ($types = $this->getEntityTypes($list)) { + if (!$this->io()->confirm(dt('Do you really want to continue?'))) { + throw new UserAbortException(); + } + try { + $multiversion_settings = $this->configFactory + ->getEditable('multiversion.settings'); + $supported_entity_types = $multiversion_settings->get('supported_entity_types') ?: []; + foreach (array_keys($types) as $id) { + if (!in_array($id, $supported_entity_types)) { + $supported_entity_types[] = $id; + } + } + // Add new entity types to the supported entity types list. + $multiversion_settings + ->set('supported_entity_types', $supported_entity_types) + ->save(); + $this->workspaceManager->enableEntityTypes($types); + } + catch (\Exception $e) { + $this->logger()->error($e->getMessage()); + } + } + } + + /** + * Disable entity types (make them non-multiversionable). + * + * @param array $entity_types + * The list of entity types, comma or space separated. + * + * @usage drush multiversion-disable-entity-types my_et + * Makes my_et entity type non-multiversionable. + * @usage drush multiversion-disable-entity-types my_et1 my_et2 + * Makes my_et and my_et2 entity types non-multiversionable. + * @usage drush mdt my_et + * Makes my_et entity type non-multiversionable. + * @usage drush mdt my_et1 my_et2 + * Makes my_et and my_et2 entity types non-multiversionable. + * + * @command multiversion:disable-entity-types + * @aliases mdt,multiversion-disable-entity-types + */ + public function disableEntityTypes(array $entity_types) { + $list = StringUtils::csvToArray($entity_types); + if (!count($list)) { + $this->logger()->error(dt('Entity types list argument is missing.')); + } + elseif ($types = $this->getEntityTypes($list)) { + if (!$this->io()->confirm(dt('Do you really want to continue?'))) { + throw new UserAbortException(); + } + try { + $this->workspaceManager->disableEntityTypes($types); + } + catch (\Exception $e) { + $this->logger()->error($e->getMessage()); + } + } + } + + /** + * Provides entity types for given type IDs. + * + * @param array $entity_type_ids + * An array of type IDs. + * + * @return array + * An array of types indexed by ID. + * + * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException + * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException + */ + protected function getEntityTypes(array $entity_type_ids) { + $entity_types = []; + try { + foreach ($entity_type_ids as $id) { + $entity_type = $this->entityTypeManager + ->getStorage($id) + ->getEntityType(); + + if ($entity_type instanceof ContentEntityTypeInterface) { + $entity_types[$id] = $entity_type; + } + } + } + catch (\Exception $e) { + $this->logger()->error($e->getMessage()); + } + + return $entity_types; + } + +}