LoginSignup
20
21

More than 5 years have passed since last update.

Symfony2でEntityRepositoryからContainerを参照できるようにする

Last updated at Posted at 2014-07-12

EntityRepositoryからContainerを参照したかったので作ってみました。
標準ではEntityRepository内からContainerを参照したい場合

global $kernel;
if ($kernel instanceOf \AppCache) {
    $kernel = $kernel->getKernel();
}
$container = $kernel->getContainer();

と記述する必要がありますが、

$container = $this->getContainer();

と記述するだけでContainerを参照できるようになります。

環境

  • Symfony 2.3.17
  • Doctrine 2.4.4
  • DoctrineBundle 1.2.0

実装する

実装手順は下記の通りです。

1. Containerを参照可能なEntityRepositoryクラス(ContainerAwareEntityRepository)を作成

ContainerAwareEntityRepository.php
<?php

namespace Some\MyBundle\Doctrine\ORM;

use Doctrine\ORM\EntityRepository;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

class ContainerAwareEntityRepository extends EntityRepository implements ContainerAwareInterface
{
    /**
     * Container
     * @var ContainerInterface
     */
    private $container;

    /**
     * {@inheritdoc}
     */
    public function setContainer(ContainerInterface $container = null)
    {
        $this->container = $container;
    }

    /**
     * Get Container
     * @return ContainerInterface
     */
    public function getContainer()
    {
        return $this->container;
    }
}

2. ContainerAwareEntityRepositoryにContainerを設定するRepositoryFactoryクラス(MyRepositoryFactory)を作成

MyRepositoryFactory.php
<?php

namespace Some\MyBundle\Doctrine\ORM\Repository;

use Some\MyBundle\Doctrine\ORM\ContainerAwareEntityRepository;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Repository\DefaultRepositoryFactory;
use Symfony\Component\DependencyInjection\ContainerInterface;

class MyRepositoryFactory extends DefaultRepositoryFactory
{
    /**
     * Container
     * @var ContainerInterface
     */
    private $container;

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

    /**
     * {@inheritdoc}
     */
    public function getRepository(EntityManagerInterface $entityManager, $entityName)
    {
        $repository = parent::getRepository($entityManager, $entityName);

        if ($repository instanceof ContainerAwareEntityRepository) {
            $repository->setContainer($this->container);
        }

        return $repository;
    }
}

サービスへの登録も忘れずに行います。

services.yml
services:
    my.doctrine.orm.repository_factory:
        class: Some\MyBundle\Doctrine\ORM\Repository\MyRepositoryFactory
        arguments: [ @service_container ]

3. MyRepositoryFactoryをEntityManagerに登録するCompilerPassクラス(MyCompilerPass)を作成

CompilerPassは他のBundleで定義されたサービスを操作する場合に利用します。
今回はDoctrineBundleで定義されたサービスに対して操作を行う必要があるので作成します。

MyCompilerPass.php
<?php

namespace Some\MyBundle\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

class MyCompilerPass implements CompilerPassInterface
{
    /**
     * {@inheritdoc}
     */
    public function process(ContainerBuilder $container)
    {
        $repositoryFactory = $container->getDefinition('my.doctrine.orm.repository_factory');
        $container->findDefinition('doctrine.orm.configuration')->addMethodCall('setRepositoryFactory', [$repositoryFactory]);
    }
}

4. MyCompilerPassをContainerBuilderに登録する

SomeMyBundle.php
<?php

namespace Some\MyBundle;

use Some\MyBundle\DependencyInjection\Compiler\MyCompilerPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;

class SomeMyBundle extends Bundle
{
    /**
     * {@inheritdoc}
     */
    public function build(ContainerBuilder $container)
    {
        parent::build($container);
        $container->addCompilerPass(new MyCompilerPass());
    }
}

使用する

ContainerAwareEntityRepositoryを継承したクラス内で$this->getContainer()するとContainerを参照できます。

SomeTableRepository.php
<?php

namespace Some\MyBundle\Entity\SomeTableRepository;

use Some\MyBundle\Doctrine\ORM\ContainerAwareEntityRepository;

/**
 * SomeTableRepository
 *
 * This class was generated by the Doctrine ORM. Add your own custom
 * repository methods below.
 */
class SomeTableRepository extends ContainerAwareEntityRepository
{
    /**
     * Get Some Data
     * @param int $id
     * @return SomeTable
     */
    public function get($id)
    {
        $container = $this->getContainer();
        $someParam = $container->getParameter('some.parameter');

        $qb = $this
            ->createQueryBuilder('some')
            ->where('some.id = :id')
            ->andWhere('some.someColumn = :someParam')
            ->setParameters([
                'id' => $id,
                'someParam' => $someParam,
            ])
        ;

        $logger = $container->get('logger');
        $logger->debug("Repositoryからログ出力!");

        return $qb->getQuery()->getSingleResult();
    }
}
20
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
21