doctrine / mongodb-odm

The Official PHP MongoDB ORM/ODM
https://www.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/
MIT License
1.09k stars 504 forks source link

Nullable embedded document not initialized when using aggregations #2310

Closed wuchen90 closed 3 years ago

wuchen90 commented 3 years ago

Bug Report

Q A
BC Break no
Version 2.2.1

Summary

This bug is the same as https://github.com/doctrine/mongodb-odm/issues/2301 but with AggregationBuilder.

How to reproduce

class Container
{
    private int $id;
    private ?Embedded $embedded;

    public function __construct(int $id, ?Embedded $embedded)
    {
        $this->id = $id;
        $this->embedded = $embedded;
    }

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

    public function getEmbedded(): ?Embedded
    {
        return $this->embedded;
    }
}

class Embedded
{
    public int $value;

    public function __construct(int $value)
    {
        $this->value = $value;
    }

    public function getValue(): int
    {
        return $this->value;
    }
}
<?xml version="1.0"?>
<doctrine-mongo-mapping xmlns="http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping"
                        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                        xsi:schemaLocation="http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping
                    https://doctrine-project.org/schemas/odm/doctrine-mongo-mapping.xsd">
    <document name="Container">
        <id type="integer" strategy="NONE"/>
        <embed-one field="embedded" target-document="Embedded" nullable="true"/>
    </document>
    <embedded-document name="Embedded">
        <field name="value" type="integer"/>
    </embedded-document>
</doctrine-mongo-mapping>
$container = new Container(10, null);

$documentManager->persist($container);
$documentManager->flush();
$documentManager->clear();

$aggBuilder = $documentManager->createAggregationBuilder(Container::class);
$aggBuilder->match()->field('id')->equals(10);

$container = $aggBuilder->hydrate(Container::class)->getAggregation()->getIterator()->current();

var_dump($container->getEmbedded());

// => Fatal error: Typed property Container::$embedded must not be accessed before initialization

Expected behavior

var_dump($container->getEmbedded());

// => null
alcaeus commented 3 years ago

This surprises me, because the hydrator is the same for the class regardless of the way we fetched the data (find vs. aggregate). I'll take a look after the long weekend. If you can provide a failing test case (you can take inspiration from this one, just use the agg builder instead of find), that would make my work of figuring out what's going on a lot easier.

wuchen90 commented 3 years ago

@alcaeus Actually the bug still occurs with find too: https://github.com/doctrine/mongodb-odm/pull/2316