Problem/Motivation

Drupal\Core\Database\Database is @final so maybe we can take a stab at making it type-strict.

Proposed resolution

Add declare(strict_types=1); and document types so that the class can be PHPStan L10 compliant.

Remaining tasks

User interface changes

Introduced terminology

API changes

Data model changes

Release notes snippet

Issue fork drupal-3532930

Command icon 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

mondrake created an issue. See original summary.

mondrake’s picture

Status: Active » Needs review
smustgrave’s picture

What's the pro of using @phpstan-type? Seems tough to read

quietone’s picture

Issue tags: +PHPStan-0

Adding tag

mondrake’s picture

This is not PHPStan level 0... it's PHPStan level 10. If you test locally the patch on the single core/lib/Drupal/Core/Database/Database.php file with PHPStan, and set the level to 10, it will pass.

I know it's a little bit futuristic but here I am exploring.

Wrt #4, on higher levels than what we have now PHPStan checks validity of the array keys being used in code against the array shape. Without @phpstan-type defined on the class level as an 'alias' of the array shape, we'd have to enter the full array shape every time it is used (16 times in this class). Readability would get definitely worse as well as the risk of errors (if you start using a new array key, you'd have to change all the instances).

There's interest in using @phpstan-type, see https://git.drupalcode.org/project/drupal/-/merge_requests/10809#note_51..., but probably not yet enough focus, see https://www.drupal.org/project/drupal/issues/3497431#comment-16102077 and https://www.drupal.org/project/drupal/issues/3082239#comment-15153451 (later comments)

BTW, such long array shapes probably hint at the opportunity to use value objects instead. I opened #3533038: Introduce a ConnectionParameters value object to store database connection parameters.

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community

I've seen a few of these popup and this one seems well scoped may serve as a good example, lets see what committers think

longwave’s picture

Status: Reviewed & tested by the community » Needs work

Overall I am +1 on doing this, and it will be a long road to getting it done everywhere in core, but added some questions to the MR.

mondrake’s picture

Status: Needs work » Needs review
  1. Removed from SettingTest:testDatabaseInfoInitialization() some test cases that were still based on db connection logic that was removed in #3294695: Drupal 8 BC for database driver namespace fails for replicas.
  2. Made keys in array shapes have quotes so to improve readibility
  3. Addressed @longwave's feedback
smustgrave’s picture

Are we losing coverage in core/tests/Drupal/Tests/Core/Site/SettingsTest.php by removing those 3 scenarios?

mondrake’s picture

No - database drivers in sub-namespaces of Drupal\Driver\Database are long gone, and in fact those test cases should have been removed when the logic was. Better late than never.

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community

Thanks for pointing that out. That was my only concern from the MR.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.

needs-review-queue-bot’s picture

Status: Reviewed & tested by the community » Needs work
StatusFileSize
new1.34 KB

The Needs Review Queue Bot tested this issue. It fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

mondrake’s picture

Status: Needs work » Reviewed & tested by the community
Issue tags: +no-needs-review-bot

bot fluke

alexpott’s picture

Status: Reviewed & tested by the community » Needs review

@final on an abstract class? That's a bit of an oxymoron right?

I think we have to confirm here that contrib db drivers are not affected - it's not like there's many and @mondrake maintains at least 1 of them :)

mondrake’s picture

I think we have to confirm here that contrib db drivers are not affected - it's not like there's many and @mondrake maintains at least 1 of them :)

@final on an abstract class? That's a bit of an oxymoron right?

Indeed, and has been so since day 1, 15 years ago, given the phpdoc said

 * This class is uninstantiatable and un-extendable. It acts to encapsulate
 * all control and shepherding of database connections into a single location
 * without the use of globals.

and all its properties and methods are static. To me, this means that the class is actually final static. Classes cannot be defined static in PHP though, but a final class could have a constructor that throws an exception in case of instantiation attempt. I'd be all for doing that, but would rather defer it to a separate issue to avoid delaying this one further (I saw heated debate on use of final).

alexpott’s picture

I missed the fact that nothing is extending database and yep abstract seems to be being used to enusre no one can construct it. Funky. So I'm not longer concerned about the return typehints at all. The concern now is the use of strict types and if someone has used an integer as a database key somewhere. Currently it works just fine... I defined a connect with a target and key of 1...

