Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Problem/Motivation
- Enable rest, serialization as well as hal module
- Enable page_manager and page_manager_ui
- Create a page pointing
/entity/node
- Goto
/entity/node
Expected result
You should be able to visit the page as well as be able to do a POST request against the same path and both continue to work.
Actual result
The website encountered an unexpected error. Please try again later.
Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException: No route found for "GET /node": Method Not Allowed (Allow: POST) in Symfony\Component\HttpKernel\EventListener\RouterListener->onKernelRequest() (line 180 of vendor/symfony/http-kernel/EventListener/RouterListener.php).
Drupal\C
The problem is that page_manager doesn't take into account formats nor HTTP methods in \Drupal\page_manager\Routing\PageManagerRoutes::findPageRouteName
.
Maybe some similar fix as #2730497: REST Views override existing REST routes could work out.
Proposed resolution
Remaining tasks
User interface changes
API changes
Data model changes
Comment | File | Size | Author |
---|---|---|---|
#56 | 2736385-format-56.patch | 43.1 KB | tim.plunkett |
#56 | 2736385-format-56-interdiff.txt | 3.85 KB | tim.plunkett |
#53 | 2736385-format-53.patch | 42.56 KB | tim.plunkett |
#53 | 2736385-format-53-interdiff.txt | 3.9 KB | tim.plunkett |
#44 | 2736385-format-42.patch | 41.41 KB | tim.plunkett |
Comments
Comment #2
tim.plunkettThis should fix it.
Comment #4
Wim LeersComment #5
dawehnerWow, that was quick!
Its a super tricky topic. Just checking for GET would override
/node/1
provided by REST module as well, I believe ...Comment #6
Wim LeersLooks great, and looks identical to #2730497: REST Views override existing REST routes in approach.
Comment #7
tim.plunkettChanging
['POST']
to['GET', 'POST']
breaks the test. Maybe this logic isn't completely correct?Comment #8
dawehnerIts so super tricky. Maybe we need to take into account formats on top of it, to distinct whether you want to override or whether you want to just add a new route.
Comment #9
tim.plunkettWhat about this? Honestly I'm not sure what to do here.
Comment #11
dawehner@tim.plunkett
Yeah I pinged crell to talk about that issue for views. I hope he'll find some time at some point.
Comment #12
Wim LeersWhy not just go with the solution we have in core for now? We can refine it later.
Comment #13
dawehnerYeah fair.
Comment #14
Nick_vhI ran into issues with routes that contain _format. The following patch fixes that for me but I have absolutely no idea why..
My problem: I have a module that adds a format to the /node/{node} route. Page manager is also enabled. For some reason when page manager is enabled it no longer recognizes the path with the _format param. Instead we get:
With this patch and a cache clear, that route is working as expected again. Using Drupal 8.2 and latest alpha of page manager
Comment #15
Nick_vhComment #16
Nick_vhMade some typos in the patch above
Comment #17
Nick_vhComment #19
Nick_vhOh boy. Not making the best impression. I should not upload patches I don't test locally.
Comment #21
Nick_vhSteps to reproduce:
Install contenthub & page_manager
composer config repositories.drupal composer https://packages.drupal.org/8
composer require drupal/acquia_contenthub:~1.0
composer require drupal/page_manager:~1.0@alpha
drush en acquia_contenthub
drush en page_manager
drush en page_manager_ui
Setup the Drupal Site
Make sure you have the Article Content Type
go to admin/config/services/acquia-contenthub/configuration
Click the Publish Checkbox of "CONTENT » ARTICLE"
Click save at the bottom of the page
Create an Article with random content
Verify that the rest endpoint is working
Clear caches
Go to /node/1?_format=acquia_contenthub_cdf
Verify you see JSON output
Import Page Manager Config
page_manager.page.node_view.yml
page_manager.page_variant.node_view-http_status_code-0.yml
Verify we can no longer access our special url
Go to /node/1?_format=acquia_contenthub_cdf
Verify you see
{"message":"Not acceptable format: acquia_contenthub_cdf"}
Comment #22
tim.plunkettAs it turns out, the _format handling already was happening in \Drupal\Core\Routing\RequestFormatRouteFilter::filter()
However, route filters ignore any sort of priority when they are managed by LazyRouteFilter (which is by default).
And RequestFormatRouteFilter was running too late, which meant page_manager's VariantRouteFilter was picking the variant to use before factoring in _format info (as the last patch tried to fix).
In order to order route filters, they must be declared as "non_lazy_route_filter".
Once that was fixed, it became clear that \Drupal\page_manager\Routing\VariantRouteFilter::routeWeightSort() was mangling the order prepared by RequestFormatRouteFilter. Changing it to preserve order by default fixed that problem.
Finally, while writing test coverage, it became clear that display variants don't have a generic schema to fall back on. Opened #2838130: Display variants are missing a generic schema but added a workaround here.
Comment #23
tim.plunkett#22 didn't actually solve the problem described in #21 though, but another issue with ordering.
Expanded the test coverage, and removed the reordering from VariantRouteFilter which should also fix #21.
Comment #25
Nick_vhConfirming this solves the issue of #21! Thanks Tim!
Comment #26
tim.plunkettIn going back through the whole flow of the patch, I noticed some conspicuous issues, and went to fix them as well. Technically could be out of scope, but the issue is basically "PM routing doesn't work like you think it does and is bad" now...
Comment #28
Nick_vhI keep wondering if this is the only differentiator that makes a route unique. Do we have any other differentiators how a route could be different other than _format?
Comment #29
tim.plunkettNot sure either, really.
Also super glad that last patch failed, because I made a mistake and the unit tests didn't cover it.
Comment #30
tim.plunkettWorking on this
Comment #31
tim.plunkettOkay this fixes everything... except PageManagerTranslationIntegrationTest, which seems to currently pass by coincidence.
I went back and found when it was added: #2342923: content_translation fails when node/% is overridden with a route.
No idea what was going on in that issue, but just removing the test for now.
It should become easier to fix the following now:
#2634276: Multiple routes break active trail and possibly other behaviors
#2782661: Page variant for node view causes internal error in other content types
#2659948: Remove support for paths with %, provide validation and description for path
Comment #32
tim.plunkettTurns out #2634276: Multiple routes break active trail and possibly other behaviors is the fix for PageManagerTranslationIntegrationTest, adding that back in.
#2782661: Page variant for node view causes internal error in other content types is also fixed here.
Not making the % change because that needs UI stuff too, and is an easy standalone fix
Comment #34
tim.plunkettOkay tracked down the problem. 'base_route_name' is only tracked and cleared for overridden routes, and yet we were adding it to all routes. That's unnecessary, and now interferes with the new checking in VariantRouteFilter.
A good amount of the interdiff is just undoing changes to tests, sorry.
Comment #35
tim.plunkettComment #37
tim.plunkettSilly bug around weight being 0, fix and coverage included
Comment #38
BerdirHm. Does actually does seem to partially fix the problem reported in #2837833: 'Required contexts without a value: node' when editing menu, but only partially and in a way that breaks my workaround.
In the site that I was debugging, I have a page_manager page with a path like /foo/{type} and then multiple variants with a selection condition on the path. Without this, it fails to match anything, resulting in url = base:foo/bar in the menu_tree table.
Now with the patch, it always uses the first route name, so the menu_tree table contains route_name = page_manager....foo_bar but then type=othervalue in route_param_key and same for route_parameters.
The problem is that this means my workaround to look up active trail based on base:foo/bar, if there is nothing matching the route name, now fails and the active trail only works for the first variant and not the others. In this case those variants could easily be completely different pages without an argument, but in case of overriden node/{node} or similar pages, with selection conditions for e.g. the bundle, that's not an option.
Comment #40
tim.plunkettThis keeps the base route name for all managed routes by switching to an "overridden_route_name" for the filtering.
Also finally fixed the sorting bugs, yowch.
Comment #41
tim.plunkettLikely should add some docs here
This comment should be moved, not deleted.
Unassigning now that it passes, will get to the docs next week if no one else does.
Comment #42
BerdirThanks!
I think I did find another problem. Some of my tests failed, and from what I see, this seems to happen because somehow this breaks the route name for views that override routes. I can see this on /admin/content for example, the local tasks and actions there are gone.
Not quite sure what is happening. Tell me if you can't reproduce.
I also had some other test fails that were because the route names changed as the special case for the first variant was removed. I can live with that, updated my code, just FYI.
I also noticed that the page manager variant filter isn't within the lazy route filter like core's route filters are. Not sure if that's some optimization in core that this module wasn't updated for or if that is actually on purpose?
Comment #43
BerdirAh. The page variant is moved here, so that seems on purpose. Maybe that makes it run on pages where it shoudn't do anything now and we need some other way of checking that?
Comment #44
tim.plunkettWalked through this with @EclipseGC, these are the only changes.
Comment #45
tim.plunkettThe ordering of lazy route filters is nondeterministic (because of \Drupal\Core\Routing\LazyRouteFilter)
In order to not recreate the functionality of those other route filters, we need ours to run last.
The only way to order route filters is to use non-lazy route filters, and rely on the normal priority system.
I have no idea how this interacts with Views, do I really want to know?
The key takeaway from this change is that the {router} table entries now all use page manager naming scheme, which is
page_manager.page_view_{page_id}_{variant_id}
. PageManagerRoutes no longer affects existing routes.VariantRouteFilter now does all of the manipulation, and it's last action (for routes overriding existing stuff) is to spoof the route name of the route we're overriding.
Comment #46
tim.plunkettNot sure what "that", "it", "it", and "that" mean in this context, sorry!
Comment #47
tim.plunkettTo address #43, maybe something like this?
I'm out for the rest of the weekend, but will be around next week.
Comment #48
BerdirI can confirm that this fixes the problem for me. I haven't figured out what exactly causes it though, couldn't reproduce on a new empty standard installation.
Comment #49
BerdirAll my tests are now passing when including that interdiff, so everything OK as far as I'm concerned :)
Comment #50
tim.plunkettSo it fails with #44 but #44 + #47 passes?
The change makes sense, but I can't actually figure out how to write a unit test for it. Seems like a sort problem, possibly...
Comment #51
BerdirYes, exactly.
But yes, I also couldn't reproduce manually, not sure what exactly is necessary to get that bug.
Comment #52
tim.plunkettCan I see the failing testcase? I can step through it with xdebug and see what's going on.
Comment #53
tim.plunkettWell, it's a version issue.
Tried to simplify but I still had to resort to a version_compare :(
Removed the applies() because Drupal\Core\Routing\RouteFilterInterface is only used by lazy route filters.
Comment #55
brianperryI was finding that I was unable to override existing routes (either in a new page, or even adding a new variant to the Node View page.) This ended up being the closest related issue I could find (which is surprising - maybe I missed something in my search.) On the plus side, the latest patch on this issue appears to resolve the problem and allows me to override existing routes.
Comment #56
tim.plunkettSwitching to array_multisort since uasort is completely unstable and differs between PHP 5 and 7.
Comment #57
tim.plunkettI'm marking this RTBC because I intend to commit it. But hopefully @Berdir and @Nick_vh could double check that everything is as expected still?
Comment #58
BerdirLooks good with manual testing, my tests are running now.
Comment #59
BerdirEverything looks good on my side, go ahead :)
Comment #60
Nick_vhAll good here as well. Thanks!
Comment #61
Wim LeersWow, this one required a lot of work and a ton of debugging! Probably worth marking
:)Great job :)
Comment #63
tim.plunkettThanks everyone!
Marking major, adding credit.
Comment #64
tim.plunkettPushed!
Closing #2634276: Multiple routes break active trail and possibly other behaviors and #2782661: Page variant for node view causes internal error in other content types as they should be fixed now.
Comment #66
tim.plunkettComment #67
Wim LeersShould we backport this to core?
#2730497: REST Views override existing REST routes
Comment #68
tim.plunkettPM
Views
I guess we could indeed add the
->hasRequirement('_format')
part to Views.Comment #70
CabKab CreditAttribution: CabKab as a volunteer commentedWhat is the recommended process for patching the affected modules in the Acquia Lightning distribution? It appears as if the files are in a different structure? Is it safe to go through and update the a .. b .. paths in the patch to match the lightning folder structure?
Comment #71
DamienMcKenna@CabKab: Please open an issue in the Lightning issue queue, that's far too general a question for the Page Manager project.