diff --git a/core/includes/config.inc b/core/includes/config.inc index 0011533..88786ac 100644 --- a/core/includes/config.inc +++ b/core/includes/config.inc @@ -253,12 +253,10 @@ function config_import_invoke_owner(array $config_changes, StorageInterface $sou // 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. + // Call to the configuration entity's storage controller to handle the + // configuration change. $handled_by_module = FALSE; - if (module_exists($module) && module_hook($module, 'config_import_' . $op)) { + if ($entity_type = config_get_config_entity_by_name($name)) { $old_config = new Config($name, $target_storage); $old_config->load(); @@ -268,7 +266,8 @@ function config_import_invoke_owner(array $config_changes, StorageInterface $sou $new_config->setData($data); } - $handled_by_module = module_invoke($module, 'config_import_' . $op, $name, $new_config, $old_config); + $method = 'import' . ucfirst($op); + $handled_by_module = entity_get_controller($entity_type)->$method($name, $new_config, $old_config); } if (!empty($handled_by_module)) { unset($config_changes[$op][$key]); @@ -297,3 +296,19 @@ function config_get_module_config_entities($module) { return ($entity_info['module'] == $module) && is_subclass_of($entity_info['class'], 'Drupal\Core\Config\Entity\ConfigEntityInterface'); }); } + +/** + * Returns the entity type of a configuration object. + * + * @param string $name + * The configuration object name. + * + * @return string|null + * Either the entity type name, or NULL if none match. + */ +function config_get_config_entity_by_name($name) { + $entities = array_filter(entity_get_info(), function($entity_info) use ($name) { + return (isset($entity_info['config_prefix']) && strpos($name, $entity_info['config_prefix']) === 0); + }); + return key($entities); +} diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php b/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php index 7f60f9d..013d1ce 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigStorageController.php @@ -11,6 +11,7 @@ use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityMalformedException; use Drupal\Core\Entity\EntityStorageControllerInterface; +use Drupal\Core\Config\Config; /** * Defines the storage controller class for configuration entities. @@ -425,4 +426,91 @@ protected function invokeHook($hook, EntityInterface $entity) { public function getQueryServicename() { throw new \LogicException('Querying configuration entities is not supported.'); } + + /** + * 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. + */ + public function importCreate($name, Config $new_config, Config $old_config) { + $entity = $this->create($new_config->get()); + $entity->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. + */ + public function importChange($name, Config $new_config, Config $old_config) { + list(, , $id) = explode('.', $name); + $entities = $this->load(array($id)); + $entity = $entities[$id]; + $entity->original = clone $entity; + + foreach ($old_config->get() as $property => $value) { + $entity->original->$property = $value; + } + + foreach ($new_config->get() as $property => $value) { + $entity->$property = $value; + } + + $entity->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. + */ + public function importDelete($name, Config $new_config, Config $old_config) { + list(, , $id) = explode('.', $name); + $entities = $this->load(array($id)); + $entity = $entities[$id]; + $entity->delete(); + return TRUE; + } + } diff --git a/core/modules/config/config.api.php b/core/modules/config/config.api.php index d845667..7b06336 100644 --- a/core/modules/config/config.api.php +++ b/core/modules/config/config.api.php @@ -11,116 +11,3 @@ * @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 hook_config_import_create($name, $new_config, $old_config) { - // Only configuration entities require custom handling. Any other module - // settings can be synchronized directly. - if (strpos($name, 'config_test.dynamic.') !== 0) { - return FALSE; - } - $config_test = entity_create('config_test', $new_config->get()); - $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 hook_config_import_change($name, $new_config, $old_config) { - // Only configuration entities require custom handling. Any other module - // settings can be synchronized directly. - if (strpos($name, 'config_test.dynamic.') !== 0) { - return FALSE; - } - - // @todo Make this less ugly. - list($entity_type) = explode('.', $name); - $entity_info = entity_get_info($entity_type); - $id = substr($name, strlen($entity_info['config_prefix']) + 1); - $config_test = entity_load('config_test', $id); - - // Store the original config, and iterate through each property to store it. - $config_test->original = clone $config_test; - foreach ($old_config->get() as $property => $value) { - $config_test->original->$property = $value; - } - - // Iterate through each property of the new config, copying it to the test - // object. - foreach ($new_config->get() as $property => $value) { - $config_test->$property = $value; - } - - $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 hook_config_import_delete($name, $new_config, $old_config) { - // Only configuration entities 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? - list($entity_type) = explode('.', $name); - $entity_info = entity_get_info($entity_type); - $id = substr($name, strlen($entity_info['config_prefix']) + 1); - config_test_delete($id); - return TRUE; -} - diff --git a/core/modules/config/tests/config_test/config_test.module b/core/modules/config/tests/config_test/config_test.module index 96d4aa0..5dbcb92 100644 --- a/core/modules/config/tests/config_test/config_test.module +++ b/core/modules/config/tests/config_test/config_test.module @@ -10,68 +10,6 @@ require_once dirname(__FILE__) . '/config_test.hooks.inc'; /** - * Implements hook_config_import_create(). - */ -function config_test_config_import_create($name, $new_config, $old_config) { - if (strpos($name, 'config_test.dynamic.') !== 0) { - return FALSE; - } - // Set a global value we can check in test code. - $GLOBALS['hook_config_import'] = __FUNCTION__; - - $config_test = entity_create('config_test', $new_config->get()); - $config_test->save(); - return TRUE; -} - -/** - * Implements hook_config_import_change(). - */ -function config_test_config_import_change($name, $new_config, $old_config) { - if (strpos($name, 'config_test.dynamic.') !== 0) { - return FALSE; - } - // Set a global value we can check in test code. - $GLOBALS['hook_config_import'] = __FUNCTION__; - - // @todo Make this less ugly. - list(, , $id) = explode('.', $name); - $config_test = entity_load('config_test', $id); - - // Store the original config, and iterate through each property to store it. - $config_test->original = clone $config_test; - foreach ($old_config->get() as $property => $value) { - $config_test->original->$property = $value; - } - - // Iterate through each property of the new config, copying it to the test - // object. - foreach ($new_config->get() as $property => $value) { - $config_test->$property = $value; - } - - $config_test->save(); - return TRUE; -} - -/** - * Implements hook_config_import_delete(). - */ -function config_test_config_import_delete($name, $new_config, $old_config) { - if (strpos($name, 'config_test.dynamic.') !== 0) { - return FALSE; - } - // Set a global value we can check in test code. - $GLOBALS['hook_config_import'] = __FUNCTION__; - - // @todo Make this less ugly. - list(, , $id) = explode('.', $name); - $config_test = entity_load('config_test', $id); - $config_test->delete(); - return TRUE; -} - -/** * Entity URI callback. * * @param Drupal\config_test\Plugin\Core\Entity\ConfigTest $config_test @@ -197,4 +135,4 @@ function config_test_cache_flush() { $GLOBALS['hook_cache_flush'] = __FUNCTION__; return array(); -} \ No newline at end of file +} diff --git a/core/modules/config/tests/config_test/lib/Drupal/config_test/ConfigTestStorageController.php b/core/modules/config/tests/config_test/lib/Drupal/config_test/ConfigTestStorageController.php new file mode 100644 index 0000000..e1fe4fe --- /dev/null +++ b/core/modules/config/tests/config_test/lib/Drupal/config_test/ConfigTestStorageController.php @@ -0,0 +1,48 @@ +get()); - $category->save(); - return TRUE; -} - -/** - * Implements MODULE_config_import_change(). - */ -function contact_config_import_change($name, $new_config, $old_config) { - if (strpos($name, 'contact.category.') !== 0) { - return FALSE; - } - - list(, , $id) = explode('.', $name); - $category = entity_load('contact_category', $id); - - $category->original = clone $category; - foreach ($old_config->get() as $property => $value) { - $category->original->$property = $value; - } - - foreach ($new_config->get() as $property => $value) { - $category->$property = $value; - } - - $category->save(); - return TRUE; -} - -/** - * Implements MODULE_config_import_delete(). - */ -function contact_config_import_delete($name, $new_config, $old_config) { - if (strpos($name, 'contact.category.') !== 0) { - return FALSE; - } - - list(, , $id) = explode('.', $name); - entity_delete_multiple('contact_category', array($id)); - return TRUE; -} - -/** * Implements hook_entity_info(). */ function contact_entity_info(&$types) { diff --git a/core/modules/image/image.module b/core/modules/image/image.module index 8312420..556467b 100644 --- a/core/modules/image/image.module +++ b/core/modules/image/image.module @@ -503,65 +503,6 @@ function image_path_flush($path) { } /** - * Implements hook_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 = entity_create('image_style', $new_config->get()); - $style->save(); - return TRUE; -} - -/** - * Implements hook_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; - } - - list(, , $id) = explode('.', $name); - $style = entity_load('image_style', $id); - - $style->original = clone $style; - foreach ($old_config->get() as $property => $value) { - $style->original->$property = $value; - } - - foreach ($new_config->get() as $property => $value) { - $style->$property = $value; - } - - $style->save(); - return TRUE; -} - -/** - * 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? - list(, , $id) = explode('.', $name); - $style = entity_load('image_style', $id); - return image_style_delete($style); -} - -/** * Loads an ImageStyle object. * * @param string $name diff --git a/core/modules/image/lib/Drupal/image/ImageStyleStorageController.php b/core/modules/image/lib/Drupal/image/ImageStyleStorageController.php new file mode 100644 index 0000000..5e0472f --- /dev/null +++ b/core/modules/image/lib/Drupal/image/ImageStyleStorageController.php @@ -0,0 +1,34 @@ +load(array($id)); + $entity = $entities[$id]; + + // @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? + return image_style_delete($entity); + } + +} diff --git a/core/modules/image/lib/Drupal/image/Plugin/Core/Entity/ImageStyle.php b/core/modules/image/lib/Drupal/image/Plugin/Core/Entity/ImageStyle.php index 363fbd8..8110b77 100644 --- a/core/modules/image/lib/Drupal/image/Plugin/Core/Entity/ImageStyle.php +++ b/core/modules/image/lib/Drupal/image/Plugin/Core/Entity/ImageStyle.php @@ -18,7 +18,7 @@ * id = "image_style", * label = @Translation("Image style"), * module = "image", - * controller_class = "Drupal\Core\Config\Entity\ConfigStorageController", + * controller_class = "Drupal\image\ImageStyleStorageController", * uri_callback = "image_style_uri", * config_prefix = "image.style", * entity_keys = { diff --git a/core/modules/views/views.module b/core/modules/views/views.module index ac4952b..c3b450a 100644 --- a/core/modules/views/views.module +++ b/core/modules/views/views.module @@ -79,19 +79,6 @@ function views_pre_render_view_element($element) { } /** - * Implements hook_config_import_create(). - */ -function views_config_import_create($name, $new_config, $old_config) { - if (strpos($name, 'views.view.') !== 0) { - return FALSE; - } - - $view = entity_create('view', $new_config->get()); - $view->save(); - return TRUE; -} - -/** * Implement hook_theme(). Register views theming functions. */ function views_theme($existing, $type, $theme, $path) { @@ -2073,22 +2060,6 @@ function views_array_key_plus($array) { } /** - * Implements hook_config_import_delete(). - */ -function views_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, 'views.view.') !== 0) { - return FALSE; - } - - list(, , $id) = explode('.', $name); - $view = entity_load('view', $id); - entity_delete($view); - return TRUE; -} - -/** * Set a cached item in the views cache. * * This is just a convenience wrapper around cache_set().