Symfony2: Как ввести ВСЕ параметры в службу?
Как я могу добавить ВСЕ параметры в службу?
Я знаю, что могу сделать: arguments: [%some.key%]
, который передаст parameters: some.key: "value"
в службу __construct.
Мой вопрос заключается в том, как вводить все, что находится под parameters
в службе?
Мне нужно это, чтобы создать сервис диспетчера навигации, где различные меню/навигационные/панировочные сухари должны создаваться в соответствии с разными настройками через все записи конфигурации.
Я знаю, что я мог бы вводить столько параметров, сколько хочу, но поскольку он будет использовать несколько из них и со временем будет расширяться, я думаю, что лучше всего передать все в самом начале.
Другой подход может заключаться в том, что если бы я мог получить параметры внутри службы, как это можно сделать в контроллере $this -> container -> getParameter('some.key');
, но я думаю, что это было бы против идеи Injection Dependency?
Спасибо заранее!
Ответы
Ответ 1
Примечание. Я знаю, что это решение не является BEST с точки зрения дизайна, но оно выполняет эту работу, поэтому, пожалуйста, избегайте голосования.
Вы можете вставить объект \AppKernel, а затем получить доступ ко всем параметрам, например:
config.yml:
my_service:
class: MyService\Class
arguments: [@kernel]
И внутри MyService\Class
:
public function __construct($kernel)
{
$this->parameter = $kernel->getContainer()->getParameter('some.key');
// or to get all:
$this->parameters = $kernel->getContainer()->getParameterBag()->all();
}
Ответ 2
Не рекомендуется применять весь контейнер в службу. Также, если у вас есть много параметров, которые вам нужны для вашей службы, нехорошо вставлять их все по одному в вашу службу. Вместо этого я использую этот метод:
1) В config.yml я определяю параметры, которые мне нужны для моего сервиса, например:
parameters:
product.shoppingServiceParams:
parameter1: 'Some data'
parameter2: 'some data'
parameter3: 'some data'
parameter4: 'some data'
parameter5: 'some data'
parameter6: 'some data'
2) Затем я вставляю этот параметр корня в мою службу, например:
services:
product.shoppingService:
class: Saman\ProductBundle\Service\Shopping
arguments: [@translator.default, %product.shoppingServiceParams%]
3) В моей службе я могу получить доступ к этим параметрам, например:
namespace Saman\ProductBundle\Service;
use Symfony\Bundle\FrameworkBundle\Translation\Translator;
class Shopping
{
protected $translator;
protected $paramaters;
public function __construct(
Translator $translator,
$parameters
)
{
$this->translator = $translator;
$this->parameters = $parameters;
}
public function dummyFunction()
{
var_dump($this->getParameter('parameter2'));
}
private function getParameter($key, $default = null)
{
if (isset($this->parameters[$key])) {
return $this->parameters[$key];
}
return $default;
}
}
4) Я также могу установить разные значения для разных сред. Например, в config_dev.yml
parameters:
product.shoppingServiceParams:
parameter1: 'Some data for dev'
parameter2: 'some data for dev'
parameter3: 'some data for dev'
parameter4: 'some data for dev'
parameter5: 'some data for dev'
parameter6: 'some data'
Ответ 3
Я считаю, что вы должны передавать параметры по отдельности. Я думаю, что это было сделано по дизайну, поэтому ваш класс обслуживания не зависит от AppKernel. Таким образом, вы можете повторно использовать свой класс обслуживания вне вашего проекта Symfony. Что-то, что полезно при тестировании вашего класса обслуживания.
Ответ 4
AppKernel будет работать, но это будет еще хуже (с точки зрения перспективы), чем инъекция контейнера, поскольку в нем есть еще больше вещей.
Вы можете посмотреть xxxProjectContainer в вашем каталоге кеша. Оказывается, что отсортированные параметры скомпилированы непосредственно в него как большой массив. Таким образом, вы можете ввести контейнер, а затем просто вытащить параметры. Нарушает букву закона, но не дух закона.
class MyService {
public function __construct($container) {
$this->parameters = $container->parameters; // Then discard container to preclude temptation
И просто вроде возиться, я обнаружил, что могу это сделать:
$container = new \arbiterDevDebugProjectContainer();
echo 'Parameter Count ' . count($container->parameters) . "\n";
Итак, вы можете создать сервис, в котором в основном была пустая копия главного контейнера, и вводить его только для получения параметров. Примите во внимание флагов dev/debug, которые могут быть больны.
Я подозреваю, что вы также можете сделать это с помощью компилятора, но никогда не пробовали.
Ответ 5
Другой вариант, как легко получить параметры - вы можете просто установить ParameterBag в свою службу. Вы можете сделать это по-разному - через аргументы или с помощью методов набора. Позвольте мне показать мой пример с помощью метода set.
Итак, в services.yml вы должны добавить что-то вроде:
my_service:
class: MyService\Class
calls:
- [setParameterBag, ["@=service('kernel').getContainer().getParameterBag()"]]
и в классе MyService\Class просто добавьте использование:
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
и создайте 2 метода:
/**
* Set ParameterBag for repository
*
* @param ParameterBagInterface $params
*/
public function setParameterBag(ParameterBagInterface $params)
{
$this->parameterBag = $params;
}
/**
* Get parameter from ParameterBag
*
* @param string $name
* @return mixed
*/
public function getParameter($name)
{
return $this->parameterBag->get($name);
}
и теперь вы можете использовать его в классе:
$this->getParameter('your_parameter_name');
Ответ 6
Предложение определить службу в services.yml, которая будет вводить параметрBag и разрешать доступ к любому из ваших параметров
service.container_parameters:
public: false
class: stdClass
factory_service: service_container
factory_method: getParameterBag
Внесите свою услугу, и вы можете получить свой параметр, используя ниже
$parameterService->get('some.key');
Ответ 7
В качестве альтернативного подхода можно было бы фактически ввести параметры приложения в вашу службу через Container- > getParameterBag в комплекте с расширением DI
<?php
namespace Vendor\ProjectBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;
/**
* This is the class that loads and manages your bundle configuration
*
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html}
*/
class VendorProjectExtension extends Extension {
/**
* {@inheritDoc}
*/
public function load(array $configs, ContainerBuilder $container) {
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$loader->load('services.yml');
/** set params for services */
$container->getDefinition('my.managed.service.one')
->addMethodCall('setContainerParams', array($container->getParameterBag()->all()));
$container->getDefinition('my.managed.service.etc')
->addMethodCall('setContainerParams', array($container->getParameterBag()->all()));
}
}
Обратите внимание, что мы не можем напрямую вводить объект ParameterBag, вызывая его:
[Symfony\Component\внедрение зависимости \Exception\RuntimeException]
Невозможно сбросить контейнер службы, если параметр является объектом или ресурс.
Протестировано по версии Symfony 2.3.4