|
|
|
@@ -0,0 +1,353 @@
|
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace Drupal\config_devel\Commands;
|
|
|
|
|
|
|
|
|
|
use Drupal\config_devel\EventSubscriber\ConfigDevelAutoExportSubscriber;
|
|
|
|
|
use Drupal\config_devel\EventSubscriber\ConfigDevelAutoImportSubscriber;
|
|
|
|
|
use Drupal\Core\Config\ConfigFactoryInterface;
|
|
|
|
|
use Drupal\Core\Config\InstallStorage;
|
|
|
|
|
use Drupal\Core\Extension\InfoParserInterface;
|
|
|
|
|
use Drupal\Core\Extension\ModuleHandlerInterface;
|
|
|
|
|
use Drupal\Core\Extension\ThemeHandlerInterface;
|
|
|
|
|
use Drupal\Core\File\FileSystemInterface;
|
|
|
|
|
use Drush\Commands\DrushCommands;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Drush integration for the Configuration Development module.
|
|
|
|
|
*/
|
|
|
|
|
class ConfigDevelCommands extends DrushCommands {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The module handler.
|
|
|
|
|
*
|
|
|
|
|
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
|
|
|
|
*/
|
|
|
|
|
protected $moduleHandler;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The theme handler.
|
|
|
|
|
*
|
|
|
|
|
* @var \Drupal\Core\Extension\ThemeHandlerInterface
|
|
|
|
|
*/
|
|
|
|
|
protected $themeHandler;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The parser for info.yml files.
|
|
|
|
|
*
|
|
|
|
|
* @var \Drupal\Core\Extension\InfoParserInterface
|
|
|
|
|
*/
|
|
|
|
|
protected $infoParser;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The configuration object factory.
|
|
|
|
|
*
|
|
|
|
|
* @var \Drupal\Core\Config\ConfigFactoryInterface
|
|
|
|
|
*/
|
|
|
|
|
protected $configFactory;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The event subscriber that listens to config change events.
|
|
|
|
|
*
|
|
|
|
|
* @var \Drupal\config_devel\EventSubscriber\ConfigDevelAutoExportSubscriber
|
|
|
|
|
*/
|
|
|
|
|
protected $autoExportSubscriber;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The event subscriber that listens to config change events.
|
|
|
|
|
*
|
|
|
|
|
* @var \Drupal\config_devel\EventSubscriber\ConfigDevelAutoImportSubscriber
|
|
|
|
|
*/
|
|
|
|
|
protected $autoImportSubscriber;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The file system service.
|
|
|
|
|
*
|
|
|
|
|
* @var \Drupal\Core\File\FileSystemInterface
|
|
|
|
|
*/
|
|
|
|
|
protected $fileSystem;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Constructs a new ConfigDevelCommands object.
|
|
|
|
|
*
|
|
|
|
|
* @param \Drupal\Core\Extension\ModuleHandlerInterface $moduleHandler
|
|
|
|
|
* The module handler.
|
|
|
|
|
* @param \Drupal\Core\Extension\ThemeHandlerInterface $themeHandler
|
|
|
|
|
* The theme handler.
|
|
|
|
|
* @param \Drupal\Core\Extension\InfoParserInterface $infoParser
|
|
|
|
|
* The parser for info.yml files.
|
|
|
|
|
* @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
|
|
|
|
|
* The configuration object factory.
|
|
|
|
|
* @param \Drupal\config_devel\EventSubscriber\ConfigDevelAutoExportSubscriber $autoExportSubscriber
|
|
|
|
|
* The event subscriber that listens to config change events, and happens to
|
|
|
|
|
* contain some code that we depend on which should be factored out into a
|
|
|
|
|
* separate service.
|
|
|
|
|
* @param \Drupal\config_devel\EventSubscriber\ConfigDevelAutoImportSubscriber $autoImportSubscriber
|
|
|
|
|
* The event subscriber that listens to config change events, and happens to
|
|
|
|
|
* contain some code that we depend on which should be factored out into a
|
|
|
|
|
* separate service.
|
|
|
|
|
* @param \Drupal\Core\File\FileSystemInterface $fileSystem
|
|
|
|
|
* The file system service.
|
|
|
|
|
*/
|
|
|
|
|
public function __construct(ModuleHandlerInterface $moduleHandler, ThemeHandlerInterface $themeHandler, InfoParserInterface $infoParser, ConfigFactoryInterface $configFactory, ConfigDevelAutoExportSubscriber $autoExportSubscriber, ConfigDevelAutoImportSubscriber $autoImportSubscriber, FileSystemInterface $fileSystem) {
|
|
|
|
|
parent::__construct();
|
|
|
|
|
|
|
|
|
|
$this->moduleHandler = $moduleHandler;
|
|
|
|
|
$this->themeHandler = $themeHandler;
|
|
|
|
|
$this->infoParser = $infoParser;
|
|
|
|
|
$this->configFactory = $configFactory;
|
|
|
|
|
// @todo We should not depend on event subscribers directly.
|
|
|
|
|
// @see https://www.drupal.org/node/2388253
|
|
|
|
|
$this->autoExportSubscriber = $autoExportSubscriber;
|
|
|
|
|
$this->autoImportSubscriber = $autoImportSubscriber;
|
|
|
|
|
$this->fileSystem = $fileSystem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Write back configuration to module's config directory.
|
|
|
|
|
*
|
|
|
|
|
* List which configuration settings you want to export in the module's info
|
|
|
|
|
* file by listing them under 'config_devel', as shown below:
|
|
|
|
|
*
|
|
|
|
|
* config_devel:
|
|
|
|
|
* install:
|
|
|
|
|
* - entity.view_display.node.article.default
|
|
|
|
|
* - entity.view_display.node.article.teaser
|
|
|
|
|
* - field.instance.node.article.body
|
|
|
|
|
* optional:
|
|
|
|
|
* - field.instance.node.article.tags
|
|
|
|
|
*
|
|
|
|
|
* @command config-devel-export
|
|
|
|
|
* @param string $extension Machine name of the module, profile or theme to export.
|
|
|
|
|
* @usage drush config-devel-export MODULE_NAME
|
|
|
|
|
* Write back configuration to the specified module, based on .info file.
|
|
|
|
|
* @aliases cde,cd-em
|
|
|
|
|
*
|
|
|
|
|
* @throws \Exception
|
|
|
|
|
* Thrown when the passed in extension
|
|
|
|
|
*/
|
|
|
|
|
public function export($extension) {
|
|
|
|
|
// Determine the type of extension we're dealing with.
|
|
|
|
|
$type = $this->getExtensionType($extension);
|
|
|
|
|
|
|
|
|
|
if (!$type) {
|
|
|
|
|
throw new \Exception("Couldn't export configuration. The '$extension' extension is not enabled.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get the config.
|
|
|
|
|
$config = $this->getExtensionConfig($type, $extension);
|
|
|
|
|
|
|
|
|
|
// Export the required config.
|
|
|
|
|
if (isset($config['install'])) {
|
|
|
|
|
$this->exportConfig($config['install'], $type, $extension, InstallStorage::CONFIG_INSTALL_DIRECTORY);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we have any optional configuration, export that as well.
|
|
|
|
|
if (isset($config['optional'])) {
|
|
|
|
|
$this->exportConfig($config['optional'], $type, $extension, InstallStorage::CONFIG_OPTIONAL_DIRECTORY);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Import configuration from module's config directory to active storage.
|
|
|
|
|
*
|
|
|
|
|
* List which configuration settings you want to export in the module's info
|
|
|
|
|
* file by listing them under 'config_devel', as shown below:
|
|
|
|
|
*
|
|
|
|
|
* config_devel:
|
|
|
|
|
* install:
|
|
|
|
|
* - entity.view_display.node.article.default
|
|
|
|
|
* - entity.view_display.node.article.teaser
|
|
|
|
|
* - field.instance.node.article.body
|
|
|
|
|
* optional:
|
|
|
|
|
* - field.instance.node.article.tags
|
|
|
|
|
*
|
|
|
|
|
* @command config-devel-import
|
|
|
|
|
* @param string $extension Machine name of the module, profile or theme.
|
|
|
|
|
* @usage drush config-devel-import MODULE_NAME
|
|
|
|
|
* Import configuration from the specified module, profile or theme into the active storage, based on .info file.
|
|
|
|
|
* @aliases cdi,cd-im
|
|
|
|
|
*
|
|
|
|
|
* @throws \Exception
|
|
|
|
|
* Thrown when the passed in extension is not enabled.
|
|
|
|
|
*/
|
|
|
|
|
public function import($extension) {
|
|
|
|
|
// Determine the type of extension we're dealing with.
|
|
|
|
|
$type = $this->getExtensionType($extension);
|
|
|
|
|
|
|
|
|
|
if (!$type) {
|
|
|
|
|
throw new \Exception("Couldn't import configuration. The '$extension' extension is not enabled.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get the config
|
|
|
|
|
$config = $this->getExtensionConfig($type, $extension);
|
|
|
|
|
|
|
|
|
|
// Import config
|
|
|
|
|
if (isset($config['install'])) {
|
|
|
|
|
$this->importConfig($config['install'], $type, $extension, InstallStorage::CONFIG_INSTALL_DIRECTORY);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Import optional config
|
|
|
|
|
if (isset($config['optional'])) {
|
|
|
|
|
$this->importConfig($config['optional'], $type, $extension, InstallStorage::CONFIG_OPTIONAL_DIRECTORY);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Import a single config item into active storage.
|
|
|
|
|
*
|
|
|
|
|
* List which configuration settings you want to export in the module's info
|
|
|
|
|
* file by listing them under 'config_devel', as shown below:
|
|
|
|
|
*
|
|
|
|
|
* config_devel:
|
|
|
|
|
* install:
|
|
|
|
|
* - entity.view_display.node.article.default
|
|
|
|
|
* - entity.view_display.node.article.teaser
|
|
|
|
|
* - field.instance.node.article.body
|
|
|
|
|
* optional:
|
|
|
|
|
* - field.instance.node.article.tags
|
|
|
|
|
*
|
|
|
|
|
* @command config-devel-import-one
|
|
|
|
|
* @param string $path Config file name.
|
|
|
|
|
* @usage drush config-devel-import-one system.site.yml
|
|
|
|
|
* Import the contents of system.site.yml into the config object system.site.
|
|
|
|
|
* @usage drush config-devel-import-one system.site
|
|
|
|
|
* Import the standard input into the config object system.site. Helpful for scripting copying to remote.
|
|
|
|
|
* @aliases cdi1,cd-i1
|
|
|
|
|
*
|
|
|
|
|
* @throws \Exception
|
|
|
|
|
* Thrown when the given file was not found.
|
|
|
|
|
*/
|
|
|
|
|
public function importSingle($path) {
|
|
|
|
|
$contents = '';
|
|
|
|
|
if (!file_exists($path)) {
|
|
|
|
|
if (substr($path, -4) != '.yml') {
|
|
|
|
|
$contents = file_get_contents('php://stdin');
|
|
|
|
|
}
|
|
|
|
|
elseif (!empty($_SERVER['PWD'])) {
|
|
|
|
|
$path = $_SERVER['PWD'] . '/' . trim($path, '/');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ($contents || file_exists($path)) {
|
|
|
|
|
$this->autoImportSubscriber->importOne($path, '', $contents);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
throw new \Exception("File '$path' not found.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the type for the given extension.
|
|
|
|
|
*
|
|
|
|
|
* @param string $extension
|
|
|
|
|
* The extension name.
|
|
|
|
|
*
|
|
|
|
|
* @return string
|
|
|
|
|
* Either 'module', 'theme', 'profile', or NULL if no valid extension was
|
|
|
|
|
* provided.
|
|
|
|
|
*/
|
|
|
|
|
protected function getExtensionType($extension) {
|
|
|
|
|
$type = NULL;
|
|
|
|
|
|
|
|
|
|
if ($this->moduleHandler->moduleExists($extension)) {
|
|
|
|
|
$type = 'module';
|
|
|
|
|
}
|
|
|
|
|
elseif ($this->themeHandler->themeExists($extension)) {
|
|
|
|
|
$type = 'theme';
|
|
|
|
|
}
|
|
|
|
|
elseif (\Drupal::installProfile() === $extension) {
|
|
|
|
|
$type = 'profile';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the config for the given extension.
|
|
|
|
|
*
|
|
|
|
|
* @param string $type
|
|
|
|
|
* Either 'module', 'theme' or 'profile'.
|
|
|
|
|
* @param string $extension
|
|
|
|
|
* The name of the extension for which to return the config.
|
|
|
|
|
*
|
|
|
|
|
* @return array
|
|
|
|
|
* An array containing install and optional config.
|
|
|
|
|
*/
|
|
|
|
|
protected function getExtensionConfig($type, $extension) {
|
|
|
|
|
$filename = drupal_get_path($type, $extension) . '/' . $extension .'.info.yml';
|
|
|
|
|
$info = $this->infoParser->parse($filename);
|
|
|
|
|
|
|
|
|
|
$config = [];
|
|
|
|
|
if (isset($info['config_devel'])) {
|
|
|
|
|
// Keep backwards compatibility for the old format. This has config names
|
|
|
|
|
// listed directly beneath 'config_devel', rather than an intermediate
|
|
|
|
|
// level for 'install' and 'optional'.
|
|
|
|
|
// Detect the old format based on whether there's neither of these two
|
|
|
|
|
// keys.
|
|
|
|
|
if (!isset($info['config_devel']['install']) && !isset($info['config_devel']['optional'])) {
|
|
|
|
|
$info['config_devel']['install'] = $info['config_devel'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$config['install'] = $info['config_devel']['install'];
|
|
|
|
|
|
|
|
|
|
// If we have any optional configuration, fetch that as well.
|
|
|
|
|
if (isset($info['config_devel']['optional'])) {
|
|
|
|
|
$config['optional'] = $info['config_devel']['optional'];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $config;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Exports a list of configuration entities.
|
|
|
|
|
*
|
|
|
|
|
* @param array $config_list
|
|
|
|
|
* An array of configuration entities.
|
|
|
|
|
* @param string $type
|
|
|
|
|
* The type of extension we're exporting, one of 'module', 'profile' or
|
|
|
|
|
* 'theme'.
|
|
|
|
|
* @param string $extension
|
|
|
|
|
* The name of the extension we're exporting.
|
|
|
|
|
* @param string $directory
|
|
|
|
|
* The directory we're exporting to.
|
|
|
|
|
*
|
|
|
|
|
* @throws \Exception
|
|
|
|
|
* Thrown when the directory to export to is missing and could not be
|
|
|
|
|
* created.
|
|
|
|
|
*/
|
|
|
|
|
protected function exportConfig($config_list, $type, $extension, $directory) {
|
|
|
|
|
$config_path = drupal_get_path($type, $extension) . "/$directory";
|
|
|
|
|
// Ensure the directory always exists.
|
|
|
|
|
if (!file_exists($config_path) && !$this->fileSystem->mkdir($config_path, NULL, TRUE)) {
|
|
|
|
|
throw new \Exception(sprintf('The %s directory could not be created', $config_path));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach ($config_list as $name) {
|
|
|
|
|
$config = $this->configFactory->get($name);
|
|
|
|
|
$file_names = [$config_path . '/' . $name . '.yml'];
|
|
|
|
|
$this->autoExportSubscriber->writeBackConfig($config, $file_names);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Imports a list of configuration entities.
|
|
|
|
|
*
|
|
|
|
|
* @param array $config_list
|
|
|
|
|
* An array of configuration entities.
|
|
|
|
|
* @param string $type
|
|
|
|
|
* The type of extension we're importing, one of 'module'. 'profile' or
|
|
|
|
|
* 'theme'.
|
|
|
|
|
* @param string $extension
|
|
|
|
|
* The module, theme or install profile we're importing.
|
|
|
|
|
* @param string $directory
|
|
|
|
|
* The directory we're importing.
|
|
|
|
|
*/
|
|
|
|
|
protected function importConfig($config_list, $type, $extension, $directory) {
|
|
|
|
|
$config_path = drupal_get_path($type, $extension) . "/$directory";
|
|
|
|
|
foreach ($config_list as $name) {
|
|
|
|
|
$file_name = $config_path . '/' . $name . '.yml';
|
|
|
|
|
$this->importSingle($file_name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|