Я разрабатываю приложение, в котором у меня есть несколько обработчиков в качестве сервисов, которые я хочу вызывать.Оба они реализуют ItemHandlerInterface
.
. Я бы хотел, чтобы в контроллере можно было получать всю коллекцию ItemHandlerInterface
сервисов , не подключая их вручную.
Пока что я пометил их специально:
services.yaml
_instanceof:
App\Model\ItemHandlerInterface:
tags: [!php/const App\DependencyInjection\ItemHandlersCompilerPass::ITEM_HANDLER_TAG]
lazy: true
И попробуйте получить мою коллекцию сервисов в контроллере.Это работает, если только один сервис реализует ItemHandlerInterface
, но как только я создаю несколько (как показано ниже TestHandler
и Test2Handler
, я получаю The service "service_locator.03wqafw.App\Controller\ItemUpdateController" has a dependency on a non-existent service "App\Model\ItemHandlerInterface".
Как я могудинамически извлекать все сервисы, реализующие мой интерфейс?
Одно грязное решение - заставить все ItemHandlerInterface
с public: true
и передать Container
моему конструктору контроллера. Но это уродливо, и я хотел бычтобы найти более элегантный способ.
ItemUpdateController
namespace App\Controller;
use App\Model\ItemHandlerInterface;
use App\Service\ItemFinder;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Debug\Exception\ClassNotFoundException;
use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use App\Model\Item;
use Psr\Container\ContainerInterface;
/**
* Class ItemUpdateController
*
* @package App\Controller
*/
class ItemUpdateController extends AbstractController
{
/**
* @var ContainerInterface
*/
protected $locator;
public function __construct(ContainerInterface $locator)
{
$this->locator = $locator;
}
public static function getSubscribedServices()
{
// Try to subscribe to all ItemHandlerInterface services
return array_merge(
parent::getSubscribedServices(),
['item_handler' => ItemHandlerInterface::class]
);
}
/**
* @param string $id
* @param RequestStack $requestStack
* @param ItemFinder $itemFinder
*
* @return Item
* @throws \Symfony\Component\Debug\Exception\ClassNotFoundException
*/
public function __invoke(
string $id,
RequestStack $requestStack,
ItemFinder $itemFinder
) {
// Find item
$item = $itemFinder->findById($id);
// Extract and create handler instance
$handlerName = $item->getHandlerName();
if($this->locator->has($handlerName)) {
$handler = $this->locator->get($handlerName);
$request = $requestStack->getCurrentRequest();
$payload = json_decode($request->getContent());
call_user_func($handler, $payload, $request);
return $item;
}
}
}
src / ItemHandler / TestHandler.php
namespace App\ItemHandler;
use App\Model\ItemHandlerInterface;
use Doctrine\ORM\EntityManagerInterface;
class TestHandler implements ItemHandlerInterface
{
// implementation
}
src / ItemHandler / Test2Handler.php
namespace App\ItemHandler;
use App\Model\ItemHandlerInterface;
use Doctrine\ORM\EntityManagerInterface;
class Test2Handler implements ItemHandlerInterface
{
// implementation
}