Problem/Motivation
As decided in #2745619: [policy, no patch] Which core entities get revisions?, custom menu links should be converted to be revisionable.
The main use case that the Workflow Initiative proposed for this change is site-wide previews of not yet published content (nodes, media items, taxonomy terms, menu links, etc.), through the Workspaces module.
Note that revision support for the menu hierarchy will not been added in this issue, and it is being discussed in #3035089: Menu link hierarchy should be revision-aware.
Proposed resolution
Convert custom menu links to be revisionable using the new API introduced in #2984782: Add an API for converting entity type schemas to (non-)revisionable/(non-)translatable, with or without data.
Remaining tasks
Review/commit/celebrate.
User interface changes
None yet, revision support is only enabled at the API level.
API changes
API additions:
\Drupal\menu_link_content\Entity\MenuLinkContentnow extends the\Drupal\Core\Entity\EditorialContentEntityBasebase entity class- The
\Drupal\menu_link_content\Entity\MenuLinkContententity type has a new entity-level constraint (MenuTreeHierarchy) which prevents theparentandweightfields from being updated when creating a pending revision \Drupal\menu_link_content\MenuLinkContentInterfacenow implements\Drupal\Core\Entity\RevisionLogInterface
Data model changes
Custom menu links are now revisionable.
Release notes snippet
Custom menu links are now revisionable, which allows them to take part in editorial workflows like other first-class entity types in core, for example Content, Media items and Custom blocks.
| Comment | File | Size | Author |
|---|---|---|---|
| #64 | interdiff-64.txt | 6.77 KB | amateescu |
| #64 | 2880152-64.patch | 43.09 KB | amateescu |
| #62 | interdiff-62.txt | 4.53 KB | amateescu |
| #62 | 2880152-62.patch | 43.46 KB | amateescu |
| #61 | drupal_8x_dev.sql_.gz | 7.17 MB | plach |
Comments
Comment #2
amateescu commentedThis depends on #2346019: Handle initial values when creating a new field storage definition, #2854732: Use initial values for content translation metadata fields and fix existing data and #2860654: Field storage CRUD operations must use the last installed entity type and field storage definitions.
Comment #4
amateescu commentedThis should fix most of the fails.
Drupal\system\Tests\Update\UpdatePathWithBrokenRoutingFilledTestis a bit weird and I don't really understand what it does, so I'm going to ask @dawehner for some help with that one.Comment #5
amateescu commentedAnd the interdiff.
Comment #7
timmillwoodLooks like this just depends on one issue now, #2860654: Field storage CRUD operations must use the last installed entity type and field storage definitions, which is RTBC.
If we can get this ready maybe it can get in 8.4.0 too?
Comment #8
timmillwoodIt looks as though the patch in #4 still applies, so queuing a test for it.
Comment #10
amateescu commentedThis patch is not ready for the testbot until the other one gets in, that's why I didn't queue any test run so far.
Comment #11
amateescu commentedThe blocker is in! Let's see how a fresh patch is doing here :)
Comment #12
timmillwoodComment #14
amateescu commentedThis fixes the REST fails but I still need some help with #4, let's try asking @dawehner :)
Comment #16
wim leersSee #2880154-11: Convert comments to be revisionable.
This is technically a BC break for API-First… I'll let core committers decide here.
Comment #17
dawehnerI'll try to help out with #4 tonight.
Comment #19
volegerMenu Link Content has a bug with current base field definitions.
Comment #21
amateescu commentedRerolled the latest patch and made a few improvements based on all the reviews from #2880149: Convert taxonomy terms to be revisionable.
I'm pretty sure we still need @dawehner's help for #4 :)
Comment #23
amateescu commentedThis fixes
MenuLinkContentDeleteTest, will still fail so not sending this one to the testbot.Comment #24
amateescu commentedI've split the "publishable" part to a separate issue: #2981915: Update MenuLinkContent to use EntityPublishedInterface
Comment #25
amateescu commentedRebased the patch on top of #2981915-2: Update MenuLinkContent to use EntityPublishedInterface, still not ready for the testbot.
Comment #26
catch#2981915: Update MenuLinkContent to use EntityPublishedInterface is in.
Comment #27
berdirWould have belonged more in the other issue, but it's not something to solve for either, just mentioning as related for now.
The weird thing about this one, for historical reasons, is that it's called enabled and not status.
The problem is that content_translation additional field logic predates having a status/published entity key, and as a result, it hardcodes the field name to status, what it does is use that if it exists and if not, then it creates it own. So you have a then a translation status and an enabled key, and neither works as expected for menu links (It's not possible to have an unpublished menu link for a specific translation, as enabled is not translatble and nothing looks at translation_status when it matters). Afaik the menu system actually can't handle a status that varies per language at all.
So basically, if we'd decide to "fix" content_translation to look at the published key instead of hardcoding a field named "status", then things would break in interesting ways..
Comment #29
amateescu commented@Berdir, I was also thinking about that problem at some point, but I was lazy so thanks for writing it down :) I opened #3005398: Content Translation should use EntityPublishedInterface or the 'published' entity key to determine if it needs to add its 'content_translation_status' field and #3005400: The menu system can't handle the publishing status of a menu link that varies per language so we have some actionable issues at least.
In the meantime, updated the patch to use the entity schema update API from #2984782-19: Add an API for converting entity type schemas to (non-)revisionable/(non-)translatable, with or without data. Leaving at NW because I'm pretty sure the test fail from #14 is still there. Ping @dawehner :P
Comment #30
amateescu commentedSpent some time looking into this test fail and I finally understood what's going on: the conditional exception thrown by
\Drupal\update_script_test\PathProcessor\BrokenInboundPathProcessor::processInbound()makes all save operations on amenu_link_contententity fail, and the only reason why the upgrade path we're adding in this patch appears to fail is simply because it's the first post_update function which saves amenu_link_contententity, when tested with a filled db dump :)Then I went digging into the history of
UpdatePathWithBrokenRoutingTestwhich was introduced in #2550601: Move update.php to a more acceptable location (note that it's not using the filled db dump), and the purpose of the test is pretty clear: check that database updates can be executed throughupdate.phpeven when Drupal's router is in a "broken" state.Now, the problematic test class (
UpdatePathWithBrokenRoutingFilledTest, note the "filled" part) was introduced in #2551341: Update test database dump should be based on beta 12 and contain content for no obvious reason.\Drupal\update_script_test\PathProcessor\BrokenInboundPathProcessor::processInbound()does not act differently based on whether there is some content or not in the database.So the only conclusion that I can come up with is that
UpdatePathWithBrokenRoutingFilledTestdoes not serve any real purpose and can be removed :)Comment #31
blazey commentedHere's the patch from #31 re-rolled on top of #2984782: Add an API for converting entity type schemas to (non-)revisionable/(non-)translatable, with or without data (#29). The for-review part hasn't changed.
Comment #32
amateescu commentedUpdated the patch for the changes in #2984782-39: Add an API for converting entity type schemas to (non-)revisionable/(non-)translatable, with or without data. Also, since we're not invoking hooks anymore during the conversion process, we can use a regular update function!
Comment #33
amateescu commentedRerolled the combined patch, the for review one is the same as #32.
Comment #36
amateescu commentedIt turns out that #32 was not entirely correct because updating an entity type invokes events, and that's also something that we can't do in regular update functions.
This patch reverts the interdiff from #32 and applies properly on top of #2984782-42: Add an API for converting entity type schemas to (non-)revisionable/(non-)translatable, with or without data.
Comment #38
amateescu commentedRerolled the combined patch to include the latest fixes from #2984782-45: Add an API for converting entity type schemas to (non-)revisionable/(non-)translatable, with or without data. The for review one from #36 doesn't need any change.
Comment #39
amateescu commented#2880152: Convert custom menu links to be revisionable is in! Re-uploading the for-review patch from #36.
Comment #40
cosmicdreams commentedYou meant #2984782: Add an API for converting entity type schemas to (non-)revisionable/(non-)translatable, with or without data right? You referenced this issue.
Comment #41
amateescu commented@cosmicdreams, oops, yes, that's what I meant :)
Brought this patch inline with the UI and functionality provided for taxonomy terms in #2880149: Convert taxonomy terms to be revisionable.
Comment #43
amateescu commentedLet's not change any UI strings if not strictly needed.
Comment #44
amateescu commentedUntil now, this patch has been an exact copy of the one for taxonomy terms, but, after doing some manual testing, I think we shouldn't enable Content Moderation support for custom menu links because they don't have a standalone "view" page, which means that the 'latest revision' tab added by Content Moderation looks very confusing.
Fixed a couple of things and added test coverage for the constraint and for making sure that the menu tree is not updated when a pending revision is saved.
Comment #45
amateescu commentedThe patch from #44 was generated from a stale branch. Rerolled it using the patch from #43 and the interdiff from #44.
Comment #46
vijaycs85Looks good +1 to RTBC. Here is the detailed summary:
Case 1:
1. Applied patch in #45 locally on an existing 8.7.x site.
2.
drush updbshows the post_update and performs without any error.3. Created new menu item (under footer menu) and works as usual.
Case 2:
1. Applied patch in #45 locally and installed a 8.7.x site.
2. Created/Updated/deleted a menu item (under footer menu) and works as usual.
3. Editing system provided default item works and no impact on the menu_link_data_* tables as expected.
nitpick: too many spaces.
Note: Few notes if anyone else manually testing (thanks @amateescu for the clarification on slack)
- As it's just API (no UI) change, we can't make a "new revision". Meaning any update to a menu item would be updated to revision id=1 (see menu_link_content_revision and menu_link_content_field_revision compare to node_revision and node_field_revision)
- Checking unpublished revision constraints (e.g. no drag and drop) is not possible via UI.
Comment #47
amateescu commentedThanks for the review, @vijaycs85!
Regarding that nitpick, the extra spaces are there to point out that the
@seetag is part of the@todoabove. With the extra spaces, IDEs like PHPStorm will highlight the @see in the same color as the @todo, which is usually different than the color for regular comments. We also have other examples of this pattern in core if you search for// @see:)Comment #48
vijaycs85Cool.
Comment #49
larowlancan you elaborate on why this change is needed?
any reason why we dropped this?
would be good to see the EXPLAIN output on this query
what if one has no parent, but the new one now does? shouldn't that trigger the message too? if so, missing tests for that too.
can we assert before running the updates the state we expect the test fixture to initialize the site in to guard against accidental updates to the fixture that contain the revision support.
should we use the new current user trait here ?
This menu form is for one menu, yet we prevent table drag if there are any menu links with pending revisions (ie. we don't filter this by menu).
That feels wrong, and probably indicates missing test coverage?
We definitely should be filtering to the menu being edited in my book.
Otherwise you get the message, but have no idea which link is pending because its in a different menu.
should this use BEM --pending-revision instead of -pending-revision?
any reason for removing this?
same here - can we use the new current user trait?
Comment #50
amateescu commentedThanks for the great review!
\Drupal\Core\Entity\ContentEntityStorageBase::doSave()returnFALSEwhen saving a pending revision (https://cgit.drupalcode.org/drupal/tree/core/lib/Drupal/Core/Entity/Cont...), so a content entity form can not rely on its return value for checking whether the save was successful. Instead, an exception is triggered by the storage.Comment #51
larowlanwe're still not filtering by menu here?
Comment #52
amateescu commentedWe can't, it's the same story as the one for taxonomy terms :)
Comment #54
amateescu commentedRandom fail in
CKEditorIntegrationTest::testDrupalImageCaptionDialog, queued a re-test.Comment #56
plachLiar :D
Can we also assert that changing either of the two triggers the same validation error?
$child_1seems unused.Comment #58
plach.
Comment #59
amateescu commentedThanks for the review!
Re #56:
Comment #60
plachThis still needs a CR and release note snippets. Additionally the IS should mention the plan to make the hierarchy revisionable.
Comment #61
plachI manually tested this by manually restoring Content Moderation support (git hash
2c166a50a611b06d85c8d8ae482c6a76a196a4c6+ #59) and it doesn't seem to work properly in a few scenarios:You can only change the hierarchy for the published version of this menu link.validation error even if I didn't touch the parent or weight fields.Notice: Undefined index: weight in Drupal\menu_ui\MenuForm->submitOverviewForm() (line 515 of core/modules/menu_ui/src/MenuForm.php).I'm attaching the test DB dump in case it helps reproducing the issues.
Comment #62
amateescu commentedThanks for the additional review, fixed both points :) Explicit test coverage for the first item will be added in #3039031: FieldItemList::equals() should filter out the empty items before checking their count.
Added a CR (https://www.drupal.org/node/3039034), updated the IS and included a release note snippet.
Comment #63
plachThe PG failure was caused by #3038892: Drupal\Tests\migrate_drupal\Kernel\d6\FieldDiscoveryTest randomly fails on PostgreSQL.
Comment #64
amateescu commentedHere's an update with a few more refinements pointed out by @plach:
- we should use
['#access'] = FALSEto hide the 'Enabled' checkbox for pending revisions, and also add test coverage for it- we can bring back
UpdatePathWithBrokenRoutingFilledTestbecause the "fieldable update API" is no longer using the storagesave()operation but a newrestore()one instead.Comment #65
plachThanks, I think this is ready to go now.
Comment #66
plachSaving credits.
Comment #67
plachTrying again.
Comment #69
plachCommitted 5ad8f59 and pushed to 8.8.x and to 8.7.x as
fbdccdc952c53fce12a81ac6640514c52e5fc3af.Celebration time now!
Comment #71
dixon_Huge thanks to everyone involved in coding, reviewing, triaging, committing, promoting and cheering on! Such a great milestone!
Comment #72
plachComment #73
amateescu commented/me celebrates by adding this tag :D
Comment #74
plach