Problem/Motivation
Database drivers that extend another database driver have to add the line with something like: include_once dirname(__DIR__, 8) . '/mysql/src/Driver/Database/mysql/Connection.php';. When this line is not added, the database driver will fail the installation proces. The extending database driver is then using a class that is not autoloaded and therefor does not exist.
The include_once only works when the module with the extending database driver is in the same level in the directory structure. This is not very practical for sitebuilders. It is also not to the standard Drupal Core would like its code to be.
Example database drivers that extend another database driver are: https://www.drupal.org/project/mysql56 and https://www.drupal.org/project/pgsql_fallback.
Proposed resolution
Improve the autoloading for database drivers that are dependent on another database driver. Add extension for database drivers and lists of database drivers.
Improve the autoloading for the parent database driver during installation.
Remaining tasks
TBD
User interface changes
None
API changes
The function drupal_get_database_types() has been deprecated and is being replaced by \Drupal::service('extension.list.database_driver')->getInstallableList();.
The function drupal_detect_database_types() has been deprecated and is being replaced by \Drupal::service('extension.list.database_driver')->getInstallableList();.
The method Drupal\Core\Database\Database::findDriverAutoloadDirectory() has been deprecated and is being replaced by \Drupal::service('extension.list.database_driver')->get($namespace)->getAutoloadInfo().
Extensions for database drivers have been added.
The service for getting a database driver or a list of database drivers is \Drupal::service('extension.list.database_driver').
Data model changes
None
Release notes snippet
TBD
| Comment | File | Size | Author |
|---|
Issue fork drupal-3256642
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:
Comments
Comment #2
daffie commentedThe fix.
Comment #3
mondrakeOuch… I have been bitten by this too. Yes we need to be able to add additional namespaces to the class loader very early. What I am afraid of in this patch is performance… scanning the directory to find the module at every request is not very fancy. Need to think about it.
Comment #4
daffie commented@mondrake: If you a better and/or more performant solution, then please say so.
Comment #5
mondrakeJust thinking. We have this comment in
Drupal\Core\Site\Settings:So, if a db driver module is dependent on some other modules, the same as above applies to the dependencies too.
I am wondering if, as part of installation, we could stash the 'additional autoloads' in the
$databasesarray insettings.php, by looking at the dependencies set in {module}.info.yml. Then at every request we'll just pick those without parsing the directories.Something like, to illustrate the idea:
Comment #6
daffie commented@mondrake: Thank you for the alternative solution. The current patch uses your solution.
To make it work I have added the requirement for database drivers that extend another that their connection URLs add "&parent=true". Only then will Drupal look for the parent infomation. Which should not be done for the vast majority of sites. Hopefully is this good enough from a performance standpoint.
I will create a CR when you think the patch is RTBC.
Comment #7
mondrakeNice, and even nicer the tests.
maybe we do not need a separate class for that, just a static array (or better a public static method) on the
Connectionclassthen also you won't need to pass
array $dependenciestoConnection::createConnectionOptionsFromUrl,Connectioncould know it by itself.Also this will work for 'one level' of dependencies only - i.e. driver B extends from driver A, not for driver C that extends from B that extends from A, but that would seem overkill to me, so fine.
We also need to reflect this in the settings.php docs...
Comment #8
daffie commented@mondrake: Thank you for the review.
Moving it to the Connection class is not possible. The extending Connection class cannot be loaded until its parent class has been loaded. And we need the data from the extending Connection class to load its parent driver.
I do this, because when I do not do it in
Connection::createConnectionOptionsFromUrl(), then I will need to callDatabase::findDriverAutoloadDirectory($parent_namespace, $root, TRUE);again. To me, that is a bit much.I have added documentation to default.settings.php.
Comment #9
mondrakeAha... need to think if we could have alternatives here. Need some time...
Comment #10
mondrakeworking on this
Comment #11
mondrakeThis changes the approach a bit to rely on the dependencies set in module.info.yml to determine the autoload dependencies for the db driver, so we do not need a new class. PSR4 allows specifying only the base namespace of a module and autodetermine the driver code in the subnamespace so we are fine without needing to change anything in the db URI.
Needs more tuning and fixing a unit test that is failing on DrupalCI but locally works fine - no idea why.
Comment #12
mondrakeComment #13
mondrakeComment #14
mondrakeStreamlined a bit.
Comment #15
mondrakeCS fixes
Comment #16
mondrakeComment #18
mondrakeChanged to MR and deprecated Database::findDriverAutoloadDirectory()
Comment #19
mondrakeComment #20
daffie commentedIt looks good, using the module dependencies for the dependency info.
I did a first quick review. I will do a second one soon (probably tomorrow).
Comment #21
mondrakeComment #22
mondrakeLet's postpone on #3257714: Remove loading from the Drupal\Drivers namespace from drupal_get_database_types() that would help further cleanup in install.inc.
Comment #23
mondrakeActually the MR fully incorporates #3257714: Remove loading from the Drupal\Drivers namespace from drupal_get_database_types(), so this can be reviewed independently
Comment #24
daffie commentedThe MR looks good! I am really happy with it.
The naming of the variables in determineDriversAutoloading() is a bit confusing.
I have create a CR and updated the IS.
@mondrake: Thank you for working on this.
Comment #25
daffie commentedI have created #3258181: Remove old code from Drupal\Core\Database\Database::convertDbUrlToConnectionInfo(). To do after this one has landed.
Comment #26
mondrakeThank you @daffie. Now we only have to add a test for the case a driver module specifies a dependency that does not exist. We need another test module with a fake driver and a missing dependency.
Comment #27
daffie commentedThe testbot is not happy with the new test.
Comment #28
mondrakeLet's see this, we need to ensure the broken test module does not get caught in the middle of a normal extension discovery.
Comment #29
mondrakeI made a small edit to the CR
Comment #30
daffie commentedAll code changes look good to me.
All threads on the MR are resolved.
The IS and the CR are in order.
For me it is RTBC.
For the committer: Could user @tmaiochi get a commit credit on this issue for his work on #3257714: Remove loading from the Drupal\Drivers namespace from drupal_get_database_types(). I think it is going to be his first core commit credit and I have closed the other issue as it has become part of this issue.
Comment #31
mondrakeRerolled
Comment #33
mondrakererolled
Comment #34
mondrakerebased
Comment #35
mondrakerebased
Comment #36
mondrakeRebased.
Comment #38
quietone commentedPer #30 I am moving credit from the other issue to here.
Comment #39
mondrakeI doubt this will make 10.0. Repurposing for 10.1.
Comment #40
mondrakeRebased
Comment #41
alexpottThere's a fail test.
Comment #42
daffie commentedI think the fail might have something to do with #3294695: Drupal 8 BC for database driver namespace fails for replicas.
Comment #43
mondrakeYeah, something new was added that the MR is not reflecting. Looking into it.
Comment #44
mondrakeI think failure is due to #3293446: Create less static cache in ExtensionDiscovery during KernelTests
Comment #45
mondrakeComment #46
daffie commentedAll the change necessary to fix the failures for #3293446: Create less static cache in ExtensionDiscovery during KernelTests look good to me.
Back to RTBC.
@mondrake: Thank for fixing this.
Comment #47
alexpottI've added some questions to MR code review.
The biggest thing is should we take this as an opportunity to introduce a DatabaseDriverList object extending from ExtensionList and DatabaseDriver extending from Extension.
Comment #48
mondrakeMade the easy changes. Do we need to try
here or it would be ok as a follow-up? I agree it makes sense, but I'd rather explore it independently, so that if we end up with ripples we can iron them out there.
Comment #49
daffie commentedAll points of @alexpott have been addressed.
For one point is a followup suggested.
All code changes look good to me.
I have updated the IS and the CR.
Back to RTBC.
Comment #50
mondrakeFiled #3314325: Introduce DatabaseDriver and DatabaseDriverList classes to manage installable driver extensions for follow-up.
Comment #51
alexpott@mondrake @daffie I'm not sure about leave new API for a follow-up. We're already adding new API for a feature request here. If we going to rework that in a follow-up that doesn't make much sense to me.
Comment #52
mondrakeso we need doing it here. pity we find that out after 8 months in RTBC.
looking into it.
Comment #53
alexpott@mondrake that's really fair. I'm sorry I had got round to a deep review and trying to think about the architectural implications. I will try to keep the reviews coming to help get this across the line asap.
Comment #56
mondrakeClosed MR 1626, and opened a new MR to introduce the new extension objects. Very first go, not for review, wanted to see how much this fails.
Comment #57
mondrakeNet of the FunctionalJavascript test failure that are bogging the bots today, this should be working now.
Points:
Database::convertDbUrlToConnectionInfo()should be working also outside of container context - for kernel tests but also for any third party script that needs to determine drivers (e.g. cli installation etc). Here I added an helper that returns the service or instantiates directly aDatabaseDriverListclass depending on whether the container is available or not.\LogicExcpetionfor all methods that are not implemented and that would not makes sense to inherit.drupal_get_database_types()anddrupal_detect_database_types(), too.DatabaseDriverListclass should interact with the cache.Comment #58
daffie commentedLets wait for the review of @alexpott, before we/I update the IS and the CR
Comment #59
mondrakeFollowing on #57, deprecated
drupal_get_database_types ()anddrupal_detect_database_types().Comment #60
daffie commentedComment #61
mondrakeThanks for reviews,
please add a comment to the d.o. issue after commenting in the MR, unfortunately MR comments do not update timestamps at the moment and there’s risk to miss progress.
Comment #62
mondrakeI am addressing some of these review points.
Comment #63
mondrakeFreeing assignment.
Comment #64
mondrakeAdded a deprecation test for the deprecated install.inc functions.
Comment #65
daffie commentedComment #66
mondrakeChanges and comments on the MR.
Comment #67
mondrakeInteresting reading about the Extension class, #2959989: Deprecate Extension::__call() magic
Comment #68
mondrakeRerolled. Would be lovely to have some input as how to progress here.
Comment #69
mondrakeHow bad it is that MR comments do not bump the timestamp of the d.o. issue...
Comment #70
mondrakeLet's see what happens with your suggestion @daffie - a patch for the moment so not to pollute the MR
Comment #71
mondrakeNow use
module\driverNameas the key for the list of drivers.Comment #72
mondrakeComment #73
mondrakeComment #74
mondrakeComment #76
mondrakeComment #77
mondrakeIt's complicated... but I think it's feasible. We need to change all internals to use the
module\driverconvention, and changeinstall_get_form()to swap calls without the module name to add the module name, so that scripts can still use legacy logic.Comment #78
mondrakeComment #79
mondrakeComment #80
mondrakeComment #81
mondrakeComment #82
mondrakeComment #83
mondrakeComment #84
mondrakeComment #85
mondrakeComment #86
mondrakeComment #87
daffie commented@mondrake: The patch looks really great. Thank you for working on this. I have some remarks:
This change is something we cannot do. Existing connection info will have the driver set to "mysql" and not "mysql\\mysql". If we do not make this change and exception for "Passing a database driver name 'mysql' to Drupal\Core\Extension\DatabaseDriverList::get() is deprecated". Therefor we unfortunatly cannot add that deprecation. I would very much like to do so, only it will result in a BC break. :(
These 2 class properties need a docblock.
Needs to be fixed.
The parameter is optional, only it does not get a default value.
Maybe add a comment with why this check is necessary.
The only problem with this change is that we are losing testing for the other thrown exception. Now we need a database driver without a Connection class.
Can we add testing for this exception?
We are missing testing for this exception.
This is to me the wrong change. Can we instead add:
Comment #88
mondrakeLet's see if this one gets green, then I'll comment and address #87.
Interdiff is vs. MR2844, For some reason I cannot open a separate branch as I would like: https://drupal.slack.com/archives/C51GNJG91/p1672150197341309
Comment #89
mondrakeComment #90
mondrakeComment #92
mondrakeOpened MR 3169 (thanks @drumm) and fixed #87.2 and #87.3.
Comment #93
mondrakeTested MR3169 on the DruDbal experimental driver, it passes ok https://github.com/mondrake/drudbal/pull/315
Comment #94
mondrakeComment #95
mondrake#87.1 and .7 - in fact here we are only preparing values for the database selection form submission, not for
settings.phpdirectly. Tried to clarify in last commint on the MR.Comment #96
daffie commentedThe testbot is not happy.
Comment #97
daffie commentedI did not want to assign this to @alexpott.
Comment #98
daffie commentedBump for posting thread on MR.
Comment #99
mondrakeThanks @daffie for reviews and input.
I start thinking to make another step, and instead of using 'module\driver' as the internal name of the extension and of the list keys, use the driver namespace instead (e.g. 'Drupal\mysql\Driver\Database\mysql').
Like that, we would anyway ensure uniqueness and avoid introducing another convention. And btw that has the benefit of being explicitly written to settings.php as such in the 'namespace' database connection info array, whereas 'module\driver' will have to be always determined programmatically.
In the end, we're making the 'driver' key in the database connection info array redundant, but that could be for another future issue.
Comment #100
mondrakeLast commit in the MR is essentially implementing #99, bar the test adjustments.
Comment #101
mondrakeComment #102
daffie commentedThe MR looks good. With the requested change to SiteSettingsForm and a bit more testing it is RTBC for me.
Comment #103
mondrakeComment #104
daffie commentedOn Monday I will update the IS and the CR. The MR looks great!
Comment #105
mondrakeComment #107
mondrakeComment #108
daffie commentedLooks good. Just 1 thread open.
Comment #109
daffie commentedI did not want to assign the issue to @alexpott.
Comment #110
mondrakeSo, where PHP doesn't get to, PHPStan to the rescue:
Comment #111
mondrakeComment #112
daffie commentedThe MR is for me RTBC. I will update the IS and the CR tomorrow.
@mondrake: Thank you for working on this issue!
Comment #113
daffie commentedAll the code changes look good to me.
Testing has been added.
I have updated the IS and the CR.
For me it is RTBC.
Comment #114
mondrakeThanks for the housekeeping of IS and CR, @daffie!
Comment #115
Manoj Raj.R commentedThe latest changes looks good to me.
Comment #116
mondrakeFound an issue with InstallerTestBase while working on the mysqli driver, fixed.
Comment #117
daffie commentedThe test change looks good to me.
Back to RTBC.
Comment #118
catchI'm concerned about the number of low level changes we're having to make after making database drivers modules, it feels a bit like all the special casing we've had over the years for install profiles. Having said that the code here seems OK in itself. I think this should be a target for early in the 10.2.x cycle so it has time to bed in. We should resolve @quietone's recent comment though so marking needs work for that.
Comment #119
mondrakeI have tried @quietone suggestion, but removing the line tests still fail. Reverted and reset to RTBC. Deprecations now are for 10.2.x.
Comment #120
mondrakeComment #121
larowlanLeft some comments on the MR, huge effort here folks 💪
Comment #122
mondrakeThank for the review @larowlan! NW to go through the points.
Comment #123
mondrakeRemoved code from Database::findDriverAutoloadDirectory to use the new API. It's OK but had an impact on a test. Can I get a review of latest changes before continuing with the rest of the points.
Comment #124
mondrakeI have addressed all points from @larowlan.
Comment #125
daffie commentedAll points of @larowlan have been addressed.
A couple of followups have been created.
Back to RTBC.
Comment #126
larowlanI took this for a spin locally, and tested that I could install with drush
Was able to install with `drush si demo_umami` and the site looked good with a click about.
I agree with @catch in #112 that its best to get this into 10.2.x early and let any issues shake out.
So in line with that, committed to 11.x - thanks all!
💃
Comment #128
mondrakeAdjusted CR for branch, and published it.
Comment #130
andypostI bet it's good parent #2024083: [META] Improve the extension system (modules, profiles, themes)
Comment #132
poker10 commentedIt seems like this issue caused regression on Windows: #3383616: "core_version_requirement key must be present" on core modules on Windows