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


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.