> \Drupal\Core\Database\Database::getConnection(1);
= Drupal\mysql\Driver\Database\mysql\Connection {#890}

And with this MR applied I can't bootstrap Drupal before I hit
TypeError: Drupal\Core\Database\Database::addConnectionInfo(): Argument #1 ($key) must be of type string, int given

mondrake’s picture

#19 yeah... can we limit to string|int or we need to support any scalar string|int|float|bool? Having database keys/targets as floats or bools would sound a bit extreme to me.

Also, shall we just limit to the $key and $target parameters of the methods?

alexpott’s picture

Status: Needs review » Needs work

I think practically bools and floats are nonsense. I think limiting to strings and ints and deprecating ints would be best. I can see how someone might have made a mistake and used an int but that's not true for floats and bools. Plus floats don't really work as array keys anymore they cause a deprecation in PHP 8.4 and eventually will error so I don't think we should worry about that.

mondrake’s picture

Status: Needs work » Needs review

Done #21. Will try to add a couple of deprecations tests when I win my current laziness...

mondrake’s picture

Added one deprecation test (could not win laziness to do a couple, so we came to a draw and added one)

mondrake’s picture

On the Database class I could revert the doc changes. On the Connection and Log classes, apparently PHPStan on higher levels matches the native type of the parameters passed within Database to the methods called there, to the phpdoc types defined in the classes, as they don't have native type signature. Since now in Database key and target are natively typed string|int, that does not match and we get this error:

 ------ -------------------------------------------------------------------------------------------------------------------- 
  Line   Database.php                                                                                                        
 ------ -------------------------------------------------------------------------------------------------------------------- 
  512    Parameter #1 $target of method Drupal\Core\Database\Connection::setTarget() expects string|null, int|string given.  
         🪪  argument.type                                                                                                   
  513    Parameter #1 $key of method Drupal\Core\Database\Connection::setKey() expects string, int|string given.             
         🪪  argument.type                                                                                                   
 ------ -------------------------------------------------------------------------------------------------------------------- 

I solved by explicity casting to string the values before passing them to Connection or Log methods.

mondrake’s picture

Rebased and fixed ConnectionTest classes now that PHPStan checks strictly argument types

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community

From what I can tell I believe feedback is addressed, this is tough one but believe it's good.

mradcliffe’s picture

I reviewed the changes, and everything seems to fall in scope of the issue. The ConnectionInfo documentation block is very helpful.

quietone’s picture

I'm triaging RTBC issues. I read the IS, comments and the MR. I didn't find any unanswered questions or other work to do. I agree with what @longwave sadi in #8.

I didn't find any unanswered questions or other work to do. I updated credit.

Leaving at RTBC.

longwave’s picture

Status: Reviewed & tested by the community » Needs work

Sorry but the deprecation notices need updating to 11.5. Do we really need to keep this around until Drupal 13 as well, I don't feel like any of these are going to be widely triggered? Could we deprecate in 11.5 for removal in 12 and just add the types there?

longwave’s picture

Also PHPStan at level 5 will already warn of this from the docblock alone, so I wonder if there is value in doing the deprecation dance at all: https://phpstan.org/r/9cfd0669-86c2-4347-ae21-7a0c54eba090

mradcliffe’s picture

I am worried that we are late in the release cycle for removing stuff from 12, but if it's possible, then that would be okay.

longwave’s picture

Discussed in Slack, let's just leave this for removal in 13, but the deprecation needs bumping to 11.5.

mradcliffe’s picture

Status: Needs work » Reviewed & tested by the community

I confirmed the change from 11.4.0 to 11.5.0 and the tests in ConnectionTest were updated. Change record updated.

mondrake’s picture

The bump commit is not showing up here, it does on GL though.

  • longwave committed 3a8ca189 on main
    refactor: #3532930 Make Drupal\Core\Database\Database type strict and...
longwave’s picture

Status: Reviewed & tested by the community » Fixed

Committed and pushed 3a8ca189fa4 to main. Thanks!

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

longwave’s picture

Status: Fixed » Patch (to be ported)

Did not cherry pick cleanly to 11.x, needs a backport MR.

mondrake’s picture

Version: main » 11.x-dev

mondrake’s picture

Status: Patch (to be ported) » Needs review

backport

dcam’s picture

Status: Needs review » Reviewed & tested by the community

The backport looks good to me. The changes were faithfully copied to 11.x. The only differences that I noticed were a pair of @phpstan-ignore comments that were omitted, which as noted in the commit log are unnecessary.

  • longwave committed 79457002 on 11.x
    refactor: #3532930 Make Drupal\Core\Database\Database type strict and...
longwave’s picture

Status: Reviewed & tested by the community » Fixed

Committed and pushed the backport to 11.x, thanks!

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

mondrake’s picture

Published CR.