There are several ways that we can access the entity's repository in Symfony2 controllers or services which each has its advantage and disadvantage. First I list them here and then asking if there is any better solution or these are the only options that we have and we should choose one or some based on our preferences. I also want to know if method 5 (which I've started to use it recently) can be good and doesn't break any rule or having any side effects.
Basic Method: Use entity manager in the controller or Inject it to a service and then accessing any repository that I want. This is the basic way of accessing a Repository in controller or service.
class DummyController
{
public function dummyAction($id)
{
$em = $this->getDoctrine()->getManager();
$em->getRepository('ProductBundle:Product')->loadProduct($id);
}
}
But there are some problems related to this method. The first problem is that I cannot do Ctrl + click on for example loadProduct function and go directly to its implementation (Unless there is a way that I don't know). The other problem is that I will end up repeating this part of code over and over.
Method 2: The other method is just to define a getter in my service or controller to access my repository.
class DummyService
{
protected $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function dummyFunction($id)
{
$this->getProductRepository()->loadProduct($id);
}
/**
* @return \ProductBundle\Entity\Repository\ProductRepository
*/
public function getProductRepository()
{
return $this->em->getRepository('ProductBundle:Product');
}
}
This method solves the first problem and somehow the second but still, I have to repeat all getters that I need in my service or controller, also I will have several getters in my services and controllers just for accessing to repositories
Method 3: Another way is to inject a repository to my service, it is nice especially if we have a good control on our code and we are not involved with other developers who inject the entire Container into your service.
class DummyService
{
protected $productRepository;
public function __construct(ProductRepository $productRepository)
{
$this->productRepository = $productRepository;
}
public function dummyFunction($id)
{
$this->productRepository->loadProduct($id);
}
}
This method solves the first and second problem, but if my service is big and it needs to deal with a lot of repositories then it is not a nice idea to inject for example 10 repository to my service.
Method 4: Another way is to have a service to wrap all of my repositories and inject this service to other services.
class DummyService
{
protected $repositoryService;
public function __construct(RepositoryService $repositoryService)
{
$this->repositoryService = $repositoryService;
}
public function dummyFunction($id)
{
$this->repositoryService->getProductRepository()->loadProduct($id);
}
}
RepositoryService:
class RepositoryService
{
protected $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
/**
* @return \ProductBundle\Entity\Repository\ProductRepository
*/
public function getProductRepository()
{
return $this->em->getRepository('ProductBundle:Product');
}
/**
* @return \CmsBundle\Entity\Repository\PageRepository
*/
public function getPageRepository()
{
return $this->em->getRepository('CmsBundle:Page');
}
}
This method also solves the first and second problem. But RepositoryService can become so big when we have for example 200 entities.
Method 5: Finally I can define a static method in each entity which returns its repository.
class DummyService
{
protected $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function dummyFunction($id)
{
Product::getRepository($this->em)->loadProduct($id);
}
}
My Entity:
/**
* Product
*
* @ORM\Table(name="saman_product")
* @ORM\Entity(repositoryClass="ProductBundle\Entity\ProductRepository")
*/
class Product
{
/**
*
* @param \Doctrine\ORM\EntityManagerInterface $em
* @return \ProductBundle\Entity\ProductRepository
*/
public static function getRepository(EntityManagerInterface $em)
{
return $em->getRepository(__CLASS__);
}
}
This method solves the first and second problem also I do not need to define a service to access repositories. I've used it recently and so far its the best method for me. I don’t think this method will break the rule of entities since it's defined in the class scope and also is so thine. But still I am not sure about it and whether or not it has any side effects.