如何在服务中注入所有参数?
我知道我可以:arguments: [%some.key%]
将parameters: some.key: "value"
传递给服务__construct。
我的问题是,如何在服务中注入parameters
下的所有内容?
我需要这个来制作导航管理器服务,其中根据不同的设置通过所有配置条目生成不同的菜单/导航/面包屑。
我知道我可以根据需要注入尽可能多的参数,但由于它会使用其中的一些参数并随着时间的推移而扩展,我认为最好在开始时将整个事情传递给我。 / p>
其他方法可能是我可以在控制器$this -> container -> getParameter('some.key');
中获取服务中的参数,但我认为这会违反依赖注入的想法吗?
提前致谢!
答案 0 :(得分:47)
将整个Container注入服务并不是一个好习惯。此外,如果您的服务需要许多参数,那么将所有这些参数逐个注入您的服务并不好。相反,我使用这种方法:
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)然后我将这个root参数注入我的服务,如:
services:
product.shoppingService:
class: Saman\ProductBundle\Service\Shopping
arguments: [@translator.default, %product.shoppingServiceParams%]
3)在may服务中,我可以访问以下参数:
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'
答案 1 :(得分:9)
另一种变体如何轻松获取参数 - 您只需将ParameterBag设置为您的服务即可。你可以通过不同的方式 - 通过参数或通过set方法。让我用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');
答案 2 :(得分:8)
我相信你应该单独传递参数。我认为它是按照设计进行的,所以你的服务类不依赖于AppKernel。这样您就可以在Symfony项目之外重用您的服务类。测试服务类时有用的东西。
答案 3 :(得分:7)
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";
因此,您实际上可以创建一个基本上是主容器的空副本的服务,并将其注入以获取参数。必须考虑可能很痛苦的开发/调试标志。
我怀疑你也可以用编译器传递来做但从未尝试过。
答案 4 :(得分:5)
注意:我知道这个解决方案从设计的角度来看并不是最好的,但是它可以胜任,所以请避免投票。
您可以注入\ 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();
}
答案 5 :(得分:4)
建议在services.yml定义服务,该服务将注入parameterBag并允许访问您的任何参数
service.container_parameters:
public: false
class: stdClass
factory_service: service_container
factory_method: getParameterBag
注入您的服务,您可以使用下面的
获取参数$parameterService->get('some.key');
答案 6 :(得分:3)
作为替代方法,您可以通过容器中的容器 - > 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的\元器件\ DependencyInjection \异常\的RuntimeException]
如果参数是对象或a,则无法转储服务容器 资源。
在Symfony版本 2.3.4
下测试