Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,16 @@ class RamseyUuidBinaryDevice
#[ORM\Column(type: 'uuid_binary', unique: true)]
public UuidInterface $id;

public function __construct(?UuidInterface $id = null)
#[ORM\Column(type: 'uuid_binary')]
public UuidInterface $externalId;

#[ORM\Column(type: 'uuid_binary')]
public UuidInterface $nameConverted;

public function __construct(?UuidInterface $id = null, ?UuidInterface $externalId = null, ?UuidInterface $nameConverted = null)
{
$this->id = $id ?? Uuid::uuid7();
$this->externalId = $externalId ?? Uuid::uuid7();
$this->nameConverted = $nameConverted ?? Uuid::uuid7();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@
'myDevice' => new QueryParameter(
filter: new UuidBinaryFilter(),
),
'myDevice.externalId' => new QueryParameter(
filter: new UuidBinaryFilter(),
property: 'myDevice.externalId',
),
'name_converted.name_converted' => new QueryParameter(
filter: new UuidBinaryFilter(),
property: 'nameConverted.nameConverted',
),
]
),
new Post(),
Expand All @@ -47,9 +55,13 @@ class RamseyUuidBinaryDeviceEndpoint
#[ORM\ManyToOne]
public ?RamseyUuidBinaryDevice $myDevice = null;

public function __construct(?UuidInterface $id = null, ?RamseyUuidBinaryDevice $myDevice = null)
#[ORM\ManyToOne]
public ?RamseyUuidBinaryDevice $nameConverted = null;

public function __construct(?UuidInterface $id = null, ?RamseyUuidBinaryDevice $myDevice = null, ?RamseyUuidBinaryDevice $nameConverted = null)
{
$this->id = $id ?? Uuid::uuid7();
$this->myDevice = $myDevice;
$this->nameConverted = $nameConverted;
}
}
10 changes: 9 additions & 1 deletion tests/Fixtures/TestBundle/Entity/Uuid/RamseyUuidDevice.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,16 @@ class RamseyUuidDevice
#[ORM\Column(type: 'uuid', unique: true)]
public UuidInterface $id;

public function __construct(?UuidInterface $id = null)
#[ORM\Column(type: 'uuid')]
public UuidInterface $externalId;

#[ORM\Column(type: 'uuid')]
public UuidInterface $nameConverted;

