Из моих контроллеров я обращаюсь к параметрам приложения (в /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%
или что-то подобное? Как мне получить доступ к моим параметрам приложения из службы?
Этот вопрос кажется таким же, но мой на самом деле отвечает на него (параметры с контроллера), я говорю о доступе от службы.
Вы можете передать параметры своей службе так же, как и другие сервисы, указав их в определении своей службы. Например, в YAML:
services:
my_service:
class: My\Bundle\Service\MyService
arguments: [%my_param1%, %my_param2%]
где %my_param1%
и т.д. соответствует параметру с именем my_param1
. Тогда ваш конструктор класса обслуживания может быть следующим:
public function __construct($myParam1, $myParam2)
{
// ...
}
Вместо того, чтобы сопоставлять необходимые параметры один за другим, почему бы вам не позволить вашему сервису напрямую обращаться к контейнеру? При этом вам не нужно обновлять свое сопоставление, если добавлены новые параметры (которые относятся к вашей службе).
Для этого:
Внесите следующие изменения в класс обслуживания
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
С 2017 года и Symfony 3.4 существует намного более чистый способ - легко настроить и использовать.
Вместо того, чтобы использовать анти-шаблон контейнера и сервиса/параметра, вы можете передавать параметры в класс через конструктор. Не беспокойтесь, это не трудоемкая работа, а настройка времени и забыть.
Как настроить его в 2 шага?
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"
}
}
Если вы используете более старый подход, вы можете автоматизировать его с помощью ректора.
Это называется инсталляцией конструктора по методу локализации сервисов.
Чтобы узнать больше об этом, проверьте мое сообщение. Как получить параметр в Symfony Controller "Чистый путь".
(Он протестирован, и я обновляю его для новой версии Symfony (5, 6...)).
Как решение некоторых из упомянутых проблем, я определяю параметр массива, а затем вставляю его. Добавление нового параметра позже просто требует добавления к массиву параметров без каких-либо изменений в аргументы или конструкцию 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 3.4 здесь.
После некоторых исследований я не думаю, что передавать параметры классу/службе через конструктор, это всегда хорошая идея. Представьте себе, если вам нужно передать контроллеру/службе еще несколько параметров, чем 2 или 3. Что тогда? Было бы смешно проходить, допустим, до 10 параметров.
Вместо этого используйте класс ParameterBag
как зависимость, объявляя службу в yml, а затем используйте столько параметров, сколько хотите.
Конкретный пример, скажем, у вас есть служба почтовой рассылки, такая как PHPMailer, и вы хотите иметь параметры подключения PHPMailer в файле paramters.yml
:
#parameters.yml
parameters:
mail_admin: [email protected]
mail_host: mail.abc.com
mail_username: [email protected]
mail_password: pass
mail_from: [email protected]
mail_from_name: [email protected]
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()
{
//...
}
Я думаю, что это лучший способ.