如何在自定义捆绑包控制器中使用学说 - "Controller has required constructor arguments and does not exist in the container. "

How to use doctrine in custom bundle controllers - "Controller has required constructor arguments and does not exist in the container. "

我有一个带有两个自定义可重用包的 Symfony 5.3 项目。

我在 bundle1 中创建了一个实体,我希望能够从 bundle2[=21 中读取和写入它=]

但是,我无法将 Doctrine 成功地包含在我的任何捆绑包控制器中。

我什么都试过了:扩展控制器,扩展AbstractController,添加一个构造函数来传递原则,将控制器定义为服务,但我什么都做不了。

project/bundle1/src/Controller/testController.php:

namespace Bundle1\TestController;

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Doctrine\ORM\EntityManagerInterface;
use Bundle1\Entity;


class TestController 
{

private $entityManager;

public function __construct( EntityManagerInterface $entityManager) {
        $this->em = $entityManager;
}

     /**
     * @Route("/list", name="list")
     */
    public function listingsAction(): Response
    {


    //$this->em = $this->getDoctrine()->getManager();

    return new Response(
            '<html><body><h1>List from DB</h1> 
            
            </body></html>'
        );
    }
}

错误:

The controller for URI "/list" is not callable: Controller "Bundle1\TestController\TestController" has required constructor arguments and does not exist in the container. Did you forget to define the controller as a service?

编辑** 根据@Cerad 的帮助对以下内容进行了修改,但不幸的是,相同的错误消息仍然存在。

我正在使用自动装配,我有以下 services.xml 通过依赖注入加载:

project/bundle1/Resources/config/services.xml:

        <?xml version="1.0" encoding="UTF-8" ?>
        <container xmlns="http://symfony.com/schema/dic/services"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://symfony.com/schema/dic/services
                https://symfony.com/schema/dic/services/services-1.0.xsd">
 <services>
             <service 
                id="Bundle1\Controller\TestController\TestController" 
               public="true">
     <call method="setContainer">
                <argument type="service" id="doctrine.orm.entity_manager"/>
     </call>
                <tag name="controller.service_arguments"/>
            </service>
</services>
        </container>

我使用了路由注释

project/config/routes/annotations.yaml文件:

controllers-bundle1:
    resource: ../../bundle1/src/Controller/
    type: annotation

当我在控制台中 运行 php bin/console debug:container 'bundle1.controller.test_controller' 时,我得到:

No services found that match "bundle1.controller.test_controller".

project/bundle1/src/Bundle1.php

namespace Bundle1;

use Symfony\Component\HttpKernel\Bundle\Bundle;

class Bundle1 extends Bundle
{
    public function getPath(): string
    {
        return \dirname(__DIR__);
    }
}

project/config/bundles.php

return [
    Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
    Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
    Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
    Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
    Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
    Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
    Bundle1\Bundle1::class => ['all' => true],
];

似乎我没有将我的控制器正确定义为服务,但在文档中找不到关于如何执行此操作的明确信息。

**更新:


刚在错误堆栈中找到这个**

ArgumentCountError Too few arguments to function Bundle1\TestController\TestController::__construct(), 0 passed in /home/Project/vendor/symfony/http-kernel/Controller/ControllerResolver.php on line 147 and exactly 1 expected

in bundle1/src/Controller/TestController.php (line 17) class TestController { private $entityManager; public function __construct( EntityManagerInterface $entityManager) { $this->em = $entityManager;

让我们从符合 'best practices' 的实际答案开始,然后讨论一下。

class TestController // Should not extend anything for bundle controllers
{
    // All services should be injected
    public function __construct(private EntityManagerInterface $em)
...
# Resources/config/services.xml
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
        https://symfony.com/schema/dic/services/services-1.0.xsd">

    <services>
        <service 
            id="my_bundle.controller.test_controller" 
            class="MyBundle\Controller\TestController" 
            public="true">
            <argument type="service" id="doctrine.orm.entity_manager"/>
            <tag name="controller.service_arguments"/>
        </service>
    </services>
</container>

# and since snake case service ids are recommended
# config/routes.yaml

bundle_test:
    path: /
    controller: my_bundle.controller.test_controller::index

这应该会为您提供一个注入了实体管理器的工作页面。

这里用xml是因为题目中用到了,但php可能更好。 web-profiler-bundle 就是一个很好的例子。

我们没有使用控制器 class 名称作为服务 ID,而是根据推荐做法拼写了一个。您的路线将需要使用它。

public=true 非常重要。 Symfony 使用容器感知控制器解析器并最终从容器中提取控制器服务。所以控制器服务必须是public.

如果您需要将服务注入到操作方法中,则需要该标签。不确定您是否应该使用捆绑包来执行此操作。如果您不需要它,请将其删除。

当然,您需要手动注入任何服务或参数。容器文档有更多示例。

讨论了一些替代方法 here