Problem/Motivation

#2361539: Config export key order is not predictable for sequences, add orderby property to config schema introduced predictable sequence ordering. It introduced orderby: value and orderby: key. But quite a few things in core and contrib depend on "source order": where the stored order actually has meaning. This was overlooked. Therefore those cases are left with an unclear upgrade path.

Relevant comments lifted from #2361539, which is closed:

  • Wim Leers:

    Actually, there is an important question that is not answered by the CR or the IS, at least not AFAICT. Quoting #2874633-5: [PP-1] Update CDN module for Drupal 8.4.x: 'orderby' in config schema for sequences:

    +++ b/config/schema/cdn.mapping.schema.yml
    @@ -27,6 +27,7 @@ cdn.mapping.auto-balanced:
    +      orderby: value
    
    @@ -43,6 +44,7 @@ cdn.mapping.complex:
    +      orderby: value
    

    Actually, these should not be sorted/ordered… the order does matter in this case, and it cannot be ordered by key (there isn't any). In fact, the key is numerical, hence indicating the order already.

    So these should be key, not value. I think that that must be the general rule for non-associative arrays where the order matters?

    Reopening this issue to get an answer to that question documented in the CR, because more modules will struggle with that.

  • Alex Pott:

    @Wim Leers hmmm this is a good question. Actually in this instance the best practice is to have a weight key and sort by something that does not change. This means that if things are re-ordered when you review the config change the only thing you have to review is the weight key changes. However maybe we need to add "in the order added" type of "sort" so at least the current behaviour of cdn could be documented and we could document that this is bad practice and recommend ways of fixing it.

  • Wim Leers;

    However maybe we need to add "in the order added" type of "sort" so at least the current behaviour of cdn could be documented and we could document that this is bad practice and recommend ways of fixing it.

    +1 to both of those.

  • Wim Leers:

    By the way, an example of exactly the same problem/requirement can be found in ckeditor.schema.yml: the Toolbar configuration mapping contains a sequence of rows, which contains a sequence of buttons groups, which contains a sequence of buttons. None of them have "weight" or "priority"; the order is relevant there, too.

    So this is not a problem that's exclusive to contrib. And probably there are even more like these in other places in core.

Proposed resolution

TBD

Remaining tasks

TBD

User interface changes

None.

API changes

TBD

Data model changes

TBD

Issue fork drupal-2885368

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

Wim Leers created an issue. See original summary.

dawehner’s picture

I would always recommend that code to have a priority in their values, as this makes it way more explicit.

On the other hand you are absolutely right, order matters in sequences:

Unlike a set, order matters, and exactly the same elements can appear multiple times at different positions in the sequence

.

wim leers’s picture

Yep. I was thinking the same thing when I wrote this IS this morning: #2361539: Config export key order is not predictable for sequences, add orderby property to config schema effectively changed sequences to sets (for orderedby: key, because there can't be multiple keys) and alphabetical sequences (for orderedby: value.

wim leers’s picture

Priority: Major » Critical

I think we should consider elevating this to critical because if it doesn't get sorted out, 8.4.0 will effectively be causing a sort-of-BC-break and sort-of-regression…

wim leers’s picture

Issue tags: +8.4.0 release notes

At this stage, it looks like #2361539: Config export key order is not predictable for sequences, add orderby property to config schema will not be reverted, and this is not getting resolved before 8.4.0, which means this newly introduced ambiguity in config schema semantics will have to be mentioned in the release notes to warn contrib/custom module authors.

catch’s picture

Is there anything missing from the change record at https://www.drupal.org/node/2852566 that would help to explain this issue better?

I've just tagged #2361539: Config export key order is not predictable for sequences, add orderby property to config schema for a release notes mention.

I don't see this as an API change, it's a change in behaviour for something that was never previously defined, so just documenting it seems fine.

dawehner’s picture

The question I would like to ask here: did we really guaranteed the order before? I remember having quite some issues with that in views. We ended up switching to using weights instead. I'm curious why you never ran into those ordering problems before.

wim leers’s picture

The CR says

It is strongly recommended to add preferred sorting to avoid confusing diffs in configuration and even potential data integrity problems. Drupal core configuration schemas will be updated with default sorting for sequences in a future release.

There are at least three problems here:

  1. This deals with cases where the "sequence" actually is a set. No mention of the case where the sequences already are in fact … sequences.
  2. It paints a picture where it will be required to have this orderby key, or else!
  3. It says core config schemas will be updated, but in fact, for at least editor.settings.ckeditor.toolbar.*, it will be impossible to add orderby, because it's actually using sequences for what they were intended.

IOW: those cases where sequences were used as intended actually are left in an ambiguous place.

wim leers’s picture

I just realized something: I think it'd have been better to add a type: set that extends type: sequence, adding orderby: key|value. #2361539: Config export key order is not predictable for sequences, add orderby property to config schema didn't clear up semantics, it just made it more confusing :( (Despite all good intentions obviously!)

dawehner’s picture

Reading the typed data definition:

 From the typed
 * data API perspective sequences are handled as ordered mappings without
 * metadata about existing properties.

this really makes it clear, that its not an unorded hashmap, like many other languages use by default.

Here is a question though: They code which does the sorting:

      if ($element instanceof Sequence) {
        $data_definition = $element->getDataDefinition();
        if ($data_definition instanceof SequenceDataDefinition) {
          // Apply any sorting defined on the schema.
          switch ($data_definition->getOrderBy()) {
            case 'key':
              ksort($value);
              break;

            case 'value':
              // The PHP documentation notes that "Be careful when sorting
              // arrays with mixed types values because sort() can produce
              // unpredictable results". There is no risk here because
              // \Drupal\Core\Config\StorableConfigBase::castValue() has
              // already cast all values to the same type using the
              // configuration schema.
              sort($value);
              break;

          }
        }

and

   public function getOrderBy() {
    return isset($this->definition['orderby']) ? $this->definition['orderby'] : NULL;
  }

don't imply any kind of sorting by default. Am I missing something obvious?

Version: 8.4.x-dev » 8.5.x-dev

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

dawehner’s picture

Status: Active » Needs review
StatusFileSize
new3.24 KB

While my question in #10 is still outstanding, I think having an explicit way to enforce no sorting is helpful

xjm’s picture

Category: Bug report » Task
Priority: Critical » Major
Issue tags: +Needs change record updates

@cottser, @cilefen, @effulgentsia, and I discussed this issue and agreed it is not critical and also not really a bug. There is no regression; core does not yet specify orderby everywhere -- #2855675: Add orderby key to all sequences in core has not had any activity at all -- and there is no hard requirement currently that orderby should be set.

When a specific ordering other than key or value is needed, it's currently the responsibility of the implementation to enforce that order on save or to add (e.g.) a weight that is independent of the configuration storage. I was going to state that the CR at https://www.drupal.org/node/2852566 indicated this, but it looks like that got omitted somehow. So, I think we should update the change record there with that information and maybe (as @effulgentsia suggested) an example of how an implementation might enforce custom ordering.

We also have this other followup still open: #2856336: Add docs for the new orderby key for sequences in configuration schema

As for the scope of this issue, it's really a request for an API addition. However, I'm not convinced that the current patch is the right approach. Arbitrary "insert order" is not something we should be encouraging because that could vary from one update to the next and create meaningless diffs and compromise the data integrity, which is what #2361539: Config export key order is not predictable for sequences, add orderby property to config schema tries to address in the first place. The fact is that arbitrary ordering has led to lots of data integrity issues in the past so we should encourage developers to rethink why they want this "insert" order in the first place.

dawehner’s picture

We could go the go route which means that unless specified, iterating over a map happens in random order, so you cannot rely on it. In this case we would enforce that contrib/custom code sorts by some parameter ... which might be quite hard, but at least it prevents any other possible future bugs.

xjm’s picture

Well, that would guarantee a config export diff on every single export, which is the kind of thing we're trying to avoid. :) Also that carries its own set of problems for us: #2571183: Deprecate random() usage in tests to avoid random test failures.

I think we can maybe go the route of deprecating the null sort order and add an example of how to implement one's own sort.

dawehner’s picture

Well, that would guarantee a config export diff on every single export, which is the kind of thing we're trying to avoid. :)

I think I was suggesting somehow a read only behaviour.

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

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

wim leers’s picture

Triaging the CDN issue queue made me look at #2874633 again, which made me look at this again.


there is no hard requirement currently that orderby should be set.

  1. I was under the impression that setting orderby is considered a best practice. I want my modules to follow every best practice possible. But it doesn't apply to/work for my use case, and it's not the only example! See #8.
  2. "currently" — if it ever is required, then this will become an important bug.

Arbitrary "insert order" is not something we should be encouraging because that could vary from one update to the next

This is not "arbitrary" insert order. This is intentional insert order. The order has meaning. I already gave examples in the IS/in #8. So order changes in config diffs do have meaning in those cases.

The fact is that arbitrary ordering has led to lots of data integrity issues in the past so we should encourage developers to rethink why they want this "insert" order in the first place.

I'd wholeheartedly support this, if it weren't for the fact that this also needlessly complicates a common use case. For example, from editor config:

settings:
  toolbar:
    rows:
      -
        -
          name: Formatting
          items:
            - Bold
            - Italic
        -
          name: Linking
          items:
            - DrupalLink
            - DrupalUnlink

would need to become the much more verbose:

settings:
  toolbar:
    rows:
      -
        weight: 0
        items:
        -
          name: Formatting
          weight: 0
          items:
            -
              button: Bold
              weight: 0
            -
              button: Italic
              weight: 1
        -
          name: Linking
          weight: 1
          items:
            -
              button: DrupalLink
              weight: 0
            -
              button: DrupalUnlink
              weight: 1

and then we'd be able to use orderby: key (but only because we're exploiting that it'd do increasing alphanumerical sorting, it'd be just as valid to do decreasing, it would still ensure consistent config exports, but it'd break the interpretation of the config!). What did we gain there? I'd argue nothing.

Again, this is because https://www.drupal.org/node/2852566 and https://www.drupal.org/project/drupal/issues/2361539 only concerned themselves with "sequences that are sets" — either sets where each set item is identified by value (orderby: value) or a set where each value is identified by key (orderby: key). The "sequences that are lists" use case seems to have been forgotten.

If we'd change the CR from

It is strongly recommended to add preferred sorting to avoid confusing diffs in configuration and even potential data integrity problems. Drupal core configuration schemas will be updated with default sorting for sequences in a future release.

to

It is strongly recommended to add preferred sorting to sequences that behave as sets rather than lists to avoid confusing diffs in configuration and even potential data integrity problems. Drupal core configuration schemas for set sequences will be updated with default sorting for sequences in a future release.

Then we could close this issue.

wim leers’s picture

We already have type: sequence with an optional orderby in two minor releases now (8.4 and 8.5). We can't change that anymore.

To improve the situation, we could:

  • add type: set which requires an export_order_by
  • add type: list for the use case that I've been explaining above
  • deprecate type: sequence ("sequence" implies order matters, but that's not the case in practice)

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.

amber himes matz’s picture

Title: Config export key order for sequences: "orderedby" does not support cases where the order actually matters » Config export key order for sequences: "orderby" does not support cases where the order actually matters
Issue summary: View changes

Updated title and issue description with correct key name (was 'orderedby'; corrected to 'orderby').

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.

quietone’s picture

Updating tag

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.

wim leers’s picture

I think perhaps the existing orderby: ~ would be sufficient, although this seems it would improve clarity?

bircher’s picture

I think we should make it more explicit and call it
orderby: none.

because it is not a default order, it is the absence of sortability.
This would be already much better, because then we know where the sorting is explicitly not wanted or where it is not yet defined.

Clarifying a bit: if we add none as an option then we could do sorting by default by key if keys are non numeric and value if keys are integers in Drupal 11

wim leers’s picture

#32++

Clarifying a bit: if we add none as an option then we could do sorting by default by key if keys are non numeric and value if keys are integers in Drupal 11

💯 — love this plan! Not sure if key or value make more sense as the default (the problem is IMHO that sequence both allows keyed and keyless sequences…), but not having none be the default absolutely makes sense! It'll most certainly lead to a better config management experience.

bircher’s picture

given the isdues could be more sorted and organised, the plan is basically to add more options for orderby.
The core extensions need values_then_keys, others need weight yet others will need some more complex algorithm. I wanted to make it so one could add a php callback, but the wise alexpott remembered that this would make it impossible for external systems to manipulate the config.

So part of the challenge is to assess what sorting algorithms we need. And none could be an option. Then "consumers" of this schema information like Config Split can just treat unsortable config as a blob and not do anything with it.
The default could then be the most complex one which tries to be smart and detect all sorts of possible sorting options at the price of performance.

wim leers’s picture

The default could then be the most complex one which tries to be smart and detect all sorts of possible sorting options at the price of performance.

I'd rather not have such magic for something as fundamental as this. 🙈 Explicitness is preferred?

bircher’s picture

well yes of course!
The default could also be value if the keys are integers and key otherwise.
The goal should be that core defines orderby for all its sequences.

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new132 bytes

The Needs Review Queue Bot tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.

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

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.

damienmckenna’s picture

This keeps coming up with so many projects, it's annoying to still deal with lines changing their ordering in config exports. I opened #3489389: Sort config alphabetically if no orderby defined as an alternative to this, because there should be a simply, predictable default to this, instead of having to manually specify it every time (as some have suggested here).

xjm credited cilefen.

xjm credited effulgentsia.

xjm credited star-szr.

xjm’s picture

Crediting for triage as per #13.

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

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.