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

发布于 2025-01-06 03:16:17 字数 448 浏览 0 评论 0原文

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

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

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

我需要这个来创建导航管理器服务,其中根据所有配置条目的不同设置生成不同的菜单/导航/面包屑。

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

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

提前致谢!

How can I inject ALL parameters in a service?

I know I can do: arguments: [%some.key%] which will pass the parameters: some.key: "value" to the service __construct.

My question is, how to inject everything that is under parameters in the service?

I need this in order to make a navigation manager service, where different menus / navigations / breadcrumbs are to be generated according to different settings through all of the configuration entries.

I know I could inject as many parameters as I want, but since it is going to use a number of them and is going to expand as time goes, I think its better to pass the whole thing right in the beginning.

Other approach might be if I could get the parameters inside the service as you can do in a controller $this -> container -> getParameter('some.key');, but I think this would be against the idea of Dependency Injection?

Thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

蓝眼泪 2025-01-13 03:16:17

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

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'

It is not a good practice to inject the entire Container into a service. Also if you have many parameters that you need for your service it is not nice to inject all of them one by one to your service. Instead I use this method:

1) In config.yml I define the parameters that I need for my service like this:

 parameters:
    product.shoppingServiceParams:
        parameter1: 'Some data'
        parameter2: 'some data'
        parameter3: 'some data'
        parameter4: 'some data'
        parameter5: 'some data'
        parameter6: 'some data'

2) Then I inject this root parameter to my service like:

services:
  product.shoppingService:
    class: Saman\ProductBundle\Service\Shopping
    arguments: [@translator.default, %product.shoppingServiceParams%]

3) In may service I can access these parameters like:

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) I can also set different values for different environments. For example in 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'
天煞孤星 2025-01-13 03:16:17

如何轻松获取参数的另一种变体 - 您只需将 ParameterBag 设置到您的服务即可。您可以通过不同的方式来完成它 - 通过参数或通过设置方法。让我用 set 方法展示我的例子。

因此,在 services.yml 中,您应该添加类似以下内容:

my_service:
    class: MyService\Class
    calls:
        - [setParameterBag, ["@=service('kernel').getContainer().getParameterBag()"]]

在类 MyService\Class 中,只需添加 use:

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');

Another variant how to get parameters easy - you can just set ParameterBag to your service. You can do it in different ways - via arguments or via set methods. Let me show my example with set method.

So in services.yml you should add something like:

my_service:
    class: MyService\Class
    calls:
        - [setParameterBag, ["@=service('kernel').getContainer().getParameterBag()"]]

and in class MyService\Class just add use:

use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;

and create 2 methods:

/**                                                                                                                                                                      
 * 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);
}

and now you can use in class:

$this->getParameter('your_parameter_name');
余罪 2025-01-13 03:16:17

我相信你应该单独传递参数。我认为它是按照设计的方式制作的,因此您的服务类不依赖于 AppKernel。这样你就可以在 Symfony 项目之外重用你的服务类。在测试您的服务类别时有用的东西。

I believe you're supposed to pass the parameters individually. I think it's made that way by design so your service class is not dependent on the AppKernel. That way you can reuse your service class outside your Symfony project. Something that is useful when testing your service class.

你的呼吸 2025-01-13 03:16:17

注意:我知道从设计的角度来看这个解决方案不是最好的,但它确实可以完成工作,所以请避免否决。

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

Note: I know that this solution is not BEST from design point of view, but it does the job, so please avoid down-voting.

You can inject \AppKernel object and then access all parameters like this:

config.yml:

my_service:
    class: MyService\Class
    arguments: [@kernel]

And inside MyService\Class:

public function __construct($kernel)
{
    $this->parameter = $kernel->getContainer()->getParameter('some.key');
    // or to get all:
    $this->parameters = $kernel->getContainer()->getParameterBag()->all();
}
无声静候 2025-01-13 03:16:17

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";

所以你实际上可以创建一个基本上具有主容器的空副本的服务,然后注入它只是为了获取参数。必须考虑开发/调试标志,这可能会很痛苦。

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

AppKernel would work but it's even worse (from a scope perspective) than injecting the container since the kernel has even more stuff in it.

You can look at xxxProjectContainer in your cache directory. Turns out that the assorted parameters are compiled directly into it as a big array. So you could inject the container and then just pull out the parameters. Violates the letter of the law but not the spirit of the law.

class MyService {
    public function __construct($container) {
        $this->parameters = $container->parameters; // Then discard container to preclude temptation

And just sort of messing around I found I could do this:

    $container = new \arbiterDevDebugProjectContainer();
    echo 'Parameter Count ' . count($container->parameters) . "\n";

So you could actually create a service that had basically a empty copy of the master container and inject it just to get the parameters. Have to take into account the dev/debug flags which might be a pain.

I suspect you could also do it with a compiler pass but have never tried.

蛮可爱 2025-01-13 03:16:17

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

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

注入您的服务,您可以使用下面的方法获取您的参数

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

Suggestion to define a service at services.yml, which will inject the parameterBag and allow access to any of your parameter

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

Inject your service, and u can get your parameter using below

$parameterService->get('some.key');
看透却不说透 2025-01-13 03:16:17

作为替代方法,您实际上可以通过捆绑 DI 扩展中的 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 下测试

As alternative approach would be that you can actually inject application parameters into your service via Container->getParameterBag in you bundle DI Extension

    <?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()));

        }
}

Please note that we can not inject ParameterBag object directly, cause it throws:

[Symfony\Component\DependencyInjection\Exception\RuntimeException]
Unable to dump a service container if a parameter is an object or a
resource.

Tested under Symfony version 2.3.4

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文