Problem/Motivation
Blocking #2418017: Implement autocomplete UI for the link widget
Now that we have the entity: URI scheme supported by the \Drupal\Core\Url API (see #2411333: Create standard logic to handle a entity: URI scheme , #2412509: Change LinkItem.uri to type 'uri' rather than 'string' and introduce user-path: scheme, #2417333: Add support for user-path: scheme to Url class), we also want to be able to actually use it in the UI.
LinkItem::getUrl()didn't supportentity:because it called thePathValidatordirectly rather than usingUrl::fromUri().LinkTypeConstraintperformed access checking; disallowing users to store links that they couldn't access. However, that should be a widget-level decision.
Proposed resolution
Fix all the problematic points listed above.
Remaining tasks
None.
User interface changes
In HEAD, for menus, the link field validation error message is "The path 'foo' is either invalid or you do not have access to it.", while for shortcuts and regular link fields it's "The URL foo is not valid.". With the patch, it's the former in all cases.
API changes
| Comment | File | Size | Author |
|---|---|---|---|
| #30 | interdiff.txt | 3.02 KB | effulgentsia |
| #30 | link_field_validation-2417793-29.patch | 32.63 KB | effulgentsia |
| #26 | interdiff.txt | 383 bytes | effulgentsia |
| #26 | link_field_validation-2417793-26.patch | 33.02 KB | effulgentsia |
| #26 | link_field_validation-2417793-26-test-only.patch | 447 bytes | effulgentsia |
Comments
Comment #1
wim leersAgain pair programming with effulgentsia!
This fixes configurable link fields. Next steps: fix
ShortcutandMenuLinkContent.Comment #2
wim leersNow allowing
node/addas input again, instead of only allowinguser-path:node/add.Still pair programming with effulgentsia.
Comment #3
yesct commentedComment #5
wim leersMenuLinkContentis now fully working, no longer doing its own validation! Yay :)(Still pair programming with effulgentsia!)
Comment #6
wim leersActually,
Shortcutis now also working completely correctly! :)Now this issue is down to fixing test failures.
Comment #8
yched commentedMinor :
Can we make that a static method, and add it as
'#element_validate' => [[get_class($this), 'elementValidate']]?Nicer on form serialization :-)
(would mean the getUserEnteredStringAsUri() helper has to be static as well, but AFAICT it can ?)
Can we move that one next to the existing getUriAsDisplayableString() ? they look kind of related :-)
Oh yeah !
Comment #10
yched commentedAlso, really minor :
getFooAsBar($bar) is a bit weird - that $uri param is not a URI yet, that's the whole point :-)
--> s/$uri/$string/ ? $input ?
Comment #11
wim leersFixing failures! (Still pair programming!)
Comment #13
wim leersThis will bring it down to a few dozen failures at most! (Still PP.)
Comment #14
wim leersComment #17
effulgentsia commentedWim left the sprint and is on his way back home, so I'll finish fixing the remaining failures.
Comment #18
dawehnerI was wondering whether we should introduce UrlHelper::getDangerousProtocols and use it, which calls out to static::$allowedProtocols
I'm wondering whether we could / should provide a more specific message? What means valid here / should we care?
Afaik you have to update validateConfigurationForm to point to something existing ... doValidate() removing should break it.
Comment #19
effulgentsia commentedHopefully green.
Comment #21
effulgentsia commentedreroll
Comment #23
effulgentsia commentedAddresses remaining feedback from yched and dawehner and fixes the failures.
Comment #25
effulgentsia commentedUnifying the violation message to match the one from menu UI, cause it's better.
Comment #26
effulgentsia commentedUsing
user-path:in the UI explicitly is pointless, so removing that from the issue purpose. Added a test forentity:, along with the test-only version to demonstrate the failure in HEAD. Also updated the summary to include the only UI change that I think is in here.I think this is ready now, unless there's further feedback.
Would be great for this to land before tomorrow morning's sprint, to unblock #2418017: Implement autocomplete UI for the link widget.
Comment #28
yesct commentedI tried it manually. allows saving with entity: and also allows user-path: (but user-path will never be entered by a user so it's kinda irrelevant. after save it displays user-path:one as one so it's ok either way)
but
two concerns yet to be addressed. discussed in person.
undelete doValidate()
move one of getUserEnteredStringAsUri() or getUriAsDisplayableString()
Comment #29
yesct commented#2418031: Remove MenuLinkContentForm::doValidate() since the logic was moved to LinkWidget::validateUriElement() to handle the doValidate() concern.
Comment #30
effulgentsia commentedAddresses #28. Adds a @todo linking to the issue in #29.
Comment #31
dawehnerI'm convinced that this is RTBC at that given point in time.
Comment #32
webchickReviewing whilst we wait for testbot. If anyone's still awake, I'm in #drupal-nj.
Comment #33
webchickI tried this out in the following way:
- Created a node/1 called "bananas" with a path of "bananas"
- Created two menu links: one to entity:node/1 and one to "bananas"
- Changed the path of node/1 to "bananaz"
- Expected result: first menu link continues to work, second one breaks.
- Actual result: Both menu links continue to work (?!?!)
Apparently our path system is doing something kinda magic here like remembering old paths, not sure?
At any rate, though, the patch is doing what it says, which is letting you enter entity:node/1 and it's linking to something. Also tried entity:user/1 for kicks and confirmed that there were no regressions in linking to e.g.
<front>. It's a little funny that the patch doesn't also introduce an addition to the link field help text explaining you can now type entity:node/1 here, but I guess the thinking is that the autocomplete will be done soon enough we won't need to bother people with doing this from the UI (which obviously would be preferable).Code-wise, only a couple of things.
This was the only part that gave me pause, because we've moved from pessimistic validation to optimistic validation. I seem to remember this being raised in another issue as well... maybe by larowlan? Not going to block commit on it, but flagging it so once everyone has got a good night's rest, we can revisit this to make sure we're capturing all cases and didn't inadvertently introduce a sechole here.
Patb? ;) Will fix on commit. OTOH, great to see that the migration path is already taken care of! That was one of the concerns I had about all of this URI transmogrification stuff.
Rock on, folks! Onward!
Committed and pushed to 8.0.x. Thanks!
Comment #35
wim leersJust landed in Brussels. Awesome to see this landed!
Comment #36
larowlanGreat work!
Comment #37
yched commentedIssue ping pong :-)
#2417783: Remove widget specific logic in MenuLinkContentForm was closed as a dupe of #2417367: Use the new entity: URI scheme,
which in turn was closed as a dupe of this issue here,
which is now fixed,
but didn't address the issue described in #2417783: Remove widget specific logic in MenuLinkContentForm :-)
So, should we re-open #2417783: Remove widget specific logic in MenuLinkContentForm ?
Comment #38
dawehnerWhat you described was removed in #2417793: Allow entity: URIs to be entered in link fields IMHO.
Comment #39
yched commentedTrivial followup for #10, which was left unadressed :-)
#2418109: Misleading param name in LinkWidget::getUserEnteredStringAsUri()
Comment #40
yched commented@dawehner : no, the lines mentioned in #2417783: Remove widget specific logic in MenuLinkContentForm in doValidate() and extractFormValues(), hardcoding logic on the widget structure, are still there.
Comment #41
yched commentedAlso, wondering if the widget validation contains stuff that would rather belong to the field/TyedData constraint (LinkTypeConstraint) ?
It's always a tricky split, but roughly the rule of thumb is: if some check needs to run on non-UI saves (like REST operations), it belongs to field constraints. Widget FAPI validation is typically about stuff specific to the $form shape of that widget (and that would not necessarily make sense for a different widget shaped differently), or input errors that prevent forming a valid FieldItem to begin with.
The LinkWidget's #element_validate currently:
- forbids unrouted internal URLs (i.e. disallow 'base:' URIs)
is that form/UI specific ? Why don't we want to prevent that on REST operations too ?
- forbids linking to a URL the current user doesn't have access to
REST operations are behind user authentication too, right ? Am I allowed to POST a link value that I would be denied in the UI ?
- Disallow external URLs using untrusted protocols.
Likewise, untrusted protocols don't seem like something we'd want to allow on REST ?
Maybe this is valid, just wondering - so, not opening a followup for now :-)
Comment #42
wim leersAll three of those restrictions were put in place to retain the current UX in HEAD. None of them make sense to enforce at the field validation constraint level:
- disallowing base: URIs is merely an oversight/omission in HEAD, that this patch didn't want to change
- disallowing inaccessible (from the current user's POV) is a relic from the D6/D7 past; and it prevents a use case that is desired by more than a few: the ability to create design the IA/URL design of a site by creating the desired menu tree structure before those URLs actually serve the desired content
- disallowing untrusted external URLs: just like the filter system, we filter away security problems on output; i.e. strip dangerous protocols when rendering links (also applies to the previous point: access checking is performed on links at render time anyway, so there is no harm in allowing users to link to inaccessible URLs)
This is the reasoning we came to, resulting from a discussion with effulgentsia, pwolanin and I.
Comment #43
yched commentedThanks for the explanations @Wim.
Not sure I get this - does it mean this will be further adjusted in a separate issue ?
OK - that desired use case seems more about non-yet-existing rather than non-accessible for a given user ? But right, if this keeps D7 behavior, changing that would be a separate feature request if anything I guess.
Comment #44
webchickNo, it's a 6+ year old regression: #308263: Allow privileged users to bypass the validation of menu items
Comment #45
effulgentsia commentedThe follow-up for #43: #2418181: Remove 404 validation from link creation
Comment #46
effulgentsia commentedThe expected behavior happens correctly (well, after a a cache clear, so we're missing a cache tag for url aliases, which makes sense since those are neither content nor config entities) if you do the same scenario via a link field on a node (or any other entity) rather than a menu link. For a menu link, even a cache clear doesn't fix it, because of the materialized {menu_tree} table, but #2417837: Update menu link definitions when aliases change is for fixing that.
Comment #47
effulgentsia commentedNot really, because highlighting a few more lines from the committed patch:
The old code was also becoming optimistic so long as getUrl() returned some URL, and then proceeded to make it false later based on specific checks about that URL. So both prior HEAD and current HEAD follow similar "assume valid until you find a problem" logic. But that's the same with a lot of our validators. For example, in HEAD, UserNameConstraintValidator contains a bunch of if statements that add violations. If none of those statements evaluate to true, then no violation is added, and therefore, the constraint is satisfied. The difference with LinkTypeConstraint is just that the violation message is the same in all cases, so we have a local variable to let us keep it in one place.
If someone spots a flaw in the above reasoning, please open an issue for it.
Comment #48
webchickFair enough! Thanks for checking into it.
Comment #49
effulgentsia commentedI thought about adding a new issue for that, but for now, just noted it in #2335661-23: Outbound path & route processors must specify cacheability metadata, and would like to leave it to people working on that issue to decide whether to spin off a specific sub-issue for that.
Comment #50
yched commentedSo, not sure if we still need a followup for this ?
[edit: never mind, #2418181: Remove 404 validation from link creation does take care of this. @effulgentsia++]
Comment #51
yched commentedFYI : #2076321-9: Link "title" validation should use a static method is about making the pre-existing LinkWidget::validateTitle() consistent with the validateUriElement() that was added here.