Z moich kontrolerów mam dostęp do parametrów aplikacji (tych w /app/config
) z
$this->container->getParameter('my_param')
Ale nie wiem, jak uzyskać do niego dostęp z usługi (wyobrażam sobie, że moja klasa usług nie powinna się rozszerzać Symfony\Bundle\FrameworkBundle\Controller\Controller
).
Czy powinienem zmapować potrzebne parametry do rejestracji mojej usługi w następujący sposób:
#src/Me/MyBundle/Service/my_service/service.yml
parameters:
my_param1: %my_param1%
my_param2: %my_param2%
my_param3: %my_param3%
czy coś podobnego? Jak mogę uzyskać dostęp do parametrów mojej aplikacji z usługi?
To pytanie wydaje się takie samo, ale moje faktycznie na nie odpowiada (parametry ze sterownika), mówię o dostępie z usługi.
$this->getParameter()
.Odpowiedzi:
Parametry można przekazywać do usługi w taki sam sposób, jak wstrzykujesz inne usługi, określając je w definicji usługi. Na przykład w YAML:
services: my_service: class: My\Bundle\Service\MyService arguments: [%my_param1%, %my_param2%]
gdzie
%my_param1%
etc odpowiada parametrowi o nazwiemy_param1
. Wtedy twój konstruktor klasy usług mógłby wyglądać następująco:public function __construct($myParam1, $myParam2) { // ... }
źródło
my_param1
bierze się wartość ?Czysta droga 2018
Od 2018 roku i Symfony 3.4 istnieje znacznie czystszy sposób - łatwy w konfiguracji i obsłudze.
Zamiast używać kontenera i anty-wzorca lokalizatora usługi / parametrów, możesz przekazać parametry do klasy za pośrednictwem jej konstruktora . Nie martw się, nie jest to czasochłonna praca, ale raczej konfiguracja raz i zapomnij .
Jak to ustawić w 2 krokach?
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. Dowolne
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" } }
Gotowe do natychmiastowej aktualizacji!
Jeśli korzystasz ze starszego podejścia, możesz je zautomatyzować za pomocą Rectora .
Czytaj więcej
Nazywa się to wstrzyknięciem konstruktora do lokalizatora usług podejściem .
Aby dowiedzieć się więcej na ten temat, zajrzyj do mojego postu Jak uzyskać parametry w kontrolerze Symfony w czysty sposób .
(Jest przetestowany i aktualizuję go pod kątem nowej głównej wersji Symfony (5, 6 ...)).
źródło
Zamiast mapować potrzebne parametry jeden po drugim, dlaczego nie pozwolić usłudze na bezpośredni dostęp do kontenera? W ten sposób nie musisz aktualizować mapowania, jeśli dodano nowe parametry (które dotyczą Twojej usługi).
Aby to zrobić:
Wprowadź następujące zmiany w klasie usługi
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 } }
Dodaj @service_container jako „argumenty” w swoim services.yml
services: my_service_id: class: ...\MyServiceClass arguments: ["@service_container"] // <- Add this
źródło
Od czasów symfony 4.1 jest nowy, bardzo czysty sposób na osiągnięcie tego celu
<?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'); ... } }
źródło: https://symfony.com/blog/new-in-symfony-4-1-getting-container-parameters-as-a-service .
źródło
Aby rozwiązać niektóre z wymienionych problemów, definiuję parametr tablicy, a następnie wstrzykuję go. Dodanie nowego parametru później wymaga jedynie dodania do tablicy parametrów bez zmiany argumentów lub konstrukcji service_container.
A więc rozszerzenie @richsage answer:
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%]
Następnie wejdź do klasy
public function __construct($params) { $this->param1 = array_key_exists('param_name_1',$params) ? $params['param_name_1'] : null; // ... }
źródło
Dzięki Symfony 4.1 rozwiązanie jest dość proste.
Oto fragment oryginalnego posta:
// 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'); // ... } }
Link do oryginalnego posta: https://symfony.com/blog/new-in-symfony-4-1-getting-container-parameters-as-a-service
źródło
@richsage jest poprawne (dla Symfony 3.?), ale nie działało z moim Symfony 4.x. A więc tutaj jest Symfony 4.
w pliku services.yaml
parameters: param1: 'hello' Services: App\Service\routineCheck: arguments: $toBechecked: '%param1%' # argument must match in class constructor
w pliku klasy usług routineCheck.php wykonaj taki konstruktor
private $toBechecked; public function __construct($toBechecked) { $this->toBechecked = $toBechecked; } public function echoSomething() { echo $this->toBechecked; }
Gotowe.
źródło
Symfony 3.4 tutaj.
Po kilku badaniach uważam, że przekazywanie parametrów do klasy / usługi za pośrednictwem jej konstruktora nie jest zawsze dobrym pomysłem. Wyobraź sobie, że musisz przekazać do kontrolera / usługi więcej parametrów niż 2 lub 3. Co wtedy? Byłoby śmieszne, gdybyśmy przekazali, powiedzmy, do 10 parametrów.
Zamiast tego użyj
ParameterBag
klasy jako zależności podczas deklarowania usługi w yml, a następnie użyj dowolnej liczby parametrów.Konkretny przykład, powiedzmy, że masz usługę pocztową, taką jak PHPMailer, i chcesz mieć parametry połączenia PHPMailer w
paramters.yml
pliku:#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() { //... }
Myślę, że to lepszy sposób.
źródło
W symfony 4 możemy uzyskać dostęp do parametrów poprzez wstrzyknięcie zależności:
Usługi:
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'
źródło