Problem/Motivation

Since Symfony 3.2, PHP constants are allowed in YAML files, but the YAML parser needs to be executed with an explicit flag to make that happen. We are not using this flag in core.

With that set, we could use this notation inside YAML files:

foo: !php/const Drupal\my_module\Plugin\Foo\Bar\MyPlugin::MY_CLASS_CONSTANT_NAME

More information:
https://symfony.com/blog/new-in-symfony-3-2-php-constants-in-yaml-files

Proposed resolution

Call the Symfony YAML parser with the Yaml::PARSE_CONSTANT flag, that also allows parsing enumerations that were added in PHP in the meantime since OP.

Given that .module files with Drupal-specific global constants are being sunset, do not generally support reading these constants but limit to class-based constants and enums.

Remaining tasks

Resolve constant resolution during module install and

User interface changes

API changes

Data model changes

Issue fork drupal-2951046

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

marcoscano created an issue. See original summary.

marcoscano’s picture

Assigned: marcoscano » Unassigned
Issue summary: View changes
Status: Active » Needs review
StatusFileSize
new894 bytes
dawehner’s picture

Can you think of a usecase in core so we have some implicit test coverage?

marcoscano’s picture

StatusFileSize
new1.47 KB
new613 bytes

That's a good idea! Let's see what the testbot says about this.

One thing I realized though is that we prioritize the PECL YAML extension over the Symfony implementation:

  /**
   * Determines which implementation to use for parsing YAML.
   */
  protected static function getSerializer() {

    if (!isset(static::$serializer)) {
      // Use the PECL YAML extension if it is available. It has better
      // performance for file reads and is YAML compliant.
      if (extension_loaded('yaml')) {
        static::$serializer = YamlPecl::class;
      }
      else {
        // Otherwise, fallback to the Symfony implementation.
        static::$serializer = YamlSymfony::class;
      }
    }
    return static::$serializer;
  }

I have no idea if the PECL YAML supports php constants, but if it doesn't it would be a bummer... :(

amateescu’s picture

It seems that the PECL YAML parser supports custom callbacks, so we could easily add one for !php/const: http://php.net/manual/en/yaml.callbacks.parse.php

Status: Needs review » Needs work

The last submitted patch, 4: 2951046-4.patch, failed testing. View results

marcoscano’s picture

Status: Needs work » Needs review
StatusFileSize
new2.64 KB
new1.17 KB

Does the d.o CI uses the PECL YAML parser? :)

Let's see if this helps.

Thanks!

marcoscano’s picture

Yay, green! :)

jibran’s picture

+++ b/core/profiles/standard/config/install/field.storage.node.field_tags.yml
@@ -12,7 +12,7 @@ settings:
-cardinality: -1
+cardinality: !php/const Drupal\Core\Field\FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED

We need an upgrade path for this.

dawehner’s picture

+++ b/core/profiles/standard/config/install/field.storage.node.field_tags.yml
@@ -12,7 +12,7 @@ settings:
 locked: false
-cardinality: -1
+cardinality: !php/const Drupal\Core\Field\FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED
 translatable: true

I'm not 100% convinced about this change here. If you think about it, resaving the UI would then trigger a config diff, doesn't it? Maybe we should add a constant to a test only file.

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

rogierbom’s picture

StatusFileSize
new2.58 KB

The patch in #7 fails to apply on 8.6.1 and 8.7.x. Attached is a new patch that does.

I was not able to create an interdiff somehow, sorry for that.

jparkinson1991’s picture

Im all for this, if at core we are wrapping symfony components, these components in my opinion must have all features enanbled for them, or (probably more work) be leveraged/used in a configurable manor so that the developers can add theses options easily without patches etc.

I would say some great use cases for this are:
- route id's,
- permission keys,
- anywhere where we can swap the use of 'hard typed' strings with accessbile constants.

Thanks for the patch, #12 applied successfully on 8.6.5

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Eduardo Morales Alberti made their first commit to this issue’s fork.

eduardo morales alberti’s picture

Version: 9.5.x-dev » 9.4.x-dev
Status: Needs review » Reviewed & tested by the community

Tested on drupal 9.4.5, thanks!!
Created MR to be easiest to merge.

quietone’s picture

Status: Reviewed & tested by the community » Needs work

@Eduardo Morales Alberti, thanks for the interest. Can you add what you did to test this patch?

