覆盖复杂的 Symfony2 class - 最佳实践
Overriding a complicated Symfony2 class - best practice
我正在使用 Symfony 2.3 LTS,我认为它与最新版本略有不同(对于我的部分问题)。
我需要覆盖 'security.authentication.listener.form' 服务,即 class: https://github.com/symfony/Security/blob/2.3/Http/Firewall/UsernamePasswordFormAuthenticationListener.php
我只是想添加一点代码,没什么大不了的。
这些是重要的声明部分(在 Symfony 配置文件中):
<parameter key="security.authentication.listener.form.class">Symfony\Component\Security\Http\Firewall\UsernamePasswordFormAuthenticationListener</parameter>
<service id="security.authentication.listener.form"
class="%security.authentication.listener.form.class%"
parent="security.authentication.listener.abstract"
abstract="true">
</service>
<service id="security.authentication.listener.abstract" abstract="true" public="false">
<tag name="monolog.logger" channel="security" />
<argument type="service" id="security.context" />
<argument type="service" id="security.authentication.manager" />
<argument type="service" id="security.authentication.session_strategy" />
<argument type="service" id="security.http_utils" />
<argument />
<argument type="service" id="security.authentication.success_handler" />
<argument type="service" id="security.authentication.failure_handler" />
<argument type="collection"></argument>
<argument type="service" id="logger" on-invalid="null" />
<argument type="service" id="event_dispatcher" on-invalid="null" />
</service>
另外还有两点很重要:
(1) I only have experience using Yaml and although it shouldn't be difficult converting this, it does add an additional obstacle to deal with. I will also use Yaml for my finished solution. I've never seen the on-invalid attribute though for a start.
(2) I need to pass in some additional parameters of my own.
我已经尝试覆盖 class 名称和基本的 class 扩展以查看它是否可以正常工作,但我认为没有任何传入的值使用:
Yaml:
parameters:
security.authentication.listener.form.class: MyBundle\Security\MyCustomUsernamePasswordFormAuthenticationListener
PHP class:
class MyCustomUsernamePasswordFormAuthenticationListener extends UsernamePasswordFormAuthenticationListener
{
/**
* {@inheritdoc}
*/
public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfProviderInterface $csrfProvider = null)
{
parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, $successHandler, $failureHandler, $options, $logger, $dispatcher, $csrfProvider);
}
/**
* {@inheritdoc}
*/
protected function attemptAuthentication(Request $request)
{
parent::attemptAuthentication($request);
}
}
另外,我不明白为什么 'security.authentication.listener.abstract' 服务中的参数 5 是空的,而 class 如果它是空的(但不是)会抛出错误。
此外,我没有在安全配置 (http://symfony.com/doc/2.3/reference/configuration/security.html) 中看到 security.authentication.listener.form 服务作为一个选项。如果不是,我可以像上面提到的那样覆盖,但如果可能的话,最好在 security.yml 中声明它。
那么在 Yaml 中执行此操作的最佳实践方法是什么?我可以通过某种方式破解、剪切和粘贴等。但理想情况下,我不需要重新声明所有参数,因为它们已经声明了。
首先,回答为什么在安全配置 (http://symfony.com/doc/2.3/reference/configuration/security.html) 中看不到 security.authentication.listener.form 服务选项:
- 在app/config/security.yml 中,您将找到安全包和组件的配置选项。这些选项可以从应用程序文件夹的配置文件中进行编辑。位于文件夹 /Resources/config 内的包中的配置只能使用 compilerPass.
进行编辑
现在是您的主要问题,解决方案取决于您要执行的操作:
- 如果您直接使用 class,您可能希望将其发送给装饰器并根据需要使用该装饰器
如果没有,你可以这样做:
在您的 services.yml 中添加:
acme.security.authentication.listener.form:
class: %security.authentication.listener.form.class%
parent: security.authentication.listener.abstract
abstract: true
然后 create a CompilerPass inside your Bundle 并添加:
public function process(ContainerBuilder $container)
{
$definition = new DefinitionDecorator( 'acme.security.authentication.listener.form' );
$definition->setClass( 'Acme\Bundle\MyCustomUsernamePasswordFormAuthenticationListener' );
$definition->setAbstract( true );
// Here you can add your additional data
$definition->setMethodCalls($callsArray);
$container->setDefinition( 'security.authentication.listener.form', $definition );
}
您可以在 Resources/config/services.yml 中覆盖 security.authentication.listener.form
而无需 compilerpass,前提是您的 bundle 在 SecurityBundle 之后启动。但这是我不推荐的做法。使用 CompilerPass 时,您将始终确保它在所有捆绑包初始化后运行。
希望对您有所帮助
我正在使用 Symfony 2.3 LTS,我认为它与最新版本略有不同(对于我的部分问题)。
我需要覆盖 'security.authentication.listener.form' 服务,即 class: https://github.com/symfony/Security/blob/2.3/Http/Firewall/UsernamePasswordFormAuthenticationListener.php
我只是想添加一点代码,没什么大不了的。
这些是重要的声明部分(在 Symfony 配置文件中):
<parameter key="security.authentication.listener.form.class">Symfony\Component\Security\Http\Firewall\UsernamePasswordFormAuthenticationListener</parameter>
<service id="security.authentication.listener.form"
class="%security.authentication.listener.form.class%"
parent="security.authentication.listener.abstract"
abstract="true">
</service>
<service id="security.authentication.listener.abstract" abstract="true" public="false">
<tag name="monolog.logger" channel="security" />
<argument type="service" id="security.context" />
<argument type="service" id="security.authentication.manager" />
<argument type="service" id="security.authentication.session_strategy" />
<argument type="service" id="security.http_utils" />
<argument />
<argument type="service" id="security.authentication.success_handler" />
<argument type="service" id="security.authentication.failure_handler" />
<argument type="collection"></argument>
<argument type="service" id="logger" on-invalid="null" />
<argument type="service" id="event_dispatcher" on-invalid="null" />
</service>
另外还有两点很重要:
(1) I only have experience using Yaml and although it shouldn't be difficult converting this, it does add an additional obstacle to deal with. I will also use Yaml for my finished solution. I've never seen the on-invalid attribute though for a start.
(2) I need to pass in some additional parameters of my own.
我已经尝试覆盖 class 名称和基本的 class 扩展以查看它是否可以正常工作,但我认为没有任何传入的值使用:
Yaml:
parameters:
security.authentication.listener.form.class: MyBundle\Security\MyCustomUsernamePasswordFormAuthenticationListener
PHP class:
class MyCustomUsernamePasswordFormAuthenticationListener extends UsernamePasswordFormAuthenticationListener
{
/**
* {@inheritdoc}
*/
public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfProviderInterface $csrfProvider = null)
{
parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, $successHandler, $failureHandler, $options, $logger, $dispatcher, $csrfProvider);
}
/**
* {@inheritdoc}
*/
protected function attemptAuthentication(Request $request)
{
parent::attemptAuthentication($request);
}
}
另外,我不明白为什么 'security.authentication.listener.abstract' 服务中的参数 5 是空的,而 class 如果它是空的(但不是)会抛出错误。
此外,我没有在安全配置 (http://symfony.com/doc/2.3/reference/configuration/security.html) 中看到 security.authentication.listener.form 服务作为一个选项。如果不是,我可以像上面提到的那样覆盖,但如果可能的话,最好在 security.yml 中声明它。
那么在 Yaml 中执行此操作的最佳实践方法是什么?我可以通过某种方式破解、剪切和粘贴等。但理想情况下,我不需要重新声明所有参数,因为它们已经声明了。
首先,回答为什么在安全配置 (http://symfony.com/doc/2.3/reference/configuration/security.html) 中看不到 security.authentication.listener.form 服务选项:
- 在app/config/security.yml 中,您将找到安全包和组件的配置选项。这些选项可以从应用程序文件夹的配置文件中进行编辑。位于文件夹 /Resources/config 内的包中的配置只能使用 compilerPass. 进行编辑
现在是您的主要问题,解决方案取决于您要执行的操作:
- 如果您直接使用 class,您可能希望将其发送给装饰器并根据需要使用该装饰器
如果没有,你可以这样做: 在您的 services.yml 中添加:
acme.security.authentication.listener.form: class: %security.authentication.listener.form.class% parent: security.authentication.listener.abstract abstract: true
然后 create a CompilerPass inside your Bundle 并添加:
public function process(ContainerBuilder $container) { $definition = new DefinitionDecorator( 'acme.security.authentication.listener.form' ); $definition->setClass( 'Acme\Bundle\MyCustomUsernamePasswordFormAuthenticationListener' ); $definition->setAbstract( true ); // Here you can add your additional data $definition->setMethodCalls($callsArray); $container->setDefinition( 'security.authentication.listener.form', $definition ); }
您可以在 Resources/config/services.yml 中覆盖 security.authentication.listener.form
而无需 compilerpass,前提是您的 bundle 在 SecurityBundle 之后启动。但这是我不推荐的做法。使用 CompilerPass 时,您将始终确保它在所有捆绑包初始化后运行。
希望对您有所帮助