'contains' returns false even the element is contained #5322

Open
opened 2026-01-22 15:04:31 +01:00 by admin · 12 comments
Owner

Originally created by @enekochan on GitHub (Nov 13, 2016).

Originally assigned to: @enekochan on GitHub.

I have 2 entities, Service and Resource, with a ManyToMany relation between them. Service has the usual getResources() method and Resource the getServices() method. The Service class also has a getEnabledResources method that uses Criteria to get all Resource objects that have a status attribute to a certain value (enabled). I just wrote a repository method findEnabledResources for Service that achieves the same result as the getEnabledResources method with Criteria. My intention is to remove the use of Criteria in the app.

There's a point I store all the enabled resources for a service calling the repository method findEnabledResources and then check with contains if each one of those resources are contained in a Service object with something like this:

$enabledResources = $serviceRespository->findEnabledResources($service);
...
foreach ($enabledResources as $resource) {
    if (!$service->getResources()->contains($resource)) {
        //
    }
}

I know for sure that a resource object is contained (I can see it while debugging) but contains still returns false, thus entering in the if block.

If I use getEnabledResources (with Criteria) the contains method works just fine!

$enabledResources = $service->getEnabledResources();
...
foreach ($enabledResources as $resource) {
    if (!$service->getResources()->contains($resource)) {
        //
    }
}

What I've been able to see while debugging is that $service->getResources() returns a Doctrine\ORM\PersistentCollection with the collection having proxie objects with class Proxies\__CG__\AppBundle\Entity\Resource. In findEnabledResources I'm returning an ArrayCollection of actual AppBundle\Entity\Resource objects. I've tried using EAGER fetch but still get the same problem.

I'm using doctrine/orm and doctrine/dbal on dev-master".

Resumed entity classes and repository:

class Service
{
    ...

    /**
     * @ORM\ManyToMany(targetEntity="\AppBundle\Entity\Resource", inversedBy="services", cascade={"persist","remove"})
     * @ORM\JoinTable(name="resources_services")
     */
    protected $resources;

    public function getResources()
    {
        return $this->resources;
    }

    public function getEnabledResources($onlyVisible = true)
    {
        $criteria = Criteria::create()
            ->where(Criteria::expr()->eq('status', Resource::STATUS_ENABLED))
            ->orderBy(array('name' => Criteria::ASC))
        ;

        if ($onlyVisible) {
            $criteria->andWhere(Criteria::expr()->eq('visible', true));
        }

        return $this->getResources()->matching($criteria);
    }

    ...
}
class Resource
{
    ...

    /**
     * @ORM\ManyToMany(targetEntity="\AppBundle\Entity\Service", mappedBy="resources", cascade={"persist","remove"})
     */
    protected $services;

    public function getServices()
    {
        return $this->services;
    }

