首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Symfony6使用"kernel.controller“事件手动更改控制器。如何注入服务容器?

Symfony6使用"kernel.controller“事件手动更改控制器。如何注入服务容器?
EN

Stack Overflow用户
提问于 2022-05-04 14:03:58
回答 1查看 444关注 0票数 -2

我正在构建的应用程序不会以传统的方式工作。所有的路线都将存储在数据库中。根据路线,我需要得到正确的控制器和动作来执行。

据我所知,这可以使用"kernel.controller“事件侦听器:https://symfony.com/doc/current/reference/events.html#kernel-controller来实现。

我正在尝试使用所提供的文档,但是这里的示例并没有准确地说明如何设置要传递的新的可调用控制器。这里有一个问题,因为我不知道如何将服务容器注入到我新调用的控制器中。

首先,设置如下:

services.yaml

代码语言:javascript
复制
parameters:
    db_i18n.entity: App\Entity\Translation
    developer: '%env(DEVELOPER)%'
    category_directory: '%kernel.project_dir%/public/uploads/category'
    temp_directory: '%kernel.project_dir%/public/uploads/temp'
    product_directory: '%kernel.project_dir%/public/uploads/product'
    app.supported_locales: 'lt|en|ru'
services:
    _defaults:
        autowire: true
        autoconfigure: true

    App\:
        resource: '../src/'
        exclude:
            - '../src/DependencyInjection/'
            - '../src/Entity/'
            - '../src/Kernel.php'

    App\Translation\DbLoader:
        tags:
            - { name: translation.loader, alias: db }

    App\Extension\TwigExtension:
        arguments:
            - '@service_container'
        tags:
            - { name: twig.extension }

    App\EventListener\RequestListener:
        tags:
            - { name: kernel.event_listener, event: kernel.controller, method: onControllerRequest }

听众:

RequestListener.php

代码语言:javascript
复制
<?php

namespace App\EventListener;

use App\Controller\Shop\HomepageController;
use App\Entity\SeoUrl;
use Doctrine\Persistence\ManagerRegistry;
use Exception;
use Psr\Container\ContainerInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Security;

class RequestListener
{
    public ManagerRegistry $doctrine;
    public RequestStack $requestStack;

    public function __construct(ManagerRegistry $doctrine, RequestStack $requestStack)
    {
        $this->doctrine = $doctrine;
        $this->requestStack = $requestStack;
    }

    /**
     * @throws Exception
     */
    public function onControllerRequest(ControllerEvent $event)
    {
        if (!$event->isMainRequest()) {
            return;
        }

        if(str_contains($this->requestStack->getMainRequest()->getPathInfo(), '/admin')) {
            return;
        }

        $em = $this->doctrine->getManager();
        $pathInfo = $this->requestStack->getMainRequest()->getPathInfo();
;
        $route = $em->getRepository(SeoUrl::class)->findOneBy(['keyword' => $pathInfo]);

        if($route instanceof SeoUrl) {
            switch ($route->getController()) {
                case 'homepage':
                    $controller = new HomepageController();
                    $event->setController([$controller, $route->getAction()]);
                    break;
                default:
                    break;
            }
        } else {
            throw new Exception('Route not found');
        }

    }
}

这是最基本的例子。我从数据库中获取路由,如果它是“主页”路由,则创建新的HomepageController并设置操作。然而,我错过了我不知道如何注入的容器接口。我知道这个错误:

对成员函数的调用在空上有()

在线:vendor\symfony\framework-bundle\Controller\AbstractController.php:216

即:

代码语言:javascript
复制
/**
 * Returns a rendered view.
 */
protected function renderView(string $view, array $parameters = []): string
{
    if (!$this->container->has('twig')) { // here
        throw new \LogicException('You cannot use the "renderView" method if the Twig Bundle is not available. Try running "composer require symfony/twig-bundle".');
    }

    return $this->container->get('twig')->render($view, $parameters);
}

控制器是最基本的:

HomepageController.php

代码语言:javascript
复制
<?php

namespace App\Controller\Shop;

use App\Repository\CategoryRepository;
use App\Repository\Shop\ProductRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class HomepageController extends AbstractController
{
    #[Route('/', name: 'index', methods: ['GET'])]
    public function index(): Response
    {
        return $this->render('shop/index.html.twig', [
        ]);
    }
}

所以基本上容器是没有设置的。如果我转储了$event->getController(),就会得到以下内容:

代码语言:javascript
复制
RequestListener.php on line 58:
array:2 [▼
  0 => App\Controller\Shop\HomepageController {#417 ▼
    #container: null
  }
  1 => "index"
]

我需要通过执行$controller->setContainer()来设置容器,但是传递什么呢?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-05-04 14:36:46

不要注入容器,控制器也是服务,手动实例化它们会阻止您使用构造函数依赖项注入。使用只包含控制器的服务定位器:

config/services.yaml中声明

代码语言:javascript
复制
# config/services.yaml
services:
    App\EventListener\RequestListener:
        arguments:
            $serviceLocator: !tagged_locator { tag: 'controller.service_arguments' }

然后在事件侦听器中,添加服务定位器参数并从它获取完全配置的控制器:

代码语言:javascript
复制
# ...
use App\Controller\Shop\HomepageController;
use Symfony\Component\DependencyInjection\ServiceLocator;

class RequestListener
{
    # ...
    private ServiceLocator $serviceLocator;

    public function __construct(
        # ...
        ServiceLocator $serviceLocator
    ) {
        # ...
        $this->serviceLocator = $serviceLocator;
    }

    public function onControllerRequest(ControllerEvent $event)
    {
        # ...

        if($route instanceof SeoUrl) {
            switch ($route->getController()) {
                case 'homepage':
                    $controller = $this->serviceLocator->get(HomepageController::class);
                    # ...
                    break;
                default:
                    break;
            }
        }

        # ...
    }
}

如果您转储任何控制器,您将看到容器已设置。对于您从构造函数中自动生成的额外服务也是如此。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72114326

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档