Как внедрить класс поставщика в Сервис?
У меня есть пример службы:
<?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 и setters (setNews) в одном классе.
1 ответ
В 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 заменят предыдущие.
Попробуй это.
AppBundle\Service\DecorateArticle:
arguments:
decorateArticle: '@AppBundle\Service\DecorateArticle'
classFromVendor: companyName.utils.ClassFromVendor
public: true
companyName.utils.ClassFromVendor:
class: CompanyName\Utils\ClassFromVendor
public: false
Я не знаю, работает ли decorateArticle, потому что вы используете в качестве параметра один и тот же сервис. Я думаю, что это правильный способ передачи класса в качестве параметра в сервис.