Problem/Motivation

As mentioned at #2852557: Config export key order is not predictable, use config schema to order keys for maps, config export ordering isn't predictable. \Drupal\filter\Entity\FilterFormat orders filters at \Drupal\filter\Entity\FilterFormat::filters() and \Drupal\filter\Entity\FilterFormat::preSave(), but those methods only update the order of filters inside of the FilterPluginCollection, and not the $filters property on FilterFormat. This happens because \Drupal\Core\Plugin\DefaultLazyPluginCollection::getConfiguration() preserves the original order so the sort in FilterFormat::preSave() does not work as expected.

This can lead to config that is not imported cleanly, and it's especially noticeable when moving config across sites or with config_split.

Steps to reproduce

Proposed resolution

Add an orderby to the filter format schema so that the sort in the configuration file is consistent.

Remaining tasks

User interface changes

None

API changes

None

Data model changes

Filter format filter configuration will be sorted by key. Note this does not affect the filter format filter plugin collection sorting at all.

When updating Drupal to a version with this change, the filter formats may be re-ordered in exported configuration YAML files but afterwards they will remain sorted consistently. (See commit cf2fd86fc for an example of such sort-order changes that may occur after a config export.)

Module and distribution maintainers should make sure their default configuration is sorted in order to minimize diffs when updating.

Release notes snippet

Filter formats are now consistently sorted. Exported filter format configuration may need re-exporting after updating, but afterwards they will remain consistent.

Issue fork drupal-3017054

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

deviantintegral created an issue. See original summary.

deviantintegral’s picture

Status: Active » Needs review
StatusFileSize
new953 bytes

Status: Needs review » Needs work

The last submitted patch, 2: 3017054-remove-filters-sort.patch, failed testing. View results

deviantintegral’s picture

The above isn't going to work because the filters() method is explicitly documented / expected to return an ordered list of filters. This may end up needing to be fixed by ensuring the saved config entity always has filters in the right order.

deviantintegral’s picture

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

This changes the approach to always sort filters by weight when returning them.

deviantintegral’s picture

Title: Remove filter format sorting to simplify config exports » Consistently sort filter formats to simplify config exports
Issue summary: View changes

Updated the issue summary to reflect change in approach.

Status: Needs review » Needs work

The last submitted patch, 5: 3017054-5-remove-filters-sort.patch, failed testing. View results

deviantintegral’s picture

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

This fixes assuming that all currently available filters are saved in the filter format, which isn't the case after installing a new module that provides a filter.

Status: Needs review » Needs work

The last submitted patch, 8: 3017054-7-remove-filters-sort.patch, failed testing. View results

deviantintegral’s picture

Status: Needs work » Needs review
StatusFileSize
new5.25 KB

Fixes failing tests, updates the default config filter formats to be sorted, and removes a stale comment about the entity filters property excluding disabled filters.

deviantintegral’s picture

StatusFileSize
new6.51 KB

It turns out we do need to ensure when saving the config entity. Also, we need an update hook to fix any existing stored formats.

Currently, filters are sorted by status, weight, and provider. Sorting by status first seems odd - it would mean that disabling a filter would cause it to be pushed to the bottom of the list, and it'd be easy to miss where it's supposed to be if you need to turn it back on. Also, if two filters have the same weight, I wouldn't expect a basic provider sort, but a sort based on the provider's module weight. I think just sorting by filter weight is clearer.

One other consideration is \Drupal\filter\Element\ProcessedText::preRenderText doesn't sort filters by weight at all. That could be a bug, but given how we force sorting with this patch I think it's OK to leave as is.

Status: Needs review » Needs work

The last submitted patch, 12: 3017054-12-remove-filters-sort.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

deviantintegral’s picture

Status: Needs work » Needs review
StatusFileSize
new57.65 KB

This fixes the order of filter formats in profiles/demo_umami/config/install/filter.format.basic_html.yml as well as the fixtures in tests/fixtures/config_install.

fls-pcate’s picture

This issue was throwing me for a loop as to why the filter configuration was always different on different env's. I applied the patch to 8.6.7 and it fixed the issue.

Status: Needs review » Needs work

The last submitted patch, 14: 3017054-14-force-filters-sort.patch, failed testing. View results

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.

deviantintegral’s picture

StatusFileSize
new148.72 KB

Reroll that resolves conflicts in the tar.gz files.

deviantintegral’s picture

Status: Needs work » Needs review
pcate’s picture

Just updated to 8.7 and patch #18 applied cleanly.

idebr’s picture

The issue #2852557: Config export key order is not predictable, use config schema to order keys for maps adds the ability to add a sorting key in the configuration schema. Filter configuration could be a good test case for the issue. It would also mean this patch is no longer required.

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.

