亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何在 Symfony 5 的其他目錄中自動注冊“控制器即服務”

如何在 Symfony 5 的其他目錄中自動注冊“控制器即服務”

PHP
紅糖糍粑 2023-04-21 17:26:59
背景我想使用功能內聚來組織我的控制器。這意味著我不會有一個Controllers/目錄,這使得框架很容易,但我會按用例組織我的代碼。一個任意的例子:src/FetchLatestNews/Controller.phpsrc/FetchLatestNews/News.phpsrc/FetchLatestNews/NewsRepository.php...ETC但是,Symfony 默認設置為要求所有控制器都在一個地方。見services.yaml:  # controllers are imported separately to make sure services can be injected    # as action arguments even if you don't extend any base controller class    App\Controller\:        resource: '../src/Controller'        tags: ['controller.service_arguments']按照上面的模板,我可以將新控制器放在src/FetchLatestNews/Controller那里,然后每次都添加每個新控制器。但是,我不想,也不應該在每次創建新用例時手動更新此文件。問題我怎樣才能避免這個錯誤:也許你忘記了將控制器注冊為服務或者錯過了用“controller.service_arguments”標記它作為用戶,我不必關心手動添加service_arguments或任何其他配置。當我指定一條路線時,它指向的東西因此是一個控制器。理想的工作流程是:在我喜歡的任何地方創建一個控制器。添加一個路由來routes.yaml引用控制器。就是這樣!是否可以在 Symfony 中實現此工作流程?應該是,因為路由中的任何內容 --> 某個類都將是控制器。有沒有辦法使用正則表達式或其他解決方案?注意:這個答案暗示了一個空的界面類型的“hack”。這也不理想。還有其他選擇嗎?
查看完整描述

1 回答

?
蝴蝶刀刀

TA貢獻1801條經驗 獲得超8個贊

請注意,此答案已使用新信息再次更新。

標簽controller.service_arguments只需要允許動作注入。堅持使用構造函數注入,__invoke()這就是您所需要的。

下面的公共添加是一項要求,但事實證明您不需要編譯器傳遞,它可以在 services.yaml 級別完成。因此,您唯一需要的是以下內容:

services:
    _defaults:
        autowire: true
        autoconfigure: true
        public: true         // <---- This is the new additional config.

然后,任何類都可以用作routes.yaml控制器并且構造注入工作得很好。

注:原答案如下。感謝 Jakumi 為我指明了正確的方向。

您需要添加一個編譯器傳遞來做兩件事。在啟動和注冊自動依賴注入的東西時,如果一個類的Controller名稱中有:

  • 添加標簽controller.service_arguments,這是您通常需要手動添加的標簽services.yaml以允許 setter 注入(如果您不關心 setter 注入,可以忽略它)

  • 將類設置為公共的,因為 Symfony 有一個奇怪的想法,即公共或私有的概念不能從類訪問修飾符中推斷出來(真的嗎?)——這是重要的事情,因為 Symfony 會抱怨控制器是私有的,否則

不要忘記您不必使用“名稱控制器”的邏輯。它可以是“Controller”在類名的末尾,這可能更好。

不管怎樣,先創建一個CompilerPass. 把它放在任何你想要的地方。我把我的放在旁邊Kernel.php。

use Symfony\Component\DependencyInjection\{Compiler\CompilerPassInterface, ContainerBuilder};


class ControllersAsServices implements CompilerPassInterface

{

    public function process(ContainerBuilder $container)

    {

        foreach ($container->getDefinitions() as $definition) {

            if (strpos($definition->getClass(), "Controller") === false) {

                continue;

            }


            $definition->addTag("controller.service_arguments");

            $definition->setPublic(true);

        }

    }

}

然后在你的Kernel.php,你需要告訴它使用這個新的。覆蓋受保護的函數build并添加您的編譯器傳遞,如文檔所示:


protected function build(ContainerBuilder $container)

{

    $container->addCompilerPass(new ControllersAsServices, PassConfig::TYPE_BEFORE_OPTIMIZATION, -1);


    parent::build($container);

}

清除您的開發緩存。在我這樣做之前,我沒有任何改變。


現在,任何Controller名稱中帶有的類都可以像最初那樣被自動裝配。


下面是來自 Jakumi 的原始答案:


我相信在你的情況下最好的方法是實現一個 CompilerPass,將類添加到容器中:


https://symfony.com/doc/current/bundles/extension.html#adding-classes-to-compile


在此過程中,可能還有一種方法可以添加標簽。


Symfony 通過RegisterControllerArgumentLocatorsPass迎合 controller.service_arguments 標簽,它解析構造函數參數并檢查一些特征。如果你讓你的編譯器傳遞優先級更高,那么你可能很容易解決這個問題......


查看完整回答
反對 回復 2023-04-21
  • 1 回答
  • 0 關注
  • 127 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號