Description
This is a bit involved, so I will try to explain it as well as I can.
We're working on stitching the CMF Routing component into Drupal: http://drupal.org/node/1874500
That involves a DynamicRouter service (part of CMF Routing), which is RequestContextAware. The Matcher and Generator in use are also RequestContextAware. OK, so put the request context in Container and inject it, no problem.
Problem: That makes the Router object request-scope sensitive, so subrequests will always trigger a new router, matcher, and generator. That works, but is not performant as @fabpot noted in the issue above.
Solution, per fabpot: Inject the context to the router via a listener before matching, rather than via the constructor. Then it gets updated prior to every match(), which is fine, and we only need one instance. Great. We'd have to override some constructors (UrlMatcher and DynamicRouter, specifically), but doable. The current RouterListener does this, albeit in a somewhat ugly way. (It's modifying a quasi-global via match(), so that it affects the generator. Ick.)
Problem: That doesn't do anything for exiting a subrequest. When exiting a subrequest, the matcher no longer matters but the generator may still be used. (No may in Drupal's case; will still be used.) The generator, however, is still referencing the context object that was last set on it, which is... the context object from the subrequest, because that's when setContext() was last called (and/or the quasi-global was last updated by the listener). That means the generator is operating on the wrong request context, which may or may not be sufficiently different to cause problems.
I talked with @merk in IRC, and we confirmed this seems to be a problem. The possible solutions we came up with include:
- Suck it up and let the request scope regenerate the routing system. (This is, as we understand it, what full stack does now.)
- Wrap the context object in a proxy object, which is ContainerAware and encapsulates the fetching of the context. Then that proxy can re-fetch the context each time the generator asks for it, but the generator itself never gets recreated.
- Add an "end subrequest" event to the kernel. Have a listener listen to that event, then call setContext() on the generator with the parent scope's context to restore it.
- Add a directive to the container's scope directive that a given object should have a certain method called on it with some other service when a scope is started or ended. That is, instead of a service reinitializing entirely it tells the container how it should handle scope changes.
The fourth option seems like the most powerful, but also likely the most complex. (Naturally.)
For the moment, I am going to go with the first option in Drupal so that we can move forward. However, given that we are likely to fire a not-small number of subrequests I think we will need a solution here.
Thoughts?