spackmat
spackmat

Reputation: 1005

Why does my Doctrine custom repositoty think, my entity is detached?

I have a weird problem with my custom Doctrine2 repository.

I have a DELETE-controller, which looks basically like this:

public function deleteAction(MyEntity $myEntity, MyEntityRepository $myEntityRepository)
{
    $myEntityRepository->remove($myEntity);
    $myEntityRepository->flushEntityManager();

    return new JsonResponse(['message' => 'Bye bye!']);
}

And the Repository's remove method looks like this:

public function remove(MyEntity $entity): MyEntityRepository
{
    $this->getEntityManager()->remove($entity);
    return $this;
}

This has worked before, but now, I get an Exception:

Detached entity AppBundle\Entity\MyEntity@000000003b458c32000000007fd2994a cannot be removed

I really don't know, why the EntityManager inside the Repository thinks, the Entity is detached. When I inject the EntityManager directly to my controller, everything is okay:

public function deleteAction(MyEntity $myEntity, EntityManagerInterface $em)
{
    $em->remove($myEntity);
    $em->flush();

    return new JsonResponse(['message' => 'Bye bye!']);
}

Any ideas on this? Why is the EntityManager I get from Doctrine\ORM\EntityRepository->getEntityManager() different from the one that is injected into my controller?

P.S. My other DELETE-actions don't have this problem and they all use their identical custom repositorys. This drives me crazy.

Edit: dumping $this->getEntityManager() within the repository comes up with:

EntityManager {#627 ▼
-config: Configuration {#461 ▶}
-conn: Connection {#471 ▶}
-metadataFactory: ClassMetadataFactory {#618 ▶}
-unitOfWork: UnitOfWork {#493 ▶}
-eventManager: ContainerAwareEventManager {#511 ▶}
-proxyFactory: ProxyFactory {#588 ▶}
-repositoryFactory: DefaultRepositoryFactory {#619 ▶}
-expressionBuilder: null
-closed: false
-filterCollection: FilterCollection {#598 ▶}
-cache: null
}

while dumping $em within the controller comes up with

DoctrineORMEntityManager_00000000644c03b80000000000dac8cc6811571fd60520ff7ea135d840b51abe {#410 ▼
-valueHolder59cfe1676bb7b138763071: EntityManager {#664 …11}
-initializer59cfe1676bb84613288121: null
}

Upvotes: 2

Views: 664

Answers (1)

spackmat
spackmat

Reputation: 1005

I created a new empty Symfony project to reproduce the problem step by step. I got to the same error, when I implemented my entity listener, which has a helper class as a dependency, which itself has the MyEntityRepository as a dependency. Removing this dependency removed the problem with the detached Entity.

Some further investigation later, I realized, that EntityManager instances that are injected are sometimes new instances. To get the main instance injected (and to remove circular reference errors by the way), you can tag the entity listener service to be lazy:

AppBundle\EventListener\MyEntityListener:
    autowire: true
    autoconfigure: true
    # the service must be public, when it's tagged lazy
    public: true
    tags:
        - { name: doctrine.orm.entity_listener, lazy: true }

This lazy stuff solves my problem!

But I still do not understand, why I get another instance of EntityManager injected to my repository, when another service gets this repository injected.

For the record, MyEntityRepository configuration:

AppBundle\Entity\Repository\MyEntityRepository:
    autowire: false
    autoconfigure: true
    public: false
    factory: ['@doctrine.orm.default_entity_manager', getRepository]
    arguments:
        - AppBundle\Entity\MyEntity

The listerner service:

class MyEntityListener
{
    /** @var MyEntityHelper */
    protected $myEntityHelper;

    public function __construct(MyEntityHelper $myEntityHelper)
    {
        $this->myEntityHelper = $myEntityHelper;
    }
    // ...
}

and the helper service:

class MyEntityHelper
{
    /** @var MyEntityRepository */
    protected $myEntityRepository;

    // this injection of MyEntityRepository creates the problem
    // with the two instances of the EntityManager
    // unless the MyEntityListener is tagged as lazy
    public function __construct(MyEntityRepository $myEntityRepository)
    {
        $this->myEntityRepository = $myEntityRepository;
    }
    // ...
}

Upvotes: 2

Related Questions