Reviewing the comments I see that #3, #5, #9 and #10 have not been addressed. Setting to NW for those.

chi’s picture

I am using patch #12 on a large project to store route names in class constants.
I works very well for me.

!php/const Drupal\example_dashboard\Routes::METRICS:
  path: '/dashboard/metrics'
  defaults:
    _title: 'Metrics'
    _controller: '\Drupal\example_dashboard\Controller\DashboardController'
  requirements:
    _permission: 'access to example dashboard'
eduardo morales alberti’s picture

@quietone okey, I will answer

#3 Can you think of a usecase in core so we have some implicit test coverage?

Maybe the usecase in core is the same that the patch. field.storage.node.field_tags.yml, this MR need tests.

It seems that the PECL YAML parser supports custom callbacks, so we could easily add one for !php/const: http://php.net/manual/en/yaml.callbacks.parse.php

The comment #6 patch do what @amateescu comments, add a custom callback:

+      '!php/const' => '\Drupal\Component\Serialization\YamlPecl::parsePhpConstant',
#9/#10
+++ b/core/profiles/standard/config/install/field.storage.node.field_tags.yml
@@ -12,7 +12,7 @@ settings:
-cardinality: -1
+cardinality: !php/const Drupal\Core\Field\FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED

We need an upgrade path for this.

Yes, we should add an upgrade for the file.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.9 was released on December 7, 2022 and is the final full bugfix release for the Drupal 9.4.x series. Drupal 9.4.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.5.x-dev branch from now on, and new development or disruptive changes should be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

alexpott’s picture

This is lovely. It'd be great to add supported to enums at the same time.

alexpott’s picture

We can extend \Drupal\Tests\Component\Serialization\YamlTest::testYamlFiles() to add explicit test coverage.

alexpott’s picture

Version: 9.5.x-dev » 11.x-dev
Status: Needs work » Needs review

Rebased the MR on to 11.x

alexpott’s picture

Category: Feature request » Task
Issue tags: +Needs change record

This will allow us to use enums as container arguments which would have been lovely for https://www.drupal.org/project/drupal/issues/3402168

I'm going to change this to a task because I don't really think this is a feature request. We need this change in order to support modern PHP in the container and config system.

alexpott’s picture

Title: Allow parsing PHP constants in YAML files » Allow parsing and writing PHP constants and enums in YAML files
wim leers’s picture

Status: Needs review » Needs work
Issue tags: +DX (Developer Experience)

This is looking great already! 🤩

alexpott’s picture

Status: Needs work » Needs review
alexpott’s picture

Our test coverage of this change is not create until #3402448: Add PECL Yaml to PHP 8.1 and PHP 8.2 is fixed.

andypost’s picture

Created https://git.drupalcode.org/issue/drupal-3386474/-/pipelines/51765 to test new dev images with YAML extension enabled

andypost’s picture

Core should be fixed before we can roll new image

