【问题标题】:Is this a good way to do dependency injection in Symfony2?这是在 Symfony2 中进行依赖注入的好方法吗?
【发布时间】:2015-03-23 14:26:59
【问题描述】:

我像这样注册了我的 services.yml 文件:

services:
    bb_shop.product_repository:
        class: BB\ShopBundle\Entity\ProductRepository
        factory_service: doctrine.orm.default_entity_manager
        factory_method: getRepository
        arguments: ['BBShopBundle:Product']
    bb_shop.product_service:
        class: BB\ShopBundle\Service\ProductService
        arguments: [@bb_shop.product_repository]

这是我的存储库类:

class ProductRepository extends EntityRepository
{
    public function saveProduct( $p)
    {
        $this->_em->persist($p);
        $this->_em->flush();
    }
}

这是我的服务类:

class ProductService {

    protected   $productRepository;
    public  function __construct(ProductRepository $R)
    {
        $this->productRepository =$R;
    }
    public function saveProduct( $p)
    {
        $this->productRepository->saveProduct($p);
    }
} 

这就是我在控制器中调用我的服务的方式:

 $this->get('bb_shop.product_service')->saveProduct($product);

一切正常。 我的问题是: 1- 你能向我解释为什么我需要这 2 行,即使我在 EntityRepository 中有 EntityManager(由 $this->_em 使用)???

factory_service: doctrine.orm.default_entity_manager
factory_method: getRepository

2 - 这是进行依赖注入的好方法吗???

【问题讨论】:

  • 既然可以在与实体相关的顶部注解中声明* @ORM\Entity(repositoryClass="My\ProjectBundle\Entity\MyRepository"),为什么还要将Repositories注册为Services
  • 我这样做是为了在服务类中注入存储库。我在实体类中声明了注释。
  • 我是 SF2 的新手,所以请原谅这个问题,但是将您的存储库注册为服务有什么意义?
  • 我对 SF2 也很陌生,但我认为关键是您可以通过将存储库声明为成员变量并在构造函数中对其进行初始化来使用服务类中的存储库。
  • 但是当您可以在 RepositoryClass 中完成所有工作(获取数据)时,拥有一个服务类有什么意义呢?在您的代码中,ProductService->saveProductProductRepository->saveProduct 之间没有太大区别。

标签: php symfony dependency-injection repository-pattern


【解决方案1】:
  1. 您需要这两行,因为存储库不扩展实体管理器。所以基本上你正在将持久/刷新传递给实体管理器。这避免了将实体管理器暴露给您的服务的需要。您可以注入管理器并直接调用persist/flush,但真的为什么要麻烦。

  2. 我一直使用您的方法。所以它一定很棒。到目前为止,我还没有遇到任何严重的问题。

您应该知道调用 saveProduct 的副作用。就目前而言,您的保存产品会刷新实体管理器,因此您最终会保存/更新任何可能已更改的实体(不仅仅是特定产品),因为所有存储库都共享同一个管理器。

这对我来说不是问题。只是需要注意的事情。如果您在一个请求中修改多个产品,那么您可能需要拆分您的持久化和刷新。一次性将所有更改添加到数据库的方式。

class ProductRepository
{
    public function persist($product) { return $this->_em->persist($product); }
    public function flush($product) { return $this->_em->flush(); }

这种方法的另一个原因是它允许您换出存储库进行测试。我有基于 yaml 的存储库,它们从 yaml 文件加载一些实体。存储库公开了简单的 find/findAll 方法,使编写测试函数变得容易。谁知道呢,总有一天你可能会决定改用 Doctrine 2 以外的东西。

我使用基础存储库类:

use Doctrine\ORM\EntityRepository as BaseRepository;

class EntityRepository extends BaseRepository
{
    // Create main entity
    public function createEntity($params = array())
    {
        $entityName = $this->getEntityName();
        return new $entityName($params);
    }
    // Allow null for id
    public function find($id)
    {
        return $id ? parent::find($id) : null;
    }
    /* ==========================================================
     * Persistence
     */
    public function persist($entity) { return $this->getEntityManager()->persist($entity); }
    public function refresh($entity) { return $this->getEntityManager()->refresh($entity); }
    public function detach ($entity) { return $this->getEntityManager()->detach ($entity); }
    public function remove ($entity) { return $this->getEntityManager()->remove ($entity); }
    public function flush()          { return $this->getEntityManager()->flush();          }
    public function clear()          { return $this->getEntityManager()->clear();          

    public function getReference($id) { return $this->getEntityManager()->getReference($this->getEntityName(),$id); }

【讨论】:

  • 可以使用通用存储库和通用服务类和接口。并从他们那里继承每个实体的存储库和服务类和接口??? @Cerad
  • 是的,您可以使用从 DoctrineRepository 扩展的通用存储库,并将您的持久/刷新等方法添加到其中。拥有通用服务类没有多大意义。每个服务类别都是独一无二的。
猜你喜欢
  • 2012-02-23
  • 1970-01-01
  • 1970-01-01
  • 2021-01-25
  • 1970-01-01
  • 2019-02-25
  • 1970-01-01
  • 1970-01-01
  • 2018-02-18
相关资源
最近更新 更多