86

从我的控制器,我访问应用程序参数(那些/app/config

$this->container->getParameter('my_param')

但我不知道如何从服务访问它(我想我的服务类不应该扩展Symfony\Bundle\FrameworkBundle\Controller\Controller)。

我是否应该像这样将所需的参数映射到我的服务注册中:

#src/Me/MyBundle/Service/my_service/service.yml
parameters:
    my_param1: %my_param1%
    my_param2: %my_param2%
    my_param3: %my_param3%

或类似的东西?我应该如何从服务访问我的应用程序参数?


这个问题看起来是一样的,但我实际上回答了它(来自控制器的参数),我说的是从服务访问。

4

9 回答 9

132

您可以通过在服务定义中指定参数,以与注入其他服务相同的方式将参数传递给您的服务。例如,在 YAML 中:

services:
    my_service:
        class:  My\Bundle\Service\MyService
        arguments: [%my_param1%, %my_param2%]

其中%my_param1%etc 对应一个名为 的参数my_param1。那么您的服务类构造函数可以是:

public function __construct($myParam1, $myParam2)
{
    // ...
}
于 2012-06-26T16:17:07.697 回答
45

清洁方式 2018

自 2018 年和 Symfony 3.4 以来,有更清洁的方式 - 易于设置和使用。

您可以通过它的构造函数将参数传递给类,而不是使用容器和服务/参数定位器反模式。别担心,这不是耗时的工作,而是设置一次后忘记的方法。

如何分两步设置?

1.config.yml

# config.yml
parameters:
    api_pass: 'secret_password'
    api_user: 'my_name'

services:
    _defaults:
        autowire: true
        bind:
            $apiPass: '%api_pass%'
            $apiUser: '%api_user%'

    App\:
        resource: ..

2.任何Controller

<?php declare(strict_types=1);

final class ApiController extends SymfonyController
{
    /**
     * @var string 
     */
    private $apiPass;

    /**
     * @var string
     */
    private $apiUser;

    public function __construct(string $apiPass, string $apiUser)
    {
        $this->apiPass = $apiPass;
        $this->apiUser = $apiUser;
    }

    public function registerAction(): void
    {
        var_dump($this->apiPass); // "secret_password"
        var_dump($this->apiUser); // "my_name"
    }
}

即时升级准备就绪!

如果您使用较旧的方法,您可以使用 Rector 将其自动化

阅读更多

这称为服务定位器方法上的构造函数注入。

要了解更多信息,请查看我的文章How to Get Parameter in Symfony Controller the Clean Way

(它已经过测试,我会为新的 Symfony 主要版本(5、6...)更新它)。

于 2018-03-03T13:02:49.710 回答
21

与其一一映射你需要的参数,为什么不让你的服务直接访问容器呢?这样做,如果添加了新参数(与您的服务相关),您不必更新映射。

为此:

对您的服务类进行以下更改

use Symfony\Component\DependencyInjection\ContainerInterface; // <- Add this

class MyServiceClass
{
    private $container; // <- Add this
    public function __construct(ContainerInterface $container) // <- Add this
    {
        $this->container = $container;
    }
    public function doSomething()
    {
        $this->container->getParameter('param_name_1'); // <- Access your param
    }
}

在 services.yml 中添加 @service_container 作为“参数”

services:
  my_service_id:
    class: ...\MyServiceClass
    arguments: ["@service_container"]  // <- Add this
于 2015-09-07T09:16:32.137 回答
15

自 symfony 4.1 以来,有一种非常干净的新方法可以实现它

<?php
// src/Service/MessageGeneratorService.php

use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;

class MessageGeneratorService
{
 private $params;
 public function __construct(ParameterBagInterface $params)
 {
      $this->params = $params;
 }
 public function someMethod()
 {
     $parameterValue = $this->params->get('parameter_name');
...
 }
}

来源:https ://symfony.com/blog/new-in-symfony-4-1-getting-container-parameters-as-a-service 。

于 2018-11-06T12:56:10.547 回答
6

作为提到的一些问题的解决方案,我定义了一个数组参数然后注入它。稍后添加一个新参数只需要添加到参数数组,而不需要对 service_container 参数或构造进行任何更改。

所以扩展@richsage的答案:

参数.yml

parameters:
    array_param_name:
        param_name_1:   "value"
        param_name_2:   "value"

服务.yml

services:
    my_service:
        class:  My\Bundle\Service\MyService
        arguments: [%array_param_name%]

然后访问类内

public function __construct($params)
{
    $this->param1 = array_key_exists('param_name_1',$params)
        ? $params['param_name_1'] : null;
    // ...
}
于 2016-11-16T19:51:07.010 回答
6

Symfony 4.1的解决方案非常简单。

这是原始帖子的一个片段:

// src/Service/MessageGenerator.php
// ...

use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;

class MessageGenerator
{
    private $params;

    public function __construct(ParameterBagInterface $params)
    {
        $this->params = $params;
    }

    public function someMethod()
    {
        $parameterValue = $this->params->get('parameter_name');
        // ...
    }
}

链接到原帖: https ://symfony.com/blog/new-in-symfony-4-1-getting-container-parameters-as-a-service

于 2018-10-24T12:12:28.507 回答
0

@richsage 是正确的(对于 Symfony 3.?),但它不适用于我的 Symfony 4.x。所以这里是 Symfony 4。

在 services.yaml 文件中

parameters:
    param1: 'hello'

Services:
    App\Service\routineCheck:
            arguments:
                $toBechecked: '%param1%'  # argument must match in class constructor

在你的服务类routineCheck.php文件中做这样的构造函数

private $toBechecked;

public function __construct($toBechecked)
{
    $this->toBechecked = $toBechecked;
}

public function echoSomething()
{
    echo $this->toBechecked;
}

完毕。

于 2019-12-28T02:39:27.537 回答
-1

Symfony 3.4 在这里。

经过一些研究,我不认为通过它的构造函数将参数传递给类/服务总是一个好主意。想象一下,如果您需要向控制器/服务传递比 2 或 3 个更多的参数。然后呢?比方说,最多传递 10 个参数会很荒谬。

相反,ParameterBag在 yml 中声明服务时,将类用作依赖项,然后使用任意数量的参数。

一个具体的例子,假设你有一个邮件服务,比如 PHPMailer,并且你想在paramters.yml文件中包含 PHPMailer 连接参数:

#parameters.yml
parameters:
    mail_admin: abc@abc.abc
    mail_host: mail.abc.com
    mail_username: noreply@abc.com
    mail_password: pass
    mail_from: contact@abc.com
    mail_from_name: contact@abc.com
    mail_smtp_secure: 'ssl'
    mail_port: 465

#services.yml
services:
    app.php_mailer:
        class: AppBundle\Services\PHPMailerService
        arguments: ['@assetic.parameter_bag'] #here one could have other services to be injected
        public: true

# AppBundle\Services\PHPMailerService.php
...
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
...
class PHPMailerService
{
    private $parameterBag;
    private $mailAdmin;
    private $mailHost;
    private $mailUsername;
    private $mailPassword;
    private $mailFrom;
    private $mailFromName;
    private $mailSMTPSecure;
    private $mailPort;
}
public function __construct(ParameterBag $parameterBag)
{
    $this->parameterBag = $parameterBag;

    $this->mailAdmin      = $this->parameterBag->get('mail_admin');
    $this->mailHost       = $this->parameterBag->get('mail_host');
    $this->mailUsername   = $this->parameterBag->get('mail_username');
    $this->mailPassword   = $this->parameterBag->get('mail_password');
    $this->mailFrom       = $this->parameterBag->get('mail_from');
    $this->mailFromName   = $this->parameterBag->get('mail_from_name');
    $this->mailSMTPSecure = $this->parameterBag->get('mail_smtp_secure');
    $this->mailPort       = $this->parameterBag->get('mail_port');
}
public function sendEmail()
{
    //...
}

我认为这是一个更好的方法。

于 2018-10-17T20:44:31.957 回答
-2

在 symfony 4 中,我们可以通过依赖注入的方式访问参数:

服务:

   use Symfony\Component\DependencyInjection\ContainerInterface as Container;

   MyServices {

         protected $container;
         protected $path;

         public function __construct(Container $container)
         {
             $this->container = $container;
             $this->path = $this->container->getParameter('upload_directory');
         }
    }

参数.yml:

parameters:
     upload_directory: '%kernel.project_dir%/public/uploads'
于 2019-05-22T00:27:08.357 回答