Problem/Motivation
It would be great to provide URLs with UUIDs in their so you can link to them.
The solution would need to meet the following requirements:
- Allow a UUID-based URL to be used in menus, end-user-facing links should use a path alias when available
- Allow a UUID-based URL to be used for front page, 403 and 404 pages, without strange redirection by-effects
- Allow a UUID-based URL to be used as in the page condition for e.g. block-placement. It should not make a difference if the alias-, numeric ID- or UUID-based URL is used, the block should be shown regardless of the URL used to access the content
- The "duplicate content" situation is not made worse then it is, i.e. search engines should be guided to a canonical URL somehow, either by redirects (for aliases and traditional numeric URLs this is handled by Redirect module in contrib) or a canonical metatag
Proposed resolution
The most recent solution uses a path converter. It relies on the existing behaviour of setting the canonical meta tag to avoid duplicate content issues in terms of SEO (because that is already the approach taken with aliases vs. system paths). Internally, the path is converted to the numeric path, so that anything relying on that also works for the UUID-based URL.
Add a new uuid link template for entities:
$node->toUrl('uuid');
Remaining tasks
- [x] Add special case code to Entity::toUrl() to handle 'uuid'
- ❓Test all use cases
- [ ] Update CR
User interface changes
The UUID-based URL is available.
API changes
It is possible to request the UUID-based URL for an entity.
| Comment | File | Size | Author |
|---|---|---|---|
| #289 | interdiff_288-289.txt | 778 bytes | vsujeetkumar |
| #289 | 2353611-289.patch | 13.44 KB | vsujeetkumar |
| #288 | interdiff_287-288.txt | 1.72 KB | vsujeetkumar |
| #288 | 2353611-288.patch | 13.49 KB | vsujeetkumar |
| #287 | diff_262-287.txt | 3.68 KB | vsujeetkumar |
Issue fork drupal-2353611
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
Comment #1
chx commentedAbsolutely lovely idea, I do not even know why that's not the default :)
Comment #2
dawehnerThis makes it at least possible to link to it.
Comment #4
dawehnerJust in case someone is already interested, here is a small module implementing this kind of functionality.
Comment #5
dawehnerJust fixing hopefully all the failures for now.
Comment #6
dawehner.
Comment #7
clemens.tolboomCool ... that would invalidate #2304849: Stop excluding local ID and revision fields from HAL output too.
Comment #8
Crell commentedThe proposal in the summary sounds great: A 301 is the right way to do this.
However, it looks like the patch is not actually setting that up yet. IMO we should put the uuid version at a different URI than the auto-inc version. In fact, it doesn't even need to be in REST. Any entity with a canonical URI can also get a /uuid/{type}/{uuid} URI that does nothing but send a redirect.
Comment #9
dawehnerAdding the tag.
Comment #10
clemens.tolboomChecking #6 and remarks from #8 this needs work.
Is #6 supposed to be a patch maybe?
Comment #11
larowlanfirst a reroll, then tackling #10
Comment #13
larowlanthis died horribly because OutboundRouteProcessorInterface changed, and invalid yml, guess that explains #6 being a txt file :)
Comment #14
larowlanworking on this a bit
Comment #15
larowlanWow
Drupal\menu_ui\Tests\MenuTestis a big one, 7 mins per run locally.Added new integration tests to it covering the new behaviour, made sure that menu links pointing to nodes by UUID are picked up by the node edit form alters in menu_ui module.
There is no redirect because the path processor lets you use serial ID (nid) or UUID. Redirect would be the job of global redirect module (we don't redirect node/2 to /some/pretty/path in core).
Had to do some refactoring in the menu tree manipulator because sometimes the node parameter is a uuid.
Comment #18
larowlanuntil tomorrow in case anyone else is inclined
Comment #20
skwashd commentedIt is great to see this functionality being incorporated into D8. This is something the D7 contrib module already does.
Comment #21
wim leersComment #22
simeUpdating patch from #15.
Comment #23
wim leersComment #25
simeThe last patch is broken.
FWIW, I've been working on this against the 8.0.x branch (so this might not a be a problem on the 8.1.x branch) and I'm having some issues getting past a route exception:
Comment #26
simeThis patch is against 8.0.x. It's basically #15 plus some hacks to make it work, and I removed the tests. I'm not setting this to issue "needs review" but maybe the patch is useful - the comments below may not even apply to 8.1.x.
So, firstly the route expects an integer so using node/{uuid} is rejected before it gets to RouteProcessorEntityUUID.php. See
->setRequirement('node', '\d+')in NodeRouteProvider.phpAlso in the patch in #15, the /node/{uuid} has no logic for redirecting to /node/{id} - I think this would be mandatory. I worked around this with a redirect in the NodeViewController. I don't know the best fix for this.
I'm not sure what the menu-related changes in #15 patch do, I left them in... perhaps they are only relevant if we don't do a redirect?
Comment #27
simeModified description to reflect the recent patches.
Comment #29
dawehnerAnyone wants to discuss what / how we actually want to implement it?
Comment #30
larowlanYeah, will try and catch you tomorrow
Comment #31
larowlanAnother option here is to add a new link template to go with the 301 redirect.
Comment #32
larowlanDiscussed with @dawehner - I'm going to do the following
Comment #33
larowlanWorking on this
Comment #34
larowlanInterdiff is against #22
Let's see what fails here.
Comment #35
benjy commentedNot sure but might be worth injecting EntityRepository for loadEntityByUuid here
Does this need an upgrade path?
Comment #36
dawehnerJust a quick thought:
So given that we have a static pattern we could improve the situation for all other routes, by registering one route per entity type together with the UUID pattern as requirement.
Comment #37
larowlan@dawehner so we'd add that to \Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider for any entity-type with a canonical link template?
Makes sense to me.
Would it be worth adding a uuid link-template to go with it, that'd make it easier to use - instead of
internal:/{entity_type}/{uuid}we could use$entity->toUrl('uuid');Sound about right?
Comment #38
dawehner+1 from me.
Comment #39
wim leers+1
Why not
entity:{entity type}/{entity uuid}?Comment #40
timmillwoodWe need a uuid index, this is something we have added as part of Multiversion.
I am proposing this for Entity module (#2690745: Create an index of UUIDs) and core (#2690747: [PLAN] Create an index of UUIDs), essentially it's just a big key_value store keyed by UUID and stores entity type id, entity id, and potentially other things.
Then, as we do in Multiversion and other modules that depend on it, we query the index with just the UUID and we can load the entity from the entity type manager.
Comment #41
larowlan@timmillwood whilst I agree a uuid index is useful, I don't think we need it here, we have the entity_type information.
Comment #42
timmillwood@larowlan - Right, this issue introduces incoming paths matching /{entity_type_id}/{uuid}, but wouldn't it be cool to introduce Incoming paths matching /{uuid}. In that case we would need a UUID index.
In Relaxed module we use paths with the uuid but not the entity type, therefore we make use of the uuid index in Multiversion.
Comment #43
dawehnerI mean technically we decided against having such URLs, so we always at least some prefix, but generically I kinda dislike to totally have missing semantic information about what is contained behind those resources.
Comment #44
larowlanworking on this
Comment #45
larowlancurrent patch, some failing tests at this stage, will continue on tuesday
Comment #47
larowlanMore work on failing tests
Comment #48
larowlanComment #50
larowlanMore work on failing tests
Comment #52
larowlanmore fixes
Comment #53
dawehnerNice, a green patch!
Do you think we should expand the test coverage of the entity type manager here?
Should we respect previously defined UUID templates?
Do we need that?
We could prevent the if() by casting it to an array first. Not sure which you though you prefer.
Can we document on the convert method that the value might also be a uuid?
Don't we miss the case of
entity:/node/$uuid?Comment #54
larowlanComment #55
acbramley commentedJust confirming this applies and works on 8.1.0 as well
Comment #56
larowlanFixes #53
Comment #57
jibranDo we need an update hook to clear the cache for this?
Comment #58
dawehnerJust some continues review ...
I still haven't got the point of this interface to be honest ...
I'm wondering what happens for page manager for example now that the path pattern is there now twice. Do they to check for the requirement to just override one of the specific routes or would they override both routes?
Comment #59
wim leersThis makes so much sense!
*can* or *must*?
Is this correct? What about file entities? They don't have a view builder, but can be referenced by UUID.
do we want this one or
EntityViewController::buildTitle()? (In-place editing needs that one. I didn't even realize we also had this one.)The
$nidsvariable name no longer makes sense with this.Also, we need to have updated test coverage for this.
Why not use
\Drupal\Core\Entity\EntityRepository::loadEntityByUuid()?This looks confusing.
This looks like a straight bugfix? Nice!
Do we have updated test coverage for this?
Nit: s/uuid/UUID/
Comment #60
dawehnerThe reason why I don't understand it is that I think people should be still able to normally register routes using yml files.
Comment #61
larowlan#60 they can, but they also have to add the uuid template to the entity-type annotation.
I can do taxonomy term in this patch to prove it works if that helps?
Comment #62
dawehnerMh I see where you are coming from, it is still a bit weird
Comment #63
dawehnerYeah I'm not 100% sure about this one. This kinda makes the assumption we would just provide HTML routes with the 'html' key. There is no such assumption somewhere in the system so far.
Comment #64
larowlanAddressing comments:
So need some feedback from @WimLeers on #59.6 and 7 and from @dawehner on removing the magic UUID link template.
Comment #65
dawehnerI like this idea. Less magic!
Comment #66
wim leers#64:
What I think is less confusing:
I think this is less confusing because it clearly shows that the route parameters are the same in both cases, it's just a different route name.
Comment #67
larowlanAddressing items from #64
Comment #68
dawehnerWhat about using a UUID link template, in case there is one?
Comment #69
jibranOther then this small feedback I think it is ready. Can you please also fix all the needs tag?
These double quotes are making it hard to understand. Can we add comment or use single quotes instead?
Comment #70
dawehnerI agree, let's go with single quotes instead ...
Comment #71
larowlan#68 - @dawehner not sure what you mean there
##6 - will fix
Draft change notice is https://www.drupal.org/node/2725969
Comment #72
larowlanFixes #69
Comment #73
wim leersNote this would also help make linking in formatted text fields better, because the content would actually be syncable across sites. Hence this is also related to #2292159: EditorLinkDialog should validate URLs, and autocomplete like the Link widget.
This is not listed at https://www.iana.org/assignments/link-relations/link-relations.xhtml, is that a problem?
Nit: The docblock for this class says:
Needs to be updated.
This causes this to be testing the Node UI, rather than the Menu UI. I think it's only necessary for the assertions I mentioned. And do we really need those here?
I don't think this comment is accurate? Looks like a c/p thing.
EDIT: forgot to say: I was very tempted to RTBC this. It's mostly because of the test that I didn't. This looks 99% ready.
Comment #74
larowlan#73.1 - I thought so too, but then I looked up all of our existing link-templates and found we're already using some that don't exist - e.g.
delete-form. In the existing templates, I only seeduplicateandalternateas possibles but I don't think that would lead to the best DX.In my opinion
$entity->toUrl('duplicate');isn't as obvious as$entity->toUrl('uuid');- thoughts?#73.2 - fixed
#73.3 - yeah I changed the logic around that form alter, so we need to test that we can also load the default value if it references a node by UUID
#73.4 - fixed
Comment #75
wim leersdelete-formalso doesn't exist, then this is fine. I agreeduplicatewould be a meaningless and even confusing relation name.So only point 3 needs further attention.
Comment #76
larowlanre #75.3 will move to MenuNodeTest from MenuTest and push the
::verifyMenuLinkand::addMenuLinkmethods up into MenuWebTestBase, making that the new base-class for MenuNodeTest.Comment #77
larowlanDone
Comment #78
wim leersThat was my only remaining concern. Thanks! :)
Comment #79
tstoecklerAs far as I can tell, the latest patch does not actually use the URI link template in the route provider.
Comment #80
larowlan@tstoeckler can you clarify what you mean there?
Comment #81
larowlan@tstoeckler - this is where it is used
Comment #82
tstoecklerSorry for being so terse. What I meant was this:
In
\Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider::getUuidRoute():This
should be
I.e. we should check whether the entity type specified a UUID link template and then use it to fetch the path for the route.
Hope that makes it clearer what I'm thinking.
Comment #83
larowlanNice one @tstoeckler - fixed
Comment #85
larowlanComment #86
wim leers@tstoeckler++
Comment #87
dawehnerNice!
Comment #88
alexpottUnused use.
Hmmm well the eg uuid doesn't really work does it.
Should be system_update_8200() since we need to leave a gap in case of an emergency update function. At last that is what @catch made a recent views patch do.
Comment #89
larowlanComment #90
dawehnerThe feedback from @alexpott got addressed
Comment #91
alexpottgit diff 8.2.x HEAD core/lib/Drupal/Core/Entity/Entity.php
Comment #92
dawehnerMerge looks perfect!
Comment #93
alexpottCommitted 85bc69d and pushed to 8.2.x. Thanks!
Comment #95
bzrudi71 commentedI'm sorry but since commit MenuNodeTest fails on PostgreSQL for 8.2.x. Please see https://dispatcher.drupalci.org/job/php5.5_postgres9.1/
Comment #96
alexpottLet's fix this in #2762413: Drupal\menu_ui\Tests\MenuNodeTest is failing on automatic testing for PostgreSQL rather than re-opening this issue.
Comment #98
alexpottAfter discussing with @catch decided to revert- since this introduces a postgres regression and increases the likelihood of adding more.
Comment #99
bzrudi71 commentedThanks @alexpott! Just found a minute to ran this locally and here is the PostgreSQL log:
PostgreSQL is a bit more strict and the IN nid condition seems obsolete ;)
Comment #100
daffie commentedTrying to fix the PostgreSQL test bug.
Comment #102
daffie commentedSecond try to fix the PostgreSQL test bug.
Comment #105
alexpottDiscussed with @catch, @xjm, @effulgentsia, @cottser. We felt that this issue is a beta target because it has been committed once before and is only help up because postgres fails and it is an important feature for some of the API first work.
The issue summary could do with an update to explain the issue, the benefits and the solution.
Comment #106
alexpottThis should fix the problem - also I'm not convinced the original patch actually worked because of how \Drupal\Core\Menu\DefaultMenuLinkTreeManipulators::checkNodeAccess() was adding the access result to the tree.
Comment #107
alexpottHere's an integration test for the
\Drupal\Core\Menu\DefaultMenuLinkTreeManipulators::checkNodeAccess(). I'm really sure why this exists - it is only used in\Drupal\Core\Menu\MenuParentFormSelectorand it's not part of\Drupal\system\Plugin\Block\SystemMenuBlock::build()which creates the menus people see on the page.Comment #108
dawehnerYou would be able to skip using this load multiple by using a groupby in the query. Not sure though whether its worth to do so.
Note: config entities don't have a serial ID, should we somehow point to that as well in the documentation?
Some new lines here would improve the readability quite a bit IMHO
What happens if views takes part in here? Don't we override this URL as well, but it doesn't work any longer?
I think we have to expand
\Drupal\views\Plugin\views\argument_validator\Entity::validateArgumentto also accept UUIDs.Is it just me that it is a bit weird to remove an existing testcase instead of just adding a new one?
This is just perfect test code ...
at(N)everywhere, what else do you needComment #109
alexpottDiscussed a bit with @dawehner - so
\Drupal\Core\Menu\DefaultMenuLinkTreeManipulators::checkNodeAccess()exists for performance reasons (as it documents in its doc block). The performance fix is to not load nodes so the fix in #107 loses that benefit for UUIDs. We have three options here:\Drupal\Core\Menu\DefaultMenuLinkTreeManipulators::checkNodeAccess()handle both\Drupal\Core\Menu\DefaultMenuLinkTreeManipulatorsfor UUIDs.The current approach I've chosen is 2 but that's because I started from #107 - maybe it is not the best option.
Comment #110
alexpott@dawehner's review in #108 still needs to be done. To be honest I don't think #108.6 is particularly fair. The existing test is full of
$this->at()already and in general I'm not a fan of mocking complex queries.Comment #111
dawehnerWe made that clear on IRC. This was me being snarky about the existing test, not about the added code.
Comment #112
xjm(Removing release notes tag; we can retag for whichever release notes whenever the change is committed.)
Comment #115
larowlanWorking on #108
Comment #116
larowlan108.1 was handled in 109
108.2 -fixed comment
108.3 -fixed
108.4 -fixed and added a new test
108.5 -added back
Comment #117
dawehnerWhat about using an entity query + a multiload?
Comment #119
larowlan\Drupal\Core\Entity\EntityStorageBase::loadByPropertiesuses an IN query by default, so we can pass the array of UUIDs and use loadMultiple instead of looping.Comment #120
dawehnerAt least for me this looks great!
Comment #121
alexpottWe could use the ctype_digit() || is_int() trick to potentially save a query here. In fact we could add these checks to Uuid::isValid() to make it cheaper.
Is this fixing a bug?
Comment #122
larowlan1 fixed
2 this is from HEAD
The URI is created as
'link' => ['uri' => 'entity:node/' . $node->id()],New tests are added here.
Comment #123
larowlanComment #124
webchickUndoing the bot, since this is still a beta target for 8.2.x.
Comment #125
alexpottSo now Uuid::isValid() is cheaper we can do only one query here.
Comment #126
alexpottSomething like this...
Also I think we need to cast to string for ctype_digit because it's weird when passed something else.
Comment #127
alexpottLet's not change the Uuid component unnecessarily here.
Comment #129
alexpottAh I see... this loads all entities. So it also loads the string IDs of config entities too.
Comment #130
larowlanChanges look good to me, thanks @alexpott
Comment #131
jibranSeems like everyone is happy.
Comment #132
effulgentsia commentedLeaving at RTBC, but a question before I'm comfortable with committing this:
With this patch, when you're on a
node/{uuid}URL, then you do not get the local task tabs, such as Edit, Delete, and Revisions. Is it ok for that to be the situation in an 8.2.0 release? The IS doesn't say much about what the real use case for UUID-based URLs is, but since the patch is allowing people to add them to their menus, I'm guessing there are some sites that will want to do so and then be confused as to how to access the revision history for that node as well as all the other local tasks provided by core and contrib?Potentially, integrating local tasks onto the UUID-based URLs could happen in follow-ups, but with the current architecture of this patch (UUID as separate routes rather than as aliases), I'm not yet clear on whether such follow-ups could be successfully implemented in patch releases, or if they'd need to be targeted for 8.3 only, and even then, how much of a pain that would end up being.
Any thoughts on this? Will we need those local tasks at some point, and if we will, then do we still think the architecture of UUID as a separate route is desirable?
Comment #133
effulgentsia commentedSorry folks. I discussed this with @alexpott, who committed this originally in #93 and tagged it as a beta target in #105, and we decided that despite that original commit, #132 is enough of a concern to keep this out of 8.2.x and finish it for 8.3.x instead. Thank you to everyone who worked hard on this, it's a great feature, and I look forward to it landing in 8.3 whenever it's ready.
Comment #134
dawehnerOne thing we could do is to provide a redirect to the other routes.
Comment #135
larowlanMy preference would to be to go back to the approach in #34 which was a processor.
We switched to actual routes based on @dawehner's review in #36 where we decided that the UUID regex meant a static pattern would mean there was no performance impact on a real route.
The other option is we add a local-task alter/deriver that duplicates any tasks that live on entity.{type}.canonical to also appear on entity.{type}.uuid routes - thoughts?
Comment #136
larowlanAlso, is there a reason why this was bunted to 8.3 without a chance/window to rectify whereas other issues that have beta target tag were given a chance to address concerns?
Comment #137
alexpott@larowlan we bunted to 8.3 because the issue is a significant and rather than do a rush fix or re-architecture we decided to take our time. There is only 1 beta target left and once that is done we plan to release the next beta and after that there shouldn't be anymore new features or tasks going in to the beta.
Comment #138
wim leersIMO this makes most sense.
Otherwise you also can end up with the exact same UI, but with two different URLs. This also means that e.g. conditionally placed blocks would need to be placed at two distinct URLs. Which has ecosystem consequences.
A simple redirect fixes that. Or am I missing something?
Comment #139
wim leersThis also has consequences for REST. Any entity that is referenced by a
entity:ENTITYTYPE/UUIDURI can also be resolved by REST clients. Also see #2577923: MenuLinkContent entities pointing to nodes are not deployable: LinkItem should have a "target_uuid" computed property.Comment #140
larowlanComment #141
acbramley commentedJust my 2c but I have to agree with #135, using a processor/redirect makes more sense to me rather than duplicating effort making (for example) node/{uuid} the same as node/{nid}
Comment #142
wim leersLet's get this issue going again, so we can put this behind us.
Here's a recap.
/node/[UUID]links in menus, which can be deployed across machines (unlike/node/[NID]). The inbound path processor then rewrote this to/node/[NID], which means the regular route+controller is used, and path-based matching like that used by blocks still works as expected. Finally, what's stored is UUID menu links, but they're rendered as "normal" menu links: creating a link to/node/[UUID]is still rendered as a link to/node/[NID]. The flaw: you can access/node/[UUID]and that would just work: as far as Drupal is concerned, you're at/node/[NID]. In other words: this violates the duplicate content rule: two distinct URLs serve identical content./node/[UUID], but rendering as/node/[NID], B) those who access/node/[UUID]directly are redirected to/node/[NID]and C) hence block placement etc still work as expected.I first wanted to agree with larowlan in #135, and the patch in #34 even still applies cleanly (!!!), but I did discover this one big flaw listed above. Hence the redirect approach seems the best candidate.
Comment #143
Crell commentedTo clarify #142: You're suggesting:
1) When generating outbound URLs, we still convert node/abc123 to just node/4, so we never OUTPUT uuid-based URLs.
2) If someone sends a uuid-based request anyway, we 301 redirect to node/4 (or its alias).
If so, that sounds like a good plan to me.
Comment #144
larowlanYeah, I think we're stuck with a redirect
Comment #145
wim leers@larowlan, do you have the time+interest to reroll this? I would provide reviews.
Comment #146
larowlaninterest √
time ?
this time of year lots of stuff going on outside, will see what I can do
Comment #147
acbramley commentedRerolling #129 to latest 8.2.x as the system update hooks conflicted.
One thing to note from the difference in #129 to #34 that may be of interest: I use a node/uuid path for the site front page so that I can have a homepage node to control the content, with #129 blocks and things that are set to display on work fine but not with #34
Comment #148
wim leers#147: can you please provide an interdiff? https://www.drupal.org/documentation/git/interdiff
Comment #149
acbramley commentedSorry, here you go
Comment #150
acbramley commentedAnother update hook collision :(
Comment #151
jibranComment #152
wim leersReuploading the patch in #150, because it was never tested by testbot.
Comment #154
wim leersRenaming
system_update_8203()tosystem_update_8300().Comment #156
wim leers#2842480: system_update_8203() is named incorrectly just landed, so now #154 must be done again, now moving from
system_update_8300tosystem_update_8301.Doing that first, then addressing the failure.
Comment #157
wim leersThe failure in #154 is because #2585899: HtmlResponseAttachmentsProcessor::processHtmlHeadLink produces invalid HTTP Link header landed since the last green test run, and it added a new test that we now also need to update.
Comment #158
wim leersComment #159
wim leersSo, in #142, I tried to get this back on the rails.
In #143, Crell summarized it as follows:
But as the fail in #154 and the fix in #157 are proving, we are outputting a UUID-based URL: in the
Linkheaders. Of course, that UUID-based URL would respond with a redirect.… except that the patch I've been rerolling to get to green is the WRONG PATCH, because @acbramley rerolled #129 in #147, rather than implementing what we discussed & agreed in #142 (me) + #143 (Crell) + #144 (larowlan).
Gaahhh!!!! I should've looked at the patches since #142 more closely before spending any time on it :(
So, I'm adding a
\Drupal\Core\Entity\Controller\EntityViewController::redirectUUidToCanonicalmethod, and am making the necessary corresponding rout e modifications to make this happen. ThatredirectUUidToCanonical()method is modeled after\Drupal\comment\Controller\CommentController::redirectNode().It seems this is unfortunately not yet passing because Views is apparently still incorrectly overriding the
entity.taxonomy_term.canonicalroute with its own controller. Or at least, that's what I conclude when I do the debugging of the exception that I'm getting, which looks like this:I'll let somebody else take it from here.
Comment #161
wim leersOops, I forgot a hunk.
This will still fail for the reasons I outlined in my previous comment.
Comment #166
acbramley commented@Wim Leers sorry, what did I do wrong?? #147 was a straight reroll of the previous patch to fix the update hook issue. The reason I didn't reroll the older patch with the newly agreed approach is because I had issues with it which are explained in #147...
Comment #167
wim leers@acbramley: no need to apologize, this is a super super super confusing issue! I didn't mean to blame you at all, sorry if that's how it came across. #142 basically said we need a hybrid of the different approaches we had had up until that point.
#159 then got that hybrid going.
Comment #168
dawehnerThis would not be flexible enough for jsonapi. I guess we would need to load the route and check somehow whether something needs a uuid. Not sure how to detect that though.
I'm wondering whether we should copy over the access checking of the normal entity somehow
Comment #169
wim leers#168.1: Perhaps we should not expand
Drupal/Core/ParamConverter/EntityConverter's capabilities, but instead add a new parameter converter. So that we have{node}and{node_uuid}, instead of just{node}that accepts both ID and UUID. Then it'd be trivial to also make this work for JSON API and other UUID-based link templates.Comment #170
damienmckenna@Wim Leers: Is that a decision the Entity subsystem maintainers should weigh in on?
Comment #171
dawehnerNot sure how you think this should work for the original problem this issue tried to solve: Linking to
/node/$uuidshould be possible. Therefore it has to be the same param converter. In the usecase of JSONAPI it would work to have two separate converters, but there is still no easy way to link to it.Comment #172
wim leersWhy?
We could add a
entity.<entity type ID.uuidroute in\Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider, because it's already$rel == 'uuid'anyway.Comment #173
dawehnerNote: We do that already. When we though use a different parameter name, like node_uuid, stuff like local tasks won't work anymore.
Comment #174
wim leersBut that's exactly what we want. We want
/node/<UUID>to redirect to/node/<ID>. See #142.Comment #175
gambryI came across this issue while a client requires content URLs not to be "guess-able". So disallowing the use of
/node/<ID>as ID is incremental and users can just decrease/increase its value. And the easiest solution seems to be using/node/<UUID>.But if I integrate the solution described from #142.4, so with the redirect, this won't work anymore.
I understand this issue original value is to be able to deploy links to content between environments without breaking them, but I can see obfuscating content paths as a good value too.
From #142.2:
The flaw exists anyway if you use multiple path aliases or whatever shows the same content. The fix for it is simply using the canonical URL meta tag which AFAIK is already on node and comments by default.
Ignore my comment if you don't think obfuscating the path is an additional value of using UUID instead of ID on paths, but generally I don't see why #142.2 was a bad approach.
Comment #176
geek-merlin#175: So you say the canonical-url metatag makes the redirect obsolete?
I'd say good news, as that redirect never felt really good imho.
Comment #177
berdir#175: Even if it would not be a redirect it wouldn't make Drupal actually *use* that route or prevent anymore from using node/ID. That is not the goal here, redirect or not.
IMHO, if your goal is to prevent access to node/ID, then this is not the right approach to do that. All you need for that are aliases (You could even make aliases the contain the UUID, that's trivial. Or anything else.) and a early request subscriber that denies access if the original URL before the alias resolver is node/ID.
Comment #178
gambry@Berdir , yeah I probably didn't make myself totally clear.
I found this issue while wondering 'Can I resolve an entity using its UUID?' and the work done so far solves the problem perfectly up to when it switched to redirect
/node/<UUID>to/node/<NID>.Redirecting UUID path --> NID path will make impossible to use just plain
/node/<UUID>URLs.So 'Can I resolve an entity using its UUID?' is answered by 'Kind of. Visiting /node/UUID will redirect to /node/NID and that will resolve your entity'.
My real question was if we do need to redirect. #142.2 refers to a "In other words: this violates the duplicate content rule: two distinct URLs serve identical content." flaw which is a problem taken care by the canonical metatag already existing on nodes.
Also @larowlan on #135 suggested to go back to original - without redirect - solution in #34.
[[P.S.: I personally solved my issue extending EntityConverter as per suggested by patch in here, but I haven't though about aliases. Thanks for the hint!]]
Comment #179
grimreaperHello,
Here is a reroll the patch from comment #161 against branch 8.3.x. I was not able to make an interdiff because patch from comment #161 did not apply anymore.
If I understood the comments it is this patch that needs to pass. If someone can confirm, thanks.
I have changed arrays into short array syntax and tried to update some code in the tests that
I had a problem updating come code in the tests because of properties that changed. I have commented using // the parts I was not able to port.
I have not tested the patch yet.
Comment #180
grimreaperAfter applying the patch, if I try to go to node/[UUID], I am redirected to node/[NID]. That is ok.
But the UUID does not seems to be stored in case of a link field, it is still the ID.
And I have the following error when displaying a taxonomy term field value:
Comment #181
wim leers#175: security through obscurity is never a good idea. If your client requirement is like that, then I suggest instead implementing Entity Access to disallow access. And if a 403 is already divulging information, then map 403s to 404s. Done.
Or… what @Berdir described in #177.
#178: the "duplicate content" I wrote was not from an SEO POV, but from a Drupal POV: we simply shouldn't have two routes serving the exact same content. This has consequences beyond SEO. An example: a block is made visible only for
/node/5… but then if you access it via/node/<UUID for node 5>, then you don't see the block. Clearly dangerous.#180: I already explained that failure at the bottom of #159: this is a long-standing bug in Views.
Comment #182
wim leersI think that that Views bug is being fixed in #2449143: REST views specify HTML as a possible request format, so if there is a "regular" HTML view on the same path, it will serve JSON.
Comment #183
michaellander commentedSo the JSONAPI module currently requires the bundle to request a resource(i.e. /jsonapi/node/article/), and I'm curious if that should be considered here. For example, If I'm moving some link field data between two sites and would like to lookup the related entity from the link, it would be great to have all the information needed for the subsequent request. This probably opens a whole other can of worms...
Comment #184
grimreaperHello,
@Wim Leers: I tried the patch from comment 179 and #2449143-123: REST views specify HTML as a possible request format, so if there is a "regular" HTML view on the same path, it will serve JSON after applying it manually because it does not apply on Drupal 8.3.2.
And I still have the Views error.
I am trying to use UUID in link field in JSON API without having to rely on this issue. I wrote a patch to alter the display of link fields #2883437: Transform link field value to use UUID but now I need to handle the deserialization.
Comment #186
reshma_n commentedRerolling #157 against latest 8.3.x. The reason I didn't reroll against the newer patch (hybrid approach) is that it had issues.
Comment #187
wim leersI think this ought to be major given its impact/value.
Comment #189
dawehnerI'm wondering whether we could split up this quite big patch into two bits:
This way we could quickly focus on the first bit, which should be easier to get done. Other issues like #2878463: [PP-1] Define a JSON API link relation for entities could leverage it.
Comment #190
wim leers#189++, that would be lovely.
Comment #191
wim leersThis is actively blocking #2878463: [PP-1] Define a JSON API link relation for entities.
Comment #192
mglamanFor #189 would that then just be the changes
Would we also target the Node route provider and UserRouteProvider.php for first half of the patch? Or first half is generic implementation, last half is per-entity and other menu support.
Or everything in patch sans things relating to DefaultMenuLinkTreeManipulatorsTest
Comment #193
valthebaldRerolling patch from #183 against the latest 8.6.x
Comment #195
valthebaldRe-adding missing parts
Comment #197
valthebaldComment #199
pwolanin commentedI found the draft change notice and disappointed this is not actually working yet.
I think dawehner is right - this patch has way too much scope. The views, menu link, and other support seem like they are not essential.
Also the issue summary is not clear as to whether there is a compelling reason we have to use the same path as the canonical path.
It would be a lot easier to make this work if the path was like
node/{node}/uuidoruuid/node/{node}or whatever variant of that makes sense.Comment #200
geek-merlin> It would be a lot easier to make this work if the path was like node/{node}/uuid or uuid/node/{node} or whatever variant of that makes sense.
Strong +1 for that. So it's clear from the route name what is requested.
Comment #201
daffie commentedIf all UUIDs are unique, would it not be better to use a generic path like:
uuid/{uuid}?Comment #202
mglamanYou still need to know the type, so you know which table.
I was really hoping we could get core to use node/{uuid} so we can move to avoiding database specific identifiers in entity canonical routes.
Comment #203
wim leers@pwolanin If you put your shoulders under this one, I'm sure that we could get this done very soon :) Especially look at the recap I wrote in #142. I ran out of steam after #161/have had higher priorities to deal with.
I don't understand this, can you clarify?
Comment #204
mglamanSorry, I'll clarify.
I was hoping we could easily use /node/52 and /node/1111-111-111-122 to retrieve the same node. Instead of what is being proposed to have a specific route for retrieving via UUID. See #199's proposal for a UUID route.
Comment #205
wim leersRight. I think I agree. See #174 and #142.
@dawehner proposed in #189 to split the patch in routing vs menu linking parts. The routing portion of the patch actually already does what you say, @mglaman, and matches what's in #174/#142. It's only #199 that's proposing a new path pattern for the route.
Comment #206
geek-merlin> I was hoping we could easily use /node/52 and /node/1111-111-111-122 to retrieve the same node.
Just realizing: For this we would need a release note like:
"If you use entities with string IDs, as a site architect you must ensure that the ID will never clash with a UUID.
This restriction is mitigated by the fact that such a clash is quite unlikely, and aggravated by the fact that such a clash will be extremely unexpected and hard to debug."
Comment #207
geek-merlinAlso note that loading an entity with string IDs will take 2 queries in the general case, if the string ID can be an ID or UUID.
Comment #208
pwolanin commentedI don't understand the use case for loading at the same path - are you somehow not aware of what kind of id (int vs uuid) that you have?
Comment #209
valthebaldHere's the routing portion of patch (menu and view parts removed). UUID paths still match canonical ones, although I too think there should be different pattern (between 2 suggestions in #109 I'd choose `/uuid/{entity_type}/{uuid}`
Is there an agreement on this?
Comment #211
valthebaldOops, forgot to add `use` in UseRouteProvider.php
Comment #213
valthebaldRemove also link templates (main reason for failing tests)
Comment #215
valthebaldRemove also menu link access test change, as this part will be spun off
Comment #216
pwolanin commentedSo looks like this is still using the same paths in the latest patch?
Comment #217
valthebald@pwolanin: I wanted to know the reasoning to use the same path. If there is no one, I can switch uuid paths to have different pattern
Comment #218
valthebaldChanging UUID paths to pattern `/uuid/{entity_type}/{entity}`
Comment #219
valthebaldUpdate issue description
Comment #220
wim leersPlease read the prior discussion on the issue. I even pointed to the specifically relevant comments in #205.
Quoting #142.3:
That's why you don't want separate paths/URLs.
Comment #221
valthebald@Wim Leers: I thought that this flaw is addressed by redirecting UUID path to canonical one, as you wrote in #142 .4
Comment #222
pwolanin commentedIs the end goal to redirect to the canonical path or serve the entity whether an ID or UUID is provided?
@Wim Leers - it seems like this is going to break things like path aliases either way?
Comment #223
geek-merlinIt is like stated in #221 iand #142:
We are just to sort out what the actual uuid path should be.
a) /[ENTITY_TYPE_ID]/[UUID] might lead to clashes, so we might use b) /uuid/[ENTITY_TYPE_ID]/[UUID] of even c) /uuid/[UUID] (as it's a UUID).
I looked in the D7 uuid module, it uses c) to redirect to the canonical route (like we want it here), but b) may have advantages too.
Comment #224
acbramley commentedWe can't do that as we need to know the entity_type when looking up by uuid.
Comment #225
vijaycs85+1 to keep node/[uuid] as this could happen when we get the circular dependency on the default content or replication, we can fall back to uuid
Comment #226
valthebaldhttps://www.drupal.org/files/issues/2018-05-06/2353611-215.patch is keeping node/{uuid} pattern (still applies and passes)
Comment #227
mahtab_alam commentedComment #228
valthebald@mahtab_alam can you provide an interdiff please? How your patch is different from previous?
Comment #230
valthebaldComment #231
ricovandevin commentedWe have tried the patch from #215 but it seems that the "node" parameter in de request does not upcasted to the actual Node object when doing a request to /node/[UUID]. The parameter propagates as a string (being the UUID) and that breaks the entity access check. The check results in a "neutral" and since there is no other access check (in our case) that results in a "allowed" we get a access denied in the end.
Update the difference described below is actually originating from custom code in the project.
When I compare the Route objects as stored in the router table I notice that the converter is present for the canonical route but not for the uuid route. In fact the complete parameters section is missing for the uuid route.
Canonical:
C:31:"Symfony\Component\Routing\Route":1164:{a:9:{s:4:"path";s:12:"/node/{node}";s:4:"host";s:0:"";s:8:"defaults";a:2:{s:11:"_controller";s:58:"Drupal\kankernl_library\Controller\LibraryController::view";s:15:"_title_callback";s:49:"\Drupal\node\Controller\NodeViewController::title";}s:12:"requirements";a:2:{s:4:"node";s:3:"\d+";s:14:"_entity_access";s:9:"node.view";}s:7:"options";a:3:{s:14:"compiler_class";s:34:"\Drupal\Core\Routing\RouteCompiler";s:10:"parameters";a:1:{s:4:"node";a:2:{s:4:"type";s:11:"entity:node";s:9:"converter";s:21:"paramconverter.entity";}}s:14:"_access_checks";a:1:{i:0;s:19:"access_check.entity";}}s:7:"schemes";a:0:{}s:7:"methods";a:2:{i:0;s:3:"GET";i:1;s:4:"POST";}s:9:"condition";s:0:"";s:8:"compiled";C:33:"Drupal\Core\Routing\CompiledRoute":425:{a:11:{s:4:"vars";a:1:{i:0;s:4:"node";}s:11:"path_prefix";s:0:"";s:10:"path_regex";s:25:"#^/node/(?P<node>\d+)$#sD";s:11:"path_tokens";a:2:{i:0;a:4:{i:0;s:8:"variable";i:1;s:1:"/";i:2;s:3:"\d+";i:3;s:4:"node";}i:1;a:2:{i:0;s:4:"text";i:1;s:5:"/node";}}s:9:"path_vars";a:1:{i:0;s:4:"node";}s:10:"host_regex";N;s:11:"host_tokens";a:0:{}s:9:"host_vars";a:0:{}s:3:"fit";i:2;s:14:"patternOutline";s:7:"/node/%";s:8:"numParts";i:2;}}}}Uuid:
C:31:"Symfony\Component\Routing\Route":1101:{a:9:{s:4:"path";s:12:"/node/{node}";s:4:"host";s:0:"";s:8:"defaults";a:1:{s:11:"_controller";s:75:"Drupal\Core\Entity\Controller\EntityViewController::redirectUUidToCanonical";}s:12:"requirements";a:2:{s:4:"node";s:41:"[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}";s:14:"_entity_access";s:9:"node.view";}s:7:"options";a:2:{s:14:"compiler_class";s:34:"\Drupal\Core\Routing\RouteCompiler";s:14:"_access_checks";a:1:{i:0;s:19:"access_check.entity";}}s:7:"schemes";a:0:{}s:7:"methods";a:2:{i:0;s:3:"GET";i:1;s:4:"POST";}s:9:"condition";s:0:"";s:8:"compiled";C:33:"Drupal\Core\Routing\CompiledRoute":502:{a:11:{s:4:"vars";a:1:{i:0;s:4:"node";}s:11:"path_prefix";s:0:"";s:10:"path_regex";s:63:"#^/node/(?P<node>[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12})$#sD";s:11:"path_tokens";a:2:{i:0;a:4:{i:0;s:8:"variable";i:1;s:1:"/";i:2;s:41:"[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}";i:3;s:4:"node";}i:1;a:2:{i:0;s:4:"text";i:1;s:5:"/node";}}s:9:"path_vars";a:1:{i:0;s:4:"node";}s:10:"host_regex";N;s:11:"host_tokens";a:0:{}s:9:"host_vars";a:0:{}s:3:"fit";i:2;s:14:"patternOutline";s:7:"/node/%";s:8:"numParts";i:2;}}}}Comment #232
ricovandevin commentedThe problem seems to be a mismatch in parameter names. The entity.node.uuid defines a parameter with the name node. The EntityViewController::redirectUUidToCanonical() method expects a parameter with the name $entity. This causes EntityResolverManager::setParametersFromReflection() to look for a parameter with the name entity in the route. Since the route does not provide a default for _entity_view or _entity_form either the node parameter can not be upcasted for the entity.node.uuid route.
When I add a redirectUUidToCanonical() method to the NodeViewController class with a parameter $node that just returns the result of the same method on the parent class (being EntityViewController) and I change the controller name for the entity.node.uuid route in the NodeRouteProvider to NodeViewController all works well.
Comment #233
ricovandevin commentedUpdated patch based on #215 attached.
Comment #234
gabesulliceGood catch @ricovandevin!
s/UUid/Uuid/g
Comment #235
manuel garcia commentedComment #236
claudiu.cristeaI think we should use different controllers for different routes. I'm not a fan of dropping everything in a single controller. Why loading a lot of useless methods for a given route?EDIT: Sorry, this is the standard entity view controller. Ignore my comment.Probably
$entity_type->hasKey('uuid')is more correct semantically?Well, I'm really concerned about this because smells like an assumption. I'm working on a project where the UUID is not following this pattern. Our UUIDs are in fact URIs, which are universally unique, at least in *this* internet. Note that the UUID generation is a service that can be swapped. A project could imagine its own UUID pattern. For this reason I'm proposing that we let the UUID generator to decide if the UUID is valid. This means that we add a new method
\Drupal\Component\Uuid\UuidInterface::isValid()(or similar).EDIT: An alternative would be to switch to a different route path pattern.
???? :)
s/taxonomy_term/entity_test
Setting to NR especially to discuss 3.
Comment #237
vijaycs85Why do we need this method anyway? not having it eventually call the parent's
redirectUuidToCanonical()Comment #238
claudiu.cristeaWhy not the the other way around? Fix first the UUID validation in a new issue and postpone this on that.
Comment #239
Marishka_ commentedTesting the patch from #235, we're seeing buggy behaviour when referencing the homepage by uuid.
We have a node with alias /home which is set as the site homepage by uuid link (the site front page is set to /node/d411fb13-5266-4e6e-8460-1a6bc917f9e6 ).
Going to https://www.mysite.com/ redirects to http://www.mysite.com/home which breaks because of the redirect to http. (Yes this can be worked around in other ways, but I don't believe it's desirable behaviour).
What I'd expect is that when the homepage is set via uuid link, https://www.mysite.com/ should load https://www.mysite.com/ (no URL change) showing the homepage specified.
Comment #240
eelkeblokThis patch also seems to cause any URL that should normally generate a 404 to redirect to the front page (which is probably related to the behaviour reported in #239).
Edit: To clarify, the observed behaviour is connected to the fact I tried using this patch to set the 404 page based on a UUID URL. I do think this is an important use case for this functionality, though.
Comment #241
eelkeblokSo, AFAICT, the approach suggested in #142 was actually never implemented, i.e. the latest patch still "only" does the redirecting. When Drupal decides it needs to delegate the 404 handling to a custom route, it executes that route which then results in a redirect (I think it is actually a little less clear cut than that, because I ended up with a 302... 😕). This would probably also at least partially explain #239.
I did a quick and dirty merge of the changes from #34, excluding the changes in menu_ui (i.e. the interdiff is basically #34 rerolled). The project I am testing this on also includes Redirect module, but I am seeing the exact behaviour I would like now:
* Configuring the 404 page with a node/{uuid} URL keeps the URL in the address bar, gives a 404 status code, and actually displays the page I wanted (i.e. just as if I would have used the regular nid-url).
* Directly visiting the /node/{uuid} URL redirects me to the path alias. At least one part of this is down to redirect module, undoubtedly. I'm not sure if the redirect code from this patch still plays a part in that.
I would like to explore a few things:
#236 and #237 still need to be processed.
Comment #242
eelkeblokThis is a reroll against 8.7.x.
Comment #243
eelkeblokI updated the issue summary with the use cases I can think of spelled out.
Comment #244
eelkeblokComment #245
eelkeblokComment #246
eelkeblokI've done some testing with the combined patch. It looks like the redirecting is completely masked by the path processor. Which is actually fine, I think, because Drupal core correctly sets a canonical meta tag, which is set to the alias when one exists, or to the numeric node ID when it doesn't. This is also true when viewing the node through the UUID URL.
Going through the "acceptance criteria" I added to the summary yesterday:
Check.
Check. (I did not test the 403 page, but I have no reason to believe that is any different from the 404).
Umm... Not exactly. However, when you use either the alias or the numeric ID as the condition, the condition does trigger when accessing the page through the UUID, so this might be something that could be done in a follow-up issue.
See above. Core already properly sets a canonical meta tag. Ideally, I do believe a site should issue redirects to make sure content is every accessed through a single URL, but from an SEO point of view, I don't think this extra URL based on the UUID actually makes the situation any worse; search engines will be directed to the "one true" URL using the meta tag (as well as them all resolving to that same "one true" URL when rendering in e.g. a menu). Redirect module can still handle the actual redirecting side of things, as it does now (and if we feel strongly enough, maybe the redirecting can be added to core, but I don't think it needs to be in the scope of this change).
So, that leaves the following tasks:
* Remove code to handle redirection.
* Process remaining feedback from #236 and #237.
Comment #247
eelkeblokSo let's see if we still have green tests. I did process the remaining tasks from my previous comment. The points from 236 and 237 were rendered obsolete by the removal of the redirects.
However, while going through the code, I did realise something. One, the node entity did not actually have a uuid link template, so I guess that could not actually work..? Also, it looks like we have some competing assumptions. On the one hand, links were assumed to be {entity-type}/{uuid}, on the other hand, the canonical link template was being used. This is often the same, but not always (e.g. taxonomy term). Because the route for the redirecting is completely gone now, there are no competing assumptions any more, but we still do have an inconsistency due to it; the path processor will accept taxonomy_term/{uuid}, not taxonomy/term/{uuid}. I guess this is bad DX.
Also, we are not actually meeting the point from the summary where you could call $entity->toUrl('uuid') (I think we weren't in at least the last few versions of the patch, mind you). This could also be a nice candidate for a follow-up, maybe..?
So, remaining tasks:
* Change path processor to base its comparison on canonical route templates for entity types instead of the entity type itself.
* Add some logic to Entity::toUrl to handle $rel='uuid', but base it on the canonical link template (or do this in a follow-up?)
Or, if we really do want to stick to a separate uuid link template, the first point becomes basing the comparison on that instead of the canonical one.
Comment #248
eelkeblokFixing the left-over test for the UUID route, fixing some code style issues.
Remaining tasks from the previous comment still open, but would like some feedback so marking as needs review anyway.
Edit: Whoops, gave the interdiff a .patch extension...
Comment #250
eelkeblokComment #252
heddnThis is looking good. One small tangible nit below.
Before we get there, I have a small requirement on a certain project to /only/ allow nodes, etc be accessible via the UUID url. And no redirect to/from the canonical URL. Meaning, /node/1 should 404 while /node/1111-222-3333 returns a 200. I don't know that this small use case is all that common, but the current solution also doesn't seem to support it very much either. I went through the last few issue comments to see if this was discussed but didn't see it. Can we have the IS updated to explain the rational for the current approach and the alternatives that were discarded?
Tagging NW for IS update and small nit.
I don't think this is needed. It doesn't change anything.
Comment #253
heddnHmm, seems like what I mentioned in my last comment was discussed in #177, #178 and #181.
Comment #254
simeYes you could do it either with aliases out-of-the-box, or some code to rewrite outbound URLs @heddn. I think we are ok on that front.
Comment #255
cytherion commentedLooking at this issue while at DrupalCon Seattle: patch in #248 fails to apply (8.8.0-dev)
error: patch failed: core/lib/Drupal/Core/Entity/Entity.php:318
error: core/lib/Drupal/Core/Entity/Entity.php: patch does not apply
A few deprecation notes:
Entity.php is deprecated in favour of EntityBase per the comments in Entity.php (8.8.0-dev):
@deprecated in Drupal 8.7.0 and will be removed in Drupal 9.0.0. Use \Drupal\Core\Entity\EntityBase instead.
getMock() is deprecated and should be replaced with createMock() or getMockBuilder() per https://www.drupal.org/project/drupal/issues/2929133
Comment #256
mrweiner commentedRe-rolling #248 for 8.8.x. Moved Entity.php updates to apply to EntityBase.php
Comment #257
JayBeeDutch commentedThis discussion is now going on for about 5 years.
I'm a totally newbie and haven no experience as an expert in Drupal and PHP. However I'm rather logical. In the response of a JSONAPI call when I look at the href of a relationship I expect the url to get the information of that relation. If I inspect the response the given url is a mixture of the object itself and the url for the relation, i.e. the type/bundle of the relation is given together with the uuid of the object itself.
I expect a url to get/read the relation with JSONAPI. For example a taxonomy term with uuid "tt" belongs to vocabulary with uuid "vv". So the reference should be "http//someserver/jsonapi/vocabulary/vocabulary/vv", now it is "http//someserver/vocabulary/vocabulary/tt?andsomemore"
That doesn't make sense.
Please make clear the "self" and the "relation" url's
A part of the practice in my case:
"data": [
{
"type": "taxonomy_term--blog_categories",
"id": "d8687362-479d-46f4-b4f3-a37959f85a0a",
"attributes": {
"drupal_internal__tid": 2,
"drupal_internal__revision_id": 1,
"langcode": "nl",
"revision_created": "2019-05-05T15:21:07+00:00",
"revision_log_message": "Blog Categories aangemaakt",
"status": true,
"name": "Basis",
"description": null,
"weight": 0,
"changed": "2016-12-02T11:02:11+00:00",
"default_langcode": true,
"revision_translation_affected": true,
"metatag": null,
"path": {
"alias": "\/blog\/categories\/basis",
"pid": 89,
"langcode": "nl"
},
"rh_action": null,
"rh_redirect": null,
"rh_redirect_response": null
},
"relationships": {
"vid": {
"data": {
"type": "taxonomy_vocabulary--taxonomy_vocabulary",
"id": "c322c2f8-fc8d-4148-bf74-5ca1cd7c9f6f"
},
"links": {
"self": {
** this should be the vocabulary???? **
"href": "http:\/\/localhost\/actual\/genesis\/docroot\/jsonapi\/taxonomy_term\/blog_categories\/d8687362-479d-46f4-b4f3-a37959f85a0a\/relationships\/vid"
},
"related": {
** related?? To what?? The uuid doesn't make sense, it's the term, not the vocabulary
"href": "http:\/\/localhost\/actual\/genesis\/docroot\/jsonapi\/taxonomy_term\/blog_categories\/d8687362-479d-46f4-b4f3-a37959f85a0a\/vid"
}
}
Comment #258
eelkeblok@JayBeeDutch I am having some trouble understanding how your comment fits in with the current issue, namely allowing a UUID-based URL to access content in addition to the current "local" ID-based one as well as any aliases applying to the URL. Did you mean to comment in a different issue?
@heddn is your use case addressed by #254? I'm wondering whether setting up an alias-scheme using UUIDs wouldn't actually clash with the functionality in this patch. What would you propose otherwise? Can you formulate your requirement in a sentence that would fit in with the other acceptance criteria?
Comment #260
erik frèrejeanJust a small nitpick, the patch in #256 introduces a coding standards violation.
Comment #262
erik frèrejeanReroll of the patch, the tests used deprecated
\Drupal\Tests\PhpunitCompatibilityTrait::getMock()method.Comment #263
erik frèrejeanComment #264
aaronmchaleAre the remaining tasks in the issue summary up to date?
I'm also not totally sure how I feel about this just automatically being on for every entity type, I'm not against it, it just makes me feel a little uneasy - for example, if I'm creating an entity type, I expect by default for there to be no assumptions, as in, I have full control over how people interact with the entity, in this case that relates to the link templates, maybe (and this really is just me thinking aloud) this should rely on whether a "cononical-uuid" link template is set so handle it in
DefaultHtmlRouteProvider.Like I said, I'm not 100% sure how I feel about this, will keep thinking on it, but that's my gut feeling above.
Comment #265
dawehnerFirst I tried to update the issue summary with what is in the patch.
I do have one question about this patch: Both the UUID status key and the link template will be optional with this patch.
Given that I'm wondering whether it would be helpful to have some form of checking for those. I know the CR puts this into the calling code, but the PR right now would produce invalid URLs.
One additional question I had: Do we have to worry due to a potential usecase of an existing link template called `uuid` but not actually using UUIDS? At least in contrib this seems not be the case,
see http://codcontrib.hank.vps-private.net/search?text=uuid+%3D+%22&filename=
This seems an unnecessary change :)
Comment #266
danchadwick commentedThis implementation has an unfortunate characteristic, which I'd call a flaw, in that it only applies to paths of the form ENTITY_TYPE/ENTITY_UUID. If a custom module uses entities in other paths, UUIDs will not be supported.
In my case, I have a path
/logbook/{user}for which I'd like UUID support. I simply wrote a ParamConverter for this and I'm wondering if perhapsDrupal\Core\ParamConverter\EntityConvertermight be the place to make UUIDs happen.Comment #267
eelkeblokThis is actually still having an issue with at least using the UUID as the front page. The user will be redirected to the alias of the page. This is on a site with redirect module enabled, although the difference in behaviour for entering a UUID-based URL vs. a numeric URL in the frontpage field (in the former case, the URL is not changed, whereas in the latter case, the URL is converted to the alias when displaying) leads me to be believe something else is still up.
@DanChadwick Using the paramconverter has been tried before, although I can't recall why that was abandoned. You can read up on it at the start of the issue.
Comment #269
colanNot yet, but we should be able to. I think that's ultimately where we want to go, and we shouldn't let the current architecture prevent it. Let's wait until the following are done (although maybe the second one can be done in parallel):
We can then have
/entity/UUIDredirect to the canonical/node/NIDhere, and afterwards, say in D10 via #1726734: Replace serial entity IDs with UUIDs in URLs, or even globally?, we can swap those so that/entity/UUIDis canonical, and/node/NIDredirects to it.Thoughts?
Comment #270
colanComment #271
sime#3157880: Determine where entities are stored without knowing their types
at comment 269 should be
#2690747: [PLAN] Create an index of UUIDs
and I'm adding it as related.
Comment #272
colanGood catch! Updated.
Comment #275
frobWhat is this issue waiting on?
Comment #276
norman.lolYour contribution.
Comment #277
frobThank you but I was thinking of something a bit more specific. ;)
According to the IS this issue needs testing of use-cases, but according to #270 the status is Postponed and not Needs Review. Are we waiting till #2690747: #3157869 are done? #2690747: [PLAN] Create an index of UUIDs looks related but I am not sure why #3157869: Store UUIDs in configuration instead of entity IDs is required.
Looks like #2690747: [PLAN] Create an index of UUIDs is stymied should this plan be re-evaluated based on that?
Comment #280
ro-no-lo commentedAfter 8 years of back and forth would it not be better to put that functionality into a module put it out into the wild and when the user base has grown and fixed everything merge it into core?
But it could be used already.
Comment #281
ro-no-lo commentedA note for everyone looking for a way to load entities by uuid. Currently Drupal has a module which can do that. If you enable the
jsonapimodule, you can load all kinds of entities by uuid. I tried it only a bit, but theEntityUuidConverter.phpis a good start to check if your use case is supported.Create your route like this:
In your Controller you can write the action like normal.
Note: As long as there are no changes in the
jsonapimodule. This should work with entities just fine. But even in the converter class it states that it will be dropped when THIS very issue here is solved.Comment #282
mxr576I have read half of the conversation and tried to update the issue summary.
Personally, I fully agree with #266 and therefore #262 is not the right solution for the problem. I also with #271 that #2690747: [PLAN] Create an index of UUIDs is a dependency of this task if we would like to avoid depending/guessing entity_type anyhow when the up-casting happens.
Comment #285
c-logemannThis Issue started with this text by @dawehner:
> It would be great to provide URLs with UUIDs in their so you can link to them.
> For poormans menu staging you could use menu_link_config and store refs to UUIDs, like uuid/{entity_type}/{uuid}
which page does a 301 redirect to the actual entity page.
I think this issue should stay on focus with the "{entity_type}/{uuid}" plan. Getting the entity_type removed from the urls is interesting but I think this should move to another issue including all the problems and dependencies like #2690747: [PLAN] Create an index of UUIDs.
Because of symfony and ParamConverter etc. there are many possibilities to fix things in contrib. So I just decided to solve things there. At first I will concentrate on user entities (e.g. "uuid/user/{uuid}") because I need a solution where users should not know their serial uid. After doing some tests today I think this is basically not complicated.
Especially for everything related to nodes, aliases, and redirects things are more complicated. And that's another reason to stay focused on {entity_type} in paths. For me the user part is the most important thing because I don't want to replace the user entity. Since we can create our own entity types with nearly everything a node can do this would be easier. And on the project where I need user/uuid paths I haven't decided yet if I really want to use nodes.
(I will add a comment here when there is a project I will add my solutions.)
Comment #286
didebruComment #287
vsujeetkumar commentedRe-roll patch created for 11.x.
Comment #288
vsujeetkumar commentedFixed the CCF issue, Please have a look.
Comment #289
vsujeetkumar commentedFixed the failed test cases.
Comment #290
c-logemannThanks @vsujeetkumar for pushing this forward/keeping patch compatible.
I removed Tasks from issue which are not on focus of this issue:
Resolve #2690747: [PLAN] Create an index of UUIDsAdapt path processor that can up-cast an {uuid} anywhere in an URL without needing to know the actual entity typeComment #291
c-logemannI'm currently working on a small symfony only project and discovered that it's possible to define multiple routes on an identical path and tested that Drupal 10.3 is compatible with this. For example this documetation:
https://symfony.com/doc/current/routing.html#parameters-validation
I tested the last patch and was wondering why it's working so I found this in the patch code:
It's interesting that it's working but with this solution we loose the benefit of routing information and debugging etc. I like the idea to just disable integer routes in custom code to only use uuids.
If we just use an entity_uuid param converter it is possible to use the same controllers for all entity paths e.g. "/user/{user}/edit" with a route 'user.uuid_edit'
I also want to make it possible to avoid user (int) ids in password reset paths where currently {uid} is used. But this maybe something for contrib.
Comment #292
c-logemannI try to improve in direction of second route as described above.
Comment #293
c-logemannBefore I start with coding want to add some additional comments after thinking about two routes which allows several thinks like the described identical scheme which is now possible with symfony.
Using two route definitions for each involved entity types makes it possible to realize many things like different access and also different routes. We can also introduce switches to enable uuid Routes of core only if somebody wants. And if somebody want the additional uuid route just as a redirect or with a path pattern like /uuid/user/{uuid}" this can be solved separately in additional code/contrib/custom code etc. So it's possible to solve seo concerns with robots.txt is possible.
In my personal opinion, it's currently a big disadvantage of Drupal that it's not possible to avoid serial IDs especially for users. At any other place I can avoid this easier e.g with not using node and other core entities. The reason why I want to avoid this that I think this is very important for situations when you run a web application where others should not see how many content entities are generated e.g. users, shop carts, issue tickets, mails etc. This gives competitor organizations and persons too much information not everyone likes to share. This is maybe a reason why companies and other organizations didn't choose Drupal.
On the the other side brings a uuid only strategy lots of possibilities to export, archive, re-import or import elsewhere of content without dealing with complex redirection data.
Both areas are my current motivation. Beside users I have already solved everything with custom entities and the wonderful module entity_reference_uuid. But it would be fine to have something more in core like an official uuid param converter. I know Drupal\jsonapi\ParamConverter and maybe start to use this at first.
Comment #294
murzBy the way, loading entities by UUID is not cached, here is the issue #3308877: Add static cache for loadEntityByUuid function to store uuid-id pairs in memory
Comment #295
c-logemann@murz Thanks for the input.
Comment #296
c-logemannI did some research of the current code and the actual patch. I still like to have an uuid everywhere strategy including revision routes. But currently the serial id strategy is deep integrated in a dynamical way. So a complete new strategy especially as dual solution ha a high complexity. So I think this should be postponed until there is more interest and some discussion and decision by core maintainers.
Meanwhile I will solve the user uuid situation in contrib and just created a new project for this: U3ID. With the U3ID module I can present a prove of concept and maybe something which can move partially to core in future.
I will try to test the current patch against the the dual route concept ASAP on path /user/{user|u3id_user} if there is a conflict which think it will be. Maybe there are other custom solutions out there based on additional routes which can be affected by the PathProcessor solution of the current patch.
Comment #297
andypostComment #298
c-logemannI created additional routes for /user/{uuid} and /user/{uuid}/edit in the u3id module and published already:
https://git.drupalcode.org/project/u3id
1. This is working fine.
2. The pathprocessing from actual patch makes it impossible for such clean route solution. So I strongly recommend to not commit for core. I currently even not recommend to not move to contrib or with add a warning for risks of breaking other code.
There are lot's of concerns against a pure uuid strategy as I read here: #1726734: Replace serial entity IDs with UUIDs in URLs, or even globally?
For getting forward I suggest to focus on a a minimal improvement:
1. First of all we should provide an entity_uuid ParamConverter. For u3id I copied of the core jsonapi: #3310170: Use UUID as entity ID
2. Following the initial feature request we can just provide a possibility to access entities based on additional uuid route configurations.
3. Per default we can just do redirections and introduce settings.php options to change behavior to an entity view.
Everything else should be postponed for core until there is a larger support for more uuid in core routes. I'm currently fine with my contrib project u3id and already solved the problem of rendering the serial uid in the canonical html link with replacing the entity view controller and use now the uuid path.
Comment #299
wim leers#3310170: Use UUID as entity ID just landed. Time to reconsider this? 😊
Comment #302
xjmAdding credits for triage from #105 (outdated though it is now).