Über meine Controller greife ich mit auf die Anwendungsparameter (die in /app/config
) zu
$this->container->getParameter('my_param')
Ich weiß jedoch nicht, wie ich von einem Dienst aus darauf zugreifen soll (ich kann mir vorstellen, dass meine Dienstklasse nicht erweitert werden soll Symfony\Bundle\FrameworkBundle\Controller\Controller
).
Sollte ich die erforderlichen Parameter wie folgt in meine Serviceregistrierung einordnen:
#src/Me/MyBundle/Service/my_service/service.yml
parameters:
my_param1: %my_param1%
my_param2: %my_param2%
my_param3: %my_param3%
oder etwas ähnliches? Wie soll ich von einem Dienst aus auf meine Anwendungsparameter zugreifen?
Diese Frage scheint dieselbe zu sein, aber meine beantwortet sie tatsächlich (Parameter von einem Controller). Ich spreche über den Zugriff von einem Dienst aus.
$this->getParameter()
.Antworten:
Sie können Parameter auf dieselbe Weise an Ihren Dienst übergeben, wie Sie andere Dienste einfügen, indem Sie sie in Ihrer Dienstdefinition angeben. Zum Beispiel in YAML:
services: my_service: class: My\Bundle\Service\MyService arguments: [%my_param1%, %my_param2%]
wobei das
%my_param1%
etc einem Parameter mit dem Namen entsprichtmy_param1
. Dann könnte Ihr Serviceklassenkonstruktor sein:public function __construct($myParam1, $myParam2) { // ... }
quelle
my_param1
von?Der saubere Weg 2018
Seit 2017 und Symfony 3.4 gibt es viel sauberere Wege - einfach einzurichten und zu verwenden.
Anstatt das Anti-Pattern für Container und Service / Parameter Locator zu verwenden, können Sie Parameter über den Konstruktor an die Klasse übergeben . Keine Sorge, es ist keine zeitaufwändige Arbeit, sondern ein einmaliges Einrichten und Vergessen des Ansatzes.
Wie richte ich es in 2 Schritten ein?
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. Beliebig
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" } }
Sofortiges Upgrade bereit!
Wenn Sie einen älteren Ansatz verwenden, können Sie ihn mit Rector automatisieren .
Weiterlesen
Dies wird als Konstruktorinjektion über den Dienstlokalisierungsansatz bezeichnet .
Weitere Informationen hierzu finden Sie in meinem Beitrag So erhalten Sie Parameter in Symfony Controller auf saubere Weise .
(Es wurde getestet und ich halte es für die neue Symfony-Hauptversion (5, 6 ...) auf dem neuesten Stand.)
quelle
Warum sollten Sie Ihrem Dienst nicht erlauben, direkt auf den Container zuzugreifen, anstatt die benötigten Parameter einzeln zuzuordnen? Auf diese Weise müssen Sie Ihr Mapping nicht aktualisieren, wenn neue Parameter hinzugefügt werden (die sich auf Ihren Service beziehen).
Um dies zu tun:
Nehmen Sie die folgenden Änderungen an Ihrer Serviceklasse vor
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 } }
Fügen Sie @service_container als "Argumente" in Ihre services.yml ein
services: my_service_id: class: ...\MyServiceClass arguments: ["@service_container"] // <- Add this
quelle
Seit Symfony 4.1 gibt es einen sehr sauberen neuen Weg, dies zu erreichen
<?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'); ... } }
Quelle: https://symfony.com/blog/new-in-symfony-4-1-getting-container-parameters-as-a-service .
quelle
Als Lösung für einige der genannten Probleme definiere ich einen Array-Parameter und füge ihn dann ein. Das spätere Hinzufügen eines neuen Parameters erfordert lediglich das Hinzufügen zum Parameterarray, ohne dass die Argumente oder das Konstrukt von service_container geändert werden müssen.
Also auf @richsage Antwort erweitern:
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%]
Dann Zugriff innerhalb der Klasse
public function __construct($params) { $this->param1 = array_key_exists('param_name_1',$params) ? $params['param_name_1'] : null; // ... }
quelle
Mit Symfony 4.1 die Lösung recht einfach.
Hier ist ein Ausschnitt aus dem ursprünglichen Beitrag:
// 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 zum Originalbeitrag: https://symfony.com/blog/new-in-symfony-4-1-getting-container-parameters-as-a-service
quelle
@richsage ist korrekt (für Symfony 3.?), hat aber für mein Symfony 4.x nicht funktioniert. Also hier ist für Symfony 4.
in der Datei services.yaml
parameters: param1: 'hello' Services: App\Service\routineCheck: arguments: $toBechecked: '%param1%' # argument must match in class constructor
Führen Sie in Ihrer Serviceklasse die Datei RoutineCheck.php so aus
private $toBechecked; public function __construct($toBechecked) { $this->toBechecked = $toBechecked; } public function echoSomething() { echo $this->toBechecked; }
Getan.
quelle
Symfony 3.4 hier.
Nach einigen Recherchen halte ich es nicht für eine gute Idee, Parameter über den Konstruktor an eine Klasse / einen Dienst zu übergeben. Stellen Sie sich vor, Sie müssen mehr Parameter als 2 oder 3 an eine Steuerung / einen Dienst übergeben. Was dann? Es wäre lächerlich, bis zu 10 Parameter zu übergeben.
Verwenden Sie stattdessen die
ParameterBag
Klasse als Abhängigkeit, wenn Sie den Dienst in yml deklarieren, und verwenden Sie dann so viele Parameter, wie Sie möchten.Ein konkretes Beispiel: Nehmen wir an, Sie haben einen Mailer-Dienst wie PHPMailer und möchten die PHPMailer-Verbindungsparameter in der
paramters.yml
Datei haben:#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() { //... }
Ich denke, das ist ein besserer Weg.
quelle
In Symfony 4 können wir über die Abhängigkeitsinjektion auf die Parameter zugreifen:
Dienstleistungen:
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'
quelle