Depuis mes contrôleurs, j’accède aux paramètres de l’application (ceux de /app/config
) Avec
$this->container->getParameter('my_param')
Mais je ne sais pas comment y accéder depuis un service (j'imagine que ma classe de service n'est pas censée s'étendre Symfony\Bundle\FrameworkBundle\Controller\Controller
).
Devrais-je mapper les paramètres nécessaires dans mon enregistrement de service comme ceci:
#src/Me/MyBundle/Service/my_service/service.yml
parameters:
my_param1: %my_param1%
my_param2: %my_param2%
my_param3: %my_param3%
ou quelque chose de similaire? Comment dois-je accéder aux paramètres de mon application depuis un service?
Cette question semble être la même chose mais la mienne y répond (paramètres d'un contrôleur), je parle d'accès depuis un service.
Vous pouvez transmettre des paramètres à votre service de la même manière que vous injectez d'autres services, en les spécifiant dans votre définition de service. Par exemple, en YAML:
services:
my_service:
class: My\Bundle\Service\MyService
arguments: [%my_param1%, %my_param2%]
où le %my_param1%
etc correspond à un paramètre nommé my_param1
. Votre constructeur de classe de service pourrait alors être:
public function __construct($myParam1, $myParam2)
{
// ...
}
Depuis 2017 et Symfony 3.4 , il existe un moyen beaucoup plus propre - facile à installer et à utiliser.
Au lieu d'utiliser l'anti-modèle de conteneur et de localisateur de service/paramètre, vous pouvez transmettre des paramètres à class via son constructeur . Ne vous inquiétez pas, ce n'est pas un travail qui demande du temps, mais plutôt installer une fois et oublier.
Comment le configurer en 2 étapes?
config.yml
# 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: ..
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"
}
}
Si vous utilisez une approche plus ancienne, vous pouvez l’automatiser avec Rector .
Cette approche s'appelle l'injection du constructeur sur le localisateur de services .
Pour en savoir plus à ce sujet, consultez mon article Comment obtenir les paramètres dans le contrôleur Symfony de manière propre .
(Il a été testé et je le garde à jour pour la nouvelle version majeure de Symfony (5, 6 ...)).
Au lieu de mapper les paramètres nécessaires un par un, pourquoi ne pas autoriser votre service à accéder directement au conteneur? Pour ce faire, vous n'avez pas besoin de mettre à jour votre mappage si de nouveaux paramètres sont ajoutés (relatifs à votre service).
Faire cela:
Apportez les modifications suivantes à votre classe de service
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
}
}
Ajoutez @service_container comme "arguments" dans votre service.yml
services:
my_service_id:
class: ...\MyServiceClass
arguments: ["@service_container"] // <- Add this
Pour résoudre certains des problèmes mentionnés, je définis un paramètre de tableau, puis je l’injecte. L'ajout ultérieur d'un nouveau paramètre nécessite simplement l'ajout d'un tableau de paramètres sans aucune modification des arguments ou de la construction service_container.
Donc, prolongeant la réponse @richsage:
paramètres.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%]
Puis accès en classe
public function __construct($params)
{
$this->param1 = array_key_exists('param_name_1',$params)
? $params['param_name_1'] : null;
// ...
}
Il y a un nouveau moyen très propre de le réaliser depuis symfony 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');
...
}
}
source: https://symfony.com/blog/new-in-symfony-4-1-getting-container-parameters-as-a-service .
Avec Symfony 4.1 la solution est assez simple.
Voici un extrait du message original:
// 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');
// ...
}
}
Lien vers le message d'origine: https://symfony.com/blog/new-in-symfony-4-1-getting-container-parameters-as-a-service
Dans symfony 4, nous pouvons accéder aux paramètres au moyen d’une injection de dépendance:
Prestations de service:
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'