    ...
}
class ServiceRepository extends EntityRepository
{
    public function findEnabledResources(Service $service, $onlyVisible = true)
    {
        $qb = $this->getEntityManager()->createQueryBuilder()
            ->select('r')
            ->from('AppBundle:Resource', 'r')
            ->innerJoin('r.services', 's', 'WITH', 's.id = :service')
            ->andWhere('r.status = :status')
            ->setParameter('service', $service)
            ->setParameter('status', Resource::STATUS_ENABLED)
            ->orderBy('r.name', 'ASC');

        if ($onlyVisible) {
            $qb
                ->andWhere('r.visible = :visible')
                ->setParameter('visible', true);
        }

        return new ArrayCollection($qb->getQuery()->getResult());
    }
}
Originally created by @enekochan on GitHub (Nov 13, 2016). Originally assigned to: @enekochan on GitHub. I have 2 entities, Service and Resource, with a ManyToMany relation between them. Service has the usual `getResources()` method and Resource the `getServices()` method. The Service class also has a `getEnabledResources` method that uses `Criteria` to get all Resource objects that have a `status` attribute to a certain value (enabled). I just wrote a repository method `findEnabledResources` for Service that achieves the same result as the `getEnabledResources` method with `Criteria`. My intention is to remove the use of `Criteria` in the app. There's a point I store all the enabled resources for a service calling the repository method `findEnabledResources` and then check with `contains` if each one of those resources are contained in a Service object with something like this: ```PHP $enabledResources = $serviceRespository->findEnabledResources($service); ... foreach ($enabledResources as $resource) { if (!$service->getResources()->contains($resource)) { // } } ``` I know for sure that a resource object is contained (I can see it while debugging) but `contains` still returns false, thus entering in the if block. If I use `getEnabledResources` (with `Criteria`) the `contains` method works just fine! ```PHP $enabledResources = $service->getEnabledResources(); ... foreach ($enabledResources as $resource) { if (!$service->getResources()->contains($resource)) { // } } ``` What I've been able to see while debugging is that `$service->getResources()` returns a Doctrine\ORM\PersistentCollection with the collection having proxie objects with class `Proxies\__CG__\AppBundle\Entity\Resource`. In `findEnabledResources` I'm returning an ArrayCollection of actual `AppBundle\Entity\Resource` objects. I've tried using EAGER fetch but still get the same problem. I'm using doctrine/orm and doctrine/dbal on dev-master". Resumed entity classes and repository: ```PHP class Service { ... /** * @ORM\ManyToMany(targetEntity="\AppBundle\Entity\Resource", inversedBy="services", cascade={"persist","remove"}) * @ORM\JoinTable(name="resources_services") */ protected $resources; public function getResources() { return $this->resources; } public function getEnabledResources($onlyVisible = true) { $criteria = Criteria::create() ->where(Criteria::expr()->eq('status', Resource::STATUS_ENABLED)) ->orderBy(array('name' => Criteria::ASC)) ; if ($onlyVisible) { $criteria->andWhere(Criteria::expr()->eq('visible', true)); } return $this->getResources()->matching($criteria); } ... } ``` ```PHP class Resource { ... /** * @ORM\ManyToMany(targetEntity="\AppBundle\Entity\Service", mappedBy="resources", cascade={"persist","remove"}) */ protected $services; public function getServices() { return $this->services; } ... } ``` ```PHP class ServiceRepository extends EntityRepository { public function findEnabledResources(Service $service, $onlyVisible = true) { $qb = $this->getEntityManager()->createQueryBuilder() ->select('r') ->from('AppBundle:Resource', 'r') ->innerJoin('r.services', 's', 'WITH', 's.id = :service') ->andWhere('r.status = :status') ->setParameter('service', $service) ->setParameter('status', Resource::STATUS_ENABLED) ->orderBy('r.name', 'ASC'); if ($onlyVisible) { $qb ->andWhere('r.visible = :visible') ->setParameter('visible', true); } return new ArrayCollection($qb->getQuery()->getResult()); } } ```
admin added the BugMissing Tests labels 2026-01-22 15:04:31 +01:00
Author
Owner

@mpdude commented on GitHub (Apr 12, 2018):

So, your Collection contains Proxies, but you're passing a real entity into the contains() method?

@mpdude commented on GitHub (Apr 12, 2018): So, your `Collection` contains Proxies, but you're passing a *real* entity into the `contains()` method?
Author
Owner

@Ocramius commented on GitHub (Apr 13, 2018):

The bug here is possibly that the private properties are not lazily loaded. Can you try changing the properties to public, re-generating the proxies and re-running this?

Also, I think this is fixed in master (3.x)

@Ocramius commented on GitHub (Apr 13, 2018): The bug here is possibly that the `private` properties are not lazily loaded. Can you try changing the properties to `public`, re-generating the proxies and re-running this? Also, I think this is fixed in `master` (`3.x`)
Author
Owner

@TheCelavi commented on GitHub (Jun 2, 2018):

I do not know if this helps, gives additional clues, or it is totally unrelated, we just had similar issue, everything worked fine, until Symfony upgrade from 3.4.2 to 3.4.11, and s*** hits the fan.

https://github.com/FriendsOfSymfony/FOSMessageBundle/issues/319#issuecomment-394083941

Downgrade fixed issue. I will probably investigate which symfony 3.4.x version broke a thing, if I get anything useful, will share....

@TheCelavi commented on GitHub (Jun 2, 2018): I do not know if this helps, gives additional clues, or it is totally unrelated, we just had similar issue, everything worked fine, until Symfony upgrade from 3.4.2 to 3.4.11, and s*** hits the fan. https://github.com/FriendsOfSymfony/FOSMessageBundle/issues/319#issuecomment-394083941 Downgrade fixed issue. I will probably investigate which symfony 3.4.x version broke a thing, if I get anything useful, will share....
Author
Owner

@kyeno commented on GitHub (Mar 22, 2019):

I've just hit the very same issue on symfony 3.4.23 and doctrine/orm 2.6.3