public function __construct(?UuidInterface $id = null, ?UuidInterface $externalId = null, ?UuidInterface $nameConverted = null)
{
$this->id = $id ?? Uuid::uuid7();
$this->externalId = $externalId ?? Uuid::uuid7();
$this->nameConverted = $nameConverted ?? Uuid::uuid7();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@
'myDevice' => new QueryParameter(
filter: new UuidFilter(),
),
'myDevice.externalId' => new QueryParameter(
filter: new UuidFilter(),
property: 'myDevice.externalId',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You give the property here while you didn't have the need for

'myDevice' => new QueryParameter(
      filter: new UuidFilter(),
),

for instance ; is it needed ?

We could have a test with something like

'myDevice.externalId' => new QueryParameter(
      filter: new UuidFilter(),
),
'myDeviceExternalIdAlias' => new QueryParameter(
     filter: new UuidFilter(),
     property: 'myDevice.externalId',
)

no ?

Same for nameConverted like

'nameConverted.nameConverted' => new QueryParameter(
     filter: new UuidBinaryFilter(),
),
'nameConvertedAlias' => new QueryParameter(
     filter: new UuidBinaryFilter(),
     property: 'nameConverted.nameConverted',
),

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without the property, I have the error

{"@context":"\/contexts\/Error","@id":"\/errors\/500","@type":"hydra:Error","detail":"ApiPlatform\\Doctrine\\Orm\\Filter\\AbstractUuidFilter::filterProperty(): Argument #1 ($property) must be of type string, null given, called in xxxxsrc\/Doctrine\/Orm\/Filter\/AbstractUuidFilter.php on line 62","status":500,"type":"\/errors\/500","trace":[{"file":"xxxxsrc\/Doctrine\/Orm\/Filter\/AbstractUuidFilter.php","line":62,"function":"filterProperty","class":"ApiPlatform\\Doctrine\\Orm\\Filter\\AbstractUuidFilter","type":"-\u003E"},{"file":"xxxxsrc\/Doctrine\/Orm\/Extension\/ParameterExtension.php","line":72,"function":"apply","class":"ApiPlatform\\Doctrine\\Orm\\Filter\\AbstractUuidFilter","type":"-\u003E"},{"file":"xxxxsrc\/Doctrine\/Orm\/Extension\/ParameterExtension.php","line":83,"function":"applyFilter","class":"ApiPlatform\\Doctrine\\Orm\\Extension\\ParameterExtension","type":"-\u003E"},{"file":"xxxxsrc\/Doctrine\/Orm\/State\/CollectionProvider.php","line":73,"function":"applyToCollection","class":"ApiPlatform\\Doctrine\\Orm\\Extension\\ParameterExtension","type":"-\u003E"},{"file":"xxxxsrc\/State\/CallableProvider.php","line":43,"function":"provide","class":"ApiPlatform\\Doctrine\\Orm\\State\\CollectionProvider","type":"-\u003E"},{"file":"xxxxsrc\/State\/Provider\/ObjectMapperProvider.php","line":41,"function":"provide","class":"ApiPlatform\\State\\CallableProvider","type":"-\u003E"},{"file":"xxxxsrc\/State\/Provider\/ReadProvider.php","line":84,"function":"provide","class":"ApiPlatform\\State\\Provider\\ObjectMapperProvider","type":"-\u003E"},{"file":"xxxxsrc\/Symfony\/Security\/State\/AccessCheckerProvider.php","line":68,"

I put it in the draft because of that, I'd like to investigate why?

Yes, I can add a test for

'myDeviceExternalIdAlias' => new QueryParameter(
     filter: new UuidFilter(),
     property: 'myDevice.externalId',
)

and

'nameConverted.nameConverted' => new QueryParameter(
     filter: new UuidBinaryFilter(),
),
nameConvertedAlias' => new QueryParameter(
     filter: new UuidBinaryFilter(),
     property: 'nameConverted.nameConverted',
),

But, I think that with nameConverted.nameConverted, the query parameter will be nameConverted.nameConverted and not name_converted.name_converted....

Copy link
Contributor

@VincentLanglet VincentLanglet Jan 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I put it in the draft because of that, I'd like to investigate why?

This is is maybe the same issue than the one I found in my draft or a related one #7667 ?

You could try removing these lines
https://github.com/api-platform/core/pull/7667/files#diff-5e7788e120b00f67edb2447978c868aac8c117f505e150dbf859f603581a9c55L262-L264
to see if it works better for you without the property (?)

But sure your investigation will be interesting ^^

),
'name_converted.name_converted' => new QueryParameter(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a third filter

            'nameConverted.nameConverted' => new QueryParameter(
                filter: new UuidBinaryFilter(),
                property: 'nameConverted.nameConverted',
            ),

?

Cause the key here is just a "name" for the filter no ? It shouldn't have any impact on the query and therefor a camelCase key should be allowed too no ?)

(In the same idea than #7667)

filter: new UuidFilter(),
property: 'nameConverted.nameConverted',
),
]
),
new Post(),
Expand All @@ -47,9 +55,13 @@ class RamseyUuidDeviceEndpoint
#[ORM\ManyToOne]
public ?RamseyUuidDevice $myDevice = null;

public function __construct(?UuidInterface $id = null, ?RamseyUuidDevice $myDevice = null)
#[ORM\ManyToOne]
public ?RamseyUuidDevice $nameConverted = null;

public function __construct(?UuidInterface $id = null, ?RamseyUuidDevice $myDevice = null, ?RamseyUuidDevice $nameConverted = null)
{
$this->id = $id ?? Uuid::uuid7();
$this->myDevice = $myDevice;
$this->nameConverted = $nameConverted;
}
}
10 changes: 9 additions & 1 deletion tests/Fixtures/TestBundle/Entity/Uuid/SymfonyUlidDevice.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,16 @@ class SymfonyUlidDevice
#[ORM\Column(type: 'ulid', unique: true)]
public Ulid $id;

public function __construct(?Ulid $id = null)
#[ORM\Column(type: 'ulid')]
public Ulid $externalId;

#[ORM\Column(type: 'ulid')]
public Ulid $nameConverted;

public function __construct(?Ulid $id = null, ?Ulid $externalId = null, ?Ulid $nameConverted = null)
{
$this->id = $id ?? new Ulid();
$this->externalId = $externalId ?? new Ulid();
$this->nameConverted = $nameConverted ?? new Ulid();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@
'myDevice' => new QueryParameter(
filter: new UlidFilter(),
),
'myDevice.externalId' => new QueryParameter(
filter: new UlidFilter(),
property: 'myDevice.externalId',
),
'name_converted.name_converted' => new QueryParameter(
filter: new UlidFilter(),
property: 'nameConverted.nameConverted',
),
]
),
new Post(),
Expand All @@ -47,9 +55,13 @@ class SymfonyUlidDeviceEndpoint
#[ORM\ManyToOne]
public ?SymfonyUlidDevice $myDevice = null;

public function __construct(?Ulid $id = null, ?SymfonyUlidDevice $myDevice = null)
#[ORM\ManyToOne]
public ?SymfonyUlidDevice $nameConverted = null;

