在Symfony 2 / Doctrine 2中拥有一个自定义存储库,但与实体无关?

12

在Symfony 2和Doctrine 2中是否可能拥有一个与实体无关的自定义存储库?我想在其中放一些不适合其他存储库的本机SQL(它可能涉及抽象或实体层次结构)。

如何替换控制器代码中的$this->getDoctrine()->getRepositoty(/* ??? */)

3个回答

16

您可以拥有任意数量的存储库。但是,只能将单个存储库与实体管理器链接。

您需要定义一些服务来添加自定义存储库。

<!-- My custom repository -->
<service id="acme.repository.my_entity" class="Acme\FQCN\MyEntityRepository" >
    <argument type="service" id="doctrine.orm.entity_manager" />
    <argument type="service" id="acme.metadata.my_entity" />
</service>

<!-- MyEntity metadata -->
<service id="acme.metadata.my_entity" class="Doctrine\ORM\Mapping\ClassMetaData">
    <argument>Acme\FQCN\MyEntity</argument>
</service>

仓库类必须继承自EntityRepository

namespace Acme\FQCN;

use Doctrine\ORM\EntityRepository;

class MyEntityRepository extends EntityRepository
{
    /** 
     * If you want to inject any custom dependencies, you'd have either have to
     * add them to the construct or create setters. I'd suggest using setters
     * in which case you wouldn't need to use the constructor in this class.
     *
     * public function __construct($em, Doctrine\ORM\Mapping\ClassMetadata $class, $custom_dependency)
     * {
     *     parent::__construct($em, $class);
     * }
     *
     */
}

很遗憾,您将无法通过Doctrine服务检索它。相反,直接从容器中检索它:

$this->get('acme.repository.my_entity');

编辑

如果你正在创建一个不应链接到任何实体的存储库,只需创建一个服务并注入必要的依赖项。

<!-- Repository for misc queries -->
<service id="acme.repository.misc" class="Acme\FQCN\MiscRepsitory">
    <argument type="service" id="database_connection" />
</service>

如果您在自定义存储库中没有使用Doctrine的ORM功能,则无需扩展 EntityManager

namespace Acme\FQCN;

use \Doctrine\DBAL\Connection;

class MiscRepository
{
    protected $conn;

    public function __construct(Connection $conn)
    {
        $this->conn = $conn;
    }
}

抱歉,我的意思是存储库不应与任何实体相关联。那么,元数据是为什么呢? - gremo
在这种情况下,创建一个额外的服务并注入数据库连接本身是有意义的。 - kgilden
注入数据库连接后,我只需要创建一个继承自EntityRepository的类,对吗? - gremo
@Gremo 不需要,因为你实际上没有使用任何ORM功能,所以存储库根本不必继承自“EntityRepository”。 - kgilden
1
好的,谢谢你的帮助,我将接受这个答案。自定义存储库(带有依赖项)唯一的不好之处是需要定义和传递元数据。为每个实体元数据创建一个服务可能会相当乏味。 - gremo
1
考虑一下,您不必定义元数据。而是在存储库的构造函数内创建“MedaData”对象。 @Gremo - kgilden

6

我采用了Symfony2父服务的略微不同的解决方案。

首先,我创建了一个父服务,即GenericRepository类,它公开了一些方法,并在以后我们想要重构代码时使生活更轻松。

services.yml

acme_core.generic_repository:
    abstract: true
    class: Acme\Bundle\CoreBundle\Repository\GenericRepository
    arguments: [@doctrine.orm.entity_manager]

Acme\Bundle\CoreBundle\Repository\GenericRepository

可以翻译为“Acme\Bundle\CoreBundle\Repository\通用仓库”。
<?php

namespace Acme\Bundle\CoreBundle\Repository;

use Doctrine\ORM\EntityManager;

/**
 * Class GenericRepository
 * @package Acme\Bundle\CoreBundle\Repository
 */
abstract class GenericRepository {
    /**
     * @var EntityManager
     */
    private $entityManager;

    /**
     * @param EntityManager $entityManager
     */
    public function __construct(EntityManager $entityManager) {
        $this->entityManager = $entityManager;
    }

    /**
     * @return EntityManager
     */
    public function getEntityManager() {
        return $this->entityManager;
    }

    /**
     * @return \Doctrine\DBAL\Connection
     */
    public function getConnection() {
        return $this->getEntityManager()->getConnection();
    }

    /**
     * @return string
     */
    abstract function getTable();
}

现在我们想要定义一个新的存储库: < p > < code > services.yml
# Repositories
acme_product.repository.product_batch:
    parent: acme_core.generic_repository
    class: Acme\Bundle\ProductBundle\Repository\ProductBatchRepository

Acme\Bundle\ProductBundle\Repository\ProductBatchRepository 是一个产品批量存储库。
<?php

namespace Acme\Bundle\ProductBundle\Repository;

use Acme\Bundle\CoreBundle\Repository\GenericRepository;

/**
 * Class ProductBatchRepository
 * @package Acme\Bundle\ProductBundle\Repository
 */
class ProductBatchRepository extends GenericRepository {
    /**
     * @param int $batchId
     * @return integer The number of affected rows.
     */
    public function deleteBatch($batchId) {
        $table = $this->getTable();

        return $this->getConnection()->delete($table, [
            'id' => $batchId
        ]);
    }

    /**
     * {@inheritdoc}
     */
    public function getTable() {
        return 'product_batch';
    }
}
deleteBatch()方法创建并执行以下查询语句:

DELETE FROM product_batch WHERE id = ?

最后在我们的控制器中:
public function deleteAction() {
    $batchId = $this->getRequest()->get('batchId');

    $affectedRows = $this->get('acme_product.repository.product_batch')->deleteBatch($batchId);

    return $this->render(/**/);
}

如需更多信息和 实体管理器 / 连接 的使用方法,请参考官方文档:http://doctrine-orm.readthedocs.org/en/latest/reference/native-sql.html


2
我的建议是创建一个简单的PHP类,将所需的依赖项放在构造函数中,并通过服务容器获取它。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接