Closed (won't fix)
Project:
Drupal core
Version:
9.4.x-dev
Component:
entity system
Priority:
Normal
Category:
Task
Assigned:
Unassigned
Issue tags:
Reporter:
Created:
7 Jun 2014 at 16:50 UTC
Updated:
25 Feb 2022 at 10:50 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #2
Crell commentedMany of the remaining issues are caused by using a simple string check for finding link elements in tests. The fix is to switch to the new cssSelect() method. Will return to this.
Comment #3
Crell commentedThis still should be done, but the above patch is completely not relevant anymore. I believe this is also 8.1-safe unless someone wants to do it sooner. It probably needs an alter hook or something now.
Comment #6
Crell commentedAdding link (no pun intended).
Comment #8
wim leersThis is as straight a rebase as is possible.
This change is omitted in this rebase, since this route is now defined in
NodeRouteProviderand will require additional changes.See next comment/patch.
Comment #9
wim leersBetter title.
Comment #10
wim leersSo the route change mentioned in #8 can no longer be done in the same way. That route is now being defined in
\Drupal\node\Entity\NodeRouteProvider::getRoutes()and looks like this:So we can't do what this patch is doing: move away from
NodeViewcontroller::view()to_entity_view: 'node.full'. Or can we?Turns out we can!
NodeViewController::title()is doing the functional equivalent of the default title callback that\Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider::getCanonicalRoute()sets:\Drupal\Core\Entity\Controller\EntityController::title()does effectively the same.NodeViewController::view()just callsEntityViewController::view()… and then just adds the link relations. That's all it does.In other words: it's trivial to move the link relation logic out of
NodeViewControllerand intoEntityViewController… or potentially a subscriber, like this patch is currently doing.And in fact, simply moving the logic from
NodeViewControllertoEntityViewControllerseems to be the most prudent approach. It means no extra overhead (unlike an event subscriber). It means less BC break (because$build['#attached']still contains the links). And it's the simplest approach.So this:
NodeRouteProviderextendDefaultHtmlRouteProviderNodeViewControllertoEntityViewControllerComment #11
wim leerscore/modules/node/src/Controller/NodeViewController.phpcan now simply be removed.Comment #12
wim leersThe
link_relationship_subscriberservice definition and its code (core/lib/Drupal/Core/EventSubscriber/LinkRelationshipSubscriber.php) can now also simply be removed.Comment #13
wim leersUserRouteProvideralso isn't inheriting fromDefaultHtmlRouteProvider, and should be. It'll then be consistent withNodeRouteProvider.Comment #15
wim leersAnd then some final cleanup.
This still needs tests though.
Comment #21
Crell commentedWim: Whee!
My one concern with this approach is that EntityViewController may be called at all sorts of times other than the entity canonical URL. Eg, make a View of nodes and show the "full" view mode, and poof, you now have all the links for all nodes showing on a single view page, which is definitely wrong.
We need a way to add links only if the page being viewed is the canonical URI. Doing it in a routing controller makes that quite easy, but then we have to do so for each entity type, which is what we're trying to get away from.
Or am I misunderstanding which controller we're dealing with here?
Comment #22
wim leersYes, you are :)
You're confusing
EntityViewController(which is a controller used only for the canonical route) withEntityViewBuilder(which is used to render (build a view of) an entity, for every place that entity may be displayed).Comment #23
wim leersApparently it's
taxonomy_page_attachments_alter()that's adding link relation headers for the canonical Term route! We'll need to refactor that away here too.Comment #24
wim leersWell there's nothing to move, it was doing exactly the same as
NodeViewController, and that now lives inEntityViewController, so it was already working for taxonomy terms :)Comment #25
wim leersThis should fix some of the test failures.
Comment #26
wim leersAnd this should fix the remainder.
Comment #27
dawehnerPeople already complained hugely about those header links being there. They seem to have huge SEO issues about that. Given that it feels like these links should be enableable, but maybe disabled by default.
One way to solve that could be its own module for that. Otherwise maybe some configuration per entity type could be done.
Comment #31
wim leersThat was because they were all exposed always, even to anonymous users. Thanks to #2406533: edit-form, delete-form etc. <link> tags added on /node/{node} are invalid according to W3C Validator, that's no longer the case. :)
Comment #32
Crell commentedWim: Ah ha! I am happy to be wrong in this case. Do carry on. (I may have been thinking of an earlier iteration of the code before there was a base class for entity route controllers.)
Comment #33
tedbow@Wim Leers I was looking into the test failure in \Drupal\system\Tests\Entity\EntityViewControllerTest::testEntityViewController
$this->assertRaw($get_label_markup($entity->label()));I think the problem is
I think \Drupal\Core\Entity\Controller\EntityViewController::buildTitle also needs to be update to match this new nesting. I tried to figure this out but
Here is $page[$label_field] is not set so this is never called.
If look at \Drupal\entity_test\EntityTestViewBuilder::buildComponents
it adds keys to the build which seems to only happen if the entity is not nested under 'entity' in the page. I can't get these keys to be added otherwise :(
Comment #34
wim leers#2776975: March 3, 2017: Convert core to array syntax coding standards for Drupal 8.3.x RC phase, #2770921: Feb 21st: Convert chunk of WTB to BTB by just moving classes, changing use statements adding traits and #2864121: Convert web tests to browser tests for statistics module all caused this patch to need a reroll. No interdiff, because functionally, the patch is still identical.
Comment #35
wim leers#2293697: EntityResource POST routes all use the confusing default: use entity types' https://www.drupal.org/link-relations/create link template if available improved
\Drupal\Core\Entity\Entity::uriRelationships(): it now only returns those link relationships for which a URL actually exists for that entity type (i.e. it automatically omits those link relationships that are defined but for which no actual route exists).That might have fixed some of the failures. If it did not, then it at least made it more reliable.
Comment #36
wim leersHere's a fix for all the failures due to
Hopefully somebody else can push it over the finish line! Note that #33 has not yet been addressed.
Comment #37
wim leersComment #40
tedbowLooking at #33 agian.
Comment #41
tedbowOk this what was causing the problem EntityViewControllerTest::testEntityViewController not being able to find the title on the page.
Shifting
$page['#pre_render'][] = [$this, 'buildTitle'];down a level to
$page['entity']['#pre_render'][] = [$this, 'buildTitle'];Means it can't actually affect the title of the page because it won't have
$pagetop level element.But if you try to set it back to
$page['#pre_render'][] = [$this, 'buildTitle'];Then the entity won't actually be built yet because
Actually set a
#pre_rendercallback toEntityViewBuilder::build()originally$page['#pre_render'][] = [$this, 'buildTitle'];was setting the
#pre_renderto run right afterEntityViewBuilder::build()Because they aren't on the same level any more this is not possible.
I got around this in this patch by build the entity directly in
EntityViewController::buildTitle()This fixed at least 2 test for me locally but it feels heavy handed.
Comment #43
wim leersFrom 15 to 9 failures, great! :)
Adding all this indeed does feel very heavy-handed…
Is it because we shifted things down a level (under the
'entity'key), and hence the things thatbuildTitle()was expecting to already been done, have actually not yet been done at this time, and hence you need to do it manually here? (Hence doing much of the work multiple times?)Hm, this one is interesting. It's because
Nodehas this:Note how all of those only require
{node}… except therevisionlink template, which requires{node_revision}.Normally this edge case is taken care of by this code in
Entity::toUrl():But,
\Drupal\node\Tests\PagePreviewTest::testPagePreviewWithRevisions()does this after testing a "normal" new revision as created through the UI:… and that is something that hasn't been taken into account yet: in that case, you do need
{node_revision}. But we can't provide it, because we're previewing an unsaved revision! Therefore generating therevisionlink relationship in this case does not make sense, and we just need to handle an additional edge case inEntity::toUrl().This should fix one more failure!
Comment #45
tedbowOk the change in #43 broke UuidFormatterTest because of the way \Drupal\Core\Field\Plugin\Field\FieldFormatter\StringFormatter::viewElements() handles the 'link_to_entity' setting.
I changed to \Drupal\Core\Entity\Entity::toUrl() to first check $this->isDefaultRevision() first before it throws an exception.
Because at that point it should be using 'canonical'
Comment #46
wim leersAnd this should fix the remaining failures (all in
NodeCacheTagsTest). The reason it was failing is thatNodeCacheTagsTest::getDefaultCacheContexts()used to contain a work-around for the fact thatNodeViewControlleradds auser.roles:anonymouscache context. But it's meant to only apply to the entire entity page… yet it was being applied to the rendered entity (infullview mode) itself! Therefore it was actually doing cache pollution.That's why it's important that
EntityViewControllermoved the rendering of the entity infullview mode down a level: then the$page['#cache']['contexts'][] = 'user.roles:anonymous';no longer affects it: cache pollution solved! And hence our tests are passing again, because they were actually asserting this cache pollution, and that's now been fixed :)Comment #49
tedbowUnassigning myself but still need to answer from #43
Yes, it is because it is under the new key 'entity'
\Drupal\Core\Entity\Controller\EntityViewController::view
Actually adds the build() method of Entity View builder to the #pre_render callback.
@see \Drupal\Core\Entity\EntityViewBuilder::view()
When this was the $page level it would guarantee that buildTitle() was called after build().
But not now we can't set:
$page['entity']['#pre_render'][] = [$this, 'buildTitle'];Because it won't have access to $page['#title'] and therefore it could not affect the page title.
So we set:
$page['#pre_render'][] = [$this, 'buildTitle'];But then the Entity View builder build() method has not be called yet.
So hence we have to build the entity ourselves.
Comment #50
tedbow#46 had only coding standards voilations, unused use statments, fixing
Comment #52
wim leersFailing tests are not showing up at https://www.drupal.org/pift-ci-job/688355…
Here they are, extracted from the log:
Comment #53
wim leersI debugged
\Drupal\comment\Tests\CommentInterfaceTest::testCommentInterface()some. The root cause is not what I thought it first was: a render cache item not being invalidated when it should. Because theentity_view:node:1:full:[languages:language_interface]=…render cache item does have thenode:1cache tag, and that is being invalidated when posting a comment on node 1.So the problem must be related to how this patch changes the rendering of full node pages and that somehow affects the rendering of the "comment" field.
Comment #54
tedbow@Wim Leers yeah manually tested the problem here
CommentInterfaceTest::testCommentInterface()
When I post the 3rd comment on the node it does put the correct parameters in the query string to show the me the new page of comments but it still renders the first 2 comments.
UPDATE: Yes it looks like the problem is with \Drupal\Core\Entity\Controller\EntityViewController::buildTitle
and the fact it also builds the entity.
So \Drupal\comment\Plugin\Field\FieldFormatter\CommentDefaultFormatter::viewElements is called twice. The first time it loads the correct comment and the 2nd time it loads the incorrect comments, the first 2 on the node.
Comment #55
tedbowRegarding my comment in #54 this patch doesn't build the entity in \Drupal\Core\Entity\Controller\EntityViewController::buildTitle() but rather just builds the field with the options from the display.
This fix the 2 test mentioned in #52
Also posted this potential bug for DrupalCI #2884084: Test failures not showing up on test results page
Comment #57
tedbowSo QuickEdit related tests failed because in quickedit_preprocess_field()
Because in #55 in \Drupal\Core\Entity\Controller\EntityViewController::buildTitle() it was using \Drupal\Core\Entity\EntityViewBuilderInterface::viewField to build the field the view mode was '_custom'.
So we just have to set the view mode because we know it at that point.
This should fix that test failures in #55. Hoping it doesn't cause any more!
Comment #58
dawehnerI'm wondering whether someone profiled this change. In views we did a LOT of changes to avoid calling viewField, given its really costly for rendering a single field. It could be to ensure in the
::viewfunction that the label will actually be rendered, so you can always pick it out.Comment #59
wim leersI added that underlined + strong text. I think that's what you meant to say? I agree with that concern — I also raised it at the beginning of my comment in #43, where I asked:
However, I'm not concerned about the performance impact here, because the result is cached by Dynamic Page Cache anyway, so subsequent visits to the page won't run that code. I'm only concerned because the increase in complexity is massive:
I stepped through this with a debugger, and I'm now pretty sure that my best-guess reasoning in #43 is actually correct.
Note that I am the one who moved shifted things down a level in #26, from
$page = $view_builder->view($entity, 'full')to$page['entity'] = $view_builder->view($entity, 'full').I did so to fix most
[entity_type]CacheTagsTesttests. (Compare the failing tests in #25 vs #26.)And given the additional insight I gained in #46, this is AFAICT a necessity. The old code was effectively polluting the render cache for nodes (see
NodeViewControll::view(), which we are now bringing to all entity types).This change is the solution.
I definitely would like to see this get a simpler solution though. After some tinkering, I think that's actually possible: what if we ensure that before
buildTitle()is called,$page['entity']has its#pre_rendercallbacks executed, so that$page['entity']['title']exists, so thatbuildTitle()can continue to work as it does in HEAD?EDIT: re-reading this, I think this is exactly what @dawehner was suggesting? :)
Comment #62
acbramley commentedI was always under the impression that canonical rel links should use the unaliased version of the url as it is the canonical source of the content?
Comment says non-aliased, but we are setting the alias option to TRUE?
Awesome, this is causing problems with the Metatag module by adding duplicate canonical rel links.
Question is, will this new approach play nice with the module? Seems like the existing approach for Node works fine.
EDIT: Answer is, yes! metatag_entity_view_alter removes core's tags if metatag is adding them itself. Since taxonomy is doing it's own thing at the moment, it doesn't catch them.
Going to take a stab at fixing the tests.
Comment #63
acbramley commentedFixes some PHPCS and adds a check to
$page['entity']['#pre_render']Comment #65
acbramley commentedWoops, wasn't meant to be a patch file.
Comment #67
borisson_Back to needs work to fix the test-failures, we should also add new tests for this functionality (or remove the needs tests tag).
This comment doesn't make sense, the parameter won't be removed, the optionality (is this a word?) of it will be removed. We should clarify this comment.
Should we also make this an optional constructor argument? At minimum we should declare the controllerResolver as a protected variable.
This comment is useless as it is, it duplicates the message in the exception, we should either document why this is - or remove the entire thing.
/s/yet//Comment #68
acbramley commentedComment #69
wim leers#2791571: Automatically supply contextual links for entities just landed, would be great to now get this one to completion too :)
Comment #70
andypostI'd better move this to protected method
new exception should be documented & probably better to not throw the exception
Comment #73
idebr commentedReroll against 8.7.x with a few minor changes:
#67.1 Updated the
__constructcomment to indicate the parameters will be required in Drupal 9.0.0.#67.2 Moved the declaration to the
__constructmethod.#67.3 Added Wim's reasoning in #43 to the comment.
#67.4 Fixed.
#70.1 Not sure what part you would move? This is a cut/paste operation from the old NodeViewController.
#70.2 Not sure how to fix, but I'm open for suggestions.
#73.1 Fixed the test failures in ContentTranslation by adding the new user.role.anonymous cache context to the assertions
The failure in ModerationFormTest is due to the fact that hook_entity_view is now called twice for each entity rendering. This results in new element names being generated, eg.
edit-new-statebecomesedit-new-state--2. Not sure how to fix this.Also the test coverage needs to be extended for different entity types.
Comment #78
berdirPossibly controversial counter-proposal in #2922570: The node view page triggers a lot of expensive access checks for relationship links ;)
Comment #82
catch#2922570: The node view page triggers a lot of expensive access checks for relationship links is fixed.
#2873648: With many languages, content_translation_page_attachments adds too many alternate links to the response headers crashing varnish (503) is another critical bug caused by these that is still open.
Marking this as won't fix to avoid even more damage.