Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Crell created an issue. See original summary.

Crell’s picture

Title: Add a View-latest tab to show forward revisions » View-latest tab rendering wrong

  • becw committed 5fafcd4 on view-latest-tab-2639990
    refs #2639990: treat the 'Latest revision' tab on nodes like a node view...
becw’s picture

Yeah, it is a theme-level issue that only (currently) applies to nodes--the view latest tab on core block content does not have this issue. The node template uses the page variable to determine whether to output the node title as part of the content.

Because this is a node-specific issue, here is a node-specific fix.

Crell’s picture

  1. +++ b/workbench_moderation.module
    @@ -90,3 +90,29 @@ function workbench_moderation_local_tasks_alter(&$local_tasks) {
    +  $variables['page'] = $variables['page'] || workbench_moderation_is_latest_page($variables['node']);
    

    Nice. :-)

  2. +++ b/workbench_moderation.module
    @@ -90,3 +90,29 @@ function workbench_moderation_local_tasks_alter(&$local_tasks) {
    +function workbench_moderation_is_latest_page(NodeInterface $node) {
    +  $route_match = \Drupal::routeMatch();
    +  if ($route_match->getRouteName() == 'entity.node.latest_version') {
    +    $page_node = $route_match->getParameter('node');
    +  }
    +  return (!empty($page_node) ? $page_node->id() == $node->id() : FALSE);
    +}
    

    Does this make sense to move to a method of a service? I'd prefer to have no non-trivial code outside of a service if possible.

becw’s picture

Is there an existing node-specific service where it might live? Otherwise, I'm not sure--it's based on what node.module does, not that that should be taken as an example.

Crell’s picture

I don't believe so. Seems too one-off to be put into one of the handlers. The question is whether it's worth the effort to move that to a new service class for the experience. :-)

becw’s picture

Assigned: Crell » becw
Status: Needs review » Needs work

Ok, looks like I need to be moving this into a new service class.

becw’s picture

Crell’s picture