@kyeno commented on GitHub (Mar 22, 2019): I've just hit the very same issue on symfony 3.4.23 and doctrine/orm 2.6.3
Author
Owner

@SenseException commented on GitHub (Mar 24, 2019):

Please try to recreate this behaviour on Doctrine ORM only without Symfony in a test.

@SenseException commented on GitHub (Mar 24, 2019): Please try to recreate this behaviour on Doctrine ORM only without Symfony in a test.
Author
Owner

@quazardous commented on GitHub (Apr 3, 2019):

Hi same here with SF v4.2.4 + doctrine/orm 2.6.3

EDIT Found what broke it down !!!

services:
...
    App\EventSubscriber\EntitiesLifecycleSubscriber:
        tags: [doctrine.event_subscriber]

<?php
// src/EventSubscriber/EntitiesLifecycleSubscriber.php
namespace App\EventSubscriber;

use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\LifecycleEventArgs;
use App\Entity\Game;
use Doctrine\ORM\Events;
use App\Service\XXX;

class EntitiesLifecycleSubscriber implements EventSubscriber
{
    protected $XXX;
    public function __construct(XXX $XXX)
    {
        $this->XXX = $XXX;
    }
    
    public function getSubscribedEvents()
    {
        return [
            Events::prePersist,
            Events::preUpdate,
        ];
    }
    
    public function preUpdate(LifecycleEventArgs $args)
    {
        $entity = $args->getObject();
        if ($entity instanceof Game) {
            $this->setGameIssue($entity);
        }
    }
    
    public function prePersist(LifecycleEventArgs $args)
    {
        $entity = $args->getObject();
        if ($entity instanceof Game) {
            $this->setGameIssue($entity);
        }
    }
    
    protected function setGameIssue(Game $game)
    {
        if ($game->getPublished() && is_null($game->getIssue())) {
            $game->setIssue($this->XXX->getNextIssue());
        }
    }
}

but my problem is on User / Group ManyToMany relation so it's some kind of side effect of plugin a event_subscriber...

EDIT2:

using doctrine entity listener is a NO GO too

https://symfony.com/doc/master/bundles/DoctrineBundle/entity-listeners.html

@quazardous commented on GitHub (Apr 3, 2019): Hi same here with SF v4.2.4 + doctrine/orm 2.6.3 EDIT Found what broke it down !!! ```yaml services: ... App\EventSubscriber\EntitiesLifecycleSubscriber: tags: [doctrine.event_subscriber] ``` ```php <?php // src/EventSubscriber/EntitiesLifecycleSubscriber.php namespace App\EventSubscriber; use Doctrine\Common\EventSubscriber; use Doctrine\ORM\Event\LifecycleEventArgs; use App\Entity\Game; use Doctrine\ORM\Events; use App\Service\XXX; class EntitiesLifecycleSubscriber implements EventSubscriber { protected $XXX; public function __construct(XXX $XXX) { $this->XXX = $XXX; } public function getSubscribedEvents() { return [ Events::prePersist, Events::preUpdate, ]; } public function preUpdate(LifecycleEventArgs $args) { $entity = $args->getObject(); if ($entity instanceof Game) { $this->setGameIssue($entity); } } public function prePersist(LifecycleEventArgs $args) { $entity = $args->getObject(); if ($entity instanceof Game) { $this->setGameIssue($entity); } } protected function setGameIssue(Game $game) { if ($game->getPublished() && is_null($game->getIssue())) { $game->setIssue($this->XXX->getNextIssue()); } } } ``` but my problem is on User / Group ManyToMany relation so it's some kind of side effect of plugin a `event_subscriber`... EDIT2: using doctrine entity listener is a **NO GO** too https://symfony.com/doc/master/bundles/DoctrineBundle/entity-listeners.html
Author
Owner

@yellow1912 commented on GitHub (Apr 30, 2019):

I think I'm running into this issue or at least something very similar. I'm on Doctrine ORM 2.6.3 and running into this very weird case where an entity object is queried via the repository just 1 line above, then if I use the objectManager to check for "contains" it returns false.

Edit: actually my issue is something different, I have noticed it just now. Going to delete this message.

@yellow1912 commented on GitHub (Apr 30, 2019): I think I'm running into this issue or at least something very similar. I'm on Doctrine ORM 2.6.3 and running into this very weird case where an entity object is queried via the repository just 1 line above, then if I use the objectManager to check for "contains" it returns false. Edit: actually my issue is something different, I have noticed it just now. Going to delete this message.
Author
Owner

