繁体   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