Подтвердить что ты не робот

Наличие пользовательского хранилища, не связанного с объектом в Symfony 2/Doctrine 2?

Возможно ли иметь пользовательский репозиторий, не связанный с объектом в Symfony 2 и Doctrine 2? Я хотел бы добавить в него некоторый собственный SQL-код, который не подходит для других репозиториев (это может относиться к абстрактной или иерархии сущностей).

Как заменить код контроллера $this->getDoctrine()->getRepositoty(/* ??? */)?

4b9b3361

Ответ 1

Возможно иметь столько репозиториев, сколько пожелаете. Однако только один репозиторий может быть связан с менеджером сущностей.

Вам нужно определить несколько служб для добавления настраиваемого репозитория.

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

К сожалению, вы не сможете получить его через службу доктрины. Вместо этого извлеките его прямо из контейнера:

$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>

Поскольку вы не используете какие-либо функции ORM Doctrine в пользовательском репозитории, нет необходимости расширять EntityManager.

namespace Acme\FQCN;

use \Doctrine\DBAL\Connection;

class MiscRepository
{
    protected $conn;

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

Ответ 2

Я принял немного другое решение, используя родительские службы 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

<?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();
}

Теперь мы хотим определить новый репозиторий:

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

Ответ 3

Мое предложение состоит в том, чтобы создать простой PHP-класс с необходимыми зависимостями в конструкторе и получить его через контейнер службы.