runopencode / traitor-bundle
通过基于定义的服务类使用的特性,通过方法注入将它们注入到服务中。
Requires
- php: >=7.0
- symfony/framework-bundle: ~2.8|~3.0
Requires (Dev)
- escapestudios/symfony2-coding-standard: ~2.0
- matthiasnoback/symfony-dependency-injection-test: ~2.0
- pdepend/pdepend: ~2.5
- phploc/phploc: dev-master
- phpmd/phpmd: @stable
- phpunit/phpunit: ~6.0
- sebastian/phpcpd: dev-master
- squizlabs/php_codesniffer: ~2.0
- symfony/debug: ~2.7|~3.0
- symfony/expression-language: ~2.8|~3.0
- symfony/phpunit-bridge: dev-master
- theseer/phpdox: dev-master
README
这是一个定义基于在服务类中使用的特性的额外服务/参数/值设置器注入的Symfony服务容器编译器传递。
在开始使用此包之前,请阅读以下文章(如果您还没有的话):[https://symfony.ac.cn/doc/current/components/dependency_injection/types.html](https://symfony.ac.cn/doc/current/components/dependency_injection/types.html),完全理解注入类型至关重要,因为此包推崇设置器注入(与构造器注入相比,它被视为非首选方法)以提高生产效率。
我们希望您仔细阅读此“readme”文件,并在使用之前理解此包的功能,以及它的所有优点和缺点,尤其是如果您不是计算机科学专业且有经验的开发者。
此包是如何工作的?
一句话总结:如果您的类在服务容器中注册为服务,并且该类使用了像\Psr\Log\LoggerAwareTrait
这样的特性,此包将重新定义您的服务,在其定义中添加一个方法调用,注入适当的服务,例如,一个logger
。
因此,您不必为您的服务定义设置器注入,只需使用某种提供或用户定义的*AwareTrait
,此包将提供适当的注入(当然,如果配置正确的话)。
您为什么要考虑定义设置器注入的这种方法?
假设您已经在服务容器中定义了服务,这些服务需要额外的注入,例如,在您的代码中将使用的服务。
例如
class MyService
{
public function __construct() { }
}
您的 services.yml
services:
my_service
class: MyService
为了将logger
服务注入到您的服务中,您必须修改您的类,例如,使用构造器注入。
class MyService
{
protected $logger
public function __construct(\Psr\Log\LoggerInterface $logger)
{
$this->logger = $logger;
}
}
您还必须修改 services.yml
。
services:
my_service
class: MyService
argumets: [ '@logger' ]
在上面的例子中,实施了良好的服务注入实践。然而,有时这种良好的实践无法在合理的时间和精力内得到满足。
特剌托包拯救了这种情况
不如说,像上面例子那样做,而是使用一些特剌托和某种“魔法”来完成剩余的工作?我们前面的例子可以这样简单完成:
class MyService
{
use \Psr\Log\LoggerAwareTrait;
public function __construct() { }
}
这已经足够好了——您只需使用适当的特剌托,此包内的编译器传递将为您提供适当的服务类设置器注入。
开发此包的动机
开发此类包的动机的最好例子是GeneratorBundle:[https://github.com/symfony2admingenerator/GeneratorBundle](https://github.com/symfony2admingenerator/GeneratorBundle)。
特别是,GeneratorBundle为您生成了所有CRUD部分,包括表单类型,这些类型(按照此库作者的荣幸)已正确注册到服务容器中,并带有标签form.type
。虽然这很好,但有时注入额外所需的服务可能会成为一个问题,这种情况相当常见。
为了进行此类注入,您需要确定您的表单类型已注册的服务名称,并通过配置文件修改该服务,例如通过在app/config/services.yml
中覆盖其定义(利用配置级联)或通过编译器通过。
然而,当我们在一个有50种表单类型需要注入额外服务的项目上工作时,我们发现这些方法都花费了太多的时间。
因此,我们需要一个更优雅、更省力的解决方案。
还有其他类似的解决方案,比如JMSDiExtraBundle,它允许您通过注解实现相同的功能。
为什么这个包应该谨慎使用呢?
- 仅应使用setter注入进行可选注入。然而,此解决方案还通过setter注入提出了所需服务的注入。这并不像Laravel的Facade那样糟糕,但如果在不了解注入类型的情况下使用,它可能会很危险,特别是对于不了解这种实践区别的开发者。
- Symfony提出了一些定义服务的约定,以提高项目的生产力和可维护性。此包打破了这些约定,如果开发人员不熟悉此包的用法,他们可能会难以理解某些服务是如何获得其所需依赖的。
- 第一次运行时的编译器通过可能会影响性能,因为此包分析了所有服务和它们所属类的所有特性,以及类的继承映射以及特性的相关使用。然而,通过配置,您可以缩小搜索范围并提高编译器通过的性能。
考虑到上述所有危险,此包可以在某些用例中帮助您很多,以牺牲良好的编码实践为代价,提供灵活性和生产力,您应该在出现这种情况时使用此包。
请注意,出于明显的原因,此包不应用于可重新分发的Symfony包。
配置
通过composer安装此包,composer require runopencode/traitor-bundle
,并在您的AppKernel.php
中注册它
class AppKernel extends Kernel
{
public function registerBundles()
{
$bundles = [
...
new RunOpenCode\Bundle\Traitor\TraitorBundle()
...
];
return $bundles;
}
}
并对其进行配置,下面的示例提供了完整的配置示例
runopencode_traitor:
use_common_traits: false
inject:
'Full\Qualified\Trait\Namespace':
- [ 'setterMethodName', [ '@service_name', 'or_parameter_value' ]]
- { method: 'otherSetterMethodName', arguments: [ '@service_name', 'or_parameter_value' ] }
filters:
tags: [ 'form.type', 'other_tag' ]
namespaces: [ '\Namespace\Prefix1', 'Namespace\Prefix2' ]
exclude:
tags: [ 'tag.to.exclude' ]
services: [ 'my.service.to_exclude' ]
classes: [ '\Exclude\Services\ThatUsesThisClass', '\Or\Uses\ThisClass' ]
namespaces: [ '\Exclude\AllServices\WithClasses\WithinThisNamespace\' ]
use_common_traits
:可选。此包在\RunOpenCode\Bundle\Traitor\Traits
命名空间内提供了一些常用的特性,以提高您的生产力。如果您正在使用它们,将此参数设置为true
,它将添加这些特性到注入映射。下面给出了您可以“开箱即用”使用的特性的完整列表。inject
:可选。一个关联数组,包含应进行检查的特性和它们的使用,如果它们在服务类中使用,则特性映射定义setter注入的方式与Symfony的calls
定义一样,是一个数组,第一个参数定义要调用的方法,第二个参数是一个数组,包含传递给该方法调用的参数,或者,您可以使用具有键method
和attributes
的关联数组。filters
:可选。为了不扫描所有服务类,您可以缩小子集以包含特定的命名空间和/或服务标记。确定哪个类使用哪个特性可能是昂贵的,此包检查继承以及相关特性的使用(例如,如果特性使用特性)。exclude
:可选。您可以排除某些服务、标记服务、服务类和命名空间,以便它们甚至可以考虑进行此类注入。
XML配置
当然,您可以通过XML配置(推荐方式)来配置包,这样您将可以使用XML模式文件进行验证和智能感知,以便配置您的配置文件。
提供的常见特性
如前所述,此包为您提供了一些常见特性,您可能使用也可能不使用它们。但是,如果您使用它们,请确保在配置中设置use_common_traits
为true,并且inject
映射将附加以下定义。
'Symfony\Component\DependencyInjection\ContainerAwareTrait': ['setContainer', ['@service_container']]
'Psr\Log\LoggerAwareTrait': ['setLogger', ['@logger']]
'RunOpenCode\Bundle\Traitor\Traits\DoctrineAwareTrait': ['setDoctrine', ['@doctrine']]
'RunOpenCode\Bundle\Traitor\Traits\EventDispatcherAwareTrait': ['setEventDispatcher', ['@event_dispatcher']]
'RunOpenCode\Bundle\Traitor\Traits\FilesystemAwareTrait': ['setFilesystem', ['@filesystem']]
'RunOpenCode\Bundle\Traitor\Traits\KernelAwareTrait': ['setKernel', ['@kernel']]
'RunOpenCode\Bundle\Traitor\Traits\MailerAwareInterface': ['setMailer', ['@mailer']]
'RunOpenCode\Bundle\Traitor\Traits\PropertyAccessorAwareTrait': ['setPropertyAccessor', ['@property_accessor']]
'RunOpenCode\Bundle\Traitor\Traits\RequestStackAwareTrait': ['setRequestStack', ['@request_stack']]
'RunOpenCode\Bundle\Traitor\Traits\RouterAwareTrait': ['setRouter', ['@router']]
'RunOpenCode\Bundle\Traitor\Traits\AuthorizationCheckerAwareTrait': ['setAuthorizationChecker', ['@security.authorization_checker']]
'RunOpenCode\Bundle\Traitor\Traits\SessionAwareTrait': ['setSession', ['@session']]
'RunOpenCode\Bundle\Traitor\Traits\TwigAwareTrait': ['setTwig', ['@twig']]
'RunOpenCode\Bundle\Traitor\Traits\TranslatorAwareTrait': ['setTranslator', ['@translator']]
'RunOpenCode\Bundle\Traitor\Traits\ValidatorAwareTrait': ['setValidator', ['@validator']]
'RunOpenCode\Bundle\Traitor\Traits\TokenStorageAwareTrait': ['setTokenStorage', ['@security.token_storage']]
通常,常见特性可以帮助您在注入以下服务时提高生产效率:
service_container
logger
doctrine
event_dispatcher
filesystem
kernel
mailer
property_accessor
request_stack
router
security.authorization_checker
session
twig
translator
validator
security.token_storage