Problem/Motivation
During the core conversion a couple of people (@pwolanin, @crell, @tim.plunkett, @dawehner) discussed what we can improve in the routing system in general.
One small aspect of it what simplifying the router itself.
Proposed resolution
Merge the routers into one basically. This removes a lot of indirection in the process and keeps the code flow much easier.
This hopefully flattens down the routers from 5 to 2. IMHO this is worth adding some additional code.
Before
- AccessAwareRouter
- ChainRouter
- NestedRouter
- DynamicRouter
- FinalMatcher
After
- AccessAwareRouter
- DynamicRouter
Pro
- Much easier to explain, especially when you look onto the backlog
- Potentially faster and less code has to be loaded by default
- Allows to document much more precisely what is going on
Con
- Swapping things out on specific levels is harder
- More core shipped with Drupal itself
- Upstream improvements would have to be synced potentially
Remaining tasks
- Get feedback from both subsytem and framework manager
- Review the code, write maybe additional test coverage
- Improve the documentation to be really good.
- Address feedback
- Commit
User interface changes
API changes
None known. Everything is changed internally.
Data model changes
| Comment | File | Size | Author |
|---|---|---|---|
| #51 | interdiff-2810303.txt | 4.01 KB | Crell |
| #51 | 2810303-reunite-router.patch | 15.99 KB | Crell |
| #31 | 2810303-31.patch | 15.9 KB | dawehner |
| #29 | interdiff.txt | 644 bytes | dawehner |
| #29 | 2810303-29.patch | 15.85 KB | dawehner |
Comments
Comment #2
dawehnerThis is really just a start
Comment #3
dawehnerComment #4
dawehnerComment #5
chx commentedWow.
Comment #7
tim.plunkettCan we switch to an interface here?
Comment #8
dawehnerSure, let's go with an actual interface. Here is some work and potential better documentation and maybe one, two or three bug fixes.
Comment #10
dawehnerThis might fix a good bunch of the failures.
Comment #11
dawehnerComment #12
dawehnerComment #13
dawehnerGiven that this change is a non minimal change to the routing system, it would be certainly required to have a subsystem maintainer review for that.
Comment #14
tim.plunkettAs long as route filters and enhancers run, I don't think we'll have any regressions. I manually tests page_manager/panels and ran the test suites with this patch applied, everything worked as expected.
I used to have a problem using a leading \ for this, great that it's not broken anymore!
I think naming this DynamicRouter but not extending \Symfony\Cmf\Component\Routing\DynamicRouter is confusing.
Why not just call it Router?
As a subsystem maintainer I'm fine with this, but I would feel better if Crell signed off on this.
Comment #15
wim leersYES PLEASE!
Anybody who has debugged the current routing system is still deeply scarred by that experience.
Also: the IS says , but then there are only two listed in the "after" step.
Comment #16
klausi+1 on the general approach.
we cannot remove services during the D8 release cycle, so the removal here will have to wait until D9. Or do we consider those services internal? Is a change notice enough to let contrib maintainers know that those services are gone now?
this exception should have a better message.
And the exception type should probably be \BadMethodCallException instead of the useless generic type?
Something like throw new \BadMethodCallException(sprintf("'%s' is not supported by Drupal 8.", __FUNCTION__));
Also elsewhere.
we should probably document where the code in this class comes from. Symfony CMF somewhere?
big +1 to rename this class from "DynamicRouter" to just "Router". The "dynamic" is meaningless.
doc blocks are incomplete and missing in this patch, so make sure to check those when we have signoff from Crell.
data type, what is in the array? More arrays? Or flat strings?
Comment #17
dawehnerOh you are right, that's a typo.
I really doubt you can use any of those services for themselves, but sure we can discuss to let them stick around.
I'll hopefully address the other feedback tomorrow. Thanks a lot for the reviews.
Comment #18
Crell commentedI'm on board with the general direction; I'll review the code after the next patch as it looks like there's a number of changes to be made for the reviews above.
I'd suggest DrupalRouter for the class name, as it's the Drupal implementation of the RouterInterface.
As far as the API breakage, this approach would eliminate a number of obscure ways to fiddle with the routing system, like multiple stages of chained routers. However, in practice I don't think that would work anyway given how much is built on the router and I'd argue we never actually said that was part of the API. Rather, the API of the routing system (as I proposed at DrupalCon Austin in my core conversation on @internal APIs) is:
1) The *.routing.yml file and its PHP equivalents.
2) RouteFilters
3) RouteEnhancers
So as long as we don't break the expected behavior of those steps and the interfaces on the latter two, I think we're fine API-wise.
Comment #19
catchI think we'd consider the services removed internal, but if we wanted to we could deprecate them in 8.3.x and remove them in 8.4.x (nothing stops us doing that if we think they're @internal anyway, it's just being extra nice if someone was somehow relying on them).
Comment #20
pwolanin commentedI'm a little unsure why we need to have __call here instead of directly delegated the expected methods?
Comment #21
dawehnerWell, we have a
call_user_func_array()call before. Let's see what happens when we throw an exception in case the method doesn't exist. Maybe we will see some more places.This patch addresses hopefully all feedback from above. I went with
RouterasDrupalRouterseems a bit duplicate.Comment #22
dawehnerRemoved accidental change of the issue summary by pwolanin
Comment #25
dawehnerThere we go.
Comment #26
Crell commentedWhat's the reasoning here? We're taking away a method, but not fixing the interface? That seems problematic. What was this method doing before, and what would be the equivalent operation now?
At its base, the RouterInterface is an aggregate of a matcher and a generator. We shouldn't be breaking that contract. Inject the generator and let it delegate here.
Otherwise this looks pretty good overall.
Comment #27
dawehnerSure, let's make that better.
We no longer need a subsystem review. Should we have a framework maintainer or are we good with just having subsystem maintainer agree on it?
Comment #28
Crell commentedThis check is too broad. Strictly speaking we only need check for GeneratorInterface here. (RouterInterface extends it.)
We should still get a framework manager to verify that they're OK with the narrow definition of "API break" we're assuming here, so leaving the tag in place.
Comment #29
dawehneroh, well here it is.
Comment #30
wim leersThis is fascinating. I didn't know this is how it worked. It's great to have this example.
Should we have
?
"Central" seems a strange adjective here?
s/process/request/
s/the output of the page/a response/
If this is a sequence, shouldn't we number them instead?
s/one/ones/
"consists ideas" needs better wording.
Comment #31
dawehnerWell, its a bit tough to decide whether 8.4.0 would be a good time as well. BC speaking we maybe have to not break it until 9.0.0?
Good catch!
Great idea!
I improved it a bit.
Comment #33
pwolanin commentedComment #34
Crell commentedNot RTBCing without a framework manager review, but I'm happy here. Thanks all!
Comment #35
dawehnerComment #36
catchI like this issue a lot. Ambivalent about the service deprecations and when they could be removed, probably needs a discussion in the @internal issue like many other things.
Adding one class to drop two confusing services is a good trade-off.
Comment #37
klausi@catch: we are dropping 3 confusing services :)
Looks good, some minor nitpicks:
stray colon here? "objects" from the first line should be on the second line.
Description missing.
Yes, i can see that this is an array. Is it also a cache same as $sortedEnhancers?
priority is not optional here, it is a required parameter. Should we make it optional by using a default value in the method signature?
catch is a framework maintainer that signed off this approach, removing tag. For the @internal services discussion I think it is a good first step to just deprecate those services before removing them. We can always remove them later if we want to.
We should probably have a change record for this.
Comment #38
dawehnerAddressed the bits from @klausi's review
To be honest I'm not entirely sure what to document on the change record, given its internal changes, but there is one: https://www.drupal.org/node/2820197
For some additional fun, checkout the revisions on this change record.
Comment #39
Crell commentedI tweaked the change record slightly. I think our work here is done.
Comment #40
klausiRTBC+1, I updated the change record with the list of deprecated services also.
Comment #41
dawehnerThe change record is no longer needed
Comment #42
alexpottCommitted 21a86f3 and pushed to 8.3.x. Thanks!
Some docs fixes on commit - reviewed in real life with @dawehner.
Comment #44
tim.plunkettThis breaks my install when opcache is turned off.
\Drupal\Core\Routing\UrlGeneratorInterface exists in the same namespace as Router, so the use statement of Symfony\Component\Routing\Generator\UrlGeneratorInterface is conflicting.
This can be fixed by aliasing the import like this:
But this should be reverted first. Also maybe we should have test runs once in a while without opcache on?
Comment #45
tim.plunkettThis was a known bug in PHP, https://bugs.php.net/bug.php?id=66773
It was just fixed in PHP 19 days ago, so it might be a while before we see the fix on testbot :)
By fix, I mean all of our tests would begin failing due to invalid imports.
Comment #46
dawehnerI wonder whether the committers might run the unit tests without opcache could detect those issues.
Comment #47
cilefen commented#2446847: [Policy] Create test runner groups for different issue stages
#2446719: Need test runners without bytecode caching
Comment #49
alexpottReverted - I think these issues are rare enough just to do the revert as asked... it is not that painful.
Comment #50
tim.plunkettComment #51
Crell commentedNew patch. Interdiff is against #38. This just rolls in the changes from #42 and #44.
Comment #52
dawehnerThank you for fixing my stupidness
Comment #53
alexpottCommitted 0e71ca6 and pushed to 8.3.x. Thanks!
Didn'r mean to remove that in my original commit if I did... doesn't look I did.