Подтвердить что ты не робот

Как получить доступ к параметрам приложения из службы?

Из моих контроллеров я обращаюсь к параметрам приложения (в /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%

или что-то подобное? Как мне получить доступ к моим параметрам приложения из службы?


Этот вопрос кажется таким же, но мой на самом деле отвечает на него (параметры с контроллера), я говорю о доступе от службы.

4b9b3361

Ответ 1

Вы можете передать параметры своей службе так же, как и другие сервисы, указав их в определении своей службы. Например, в YAML:

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

где %my_param1% и т.д. соответствует параметру с именем my_param1. Тогда ваш конструктор класса обслуживания может быть следующим:

public function __construct($myParam1, $myParam2)
{
    // ...
}

Ответ 2

Вместо того, чтобы сопоставлять необходимые параметры один за другим, почему бы вам не позволить вашему сервису напрямую обращаться к контейнеру? При этом вам не нужно обновлять свое сопоставление, если добавлены новые параметры (которые относятся к вашей службе).

Для этого:

Внесите следующие изменения в класс обслуживания

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
    }
}

Добавьте @service_container в качестве "аргументов" в ваших services.yml

services:
  my_service_id:
    class: ...\MyServiceClass
    arguments: ["@service_container"]  // <- Add this

Ответ 3

Чистый путь 2018

С 2017 года и Symfony 3.4 существует намного более чистый способ - легко настроить и использовать.

Вместо того, чтобы использовать анти-шаблон контейнера и сервиса/параметра, вы можете передавать параметры в класс через конструктор. Не беспокойтесь, это не трудоемкая работа, а настройка времени и забыть.

Как настроить его в 2 шага?

1. config.yml

# 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"
    }
}

Мгновенный апгрейд готов!

Если вы используете более старый подход, вы можете автоматизировать его с помощью ректора.

Прочитайте больше

Это называется инсталляцией конструктора по методу локализации сервисов.

Чтобы узнать больше об этом, проверьте мое сообщение. Как получить параметр в Symfony Controller "Чистый путь".

(Он протестирован, и я обновляю его для новой версии Symfony (5, 6...)).

Ответ 4

Как решение некоторых из упомянутых проблем, я определяю параметр массива, а затем вставляю его. Добавление нового параметра позже просто требует добавления к массиву параметров без каких-либо изменений в аргументы или конструкцию service_container.

Итак, продолжаем отвечать на @richsage:

parameters.yml

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

services.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;
    // ...
}

Ответ 5

Начиная с 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.

Ответ 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

Ответ 7

В 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');
         }
    }

parameters.yml:

parameters:
     upload_directory: '%kernel.project_dir%/public/uploads'

Ответ 8

Symfony 3.4 здесь.

После некоторых исследований я не думаю, что передавать параметры классу/службе через конструктор, это всегда хорошая идея. Представьте себе, если вам нужно передать контроллеру/службе еще несколько параметров, чем 2 или 3. Что тогда? Было бы смешно проходить, допустим, до 10 параметров.

Вместо этого используйте класс ParameterBag как зависимость, объявляя службу в yml, а затем используйте столько параметров, сколько хотите.

Конкретный пример, скажем, у вас есть служба почтовой рассылки, такая как PHPMailer, и вы хотите иметь параметры подключения PHPMailer в файле paramters.yml:

#parameters.yml
parameters:
    mail_admin: [email protected]
    mail_host: mail.abc.com
    mail_username: [email protected]
    mail_password: pass
    mail_from: [email protected]
    mail_from_name: [email protected]
    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()
{
    //...
}

Я думаю, что это лучший способ.