Problem/Motivation
If there is a link template with mandatory parameters the url cannot be generated without providing those parameters. If we try to build the url without the mandatory parameters the exception Symfony\Component\Routing\Exception\MissingMandatoryParametersException
will be thrown.
The entity predelete hook menu_link_content_entity_predelete
introduced in #2350797: Orphaned menu links when nodes are deleted if menu_link_ui is not enabled is the one that introduced the problem by calling \Drupal\Core\Entity\EntityInterface::uriRelationships()
.
This might occur if the diff module is used and a link template like this is added:
"revisions-diff" = "/custom_entity/{custom_entity}/revision/{left_revision}/{right_revision}/{filter}"
This is a major as it prevents deleting entities having such link templates and there is no workaround for this.
Proposed resolution
\Drupal\Core\Entity\EntityInterface::uriRelationships()
should catch exceptions of the type MissingMandatoryParametersException
.
Remaining tasks
User interface changes
API changes
Data model changes
Comment | File | Size | Author |
---|---|---|---|
#26 | 2924338-26.patch | 3.09 KB | hchonov |
#26 | 2924338-26-test-only.patch | 2.38 KB | hchonov |
#25 | 2924338-25.patch | 729 bytes | hchonov |
Comments
Comment #2
hchonovComment #4
hchonovThe only thing I am not really sure about is if we should or should not return the link template in case we cannot automatically build the url for it?
Also will
menu_link_content_entity_predelete
be able to find the menu links without the route parameters?Comment #5
cspitzlayComment #6
cspitzlayI set the issue back to needs review, the test failure was unrelated and a retest was green.
Comment #7
cburschkaI think the answer is no for both. With missing parameters, it's an invalid Url (since it did actually throw an exception while rendering), so it doesn't have a path representation, so it can't actually match any menu link. It doesn't make a practical difference, but it'd probably be better to return FALSE and filter it out.
Edit: Confirmed that if I create an entity type with a revision-revert link relationship, then create an entity and revisions, then create a menu link that points at the revert link for a specific revision, then delete the entity, the orphaned menu link will not be deleted, even after the patch. Whether we need to fix that is a separate issue, but this patch doesn't seem to fix it beyond preventing the crash. There doesn't seem to be a way to find all menu links matching a partially parameterized route (ie a specific entity ID, and any revision ID).
Comment #8
cburschkaUpdate to the above: The
revision
relationship (the canonical link to a specific revision) automatically gets the revision parameter set by the entity, so it's not affected by this bug, and revision-specific menu links should in fact get deleted, assuming that menu_link_content_entity_predelete() is called for each revision of the deleted entity (haven't checked in detail).So the crash only affects other link templates (such as revision_revert or revision_delete, which are autogenerated when creating the content entity type with DrupalConsole). Since it's hard to imagine a legitimate case where you would have a custom menu link pointing at a revision-deletion form, we probably don't need to go out of our way to find and delete those. At worst, you'll need to remove the orphaned menu link yourself.
Comment #9
asherry CreditAttribution: asherry commentedI very much need this patch, but, I agree with cburschka it should really be returning FALSE. I'm just going to post a version with the boolean flipped so that I can use it in my composer file for now.
Thanks cspitzlay!
Comment #10
cburschkaThis looks ready, now we just need to remove the comment as it no longer applies.
Comment #11
cburschkaMay still need tests. (The original code was added in #2293697-188: EntityResource POST routes all use the confusing default: use entity types' https://www.drupal.org/link-relations/create link template if available, but I can't see any tests that specifically cover it specifically.)
Comment #12
slydevil CreditAttribution: slydevil commentedPatch from #11 works great. I uncovered this issue is the 8.4.3 release, so it should be included in the 8.4 branch as well.
Comment #13
Wim Leers"we still want to return the uri relationship" doesn't really make sense.
Plus, there already is a comment above the
try
. This should instead expand that.#11 is indeed right that #2293697: EntityResource POST routes all use the confusing default: use entity types' https://www.drupal.org/link-relations/create link template if available did not add explicit tests, but that's because certain (functional) tests were failing without this change. If we want explicit test coverage for this now, then we probably want to add a
testUriRelationships()
to\Drupal\Tests\Core\Entity\EntityUnitTest
and add mocks for the different edge cases.Comment #15
hchonovSimilar problem has been reported in #2941443: EntityInterface::uriRelationships() should document you can't call it on a new entity, but the work on the problem continues here. An easy test inspired by the referenced issue would be to simply create a new entity and before saving it call
uriRelationships()
on it, which should fail as the entity doesn't yet have an ID.Comment #16
hchonovComment #17
RoSk0Crosslinking
Comment #18
RoSk0From my understanding the issue is actually in the way this module tries to clean up links to entity being deleted.
There is no need to loop over entity relationships when we just need a canonical URL for it.
Described approach is Implemented in patch.
Also in my case exception was caused by #2927051: Re-use parent code in RevisionableContentEntityBase::urlRouteParameters().
I think my approach could be treated not as bug fix but probably as improvement?
Comment #20
hchonovThere might be a menu link to other entity URI relationships than to the canonical one and if we could generate the URL and automatically delete it then we should do it. What we do is best effort. Why do you think that we just need the canonical URL?
You could register a link template pointing to e.g. the settings of an entity something like
entity/{entity}/settings
and you might have a menu link pointing to it and if you delete the entity we should delete the menu link as well.Additionally we should prevent
::uriRelationships()
from throwing exceptions as otherwise the method is pretty much useless and couldn't be relied on, which then will solve this issue and the other one where the method is called on a new entity as if the method is called on a new entity it will not be able to generate the canonical URL and still throw an exception.Do you mind moving the issue back to the entity system?
I think that #11 is the way to go. We only need a test coverage for the implemented solution.
Comment #21
RoSk0Thank you for that explanation @hchonov. Now that code actually make sense for me. Much appreciated.
Comment #22
acrollet CreditAttribution: acrollet commentedThere is an issue with this patch, which is that we can't assume that entities have a canonical URL. (e.g. paragraphs, flagging entities etc.)
Comment #23
hchonov@acrollet, could you please elaborate on that? I don't understand what is the problem with this? All we do is the prevent throwing exceptions if we could not generate the full URL for an entity link template.
Comment #24
acrollet CreditAttribution: acrollet commented@hchonov, I'd be happy to - the patch in #18 simply calls $entity->toUrl() instead of enumerating the uriRelationships method. The default parameter for that method is 'canonical' - entities that do not define a canonical link template (such as flagging entities) trigger this exception:
Comment #25
hchonov@acrollet, in the comments afterwards I've explained that #18 is not the right approach, but #11. I am re-uploading the patch from #11 so that this is more clear. We only need a test coverage.
Comment #26
hchonovI've added an unit test.
Comment #28
Wim Leers👌
Comment #29
alexpottLooking at the exceptions that url generation can throw we have:
2 of which are now caught here. Thinking about InvalidParameterException I think it makes sense to ignore that one since if that was thrown something would probably be very wrong.
Comment #30
alexpottGiving review credit to @Wim Leers for a review that changed the patch.
Comment #31
alexpottCommitted and pushed 7aa16e856b to 8.6.x and f51e1bde98 to 8.5.x. Thanks!