Как я могу ввести ВСЕ параметры в службу?
Я знаю, что могу сделать: arguments: [%some.key%]
которые передадут parameters: some.key: "value"
для службы __construct.
Мой вопрос заключается в том, как вводить все, что находится под parameters
в сервисе?
Мне нужно это, чтобы создать службу диспетчера навигации, где различные меню / навигационные / панировочные сухари должны создаваться в соответствии с разными настройками через все записи конфигурации.
Я знаю, что я мог бы вводить столько параметров, сколько хочу, но поскольку он собирается использовать их и со временем будет расширяться, я думаю, что лучше всего передать все в самом начале.
Другим подходом могло бы быть, если бы я мог получить параметры внутри службы, как вы можете сделать в контроллере $this -> container -> getParameter('some.key');
, но я думаю, что это было бы против идеи инъекции зависимостей?
Заранее спасибо!
Примечание. Я знаю, что это решение не является 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(); }
Не рекомендуется применять весь контейнер в услугу. Также, если у вас есть много параметров, которые вам нужны для вашей службы, нехорошо вставлять их все по одному в вашу службу. Вместо этого я использую этот метод:
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'
Я считаю, что вы должны передавать параметры по отдельности. Я думаю, что это сделано таким образом, чтобы ваш класс обслуживания не зависел от AppKernel. Таким образом, вы можете повторно использовать свой класс обслуживания вне вашего проекта Symfony. Что-то, что полезно при тестировании вашего класса обслуживания.
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, которые могут быть больны.
Я подозреваю, что вы также можете сделать это с помощью компилятора, но никогда не пробовали.
Другой вариант, как легко получить параметры – вы можете просто установить 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');
Предложение определить службу в services.yml, которая будет вводить параметрBag и разрешать доступ к любому из ваших параметров
service.container_parameters: public: false class: stdClass factory_service: service_container factory_method: getParameterBag
Внесите свой сервис, и вы можете получить свой параметр, используя ниже
$parameterService->get('some.key');
Поскольку альтернативный подход состоял бы в том, что вы действительно можете вводить параметры приложения в свою службу через 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]
Невозможно сбросить контейнер службы, если параметр является объектом или ресурсом.
Протестировано по версии 2.3.4 Symfony