Commit 7b757ff4 authored by webchick's avatar webchick
Browse files

Issue #1646580 by chx, Jose Reyero, beejeebus: Implement Config Events and...

Issue #1646580 by chx, Jose Reyero, beejeebus: Implement Config Events and Listeners, and storage realms for localized configuration.
parent 8546e383
......@@ -2442,9 +2442,13 @@ function drupal_container(Container $reset = NULL) {
$container->register('config.storage', 'Drupal\Core\Config\DatabaseStorage')
->addArgument('%config.storage.options%');
$container->register('config.subscriber.globalconf', 'Drupal\Core\EventSubscriber\ConfigGlobalOverrideSubscriber');
$container->register('dispatcher', 'Symfony\Component\EventDispatcher\EventDispatcher')
->addMethodCall('addSubscriber', array(new Reference('config.subscriber.globalconf')));
// 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;
}
......
......@@ -8,6 +8,7 @@
namespace Drupal\Core\Config;
use Drupal\Component\Utility\NestedArray;
use Symfony\Component\EventDispatcher\EventDispatcher;
/**
* Defines the default configuration object.
......@@ -40,7 +41,7 @@ class Config {
*
* @var array
*/
protected $overrides;
protected $overrides = array();
/**
* The current runtime data ($data + $overrides).
......@@ -50,12 +51,19 @@ 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.
*
......@@ -64,10 +72,21 @@ 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');
}
/**
* Initializes a configuration object.
*/
public function init() {
$this->notify('init');
return $this;
}
/**
......@@ -159,7 +178,7 @@ public function setData(array $data) {
* The overridden values of the configuration data.
*/
public function setOverride(array $data) {
$this->overrides = $data;
$this->overrides = NestedArray::mergeDeepArray(array($this->overrides, $data));
$this->resetOverriddenData();
return $this;
}
......@@ -283,6 +302,7 @@ public function load() {
$this->isNew = FALSE;
$this->setData($data);
}
$this->notify('load');
return $this;
}
......@@ -293,6 +313,7 @@ public function save() {
$this->sortByKey($this->data);
$this->storage->write($this->name, $this->data);
$this->isNew = FALSE;
$this->notify('save');
return $this;
}
......@@ -324,6 +345,21 @@ public function delete() {
$this->storage->delete($this->name);
$this->isNew = TRUE;
$this->resetOverriddenData();
$this->notify('delete');
return $this;
}
/**
* Retrieve the storage used to load and save this configuration object.
*/
public function getStorage() {
return $this->storage;
}
/**
* Dispatch a config event.
*/
protected function notify($config_event_name) {
$this->eventDispatcher->dispatch('config.' . $config_event_name, new ConfigEvent($this));
}
}
<?php
namespace Drupal\Core\Config;
use Symfony\Component\EventDispatcher\Event;
use Drupal\Core\Config\Config;
class ConfigEvent extends Event {
/**
* Configuration object.
*
* @var Drupal\Core\Config\Config
*/
protected $config;
/**
* Constructor.
*/
public function __construct(Config $config) {
$this->config = $config;
}
/**
* Get configuration object.
*/
public function getConfig() {
return $this->config;
}
}
......@@ -7,6 +7,8 @@
namespace Drupal\Core\Config;
use Symfony\Component\EventDispatcher\EventDispatcher;
/**
* Defines the configuration object factory.
*
......@@ -29,15 +31,25 @@ 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,13 +82,8 @@ public function get($name) {
// @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);
// Set overridden values from global $conf, if any.
if (isset($conf[$name])) {
$config->setOverride($conf[$name]);
}
return $config;
$config = new Config($name, $this->storage, $this->eventDispatcher);
return $config->init();
}
}
......@@ -58,6 +58,7 @@ public function build(ContainerBuilder $container) {
$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 @@ public function build(ContainerBuilder $container) {
->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')
......
<?php
/**
* @file
* Definition of Drupal\Core\EventSubscriber\ConfigGlobalOverridesubscriber.
*/
namespace Drupal\Core\EventSubscriber;
use Drupal\Core\Config\Config;
use Drupal\Core\Config\ConfigEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Override configuration values with values in global $conf variable.
*/
class ConfigGlobalOverridesubscriber implements EventSubscriberInterface {
/**
* Override configuration values with global $conf.
*
* @param Drupal\Core\Config\ConfigEvent $event
* The Event to process.
*/
public function configInit(ConfigEvent $event) {
global $conf;
$config = $event->getConfig();
if (isset($conf[$config->getName()])) {
$config->setOverride($conf[$config->getName()]);
}
}
/**
* Implements EventSubscriberInterface::getSubscribedEvents().
*/
static function getSubscribedEvents() {
$events['config.init'][] = array('configInit', 30);
return $events;
}
}
<?php
/**
* @file
* Definition of Drupal\config\Tests\LocaleConfigOverride.
*/
namespace Drupal\config\Tests;
use Drupal\simpletest\WebTestBase;
/**
* Tests locale config override.
*/
class LocaleConfigOverride extends WebTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('locale', 'config_test');
public static function getInfo() {
return array(
'name' => 'Locale override',
'description' => 'Confirm that locale overrides work',
'group' => 'Configuration',
);
}
function testLocaleConfigOverride() {
$name = 'config_test.system';
// Verify the default configuration values exist.
$config = config($name);
$this->assertIdentical($config->get('foo'), 'bar');
// Spoof multilingual.
$GLOBALS['conf']['language_count'] = 2;
drupal_language_initialize();
$config = config($name);
$this->assertIdentical($config->get('foo'), 'en bar');
}
}
<?php
/**
* @file
* Definition of Drupal\locale\LocaleConfigsubscriber.
*/
namespace Drupal\locale;
use Drupal\Core\Config\Config;
use Drupal\Core\Config\ConfigEvent;
use Drupal\Core\Config\StorageDispatcher;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Locale Config helper
*
* $config is always a DrupalConfig object.
*/
class LocaleConfigsubscriber implements EventSubscriberInterface {
/**
* Override configuration values with localized data.
*
* @param Drupal\Core\Config\ConfigEvent $event
* The Event to process.
*/
public function configLoad(ConfigEvent $event) {
$config = $event->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;
}
}
......@@ -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());
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment