Problem/Motivation

A lot of major service require the router.builder service:

  • theme_handler
  • plugin.manager.menu.local_task
  • router.route_provider

Proposed resolution

Introduce a state-only service and inject it into both router.builder and the other services.

Remaining tasks

User interface changes

API changes

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

dawehner’s picture

Issue tags: +Needs benchmarks

This will certainly needs benchmarks in the future in order to justify whether it is worth to do it.

chx’s picture

You could use setter injection in the proxy to get route.builder in there so that it can provide actual rebuild functionality for router provider.

catch’s picture

I think this is valuable just for disentanglement reasons.

Fabianx’s picture

The advantage of the state / rebuild service is that it can decide to either inject or lazily load the services, but we can always replace the implementation without having to change all services using that.

So +1 to that.

chx’s picture

Priority: Normal » Critical

Now this is critical because #2351777: Do not depend on event subscribers for security: Replace AccessRouteSubscriber with build-in checks depends on it: that patch fails because of a circular dependency "router.builder -> access_manager -> router.route_provider -> router.builder"

chx’s picture

Status: Active » Needs review
Issue tags: -Performance, -needs profiling
FileSize
2.42 KB

Now this no longer needs a performance review because of #5 :) catch indicated he wanted ContainerAware which made this stupid simple. Since we always need to call rebuildIfNeeded() in a request, I opted to inject state because it always will be needed.

Status: Needs review » Needs work

The last submitted patch, 6: 2352641_6.patch, failed testing.

chx’s picture

Status: Needs work » Needs review
FileSize
3.2 KB

This can't be real ;)

Status: Needs review » Needs work

The last submitted patch, 8: 2352641_8.patch, failed testing.

chx’s picture

Status: Needs work » Needs review
FileSize
3.26 KB

Odd, I thought that's automated.

Status: Needs review » Needs work

The last submitted patch, 10: 2352641_10.patch, failed testing.

chx’s picture

Status: Needs work » Needs review
FileSize
6.3 KB

Typehinting with an object? Tsk, tsk.

Status: Needs review » Needs work

The last submitted patch, 12: 2352641_12.patch, failed testing.

chx’s picture

Status: Needs work » Needs review
FileSize
6.2 KB

The missing return in getCollectionDuringRebuild broke it. For good measure, added to rebuild to.

dawehner’s picture

So with that patch we save one initialized service and one rather complex object (RouteBuilder) to initialize, this is quite sad to be honest.

chx’s picture

This patch allows the passing of access_manager into router.builder.real. That's all.

Fabianx’s picture

Fabianx’s picture

Status: Needs review » Reviewed & tested by the community

RTBC, the proxy is a good step to unblock other issues and get some lazyness into the route system.

We can always replace with a lazy proxy from #1973618: DIC: Lazy instantiation of service dependencies (ProxyManager for "proxy services") later on - when / if that landed.

This unblocks a circular dependency.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 14: 2352641_14.patch, failed testing.

chx’s picture

Status: Needs work » Reviewed & tested by the community
FileSize
5.58 KB

Rerolled.

catch’s picture

I'm still a bit uneasy about this proxy compared to the smaller self-contained service we could inject both into RouterBuilder and other things that currently take RouterBuilder as a dependency. Is that really much harder to implement? I know it's an API change but RouterBuilder could also proxy through to those methods, keeping a BC layer no?

Had brief discussion with alexpott and he had similar concerns so it doesn't feel like just me.

alexpott’s picture

Status: Reviewed & tested by the community » Needs review
FileSize
29.95 KB
27.19 KB

My concerns have translated into a patch. That said I'm not sure how either patch really breaks the dependency chain router.builder -> access_manager -> router.route_provider -> router.builder.

Status: Needs review » Needs work

The last submitted patch, 22: 2352641.22.patch, failed testing.

alexpott’s picture

Status: Needs work » Needs review
FileSize
614 bytes
27.52 KB

Fixed ThemeController

Fabianx’s picture

Status: Needs review » Reviewed & tested by the community

RTBC - Looks great to me.

It makes a lot of sense to keep the state separate from the actual builder.

Please also be aware of: #356399: Optimize the route rebuilding process to rebuild on write

But I think we get this one in first and then follow-up on #356399: Optimize the route rebuilding process to rebuild on write as we can then nicely couple the isRebuildNeeded() into the isRebuildReallyNeeded parts more cleanly.

Thanks!

chx’s picture

Status: Reviewed & tested by the community » Needs review

The problem here is that access manager depends on route provider depends on route.builder which then can't depend on access manager. That's the chain we tried to break and this patch didn't break that. Mine did because access manager depends on route provider depends on route.builder and then route.builder.real can get access manager freely.

Edit: the chain breaking happens the moment route.builder.real is not constructor injected but via the container aware way.

catch’s picture

AccessManager only uses the injected route provider for checkNamedRoute().

checkNamedRoute() isn't used by route.builder.

So we should also be able to split that up to break the circular dependency.

chx’s picture

Status: Needs review » Reviewed & tested by the community

Right, let's do that. I will split access_manager in two by introducing a loadcheck private service both halves rely on. This will break the backwards compatibility of AccessManagerInterface . Are we cool with that? Notably setChecks will be removed which of course is not used by anyone except the route builder.

  • catch committed 4e0e15b on 8.0.x
    Issue #2352641 by chx, alexpott: Break router.builder dependency.
    
catch’s picture

Status: Reviewed & tested by the community » Fixed

#28 sounds like we get to clearly delineated services, with no circular dependencies, and without using either ContainerAware or EventDispatcher (which is on top of ContainerAware anyway) tricks to solve them, which sounds great.

Committed/pushed to 8.0.x, thanks!

See you in the follow-ups.

Status: Fixed » Closed (fixed)

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