10

我有类 ModelsRepository:

class ModelsRepository extends EntityRepository
{}

和服务

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

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

你知道怎么做吗?

4

8 回答 8

13

恕我直言,这不应该是必需的,因为您可能很容易违反SRP德米特法则等规则

但是如果你真的需要它,这里有一种方法可以做到这一点:

首先,我们定义一个基类“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\Repository\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\Repository\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
于 2013-07-02T16:56:20.733 回答
7

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

模型库:

class ModelRepository extends EntityRepository
{
    private $container;

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

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

安全性.yml:

providers:
    default:
        id: model_auth

服务.yml

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

结果,我根据需要获得了具有使用容器能力的存储库。但是这种实现只能在危急情况下使用,因为她对 Repository 有限制。谢谢4所有。

于 2012-10-19T12:11:12.620 回答
7

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

如果您需要比这更复杂的东西,您可能应该为此创建一个单独的(如果您愿意,可以感知容器)服务。

于 2013-07-02T16:30:26.413 回答
4

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

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

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

于 2012-10-19T10:27:56.617 回答
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  
于 2016-05-27T03:52:24.233 回答
4

我强烈同意只有在绝对必要时才应该这样做。虽然现在有一个相当简单的方法(用 Symfony 2.8 测试过)。

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

存储库类:

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');
    }

}

服务.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'
于 2017-12-08T10:28:43.087 回答
0

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

class ModelsRepository extends EntityRepository
{
  private $your_service;

  public function __construct(ProjectName\MyBundle\Common\Container $service) {
    $this->your_service = $service;
  } 
}
于 2012-10-19T10:05:29.920 回答
0

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

models.repository:
      class: ModelsRepository
      arguments: ['@service_you_want_to_pass']
于 2012-10-19T10:08:15.483 回答