diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index e26cb36..00b2395 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -2458,9 +2458,13 @@ function drupal_container(Container $reset = NULL) { $container->register('config.storage', 'Drupal\Core\Config\DatabaseStorage') ->addArgument('%config.storage.options%'); + $container->register('config.globaloverridesubscriber', 'Drupal\Core\EventSubscriber\ConfigGlobalOverrideSubscriber'); + $container->register('dispatcher', 'Symfony\Component\EventDispatcher\EventDispatcher') + ->addMethodCall('addSubscriber', array(new Reference('config.globaloverridesubscriber'))); // Register configuration object factory. $container->register('config.factory', 'Drupal\Core\Config\ConfigFactory') - ->addArgument(new Reference('config.storage')); + ->addArgument(new Reference('config.storage')) + ->addArgument(new Reference('dispatcher')); } return $container; } diff --git a/core/includes/config.inc b/core/includes/config.inc index 347bf85..97570df 100644 --- a/core/includes/config.inc +++ b/core/includes/config.inc @@ -65,7 +65,7 @@ function config_get_storage_names_with_prefix($prefix = '') { * A configuration object. */ function config($name) { - return drupal_container()->get('config.factory')->get($name)->load(); + return drupal_container()->get('config.factory')->get($name); } /** @@ -195,7 +195,6 @@ function config_import_invoke_owner(array $config_changes, StorageInterface $sou $handled_by_module = FALSE; if (module_hook($module, 'config_import_' . $op)) { $old_config = new Config($name, $target_storage); - $old_config->load(); $data = $source_storage->read($name); $new_config = new Config($name, $target_storage); diff --git a/core/lib/Drupal/Core/Config/Config.php b/core/lib/Drupal/Core/Config/Config.php index 10bf925..374857e 100644 --- a/core/lib/Drupal/Core/Config/Config.php +++ b/core/lib/Drupal/Core/Config/Config.php @@ -8,6 +8,7 @@ namespace Drupal\Core\Config; use Drupal\Component\Utility\NestedArray; +use Symfony\Component\EventDispatcher\EventDispatcher; /** * Defines the default configuration object. @@ -50,13 +51,20 @@ class Config { protected $overriddenData; /** - * The storage used for reading and writing. + * The storage used to load and save this configuration object. * * @var Drupal\Core\Config\StorageInterface */ protected $storage; /** + * The event dispatcher used to notify subscribers. + * + * @var Symfony\Component\EventDispatcher\EventDispatcher + */ + protected $eventDispatcher; + + /** * Constructs a configuration object. * * @param string $name @@ -64,10 +72,13 @@ class Config { * @param Drupal\Core\Config\StorageInterface $storage * A storage controller object to use for reading and writing the * configuration data. + * @param Symfony\Component\EventDispatcher\EventDispatcher $event_dispatcher + * The event dispatcher used to notify subscribers. */ - public function __construct($name, StorageInterface $storage) { + public function __construct($name, StorageInterface $storage, EventDispatcher $event_dispatcher = NULL) { $this->name = $name; $this->storage = $storage; + $this->eventDispatcher = $event_dispatcher ? $event_dispatcher : drupal_container()->get('dispatcher'); } /** @@ -89,6 +100,7 @@ class Config { * Returns whether this configuration object is new. */ public function isNew() { + $this->build(); return $this->isNew; } @@ -120,9 +132,7 @@ class Config { * The data that was requested. */ public function get($key = '') { - if (!isset($this->overriddenData)) { - $this->setOverriddenData(); - } + $this->build(); if (empty($key)) { return $this->overriddenData; } @@ -146,8 +156,7 @@ class Config { */ public function setData(array $data) { $this->data = $data; - $this->resetOverriddenData(); - return $this; + return $this->rebuild(); } /** @@ -160,32 +169,7 @@ class Config { */ public function setOverride(array $data) { $this->overrides = $data; - $this->resetOverriddenData(); - return $this; - } - - /** - * Sets the current data for this configuration object. - * - * Merges overridden configuration data into the original data. - */ - protected function setOverriddenData() { - $this->overriddenData = $this->data; - if (!empty($this->overrides)) { - $this->overriddenData = NestedArray::mergeDeepArray(array($this->overriddenData, $this->overrides)); - } - return $this; - } - - /** - * Resets the current data, so overrides are re-applied. - * - * This method should be called after the original data or the overridden data - * has been changed. - */ - protected function resetOverriddenData() { - unset($this->overriddenData); - return $this; + return $this->rebuild(); } /** @@ -197,6 +181,7 @@ class Config { * @todo */ public function set($key, $value) { + $this->build(); // Type-cast value into a string. $value = $this->castValue($value); @@ -209,8 +194,7 @@ class Config { else { NestedArray::setValue($this->data, $parts, $value); } - $this->resetOverriddenData(); - return $this; + return $this->rebuild(); } /** @@ -259,6 +243,7 @@ class Config { * Name of the key whose value should be unset. */ public function clear($key) { + $this->build(); $parts = explode('.', $key); if (count($parts) == 1) { unset($this->data[$key]); @@ -266,8 +251,7 @@ class Config { else { NestedArray::unsetValue($this->data, $parts); } - $this->resetOverriddenData(); - return $this; + return $this->rebuild(); } /** @@ -283,17 +267,20 @@ class Config { $this->isNew = FALSE; $this->setData($data); } - return $this; + $this->notify('load'); + return $this->rebuild(); } /** * Saves the configuration object. */ public function save() { + $this->build(); $this->sortByKey($this->data); $this->storage->write($this->name, $this->data); $this->isNew = FALSE; - return $this; + $this->notify('save'); + return $this->rebuild(); } /** @@ -323,7 +310,51 @@ class Config { $this->data = array(); $this->storage->delete($this->name); $this->isNew = TRUE; - $this->resetOverriddenData(); + $this->notify('delete'); + return $this->rebuild(); + } + + /** + * Build the data for this configuration object. + * + * Loads the base data if not loaded, and builds the overriddenData runtime + * configuration computing the overridden values. + */ + public function build() { + if (!isset($this->overriddenData)) { + if (!isset($this->data)) { + $this->load(); + } + $this->overriddenData = $this->data; + if (!empty($this->overrides)) { + $this->overriddenData = NestedArray::mergeDeepArray(array($this->overriddenData, $this->overrides)); + } + } return $this; } + + /** + * Resets the current data, so overrides are re-applied. + * + * This method should be called after the original data or the overridden data + * has been changed. + */ + public function rebuild() { + unset($this->overriddenData); + return $this->build(); + } + + /** + * Retrieve the storage used to load and save this configuration object. + */ + public function getStorage() { + return $this->storage; + } + + /** + * Dispatch a config event. + */ + public function notify($config_event_name) { + $this->eventDispatcher->dispatch('config.' . $config_event_name, new ConfigEvent($this)); + } } diff --git a/core/lib/Drupal/Core/Config/ConfigEvent.php b/core/lib/Drupal/Core/Config/ConfigEvent.php new file mode 100644 index 0000000..aabd1d8 --- /dev/null +++ b/core/lib/Drupal/Core/Config/ConfigEvent.php @@ -0,0 +1,29 @@ +config = $config; + } + + /** + * Get configuration object. + */ + public function getConfig() { + return $this->config; + } +} diff --git a/core/lib/Drupal/Core/Config/ConfigFactory.php b/core/lib/Drupal/Core/Config/ConfigFactory.php index 4bf5b62..1d1dec3 100644 --- a/core/lib/Drupal/Core/Config/ConfigFactory.php +++ b/core/lib/Drupal/Core/Config/ConfigFactory.php @@ -7,6 +7,8 @@ namespace Drupal\Core\Config; +use Symfony\Component\EventDispatcher\EventDispatcher; + /** * Defines the configuration object factory. * @@ -30,14 +32,24 @@ class ConfigFactory { protected $storage; /** + * An event dispatcher instance to use for configuration events. + * + * @var Symfony\Component\EventDispatcher\EventDispatcher + */ + protected $eventDispatcher; + + /** * Constructs the Config factory. * * @param Drupal\Core\Config\StorageInterface $storage * The storage controller object to use for reading and writing * configuration data. + * @param Symfony\Component\EventDispatcher\EventDispatcher + * An event dispatcher instance to use for configuration events. */ - public function __construct(StorageInterface $storage) { + public function __construct(StorageInterface $storage, EventDispatcher $event_dispatcher) { $this->storage = $storage; + $this->eventDispatcher = $event_dispatcher; } /** @@ -70,12 +82,9 @@ class ConfigFactory { // @todo The decrease of CPU time is interesting, since that means that // ContainerBuilder involves plenty of function calls (which are known to // be slow in PHP). - $config = new Config($name, $this->storage); + $config = new Config($name, $this->storage, $this->eventDispatcher); + $this->eventDispatcher->dispatch('config.create', new ConfigEvent($config)); - // Set overridden values from global $conf, if any. - if (isset($conf[$name])) { - $config->setOverride($conf[$name]); - } return $config; } diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php index b0830a0..f8e8691 100644 --- a/core/lib/Drupal/Core/CoreBundle.php +++ b/core/lib/Drupal/Core/CoreBundle.php @@ -58,6 +58,7 @@ class CoreBundle extends Bundle $dispatcher->addSubscriber(new \Drupal\Core\EventSubscriber\LegacyControllerSubscriber()); $dispatcher->addSubscriber(new \Drupal\Core\EventSubscriber\FinishResponseSubscriber()); $dispatcher->addSubscriber(new \Drupal\Core\EventSubscriber\RequestCloseSubscriber()); + $dispatcher->addSubscriber(new \Drupal\Core\EventSubscriber\ConfigGlobalOverrideSubscriber()); $container->set('content_negotiation', $content_negotation); $dispatcher->addSubscriber(\Drupal\Core\ExceptionController::getExceptionListener($container)); /* @@ -85,6 +86,7 @@ class CoreBundle extends Bundle ->addTag('kernel.event_subscriber'); $container->register('request_close_subscriber', 'Drupal\Core\EventSubscriber\RequestCloseSubscriber') ->addTag('kernel.event_subscriber'); + $container->register('config_global_override_subscriber', '\Drupal\Core\EventSubscriber\ConfigGlobalOverrideSubscriber'); $container->register('database', 'Drupal\Core\Database\Connection') ->setFactoryClass('Drupal\Core\Database\Database') ->setFactoryMethod('getConnection') diff --git a/core/lib/Drupal/Core/EventSubscriber/ConfigGlobalOverrideSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ConfigGlobalOverrideSubscriber.php new file mode 100644 index 0000000..d17fcfc --- /dev/null +++ b/core/lib/Drupal/Core/EventSubscriber/ConfigGlobalOverrideSubscriber.php @@ -0,0 +1,39 @@ +getConfig(); + if (isset($conf[$config->getName()])) { + $config->setOverride($conf[$config->getName()]); + } + } + + /** + * Implements EventSubscriberInterface::getSubscribedEvents(). + */ + static function getSubscribedEvents() { + $events['config.create'][] = array('configCreate', 30); + return $events; + } +} diff --git a/core/modules/locale/lib/Drupal/locale/LocaleConfigSubscriber.php b/core/modules/locale/lib/Drupal/locale/LocaleConfigSubscriber.php new file mode 100644 index 0000000..64e27cd --- /dev/null +++ b/core/modules/locale/lib/Drupal/locale/LocaleConfigSubscriber.php @@ -0,0 +1,53 @@ +getConfig(); + $language = language(LANGUAGE_TYPE_INTERFACE); + $locale_name = $this->getLocaleConfigName($config->getName(), $language); + if ($override = $config->getStorage()->read($locale_name)) { + $config->setOverride($override); + } + } + + /** + * Get configuration name for this language. + * + * It will be the same name with a prefix depending on language code: + * locale.config.LANGCODE.NAME + */ + public function getLocaleConfigName($name, $language) { + return 'locale.config.' . $language->langcode . '.' . $name; + } + + /** + * Implements EventSubscriberInterface::getSubscribedEvents(). + */ + static function getSubscribedEvents() { + $events['config.load'][] = array('configLoad', 20); + return $events; + } +} diff --git a/core/modules/locale/locale.module b/core/modules/locale/locale.module index f7c22c1..86f776c 100644 --- a/core/modules/locale/locale.module +++ b/core/modules/locale/locale.module @@ -12,6 +12,7 @@ */ use Drupal\locale\LocaleLookup; +use Drupal\locale\LocaleConfigSubscriber; /** * Regular expression pattern used to localize JavaScript strings. @@ -879,3 +880,11 @@ function _locale_rebuild_js($langcode = NULL) { return TRUE; } } + +/** + * Implements hook_language_init(). + */ +function locale_language_init() { + // Add locale helper to configuration subscribers. + drupal_container()->get('dispatcher')->addSubscriber(new LocaleConfigSubscriber()); +}