当前位置: 首页 > 知识库问答 >
问题:

Symfony 4在不同环境中提供本地绑定服务

柳宏深
2023-03-14

我必须在不同的环境中绑定具有不同值的参数,并且在这方面存在问题。

我在尝试这个:

# config/services.yaml
services:
    _defaults:
        bind:
            $param: 'param for PROD'

# config/services_dev.yaml
services:
    _defaults:
        bind:
            $param: 'param for DEV'

# src/Controller/SomeController.php
class MyController extends AbstractController
{
    public function example($param)
    {
        echo $param;
    }
}

但它迫使我在services.yaml和services_dev.yaml文件中定义所有服务,否则它不起作用。

我想有一个services.yaml共享的任何环境,并只重写自定义服务/绑定等,而不是有两个相同的文件与所有的服务列在他们改变一个绑定值。

真正的问题是,我必须创建两个具有相同接口的http客户端(real和dummy),在生产中加载real客户端,在开发中加载dummy,Symfony 4-s autowiring允许我将接口插入控制器中,并选择在绑定中使用哪个客户端

# config/services.yaml
services:
    _defaults:
        bind:
            'ClientInterface': '@real_client'
    # More services here...

# config/services_dev.yaml
services:
    _defaults:
        bind:
            'ClientInterface': '@dummy_client'
    # Here I don't want to have another copy of the services, 
    # but it does not work without them

# Controller
public function someMethod(ClientInterface $client)
{
    // ...
}

在Symfony 2中,我能够扩展服务。yml和in services_dev.yml只定义我想要覆盖/添加的特定值,但在Symfony 4 services_dev.yaml中不能使用来自服务的服务。yaml和我必须在两个不同的文件中保持我的服务相同,这很痛苦。

奇怪的建议?

谢谢你。

我再次更新后与一个真实的例子:

# 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/configuration.html#application-related-configuration
parameters:
    locale: 'en'
    app.access_token: '%env(string:APP_ACCESS_TOKEN)%'
    app.aws_version: '%env(string:AWS_VERSION)%'
    app.aws_profile: '%env(string:AWS_PROFILE)%'
    app.aws_region: '%env(string:AWS_REGION)%'
    app.aws_queue_url_creation: '%env(string:AWS_QUEUE_URL_CAMPAIGN_CREATION)%'
    app.aws_queue_url_edition: '%env(string:AWS_QUEUE_URL_CAMPAIGN_EDITION)%'
    app.redis_host: '%env(string:REDIS_HOST)%'
    app.redis_port: '%env(string:REDIS_PORT)%'

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.
        public: false       # Allows optimizing the container by removing unused services; this also means
                            # fetching services directly from the container via $container->get() won't work.
                            # The best practice is to be explicit about your dependencies anyway.
        bind:
            App\Service\MessageSenderServiceInterface: '@App\Service\MessageSenderSqsService'

    # 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/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'

    # 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']

    # add more service definitions when explicit configuration is needed
    # please note that last definitions always *replace* previous ones

    # Authenticators
    App\Security\ApiKeyAuthenticator:
        arguments:
            - "%app.access_token%"

    # Clients
    App\Client\AwsSqsClient:
        arguments:
            - "%app.aws_version%"
            - "%app.aws_profile%"
            - "%app.aws_region%"

    App\Client\RedisClient:
        arguments:
            - "%app.redis_host%"
            - "%app.redis_port%"

    # Services
    App\Service\MessageSenderSqsService:
        arguments:
            - '@App\Client\AwsSqsClient'
            - '@App\Client\RedisClient'
            - "%app.aws_queue_url_creation%"
            - "%app.aws_queue_url_edition%"

    App\Service\MessageSenderRedisService:
        arguments:
            - '@App\Client\RedisClient'
imports:
    - { resource: services.yaml }

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.
        public: false       # Allows optimizing the container by removing unused services; this also means
                            # fetching services directly from the container via $container->get() won't work.
                            # The best practice is to be explicit about your dependencies anyway.
        bind:
            App\Service\MessageSenderServiceInterface: '@App\Service\MessageSenderRedisService'
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;

class TestController extends AbstractController
{
    /**
     * @Route("/api/dummy")
     */
    public function dummyEndpoint(MessageSenderServiceInterface $messageSender)
    {
        echo get_class($messageSender); exit;
    }
}

来自两个环境(prod和dev)的控制器的回音是

App\Service\MessageSenderSqsService

但如果我复制整个节点的“服务”表单服务。yaml到services_dev.yaml,并且只更改绑定配置,它工作正常,并说明注入的类是:

App\Service\MessageSenderRedisService

我刚刚注意到,如果我不触摸“_defaults”节点,它会按预期工作,只有当我想覆盖服务的_defaults节点时,问题才会开始...

