Из своих контроллеров я получаю доступ к параметрам приложения (тем, что есть /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%
или что-то подобное? Как мне получить доступ к параметрам моего приложения из службы?
Этот вопрос кажется таким же, но мой на самом деле отвечает на него (параметры от контроллера), я говорю о доступе из службы.
$this->getParameter()
.Ответы:
Вы можете передавать параметры своей службе так же, как и другие службы, указав их в определении службы. Например, в YAML:
services: my_service: class: My\Bundle\Service\MyService arguments: [%my_param1%, %my_param2%]
где
%my_param1%
etc соответствует параметру с именемmy_param1
. Тогда ваш конструктор класса обслуживания может быть:public function __construct($myParam1, $myParam2) { // ... }
источник
my_param1
?Чистый путь 2018
Начиная с 2018 и Symfony 3.4, существует гораздо более чистый способ - простой в настройке и использовании.
Вместо использования контейнера и антипаттерна локатора службы / параметров вы можете передавать параметры классу через его конструктор . Не волнуйтесь, это не работа, требующая много времени, а скорее подход « один раз и забыл» .
Как настроить за 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 .
Читать больше
Это называется подходом с внедрением конструктора поверх локатора сервисов .
Чтобы узнать больше об этом, прочтите мой пост Как получить параметр в контроллере Symfony в чистом виде .
(Он протестирован, и я постоянно обновляю его до новой основной версии Symfony (5, 6 ...)).
источник
Вместо того, чтобы сопоставлять необходимые параметры один за другим, почему бы не разрешить вашей службе напрямую обращаться к контейнеру? При этом вам не нужно обновлять отображение, если добавлены новые параметры (которые относятся к вашей службе).
Для этого:
Внесите следующие изменения в свой класс обслуживания
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 } }
Добавьте @service_container в качестве «аргументов» в свой services.yml
services: my_service_id: class: ...\MyServiceClass arguments: ["@service_container"] // <- Add this
источник
Начиная с 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'); ... } }
источник: https://symfony.com/blog/new-in-symfony-4-1-getting-container-parameters-as-a-service .
источник
В качестве решения некоторых из упомянутых проблем я определяю параметр массива, а затем вставляю его. Для добавления нового параметра позже просто требуется добавление в массив параметров без каких-либо изменений аргументов или конструкции 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; // ... }
источник
С Symfony 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
источник
@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
в вашем файле класса обслуживания systemCheck.php создайте конструктор следующим образом
private $toBechecked; public function __construct($toBechecked) { $this->toBechecked = $toBechecked; } public function echoSomething() { echo $this->toBechecked; }
Готово.
источник
Symfony 3.4 здесь.
После некоторых исследований я не думаю, что передача параметров классу / сервису через его конструктор всегда является хорошей идеей. Представьте, что вам нужно передать контроллеру / службе еще несколько параметров, чем 2 или 3. Что тогда? Было бы смешно передавать, скажем, до 10 параметров.
Вместо этого используйте
ParameterBag
класс как зависимость при объявлении службы в yml, а затем используйте столько параметров, сколько захотите.Конкретный пример, допустим, у вас есть почтовая служба, такая как PHPMailer, и вы хотите, чтобы параметры подключения PHPMailer были в
paramters.yml
файле:#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() { //... }
Я думаю, это лучший способ.
источник
В symfony 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'
источник