【问题标题】:Symfony: How to get all services and their respective classesSymfony:如何获取所有服务及其各自的类
【发布时间】:2016-01-31 07:44:13
【问题描述】:

我想要实现的是:我的应用程序中的一些服务带有一个特殊的注释。稍后,在构建过程中,一个特殊的命令应该找到所有带有该注释的文件。

我的做法是先加载所有的bundle:

$container = $this->getContainer();

foreach ($container->getParameter('kernel.bundles') as $alias => $namespace)
    $bundle = $container->get('kernel')->getBundle($alias);

我被困在这一点上。如何让$bundle 实例告诉我它的服务?

注意:我也很高兴有一个不是特定于捆绑包的解决方案,即加载所有可用服务定义的解决方案。 ContainerBuilder 有一个 getDefinitions,看起来很有希望,虽然我不知道如何通过命令访问它。

我需要获取一个包含服务 ID 及其类的列表——尤其是类,因为这些是我需要加载到注释阅读器中的那些。

显然,我不想自己解析services.yml,并且我还想避免从$container->getServiceIds() 加载每个服务的实例。

(顺便说一句,tagged services 不会有帮助;我需要注释。我想自动检测带注释的服务,因为标记它们需要额外的步骤,这是不必要且容易出错的。)

【问题讨论】:

  • 您可能需要重新考虑您的方法。您可以查看缓存目录以查看容器对其可用的信息。您不会找到捆绑信息。事实上,完全可以在包之外定义服务。也许标记服务是您正在寻找的? symfony.com/doc/current/components/dependency_injection/…
  • 感谢您提供标记服务的建议,但它们不是我想要的。我已经通过澄清 w.r.t 更新了这个问题。标记服务。

标签: php symfony dependency-injection


【解决方案1】:

编译器通过仍然可以。但是,您可以获得所有定义,而不是查找标记的服务。这具有使用定义而不是实例化每个服务的优点。

当然,您需要创建一个管理器类,它接受所有类名,以便稍后在您的命令中使用它。

<?php

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Reference;

class RegisterClassNamesPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        if (!$container->has('app.class_names_manager')) {
            return;
        }

        $manager = $container->findDefinition(
            'app.class_names_manager'
        );

        foreach ($container->getDefinitions() as $id => $definition) {
            $class = $container->getParameterBag()->resolveValue($def->getClass());

            $definition->addMethodCall(
                'addClassName',
                array($id, $class)
            );
        }
    }
}

【讨论】:

  • 啊,是的……那是去ContainerBuilder的方法,很好。我仍然认为我现在会坚持使用getServiceIds 方法,因为摆弄编译通道并将结果存储在一些中间服务中似乎对我的场景来说有点过头了。还是谢谢你!
  • 您的方式是实例化每个服务,这可能是一项繁重的任务。而且你必须每次都这样做,而编译器传递只执行一次。
  • 好的,经过一番思考,这可能确实是一个合适的方法。仍然不能 100% 确定,但让我们试试看我们能走多远。
【解决方案2】:

好的,我现在已经通过 getServiceIds 加载所有服务的不太优雅的方法解决了这个问题:

$container = $this->getContainer();

foreach ($container->getServiceIds() as $id)
{
    $service = $container->get($id, $container::IGNORE_ON_INVALID_REFERENCE);
    if (!$service) continue;

    $class = get_class($service);

    // ...
}

【讨论】:

  • 你必须有一个超级重要的用例。遍历并实例化每一个最后的服务似乎有点过头了。有一个 cache/dev/Container.xml 文件,其中包含您需要的信息。阅读起来可能会更快。
  • 该命令仅在构建时运行一次。所以我认为通过所有服务是可以的。 (这甚至不是最密集的部分。)
猜你喜欢
  • 2021-08-18
  • 2018-11-06
  • 1970-01-01
  • 2013-12-31
  • 1970-01-01
  • 2020-05-27
  • 2020-06-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多