忽略自动装配目录中的 class
Ignore a class in a autowired directory
我的服务/文件夹中某处有异常,Symfony 正在尝试自动装配它:
Cannot autowire service
"App\Service\Order\Exception\StripeRequiresActionException": argument
"$secretKey" of method "__construct()" is type-hinted "string", you
should configure its value explicitly.
这是我的 class :
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;
}
}
我不希望它自动装配。有没有一种简单的方法可以防止 class 被 DI 加载,例如 带有注释 ?我知道我可以在我的 yaml 配置中排除这个 class,但我不想这样做,因为我发现它很难维护。
也许您可以排除所有异常,无论它们在哪里。
如果您的所有异常都遵循您在问题中显示的模式,您可以执行类似于:
App\:
resource: '../src/*'
exclude: ['../src/{Infrastructure/Symfony,Domain,Tests}', '../src/**/*Exception.php']
这直接来自我在这里打开的一个项目。 Symfony 的默认 exclude
看起来有些不同。但重要的一点是将模式 *Exception.php
添加到排除的文件中。
这比注释更易于维护,即使注释是可能的(我相信它不是)。将配置全部保存在同一个地方,您可以创建新的异常,而无需更改配置或添加不必要的代码。
即使我同意在您的特定情况下最干净的方法是执行 yivi
建议的操作,我认为我有一个更通用的解决方案可以适用于更多情况。
在我的例子中,我有一个 PagesScanner
服务 returns PageResult
对象,两者都深入到自动装配目录中。
像建议的那样排除 class 是一种痛苦,并且随着异常数量的增加会使 yaml 很快变得不可读。
所以我创建了一个新的编译器通道,它在 App/
文件夹下的每个 class 上搜索 @IgnoreAutowire
注释:
<?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
}
}
}
}
}
这样我所要做的就是将注释添加到 classes 我不想被自动装配:
<?php
namespace App\Utils\Cms\PagesFinder;
use App\Annotation\IgnoreAutowire;
/**
* @IgnoreAutowire()
*/
class PageResult
{
[...]
}
这个方法的另一个好处是你甚至可以在 class 构造函数中使用参数而不会出现任何错误,因为实际的自动装配是在编译器通过之后完成的。
您也可以在 config/services.yaml
:
中仅禁用此 class 的自动配置
App\Service\Order\Exception\StripeRequiresActionException:
autoconfigure: false
Symfony 不会将此 class 添加到 DI。
php8 属性的顺便说一句代码:
CompilerPass
<?php
namespace App\DependencyInjection\Compiler;
use App\Annotation\IgnoreAutowire;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
final class RemoveUnwantedAutoWiredServicesPass implements CompilerPassInterface
{
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
$definitions = $container->getDefinitions();
foreach ($definitions as $fqcn => $definition) {
if (str_starts_with($fqcn, 'App\')) {
try {
$refl = new \ReflectionClass($fqcn);
$attribute = $refl->getAttributes(IgnoreAutowire::class)[0] ?? null;
if ($attribute !== null) {
$container->removeDefinition($fqcn);
}
} catch (\Exception $e) {
// Ignore
}
}
}
}
}
属性
<?php
namespace App\Annotation;
use Attribute;
/**
* Annotation class for @IgnoreAutowire().
*
* @Annotation
* @Target({"CLASS"})
*/
#[Attribute(Attribute::TARGET_CLASS)]
class IgnoreAutowire
{
}
我的服务/文件夹中某处有异常,Symfony 正在尝试自动装配它:
Cannot autowire service "App\Service\Order\Exception\StripeRequiresActionException": argument "$secretKey" of method "__construct()" is type-hinted "string", you should configure its value explicitly.
这是我的 class :
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;
}
}
我不希望它自动装配。有没有一种简单的方法可以防止 class 被 DI 加载,例如 带有注释 ?我知道我可以在我的 yaml 配置中排除这个 class,但我不想这样做,因为我发现它很难维护。
也许您可以排除所有异常,无论它们在哪里。
如果您的所有异常都遵循您在问题中显示的模式,您可以执行类似于:
App\:
resource: '../src/*'
exclude: ['../src/{Infrastructure/Symfony,Domain,Tests}', '../src/**/*Exception.php']
这直接来自我在这里打开的一个项目。 Symfony 的默认 exclude
看起来有些不同。但重要的一点是将模式 *Exception.php
添加到排除的文件中。
这比注释更易于维护,即使注释是可能的(我相信它不是)。将配置全部保存在同一个地方,您可以创建新的异常,而无需更改配置或添加不必要的代码。
即使我同意在您的特定情况下最干净的方法是执行 yivi
建议的操作,我认为我有一个更通用的解决方案可以适用于更多情况。
在我的例子中,我有一个 PagesScanner
服务 returns PageResult
对象,两者都深入到自动装配目录中。
像建议的那样排除 class 是一种痛苦,并且随着异常数量的增加会使 yaml 很快变得不可读。
所以我创建了一个新的编译器通道,它在 App/
文件夹下的每个 class 上搜索 @IgnoreAutowire
注释:
<?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
}
}
}
}
}
这样我所要做的就是将注释添加到 classes 我不想被自动装配:
<?php
namespace App\Utils\Cms\PagesFinder;
use App\Annotation\IgnoreAutowire;
/**
* @IgnoreAutowire()
*/
class PageResult
{
[...]
}
这个方法的另一个好处是你甚至可以在 class 构造函数中使用参数而不会出现任何错误,因为实际的自动装配是在编译器通过之后完成的。
您也可以在 config/services.yaml
:
App\Service\Order\Exception\StripeRequiresActionException:
autoconfigure: false
Symfony 不会将此 class 添加到 DI。
php8 属性的顺便说一句代码:
CompilerPass
<?php
namespace App\DependencyInjection\Compiler;
use App\Annotation\IgnoreAutowire;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
final class RemoveUnwantedAutoWiredServicesPass implements CompilerPassInterface
{
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
$definitions = $container->getDefinitions();
foreach ($definitions as $fqcn => $definition) {
if (str_starts_with($fqcn, 'App\')) {
try {
$refl = new \ReflectionClass($fqcn);
$attribute = $refl->getAttributes(IgnoreAutowire::class)[0] ?? null;
if ($attribute !== null) {
$container->removeDefinition($fqcn);
}
} catch (\Exception $e) {
// Ignore
}
}
}
}
}
属性
<?php
namespace App\Annotation;
use Attribute;
/**
* Annotation class for @IgnoreAutowire().
*
* @Annotation
* @Target({"CLASS"})
*/
#[Attribute(Attribute::TARGET_CLASS)]
class IgnoreAutowire
{
}