Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Nullable embedded documents not initialized #2453

Closed
p-golovin opened this issue Aug 15, 2022 · 6 comments
Closed

Nullable embedded documents not initialized #2453

p-golovin opened this issue Aug 15, 2022 · 6 comments

Comments

@p-golovin
Copy link

Bug Report

Q A
BC Break no
Version 2.4.2

Summary

Problem is quite similar to #2301, but we try to configure not with xml, but with attributes.

Current behavior

class Publication
{
    #[ODM\EmbedOne(targetDocument: Image::class, nullable: true)]
    private ?Image $image;

    public function getImage(): ?Image
    {
        return $this->image;
    }
}

class Image
{
    #[ODM\Field]
    private string $url;

    public function getUrl(): string
    {
        return $this->url;
    }
}

On loading document without Image subdocument we get error
Typed property Publication::$image must not be accessed before initialization
on request
$pub->getImage();

Expected behavior

Get null.

@malarzm
Copy link
Member

malarzm commented Aug 15, 2022

but we try to configure not with xml, but with attributes.

I don't think this is related as nothing mapping related changed in #2302. I'd rather guess that your document has no null field stored in the database?

@p-golovin
Copy link
Author

p-golovin commented Aug 15, 2022

We tried both cases:

  1. Without null stored in database.
    Get error.

  2. With null stored in database.
    Get no error in case of requesting full field 'image' in query builder projection:
    $qb->select('title', 'pub_date', 'image')
    And get error in case of requesting 'image.url' subfield:
    $qb->select('title', 'pub_date', 'image.url')

I think, that field need to be initialised with null even in case of absence in database document (In case we embed collection of documents, it is initialised with empty collection in any case, even if there is no such key in database). Or there are another ways to deal with this?

@malarzm
Copy link
Member

malarzm commented Aug 15, 2022

Or there are another ways to deal with this?

Try making null a default value: private ?Image $image = null;. That way the field will be initialized with null even though ODM didn't hydrate the field.

With null stored in database. [...] And get error in case of requesting 'image.url' subfield:

Is the error coming from hydration as well?

@p-golovin
Copy link
Author

p-golovin commented Aug 15, 2022

  1. In case of storing null in database and use 'image' in projection:
    image
    All works at this point. But there is problem with document serialisation: we get 'image': null in json instead of absence image field.

  2. In case of storing null in database and using 'image.url' in projection:
    image
    No errors on hydration, but no 'image' field in document. So error Typed property Publication::$image must not be accessed before initialisation.

  3. If we use private ?Image $image = null; then we have field in serialised document again:
    image
    We can solve this with options of serialisation context.

So only question with projection is actual.

@malarzm
Copy link
Member

malarzm commented Aug 15, 2022

In case of storing null in database and using 'image.url' in projection:

Using 3 should still make projection "work" as the image will be initialized to null, no? Generally speaking if there's no image object in stored document projection will not return it. Same goes for null:

> db.test.find();
{ "_id" : ObjectId("62faa4f3417246422135f933"), "name" : "Withembed", "embed" : { "test" : "aaa" } }
{ "_id" : ObjectId("62faa50d417246422135f934"), "name" : "Noembed" }
{ "_id" : ObjectId("62faa589417246422135f935"), "name" : "Nulled", "embed" : null }
> db.test.find({}, {"name": 1, "embed.test": 1});
{ "_id" : ObjectId("62faa4f3417246422135f933"), "name" : "Withembed", "embed" : { "test" : "aaa" } }
{ "_id" : ObjectId("62faa50d417246422135f934"), "name" : "Noembed" }
{ "_id" : ObjectId("62faa589417246422135f935"), "name" : "Nulled" }

@p-golovin
Copy link
Author

Thank you! This works well.

@malarzm malarzm closed this as completed Aug 16, 2022
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants