diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php index a9b6d97..545ef7b 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php @@ -87,6 +87,13 @@ class ConfigEntityStorage extends EntityStorageBase implements ConfigEntityStora protected $languageManager; /** + * A flag indicating if we should use overrides. + * + * @var boolean + */ + protected $useOverrides = TRUE; + + /** * Constructs a ConfigEntityStorage object. * * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type @@ -172,15 +179,37 @@ protected function doLoadMultiple(array $ids = NULL) { // Load all of the configuration entities. $records = array(); + if (!$this->getOverrideState()) { + $old_state = $this->configFactory->getOverrideState(); + $this->configFactory->setOverrideState(FALSE); + } foreach ($this->configFactory->loadMultiple($names) as $config) { $records[$config->get($this->idKey)] = $config->get(); } + if (isset($old_state)) { + $this->configFactory->setOverrideState($old_state); + } return $this->mapFromStorageRecords($records); } /** * {@inheritdoc} */ + public function setOverrideState($state) { + $this->useOverrides = $state; + return $this; + } + + /** + * {@inheritdoc} + */ + public function getOverrideState() { + return $this->useOverrides; + } + + /** + * {@inheritdoc} + */ protected function doCreate(array $values) { // Set default language to site default if not provided. $values += array('langcode' => $this->languageManager->getDefaultLanguage()->id); diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorageInterface.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorageInterface.php index 5efa615..44ef434 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorageInterface.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorageInterface.php @@ -37,4 +37,22 @@ public function getConfigPrefix(); */ public static function getIDFromConfigName($config_name, $config_prefix); + /** + * Sets the override state. + * + * @param bool $state + * TRUE if overrides should be applied, FALSE otherwise. + * + * @return $this + */ + public function setOverrideState($state); + + /** + * Gets the override state. + * + * @return bool + * Get the override state. + */ + public function getOverrideState(); + } diff --git a/core/lib/Drupal/Core/EventSubscriber/EntityRouteAlterSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/EntityRouteAlterSubscriber.php index 6283dae..e0d14cc 100644 --- a/core/lib/Drupal/Core/EventSubscriber/EntityRouteAlterSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/EntityRouteAlterSubscriber.php @@ -50,6 +50,7 @@ public function __construct(EntityManagerInterface $entity_manager) { */ public function onRoutingRouteAlterSetType(RouteBuildEvent $event) { $entity_types = array_keys($this->entityManager->getDefinitions()); + /** @var $route \Symfony\Component\Routing\Route */ foreach ($event->getRouteCollection() as $route) { $parameter_definitions = $route->getOption('parameters') ?: array(); // For all route parameter names that match an entity type, add the 'type' @@ -65,6 +66,11 @@ public function onRoutingRouteAlterSetType(RouteBuildEvent $event) { if (!empty($parameter_definitions)) { $route->setOption('parameters', $parameter_definitions); } + + // Entity forms should not use config overrides. + if ($route->hasDefault('_entity_form')) { + $route->setOption('skip_config_overrides', TRUE); + } } } diff --git a/core/lib/Drupal/Core/ParamConverter/EntityConverter.php b/core/lib/Drupal/Core/ParamConverter/EntityConverter.php index e906814..bad80a2 100644 --- a/core/lib/Drupal/Core/ParamConverter/EntityConverter.php +++ b/core/lib/Drupal/Core/ParamConverter/EntityConverter.php @@ -7,7 +7,9 @@ namespace Drupal\Core\ParamConverter; +use Drupal\Core\Config\Entity\ConfigEntityStorageInterface; use Drupal\Core\Entity\EntityManagerInterface; +use Symfony\Cmf\Component\Routing\RouteObjectInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Route; @@ -39,7 +41,20 @@ public function __construct(EntityManagerInterface $entity_manager) { public function convert($value, $definition, $name, array $defaults, Request $request) { $entity_type = substr($definition['type'], strlen('entity:')); if ($storage = $this->entityManager->getStorage($entity_type)) { - return $storage->load($value); + // If this route is set to skip config overrides, and this entity type + // uses config entity storage, set the storage to skip overrides. + if ($storage instanceof ConfigEntityStorageInterface && $defaults[RouteObjectInterface::ROUTE_OBJECT]->getOption('skip_config_overrides')) { + $old_state = $storage->getOverrideState(); + $storage->setOverrideState(FALSE); + } + + $entity = $storage->load($value); + + // Restore the override state. + if (isset($old_state)) { + $storage->setOverrideState($old_state); + } + return $entity; } } diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigEntityFormOverrideTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigEntityFormOverrideTest.php new file mode 100644 index 0000000..e8510a2 --- /dev/null +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigEntityFormOverrideTest.php @@ -0,0 +1,71 @@ + 'Config entity form overrides', + 'description' => 'Tests that config overrides do not bleed through in entity forms.', + 'group' => 'Configuration', + ); + } + + /** + * Tests that overrides do not affect forms. + */ + public function testFormsWithOverrides() { + $this->drupalLogin($this->drupalCreateUser(array('access administration pages', 'administer site configuration'))); + + $overridden_name = 'Overridden label'; + + // Set up an override. + $settings['config']['config_test.dynamic.dotted.default']['label'] = (object) array( + 'value' => $overridden_name, + 'required' => TRUE, + ); + $this->writeSettings($settings); + \Drupal::configFactory()->setOverrideState(TRUE); + + // Test that everything on the form is the same, but that the override + // worked for the actual site name. + $this->drupalGet('admin/structure/config_test'); + $this->assertText($overridden_name); + + $this->drupalGet('admin/structure/config_test/manage/dotted.default'); + $elements = $this->xpath('//input[@name="label"]'); + $this->assertIdentical((string) $elements[0]['value'], 'Default'); + $this->assertNoText($overridden_name); + $edit = array( + 'label' => 'Custom label', + ); + + $this->drupalPostForm(NULL, $edit, t('Save')); + $this->drupalGet('admin/structure/config_test'); + $this->assertText($overridden_name); + $this->assertNoText($edit['label']); + + $this->drupalGet('admin/structure/config_test/manage/dotted.default'); + $elements = $this->xpath('//input[@name="label"]'); + $this->assertIdentical((string) $elements[0]['value'], $edit['label']); + } + +} diff --git a/core/modules/config/tests/config_test/config_test.routing.yml b/core/modules/config/tests/config_test/config_test.routing.yml index 4e1b22d..a78eb65 100644 --- a/core/modules/config/tests/config_test/config_test.routing.yml +++ b/core/modules/config/tests/config_test/config_test.routing.yml @@ -16,16 +16,16 @@ config_test.entity_add: config_test.entity: path: '/admin/structure/config_test/manage/{config_test}' defaults: - _content: '\Drupal\config_test\ConfigTestController::edit' - entity_type: 'config_test' + _entity_form: config_test + _title_callback: '\Drupal\config_test\ConfigTestController::editTitle' requirements: _access: 'TRUE' config_test.entity_config_test_no_status: path: '/admin/structure/config_test/manage/{config_test_no_status}' defaults: - _content: '\Drupal\config_test\ConfigTestController::edit' - entity_type: 'config_test_no_status' + _entity_form: config_test_no_status + _title_callback: '\Drupal\config_test\ConfigTestController::editTitle' requirements: _access: 'TRUE' diff --git a/core/modules/config/tests/config_test/lib/Drupal/config_test/ConfigTestController.php b/core/modules/config/tests/config_test/lib/Drupal/config_test/ConfigTestController.php index 836b76a..c561366 100644 --- a/core/modules/config/tests/config_test/lib/Drupal/config_test/ConfigTestController.php +++ b/core/modules/config/tests/config_test/lib/Drupal/config_test/ConfigTestController.php @@ -9,7 +9,6 @@ use Drupal\Core\Controller\ControllerBase; use Drupal\config_test\Entity\ConfigTest; -use Drupal\Component\Utility\String; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\RedirectResponse; @@ -19,7 +18,7 @@ class ConfigTestController extends ControllerBase { /** - * Presents the ConfigTest edit form. + * Route title callback. * * @param \Drupal\config_test\Entity\ConfigTest $config_test * The ConfigTest object to edit. @@ -27,10 +26,8 @@ class ConfigTestController extends ControllerBase { * @return array * A form array as expected by drupal_render(). */ - public function edit(ConfigTest $config_test) { - $form = $this->entityFormBuilder()->getForm($config_test); - $form['#title'] = String::format('Edit %label', array('%label' => $config_test->label())); - return $form; + public function editTitle(ConfigTest $config_test) { + return $this->t('Edit %label', array('%label' => $config_test->label())); } /** diff --git a/core/modules/config/tests/config_test/lib/Drupal/config_test/ConfigTestForm.php b/core/modules/config/tests/config_test/lib/Drupal/config_test/ConfigTestForm.php index 6fcc00c..8a680b2 100644 --- a/core/modules/config/tests/config_test/lib/Drupal/config_test/ConfigTestForm.php +++ b/core/modules/config/tests/config_test/lib/Drupal/config_test/ConfigTestForm.php @@ -33,6 +33,7 @@ public function form(array $form, array &$form_state) { '#required' => TRUE, '#machine_name' => array( 'exists' => 'config_test_load', + 'replace_pattern' => '[^a-z0-9_.]+', ), ); $form['weight'] = array(