Symfony2:如何从存储库访问服务

时间:2012-10-19 09:44:30

标签: php symfony

我有类ModelsRepository:

class ModelsRepository extends EntityRepository
{}

服务

container_data:
 class:        ProjectName\MyBundle\Common\Container
 arguments:    [@service_container]

我希望从ModelsRepository访问service_data。我无法从控制器使用的构造函数传输服务。

你知道怎么做吗?

8 个答案:

答案 0 :(得分:12)

恕我直言,不应该这样做,因为你可能很容易违反SRPLaw of Demeter等规则

但如果你真的需要它,这是一种方法:

首先,我们定义一个基础“ContainerAwareRepository”类,它有一个调用“setContainer”

services.yml

services:
    # This is the base class for any repository which need to access container
    acme_bundle.repository.container_aware:
        class: AcmeBundle\Repository\ContainerAwareRepository
        abstract: true
        calls:
            - [ setContainer, [ @service_container ] ]

ContainerAwareRepository可能看起来像这样

AcmeBundle \库\ ContainerAwareRepository.php

abstract class ContainerAwareRepository extends EntityRepository
{
    protected $container;

    public function setContainer(ContainerInterface $container)
    {
        $this->container = $container;
    }
}

然后,我们可以定义我们的模型库 我们在这里使用了学说的getRepository方法来构建我们的存储库

services.yml

services:
    acme_bundle.models.repository:
        class: AcmeBundle\Repository\ModelsRepository
        factory_service: doctrine.orm.entity_manager
        factory_method:  getRepository
        arguments:
            - "AcmeBundle:Models"
        parent:
            acme_bundle.repository.container_aware

然后,只需定义类

AcmeBundle \库\ ModelsRepository.php

class ModelsRepository extends ContainerAwareRepository
{
    public function findFoo()
    {
        $this->container->get('fooservice');
    }
}

为了使用存储库,您绝对需要首先从服务中调用它。

$container->get('acme_bundle.models.repository')->findFoo(); // No errors
$em->getRepository('AcmeBundle:Models')->findFoo(); // No errors

但如果你直接做

$em->getRepository('AcmeBundle:Models')->findFoo(); // Fatal error, container is undefined

答案 1 :(得分:8)

你应该从不将容器传递给存储库,就像你永远不应该让实体处理繁重的逻辑一样。存储库只有一个目的 - 从数据库中检索数据。没有更多(阅读:http://docs.doctrine-project.org/en/2.0.x/reference/working-with-objects.html)。

如果你需要比这更复杂的东西,你应该为它创建一个单独的(容器意识到你想要的)服务。

答案 2 :(得分:6)

我尝试了一些版本。问题解决了

ModelRepository:

class ModelRepository extends EntityRepository
{
    private $container;

    function __construct($container, $em) {
        $class = new ClassMetadata('ProjectName\MyBundle\Entity\ModelEntity');
        $this->container = $container;

        parent::__construct($em, $class);
    }
}

security.yml:

providers:
    default:
        id: model_auth

services.yml

model_auth:
    class: ProjectName\MyBundle\Repository\ModelRepository
    argument

结果我得到了能力使用容器的存储库 - 根据需要。 但是这种实现只能在关键情况下使用,因为她对Repository有限制。 Thx 4all。

答案 3 :(得分:4)

您确定从repo访问服务是个好主意吗?

存储库是为自定义SQL而设计的,在学说的情况下,学说可以帮助您使用find()findOne()findBy(),“魔术”方法。

考虑在您使用回购的地方注入您的服务,如果您需要一些参数,请将其直接传递给repo的方法。

答案 4 :(得分:4)

我建议使用工厂服务:

http://symfony.com/doc/current/components/dependency_injection/factories.html

//Repository
class ModelsRepositoryFactory
{
    public static function getRepository($entityManager,$entityName,$fooservice)
    {
        $em     = $entityManager;
        $meta   = $em->getClassMetadata($entityName);

        $repository = new ModelsRepository($em, $meta, $fooservice);
        return $repository;
    }
}

//service
AcmeBundle.ModelsRepository:
        class: Doctrine\ORM\EntityRepository
        factory: [AcmeBundle\Repositories\ModelsRepositoryFactory,getRepository]
        arguments:
            - @doctrine.orm.entity_manager
            - AcmeBundle\Entity\Models
            - @fooservice  

答案 5 :(得分:3)

我非常同意只有在绝对必要时才能这样做。虽然现在有一种非常简单的方法(用Symfony 2.8测试)。

  1. 在您的存储库中实现“ContainerAwareInterface”
  2. 使用“ContainerAwareTrait”
  3. 调整services.yml
  4. RepositoryClass:

    namespace AcmeBundle\Repository;
    
    use Doctrine\ORM\EntityRepository;
    use Symfony\Component\DependencyInjection\ContainerAwareInterface;
    use Symfony\Component\DependencyInjection\ContainerAwareTrait;
    use AcmeBundle\Entity\User;
    
    class UserRepository extends EntityRepository implements ContainerAwareInterface
    {
    
        use ContainerAwareTrait;
    
        public function findUserBySomething($param)
        {
            $service = $this->container->get('my.other.service');
        }
    
    }
    

    services.yml:

    acme_bundle.repository.user:
        lazy: true
        class: AcmeBundle\Repository\UserRepository
        factory: ['@doctrine.orm.entity_manager', getRepository]
        arguments:
            - "AcmeBundle:Entity/User"
        calls:
            - method: setContainer
              arguments:
                - '@service_container'
    

答案 6 :(得分:1)

扩展LaurynasMališauskas的答案,将服务传递给构造函数,使您的存储库也成为服务并使用参数传递它:

models.repository:
      class: ModelsRepository
      arguments: ['@service_you_want_to_pass']

答案 7 :(得分:0)

最简单的方法是将服务注入存储库构造函数。

class ModelsRepository extends EntityRepository
{
  private $your_service;

  public function __construct(ProjectName\MyBundle\Common\Container $service) {
    $this->your_service = $service;
  } 
}