簡體   English   中英

Symfony - 如何從容器動態獲取服務?

[英]Symfony - How do I get services dynamically from the container?

對於一個 API 項目,如果輸入數據不正確,我想盡早失敗,在 controller 被調度之前。 我已經設法通過使用路由默認值和訂閱KernelEvents::REQUEST事件的事件訂閱者來完成驗證。

正如您在代碼中看到的,我正在嘗試從容器中獲取驗證器。 我在這里的假設是,因為自動連線已打開,所以它應該找到它們,但has()永遠不會返回true

那么我到底做錯了什么? 我正在嘗試自動解析驗證器,我寧願不必在 services.yml 文件中顯式聲明它。

Controller(摘錄):

    #[Route('/sign-up', name: 'sign_up', defaults: ['_validator' => SignUpValidator::class],methods: ['POST'])]
    public function register(int $page): Response
    {
        return new Response();
    }

事件訂閱者(摘錄):

    public function __construct(
        protected readonly Container $container
    ) {}
    
    protected function resolveValidator(Request $request): ?RequestValidatorInterface
    {
        $validatorClass = (string)$request->attributes->get('_validator');

        if ($this->container->has($validatorClass)) {
            return $this->container->get($validatorClass);
        }

        return null;
    }
# This file is the entry point to configure your own services.
# Files in the packages/ subdirectory configure your dependencies.

# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
parameters:

services:
    # default configuration for services in *this* file
    _defaults:
        autowire: true      # Automatically injects dependencies in your services.
        autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.

    # makes classes in src/ available to be used as services
    # this creates a service per class whose id is the fully-qualified class name
    App\:
        resource: '../src/'

        exclude:
            - '../src/Entity/'
            - '../src/Kernel.php'

    # add more service definitions when explicit configuration is needed
    # please note that last definitions always *replace* previous ones
    Psr\Container\ContainerInterface: '@service_container'
    Symfony\Component\DependencyInjection\Container: '@service_container'

雖然不再可能從主服務容器獲取私有服務,但您可以選擇將其公開。 這當然需要額外的開發人員工作,但這將阻止它被自動刪除/內聯,並將使其直接在服務容器中可用。

順便說一下,自動裝配只有在服務被定義為控制器/方法的參數時才有效。 在您的情況下, Symfony 在確定要注入的服務時不考慮 Route 注釋的默認值。

如果您不想公開這些類型的驗證器服務,一種可能的方法是創建一個包含所有可能的驗證器服務的自定義服務定位器。 您可以為這些服務創建服務標簽(例如app.request_validator )並使用標記接口 ( RequestValidatorInterface ) 來自動配置它們。 這將允許您通過一個統一的界面管理和訪問所有驗證器服務:

class SignUpValidator implements RequestValidatorInterface
{
    // ...
}

在任何 DI 擴展上下文中:

$container->registerForAutoconfiguration(RequestValidatorInterface::class)
    ->addTag('app.request_validator');

然后,您的事件訂閱者可以注入這個小定位器:

App\EventSubscriber\RequestValidatorSubscriber:
    arguments:
        - !tagged_locator 'app.request_validator'

RequestValidatorSubscriber可以使用Psr\Container\ContainerInterface作為此定位器參數的類型。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM