Problem/Motivation

The Drupal ArgumentsResolver component is unable to handle composite type hints such as string|\Stringable.

Steps to reproduce

  /**
   * Tests getArgument() with string|\Stringable.
   */
  public function testGetArgumentStringable(): void {
    $callable = function (string|\Stringable $string) {};

    $string = 'Untranslated string';
    $arguments = (new ArgumentsResolver([], ['string' => $string], []))->getArguments($callable);
    $this->assertSame([$string], $arguments);

    $stringable = new TranslatableMarkup('Translated string');
    $arguments = (new ArgumentsResolver([], ['string' => $stringable], []))->getArguments($callable);
    $this->assertSame([$stringable], $arguments);
  }

This results in an error.

Proposed resolution

Introduce symfony/type-info component and use it in ArgumentsResolver.

Dependency Evaluation

Maintainership of the package

The package is maintained in the symfony source since Symfony 7.1

The package is maintained as part of the symfony monorepo.

Security policies of the package

The package is covered by the Symfony security process.

Expected release and support cycles

The package has been introduced as experimental in Symfony 7.1. Since Symfony 7.2 the component is stable and covered by the Symfony BC policy.

Code quality

Same as with other Symfony components.

Other dependencies it would add, if any (the full tree, not just direct dependencies), and evaluations for those dependencies as well

This package requires PHP 8.2, some psr/container implementation and symfony/deprecation-contracts. All of that is already required by core.

Remaining tasks

User interface changes

Introduced terminology

API changes

Data model changes

Release notes snippet

Issue fork drupal-3548968

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

znerol created an issue. See original summary.

znerol’s picture

Status: Active » Needs review
znerol’s picture

Adding dependency evaluation section and required issue tags.

mstrelan’s picture

Seems like a good idea, just one question on the test

znerol’s picture

znerol’s picture

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new91 bytes

The Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. 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.

znerol’s picture

Status: Needs work » Needs review
geek-merlin’s picture

Reviewed the MR.

It looks good and does what it announces:
- It adds the library
- leverages it in ArgumentsResolver the way expected
- adds a test that elegantly covers both code paths, scalar and object

Yay, i waited a long time for this one.

I'd set this RTBC, but one check is missing:
- [ ] Test-only is red

For some reason i seem not to be permitted to start the test-only manual action (both ones, and yes, i'm logged in, and tried to re-login.)

So if that is checked, it's RTBC.

znerol’s picture

Thanks, I kicked off the test-only pipeline (results).

geek-merlin’s picture

Status: Needs review » Reviewed & tested by the community

Great! Setting RTBC as of #10 plus test-only result.
The new test fails as expected.

(Still wondering why i could not trigger the test-only run myself...)

Note on the failing test: That test shows that the existing ArgumentResolver code throws a rather obscure error on union types.
Nice that that one is fixed by this MR too!

geek-merlin’s picture

No changes, still rtbc.

longwave’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: -Needs release manager review

core/lib/Drupal/Component/Utility/composer.json also needs to add the new dependency.

This makes sense to me, we're going to need it sooner or later somewhere (if we don't already), and it's just another Symfony dependency to add to the pile - no issues from the release management side, so untagging for that.

znerol’s picture

Status: Needs work » Needs review
geek-merlin’s picture

Status: Needs review » Reviewed & tested by the community

The new commit adds the #14 composer.json line.
Nothing else changed, so still rtbc.

needs-review-queue-bot’s picture

Status: Reviewed & tested by the community » Needs work
StatusFileSize
new91 bytes

The Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. 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.

znerol’s picture

Status: Needs work » Needs review

Rebased.

nicxvan’s picture

Will this help with the closure type resolving?

znerol’s picture

ArgumentsResolver::getArguments() works fine with any callable (closures included). This MR doesn't change that.

ghost of drupal past’s picture

tl;dr: symfony/type-info is probably the best bet indeed but I am very slightly worried about performance.

I have reviewed the problem instead of the branch and had the following thoughts:

  1. One obvious alternative which deals with types would be phpstan. I wrote draft implementation but phpstan is not distributed in a reusable library format. phpstan/phpstan puts phpstan in a phar and phpstan/phpstan-src is not in packagist at all, needs to be downloaded from github and installing it with composer as a vcs repo takes forever because of the hundreds of tags it downloads. This is a no-go. However, on further reading I have found symfony/type-info supports phpstan types from phpdoc which made me quite happy. I would love to see a followup exploring this. phpstan types for the win.
  2. But before that reading I have coded this with nette/utils because I much prefer the (much) simpler API and source code and this revealed something interesting.

So with nettle/utils it would start like this:

    if ($parameter->hasType()) {
      $parameter_type = Type::fromReflection($parameter);
      // If the argument exists and complies with the type hint, return it.
      if (isset($this->objects[$parameter_name]) && $parameter_type->allows(Type::fromValue($this->objects[$parameter_name]))) {
        return $this->objects[$parameter_name];
      }

What this reveals is that you can't determine whether the parameter type allows/accepts the value without determining the type of the value. This might be obvious but I sure didn't catch this without writing it out. This certainly raises the question: would it make sense to store the types of objects/scalars/wildcards? The reason to do so would be performance to avoid recalculating the type of values but is that a legit concern? How much is this called anyways? And overall, what does the performance impact look like if anything?

And I am not sure whether storing value types would be useful with symfony/type-info: there is a $type->accepts($value) API but is there a $type->allows($other_type API?

znerol’s picture

Request routing relies on Symfony ArgumentResolver (see also these docs). This MR doesn't change anything about request routing.

Drupal ArgumentsResolver (note the s) is used in access checks and in the rest module. Hence, this MR allows for composed types in access checks and rest resources.

Regarding performance: Profiling of this change is indeed necessary. Access checks are not only performed when an incoming request is routed, but also when links are generated (AFAIR).

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: Needs review » Needs work
StatusFileSize
new91 bytes

The Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. 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.