2015-08-12 5 views
8

Существует несколько способов доступа к репозиторию объекта в контроллерах или службах Symfony2, каждый из которых имеет свои преимущества и недостатки. Сначала я перечисляю их здесь, а затем спрашиваю, есть ли лучшее решение или это единственные варианты, которые у нас есть, и мы должны выбрать один или несколько, основанный на наших предпочтениях. Я также хочу знать, может ли быть метод 5 (который я начал использовать недавно), и не нарушает никакого правила или каких-либо побочных эффектов.Symfony - Как получить доступ к репозиторию объекта

Основной метод: Использование диспетчера объектов в контроллере или его внедрение в службу, а затем доступ к любому репозиторию, который я хочу. Это основной способ доступа к репозиторию в контроллере или службе.

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

Но есть некоторые проблемы, связанные с этим методом. Первая проблема заключается в том, что я не могу сделать Ctrl + щелчок, например, функцию loadProduct и перейти непосредственно к ее реализации (если только не существует способа, который я не знаю). Другая проблема заключается в том, что я снова и снова повторяю эту часть кода.

Способ 2: Другой метод - это просто определить получателя в моем сервисе или контроллере для доступа к моему репозиторию.

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

Этот метод решает первую проблему и как-то второй, но все же у меня есть повторить все добытчик, что мне нужно в моей службе или контроллере, а также у меня будет несколько добытчиков в моих услугах и контролерах только для доступа к хранилища

Метод 3: Другой способ внедрить хранилище для моей службы, это хорошо, особенно если у нас есть хороший контроль над нашим кодом, и мы не связаны с другими разработчиками, которые инъекционные весь контейнер в свой оказание услуг.

class DummyService 
{ 
    protected $productRepository; 

    public function __construct(ProductRepository $productRepository) 
    { 
     $this->productRepository = $productRepository; 
    } 

    public function dummyFunction($id) 
    { 
     $this->productRepository->loadProduct($id); 
    } 
} 

Этот метод решает первую и вторую проблему, но если моя служба большая и он должен иметь дело с большим количеством хранилищ, то это не хорошая идея Inject например, 10 репозитарий моей службы ,

Способ 4: Другим способом является предоставление услуги для переноса всех моих репозиториев и перевода этой службы на другие службы.

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

Этот метод также решает первую и вторую проблему. Но RepositoryService может стать настолько большим, если у нас есть, например, 200 объектов.

Метод 5: Наконец, я могу определить статический метод в каждом объекте, который возвращает свой репозиторий.

class DummyService 
{ 
    protected $em; 

    public function __construct(EntityManager $em) 
    { 
     $this->em = $em; 
    } 

    public function dummyFunction($id) 
    { 
     Product::getRepository($this->em)->loadProduct($id); 
    } 
} 

Мои 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__); 
    } 
} 

Этот метод решает первую и вторую проблему также не нужно определить службу доступа к хранилищам. Я использовал его в последнее время, и пока это лучший метод для меня.Я не думаю, что этот метод нарушит правило сущностей, поскольку он определен в области видимости класса и также является вашим. Но все же я не уверен в этом и не имеет никаких побочных эффектов.

ответ

2

Для меня ни одно из ваших предложений не верны.
Потому что я не понимаю, почему вам нужно создать службу вашей сущности.
Если вам нужен доступ к этому сущности, единственное, что вам нужно, это доступ к доктрине.
И учение имеет службу (@doctrine).
Это зависит от вас, чтобы подготовить в конструкции доступ только к этому объекту.

Статика являются забыто:

А что вы отправляете в методе 5 не является правильным, ваша сущность продукта уже доступ к EntityManager через ProductRepository с getEntityManager ().

+2

Я использую услуги для своих репозиториев с интерфейсами. Это сокращает количество, которое мой код напрямую связан с Doctrine, когда это действительно не нужно. Все требования к сервису/объекту - это то, что он получает репозиторий, который подходит для интерфейса, а не для получения Doctrine, для получения репозитория (который также не проверяется типом, поэтому не может иметь никаких настраиваемых методов). – qooplmao

+1

Вы определенно НЕ нуждаетесь в доктрине. Это похоже на получение коровы, когда вам нужно только немного молока. – user2268997

+0

у вас есть право @ user2268997 – Roukmoute

7

В мире Доктрины сущность должна быть анемичной моделью геттеров и сеттеров (и добавлять или удалять), поэтому инъекция репозитория была бы неправильной.

Все зависит от того, насколько вы должны быть привязаны к Доктрине. Если вы хорошо с пропусканием @doctrine обслуживание вокруг, то вы могли бы просто использовать что-то вроде:

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

.. но потом, что, как уже упоминалось, может потребовать от вас пройти @doctrine службу в каждом объекте. Это означало бы, что если вы когда-либо решили не использовать Doctrine по какой-либо причине, вам нужно будет реорганизовать весь свой код, чтобы он соответствовал вашей новой методологии (что бы это ни было), но это может быть для вас проблемой. Кроме того, репозиторий был бы намечен на тип, поэтому нет гарантии (помимо проверки правильности кода в коде), чтобы гарантировать, что это правильный сервис.

На мой взгляд, самый чистый способ сделать это, чтобы создать услугу, как:

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' ] 

.. а затем вы можете передать службы репозитория, где бы вы ни захотели, без необходимости использования услуги doctrine в вашем фактическом коде. При таком подходе, если вы когда-либо решите отойти от Доктрины, вам нужно только изменить определения служб, а не реорганизовывать все. Также в связи с тем, что вы создаете службу вашего конкретного хранилища, вы можете использовать тип намекая в вашем __construct, чтобы гарантировать правильное обслуживание впрыскивается как:

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

Если ваш проект слишком запутан, чтобы иметь возможность создавать и вводить услугу, тогда у вас гораздо больше проблем, чем лучших практик. – qooplmao

+0

Я не хочу вводить репозиторий в свою сущность, функция в методе 5 является статической функцией, и она не относится к области объектов и сущностей. Я согласен с вами, лучший способ - определить службу репозитория, но если вы работаете в большом и грязном проекте, это сложно сделать, но определенно, если я хочу работать над новым, я буду следовать этому шаблону. –

+0

Например, одной из моих служб необходимо получить доступ к 5 репозиториям + еще 5 службам, после чего у меня есть 10 услуг в моей службе. Я не думаю, что это хорошая идея. –

1

Я предлагаю вам использовать метод 4, ваш сервис будет следовать за Single Resposability Principe, поскольку он делает только одно: дает вам доступ ко всем вашим репозиториям.

Эта услуга будет в основном зависеть от других услуг. Для контроллеров я предлагаю вам создать собственный базовый класс контроллера с теми же вспомогательными функциями.

О дублировании кода, чертах может быть решение. Даже с количеством методов, если вы используете признак по «категории»

+0

Спасибо Yassine, в моем контроллере я также могу использовать ту же услугу, и мне не нужно иметь базовый контроллер. –

+0

На всякий случай вы предпочитаете '$ this-> getMyRepository()' over' $ this-> get ('app.repositories') -> getMyRepository() ':) –

+0

class baseController {public function getRepositories() {return $ this -> Get ('app.repositories'); }} class myController extends baseController {public function dummyAction() {$ this-> getRepositories() -> getProductRepo() -> loadProduct()}} –