Change the URL of a node based on parent path So let's say I have a basic page node.

I want to have this as an entity reference inside another content type - let's say an event content type.

So let's say that the event content has a url like baseurl.com/eventblahblahblah

When a user clicks over to the basic page that is the reference on node eventblahblahblah, I want them to go to baseurl.com/eventblahblahblah/basicpagenodehere - this needs to be the URL in the browser.

In addition, basicpagenodehere can be in multiple references - so if basicpagenodehere is also referenced by event2blah, then I want it to also be located at the url baseurl.com/event2blah/basicpagenodehere

I'm looking at possibly doing this with alterRoute - 

class RouteSubscriber extends RouteSubscriberBase {
  /**
   * {@inheritdoc}
   */
  public function alterRoutes(RouteCollection $collection) {
  }
}


But I'm not sure if this is the correct place to do it.

This link suggests maybe PathProcessor, but I don't think that would change the actual URL on the node at the end of processing:

How to alter and rewritte current path programmatically in Drupal 8?

So how do I set a dynamic URL based on referring node?
The routing system is probably not the right place for this, you would need to rebuild the routing table whenever the content is changed, which is very slow.

PathProcessor is the right tool. By the way, path aliases are also implemented in a PathProcessor, the aliases are coming from a lookup table. You can change the path in and outbound dynamically or with your own lookup table if you need it for performance reasons.

Better for SEO would be a redirect to avoid duplicate content, but this changes the url in the browser, what you don't want.



Example for the symmetrical inbound/outbound (asked in the comments):

  public function processInbound($path, Request $request) {
    if (strpos($path, '/foo/') === 0) {
      $path = preg_replace('#^/foo#', '', $path);
    }
    return $path;
  }

  public function processOutbound($path, &amp;$options = array(), Request $request = NULL, BubbleableMetadata $bubbleable_metadata = NULL) {
    $path = '/foo' . $path;
    return $path;
  }


This will add /foo to all paths.

One way to approach this could be, you get the child node node/x in the outbound processor as input, the parent node id from the current route. Then you get the title from each of both nodes and put the path together.

For inbound I suggest a third fix path parameter, so that you can identify this kind of path right away and scrap all but the title from the child node, query the node id and you are back where you started at /node/x.