2016-06-08 51 views
2

我正在使用Gedmo Loggable来跟踪用户对实体所做的更改。每次更改都不会默认存储用户名,但有必要将其提供给侦听器。在Symfony2中将security用户的名称传递给services.yml中的监听器

这方面的例子,可记录的的文件中发现:

$loggableListener = new Gedmo\Loggable\LoggableListener; 
    $loggableListener->setAnnotationReader($cachedAnnotationReader); 
    $loggableListener->setUsername('admin'); 
    $evm->addEventSubscriber($loggableListener); 

这并没有为我工作的原因有两个:

  1. 我注册听众中services.yml,不在控制器中
  2. 我不希望存储预先知道的用户名(如示例中的用户名)

loggableListener的setUsername方法要么使用字符串,要么使用getUsername方法提供字符串。

我该如何传递给听众?我找到了一个通过security_token的方法,但这还不够。我现在有是这样的:

(...) 
gedmo.listener.loggable: 
class: Gedmo\Loggable\LoggableListener 
tags: 
    - { name: doctrine.event_subscriber, connection: default } 
calls: 
    - [ setAnnotationReader, [ "@annotation_reader" ] ] 
    #- [ setUsername, [ "A fixed value works" ] ] 
    - [ setUserValue, [ @security.??? ] ] 

我也使用Blameable并发现了类似的问题一个很好的解决方法(在整个监听器重写)。我试图为Loggable做同样的事情,但这似乎更复杂一些。

主要问题:如何将security用户对象(或其用户名)传递给services.yml中的侦听器?

更新

利玛窦向我展示了如何通过一个函数的结果作为一个参数给听众。这几乎解决了这个问题。还有另一种服务,它在提供token_storage时提供用户名。但是这意味着我需要将一个参数传递给一个服务,该参数作为另一个服务的参数给出。这个例子将解释:

- [ setUsername, [ "@=service('gedmo.listener.blameable').getUsername(@security.token_storage)" ] ] 

现在的问题是,@ security.token_storage不被接受在这种情况下。我如何将参数传递给方法getUsername()?

回答

0

我认为不可能在服务中注入authed用户。但是,你可以注入令牌存储:@security.token_storage(前symfony的2.6,你将不得不使用@security.context代替@security.token_storage) 在服务(LoggableListener),你就可以得到authed用户名是这样的: $tokenStorage->getToken()->getUser()->getUsername()

1

您可以使用Symfony Service Expressions,作为例子,你可以尝试以下方法:

gedmo.listener.loggable: 
class: Gedmo\Loggable\LoggableListener 
tags: 
    - { name: doctrine.event_subscriber, connection: default } 
calls: 
    - [ setAnnotationReader, [ "@annotation_reader" ] ] 
    - [ setUserValue, ["@=service('security.token_storage').getToken()->getUser()->getUsername()"] ] 

但在某些情况下,用户可以null,这样你就可以?条件(见文档)。

希望这有助于

+0

我们已经很接近了。我用点替换了 - >。从技术上讲,这是有效的,但由于某种原因,令牌几乎总是空的,并且没有用户名被返回。然后我想:我有另一个侦听器(用于Blameable)返回用户名。如果我可以调用该服务,并将其值作为可登录服务的参数,则可以解决该问题。但问题是:该监听器还需要一个参数。你知道如何传递它吗?一个固定值被接受,一个变量不被接受。我会更新我的问题。 –

0

我遇到了同样的问题,我通过创建一个记录监听器就像stofDoctrineExtensionsBundle解决它。在我services.yml文件

//src/AppBundle/Listener/LoggerListener 
<?php 

namespace AppBundle\Listener; 

use Gedmo\Loggable\LoggableListener; 
use Symfony\Component\EventDispatcher\EventSubscriberInterface; 
use Symfony\Component\HttpKernel\Event\GetResponseEvent; 
use Symfony\Component\HttpKernel\HttpKernelInterface; 
use Symfony\Component\HttpKernel\KernelEvents; 
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; 
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; 

/** 
* LoggerListener 
* 
* @author Alexandre Tranchant <[email protected]> 
* @author Christophe Coevoet <[email protected]> 
*/ 
class LoggerListener implements EventSubscriberInterface 
{ 
    /** 
    * @var AuthorizationCheckerInterface 
    */ 
    private $authorizationChecker; 
    /** 
    * @var TokenStorageInterface 
    */ 
    private $tokenStorage; 
    /** 
    * @var LoggableListener 
    */ 
    private $loggableListener; 

    /** 
    * LoggerListener constructor. 
    * 
    * @param LoggableListener $loggableListener 
    * @param TokenStorageInterface|null $tokenStorage 
    * @param AuthorizationCheckerInterface|null $authorizationChecker 
    */ 
    public function __construct(LoggableListener $loggableListener, TokenStorageInterface $tokenStorage = null, AuthorizationCheckerInterface $authorizationChecker = null) 
    { 
     $this->loggableListener = $loggableListener; 
     $this->tokenStorage = $tokenStorage; 
     $this->authorizationChecker = $authorizationChecker; 
    } 
    /** 
    * Set the username from the security context by listening on core.request 
    * 
    * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event 
    */ 
    public function onKernelRequest(GetResponseEvent $event) 
    { 
     if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) { 
      return; 
     } 
     if (null === $this->tokenStorage || null === $this->authorizationChecker) { 
      return; 
     } 
     $token = $this->tokenStorage->getToken(); 
     if (null !== $token && $this->authorizationChecker->isGranted('IS_AUTHENTICATED_REMEMBERED')) { 
      $this->loggableListener->setUsername($token); 
     } 
    } 
    public static function getSubscribedEvents() 
    { 
     return array(
      KernelEvents::REQUEST => 'onKernelRequest', 
     ); 
    } 
} 

然后我宣布这个监听器:

为了做到这一点,我创造了这个文件。

services: 
    #Loggable 
    gedmo.listener.loggable: 
      class: Gedmo\Loggable\LoggableListener 
      tags: 
       - { name: doctrine.event_subscriber, connection: default } 
      calls: 
       - [ setAnnotationReader, [ "@annotation_reader" ] ] 

    # KernelRequest listener 
    app.listener.loggable: 
     class: AppBundle\Listener\LoggerListener 
     tags: 
      # loggable hooks user username if one is in token_storage or authorization_checker 
      - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest} 
     arguments: 
      - '@gedmo.listener.loggable' 
      - '@security.token_storage' 
      - '@security.authorization_checker' 

正如你可以在这个破截图中看到,它工作正常: Screenshot of Log dump