Status: Needs review » Needs work
  1. +++ b/src/IsLatestPage.php
    @@ -0,0 +1,47 @@
    +class IsLatestPage {
    

    I wouldn't make the class this specific. Rather, what is appropriate to live here? What else might we add?

    My inclination would be to rename this to WorkbenchPreprocess, and then move the entire preprocess hook into a preprocessNode() method, which in turn can just call isLatestPage() as now.

    A class that's name is the same as its one method is generally a sign that the class is too specific.

  2. +++ b/src/IsLatestPage.php
    @@ -0,0 +1,47 @@
    +  public function isLatestPage(Node $node) {
    

    Better name: isLatestVersionPage(). (isLatestPage to me implies "is this the latest page of something else", like a most-recently-updated view or something.)

  3. +++ b/src/IsLatestPage.php
    @@ -0,0 +1,47 @@
    +    if ($this->routeMatch->getRouteName() == 'entity.node.latest_version') {
    +      $pageNode = $this->routeMatch->getParameter('node');
    +    }
    +    return (!empty($pageNode) ? $pageNode->id() == $node->id() : FALSE);
    

    The need for !empty() suggests this could be restructured. Actually, I'm not clear on why we need to compare the IDs. When would those not match?

    Assuming we still need that comparison, then we can take advantage of boolean short-circuiting, as elsewhere in the module, and the fact that = evaluates to the value assigned:

    return 
      $this->routeMatch->getRouteName() == '...'
      && $page_node = ...
      && $page_node->id() == $node->id();
    
becw’s picture

The IDs would not match if you were rendering a node as part of another node -- for example, when it is referenced in a field.

Here's an updated patch with the renamed/refactored class. I have one question, which is inline as a @TODO: I passed $variables by reference to the WorkbenchPreprocess::preprocessNode method, and I'm not sure whether that is acceptable.

Status: Needs review » Needs work

The last submitted patch, 11: view_latest_tab-2639990-11.patch, failed testing.

The last submitted patch, 11: view_latest_tab-2639990-11.patch, failed testing.

The last submitted patch, 11: view_latest_tab-2639990-11.patch, failed testing.

Crell’s picture

  1. +++ b/src/WorkbenchPreprocess.php
    @@ -0,0 +1,58 @@
    +class WorkbenchPreprocess {
    

    As a service, this class is now testable. Yay! It involves an entity and routes, so probably a KernelTest, but it's definitely doable. Let's.

  2. +++ b/src/WorkbenchPreprocess.php
    @@ -0,0 +1,58 @@
    +   * @todo I don't like passing $variables by reference here, but I did it
    +   *       because it matches the way hook_preprocess_HOOK() works. Is this OK?
    

    I don't like it either, but that's what we've done elsewhere in the module. Everything else is doing proper returns, but this method is really just the hook itself copied into a class keyword to mirroring the hook's API makes the most sense.

  3. +++ b/src/WorkbenchPreprocess.php
    @@ -0,0 +1,58 @@
    +  public function isLatestPage(\Drupal\node\Entity\Node $node) {
    

    "use" the class name at the top of the file, then the short-name "Node" here.

dawehner’s picture

  1. +++ b/src/WorkbenchPreprocess.php
    @@ -0,0 +1,58 @@
    +   * @todo I don't like passing $variables by reference here, but I did it
    +   *       because it matches the way hook_preprocess_HOOK() works. Is this OK?
    +   */
    +  public function preprocessNode(array &$variables) {
    

    Totally. It is how it works.

  2. +++ b/src/WorkbenchPreprocess.php
    @@ -0,0 +1,58 @@
    +  public function isLatestPage(\Drupal\node\Entity\Node $node) {
    +    return $this->routeMatch->getRouteName() == 'entity.node.latest_version'
    +           && $pageNode = $this->routeMatch->getParameter('node')
    +           && $pageNode->id == $node->id;
    

    IMHO ideally we would pass along the route match from outside into this method. One less "state" needed. Is there a reason why this wasn't implemented in an entity generic way?

Crell’s picture

Hm, yeah getting the route match in the hook method and passing that to isLatestPage() is even better, and makes testing easier, too.

This is a node-specific bug due to the way nodes get themed. That's why it's a node-specific solution.

  • becw committed 435441c on view-latest-tab-2639990
    refs #2639990: service cleanup.
    
becw’s picture

I've added a unit test now, but I haven't refactored the CurrentRouteMatch thing yet.

I did a unit test instead of a kernel test because I don't think it's necessary to have that much integration available for what is being tested here. On question, though: am I using prophesize/willReturn wrong in WorkbenchPreprocessTest::setupCurrentRouteMatch?

Status: Needs review » Needs work

The last submitted patch, 19: view_latest_tab-2639990-19.patch, failed testing.

The last submitted patch, 19: view_latest_tab-2639990-19.patch, failed testing.

The last submitted patch, 19: view_latest_tab-2639990-19.patch, failed testing.

  • becw committed 5e556be on view-latest-tab-2639990
    refs #2639990: fix test bugs.
    
  • becw committed e2f20c4 on view-latest-tab-2639990
    refs #2639990: use ->id() instead of ->id.
    
becw’s picture

dawehner’s picture

+++ b/src/WorkbenchPreprocess.php
@@ -0,0 +1,59 @@
+    return $this->routeMatch->getRouteName() == 'entity.node.latest_version'

Mh, so the route at least is generated for every entity type, so is there a reason this code is specific to nodes?

becw’s picture

This code is specific to nodes because the bug is specific to nodes--node templates use the $page variable, which is what is being tweaked... ahh, I see, so perhaps this specific method should not be node specific. I'll tweak that, thanks!

becw’s picture

Ok, I looked at the code more closely and changed my mind. The route is added to any moderatable entity type, but I think asking the router for arbitrary loaded entities and comparing them to the passed-in entity is too much complication here.

  • becw committed 3507011 on 8.x-1.x
    refs #2639990: treat the 'Latest revision' tab on nodes like a node view...
  • becw committed 5e556be on 8.x-1.x
    refs #2639990: fix test bugs.
    
  • becw committed 6d2a2c5 on 8.x-1.x
    refs #2639990: move latest version tab check into a service.
    
  • becw committed 756db87 on 8.x-1.x
    refs #2639990: add test for latest version page.
    
  • Crell committed 78d31b9 on 8.x-1.x
    Issue #2639990 by becw: View-latest tab rendering wrong
    
  • becw committed 8a87b4c on 8.x-1.x
    refs #2639990: rename service.
    
  • becw committed baaf8c5 on 8.x-1.x
    refs #2639990: update method name.
    
  • becw committed df79e1f on 8.x-1.x
    refs #2639990: service cleanup.
    
  • becw committed e2f20c4 on 8.x-1.x
    refs #2639990: use ->id() instead of ->id.
    
Crell’s picture

Status: Needs review » Fixed

I agree with Bec. This is node-specific code to fix a node-specific bug, using a node-specific core oddity because nodes are still special, even in D8. :-(

Merged. Thanks, Bec!

dawehner’s picture

Alright!

Status: Fixed » Closed (fixed)

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