Symfony2:如何在服务中注入所有参数


Symfony2: How to inject ALL parameters in a service?

如何在服务中注入所有参数?

我知道我可以做:arguments: [%some.key%],它将把parameters: some.key: "value"传递给服务__construct。

我的问题是,如何在服务中注入parameters下的所有内容?

我需要这一点来制作导航管理器服务,在该服务中,将根据所有配置条目的不同设置生成不同的菜单/导航/面包屑。

我知道我可以注入尽可能多的参数,但由于它将使用其中的一些参数,并且会随着时间的推移而扩展,我认为最好一开始就通过整个过程。

另一种方法可能是,如果我可以像在控制器$this -> container -> getParameter('some.key');中那样在服务中获取参数,但我认为这将违背依赖注入的想法?

提前感谢!

将整个容器注入服务不是一个好的做法。此外,如果您的服务需要许多参数,那么将所有参数逐一注入到服务中是不好的。相反,我使用这种方法:

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 $parameters;
    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'

另一个如何轻松获取参数的变体-您只需将ParameterBag设置为您的服务即可。您可以通过不同的方式来实现它——通过参数或通过set方法。让我用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');

我认为应该单独传递参数。我认为它是这样设计的,所以你的服务类不依赖于AppKernel。这样,您就可以在Symfony项目之外重用您的服务类。测试服务类时有用的东西。

注意:我知道从设计的角度来看,这个解决方案不是最好的,但它能完成任务,所以请避免投反对票

您可以注入''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();
}

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标志,这可能会很痛苦。

我怀疑您也可以使用编译器通行证来完成此操作,但从未尝试过。

建议在services.yml中定义一个服务,该服务将注入parameterBag并允许访问任何参数

service.container_parameters:
  public: false
  class: stdClass
  factory_service: service_container
  factory_method: getParameterBag

注入你的服务,你可以使用下面的获得你的参数

$parameterService->get('some.key');

另一种方法是,您可以通过捆绑DI Extension 中的Container->getParameterBag将应用程序参数注入到您的服务中

    <?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''DependencyInjection''Exception''RuntimeException]
如果参数是对象或资源

在Symfony版本2.3.4

下测试