Problem/Motivation
Over in #2723579: NodeRouteProvider should extend DefaultHtmlRouteProvider we are trying to deprecate 'node.add_page' and 'node.add' routes.
The problem is these route names are getting used in a lot of places:
- The URL generation. e.g.
Url::fromRoute('node.add_page') - Menu Link/local task/local action generation.
Drupal::routeMatch()->getRouteNameis used in various contexts for doing things conditionally.- Breadcrumb builders primarily seem to use route names to derive context.
- There might be a few more.
Over in #2723579: NodeRouteProvider should extend DefaultHtmlRouteProvider, NodeRouteProcessorBc is added which take care of URL generation but what about the rest?
Proposed resolution
- Introduce the ability to mark routes as being an alias and (optionally) deprecated in
routing.ymlfiles. - Internally those deprecations are also converted into aliases, so that the previous (deprecated) route names can still be fetched for calls like
getRouteByName() - During the routing process those aliases don't make a difference, because their
pathparameter (table column) is empty - When the routes are loaded by their old names (for example in local tasks), a deprecation notice is thrown
Remaining tasks
Figure out all the edge cases by looking at contrib usage of e.g. node.add_page
Fix local tasks when pointing to an alias
Store alias information in the router table
Decide if we want to trigger a deprecation for local tasks that point to an alias
Test coverage for the new methods on RouterProviderInterface
Upgrade path tests
User interface changes
None.
API changes
This will be an API addition. An API to allow the deprecation of the routes.
Data model changes
A new alias column and an index for it are added to the router table.
Release notes snippet
TBD.
| Comment | File | Size | Author |
|---|
Issue fork drupal-3159210
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
- 3159210-support-route-aliasing
changes, plain diff MR !6738
Comments
Comment #2
berdirI think the list can be grouped into two cases. URL generation and checking for the current route. Generation is reasonably easy, as done on the node patch. Checking the current route is the problem, and given how the API works, I honestly have no idea how to deal with that. I can't think of anything to make that work. It returns exactly one string that we compare, so that's a hard break.
Either we get an OK from a release manager to make that breaking change, possibly only for a major release or the issue is won't fix and we'll have to live with node not conforming to the naming standard and if necessary find alternative ways to deal with that, like support non-standard route names for link templates somehow.
Comment #8
jibranI think we have a way forward here based on https://symfony.com/blog/new-in-symfony-5-4-route-aliasing#deprecating-r.... All we need to add the route alias support to Drupal core.
Comment #9
aaronmchaleRoute Aliasing does look promising, would likely unblock #2723579: NodeRouteProvider should extend DefaultHtmlRouteProvider and make #3153559: Switch Node revision UI to generic UI easier to implement.
Comment #10
catchComment #11
andypostHere's initial stub to allow parse aliases - using code from https://github.com/symfony/symfony/pull/38464/files#diff-2b6a8c06ec813f6...
looks like it will throw deprecation on routeCollection::get() so needs some test to make sure it works
Comment #12
andypostOur
routertable supports to save aliases so reusing current storageThe only issue I see is broken local tasks (no tab displayed at dblog clean-up
admin/reports/dblog/confirm)So it should be covered by tests
Comment #14
jibranDo we actually want to deprecate this route?
Comment #15
andypost@jibran surely no, but this route is handy to test local tasks (is where I stuck in patch)
Comment #16
pwolanin commentedUsing the built-in symfony mechanism sounds like a the right starting point.
Looking at the patch quickly, I'm concerned that the route saved to the table doesn't have any flag as a separate table column that it's an alias, but i guess the fact that it's not saved with a path or pattern outline means it will never be found doing a lookup by path?
I'd also, ideally, want some way in the route or route match to list the known aliases of a matched route. This could be helpful for e.g. writing a hook_help() or something else looking at the current route name that would work before and after this change.
Comment #17
aaronmchaleComment #18
dpiWe could alias
user.well-known.change_password->user.editas a working example of aliasing without deprecation.Comment #19
andypostLooks it's blocker for #2723615: Use entity route providers for all content entity types
Comment #20
andypost@dpi thanks for #18 good idea to have it as alias
@pwolanin do we need a flag in routing table for aliases? I think as the "route" column deserialized we can determine is it alias or route.
Comment #21
larowlanUpdated remaining tasks based on conversation, going to poke at the local tasks issue for a bit
Comment #22
larowlanThis addresses @pwolanin's request at #16 and fixes local tasks per #12
To-do - decide if we want to trigger a deprecation when a local task references a deprecated route name.
Tests for the new methods on router provider.
Comment #23
larowlanDone for the time being
Comment #24
longwavePatch in #22 is the same as #12, though the interdiff looks correct.
Comment #25
larowlanThanks I git stashed my autoload.php changes before I committed the diff to my local branch, so stashed my changes too
Here's the correct patch for the interdiff above
Comment #27
andypostThanks 👍 I bet it needs upgrade hook and test as well because schema change
Comment #28
larowlanThe hook is there, but the test is nitt
What do people think about triggering a deprecation if a local task points to an alias?
Comment #29
andypostI think every use of deprecated route should cause a warning but it could be overkill for logs.
But local actions like tasks need it but usage in URL generation may need throttling
Comment #30
aaronmchaleSounds like a good idea.
Comment #31
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".
Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #32
pooja saraah commentedFixed failed commands on #25
Attached patch against Drupal 10.1.x
Comment #33
nod_Comment #34
andypostClosed as duplicate #3218088: Rename the 'alias' option for URLs and proper re-roll, leaving NW for tests
Comment #35
andypostAll failed tests showing that deprecated route is used somehow, so it needs to clean-up usage
Moreover the error message is not clear enough - no route alias name is displayed (only in argument
dblog.deleteComment #36
andypostBetter to use route from #18
Comment #37
wim leersThis blocks:
… and probably more. So tagging .
Comment #38
joachim commentedThe IS doesn't mention the plan that's in the title.
Comment #40
andypostComment #41
andypostnew column and index - schema change should go to update hook I bet and rebuild probably will be automatic
also it needs upgrade test
the only API addition
Comment #42
_utsavsharma commentedPatch for 11.x, as the previous was failing to apply.
Comment #43
duadua commentedI'm coming here from https://www.drupal.org/project/drupal/issues/3311365. It seems like this assumption might not hold necessarily?
Is this a case where it would be better to use
->setRebuildNeeded(). Looking at what post update is doing, it does flush all caches afterwards, which would rebuild the router if needed.Comment #44
amateescu commentedFixed the feedback from #41 and #43.
Local tasks are not broken for an aliased route, so I removed the change from
LocalTaskManagerand the newgetUnAliasedRouteName()which didn't have a purpose anymore.For aliasing
user.well-known.change_passwordtouser.edit, after reading https://symfony.com/blog/new-in-symfony-5-4-route-aliasing I think that's not a valid example, because the two routes are not pointing to the same (URL) path.Wrote an upgrade path test, so we only need some test coverage for the new
RouteProvider::getRouteAliases()method now.As for triggering deprecation errors for local tasks, I don't think that's necessary, the current
trigger_error()fromRouteProvider::getRouteByName()is enough IMO. And combined with #3024296: Add option to log deprecation errors, it should provide enough visibility for deprecated routes.Comment #46
andypostThank you! Still needs work to fix CS and
Comment #48
andypostand it shou8ld prove a test with deprecated route - let it be test module
Comment #49
andypostComment #50
andyposthide patches as MR is used
Comment #51
amateescu commentedAdded some test coverage in
\Drupal\Tests\system\Functional\Routing\RouterTestbut I think we need to add more in\Drupal\KernelTests\Core\Routing\RouteProviderTest, so leaving at NW.Comment #52
amateescu commentedAdded the remaining test coverage needed for
\Drupal\Core\Routing\RouteProvider::getRouteAliases(), the MR is ready for final reviews now!Comment #53
andypostLooks great and ready to go!
Just not sure about return type which I think which be
iterable(traversable) instead ofarrayComment #55
acbramley commentedComment #56
andypostthe only question is
arrayvsiterableComment #57
andypostany somehow update hooks fails on mysql
Comment #58
andypostsqlite pass all
upgrade fails on mysql (every upgrade test) https://git.drupalcode.org/issue/drupal-3159210/-/jobs/4004297
pgsql fails only 1 test
RouteProviderTesthttps://git.drupalcode.org/issue/drupal-3159210/-/jobs/4004507Comment #59
catchTo me this looks broken in the MySQL driver.
::addField() calls ::createKeysSql(), ::createKeysSql() calls ::getNormalizedIndexes(), ::getNormalizedIndexes() expects a $spec['fields'] to be passed in with the field definition(s) and that is not done.
Comment #60
andypost@amateescu Thank you fixing update hook! Probably it needs follow-up and todo added to allow add field with index to mysql table in one transaction
Comment #61
andypostThe only failure is pgsql with strange warning
Comment #62
andyposton pgsql able to reproduce, the failing value is
Comment #63
andypostFixed pgsql and filed issue for mysql schema #3499524: Mysql Schema::addField() incorectly processing indexes specification
Comment #64
amateescu commented@andypost, thanks for fixing the pgsql issue, I was really scratching my head around it. Reverted your latest commit, we can't add them at the same time until the issue you just opened is fixed, and it's also not worth waiting for it :)
Comment #65
daffie commentedBack to needs work for my remark on the PR.
Comment #66
amateescu commentedReplied to the MR comment.
Comment #67
andypostI think it's ready for commiters
Comment #68
catchOne question.
There is no change to RouteProvider::getRoutesByPath(), shouldn't be filtering aliases in any case where we're not explicitly loading the route by name? If not in that method then somewhere else?
Comment #69
amateescu commented@catch, there's no need to do any additional filtering in
RouteProvider::getRoutesByPath()because we only store data in thename,routeandaliascolumns, so the current conditions onpattern_outlineornumber_partsalready exclude aliases.Another place would be
::preLoadRoutes(), but that's called by::getRoutesByNames()(which in turn is used by::getRouteByName()and the new::getRouteAliases()), so no need to filter there.And then there's
::getAllRoutes()which is documented to return an array of Route objects and has this doxygen:Added a filter in
::getAllRoutes()and moving back to RTBC because I don't think this change requires test coverage.Comment #71
catchThanks for #69 that all looks sensible.
No other complaints, so committed/pushed to 11.x, thanks!
Comment #73
quietone commentedI updated the CR to have two examples and to include the message property that was missing. Also, added this to 'How to deprecate' and added alias to Structure of routes.
Comment #74
catchThanks @quietone!
Comment #76
amateescu commentedOpened a followup for this: #3506653: Add an API for comparing the (current) route name that takes into account deprecated routes