BasicEntityPersister::expandParameters() expands criteria parameters with custom types wrong #6871

Open
opened 2026-01-22 15:40:28 +01:00 by admin · 0 comments
Owner

Originally created by @bravik on GitHub (Nov 10, 2021).

BC Break Report

Q A
BC Break yes
ORM Version 2.10.2
DBAL Version 3.1.3

Summary

Short version:
expandParameters method does unwanted conversion of object with custom Doctrine type to plain value, which DBAL later tries to convert again during query execution and fails, because it expects an object. So double conversion happens

Long version:

I have a value object for Id (and actually a lot of other value objects):


/**
 * @ORM\Embeddable
 */
final class Id
{
    /**
     * @ORM\Column(name="id", type="integer", nullable=false, options={"unsigned"=true})
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private int $value;

    public function __construct(int $value)
    {
        Assert::greaterThan($value, 0);
        $this->value = $value;
    }

    public function getValue(): int
    {
        return $this->value;
    }

For it I have a custom Doctrine type IdType:

class IdType extends IntegerType
{
    public const NAME = 'id';

    public function convertToDatabaseValue($value, AbstractPlatform $platform)
    {
        Assert::isInstanceOf($value, Id::class);
        return $value->getValue();
    }
}

which is used in entities:

    /** @ORM\Column(name="customer_id", type="id", nullable=false) */
    private Id $accountId;

In one of my repositories I have:

    public function getByAccountAndMetric(Id $accountId, Metric $metric): Tracker
    {
        $tracker = $this->doctrineRepository->findOneBy([
            'accountId'    => $accountId,
            'metric.value' => $metric->getValue(),
        ]);

Which worked fine, until orm silently updated dbal to version 3.
Now, findOneBy fails to retrieve values.

My investigation led me to BasicEntityPersister::expandParameters() method.
8336420a26/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php (L1817)
8336420a26/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php (L1828)

This method retuns [$params, $types] and passes to dbal to execute query.
In my particular case it should return

Previous behavior

[
    [
        object Id{value => 1},
       "metric"
    ],
    [
        "id",
       "string"
    ]
]

Current behavior

But it actually converts my Id object to plain value and returns:

[
    [
        1,           
       "metric"
    ],
    [
        "id",        // My custom type name
       "string"
    ]
]

Then query is executed and DBAL is trying to convert plain 1 value to id type (see IdType) and it fails

Originally created by @bravik on GitHub (Nov 10, 2021). ### BC Break Report <!-- Fill in the relevant information below to help triage your issue. --> | Q | A |------------ | ------ | BC Break | yes | ORM Version | 2.10.2 | DBAL Version | 3.1.3 #### Summary **Short version:** **`expandParameters` method does unwanted conversion of object with custom Doctrine type to plain value, which DBAL later tries to convert again during query execution and fails, because it expects an object. So double conversion happens** **Long version:** I have a value object for `Id` (and actually a lot of other value objects): ```php /** * @ORM\Embeddable */ final class Id { /** * @ORM\Column(name="id", type="integer", nullable=false, options={"unsigned"=true}) * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ private int $value; public function __construct(int $value) { Assert::greaterThan($value, 0); $this->value = $value; } public function getValue(): int { return $this->value; } ``` For it I have a custom Doctrine type `IdType`: ```php class IdType extends IntegerType { public const NAME = 'id'; public function convertToDatabaseValue($value, AbstractPlatform $platform) { Assert::isInstanceOf($value, Id::class); return $value->getValue(); } } ``` which is used in entities: ```php /** @ORM\Column(name="customer_id", type="id", nullable=false) */ private Id $accountId; ``` In one of my repositories I have: ```php public function getByAccountAndMetric(Id $accountId, Metric $metric): Tracker { $tracker = $this->doctrineRepository->findOneBy([ 'accountId' => $accountId, 'metric.value' => $metric->getValue(), ]); ``` Which worked fine, until orm silently updated dbal to version 3. Now, `findOneBy` fails to retrieve values. My investigation led me to `BasicEntityPersister::expandParameters()` method. https://github.com/doctrine/orm/blob/8336420a266b310db2159949d110e3612e84a85c/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php#L1817 https://github.com/doctrine/orm/blob/8336420a266b310db2159949d110e3612e84a85c/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php#L1828 This method retuns `[$params, $types] ` and passes to dbal to execute query. In my particular case it should return #### Previous behavior ```php [ [ object Id{value => 1}, "metric" ], [ "id", "string" ] ] ``` #### Current behavior But it actually converts my Id object to plain value and returns: ```php [ [ 1, "metric" ], [ "id", // My custom type name "string" ] ] ``` Then query is executed and DBAL is trying to convert plain `1` value to `id` type (see `IdType`) and it fails
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#6871