symfony design-patterns doctrine2 doctrine symfony-2.3

Symfony-Cómo acceder al repositorio de la entidad



design-patterns doctrine2 (3)

Le sugiero que use el método 4, su servicio seguirá al Principio de resposabilidad simple ya que solo hace una cosa: darle acceso a todos sus repositorios.

Este servicio será principalmente como una dependencia en otros servicios. Para los controladores, le sugiero que cree una clase base de controlador personalizado con las mismas funciones auxiliares.

Acerca de las duplicaciones de código, los rasgos pueden ser la solución. Incluso con la cantidad de métodos si usa un rasgo por "categoría"

Existen varias maneras de acceder al repositorio de la entidad en los controladores o servicios Symfony2, cada uno de los cuales tiene su ventaja y desventaja. Primero los enumero aquí, y luego pregunto si hay alguna solución mejor o estas son las únicas opciones que tenemos y debemos elegir una o algunas basadas en nuestras preferencias. También quiero saber si el método 5 (que comencé a usarlo recientemente) puede ser bueno y no infringe ninguna regla ni tiene ningún efecto secundario.

Método básico: Usar el administrador de entidades en el controlador o Inyectarlo en un servicio y luego acceder a cualquier repositorio que desee. Esta es la forma básica de acceder a un repositorio en el controlador o servicio.

class DummyController { public function dummyAction($id) { $em = $this->getDoctrine()->getManager(); $em->getRepository(''ProductBundle:Product'')->loadProduct($id); } }

Pero hay algunos problemas relacionados con este Methos. El primer problema es que no puedo hacer Ctrl + clic en, por ejemplo, la función loadProduct e ir directamente a su implementación (a menos que haya una manera que no sé). El otro problema es que terminaré repitiendo esta parte del código una y otra vez.

Método 2: El otro método es simplemente definir un getter en mi servicio o controlador para acceder a mi repositorio.

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''); } }

Este método resuelve el primer problema y de alguna manera el segundo, pero aún tengo que repetir todos los getters que necesito en mi servicio o controlador, también tendré varios getters en mis servicios y controladores solo para acceder a los repositorios.

Método 3: Otra forma es inyectar un repositorio a mi servicio, es bueno especialmente si tenemos un buen control sobre nuestro código y no estamos involucrados con otros desarrolladores que inyecten todo el contenedor a su servicio.

class DummyService { protected $productRepository; public function __construct(ProductRepository $productRepository) { $this->productRepository = $productRepository; } public function dummyFunction($id) { $this->productRepository->loadProduct($id); } }

Este método resuelve el primero y el segundo problema, pero si mi servicio es grande y necesita tratar con muchos repositorios, no es una buena idea inyectar, por ejemplo, 10 repositorios a mi servicio.

Método 4: Otra forma es tener un servicio para envolver todos mis repositorios e inyectar este servicio a otros servicios.

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''); } }

Este método también resuelve el primer y el segundo problema. Pero RepositoryService puede llegar a ser tan grande cuando tenemos, por ejemplo, 200 entidades.

Método 5: Finalmente, puedo definir un método estático en cada entidad que devuelve su repositorio.

class DummyService { protected $em; public function __construct(EntityManager $em) { $this->em = $em; } public function dummyFunction($id) { Product::getRepository($this->em)->loadProduct($id); } }

Mi entidad:

/** * 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__); } }

Este método resuelve el primer y el segundo problema, además no necesito definir un servicio para acceder a los repositorios. Lo he usado recientemente y hasta ahora es el mejor método para mí. No creo que este método rompa la regla de las entidades, ya que está definido en el alcance de la clase y también lo es tuyo. Pero todavía no estoy seguro de eso y de si tiene o no algún efecto secundario.


Para mí, ninguna de tus sugerencias es correcta.
Porque no entiendo por qué necesita crear un servicio de su entidad.
Si necesita acceder a esta entidad, lo único que necesita es tener acceso a la doctrina.
Y la doctrina tiene un servicio (@doctrine).
Depende de usted prepararse en el constructo para tener acceso solo a esa entidad.

La estática es olvidada:

Y lo que envía en el método 5 no es correcto, su entidad de Producto ya tiene acceso a entityManager a través del ProductRepository con el método getEntityManager ().


En el mundo de Doctrine, se supone que la entidad es un modelo anémico de getters y setters (y agrega o elimina), por lo que inyectar el repositorio sería algo incorrecto.

Todo depende de qué tan acoplado quieras estar con Doctrine. Si está de acuerdo con pasar el servicio @doctrine , entonces podría usar algo como:

$this->repository = $doctrine->getRepository(''CmsBundle:Page'');

.. pero luego eso, como se mencionó, requeriría pasar el servicio @doctrine a cada objeto. Esto significaría que si alguna vez decidiera no usar Doctrine por alguna razón, necesitaría refactorizar todo su código para adaptarlo a su nueva metodología (cualquiera que sea), pero esto puede no ser un problema para usted. Además, el repositorio estaría insinuado por tipo, por lo que no hay garantía (más allá de verificar si es la clase correcta en el código) para garantizar que sea el servicio correcto.

En mi opinión, la forma más limpia de hacerlo es crear un servicio como:

XML

<service id="cms.page_repository" class="Acme/CmsBundle/Repository/PageRepository"> <factory service="doctrine" method="getRepository" /> <argument>AcmeDemoBundle:ExampleRepository</argument> </service>

YAML

cms.page_repository: class: Acme/CmsBundle/Repository/PageRepository factory: [ @doctrine, ''getRepository'' ]

.. y luego puede pasar su servicio de repositorio donde quiera sin la necesidad de utilizar el servicio de doctrina en su código actual. Con este enfoque, si alguna vez decides alejarte de Doctrine, solo necesitas cambiar las definiciones de servicio en lugar de tener que refactorizar todo. Además, debido a que está creando el servicio de su repositorio específico, puede usar la sugerencia de tipo en su __construct para garantizar que el servicio correcto se está inyectando como:

public function __construct(PageRepository $repository) { $this->repository = $repository; }