Reputation: 37
For simplicity, I have a service 'TenantContext', that retrieves the current tenant from the database on each request and therefore requires the EntityManager.
Furthermore I want to associate all Entities that have a ManyToOne relationship with Tenant automatically just before a flush happens, so I implemented a TenantListener that will detect those entities and do the association (setTenant()). To do that, the TenantListener requires the TenantContext.
Here is my services.yml
services:
tenant.service.tenant_context:
class: TenantBundle\Context\TenantContext
arguments: [ "@doctrine.orm.entity_manager" ]
tenant.event_listener.tenant_listener:
class: TenantBundle\EventListener\TenantListener
arguments: [ "@tenant.service.tenant_context" ]
tags:
- { name: doctrine.event_listener, event: preFlush }
This configuration gives me a circular reference error:
[Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException]
Circular reference detected for service "doctrine.dbal.default_connection", path: "doctrine.dbal.default_connection".
If I understand correctly, by tagging the EntityListener as a 'doctrine.event_listener' I am making the Doctrine EntityManager dependent on the TenantListener which depends on the TenantContext which again depends on the Doctrine EntityManager, etc.
I have looked into a similar post Symfony Circular Reference Exception for Doctrine onFlush Event Listener Service but my situation is somehow different. The TenantContext is used in many different ways besides from the TenantListener and I can't always pass the Doctrine EntityManager to get the current tenant.
I can't see a solution to break this circle. How can I resolve this?
Upvotes: 1
Views: 1098
Reputation: 309
You may do not want to inject the EntityManager
but the Doctrine Registry to your tenant.service.tenant_context
service:
services:
tenant.service.tenant_context:
class: TenantBundle\Context\TenantContext
arguments: [ "@doctrine" ]
Example on how to access the EntityManager
instance in your TenantBundle\Context\TenantContext
class:
namespace TenantBundle\Context
use Symfony\Bridge\Doctrine\RegistryInterface;
class TenantContext
{
protected $doctrine;
public function __construct(RegistryInterface $doctrine)
{
$this->doctrine = $doctrine;
}
public function getEntityManager()
{
return $this->doctrine->getEntityManager();
}
}
Upvotes: 4