共有3个答案

谷梁迪
2023-03-14

您有一些选择:

1.不要使用bind为不同的环境编写不同的服务配置

# services.yaml
App\Controller:
  arguments:
    - "@client"

# services_dev.yaml
App\Controller:
  arguments:
    - "@dummy_client"

2.使用bind并在每个环境的services.yaml中创建服务别名:

# services.yaml
services:
  some.client:
    alias: "@client"

# services_dev.yaml    
services:
  some.client:
    alias: "@dummy_client"

3.只需为每个环境配置一个ClientInterface服务:

# services.yaml
App\ClientInterface:
  class: App\RealClient

# services_dev.yaml
App\ClientInterface:
  class: App\DummyClient

4.使用将创建此客户端的工厂取决于环境(但这对我来说不是很好的做法)

# services.yaml
App\ClientInterface:
  factory: ["@App\ClientFactory", create]
  arguments:
    - '%kernel.environment%'

class ClientFactory 
{
    public function create(string $env): ClientInterface
    {
        if ($env === 'dev') {
            return new DummyClient();
        } else {
            return new Client();
        }
    }
}

5.在您的情况下,当您有这么多服务,并且您想在所有服务中注入相同的服务时,您可以使用选项#3,或者您可以为所有服务创建一个接口,并使用_instanceof

# services.yaml
_instanceof:
  App\SomeCommonInterface:
    calls:
      - method: setSomeService # interface's method
        arguments:
          - '@service'

# services_dev.yaml
_instanceof:
  App\SomeCommonInterface:
    calls:
      - method: setSomeService
        arguments:
          - '@dummy_service'
甄煜
2023-03-14

您可以在config的parameters部分中定义参数。yml并在配置文件yml中覆盖此参数。

# config.yml
imports:
    # ...
parameters:
    parameter_1: value 1
    parameter_2: value 2
    # ...
framework:
    # ...

# config_dev.yml
imports:
    # ...
parameters:
    parameter_1: dev value 1
    # ...
framework:
    # ...

此参数可在服务中使用。yml格式如下:

# service.yml
services:
    _defaults:
        bind:
            $param: '%parameter_1%'
令狐运珧
2023-03-14

最后,问题只出在重写_defaults节点上(为了在项目中有不同的绑定配置,我接触了这个节点)。

扩展服务。yaml在不覆盖默认值的情况下,一切正常。解决方案是根据环境对具有绑定的服务进行不同的配置,并且只在服务中使用“\u默认值”。亚马尔。

如果我们覆盖其他文件中的“_defaults”,我们也必须重新定义所有服务。

谢谢大家的帮助。

 类似资料:
  • 本文向大家介绍spring Profile如何为不同环境提供不同的配置支持,包括了spring Profile如何为不同环境提供不同的配置支持的使用技巧和注意事项,需要的朋友参考一下 说明 Profile为在不同环境下使用不同的配置提供了支持(开发环境下的配置和生产环境下的配置肯定是不同的, 例如, 数据库的配置) 。 在spring开发中用@Profile 注解使用来选择行配置系统属性。而在sp

  • 我有一个树视图,其中单元格必须根据TreeItem值的实际实现显示不同的信息。 我的域模型如下所示: 在我看来,将“如何在单元格中显示任务”或“如何在单元格中显示组”的行为分为两个不同的类是很自然的。 下面的控制器类包含一个树视图,我在其中设置CellFactory。 但现在我被困在这里,无法决定我必须返回哪种类型的牢房。事实上,我只有相关的TreeView参数,而没有相关的TreeItem! 在

  • 我有一个Spring boot应用程序,它使用以下方法将时间戳解析为我需要的格式 现在,当该代码在本地机器中执行时,上述方法返回: 2021-08-11T09:00:02.237 05:30 但是当我将其部署到运行nginx服务器的环境时,上述方法返回: 2021-08-11T09:00:02.237Z 现在我的理解是,它正在转换为UTC格式(0000/Z)。如果我错了,请纠正我。但是预期的格式是

  • 我在React本地(世博环境)导航有问题。我想使用在中的上放置一个保存按钮,但是会抛出错误消息,该消息在附加的中给出。 另外,由于这个按钮需要访问组件状态,所以我不想在外部使用 如何访问和修改组件中的标头部分?

  • - Getting the Code To download all of the code, clone the eos repository and its submodules. git clone https://github.com/EOSIO/eos --recursive If a repository is cloned without the --recursive flag,

  • 当我尝试在maven项目上构建Jenkins时,我收到了这个错误: java和maven插件是自动安装的,经过几次研究,我找不到解决方案! 有没有人遇到过这个问题?