John Davidson

php - Symfony multiple entity managers with one repository

0 comments
Message:


I have a symfony/api-platform application which connects to 2 different databases configured in doctrine.yaml. I want to notice that both databases store the same entities (but with different actions on each), hence we duplicated all the entity classes and created a repository for each, in order for migrations and api-platform actions to work. Since those enities share a lot of common repository functionallity, what I have done so far to remove code
duplication is:


Create entity manager decorators


class AEntityManager extends EntityManagerDecorator{}
class BEntityManager extends EntityManagerDecorator{}

config/services.yaml


App\EntityManager\AEntityManager:
decorates: doctrine.orm.a_entity_manager
App\EntityManager\BEntityManager:
decorates: doctrine.orm.b_entity_manager
App\Repository\Main\AResourceRepository:
arguments:
- '@App\EntityManager\AEntityManager'
App\Repository\ProductPending\BResourceRepository:
arguments:
- '@App\EntityManager\BEntityManager'

Create a base class (for each entity) to share code between the 2 repositories


class RepositoryBase extends ServiceEntityRepository
{
public function __construct(EntityManagerInterface $em, string $class) {...}

// common methods
}

class ARepository extends RepositoryBase
{
public function __construct(EntityManagerInterface $em)
{
parent::__construct($em, A::class);
}
}

class BRepository extends RepositoryBase
{
public function __construct(EntityManagerInterface $em)
{
parent::__construct($em, B::class);
}
}

And entities


/**
@Orm\Entity(repositoryClass=ARepository::class)
*/
class A {
string $prop;
}

/**
@Orm\Entity(repositoryClass=BRepository::class)
*/
class B {
string $prop;
}

Note that all actions for the second database occur in endpoints prefixed with (let's say) /api/b/...


I would like to know if there is a way to eliminate the different repository classes and define the same repository across the 2 different entities. What I have in mind is to change the object which is used to inject the EntityManagerInterface constructor parameter based on the url of the request, but I haven't found something specific about it and I don't know if that's even possible.



My Answer:
One approach you could take is to create a single repository class that can handle both entities, and then determine which entity to work with based on the URL of the request. Here's an example of how you could achieve this:

php
class MultiEntityRepository extends ServiceEntityRepository
{
private $entityManager;
private $entityClass;

public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
$this->entityClass = $this->determineEntityClass();
parent::__construct($entityManager, $this->entityClass);
}

private function determineEntityClass()
{
// Determine the entity class based on the URL of the request
$request = Request::createFromGlobals();
$path = $request->getPathInfo();

if (strpos($path, '/api/b/') !== false) {
return B::class;
}

return A::class;
}

// Add common methods that can work with both entities
}

/**
* @ORM\Entity(repositoryClass=MultiEntityRepository::class)
*/
class A {
// Entity A properties
}

/**
* @ORM\Entity(repositoryClass=MultiEntityRepository::class)
*/
class B {
// Entity B properties
}


In this example, the `MultiEntityRepository` class determines which entity class to work with based on the URL of the request. You can then add common methods to this repository class that can work with both entities.

Keep in mind that this approach may not be suitable for all scenarios, as it can make the repository class more complex and harder to maintain. It's important to carefully consider the trade-offs and make sure this approach aligns with your project requirements.

Rate this post

4 of 5 based on 9469 votes

Comments




© 2024 Hayatsk.info - Personal Blogs Platform. All Rights Reserved.
Create blog  |  Privacy Policy  |  Terms & Conditions  |  Contact Us