Desde mis controladores, accedo a los parámetros de la aplicación (aquellos en /app/config
) con
$this->container->getParameter('my_param')
Pero no sé cómo acceder a él desde un servicio (imagino que no se supone que mi clase de servicio se extienda Symfony\Bundle\FrameworkBundle\Controller\Controller
).
¿Debería asignar los parámetros necesarios en el registro de mi servicio de esta manera:
#src/Me/MyBundle/Service/my_service/service.yml
parameters:
my_param1: %my_param1%
my_param2: %my_param2%
my_param3: %my_param3%
¿o algo similar? ¿Cómo debo acceder a los parámetros de mi aplicación desde un servicio?
Esta pregunta parece la misma, pero la mía en realidad la responde (parámetros de un controlador), estoy hablando de acceder desde un servicio.
$this->getParameter()
.Respuestas:
Puede pasar parámetros a su servicio de la misma manera que inyecta otros servicios, especificándolos en su definición de servicio. Por ejemplo, en YAML:
services: my_service: class: My\Bundle\Service\MyService arguments: [%my_param1%, %my_param2%]
donde
%my_param1%
etc corresponde a un parámetro llamadomy_param1
. Entonces su constructor de clase de servicio podría ser:public function __construct($myParam1, $myParam2) { // ... }
fuente
my_param1
viene el valor de ?El camino limpio 2018
Desde 2018 y Symfony 3.4 hay una forma mucho más limpia: fácil de configurar y usar.
En lugar de utilizar un anti-patrón de contenedor y localizador de servicios / parámetros, puede pasar parámetros a la clase a través de su constructor . No se preocupe, no se trata de un trabajo que requiera tiempo, sino de configurar una vez y olvidar el enfoque.
¿Cómo configurarlo en 2 pasos?
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. Cualquiera
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" } }
¡Actualización instantánea lista!
En caso de que utilice un enfoque anterior, puede automatizarlo con Rector .
Lee mas
Esto se denomina enfoque de localizador de inyección de constructor sobre servicios .
Para leer más sobre esto, consulte mi publicación Cómo obtener parámetros en el controlador Symfony de forma limpia .
(Está probado y lo mantengo actualizado para la nueva versión principal de Symfony (5, 6 ...)).
fuente
En lugar de mapear los parámetros necesarios uno por uno, ¿por qué no permitir que su servicio acceda al contenedor directamente? Al hacerlo, no tiene que actualizar su mapeo si se agregan nuevos parámetros (que se relacionan con su servicio).
Para hacerlo:
Realice los siguientes cambios en su clase de servicio
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 } }
Agregue @service_container como "argumentos" en su services.yml
services: my_service_id: class: ...\MyServiceClass arguments: ["@service_container"] // <- Add this
fuente
Hay una nueva forma muy limpia de lograrlo desde 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'); ... } }
fuente: https://symfony.com/blog/new-in-symfony-4-1-getting-container-parameters-as-a-service .
fuente
Como solución a algunos de los problemas mencionados, defino un parámetro de matriz y luego lo inyecto. Agregar un nuevo parámetro más tarde solo requiere agregarlo a la matriz de parámetros sin ningún cambio en los argumentos o la construcción de service_container.
Entonces, extendiendo la respuesta de @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%]
Luego acceda al interior de la clase
public function __construct($params) { $this->param1 = array_key_exists('param_name_1',$params) ? $params['param_name_1'] : null; // ... }
fuente
Con Symfony 4.1 la solución es bastante simple.
Aquí hay un fragmento de la publicación 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'); // ... } }
Enlace a la publicación original: https://symfony.com/blog/new-in-symfony-4-1-getting-container-parameters-as-a-service
fuente
@richsage es correcto (para Symfony 3.?) pero no funcionó para mi Symfony 4.x. Así que aquí está Symfony 4.
en el archivo services.yaml
parameters: param1: 'hello' Services: App\Service\routineCheck: arguments: $toBechecked: '%param1%' # argument must match in class constructor
en su archivo de clase de servicio rutinaCheck.php, haga el constructor así
private $toBechecked; public function __construct($toBechecked) { $this->toBechecked = $toBechecked; } public function echoSomething() { echo $this->toBechecked; }
Hecho.
fuente
Symfony 3.4 aquí.
Después de algunas investigaciones, no creo que pasar parámetros a una clase / servicio a través de su constructor sea siempre una buena idea. Imagínese si necesita pasar a un controlador / servicio algunos parámetros más que 2 o 3. ¿Entonces qué? Sería ridículo pasar, digamos, hasta 10 parámetros.
En su lugar, use la
ParameterBag
clase como una dependencia, cuando declare el servicio en yml, y luego use tantos parámetros como desee.Un ejemplo concreto, digamos que tiene un servicio de correo, como PHPMailer, y desea tener los parámetros de conexión de PHPMailer en el
paramters.yml
archivo:#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() { //... }
Creo que esta es una forma mejor.
fuente
En Symfony 4, podemos acceder a los parámetros mediante inyección de dependencias:
Servicios:
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'); } }
parámetros.yml:
parameters: upload_directory: '%kernel.project_dir%/public/uploads'
fuente