public function __construct(?Ulid $id = null, ?SymfonyUlidDevice $myDevice = null, ?SymfonyUlidDevice $nameConverted = null)
{
$this->id = $id ?? new Ulid();
$this->myDevice = $myDevice;
$this->nameConverted = $nameConverted;
}
}
10 changes: 9 additions & 1 deletion tests/Fixtures/TestBundle/Entity/Uuid/SymfonyUuidDevice.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,16 @@ class SymfonyUuidDevice
#[ORM\Column(type: 'symfony_uuid', unique: true)]
public Uuid $id;

public function __construct(?Uuid $id = null)
#[ORM\Column(type: 'symfony_uuid')]
public Uuid $externalId;

#[ORM\Column(type: 'symfony_uuid')]
public Uuid $nameConverted;

public function __construct(?Uuid $id = null, ?Uuid $externalId = null, ?Uuid $nameConverted = null)
{
$this->id = $id ?? Uuid::v7();
$this->externalId = $externalId ?? Uuid::v7();
$this->nameConverted = $nameConverted ?? Uuid::v7();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@
'myDevice' => new QueryParameter(
filter: new UuidFilter(),
),
'myDevice.externalId' => new QueryParameter(
filter: new UuidFilter(),
property: 'myDevice.externalId',
),
'name_converted.name_converted' => new QueryParameter(
filter: new UuidFilter(),
property: 'nameConverted.nameConverted',
),
]
),
new Post(),
Expand All @@ -46,9 +54,13 @@ class SymfonyUuidDeviceEndpoint
#[ORM\ManyToOne]
public ?SymfonyUuidDevice $myDevice = null;

public function __construct(?Uuid $id = null, ?SymfonyUuidDevice $myDevice = null)
#[ORM\ManyToOne]
public ?SymfonyUuidDevice $nameConverted = null;

public function __construct(?Uuid $id = null, ?SymfonyUuidDevice $myDevice = null, ?SymfonyUuidDevice $nameConverted = null)
{
$this->id = $id ?? Uuid::v7();
$this->myDevice = $myDevice;
$this->nameConverted = $nameConverted;
}
}
70 changes: 70 additions & 0 deletions tests/Functional/Uuid/UuidFilterBaseTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,76 @@ public function testGetOpenApiDescription(): void
);
}

public function testSearchFilterByUuidNested(): void
{
$this->recreateSchema(static::getResources());

$manager = $this->getManager();
$manager->persist($fooDevice = $this->createDevice());
$manager->persist($barDevice = $this->createDevice());
$manager->persist($this->createDeviceEndpoint(null, $fooDevice));
$manager->persist($barDeviceEndpoint = $this->createDeviceEndpoint(null, $barDevice));
$manager->flush();

$response = self::createClient()->request('GET', '/'.$this->getUrlPrefix().'_device_endpoints', [
'query' => [
'myDevice.externalId' => (string) $barDeviceEndpoint->myDevice->externalId,
],
]);

self::assertResponseIsSuccessful();
$json = $response->toArray();

self::assertArraySubset(['hydra:totalItems' => 1], $json);
self::assertArraySubset(
[
'hydra:member' => [
[
'@id' => '/'.$this->getUrlPrefix().'_device_endpoints/'.$barDeviceEndpoint->id,
'@type' => $this->geTypePrefix().'DeviceEndpoint',
'id' => (string) $barDeviceEndpoint->id,
],
],
],
$json
);
}

public function testSearchFilterByUuidNestedWhenNameIsConverted(): void
{
$this->recreateSchema(static::getResources());

$manager = $this->getManager();
$manager->persist($fooDevice = $this->createDevice());
$manager->persist($barDevice = $this->createDevice());
$manager->persist($this->createDeviceEndpoint(null, null, $fooDevice));
$manager->persist($barDeviceEndpoint = $this->createDeviceEndpoint(null, null, $barDevice));
$manager->flush();

$response = self::createClient()->request('GET', '/'.$this->getUrlPrefix().'_device_endpoints', [
'query' => [
'name_converted.name_converted' => (string) $barDeviceEndpoint->nameConverted->nameConverted,
],
]);

self::assertResponseIsSuccessful();
$json = $response->toArray();

self::assertArraySubset(['hydra:totalItems' => 1], $json);
self::assertArraySubset(
[
'hydra:member' => [
[
'@id' => '/'.$this->getUrlPrefix().'_device_endpoints/'.$barDeviceEndpoint->id,
'@type' => $this->geTypePrefix().'DeviceEndpoint',
'id' => (string) $barDeviceEndpoint->id,
],
],
],
$json
);
}

protected function tearDown(): void
{
if ($this->isMongoDB()) {
Expand Down
Loading