Имеете собственный репозиторий, не связанный с сущностью в Symfony 2 / Doctrine 2?
Возможно ли иметь собственный репозиторий, не связанный с сущностью в Symfony 2 и Doctrine 2? Я хотел бы вставить в него некоторый нативный SQL, который не очень хорошо вписывается в другие репозитории (это может относиться к абстрактной или иерархии сущностей).
Как код контроллера $this->getDoctrine()->getRepositoty(/* ??? */)
следует заменить?
3 ответа
Можно иметь столько хранилищ, сколько пожелаете. Однако только один репозиторий может быть связан с менеджером сущностей.
Вам нужно определить несколько сервисов для добавления собственного репозитория.
<!-- 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>
Поскольку вы не используете какие-либо функции Doctrine ORM в настраиваемом хранилище, расширять их не нужно EntityManager
,
namespace Acme\FQCN;
use \Doctrine\DBAL\Connection;
class MiscRepository
{
protected $conn;
public function __construct(Connection $conn)
{
$this->conn = $conn;
}
}
Я принял немного другое решение, используя родительские сервисы 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
Мое предложение состоит в том, чтобы создать простой класс PHP с необходимыми зависимостями в конструкторе и получить его через служебный контейнер.