@AntoniusGolly commented on GitHub (Jul 7, 2019):

@yellow1912 can you tell me anyways? I just need a hint. I have the exact same issue. I can see the entity in the debugger just fine, but still contains() returns false. Maybe your solution gives me a hint to investigate...

@AntoniusGolly commented on GitHub (Jul 7, 2019): @yellow1912 can you tell me anyways? I just need a hint. I have the exact same issue. I can see the entity in the debugger just fine, but still `contains()` returns false. Maybe your solution gives me a hint to investigate...
Author
Owner

@lcobucci commented on GitHub (Sep 5, 2019):

It would be extremely helpful if someone could provide a PR with a failing functional that reproduces this behaviour. Any volunteer?

@lcobucci commented on GitHub (Sep 5, 2019): It would be extremely helpful if someone could provide a PR with a failing functional that reproduces this behaviour. Any volunteer?
Author
Owner

@hubertnnn commented on GitHub (Nov 13, 2019):

I am not sure if its the same problem, but I got here trying to figure out similar issue.
What I found is that if you use a service inside doctrine eventSubscriber then the service will receive a broken EntityManager.

Here is some code:

class DoctrineSubscriber implements EventSubscriber
{
    /** @var CategoryService */
    protected $categoryService;

    /** @required */
    public function setCategoryService(CategoryService $categoryService)
    {
        $this->categoryService = $categoryService;
    }

    public function getSubscribedEvents()
    {
        return [
            // Irrelevant
        ];
    }
}

class CategoryService
{
    /** @var EntityManagerInterface */
    protected $doctrine;

    /** @required */
    public function setDoctrineService(EntityManagerInterface $doctrine)
    {
        $this->doctrine = $doctrine;
    }

    public function foo()
    {
        $categories = $this->doctrine->getRepository(Category::class)->findAll();
        foreach ($categories as $category) {
            dump($this->doctrine->contains($category));
        }
    }
}

Calling $categoryService->foo() will dump false in this case, but if I remove the EventSubscriber (or even remove the dependency on the service) it will show true instead.

@hubertnnn commented on GitHub (Nov 13, 2019): I am not sure if its the same problem, but I got here trying to figure out similar issue. What I found is that if you use a service inside doctrine eventSubscriber then the service will receive a broken EntityManager. Here is some code: ```PHP class DoctrineSubscriber implements EventSubscriber { /** @var CategoryService */ protected $categoryService; /** @required */ public function setCategoryService(CategoryService $categoryService) { $this->categoryService = $categoryService; } public function getSubscribedEvents() { return [ // Irrelevant ]; } } class CategoryService { /** @var EntityManagerInterface */ protected $doctrine; /** @required */ public function setDoctrineService(EntityManagerInterface $doctrine) { $this->doctrine = $doctrine; } public function foo() { $categories = $this->doctrine->getRepository(Category::class)->findAll(); foreach ($categories as $category) { dump($this->doctrine->contains($category)); } } } ``` Calling `$categoryService->foo()` will dump `false` in this case, but if I remove the EventSubscriber (or even remove the dependency on the service) it will show `true` instead.
Author
Owner

@SenseException commented on GitHub (Nov 17, 2019):

Please try to recreate this behaviour on Doctrine ORM only without Symfony in a test.

@SenseException commented on GitHub (Nov 17, 2019): Please try to recreate this behaviour on Doctrine ORM only without Symfony in a test.
Author
Owner

@RafaelKr commented on GitHub (Jul 5, 2024):

I had a similar problem and want to leave this here just in case someone stumbles upon this.

In my Symfony project I manually created a Proxy Object by using $this->entityManager->getProxyFactory()->getProxy($entityClass, $id).
But this doesn't attach the object to the EntityManager. After some debugging I found out I need to use $this->entityManager->getReference($entityClass, $id) instead.

@RafaelKr commented on GitHub (Jul 5, 2024): I had a similar problem and want to leave this here just in case someone stumbles upon this. In my Symfony project I manually created a Proxy Object by using `$this->entityManager->getProxyFactory()->getProxy($entityClass, $id)`. But this doesn't attach the object to the EntityManager. After some debugging I found out I need to use `$this->entityManager->getReference($entityClass, $id)` instead.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#5322