忽略自动装配目录中的类

Rap*_*lié 3 php autowired symfony

我的服务/文件夹中的某个地方有一个异常,Symfony 正在尝试自动装配它:

无法自动装配服务“App\Service\Order\Exception\StripeRequiresActionException”:方法“__construct()”的参数“$secretKey”是类型提示的“string”,您应该明确配置其值。

这是我的课:

class StripeRequiresActionException extends \Exception
{
    /**
     * @var string
     */
    protected $secretKey;

    public function __construct(string $secretKey)
    {
        parent::__construct();

        $this->secretKey = $secretKey;
    }

    /**
     * @return string
     */
    public function getSecretKey(): string
    {
        return $this->secretKey;
    }
}
Run Code Online (Sandbox Code Playgroud)

我不希望它被自动装配。有没有一种简单的方法来防止这个类被 DI 加载,例如带有注释?我知道我可以在我的 yaml 配置中排除这个类,但我不想这样做,因为我觉得这很丑陋且难以维护。

yiv*_*ivi 8

也许您可以排除所有异常,无论它们在哪里。

如果您的所有异常都遵循您在问题中显示的模式,您可以执行类似以下操作:

App\:
  resource: '../src/*'
  exclude: ['../src/{Infrastructure/Symfony,Domain,Tests}', '../src/**/*Exception.php']
Run Code Online (Sandbox Code Playgroud)

这直接来自我在这里打开的一个项目。excludeSymfony的默认设置看起来有些不同。但重要的一点是将模式添加*Exception.php到排除的文件中。

这比注释更易于维护,即使注释是可能的(我认为不是)。将所有配置保持在同一位置,您可以创建新的异常而无需更改配置或添加不必要的代码。

  • 你是对的,这比使用注释更聪明。它运行良好,我只需执行 `../src/Service/**/{*Exception.php}` 即可使其在所有子文件夹中运行。谢谢。 (2认同)

Stn*_*ire 5

即使我同意在您的特定情况下最干净的方法是按照yivi建议进行操作,但我认为我有一个更通用的解决方案可以适合更多情况。

在我的情况下,我有一个PagesScanner返回PageResult对象的服务,两者都深入到自动装配目录中的几个级别。

像建议的那样排除类是一种痛苦,并且随着异常数量的增加会使 yaml 很快变得不可读。

因此,我创建了一个新的编译器传递,用于@IgnoreAutowireApp/文件夹下的每个类上搜索注释:

<?php
namespace App\DependencyInjection\Compiler;

use App\Annotation\IgnoreAutowire;
use Doctrine\Common\Annotations\AnnotationReader;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

final class RemoveUnwantedAutoWiredServicesPass implements CompilerPassInterface
{
    /**
     * {@inheritdoc}
     */
    public function process(ContainerBuilder $container)
    {
        $annotationReader = new AnnotationReader();
        $definitions = $container->getDefinitions();
        foreach ($definitions as $fqcn => $definition) {
            if (substr($fqcn, 0, 4) === 'App\\') {
                try {
                    $refl = new \ReflectionClass($fqcn);
                    $result = $annotationReader->getClassAnnotation($refl, IgnoreAutowire::class);
                    if ($result !== null) {
                        $container->removeDefinition($fqcn);
                    }
                } catch (\Exception $e) { 
                    // Ignore
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这样我所要做的就是将注释添加到我不想被自动装配的类中:

<?php
namespace App\Utils\Cms\PagesFinder;

use App\Annotation\IgnoreAutowire;

/**
 * @IgnoreAutowire()
 */
class PageResult
{
    [...]
}
Run Code Online (Sandbox Code Playgroud)

这个方法的另一个好处是你甚至可以在类构造函数中使用参数而不会出现任何错误,因为实际的自动装配是在编译器通过之后完成的。