Issue #1609760 by chx, sun: Fixed hook_image_style_()*() is not invoked for image styles upon Image module installation.
parent
9df50e2f14
commit
83a9b89aa9
|
@ -1,7 +1,10 @@
|
|||
<?php
|
||||
|
||||
use Drupal\Core\Config\Config;
|
||||
use Drupal\Core\Config\DatabaseStorage;
|
||||
use Drupal\Core\Config\FileStorage;
|
||||
use Drupal\Core\Config\NullStorage;
|
||||
use Drupal\Core\Config\StorageInterface;
|
||||
|
||||
/**
|
||||
* @file
|
||||
|
@ -20,13 +23,21 @@ use Drupal\Core\Config\FileStorage;
|
|||
function config_install_default_config($module) {
|
||||
$module_config_dir = drupal_get_path('module', $module) . '/config';
|
||||
if (is_dir($module_config_dir)) {
|
||||
$database_storage = new DatabaseStorage();
|
||||
$module_file_storage = new FileStorage(array('directory' => $module_config_dir));
|
||||
$source_storage = new FileStorage(array('directory' => $module_config_dir));
|
||||
$target_storage = new DatabaseStorage();
|
||||
$null_storage = new NullStorage();
|
||||
|
||||
foreach ($module_file_storage->listAll() as $config_name) {
|
||||
$data = $module_file_storage->read($config_name);
|
||||
$database_storage->write($config_name, $data);
|
||||
// Upon module installation, only new config objects need to be created.
|
||||
// config_sync_get_changes() would potentially perform a diff of hundreds or
|
||||
// even thousands of config objects that happen to be contained in the
|
||||
// active store. We leverage the NullStorage to avoid that needless
|
||||
// computation of differences.
|
||||
$config_changes = config_sync_get_changes($source_storage, $null_storage);
|
||||
if (empty($config_changes)) {
|
||||
return;
|
||||
}
|
||||
$remaining_changes = config_import_invoke_owner($config_changes, $source_storage, $target_storage);
|
||||
config_sync_changes($remaining_changes, $source_storage, $target_storage);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,3 +68,111 @@ function config($name) {
|
|||
return drupal_container()->get('config.factory')->get($name)->load();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of differences between configuration storages.
|
||||
*
|
||||
* @param Drupal\Core\Config\StorageInterface $source_storage
|
||||
* The storage to synchronize configuration from.
|
||||
* @param Drupal\Core\Config\StorageInterface $target_storage
|
||||
* The storage to synchronize configuration to.
|
||||
*
|
||||
* @return array|bool
|
||||
* An assocative array containing the differences between source and target
|
||||
* storage, or FALSE if there are no differences.
|
||||
*/
|
||||
function config_sync_get_changes(StorageInterface $source_storage, StorageInterface $target_storage) {
|
||||
$source_names = $source_storage->listAll();
|
||||
$target_names = $target_storage->listAll();
|
||||
$config_changes = array(
|
||||
'create' => array_diff($source_names, $target_names),
|
||||
'change' => array(),
|
||||
'delete' => array_diff($target_names, $source_names),
|
||||
);
|
||||
foreach (array_intersect($source_names, $target_names) as $name) {
|
||||
$source_config_data = $source_storage->read($name);
|
||||
$target_config_data = $target_storage->read($name);
|
||||
if ($source_config_data != $target_config_data) {
|
||||
$config_changes['change'][] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
// Do not trigger subsequent synchronization operations if there are no
|
||||
// changes in either category.
|
||||
if (empty($config_changes['create']) && empty($config_changes['change']) && empty($config_changes['delete'])) {
|
||||
return FALSE;
|
||||
}
|
||||
return $config_changes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an array of config file changes from a source storage to a target storage.
|
||||
*
|
||||
* @param array $config_changes
|
||||
* An array of changes to be written.
|
||||
* @param Drupal\Core\Config\StorageInterface $source_storage
|
||||
* The storage to synchronize configuration from.
|
||||
* @param Drupal\Core\Config\StorageInterface $target_storage
|
||||
* The storage to synchronize configuration to.
|
||||
*/
|
||||
function config_sync_changes(array $config_changes, StorageInterface $source_storage, StorageInterface $target_storage) {
|
||||
foreach (array('delete', 'create', 'change') as $op) {
|
||||
foreach ($config_changes[$op] as $name) {
|
||||
if ($op == 'delete') {
|
||||
$target_storage->delete($name);
|
||||
}
|
||||
else {
|
||||
$data = $source_storage->read($name);
|
||||
$target_storage->write($name, $data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes MODULE_config_import() callbacks for configuration changes.
|
||||
*
|
||||
* @param array $config_changes
|
||||
* An array of changes to be loaded.
|
||||
* @param Drupal\Core\Config\StorageInterface $source_storage
|
||||
* The storage to synchronize configuration from.
|
||||
* @param Drupal\Core\Config\StorageInterface $target_storage
|
||||
* The storage to synchronize configuration to.
|
||||
*
|
||||
* @todo Add support for other extension types; e.g., themes etc.
|
||||
*/
|
||||
function config_import_invoke_owner(array $config_changes, StorageInterface $source_storage, StorageInterface $target_storage) {
|
||||
$storage_dispatcher = drupal_container()->get('config.storage.dispatcher');
|
||||
|
||||
// Allow modules to take over configuration change operations for
|
||||
// higher-level configuration data.
|
||||
// First pass deleted, then new, and lastly changed configuration, in order to
|
||||
// handle dependencies correctly.
|
||||
foreach (array('delete', 'create', 'change') as $op) {
|
||||
foreach ($config_changes[$op] as $key => $name) {
|
||||
// Extract owner from configuration object name.
|
||||
$module = strtok($name, '.');
|
||||
// Check whether the module implements hook_config_import() and ask it to
|
||||
// handle the configuration change.
|
||||
$handled_by_module = FALSE;
|
||||
if (module_hook($module, 'config_import_' . $op)) {
|
||||
$old_config = new Config($storage_dispatcher);
|
||||
$old_config
|
||||
->setName($name)
|
||||
->load();
|
||||
|
||||
$data = $source_storage->read($name);
|
||||
$new_config = new Config($storage_dispatcher);
|
||||
$new_config->setName($name);
|
||||
if ($data !== FALSE) {
|
||||
$new_config->setData($data);
|
||||
}
|
||||
|
||||
$handled_by_module = module_invoke($module, 'config_import_' . $op, $name, $new_config, $old_config);
|
||||
}
|
||||
if (!empty($handled_by_module)) {
|
||||
unset($config_changes[$op][$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $config_changes;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Definition of Drupal\Core\Config\NullStorage.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Config;
|
||||
|
||||
/**
|
||||
* Defines a stub storage controller.
|
||||
*
|
||||
* This storage is always empty; the controller reads and writes nothing.
|
||||
*
|
||||
* The stub implementation is needed for synchronizing configuration during
|
||||
* installation of a module, in which case all configuration being shipped with
|
||||
* the module is known to be new. Therefore, the module installation process is
|
||||
* able to short-circuit the full diff against the active store; the diff would
|
||||
* yield all currently available configuration as items to remove, since they do
|
||||
* not exist in the module's default configuration directory.
|
||||
*
|
||||
* This also can be used for testing purposes.
|
||||
*/
|
||||
class NullStorage implements StorageInterface {
|
||||
/**
|
||||
* Implements Drupal\Core\Config\StorageInterface::__construct().
|
||||
*/
|
||||
public function __construct(array $options = array()) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Config\StorageInterface::read().
|
||||
*/
|
||||
public function read($name) {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Config\StorageInterface::write().
|
||||
*/
|
||||
public function write($name, array $data) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Config\StorageInterface::delete().
|
||||
*/
|
||||
public function delete($name) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Config\StorageInterface::encode().
|
||||
*/
|
||||
public static function encode($data) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Config\StorageInterface::decode().
|
||||
*/
|
||||
public static function decode($raw) {
|
||||
return $raw;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Config\StorageInterface::listAll().
|
||||
*/
|
||||
public function listAll($prefix = '') {
|
||||
return array();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Hooks provided by the Configuration module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup config_hooks Configuration system hooks
|
||||
* @{
|
||||
* @todo Overall description of the configuration system.
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create configuration upon synchronizing configuration changes.
|
||||
*
|
||||
* This callback is invoked when configuration is synchronized between storages
|
||||
* and allows a module to take over the synchronization of configuration data.
|
||||
*
|
||||
* Modules should implement this callback if they manage configuration data
|
||||
* (such as image styles, node types, or fields) which needs to be
|
||||
* prepared and passed through module API functions to properly handle a
|
||||
* configuration change.
|
||||
*
|
||||
* @param string $name
|
||||
* The name of the configuration object.
|
||||
* @param Drupal\Core\Config\Config $new_config
|
||||
* A configuration object containing the new configuration data.
|
||||
* @param Drupal\Core\Config\Config $old_config
|
||||
* A configuration object containing the old configuration data.
|
||||
*/
|
||||
function MODULE_config_import_create($name, $new_config, $old_config) {
|
||||
// Only configurable thingies require custom handling. Any other module
|
||||
// settings can be synchronized directly.
|
||||
if (strpos($name, 'config_test.dynamic.') !== 0) {
|
||||
return FALSE;
|
||||
}
|
||||
$config_test = new ConfigTest($new_config);
|
||||
$config_test->save();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update configuration upon synchronizing configuration changes.
|
||||
*
|
||||
* This callback is invoked when configuration is synchronized between storages
|
||||
* and allows a module to take over the synchronization of configuration data.
|
||||
*
|
||||
* Modules should implement this callback if they manage configuration data
|
||||
* (such as image styles, node types, or fields) which needs to be
|
||||
* prepared and passed through module API functions to properly handle a
|
||||
* configuration change.
|
||||
*
|
||||
* @param string $name
|
||||
* The name of the configuration object.
|
||||
* @param Drupal\Core\Config\Config $new_config
|
||||
* A configuration object containing the new configuration data.
|
||||
* @param Drupal\Core\Config\Config $old_config
|
||||
* A configuration object containing the old configuration data.
|
||||
*/
|
||||
function MODULE_config_import_change($name, $new_config, $old_config) {
|
||||
// Only configurable thingies require custom handling. Any other module
|
||||
// settings can be synchronized directly.
|
||||
if (strpos($name, 'config_test.dynamic.') !== 0) {
|
||||
return FALSE;
|
||||
}
|
||||
$config_test = new ConfigTest($new_config);
|
||||
$config_test->setOriginal($old_config);
|
||||
$config_test->save();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete configuration upon synchronizing configuration changes.
|
||||
*
|
||||
* This callback is invoked when configuration is synchronized between storages
|
||||
* and allows a module to take over the synchronization of configuration data.
|
||||
*
|
||||
* Modules should implement this callback if they manage configuration data
|
||||
* (such as image styles, node types, or fields) which needs to be
|
||||
* prepared and passed through module API functions to properly handle a
|
||||
* configuration change.
|
||||
*
|
||||
* @param string $name
|
||||
* The name of the configuration object.
|
||||
* @param Drupal\Core\Config\Config $new_config
|
||||
* A configuration object containing the new configuration data.
|
||||
* @param Drupal\Core\Config\Config $old_config
|
||||
* A configuration object containing the old configuration data.
|
||||
*/
|
||||
function MODULE_config_import_delete($name, $new_config, $old_config) {
|
||||
// Only configurable thingies require custom handling. Any other module
|
||||
// settings can be synchronized directly.
|
||||
if (strpos($name, 'config_test.dynamic.') !== 0) {
|
||||
return FALSE;
|
||||
}
|
||||
// @todo image_style_delete() supports the notion of a "replacement style"
|
||||
// to be used by other modules instead of the deleted style. Essential!
|
||||
// But that is impossible currently, since the config system only knows
|
||||
// about deleted and added changes. Introduce an 'old_ID' key within
|
||||
// config objects as a standard?
|
||||
$config_test = new ConfigTest($old_config);
|
||||
$config_test->delete();
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Definition of Drupal\config\Tests\ConfigInstallTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\config\Tests;
|
||||
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests installation of configuration objects in installation functionality.
|
||||
*/
|
||||
class ConfigInstallTest extends WebTestBase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Installation functionality',
|
||||
'description' => 'Tests installation of configuration objects in installation functionality.',
|
||||
'group' => 'Configuration',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests module installation.
|
||||
*/
|
||||
function testModuleInstallation() {
|
||||
$default_config = 'config_test.system';
|
||||
$default_thingie = 'config_test.dynamic.default';
|
||||
|
||||
// Verify that default module config does not exist before installation yet.
|
||||
$config = config($default_config);
|
||||
$this->assertIdentical($config->isNew(), TRUE);
|
||||
$config = config($default_thingie);
|
||||
$this->assertIdentical($config->isNew(), TRUE);
|
||||
|
||||
// Install the test module.
|
||||
module_enable(array('config_test'));
|
||||
|
||||
// Verify that default module config exists.
|
||||
$config = config($default_config);
|
||||
$this->assertIdentical($config->isNew(), FALSE);
|
||||
$config = config($default_thingie);
|
||||
$this->assertIdentical($config->isNew(), FALSE);
|
||||
|
||||
// Verify that configuration import callback was invoked for the dynamic
|
||||
// thingie.
|
||||
$this->assertTrue($GLOBALS['hook_config_import']);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
id: default
|
||||
label: Default
|
|
@ -0,0 +1 @@
|
|||
foo: bar
|
|
@ -0,0 +1,6 @@
|
|||
name = Configuration test module
|
||||
package = Core
|
||||
version = VERSION
|
||||
core = 8.x
|
||||
dependencies[] = config
|
||||
hidden = TRUE
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Implements MODULE_config_import_create().
|
||||
*/
|
||||
function config_test_config_import_create($name, $new_config, $old_config) {
|
||||
// Only configurable thingies require custom handling. Any other module
|
||||
// settings can be synchronized directly.
|
||||
if (strpos($name, 'config_test.dynamic.') !== 0) {
|
||||
return FALSE;
|
||||
}
|
||||
// Set a global value we can check in test code.
|
||||
$GLOBALS['hook_config_import'] = __FUNCTION__;
|
||||
|
||||
$new_config->save();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements MODULE_config_import_change().
|
||||
*/
|
||||
function config_test_config_import_change($name, $new_config, $old_config) {
|
||||
// Only configurable thingies require custom handling. Any other module
|
||||
// settings can be synchronized directly.
|
||||
if (strpos($name, 'config_test.dynamic.') !== 0) {
|
||||
return FALSE;
|
||||
}
|
||||
// Set a global value we can check in test code.
|
||||
$GLOBALS['hook_config_import'] = __FUNCTION__;
|
||||
|
||||
$new_config->save();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements MODULE_config_import_delete().
|
||||
*/
|
||||
function config_test_config_import_delete($name, $new_config, $old_config) {
|
||||
// Only configurable thingies require custom handling. Any other module
|
||||
// settings can be synchronized directly.
|
||||
if (strpos($name, 'config_test.dynamic.') !== 0) {
|
||||
return FALSE;
|
||||
}
|
||||
// Set a global value we can check in test code.
|
||||
$GLOBALS['hook_config_import'] = __FUNCTION__;
|
||||
|
||||
$old_config->delete();
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -499,6 +499,50 @@ function image_path_flush($path) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements MODULE_config_import_create().
|
||||
*/
|
||||
function image_config_import_create($name, $new_config, $old_config) {
|
||||
// Only image styles require custom handling. Any other module settings can be
|
||||
// synchronized directly.
|
||||
if (strpos($name, 'image.style.') !== 0) {
|
||||
return FALSE;
|
||||
}
|
||||
$style = $new_config->get();
|
||||
return image_style_save($style);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements MODULE_config_import_change().
|
||||
*/
|
||||
function image_config_import_change($name, $new_config, $old_config) {
|
||||
// Only image styles require custom handling. Any other module settings can be
|
||||
// synchronized directly.
|
||||
if (strpos($name, 'image.style.') !== 0) {
|
||||
return FALSE;
|
||||
}
|
||||
$style = $new_config->get();
|
||||
return image_style_save($style);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements MODULE_config_import_delete().
|
||||
*/
|
||||
function image_config_import_delete($name, $new_config, $old_config) {
|
||||
// Only image styles require custom handling. Any other module settings can be
|
||||
// synchronized directly.
|
||||
if (strpos($name, 'image.style.') !== 0) {
|
||||
return FALSE;
|
||||
}
|
||||
// @todo image_style_delete() supports the notion of a "replacement style"
|
||||
// to be used by other modules instead of the deleted style. Essential!
|
||||
// But that is impossible currently, since the config system only knows
|
||||
// about deleted and added changes. Introduce an 'old_ID' key within
|
||||
// config objects as a standard?
|
||||
$style = $old_config->get();
|
||||
return image_style_delete($style);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of all styles and their settings.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue