program tip

서비스에서 애플리케이션 매개 변수에 액세스하는 방법은 무엇입니까?

radiobox 2020. 11. 7. 09:12
반응형

서비스에서 애플리케이션 매개 변수에 액세스하는 방법은 무엇입니까?


내 컨트롤러에서 나는 응용 프로그램 매개 변수 (에서와 액세스 /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%

또는 비슷한 것? 서비스에서 내 애플리케이션 매개 변수에 어떻게 액세스해야합니까?


이 질문 은 똑같은 것처럼 보이지만 실제로 대답합니다 (컨트롤러의 매개 변수), 서비스에서 액세스하는 것에 대해 이야기하고 있습니다.


서비스 정의에서 매개 변수를 지정하여 다른 서비스를 삽입하는 것과 동일한 방식으로 서비스에 매개 변수를 전달할 수 있습니다. 예를 들어 YAML에서 :

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

여기서 %my_param1%etc는라는 매개 변수에 해당합니다 my_param1. 그러면 서비스 클래스 생성자가 다음과 같을 수 있습니다.

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

클린 웨이 2018

2017 년과 Symfony 3.4 이후 훨씬 더 깔끔한 방법이 있습니다. 설정과 사용이 쉽습니다.

컨테이너 및 서비스 / 매개 변수 로케이터 안티 패턴을 사용하는 대신 constructor를 통해 매개 변수를 클래스에 전달할 수 있습니다 . 걱정하지 마세요. 시간이 많이 걸리는 작업이 아니라 한 번 설정하고 접근을 잊어 버립니다 .

2 단계로 설정하는 방법은 무엇입니까?

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 ...)에 대해 계속 업데이트합니다.)


필요한 매개 변수를 하나씩 매핑하는 대신 서비스가 컨테이너에 직접 액세스하도록 허용하지 않는 이유는 무엇입니까? 이렇게하면 서비스와 관련된 새 매개 변수가 추가 된 경우 매핑을 업데이트 할 필요가 없습니다.

그렇게하려면 :

서비스 클래스를 다음과 같이 변경하십시오.

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

언급 된 몇 가지 문제에 대한 해결책으로 배열 매개 변수를 정의한 다음 삽입합니다. 나중에 새 매개 변수를 추가하려면 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;
    // ...
}

심포니 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 .


함께 심포니 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


심포니 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'

여기에 Symfony 3.4가 있습니다.

After some researches, I don't think passing parameters to a class/service via it's constructor, is always a good idea. Imagine if you need to pass to a controller/service some more parameters than 2 or 3. What then? Would be ridiculous to pass, let's say, up to 10 parameters.

Instead, use the ParameterBag class as a dependency, when declaring the service in yml, and then use as many parameters as you wish.

A concrete example, let's say you have a mailer service, like PHPMailer, and you want to have the PHPMailer connection parameters in the paramters.yml file:

#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()
{
    //...
}

I think this is a better way.

참고URL : https://stackoverflow.com/questions/11209529/how-to-access-an-application-parameters-from-a-service

반응형