Status    Group      Filename          Line Function                            
--------------------------------------------------------------------------------
[33mException Other      phpunit-208.xml      0 Drupal\Tests\Core\DependencyInjecti
[0m    PHPUnit Test failed to complete; Error: PHPUnit 9.6.13 by Sebastian
    Bergmann and contributors.
    
    Testing Drupal\Tests\Core\DependencyInjection\YamlFileLoaderTest
    .............E                                                    14 / 14
    (100%)
    
    Time: 00:00.074, Memory: 6.00 MB
    
    There was 1 error:
    
    1) Drupal\Tests\Core\DependencyInjection\YamlFileLoaderTest::testExceptions
    with data set "YAML must be valid" ('   do not:\n      do this for...o
    Bar!', 'The file "vfs://drupal/module...d YAML')
    Array to string conversion
    
    /builds/issue/drupal-3386474/core/lib/Drupal/Core/DependencyInjection/YamlFileLoader.php:454
    /builds/issue/drupal-3386474/core/lib/Drupal/Core/DependencyInjection/YamlFileLoader.php:423
    /builds/issue/drupal-3386474/core/lib/Drupal/Core/DependencyInjection/YamlFileLoader.php:71
    /builds/issue/drupal-3386474/core/tests/Drupal/Tests/Core/DependencyInjection/YamlFileLoaderTest.php:78
    /builds/issue/drupal-3386474/vendor/phpunit/phpunit/src/Framework/TestResult.php:728
    /builds/issue/drupal-3386474/vendor/phpunit/phpunit/src/Framework/TestSuite.php:684
    /builds/issue/drupal-3386474/vendor/phpunit/phpunit/src/Framework/TestSuite.php:684
    /builds/issue/drupal-3386474/vendor/phpunit/phpunit/src/TextUI/TestRunner.php:651
    /builds/issue/drupal-3386474/vendor/phpunit/phpunit/src/TextUI/Command.php:144
    /builds/issue/drupal-3386474/vendor/phpunit/phpunit/src/TextUI/Command.php:97
    
    ERRORS!
    Tests: 14, Assertions: 32, Errors: 1.
[31mFail      run-tests. Unknown              0 Unknown                            
[0m    FATAL Drupal\Tests\Core\DependencyInjection\YamlFileLoaderTest: test runner
    returned a non-zero error code (2).
alexpott’s picture

opened #3402548: YamlFileLoaderTest fails if you have PECL yaml installed to fix the HEAD fail with PECL yaml.

smustgrave made their first commit to this issue’s fork.

smustgrave’s picture

Just rebased since the issue in #38 was merged.

smustgrave’s picture

Status: Needs review » Needs work

See it was tagged for a CR, so only moving to NW for that.

neclimdul’s picture

Looking through the code, I expect this is probably only reading constants not writing them unless there's some magic I missed so the title/scope should probably be updated to avoid confusion.

That makes this only useful to developers writing config directly like comments that also cannot be sync'd but that was probably always the only reasonable scope. I think that's still worthwhile for maintainability of core and contrib so +1

Our CR should probably be clear about the side effects/impact of this though. If you write a constant in your install config, then at some point in the future change that constant's value (like bumping password strengths or something) it won't change installed config on sites. You'll need to provide a method for user's to get that updated value. This is also going to be hard to test for because your test site in CI will get the new value during install masking the impact.

alexpott’s picture

@neclimdul Symfony yaml can write enums - which come out as constants... see the test added here. Also core only ever writes with Symfony yaml... you are not supposed to write with PECL yaml. It is not supported since forever.

neclimdul’s picture

I'm aware symphony does all the writing in drupal. We don't touch the encoder though and the test asserts the parsed yaml matches the value of the constant, not that the constant format is in the encoded yaml.

I'll do some manual testing in a few days to make sure I'm not missing something though.

alexpott’s picture

@neclimdul there is no value for
$this->assertSame($symfony['foo'], EnumValue::Yes); - it's not backed... this is an instance of test. It's the same for the backed enum - it would have to be BackedEnumValue::Maybe->value and not BackedEnumValue::Maybe for a comparison of values. Which would fail....

alexpott’s picture

Status: Needs work » Needs review
Issue tags: -Needs change record

Added the CR...

In doing that I've realised that we have a problem... due to config import. We read configuration prior to doing the import. At this point, if a module that is providing a enum that's in config is being installed everything will crash. Because the enum won't exist and be autoloadable yet. Fixing that would take a complicated changes to the ConfigImporter. I think in the long run we're going to have to make because if we want to validate config we're going to need to be able to load the custom constraints... but it is all very very awkward.

alexpott’s picture

Re #46 even if we fix the config importer we'd still have the config comparing via the UI and Drush... so maybe we just have to say no to enums in config - until we stop futzing with the autoloader and just let composer do it all - which would be a massive massive change.

wim leers’s picture

Status: Needs review » Needs work
Issue tags: +Needs tests

This looks very close, but I think we need a bit more test coverage to ship this with full confidence.

alexpott’s picture

@Wim Leers
1. That doesn't really matter... we're not storing the backed value FWIW.
2. That's just a regular const - no different from another class constant. It's not a special case.
3. When Symfony writes out an enum it uses php/const not php/enum - enums in PHP are really constants under the hood.

wim leers’s picture

Issue tags: -Needs tests
  1. I know it doesn't really matter. Personally, for something as low-level and fundamental as this, I find it reassuring to see the whole spectrum explicitly tested. Especially when writing tests for it isn't painful. Anyway, no big deal, just a matter of preference 👍
  2. [See point 3 first.] That may be, but I'd be interested to see how it gets serialized into YAML: as !php/enum SomeEnum::ValueUsingAConstant or as !php/const TheConstant.
  3. Huh — then why does https://symfony.com/blog/new-in-symfony-6-2-improved-enum-support#enums-... literally show !php/enum SomeEnum::Foo? 😳

    Did some investigating, and you're right! 🤪

    Quoting @nicolas-grekas from https://github.com/symfony/symfony/pull/46771:

    This PR allows one to use the following Yaml together with enums:

    - !php/enum SomeEnum::Bar
    - !php/enum SomeEnum::Bar->value
    

    The first line gets the SomeEnum::Bar instance. It's the same as writing !php/const SomeEnum::Bar but with an additional check that this is really an enum.

    IOW:

    1. Symfony will only encode enums using ONLY !php/const
    2. Symfony will only decode enums using BOTH !php/const and !php/enum, and in the latter case it will run extra checks.

    I think it'd be very confusing to use Symfony's advanced YAML capabilities but then do it in a way that only a subset of what their public docs/announcements show. Even if in Drupal's configuration we cannot encode !php/enum, I think it would be valuable to support decoding it: to match what Symfony supports/its docs claim, as well as for the extra assurances.

    More importantly: otherwise the PECL and Symfony YAML decoders would behave differently on the same YAML. Because Yaml::PARSE_CONSTANT triggers support for both !php/const and !php/enum.

    Just pushed suggested additional test coverage: once that passes my concerns would be addressed. If you disagree Drupal should support Symfony's !php/enum even when using PECL, then … that's fine, I defer to you, but then at least I've expressed my concern and demonstrated it to the best of my ability 😄

alexpott’s picture

Sure lets support Symfony's !php/enum this will be useful for services. As per #46 I'm not convinced that we can use this in Config :(

wim leers’s picture

Right 😞 We'd need the config subsystem to special-case core.extension more than it already does. Not simple, but doable, and probably worthwhile. Once this issue is done we'll have at least one use case already — and I suspect more once we factor in Recipes' needs 😄🤓

alexpott’s picture

@Wim Leers - I think we'll need a special autoloader for comparing configuration. It's going to be horrible! The better solution would be to completely remove Drupal's approach to autoloading. But this is a significant challenge.

wim leers’s picture

Title: Allow parsing and writing PHP constants and enums in YAML files » [PP-1] Allow parsing and writing PHP constants and enums in YAML files
wim leers’s picture

Title: [PP-1] Allow parsing and writing PHP constants and enums in YAML files » Allow parsing and writing PHP constants and enums in YAML files

Wow, what a coincidence: minutes after posting that, #3205480: Drop PECL YAML library support in favor of only Symfony YAML actually landed! 😄

wim leers’s picture

Priority: Normal » Major
Status: Needs work » Needs review
Issue tags: +Configuration schema, +validation

Merged in 3 months of upstream changes, most notably: resolved the conflict with #3205480: Drop PECL YAML library support in favor of only Symfony YAML (hopefully correctly).

@alexpott's work on this MR was already demonstrating very clearly how much this helps improve the config validation DX. So tagging and bumping priority.

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new2.98 KB

The Needs Review Queue Bot tested this issue. It fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

wim leers’s picture

Assigned: Unassigned » wim leers

gapple made their first commit to this issue’s fork.

gapple’s picture

Assigned: wim leers » Unassigned
Priority: Major » Normal
Status: Needs work » Needs review

Added some small changes:
- Cleanup unused data provider
- Don't require yaml extension for tests
- Cleanup mentions of Pecl in doc comments
- Symfony doesn't accept !php/const for the value of a backed enum (BackedEnumValue::Maybe->value)

gapple’s picture

Priority: Normal » Major

Restoring priority

wim leers’s picture

Status: Needs review » Reviewed & tested by the community

Thanks for fixing my conflict resolution mistakes, @gapple! 😄🙏

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

I think we need to address #53 before we allow this. I think we need a special autoloader that can only autoload enums from uninstalled modules that we activate in the ConfigImporter. If we don't do this then we're going to give people an easy way to break a site.

wim leers’s picture

Issue tags: +Needs tests

I missed that 😬 🫣

#46 provides a good description of the edge case. We should start by adding test coverage for the exact scenario described in #46, and that test will fail with the current MR.

neclimdul’s picture

Issue summary: View changes

Yeah, that seems pretty important since my understanding is that's the only place we'd be supporting this this right? Managing dependencies in the active store or exports sounds like an impossible task that would largely undo the consistency promises of config.

wim leers’s picture

narendraR made their first commit to this issue’s fork.

narendrar’s picture

I tried to add a test in previous commit, which should fail, but it is not failing. 🤷‍♂️

alexpott’s picture

@narendraR the test autoloader is pure evil. It needs to be a functional test and you need to do the config import via the UI on the system-under-test.

wim leers’s picture

@narendraR Would be great if you could push this forward again 😇

narendrar’s picture

Functional tests are failing in _install_get_version_info($version) for $version=11.0-dev in current MR and passing in 11.x 🤯. I think it needs unblocking from @alexpott 🙏

mikelutz made their first commit to this issue’s fork.

alexpott’s picture

Status: Needs work » Needs review

The tests are now fixed... sorry everyone I messed up implementing \Drupal\Core\Config\AutoloadingStorage::listAll() and didn't pass the prefix on to the underlying storage - which messed things up in a really confusing way.

alexpott’s picture

Issue tags: -Needs tests

We have added the missing test coverage that @Wim Leers identifier - i.e. test coverage of config import containing enums for class in modules that are not yet installed.

mikelutz’s picture

Lol, took forever to find the listAll() bug, and you fixed it before I could push :-)

longwave’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: +DevDaysBurgas2024

This looks good to me and means our YAML can be more readable instead of copy-pasting constant values around.

mikelutz’s picture

Status: Reviewed & tested by the community » Needs review

https://git.drupalcode.org/project/drupal/-/blob/11.x/core/lib/Drupal/Co.... Found this too, while I was debugging the tests. Do we need to add the Autoloading storage here?

in the Storage Comparer:

  if ($source_storage instanceof FileStorage) {
      // FileStorage has its own static cache so that multiple reads of the
      // same raw configuration object are not costly.
      $this->sourceCacheStorage = new NullBackend('storage_comparer');
      $this->sourceStorage = $source_storage;
    }
neclimdul’s picture

Not the decision maker but just going to re-iterate, I think this is a bad idea. The hacks I see for uninstalled modules seem like just the tip of the iceberg. What about removed modules. removed libraries. uninstalled themed. profiles.... it seems like a loosing battle for little benefit.

alexpott’s picture

@mikelutz we already get an autoloading storage here because it's getting the storage from config.storage.sync and we have test coverage in \Drupal\Tests\config\Functional\ConfigImportUITest::testEnumViaConfigImporter()

mikelutz’s picture

Right, that was my question. We now get an AutoloadingStorage here. Previously we got a FileStorage, and since FileStorage has it's own static cache, we were not setting a storage cache. Now we have an AutoloadingStorage, which is based on FileStorage and uses it behind the scenes, but we are setting the storage cache as well, since it's not a FileStorage. I was wondering if we needed to. As I was stepping through HEAD and the patch trying to find the difference that caused the bug in listAll it was one of the differences I noticed, as the importer was operating on a CachedStorage object in the patch versus a FileStorage object on HEAD. It wasn't the problem, but I'm wondering if we need the sourceCacheStorage with the Autoloading storage, or if we should carve out the same exception for AutoloadingStorage here that we have carved out for FileStorage.

It works either way, but I'm not certain which way is more performant, or if something new in the AutoloadingStorage makes the cached storage helpful again.

mikelutz’s picture

Status: Needs review » Reviewed & tested by the community

I don't want to block this, I just wanted to point it out and ask.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

@mikelutz oh I see what you are on about. We are undoing the work in #3415821: StorageComparer should not wrap sourceStorage with a memory cache if it extends \Drupal\Core\Config\FileStorage - that's not good. Hmmm....

phenaproxima’s picture

Just now getting into this issue, but I'm pretty spooked by @neclimdul's comment in #78. This has serious implications because, with this change as proposed, config schema can indirectly influence the dependency tree. That's a real danger zone.

If we're going to do this, then I think we need to have some kind of coherent fallback mechanism if a constant or enum cannot be loaded or parsed. It must fail gracefully.

Either that, or we should go in the opposite direction and it should be extremely strict, with clear rules about when a constant in YAML is valid or not, and what conditions need to be fulfilled for that.

alexpott’s picture

It must fail gracefully.

I beg to differ. It must fail loudly and obviously. If you have removed code that your configuration expects this is a big error that Drupal soldiers on from time and time again causing more harm.

phenaproxima’s picture

Then it has to be extremely strict, and exceptionally clear about what the rules are.

So, like @neclimdul, stuff like this is giving me pause:

    // Ensure enums and constants from uninstalled modules can be autoloaded.
    $storage = new AutoloadingStorage($storage, [$name => \Drupal::root() . '/' . $this->extensionPathResolver->getPath($type, $name)]);

What is the justification for allowing this kind of thing?

alexpott’s picture

Because we need to be able to load configuration during config import before a module has been installed. NOTE: the AutolaodingStorage only applies to sync storage and not to active storage - so in my mind the risk is actually minimal and correct because it is exactly the time you expect code to change. FWIW there is no difference here if you try to import a config entity for a module and the entity class is not present. Once you run the import things are not going to work as you expect or want. It would be great if #2628144: Ensure that ConfigImport is taking place against the same code base and #2762235: Ensure that ConfigImport is taking place without outstanding updates had landed back when they were green years ago but people got far too used to being able to import incorrect versions config and began to see it as a feature rather than the bug that it is.

mikelutz’s picture

Not the decision maker but just going to re-iterate, I think this is a bad idea. The hacks I see for uninstalled modules seem like just the tip of the iceberg. What about removed modules. removed libraries. uninstalled themed. profiles.... it seems like a loosing battle for little benefit.

I'm not fully seeing the issue here. What do you mean about removed modules, removed libraries, etc? If you uninstall/remove code providing a constant/enum used in your active configurations, you will have problems, as you should. The 'hack' here only adds a module to the classloader as it's config is read in preparation to install it. This seems appropriate to me, as the config you are installing should be able to use enums defined in the module you are installing. This isn't about loading enums and consts from uninstalled modules, this is to load enums and consts from a module that we are in the process of installing. I really think the inline comments are scarier than what the code is doing, and I made a couple suggestions on the comments.

I also added a test here that I think shows another issue, config referencing constants that are in the modules .module file. I think we will have to include the .module file before parsing the config as well.

Also, I tried to find a more elegant way to prevent double caching of the autoloading storage, but I really couldn't, so I just added a second instanceof check in the Comparer. I don't like it.

mondrake made their first commit to this issue’s fork.

mondrake’s picture

Merged wit 11.x HEAD, resolved conflicts and addressed PHPCS and PHPStan errors. Would love to see this in.

mondrake’s picture

This is now failing with

Drupal\Core\Config\UnsupportedDataTypeConfigException: Invalid data type in config config_enum_test.settings, found in file core/modules/config/tests/config_enum_test/config/install/config_enum_test.settings.yml: The constant "CONFIG_ENUM_TEST_VALUE" is not defined at line 2 (near "bar: !php/const CONFIG_ENUM_TEST_VALUE"). in Drupal\Core\Config\FileStorage->read() (line 118 of core/lib/Drupal/Core/Config/FileStorage.php).

I suppose because CONFIG_ENUM_TEST_VALUE is a global const defined in config_enum_test.module, but the module file is not preloaded.

mikelutz’s picture

I suppose because CONFIG_ENUM_TEST_VALUE is a global const defined in config_enum_test.module, but the module file is not preloaded.

That is the test I added in #87 to show the issue regarding loading the module file. It hasn't been addressed yet in the MR

mondrake’s picture

Whops… ok.

mondrake’s picture

Is it really worth supporting global const defined in .module files as we speak? Could we not assume OOP consts only?

mikelutz’s picture

I'm not opposed to documenting that limitation and moving on without it. Alternatively, we could just load the module files prior to installation, same as we are now doing with the classloader. I didn't code up any solutions because I wanted some comments on whether we should worry about it at all. I mainly wanted to surface the issue, as we did the work on the classloader to ensure OOP constants and enums in a module's src folder were loaded and accessible during config install.

Also, to clarify for anyone reading this in the future, constants in .module files of active modules do work. The issue here is specifically happening when installing a module whose install config references a constant defined in the .module file. It's only during module install where a module's config files are loaded without the .module file being loaded.

sorlov’s picture

StatusFileSize
new25.3 KB

Rerolled patch to use with 10.4.x core

dpi’s picture

This issue might be suitable to also update \Drupal\Component\DependencyInjection\Container::getParameter to allow enum returns.

Method signatures

\Symfony\Component\DependencyInjection\ContainerInterface::getParameter

public function getParameter(string $name): array|bool|string|int|float|\UnitEnum|null;

\Drupal\Component\DependencyInjection\Container::getParameter

public function getParameter($name): array|bool|string|int|float|NULL {

--

And somewhat related, looking to address use of enums [and object instances] in parameters throwing fatal errors since autoloader isnt fully populated and unserialisation is attempted, at @ #3522410: Using instances of classes defined by modules in service container parameters causes fatal errors

mondrake’s picture

Title: Allow parsing and writing PHP constants and enums in YAML files » Allow parsing and writing PHP class constants and enums in YAML files
Issue summary: View changes
Status: Needs work » Needs review

#93 and #94 IMHO the effort to try supporting global constants in unloaded .module files is not worth doing at this point. So dropped it in the last commit.

Retitled and updated IS.

dcam made their first commit to this issue’s fork.

dcam’s picture

Based on recent comments it looks like this one is pretty close to being ready. I made a couple of suggestions to change the comments that are causing some of the recent concern.

mondrake’s picture

Applied suggestions, thanks.

dcam’s picture

Status: Needs review » Reviewed & tested by the community

I double-checked the feedback on the MR since this was last RTBC in #81 and it's all been addressed.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

It's a lovely present for 2026 that this issue is RTBC - but unfortunately I think we have to add some test coverage and resolve the @todo we're adding in the code.

longwave’s picture

Status: Needs work » Needs review

Added some review comments, but also converted the setValue() validation to a constraint including tests, and converted the Enum data type to use PrimitiveBase.

Disclaimer: some of the changes in the last commit were created by Google Gemini, then reviewed and tweaked by hand.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.

smustgrave’s picture

Appears to have some open threads? @alexpott thoughts on the test coverage added?

mondrake’s picture

Merged with main.

dcam’s picture

Status: Needs review » Needs work

The functionality of the test looks good. I had one comment on the implementation.

I'm mostly setting the status to Needs Work because of the unresolved comment from @longwave on core.services.yml.

borisson_ made their first commit to this issue’s fork.

borisson_’s picture

Issue tags: +DevDaysAthens2026

The test that is failing should now be green again (it is on my local machine), I've also fixed the remark from fabian in this issue.
We still need to look at the remark from @longwave.

borisson_’s picture

Status: Needs work » Needs review

I don't really agree with the request to name it back to the original names, to me this is a lot clearer. I think this is good to review.

borisson_’s picture

Added the deprecation for the class as well as the test for installing a module that has a reference to an Enum that is installed in a different module.
This test was generated by AI after @bircher and I wrote the prompt together at dev days yesterday.

The last comment, about the RecipeConfigStorage, I'm not sure about.

bircher’s picture

Nice!
I think if we install the two modules in a test also via a recipe we will know if the recipe system can deal with it too.

bircher’s picture

Status: Needs review » Reviewed & tested by the community

Ok, now I didn't find anything more to complain about I think I can give this a RTBC status again.

bircher’s picture

reviewed the last few commits again, and still RTBC

borisson_’s picture

Agreeing with @bircher, I looked at the last couple of commits as well, those look great.

longwave’s picture

Status: Reviewed & tested by the community » Needs work

Added some very small nits but this looks great so far!

alexpott’s picture

Status: Needs work » Reviewed & tested by the community

Fixed all the very small nits. As these were very small moving back to RTBC

needs-review-queue-bot’s picture

Status: Reviewed & tested by the community » Needs work
StatusFileSize
new851 bytes

The Needs Review Queue Bot tested this issue. It fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

longwave’s picture

Status: Needs work » Reviewed & tested by the community
catch’s picture

Status: Reviewed & tested by the community » Needs work

Couple of questions on the MR - mostly about code comments, but they're code comments about the trickiest part of this.

alexpott’s picture

Status: Needs work » Reviewed & tested by the community

Thanks for the review @catch. Given both were about comments setting back to rtbc... responded to both comments on the MR and added commentary for one of them.

quietone’s picture

I read both change records. The one about how to write constants and enum in yaml file is fine The one about FileStorageFactory I found hard to read. I reworded it but there is one sentence that is difficult. It is "Using the sync storage service ensures any configuration for modules or themes that are not installed will be able to use constants and enums from these modules". I am just too jet lagged to improve that one. Maybe someone else can do that. And a review of it to make sure that it is still correct would be good.

I have updated credit.