Overview
#3545859: Add a `host-entity-url` prop source for linking to the host entity added a prop source to get the absolute, canonical URL of the host entity. Right now, it can only get the canonical URL, and it can only get it as an absolute URL. URL options (like query strings, for example) are not supported.
Proposed resolution
We might want to support some, or all, of those things. This issue is to decide what we'd like to support here, and implement it:
- Do we want to support more than just the
canonical link template? (This would allow linking to, say, the edit form for an entity, or some other useful link template.) 👉 Not in this issue. Let's do this in a follow-up per #15.
- Do we want to allow the generated URL to be relative, instead of always absolute?
I'm not entirely sure it matters, but it's worth considering. → for type: string, format: uri-reference, only HostEntityUrlPropSource with relative URLs should be suggested, to minimize the occurrence of avoidably reduced cacheability (absolute URLs vary by the url.site cache context)
- URL options, like query strings or document fragments -- do we want to support those? I think fragments might be quite useful in some situations (linking to anchors on a page) -- how would we do this? 👉 We'll support a specific set of URL generation options that are known to the URL object and friends:
absolute, query, fragment, language, path_processing. Passing in any other options will raise an exception.
User interface changes

Comments
Comment #2
wim leersThanks for creating this!
Comment #3
wim leersNote: only if the
path_processingURL generator option is set toFALSEwould an actual permalink be bgenerated.Comment #4
wim leersThis needs to be assessed for being a stable blocker or not. Because right now, this would store the following:
But once this MR lands, that would change to something like
This would be a BC break and need an update path.
Unless of course we say that that is the default. But if we make this the default, then for
type: string, format: uri-reference, we'd need to explicitly storeor at least
(stored prop sources should be possible to evaluate without knowing the target prop shape — because
\Drupal\canvas\PropSource\PropSourceBase::evaluate()does not receive that information)Comment #5
phenaproxima+1 on this being a stable blocker. I definitely think this prop source should store as (YAML for easier formatting):
Comment #6
wim leersComment #7
wim leersThis matters a great deal.
Because all absolute URLs vary by the
url.sitecache context, which undermines the cacheability.→ for
type: string, format: uri-reference, onlyHostEntityUrlPropSourcewith relative URLs should be suggested, to minimize the occurrence of avoidably reduced cacheability (related: #4)P.S.: #3554184: Bubble cacheability of resolved props values and access results + `PropSourceBase::evaluate()` does not return cacheability at all will need to fix the bubbling of cacheability of
HostEntityUrlPropSource::evaluate(), too.Comment #8
phenaproximaGot some ideas on this one.
Comment #10
phenaproximaStill needs tests but the initial approach could use a look.
Comment #11
wim leersPostponing this until we get clarity at #3555413-10: Allow linking to referenced entities: add `url` property to `EntityReferenceItem::propertyDefinitions()`.
Comment #12
wim leersUnpostponing per #3555413-15: Allow linking to referenced entities: add `url` property to `EntityReferenceItem::propertyDefinitions()` 👍
Comment #13
wim leersThis is:
\Drupal\Tests\canvas\Kernel\PropSourceTest::testHostEntityUrlPropSource()needs to be expanded significantly\Drupal\canvas\ShapeMatcher\PropSourceSuggester::matchHostEntityUrlPropSources()'s👆 I'd expect that to return sensible new choices, and for it to then also appear in the UI :)
Comment #14
phenaproximaI think I now disagree with myself in #5, where I said that this needs to be a stable blocker.
This prop source can safely assume it's using the canonical, absolute URL. Why not just keep that assumption, but allow it to hold more options later? I don't see why that needs to result in a nasty update path.
host-entity-urlwith no other options can be an alias, effectively, for "canonical absolute URL". If we add additional options later (and support different relationships), as I sketched out in #5, so be it. We wouldn't need to update every single component tree to make that explicit. (Would we?)Leaving the tag on to see if Wim agrees, or if I'm missing something, but I just don't see a reason why these feature additions need to block a stable release.
Comment #15
effulgentsia commentedI think the "absolute or relative URLs" part of this issue should be stable blocking per #4, since that affects shape matching to
urivsuri-referenceprops. I think supporting other options and link templates can be a post-stable follow-up unless it's trivial to include here as part of solving for theabsoluteoption.Comment #16
phenaproximaPer Alex in #15, I have reduced the scope a bit to still only support the
canonicallink template, but to allow URL options (certain ones) to be passed in. There is test coverage that absolute and relative URLs are supported via theabsoluteoption, which defaults to TRUE in order to be broadly compatible withurianduri-referenceformats. That also sidesteps any need for an update path; existing uses ofhost-entity-urlin the wild are generating absolute URLs, and that will continue to be the case unlessabsolute: falseis explicitly set.What else needs to be done here?
Comment #17
phenaproximaComment #18
wim leersThanks, will review tomorrow!
Comment #19
wim leersOn the right track, but some things were still missing:
\Drupal\canvas\ShapeMatcher\PropSourceSuggester::matchHostEntityUrlPropSources(), so nobody would EVER have gotten to use relative URLs 😅I've pushed commits to propose how I would like to see #2 + #4 + #5 fixed. Your call on what you do with them.
Comment #20
phenaproximaAs far as I can tell, feedback is now addressed.
Wim and I agreed on removing generalized
optionssupport, or even a subset of that, as a way of keeping the PropSource abstraction sealed (I can't deny that passing$optionson to the underlyingUrlobject qualifies as a leaky abstraction).I think we also agreed that it's okay if
absoluteis defaulted to TRUE unless otherwise specified, which preserves existing behavior. This does mean that the at-rest data will change upon save/re-export, but it's hard to see why that's a problem; it's an example of a just-in-time update, a pattern which core has adopted in some places. I would hazard to assume that end users don't care at all about how the data looks at rest, as long as Canvas's behavior remains sensible and consistent, which is the case here.It's worth mentioning that Canvas has also already adopted the just-in-time update pattern; consider what happens in
\Drupal\canvas\Plugin\ComponentPluginManager::setCachedDefinitions()and\Drupal\canvas\Plugin\BlockManager::setCachedDefinitions()-- these create or update component entities as the underlying component's metadata changes.Comment #21
phenaproximaReducing the scope further, since path processing doesn't (shouldn't) affect shape matching.
Comment #22
wim leersThis is inaccurate, for 2 reasons:
Componentconfig entities do NOT contain user data. They're only used for internal tracking purposes. So different data integrity and update path considerations apply.Componentconfig entities, it instead chooses to update-and-append. See\Drupal\canvas\Entity\VersionedConfigEntityBase, introduced in #3523841: Versioned Component config entities (SDC, JS: prop_field_definitions, block: default_setting, all: slots for fallback) + component instances refer to versions ⇒ less data to store per XB field row. So, no data is lost: old data is kept as-is, unchanged, because existing component instances would be referencing oldComponentversions, so we still need that metadata too.Comment #23
wim leersThere's 3 actual test failures left I'm afraid 😓
Other than that: looks fantastic! Just nits 🤓
Comment #24
phenaproximaI think the failures should now be addressed!
This is also true of the JIT update we are implementing here. The "old" behavior is to always produce an absolute URL; the old data represents that, but is not explicit about it, because there was no other option. With this update, the form of the old data changes, but the semantics and behavior remain identical, and IMHO that's the important part (for end users, anyway).
Comment #25
wim leersLint failures need to be fixed, but other than that this is good to go, so approved!
Comment #27
phenaproximaMerged into 1.x with Wim's approval.
Comment #29
wim leersThanks! Here's the end result in action:

(Until #3555068: Linking a `HostEntityUrlPropSource` to populate a `type: string, format: uri|uri-reference` in a `ContentTemplate` has no effect is fixed, it won't work quite right though. But that is a problem that was not introduced here.)