Problem/Motivation
The current implementation of getCid() of Drupal\Core\Menu\MenuActiveTrail is the following:
protected function getCid() {
if (!isset($this->cid)) {
$route_parameters = $this->routeMatch->getRawParameters()->all();
ksort($route_parameters);
return 'active-trail:route:' . $this->routeMatch->getRouteName() . ':route_parameters:' . serialize($route_parameters);
}
return $this->cid;
}
This results into calculating the cid everytime, when getCid() is called.
This is not only a performance issue, but does lead also to bugs.
One Scenario:
We have a route, which can be only access by authorized users. Anonymous people do get an access denied page.
When authorized users are accessing the page, the cid is always the same.
When anonymous users access the route, they get a 403, so the routeMatch in $kernel->handle phase is the 403 page.
MenuActiveTrail cid is calculated for the 403 page and the value is put in the queue for persistance.
Now, the $kernel->terminate phase is executed, and during the destruction, the cache entries are written to cache.
Unfortunately now, the cid is same as the one from the original requested path. So the 403 activetrail does overwrite the original active trail.
If we would persist the cid over the whole request, this would not be the case, as the cid for the 403 path would remain.
Proposed resolution
Change the line
return 'active-trail:route:' . $this->routeMatch->getRouteName() . ':route_parameters:' . serialize($route_parameters);
to be
$this->cid = 'active-trail:route:' . $this->routeMatch->getRouteName() . ':route_parameters:' . serialize($route_parameters);