Skip to content

Query built incorrectly when having embedMany with discriminatorMap and non BSON id field #2531

Open
@xammmue

Description

@xammmue

Bug Report

Q A
BC Break no
Version 2.5.2

Summary

I created a combination of 5 classes Tree, Branch, Fruit, Apple and Mango. Apple and Mango extend Frui.
A Tree embeds many branches and a branch embeds many fruits using a discriminator field and discriminator map.
Fruit also has an id property which is not a BSON id but some other string (in this example UUID V4) which was generated from outside.

Current behavior

Writing a query to find a branch by a fruit id fails, as the query builder converts the value for the id field into a BSON Object id.

$this->createQueryBuilder()
            ->field('branches.fruits.id')->equals($fruitId)
            ->getQuery();

image

This is what it looks like when also specifying the targetDocument for Branch.fruits to be Fruit::class which has been deprecated.
image

How to reproduce

I provided an example here: https://github.com/xammmue/embedManyWithNonBSONId
But these are the essentials:

The bug only occurs when there is a "chain" of at least two embedded documents.

#[Document]
class Tree
{
    #[Id]
    private $id;
    #[EmbedMany(targetDocument: Branch::class)]
    private Collection $branches;

    public function __construct(array $branches)
    {
        $this->branches = new ArrayCollection($branches);
    }

    public function getId()
    {
        return $this->id;
    }

    public function getBranches(): array
    {
        return $this->branches->toArray();
    }
}
#[EmbeddedDocument]
class Branch
{
    #[
        EmbedMany(
            //targetDocument: Fruit::class,
            discriminatorField: Fruit::DISCRIMINATOR_FIELD,
            discriminatorMap: Fruit::DISCRIMINATOR_MAP
        )
    ]
    private Collection $fruits;

    public function __construct(array $fruits)
    {
        $this->fruits = new ArrayCollection($fruits);
    }

    public function getFruits(): Collection
    {
        return $this->fruits;
    }
}
#[EmbeddedDocument]
class Fruit
{
    public const DISCRIMINATOR_FIELD = 'type';
    public const DISCRIMINATOR_MAP = [
        'Apple' => Apple::class,
        'Mango' => Mango::class
    ];

    #[Field]
    private string $id;

    #[Field]
    private bool $ripe;

    public function __construct(string $id, bool $ripe)
    {
        $this->id = $id;
        $this->ripe = $ripe;
    }

    public function getId(): string
    {
        return $this->id;
    }

    public function isRipe(): bool
    {
        return $this->ripe;
    }
}
class TreeRepository extends ServiceDocumentRepository
{
    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, Tree::class);
    }

    public function findByFruitId(string $fruitId): ?Tree
    {
        return $this->createQueryBuilder()
            ->field('branches.fruits.id')->equals($fruitId)
            ->getQuery()
            ->getSingleResult();
    }
}

Expected behavior

I expected the correct Tree to be returned / the correct query to be built.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions