Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

NULL returned instead of collection after update to 2.14.0 #10376

Closed
DigitalTimK opened this issue Jan 5, 2023 · 13 comments
Closed

NULL returned instead of collection after update to 2.14.0 #10376

DigitalTimK opened this issue Jan 5, 2023 · 13 comments

Comments

@DigitalTimK
Copy link

DigitalTimK commented Jan 5, 2023

BC Break Report

Q A
BC Break yes
Version 2.13.4 => 2.14.0
Symfony 5.4
PHP (on localhost) 8.1.13
PHP (in composer.json) "require": { "php": "^7.3.0" ...}

Summary

After composer update "doctrine/orm" I have an error during my phpunit (v9.5.27) tests. The returned value (children) is null instead of an collection.

Previous behavior

tests are running w/o error

Current behavior

Tests raise an error: TypeError: App\Entity\Pricing::getDiscounts(): Return value must be of type Doctrine\Common\Collections\Collection, null returned

How to reproduce

This error seems to be happen only during PHPUNIT-test. I encounter no issue when calling this function in a controller or in twig.

class Pricing
{
    /**
     * @var int
     *
     * @ORM\Column(name="RabattGruppeID", type="integer", nullable=false, options={"unsigned"=true})
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="CUSTOM")
     * @ORM\CustomIdGenerator(class="App\Service\RandomIdGenerator")
     */
    private $id;

    /* ... */

    /**
     * @ORM\OneToMany(targetEntity=Discount::class, mappedBy="pricing", cascade={"persist"})
     * @ORM\OrderBy({"until" = "ASC"})
     */
    private $discounts;

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

    /**
     * @return Collection|Discount[]
     */
    public function getDiscounts(): Collection
    {
        return $this->discounts;
    }

    public function addDiscount(Discount $discount): self
    {
        if (!$this->discounts->contains($discount)) {
            $this->discounts[] = $discount;
            $discount->setPricing($this);
        }

        return $this;
    }

    public function removeDiscount(Discount $discount): self
    {
        if ($this->discounts->contains($discount)) {
            $this->discounts->removeElement($discount);
            // set the owning side to null (unless already changed)
            if ($discount->getPricing() === $this) {
                $discount->setPricing(null);
            }
        }

        return $this;
    }
}
class Discount
{
    /**
     * @var int
     *
     * @ORM\Column(name="RabattDetailID", type="integer", nullable=false, options={"unsigned"=true})
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="CUSTOM")
     * @ORM\CustomIdGenerator(class="App\Service\RandomIdGenerator")
     */
    private $id;

    /* ... */

    /**
     * @var Pricing
     *
     * @ORM\ManyToOne(targetEntity=Pricing::class, inversedBy="discounts")
     * @ORM\JoinColumn(name="FK_RabattGruppeID", referencedColumnName="RabattGruppeID", nullable=false)
     */
    private $pricing;


    public function getPricing(): ?Pricing
    {
        return $this->pricing;
    }

    public function setPricing(?Pricing $pricing): self
    {
        $this->pricing = $pricing;

        return $this;
    }
}
@mbabker
Copy link
Contributor

mbabker commented Jan 5, 2023

As a suggested best practice, you should instantiate a default collection in your entity's constructor to ensure it has a valid state before it's persisted.

Not knowing how your test works, at the bare minimum, a (new Pricing())->getDiscounts() would hit the same issue of returning null.

@joshlopes
Copy link

joshlopes commented Jan 5, 2023

I'm actually getting the same, and on my constructor I'm setting an ArrayCollection, but the lazy proxy is returning null instead on my test and strict type failed.

image

foreach() argument must be of type array|object, null given
...
 /var/www/var/cache/test/doctrine/orm/Proxies/__CG__AppBundleEntityProductCategory.php:1402
...

The upgrade was suggested by dependabot but tests started failing.

The issue happens after the data is persisted, the proxy seems unable to fetch the right data or when it does the data is not what it is in the database, so something must be blocking it to properly initialise -- that would be my guess.

@DigitalTimK
Copy link
Author

DigitalTimK commented Jan 5, 2023

Hey @mbabker.
thanks for this quick reaction. Actually I am initiating the variable in the constructor. I didn't put these details in my description above. I updated my initial bug report which is now showing the constructor.

@simonberger
Copy link
Contributor

There is a possibility your issues or at least one of those is fixed by #10362. It could be helpful if you try those changes on your tests.

@joshlopes
Copy link

@simonberger it sounds like it does fix the current issue -- I just tried to manually load the data after using fixtures on my test and the test passed. So between loading fixtures and using it through proxies it fails, all proxy data is empty, only have id, rest of the fields are empty.

Thanks for all your work everyone 👌

@simonberger
Copy link
Contributor

Yes I expected the problem to be your private id field which the PR fixes. In case someone fights the problem a workaround can also be the change the visibility of the identifier to protected.

@DigitalTimK
Copy link
Author

DigitalTimK commented Jan 5, 2023

I was also able to solve the issue. In my case I lost the data below the initial object (lazy loading?) by decomposing to much the object... so this is why the result was NULL.

Not sure if I shall close this ... at least my solution is a work around.... But at the end this new version created an issue that might need to be solved on doctrine's side.

@derrabus
Copy link
Member

derrabus commented Jan 6, 2023

If the problem is solved for you, feel free to close. But if we should accept it as a bug, we need a stable reproducer or a failing test. A reproducer would be a repository that I can check out and execute in order to reproduce your problem.

@DigitalTimK
Copy link
Author

So, I will close this item as I was not able to produce a failing specimen.

@flohw
Copy link

flohw commented Jan 16, 2023

Is it possible that this issue is related to #10336 ? I had the same behavior : using my fixtures just after they were initialized everything was fine but as soon as I started a functional test (EM::clear() is called), I got this error. Not on collection though but on standard property which were not initialized properly somewhere.

I downgraded to doctrine/orm:2.13.5 for now waiting for the next release.

@mpdude
Copy link
Contributor

mpdude commented Jan 31, 2023

@DigitalTimK did I get it right that you intended to close this issue?

@derrabus derrabus closed this as not planned Won't fix, can't repro, duplicate, stale Jan 31, 2023
@DigitalTimK
Copy link
Author

@mpdude yes, that correct.

@Herz3h
Copy link

Herz3h commented Aug 11, 2023

Just for information, this happened to me with ORM 2.9.5 after upgrading from php 7.4 to php 8.1 and after debugging, it seems that there was an "invalid mapping" exception that was silently thrown here: https://github.com/doctrine/orm/blob/2.16.x/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php#L269

The reason is that one of my entity's relation, was implementing JsonSerializable, but didn't have a return type. Which threw this error:

Error: During inheritance of JsonSerializable: Uncaught

I had to add a return type to jsonSerialized() as required by php 8.1

And that fixed my Collection being null problem

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants