Problem/Motivation
When removing a field from a content type that has layout builder enabled, the field removal will actually trigger an update of a ROLE that uses a layout builder permission. The end result is that a field gets removed, and then users of that role can no longer edit a page through layout builder, b/c the permission has been removed.
It appears that this issue (based on below tests) is present based on the name of the module that contains the media source plugin.
There are two branches below, both with the EXACT SAME test scenario in them, just with a different module name. The branch with the module named "a" passes as expected, but the branch with the module named "z" fails.
Steps to reproduce
This has been a VERY difficult bug to track down. Please review the test which I think presents a very simple display of what's happening. From what I can tell, one of the PRIMARY drivers of this behavior is that one field on the content type must use a custom media type. In my own project, when I use a CORE "image" media type, I don't have the problem, but when I use a custom media type in one of the fields, I am encountering the problem.
Unfortunately, there's not great steps to reproduce this issue b/c you have to be working in code. I'll try to outline what I did as best as I can, but you need a module that's providing a MEDIA SOURCE plugin to have an alphabetically significant ("a" vs "z") name. That's not something you can do in the UI.
Proposed resolution
See #9
The use of entity storage "loadMultiple()" in findConfigEntityDependenciesAsEntities() can break the order that dependencies need to be processed in on a config entity removal. findConfigEntityDependenciesAsEntities() should be updated to return the dependencies in the same order it receives them from findConfigEntityDependencies()
I don't have any idea what a proposed resolution is here. I think there's a problem in the Graph.php building, which has proven a little more complex than I'm able to debug through. I'm unsure why the custom media type is causing the order of the discovered dependencies to be ordered in a way where the role gets processed before the entity_view_display, and the role deletes the permission. If the entity_view_display gets processed first, the role will be dropped from the dependencies, and then it's not affected.
Remaining tasks
??
User interface changes
N/A I believe.
Introduced terminology
N/A
API changes
N/A
Data model changes
N/A
Release notes snippet
N/A
| Comment | File | Size | Author |
|---|---|---|---|
| #19 | 3504368-nr-bot.txt | 2.12 KB | needs-review-queue-bot |
Issue fork drupal-3504368
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
Comment #3
dpagini commentedUgh. Pointed out by @godotislate on Slack that my permission name is wrong in my test. I need to revisit and see how I can reproduce my problem with a test. =/
Comment #4
quietone commentedChanges are made on on 11.x (our main development branch) first, and are then back ported as needed according to the Core change policies.
Comment #6
dpagini commentedAlright, I think I have figured out a way to demonstrate this...
I have put up two scenarios. In both branches, I have a content type w/ layout builder, a user role, and a field that references a media item. The scenario that I'm trying to prove is that when I delete a field, my user role is getting it's layout builder permission stripped from the role. I have one branch where this scenario passes, and in that case, the module that provides the media source plugin is named "a". In the same exact scenario, I can cause a failure by naming my module "z" instead. I think it's not likely to be controversial to say that the name of the module should not have this much affect on how these dependencies are getting processed...?
Now that I'm a little more confident that this is a core bug, I want to flirt with marking this as "MAJOR" b/c it really is unsuspected data loss that's occurring. I have to imagine that if there's a problem with how the dependency graph is built, that this could affect other unknown areas as well...?
Sorry, I was just trying to show a failing test where I know it's failing (10.4.x). I'm guessing this is also present in 11.x, but haven't made it that far yet.
Comment #9
godotislateInvestigated this a little, and one thing that's happening is that when the config dependencies are being determined, in the erroneous state, the order of the dependencies returned from
Drupal\Core\Config\ConfigManager::findConfigEntityDependencies()looks some thing like this:And when it behaves correctly, the order is like this:
I haven't determined yet why this is happening, but for this specific case, the different ordering should be fine. The test role permission only has a dependency on the full entity display, and not the default one. So when
ConfigManager::getConfigEntitiesToChangeOnDependencyRemovalacts on the list of of dependencies, it starts with the end of the list, and as long as the full entity display is processed before the role, everything should be fine.The problem is that the list from
findConfigEntityDependencies()is returned tofindConfigEntityDependenciesAsEntities(), where entities are loaded from the list of config names. For efficiency, entities of the same type are loaded in oneloadMultiple()operation instead of separate loads, and the order of the list returned becomes:With this ordering, the role is processed before the full entity view display and is erroneously handled to remove the permission.
I have put up MR 11141 with a fix for
findConfigEntityDependenciesAsEntities(), to make sure the loaded entities stay in the order of the dependency config names. The tests in MR 11120 need to be updated for 11.x, but there were some issues with the config provided by the test modules that needs resolving, then the test can be added to the MR with the fix. Leaving this at Needs Work.Comment #10
godotislateOne thing I have discovered is that
Drupal\Core\Config\ConfigManager::findConfigEntityDependencies()with the same parameters is not idempotent for the order of the dependencies.This occurs because when the ConfigDependencyManager is instantiated in
getConfigDependencyManager(), the order of config loaded the config factory can vary depending on how much config objects are loaded from the static cache vs database storage. On the first call toConfigFactory::loadMultiple(), it's possible that only a partial list of config objects were loaded into the static cache, with the remainder needing to be loaded from database storage. On the subsequent calls, all the config objects may already be loaded in the static cache, so the returned order can be different from the first call.The order the config data is loaded set at ConfigDependencyManager instantiations ultimately affects the sorted order of the dependencies. Trying to fix this by sorting the list of config objects does seem to make
findConfigEntityDependencies()idempotent, but this breaks an existing test atDrupal\KernelTests\Core\Config\ConfigDependencyTest::testConfigEntityUninstallComplex().I'm not sure the results need to be idempotent, either. As long as the order returned by
findConfigEntityDependencies()has the correct relative order between dependencies, the overall order probably doesn't need to be consisitent. Meaning, if list of returned dependencies includes a config object (config 1) that depends on another (config 2) within the list, then as long as config 1 comes before config 2 in the list, this should be fine, for all listed dependencies. Investigating further whether true idempotency is required might be out of scope for this issue.I've added a Kernel test to MR 11141 that creates a similar scenario with permissions being removed incorrectly, that demonstrates how the relative order can be broken per comment #9 when config entities are loaded.
Producing in browser reproduction steps has proven difficult, so the issue mgith be best be observed by the failing test-only job.
Comment #11
smustgrave commentedCould the solution suggestion be flushed out a bit?
Comment #12
godotislateProposed resolution updated.
Comment #15
smustgrave commentedClosed the older MRs to make it more clear
Test-only feature
If showing coverage
Don't see any open threads.
Believe this could be ready but not as familiar so will give +1 but leave in review for others to also chime in.
Comment #16
smustgrave commentedGoing to take a swing and go ahead and mark it. If too soon apologize!
Comment #17
godotislateNote that in MR 11141, the test does not address Layout Builder permissions and field configuration specifically, but does generic config entity dependency order in a similar fashion. I had difficulty recreating the previous test MR that was against 10.4.x to 11.x, and a kernel test is more efficient than a functional test.
Comment #18
dpagini commentedJust going to add my $0.02 here as the OP... I pulled in the patch for MR 11141, and it's fixing the original problem I had. So I definitely 2nd this for RTBC status to get some core maintainer eyes on this issue.
I definitely don't think we need to have the layout_builder use case as a test for this, that was just the best way that I could come up with to demonstrate exactly how this bug was affecting my project. Just want to give a huge thanks for @godotislate & @smustgrave for kind of taking this bug report and running with it.
Comment #19
needs-review-queue-bot commentedThe 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.
Comment #20
godotislateRebased and removed the unused variable flagged by the nr-bot.
Comment #21
godotislateComment #22
smustgrave commentedRebase seems fine.
Comment #23
catchOne question on the MR - either an easy fix or an easy 'no it's not possible'.
Comment #24
godotislateUpdated per MR review.
Comment #25
smustgrave commentedFeedback appears to be addressed for this one.
Comment #29
catchSorry this took a while to get back to, just sheer volume in the RTBC queue at the moment ,meaning I didn't spot it was back at RTBC.
Committed/pushed to 11.x, 11.1.x, and 10.5.x thanks!