Once #2392319: Config objects (but not config entities) should by default be immutable is committed, we should be able to remove these functions and the whole concept of an override free config factory.

It should still be possible to get editable configuration objects override free but the state should not settable. This will help us prevent unexpected usage of override free configuration objects. For example, if you create a config event listener the config factory will be in an override-free state for the save and delete events but not for rename. The save and delete events should have the override-free config object but all other configuration obtained from the factory should have overrides.

Proposed resolution

Remove the methods.

Remaining tasks

On commit add this issue to the CR

User interface changes


API changes

Removed ConfigFactory::setOverrideState and ConfigFactory::getOverrideState()

Beta phase evaluation

Issue category Bug because a stateful config factory is problematic. It makes unintentional side effects very difficult to avoid.
Issue priority Critical because config CRUD events are runtime actions but the config factory is in override free state.
Disruption Disruptive for anything that use setOverrideState or getOverrideState. This is mitigated by the fact that these should probably be using ConfigFactory::getEditable() anyway.
#6 2406543.6.patch33.82 KBalexpott
PASSED: [[SimpleTest]]: [PHP 5.4 MySQL] 84,130 pass(es). View
#6 3-6-interdiff.txt1.44 KBalexpott
#3 2406543.3.patch33.79 KBalexpott
FAILED: [[SimpleTest]]: [PHP 5.4 MySQL] 83,738 pass(es), 60 fail(s), and 24 exception(s). View
Members fund testing for the Drupal project. Drupal Association Learn more


alexpott’s picture

Issue summary: View changes
alexpott’s picture

Status: Postponed » Active
alexpott’s picture

Status: Active » Needs review
33.79 KB
FAILED: [[SimpleTest]]: [PHP 5.4 MySQL] 83,738 pass(es), 60 fail(s), and 24 exception(s). View

Patch that removes these methods from the factory. Things to note:

  • We no longer need to be override free in the early installer - this was a leftover from when language overrides were baked into the config factory.
  • ConfigEntityStorage has an overrideFree flag - this is okay was it is only set and unset during loadMultipleOverrideFree and therefore does not affect the state of the entity storage for subsequent loads. We have to do this because of the way EntityStorageBase::loadMultiple() is used.
alexpott’s picture

Issue summary: View changes

Status: Needs review » Needs work

The last submitted patch, 3: 2406543.3.patch, failed testing.

alexpott’s picture

Status: Needs work » Needs review
1.44 KB
33.82 KB
PASSED: [[SimpleTest]]: [PHP 5.4 MySQL] 84,130 pass(es). View

Fixing the tests (hopefully).

alexpott’s picture

Issue summary: View changes
alexpott’s picture

alexpott queued 6: 2406543.6.patch for re-testing.

Gábor Hojtsy’s picture

Issue tags: +Needs change notice

I think this is a clear improvement, removes one moving piece. I think it would be *really* fabulous to document when to use getEditable() on the factory vs. getOriginal() on config vs. getOverrideFree on storage. They are similar in some way (also see some notes below). However I don't think that could be in this patch in some way. Also whole #2392319: Config objects (but not config entities) should by default be immutable's change notice covers some of this, the removal of the public API to switch this state is well worth its own change notice.

  1. +++ b/core/lib/Drupal/Core/Config/ConfigFactory.php
    @@ -278,20 +252,17 @@ public function rename($old_name, $new_name) {
    -    $keys = array();
    -    if ($this->useOverrides) {
    -      // Because get() adds overrides both from $GLOBALS and from
    -      // $this->configFactoryOverrides, add cache keys for each.
    -      $keys[] = 'global_overrides';
    -      foreach($this->configFactoryOverrides as $override) {
    -        $keys[] =  $override->getCacheSuffix();
    -      }
    +    // Because get() adds overrides both from $GLOBALS and from

    Should this not depend on immutability as well? Correction: ah, you only invoke it if immutable.

  2. +++ b/core/modules/config/src/Tests/ConfigCRUDTest.php
    @@ -87,9 +85,7 @@ function testCRUD() {
    -    $config_factory->setOverrideState(FALSE);
    -    $this->assertIdentical($config_factory->get($name)->isNew(), TRUE);
    -    $config_factory->setOverrideState(TRUE);
    +    $this->assertIdentical($config_factory->getEditable($name)->isNew(), TRUE);

    Woot, so much better :)

  3. +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php
    @@ -179,7 +186,7 @@ protected function doLoadMultiple(array $ids = NULL) {
    -      $records[$config->get($this->idKey)] = $config->get();
    +      $records[$config->get($this->idKey)] = $this->overrideFree ? $config->getOriginal(NULL, FALSE) : $config->get();

    Is this what we expect? Config's get returns the current runtime value (may be different from getOriginal() which is the "on disk" value). So there are subtle differences between override free and original depending on whether there are runtime changes.

alexpott’s picture

#10.3 Well if we are relying on the object to hold changes that have not been saved for config entities we'll have major problems. So I think this is acceptable. No one should be interacting with config entities directly through the config factory unless they are doing something exceptionally low level - i.e. certain language operations. And these definitely should only be doing reads and not sets/saves - since if they save then all the entity hooks are avoided.

Gábor Hojtsy’s picture

@alexpott: ok I don't have a problem with that; I think there are definitely tests where they use the config API direct so the config entity storage cache may not be updated; that evidently does not fail, I guess we don't use the entity API after that. Not sure if we want to add a test for or against what we expect here but if this is an expected behavior it sounds like it would make sense.

alexpott’s picture

I wonder if we should remove the static cache in the ConfigFactory for config entities. This would remove an unnecessary layer of static caching and make the concerns go away.

Berdir’s picture

Config entities do not have static cache enabled by default at the moment: #1885830: Enable static caching for config entities

Gábor Hojtsy’s picture

I see there are getFromStaticCache and setStaticCache methods but the config entity type is not statically cacheable, so no use. Haha.

Berdir’s picture

Yes they are theoretically, we AFAIK use it for roles, but it is not enabled by default. And if you look at the other issue, the tests there fail with dozens of weird invalid cache issues, that I was too lazy to track down.

Berdir’s picture

But agreed that for those that we do cache statically, we should not cache them twice. Which is more complicated than it sounds I think, maybe the entity storage class could tell the factory to not cache what it is loading, but there is also the entity query implementation that afaik works on raw config values, so that would make entity queries possibly slower.

alexpott’s picture

So I've tried to add a test for this but it's just impossible because you can't set data on an immutable config object :) and if you are changing a config entity it does a setData() so anything that is set is blotto-ed anyway. So I think we are good to go here.

Gábor Hojtsy’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs change notice

All right, I did not find anything else. Added draft change notice at

webchick’s picture

Assigned: Unassigned » catch

Since catch committed #2392319: Config objects (but not config entities) should by default be immutable and this seems highly related, tossing over to him.

  • catch committed ea1dd45 on 8.0.x
    Issue #2406543 by alexpott: Remove ConfigFactory::setOverrideState and...
catch’s picture

Assigned: catch » Unassigned
Status: Reviewed & tested by the community » Fixed

Really like this. It's hard to get your head around config overrides and this removes a potential source of confusion.

Committed/pushed to 8.0.x, thanks!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.