9

I use the sonata-admin bundle. I have the relationship with the user (FOSUserBundle) in the PageEntity. I want to save the current user which create or change a page.

My guess is get the user object in postUpdate and postPersist methods of the admin class and this object transmit in setUser method.

But how to realize this?

On the google's group I saw

    public function setSecurityContext($securityContext) {
        $this->securityContext = $securityContext;
    }

    public function getSecurityContext() {
        return $this->securityContext;
    }

    public function prePersist($article) {
        $user = $this->getSecurityContext()->getToken()->getUser();

        $appunto->setOperatore($user->getUsername());
    }

but this doesn't work

Guillermo Gutiérrez
  • 17,273
  • 17
  • 89
  • 116
user3342506
  • 159
  • 1
  • 2
  • 8
  • What do you mean by *"doesn't work"*? Were there any error message? – Touki Feb 27 '14 at 13:18
  • How and where do you pass the current security context to your entity's `setSecurityContext()` method? You should probably create a listener/subscriber instead of using lifecycle events to perform such an operation btw. – Nicolai Fröhlich Feb 27 '14 at 13:26
  • There is "FatalErrorException: Error: Call to a member function getToken() on a non-object" – user3342506 Feb 27 '14 at 13:27
  • nifr, in the admin class also. – user3342506 Feb 27 '14 at 13:28
  • nifr, thank, I have created listener/subscriber, the error message already doesn't display. But user dosn't save in the page entity. There aren't errors, but field for the user id is empty in the page table. – user3342506 Feb 27 '14 at 13:50

3 Answers3

27

In the admin class you can get the current logged in user like this:

$this->getConfigurationPool()->getContainer()->get('security.token_storage')->getToken()->getUser()

EDIT based on feedback

And you are doing it this? Because this should work.

 /**
     * {@inheritdoc}
     */
    public function prePersist($object)
    {

$user = $this->getConfigurationPool()->getContainer()->get('security.token_storage')->getToken()->getUser();
        $object->setUser($user);
    }

    /**
     * {@inheritdoc}
     */
    public function preUpdate($object)
    {
$user = $this->getConfigurationPool()->getContainer()->get('security.token_storage')->getToken()->getUser();
        $object->setUser($user);
    }
Baba Yaga
  • 1,819
  • 15
  • 20
  • No errors, but don't save in the table also. My code `$user = $this->getConfigurationPool()->getContainer()->get('security.context')->getToken()->getUser(); $object->setUser($user);` – user3342506 Feb 27 '14 at 14:01
  • yes, is the same. Probably, issue is in the user entity, therefore my code don't work... – user3342506 Feb 28 '14 at 07:28
  • Right, I have decided my problem with the user now. Your code works. – user3342506 Feb 28 '14 at 07:43
  • 1
    `security.context` component is deprecated since 2.6 and removed since 3.0, use `security.token_storage` instead. – chalasr Apr 05 '16 at 13:55
  • @chalasr : strangely, the token is null when I try this. – greg0ire Apr 11 '16 at 17:04
  • @greg0ire on what symfony version do you are? It's surely a cache issue, be sure that you use `$this->getConfigurationPool()->getContainer()->get('security.token_storage')->getToken()->getUser()` . See [the corresponding changelog](http://symfony.com/blog/new-in-symfony-2-6-security-component-improvements). – chalasr Apr 11 '16 at 17:09
  • I'm using 2.8, and I got the issue in CI too, so probably not a cache issue, but I'll try clearing the cache locally tomorrow. Please note that I get a TokenStorage object, but the token inside is null – greg0ire Apr 11 '16 at 20:26
  • @chalasr : I found a solution : inject the token storage properly, with the admin constructor. Otherwise, I think symfony does not "see" the dependency and does not build the service properly. – greg0ire Apr 12 '16 at 09:53
  • @greg0ire Glad to hear that! For a lot of 3rd party bundles, this service has been configured through hacks In compiler passes and bundle extension in order to keep the compatibility with versions < 2.6, so it surely need to be explicitly set in your sonata+sf versions – chalasr Apr 12 '16 at 09:57
  • I posted an answer below (below for the moment ;) ) – greg0ire Apr 12 '16 at 10:02
8

Starting with symfony 2.8, you should use security.token_storage instead of security.context to retrieve the user. Use constructor injection to get it in your admin:

public function __construct(
    $code,
    $class,
    $baseControllerName,
    TokenStorageInterface $tokenStorage
) {
    parent::__construct($code, $class, $baseControllerName);
    $this->tokenStorage = $tokenStorage;
}

admin.yml :

    arguments:
        - ~
        - Your\Entity
        - ~
        - '@security.token_storage'

then use $this->tokenStorage->getToken()->getUser() to get the current user.

greg0ire
  • 22,714
  • 16
  • 72
  • 101
1

I was dealing with this issue on the version 5.3.10 of symfony and 4.2 of sonata. The answer from greg0ire was really helpful, also this info from symfony docs, here is my approach:

In my case I was trying to set a custom query based on a property from User.

// ... 
use Symfony\Component\Security\Core\Security;

final class YourClassAdmin extends from AbstractAdmin {
    // ... 
    private $security;
    public function __construct($code, $class, $baseControllerName, Security $security)
    {
        parent::__construct($code, $class, $baseControllerName);
        // Avoid calling getUser() in the constructor: auth may not
        // be complete yet. Instead, store the entire Security object.
        $this->security = $security;
    }

    // customize the query used to generate the list
    protected function configureQuery(ProxyQueryInterface $query): ProxyQueryInterface 
    {
        $query = parent::configureQuery($query);
        $rootAlias = current($query->getRootAliases());
        // ..
        $user = $this->security->getUser();
        // ...    
        return $query;
    }

}
laviku
  • 531
  • 12
  • 32