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

CommentFileSizeAuthor
#29 after.gif133.14 KBwim leers

Issue fork canvas-3551455

Command icon 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

phenaproxima created an issue. See original summary.

wim leers’s picture

Component: … to be triaged » Component sources
Related issues: +#3545859: Add a `host-entity-url` prop source for linking to the host entity

Thanks for creating this!

wim leers’s picture

Title: HostEntityUrlPropSource should be able to support absolute or relative URLs, URL options, and different link templates » HostEntityUrlPropSource should be able to support absolute or relative URLs, URL options (e.g. disable path processing), different link templates

Note: only if the path_processing URL generator option is set to FALSE would an actual permalink be bgenerated.

wim leers’s picture

Component: Component sources » Data model
Issue tags: +stable blocker

This needs to be assessed for being a stable blocker or not. Because right now, this would store the following:

{"sourceType": "host-entity-url"}

But once this MR lands, that would change to something like

{"sourceType": "host-entity-url", "rel": "canonical", "options": {"absolute": true}}

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 store

{"sourceType": "host-entity-url", "rel": "canonical", "options": {"absolute": false}}

or at least

{"sourceType": "host-entity-url", "options": {"absolute": false}}

(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)

phenaproxima’s picture

+1 on this being a stable blocker. I definitely think this prop source should store as (YAML for easier formatting):

sourceType: host-entity-url
rel: canonical
options:
  absolute: true
  query:
    foo: bar
wim leers’s picture

Issue summary: View changes

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.

This matters a great deal.

Because all absolute URLs vary by the url.site cache context, which undermines the cacheability.

→ for type: string, format: uri-reference, only HostEntityUrlPropSource with 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.

phenaproxima’s picture

Assigned: Unassigned » phenaproxima

Got some ideas on this one.

phenaproxima’s picture

Status: Active » Needs review
Issue tags: +Needs tests

Still needs tests but the initial approach could use a look.

wim leers’s picture

Title: HostEntityUrlPropSource should be able to support absolute or relative URLs, URL options (e.g. disable path processing), different link templates » [PP-1] HostEntityUrlPropSource should be able to support absolute or relative URLs, URL options (e.g. disable path processing), different link templates
Status: Needs review » Postponed
wim leers’s picture

Title: [PP-1] HostEntityUrlPropSource should be able to support absolute or relative URLs, URL options (e.g. disable path processing), different link templates » HostEntityUrlPropSource should be able to support absolute or relative URLs, URL options (e.g. disable path processing), different link templates
Assigned: phenaproxima » wim leers
Status: Postponed » Needs review
wim leers’s picture

Assigned: wim leers » phenaproxima
Status: Needs review » Needs work
Issue tags: +Needs screenshots

This is:

  1. AFAICT dangerously open-ended (from a maintainability POV)
  2. does not yet have the appropriate settings-dependent labels
  3. does not yet have any tests proving any of this works — \Drupal\Tests\canvas\Kernel\PropSourceTest::testHostEntityUrlPropSource() needs to be expanded significantly
  4. and most crucially, does not yet update \Drupal\canvas\ShapeMatcher\PropSourceSuggester::matchHostEntityUrlPropSources()'s
        $matches = [];
        // @todo Offer `canonical` vs `edit-form` vs … (and check whether the given entity type actually contains such a link template) in https://www.drupal.org/i/3551455.
        // @todo Return either relative (`uri-reference`) or absolute (`uri`) suggestions in https://www.drupal.org/i/3551455.
        $matches[] = new HostEntityUrlPropSource();
        return $matches;
    

    👆 I'd expect that to return sensible new choices, and for it to then also appear in the UI :)

phenaproxima’s picture

I 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-url with 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.

effulgentsia’s picture

I think the "absolute or relative URLs" part of this issue should be stable blocking per #4, since that affects shape matching to uri vs uri-reference props. 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 the absolute option.

phenaproxima’s picture

Title: HostEntityUrlPropSource should be able to support absolute or relative URLs, URL options (e.g. disable path processing), different link templates » HostEntityUrlPropSource should be able to support absolute or relative URLs, URL options (e.g. disable path processing)
Assigned: phenaproxima » Unassigned
Status: Needs work » Needs review
Issue tags: -Needs tests

Per Alex in #15, I have reduced the scope a bit to still only support the canonical link template, but to allow URL options (certain ones) to be passed in. There is test coverage that absolute and relative URLs are supported via the absolute option, which defaults to TRUE in order to be broadly compatible with uri and uri-reference formats. That also sidesteps any need for an update path; existing uses of host-entity-url in the wild are generating absolute URLs, and that will continue to be the case unless absolute: false is explicitly set.

What else needs to be done here?

phenaproxima’s picture

Issue summary: View changes
wim leers’s picture

Assigned: Unassigned » wim leers

Thanks, will review tomorrow!

wim leers’s picture

Assigned: wim leers » phenaproxima
Status: Needs review » Needs work

On the right track, but some things were still missing:

  1. Tests were literally failing due to PHP errors… 🙈
  2. it was not yet updating \Drupal\canvas\ShapeMatcher\PropSourceSuggester::matchHostEntityUrlPropSources(), so nobody would EVER have gotten to use relative URLs 😅
  3. test coverage for the JSON representation
  4. … which would've caught the BC break I was alluding to in #4
  5. still exposing core's \Drupal\Core\Url's API as-is, which is risky for the 3 reasons outlined on the MR

I've pushed commits to propose how I would like to see #2 + #4 + #5 fixed. Your call on what you do with them.

phenaproxima’s picture

Status: Needs work » Needs review

As far as I can tell, feedback is now addressed.

Wim and I agreed on removing generalized options support, or even a subset of that, as a way of keeping the PropSource abstraction sealed (I can't deny that passing $options on to the underlying Url object qualifies as a leaky abstraction).

I think we also agreed that it's okay if absolute is 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.

phenaproxima’s picture

Title: HostEntityUrlPropSource should be able to support absolute or relative URLs, URL options (e.g. disable path processing) » HostEntityUrlPropSource should be able to support absolute or relative URLs, URL options

Reducing the scope further, since path processing doesn't (shouldn't) affect shape matching.

wim leers’s picture

It's worth mentioning that Canvas has also already adopted the just-in-time update pattern; consider what happens in […]

This is inaccurate, for 2 reasons:

  1. Component config entities do NOT contain user data. They're only used for internal tracking purposes. So different data integrity and update path considerations apply.
  2. The code you reference does not update-and-overwrite Component config 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 old Component versions, so we still need that metadata too.
wim leers’s picture

Status: Needs review » Needs work

There's 3 actual test failures left I'm afraid 😓

Other than that: looks fantastic! Just nits 🤓

phenaproxima’s picture

Assigned: phenaproxima » Unassigned
Status: Needs work » Needs review

I think the failures should now be addressed!

So, no data is lost: old data is kept as-is

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).

wim leers’s picture

Assigned: Unassigned » phenaproxima
Status: Needs review » Reviewed & tested by the community

Lint failures need to be fixed, but other than that this is good to go, so approved!

  • phenaproxima committed fb05b5bd on 1.x
    feat: #3551455 HostEntityUrlPropSource should be able to support...
phenaproxima’s picture

Assigned: phenaproxima » Unassigned
Status: Reviewed & tested by the community » Fixed

Merged into 1.x with Wim's approval.

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

wim leers’s picture

Issue summary: View changes
Issue tags: -Needs screenshots
StatusFileSize
new133.14 KB

Thanks! 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.)

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.