首页 > 解决方案 > Symfony 5.1 - 无法自动装配服务

问题描述

我想重构我的代码,但现在我有错误并且不明白是什么。Objectif :调用 TokenService 时不需要传递参数,使用自动装配来自动装配 EntityManager & Request,控制器调用服务时不要设置。

无法解析 App\Controller\TokenController::showTokens() 的参数 $tokenService 无法自动装配服务 App\Service\TokenService 方法 __construct() 的参数 $request 引用类 Symfony\Component\HttpFoundation\Request 但不存在此类服务。

前 :

/src/Controller/TokenController.php

<?php

namespace App\Controller;

use App\Service\TokenService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request;

/**
 * @Route("/v1")
 */
class TokenController
{
   /** @var EntityManagerInterface $em */
    private $em;
    /** @var Request $request */
    private $request;

    /**
     * TokenService constructor.
     *
     * @param Request $request
     * @param EntityManagerInterface $em
     */
    public function __construct(Request $request, EntityManagerInterface $em)
    {
        $this->request = $request;
        $this->em = $em;
    }

    public function showTokens(Request $request, EntityManagerInterface $em): JsonResponse
    {
        $tokenService = new TokenService($request, $em);

        return $tokenService->getTokens();
    }
}

/src/Service/TokenService.php

<?php

namespace App\Service;

use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

/**
 * Class TokenService
 * @package App\Service
 */
class TokenService
{
    /** @var EntityManagerInterface $em */
    private $em;
    /** @var Request $request */
    private $request;

    /**
     * TokenService constructor.
     *
     * @param Request $request
     * @param EntityManagerInterface $em
     */
    public function __construct(Request $request, EntityManagerInterface $em)
    {
        $this->request = $request;
        $this->em = $em;
    }

    public function getTokens()
    {
        return true;
    }
}

后 :

/config/services.yaml

parameters:

services:
    _defaults:
        autowire: true
        autoconfigure: true

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

    App\Controller\:
        resource: '../src/Controller/'
        tags: ['controller.service_arguments']

    App\Service\TokenService: ~

/src/Controller/TokenController.php

<?php

namespace App\Controller;

use App\Service\TokenService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request;

/**
 * @Route("/v1")
 */
class TokenController
{
    public function showTokens(Request $request, EntityManagerInterface $em, TokenService $tokenService): JsonResponse
    {
        return $tokenService->getTokens();
    }

/src/Service/TokenService.php

<?php

namespace App\Service;

use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request;
/**
 * Class TokenService
 * @package App\Service
 */
class TokenService
{
    /** @var EntityManagerInterface $em */
    private $em;
    /** @var Request $request */
    private $request;

    /**
     * TokenService constructor.
     *
     * @param Request $request
     * @param EntityManagerInterface $em
     */
    public function __construct(Request $request, EntityManagerInterface $em)
    {
        $this->request = $request;
        $this->em = $em;
    }

    public function getTokens()
    {
        return true;
    }
}

谢谢 !

标签: phpsymfonydoctrine-ormautowired

解决方案


我想我们已经有一段时间没有提出很好的请求堆栈问题了。我进行了一些搜索,但没有找到任何直接适用并提供了体面解释的答案。

基本问题是 Symfony 框架支持嵌套请求。例如,当使用嵌入式控制器时,您会得到这些。所以没有实际的请求服务。实际上曾经有过 Symfony 2.0 第一次发布的时候,但它真的是一团糟。支持嵌套请求服务是在容器级别完成的,并不好玩。

因此引入了称为请求堆栈的大锤子来一劳永逸地解决问题。您注入请求堆栈而不是请求,然后在您实际需要时访问请求。

class TokenService
{
    private $em;
    private $requestStack;

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

    public function getTokens()
    {
        $request = $this->requestStack->getMasterRequest(); // or possibly getCurrentRequest depending on where the tokens are
        return true;
    }

话虽如此,我个人只会传递控制器的请求。这样做可以消除我的“取决于”评论。我也认为它减少了一点所涉及的“魔法”。这两种方法都行得通。

class TokenService
{
    public function getTokens(Request $request)
    {
        return true;
    }
...
class TokenController
{
    public function showTokens(Request $request, TokenService $tokenService): JsonResponse
    {
        return $tokenService->getTokens($request);
    }

推荐阅读