mattwith’s picture

StatusFileSize
new73.04 KB

Re-roll for 8.8.x

Status: Needs review » Needs work

The last submitted patch, 23: 3017054-23-force-filters-sort.patch, failed testing. View results

mattwith’s picture

StatusFileSize
new74.69 KB

This fixes the order of filter formats in profiles/demo_umami/config/install/filter.format.full_html.yml.

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.

pcate’s picture

Looks like this needs a re-roll for 9.1.10.

percoction’s picture

StatusFileSize
new72.87 KB

Reroll attempt for new 9.1.10 release

percoction’s picture

StatusFileSize
new73.6 KB

Add missing updated file

longwave’s picture

+++ b/core/modules/filter/filter.install
@@ -0,0 +1,18 @@
+function filter_update_8101() {

I think this can be a post_update hook. If not, 8101 is not the right number as this will go into 9.3.x now.

ankithashetty’s picture

Status: Needs work » Needs review
StatusFileSize
new73.67 KB
new945 bytes

Updated the patch in #31 addressing the changes suggested in #32 i.e., moved the update_8101() hook in filter.install to post_update_Name hook in filter.post_update.php, thanks!

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.

hctom’s picture

Status: Needs review » Needs work

This seems to need a re-roll for 9.3.x/9.4.x because the patch does not apply anymore.

hctom’s picture

StatusFileSize
new10.89 KB

Here is a rerolled version of the patch for 9.3.x/9.4.x - WARNING: It does not contain the changes in the core/tests/fixtures/config_install/multilingual.tar.gz and core/tests/fixtures/config_install/testing_config_install.tar.gz files that were included in the older patches!

Those files were the cause for the problems applying the patches in 9.3.x - but unfortunately I do not have any idea what has to be done or what has been done in this issues that changed those files.

@deviantintegral: Maybe you can give me some insights, so I can rework the rerolled patch to contain those changes as well again (if really needed).

Therefore this patch is not listed in the files table for now!

deviantintegral’s picture

This is going a ways back, but I think what I did was extract those files, import them into a site, then re-export them to update config key ordering. Then, I recreated the tarballs and ran tests locally to check.

utcwebdev’s picture

Is this issue/patch obsolete, now that the underlying issue is addressed in 9.3?

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.

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

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now 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.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

bradjones1’s picture

Status: Needs work » Closed (outdated)

I think this is outdated now. There is a follow-up at #2855675: Add orderby key to all sequences in core that appears to address some lingering edge cases.

alexpott’s picture

Status: Closed (outdated) » Needs work

@bradjones1 I think this is still an issue - that filters are not consistently sorted. This issue is trying to fix the current sorting in implementation in the Filter system and the other one is a generic issue for all sequences in config. I think that filter sorts when operating on a filter format have to be by weight whereas in the config this is different.

I think this issue should leave filter plugin collection sorting alone as that does not feel like it should change. But what we could investigate here is disconnecting config sorting from the plugin sorting and using the orderby config schema capabilities.

wim leers’s picture

Priority: Normal » Major
Issue tags: +Configuration schema

Huge thread about this over at https://drupal.slack.com/archives/C01GWN3QYJD/p1694532185920599, 1 hour after #43 was posted!

Related: https://www.drupal.org/node/2852566

alexpott’s picture

Status: Needs work » Needs review

Hiding all the files as the MR is the way forward here.

alexpott’s picture

Issue summary: View changes

Applied the issue summary template.

alexpott’s picture

Issue summary: View changes

Finally worked out why this is actually occurring. It's because \Drupal\Core\Plugin\DefaultLazyPluginCollection::getConfiguration() preserves ordering so that \Drupal\filter\Entity\FilterFormat::preSave() sort just doesn't work as expected. This functionality was added in #2062367: Prevent PluginBags from reordering the export based on their sort.

I think sorting added in the MR is desirable. It'll mean less configuration change when re-ordering filter plugins and make it easier to see what is changing. This does point to an alternate fix by adding a flag to \Drupal\Core\Plugin\DefaultLazyPluginCollection::sort() to reset the \Drupal\Core\Plugin\DefaultLazyPluginCollection::$originalOrder to the new order.

alexpott’s picture

The alternate fix would result in the config order changing when the a plugin is enabled or disabled - which makes the diff really hard to read so I think the fix here is correct. The remaining question is what to do about the sorting in the preSave(). I think we can remove it as it is not doing what we want - I think we might want to ensure that the FilterCollection is re-initialised after saving.

alexpott’s picture

Okay well doing #49 reveals another bug in Filter formats - a different behaviour if the plugin collection is initialised on the entity and you call \Drupal\filter\FilterFormatInterface::setFilterConfig(). I think we should leave removing the sort in preSave() to a follow-up - #3392978: Inconsistent behaviour in \Drupal\filter\FilterFormatInterface::setFilterConfig()

bircher’s picture

Status: Needs review » Reviewed & tested by the community

This MR is basically just one line added in core/modules/filter/config/schema/filter.schema.yml: orderby: key:

in context:

    filters:
      type: sequence
      orderby: key
      label: 'Enabled filters'
      sequence:
        type: filter

This is very much the goal of #2855675: Add orderby key to all sequences in core! So I am very excited to see this green.
The rest of the MR is basically fixing the default to adhere to this, and is a taste of what kind of changes are to be expected on a site when the update hook runs. So the changes are sorting in config files, changes in test files to assert the correct order, an update hook and a test for it.
It all looks good to me and proves that #2855675: Add orderby key to all sequences in core may have to be a meta with many children.
Given that site builders will most likely see a diff in their config after this change (for the last time) I went ahead and created a change record so with that I think this has everything now and is RTBC.

jwilson3’s picture

The CR looks good, I left a little more context (mentioning explicitly config export YAMLs, and linking to the commit hash in the MR that shows an example of what kind of changes could be expected).

https://www.drupal.org/node/3393754/revisions/view/13267842/13268066

jwilson3’s picture

Issue summary: View changes

Updated IS with some of same indications from the CR.

wim leers’s picture

Status: Reviewed & tested by the community » Needs review

+1 for this, was just wondering why this is not using ConfigEntityUpdater?

AFAICT this should work fine:

function filter_post_update_sort_filters(&$sandbox = []) {
  $config_entity_updater = \Drupal::classResolver(ConfigEntityUpdater::class);
  $config_entity_updater->update($sandbox, 'filter_format', function (FilterFormat $format): bool {
    $sorted_filters = $filters = array_keys($format->get('filters'));
    sort($sorted_filters);
    return $sorted_filters !== $filters;
  });
}
alexpott’s picture

@Wim Leers yeah so I did this because ConfigEntityUpdater's save does not result in sorting because the data is "trusted". There is a tension here - see #3347842: Deprecate the trusted data concept in configuration and #2989256: Old post_update functions that ->save() config entities without calling ->trustData() first mask errors in other post_update functions.

Looking at #2989256: Old post_update functions that ->save() config entities without calling ->trustData() first mask errors in other post_update functions the update function I've written falls into this trap and uses the fact we're not trusting the data :) so we need to fix that.

I think even though we've got the orderBy thing in config schema we need to do the ordering on the entity so it will occur regardless of whether we trust the data. If we don't then anytime a config entity is saved with the trusted data flag set we'll end up changing the order. Fun.

borisson_’s picture

Status: Needs review » Reviewed & tested by the community

Back to rtbc, the discussion at drupalcon we had about the trusting data and why this can't use the config Updater suggested by Wim makes sense to me.

alexpott’s picture

@borisson_ funnily enough now the update does use ConfigEntityUpdater because we work out that due to trusted data we need to sort in the preSave the correct way.

recrit’s picture

Attached is a patch for anyone looking for this fix on 10.1.x.

recrit’s picture

wim leers’s picture

Following those issues now 👍 —thanks for the links, @alexpott in #55 🤓

Agreed with RTBC. This is a clear improvement, and should not be blocked on solving #3347842: Deprecate the trusted data concept in configuration.

(In fact, the current solution reminds me about @catch's repeated recommendations/requests to not write update/post-update hooks, but instead make config changes in presave hooks. This is very similar to that. (See #3393557-20: [upstream] Update CKEditor 5 to 40.0.0 + #3393557: [upstream] Update CKEditor 5 to 40.0.0.)

longwave’s picture

Version: 11.x-dev » 10.2.x-dev
Issue summary: View changes
Status: Reviewed & tested by the community » Fixed
Issue tags: +10.2.0 release notes

Nice to see this finally fixed. Adding a release note snippet because this might affect config exports after sites have upgraded.

Committed and pushed 5f533ca660 to 11.x and fee08681da to 10.2.x. Thanks!

Also published the change record and tweaked it slightly.

  • longwave committed fee08681 on 10.2.x
    Issue #3017054 by alexpott, deviantintegral, percoction, mattwith,...

  • longwave committed 5f533ca6 on 11.x
    Issue #3017054 by alexpott, deviantintegral, percoction, mattwith,...

Status: Fixed » Closed (fixed)

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