【问题标题】:How to inject vendor class to Service?如何将供应商类注入服务?
【发布时间】:2018-03-27 17:25:20
【问题描述】:

我有示例服务:

<?php

namespace AppBundle\Service;

use AppBundle\Entity\Article;
use CompanyName\Utils\ClassFromVendor;

class DecorateArticle
{
    private $customDecorator;
    private $article;

    public function __construct(CustomDecorator $customDecorator)
    {
        $this->customDecorator = $customDecorator;
    }

    public function setNews(Article $article)
    {
        $this->article = $article;
    }

    public function decorate() : string
    {
         $text = strip_tags($this->article->getBody());

         $text = $this->customDecorator->doIt($text);

         $classFromVendor = new ClassFromVendor();
         $text = $classFromVendor->doIt($text);

         return $text;
    }
}

//controller:

public function showToApiAction(Request $request)
{
    $em = $this->getDoctrine()->getManager();
    $news = $em->getRepository('AppBundle:News')->find($request->get('id'));

    $decorateArticle = $this->get('AppBundle\Service\DecorateArticle');
    $decorateArticle->setNews($news);

    return $decorateArticle->decorate();
}

//services.yml:

AppBundle\Service\DecorateArticle:
    arguments:
        $decorateArticle: '@AppBundle\Service\DecorateArticle'
    public: true

这段代码一切正常,但我的团队负责人告诉我,它违反了 SOLID 原则。

这就是我这样做的原因:

<?php

namespace AppBundle\Service;

use AppBundle\Entity\Article;
use CompanyName\Utils\ClassFromVendor;

class DecorateArticle
{
    private $customDecorator;
    private $classFromVendor;
    private $article;

    public function __construct(CustomDecorator $customDecorator, ClassFromVendor $classFromVendor)
    {
        $this->customDecorator = $customDecorator;
        $this->classFromVendor = $classFromVendor;
    }

    public function setNews(Article $article)
    {
        $this->article = $article;
    }

    public function decorate() : string
    {
         $text = strip_tags($this->article->getBody());

         $text = $this->customDecorator->doIt($text);

         $text = $this->classFromVendor->doIt($text);

         return $text;
    }
}

//controller:

public function showToApiAction(Request $request)
{
    $em = $this->getDoctrine()->getManager();
    $news = $em->getRepository('AppBundle:News')->find($request->get('id'));

    $decorateArticle = $this->get('AppBundle\Service\DecorateArticle');
    $decorateArticle->setNews($news);

    return $decorateArticle->decorate();
}

//services.yml:

AppBundle\Service\DecorateArticle:
    arguments:
        $decorateArticle: '@AppBundle\Service\DecorateArticle'
        $classFromVendor: 'CompanyName\Utils\ClassFromVendor'
    public: true

但是这个抛出错误:

类型错误:参数 2 传递给 AppBundle\Service\DecorateArticle::__construct() 必须是一个实例 CompanyName\Utils\ClassFromVendor 或 null,给定字符串

如何将供应商类注入服务?

也许有更好的方法来做我所做的事情? 我不确定是否可以在一个类中使用 services.yml 和 setter (setNews) 中的注入。

【问题讨论】:

  • 注入问题更少,更多的是您传递的是字符串而不是对象。检查你的论点
  • 是的,您可以在同一个服务定义中同时使用构造函数和设置器注入。但是,请仔细查看服务定义中的参数。注意到 classFromVendor 中缺少什么吗?可能值得查看有关创建服务的文档,以便了解差异为何如此重要。

标签: php symfony solid-principles symfony-3.4


【解决方案1】:

试试这个。

AppBundle\Service\DecorateArticle:
        arguments:
            decorateArticle: '@AppBundle\Service\DecorateArticle'
            classFromVendor: companyName.utils.ClassFromVendor
        public: true


companyName.utils.ClassFromVendor:
    class: CompanyName\Utils\ClassFromVendor
    public: false

我不知道 decorateArticle 是否有效,因为您使用同一个服务作为参数.. 我认为这是将类作为参数传递给服务的正确方法。

【讨论】:

  • 好吧,不。可能会再试一次。
【解决方案2】:

在 Symfony 4 中,我需要将供应商类注入我的一项服务:

 jiraRestApi.ClassFromVendor:
    class: JiraRestApi\Issue\IssueService
    public: false

CM\Infrastructure\IssueJira\IssueJiraDbRepository:
    arguments: ['@jiraRestApi.ClassFromVendor', '@parameter_bag']
    public: false

您可能认为 jiraRestApi.ClassFromVendor 是一个供应商类。

我的 IssueJiraDbRepository.php 有一个构造函数:

public function __construct(JiraRestApi Issue, ParameterBagInterface $params){ ...

所以在你的情况下,我假设你必须制作 service.yaml:

CompanyName.ClassFromVendor:
    class: CompanyName\Utils\ClassFromVendor
    public: false

AppBundle\Service\DecorateArticle:
    arguments:['@CompanyName.ClassFromVendor']
    public: true

记住参数中的“@”。控制器中的构造函数应该保持不变:

public function __construct(CustomDecorator $customDecorator)
{
    $this->customDecorator = $customDecorator;
}

将 services.yaml 视为控制器的构造函数。放置在那里的参数将用于创建控制器的实例。您遇到的错误是您传递了字符串而不是对象。如果您遇到问题,您可以随时使用 autowire,在大多数情况下就足够了。请记住,service.yaml 中的新条目将替换以前的条目。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-11
    • 2020-07-22
    • 1970-01-01
    相关资源
    最近更新 更多