Skip to content

Multi-link operation provider gets incorrect parameter values ​​when enable_link_security is enabled #7282

Open
@7-zete-7

Description

@7-zete-7

API Platform version(s) affected: 4.1.18

Description
The ApiPlatform\State\ParameterProvider\ReadLinkParameterProvider::getUriVariables() method returns the same values ​​for all parameters.

How to reproduce
It is enough to set up an operation with more than one Link and enable the enable_link_security.

How to test
final class ReadLinkParameterProviderTest extends PHPUnit\Framework\TestCase
{
    public function testProvideWithComplexLink(): void
    {
        $locator = $this->createMock(ApiPlatform\State\ProviderInterface::class);
        $resourceMetadataCollectionFactory = $this->createMock(ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface::class);

        $provider = new ApiPlatform\State\ParameterProvider\ReadLinkParameterProvider(
            locator: $locator,
            resourceMetadataCollectionFactory: $resourceMetadataCollectionFactory,
        );

        $firstParameter = new ApiPlatform\Metadata\Link(
            parameterName: 'first',
            fromClass: DateTimeImmutable::class, // stub
        );
        $firstParameter->setValue('foo');

        $secondParameter = new ApiPlatform\Metadata\Link(
            parameterName: 'second',
            fromClass: DateTimeImmutable::class, // stub
        );
        $secondParameter->setValue('bar');

        $thirdParameter = new ApiPlatform\Metadata\Link(
            parameterName: 'third',
            fromClass: DateTimeImmutable::class, // stub
        );
        $thirdParameter->setValue('baz');

        $parameters = [
            'first' => $firstParameter,
            'second' => $secondParameter,
            'third' => $thirdParameter,
        ];

        $operation = new ApiPlatform\Metadata\GetCollection(
            extraProperties: [
                'parent_uri_template' => 'stub_uri',
            ],
            parameters: $parameters,
            uriVariables: $parameters,
        );

        $resourceMetadataCollection = new ApiPlatform\Metadata\Resource\ResourceMetadataCollection(
            resourceClass: DateTimeImmutable::class, // stub
            input: [
                new ApiPlatform\Metadata\ApiResource(
                    operations: [
                        'stub_uri' => $operation,
                    ],
                ),
            ],
        );

        $resourceMetadataCollectionFactory
            ->method('create')
            ->willReturn($resourceMetadataCollection)
        ;

        $locator
            ->expects($this->once())
            ->method('provide')
            ->with(
                self::identicalTo($operation),
                self::identicalTo([
                    'first' => 'foo',
                    'second' => 'bar',
                    'third' => 'baz',
                ]),
                self::anything(),
            )
            ->willReturn($this->createStub(ApiPlatform\Metadata\Operation::class))
        ;

        $provider->provide(
            parameter: $thirdParameter,
            parameters: $parameters,
            context: [
                'operation' => $operation,
            ],
        );
    }
}
Test result
Expectation failed for method name is "provide" when invoked 1 time
Parameter 1 for invocation ApiPlatform\State\ProviderInterface::provide(ApiPlatform\Metadata\GetCollection Object (...), [...], [...]): array|null|object does not match expected value.
Failed asserting that two arrays are identical.
--- Expected
+++ Actual
@@ @@
 Array &0 [
-    'first' => 'foo',
-    'second' => 'bar',
+    'first' => 'baz',
+    'second' => 'baz',
     'third' => 'baz',
 ]

Possible Solution
I guess we need to rethink the way we get values ​​for $uriVariables so that each parameter can have its own value.

foreach ($links as $key => $link) {
if (!\is_string($key)) {
$key = $link->getParameterName() ?? $extraProperties['uri_variable'] ?? $link->getFromProperty();
}
if (!$key || !\is_string($key)) {
continue;
}
$uriVariables[$key] = $value;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions