首页 > 解决方案 > 将 EntityManager 从另一个服务注入到一个服务中

问题描述

我正在将代码从 Controller 提取到 Symfony 3.4 App 中的一种 ApplicationService 中。

我有一个用于抓取数据的具体类和另一个用于更改一些数据的具体转换器。

src\App\Service 

class CompanyScraping implements ScrapingInterface
{
    private $crawler;

    public function __construct(CrawlerInterface $crawler)
    {
        $this->crawler = $crawler;

    }

    public function extract()
    {
        ...
    }

    public function transform()
    {
        $transformer = new concreteTransformer();

    }
}

class concreteTransformer
{
    private $em;

    public __construct(EntityManagerInterface $em)
    {
        $this->em = $em;
    }
}

如果在 CompanyScraping 类中未调用 EntityManager,我如何将 EntityManager 传递给具体的Transformer 类?我不能用新的实例化concreteTransformer。

我正在考虑这两个选项:

$crawler =  new CompanyScraping(new GoutteClient());
$rawData = $crawler->extract(...);
$data = new concreteTransformer($em, $rawData);

还有什么想法吗?

谢谢。

标签: phpsymfonyprivate

解决方案


我想到的第一个解决方案是将(不是 EM,而是)Transformer 注入到 Scraper 类中,如评论中所述。

然而,这样的解决方案并不能解决根本问题:Scraper 是在抓取、转换还是两者兼而有之?在后一种情况下,它不是坚持单一职责原则,因为它兼有抓取转换的责任。

一种可以非常有效地解决这个问题的设计模式是装饰器模式。在这种情况下,想法是通过转换来“装饰”抓取的结果。

结果看起来有点像这样:

class Transformer implements ScrapingInterface
{
    private $scraper;
    private $em;

    public __construct(ScrapingInterface $scraper, EntityManagerInterface $em)
    {
        $this->scraper = $scraper;
        $this->em = $em;
    }

    public function extract()
    {
        return $this->transform($this->scraper->extract());
    }

    private function transform() {...}
}

它可以构造为:

$crawler = new Transformer(new CompanyScraping(new GoutteClient()), $em);

如果您有多个转换器实现,您可以使装饰器更通用:

class TransformingScraper implements Scraper
{
    private $scraper;
    private $transformer;

    public __construct(Scraper $scraper, Transformer $transformer)
    {
        $this->scraper = $scraper;
        $this->transformer = $transformer;
    }

    public function extract()
    {
        return $this->transformer->transform($this->scraper->extract());
    }
}

$crawler = new TransformingScraper(
    new CompanyScraping(new GoutteClient()),
    new ConcreteTransformer($em)
);

推荐阅读