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


81

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

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


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



내 질문은 사실이 하나 (컨트롤러에서 매개 변수), 여기 서비스로부터 접근에 대해서 이야기하고 답변
— 피에르 드 LESPINAY을

내가 당신을 이해하는지 잘 모르겠습니다. 중복에 동의하십니까? 컨트롤러는 오늘날 Symfony의 서비스입니다.
— Tomáš Votruba 2018 년

나는 중복에 동의하지 않는다. 다른 질문은 특히 $this->getParameter().
— Pierre de LESPINAY

사실입니다. 동의합니다. 그리고 그것은 여전히 ​​가능합니다. 컨테이너가 어디에 든 주입되지 않고 생성자 주입으로 이동하는 추세도 있습니다. PSR-4 서비스 자동 검색 및 매개 변수 바인딩 ( symfony.com/blog/new-in-symfony-3-4-local-service-binding) 덕분 에 깔끔하고 작업 시간이 훨씬 짧습니다.
— Tomáš Votruba

답변:


123

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

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

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

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

매개 변수가 존재하지 않는 경우 처리하는 방법이 있습니까? 심포니 예외 IOC 대신에.
— Mohammed Yassine CHABLI

의 가치는 my_param1어디에서 왔습니까?
— Sliq

@Sliq, 당신은 parameters.yml에서 정의합니다
— Graph

35

클린 웨이 2018

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


1
OP가 모든 서비스에 매개 변수를 삽입하고 SF3 컨트롤러에서 기본적으로 자동 연결이 활성화되어 있으므로 코드 예제로 컨트롤러 클래스 이외의 것을 취했을 것입니다
— alpadev

귀하의 의견에 감사드립니다. 위의 구성은 모든 서비스, 컨트롤러, 저장소 또는 자체 서비스에서 작동합니다. 다른 점이 없다.
— Tomáš Votruba 2018 년

18

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

그렇게하려면 :

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

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

1
정확히 내가 찾던 것, 그것이 내가 의존성 주입을 좋아하는 이유입니다 :)
— klimpond

44
-1. 컨테이너를 전체적으로 전달하면 종속성 주입의 목적이 무효화됩니다. 클래스는 전체 컨테이너가 아니라 실제로 작동하는 데 필요한 것만 제공해야합니다.
— richsage 2015

@richsage, 비슷한 결과를 얻을 수있는 대안이 있습니까? 따라서 서비스 선언이 각 매개 변수에 대해 업데이트되지 않습니까? 이것은 또한 매개 변수를 하나씩 주입하는 것보다 약간 깔끔해 보입니다.
— Batandwa

1
전체 컨테이너를 서비스에 전달하는 것은 정말 나쁜 생각입니다. @richsage가 말했듯이 의존성 주입 목적에 맞지 않습니다. 당신은 의존성 주입 후, 그나마 사용 Symfony2 : 사용하려는 해달라고하면
— tersakyan

2
@tersakyan,하지만 컨트롤러는 어떨까요? 기본적으로 모든 컨트롤러는 컨트롤러에 액세스 할 수 있습니다. 그렇다면 컨트롤러도 사용하지 말아야할까요? :)
— Alex Zheka

9

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

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

이 댓글을 쓰는 시점에서, 불행하게도, PARAMS의 중첩하는 심포니에 불가능 문서를 참조하십시오 symfony.com/doc/current/service_container/...
— 토마스 Votruba

5

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


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

끝난.


더 설명해 주시겠습니까? 다른 솔루션에서 정확히 작동하지 않은 것은 무엇입니까? 제공된 오류 메시지가 있습니까?
— Nico Haase

그는 생성자에서 ParameterBagInterface $ params를 사용했지만 services.yaml에서 매개 변수 구성을 완전히 활용하기 위해 종속성 주입을 사용했습니다.
— Dung

더 설명해 주시겠습니까? richsage에 의한 대답은 그 ParameterBagInterface하지만, 매개 변수의 목록을 포함하지 않는 것은 당신의 코드와 같이 주입한다
— 니코 하세에게

내 대답은 2012 년에 게시되었는데, 생태계는 Symfony 2뿐이었습니다. 저는 더 이상 Symfony를 사용하지 않으므로 후속 버전에 대해 업데이트하지 않았습니다.
— richsage

-1

여기에 Symfony 3.4가 있습니다.

몇 가지 연구 후에는 생성자를 통해 클래스 / 서비스에 매개 변수를 전달하는 것이 항상 좋은 생각이라고 생각하지 않습니다. 컨트롤러 / 서비스에 2 또는 3보다 더 많은 매개 변수를 전달해야한다고 상상해보십시오. 그러면 어떻게됩니까? 최대 10 개의 매개 변수를 전달하는 것은 말도 안되는 일입니다.

대신 ParameterBagyml에서 서비스를 선언 할 때 클래스를 종속성으로 사용하고 원하는만큼 많은 매개 변수를 사용하십시오.

구체적인 예를 들어, 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()
{
    //...
}

이것이 더 나은 방법이라고 생각합니다.


-1

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

제공된 코드는 DI를 제대로 사용하지 않습니다. 전체 컨테이너를 주입하는 것은 실제 종속성을 숨기므로 잘못된 스타일로 간주됩니다.
— Nico Haase

나는 당신이 개념을 착각하고 있다고 생각합니다. 예제에서는 일반적인 경우 만 보여줍니다. 의심스러운 경우 투표하기 전에 공식 심포니 문서를 참조하십시오. symfony.com/doc/current/components/dependency_injection.html
— shades3002

더 설명해 주시겠습니까? 링크 된 문서는 컨테이너 주입이 좋은 생각이 아니라고 명시하고 있으며 이러한 유형의 주입을 사용하는 예를 보여주지 않습니다. 분명히 전체 컨테이너를 주입 할 때 종속성을 주입하지 않습니다
— Nico Haase
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.