0
votes

I try to set the current authenticated user within a SonataAdminBundle Form:

protected function configureFormFields(FormMapper $formMapper)
{
    $formMapper
    ->add('title')
    ->add('content')
    ->add('slug')
    //->add('user')
    ;
}

Since I don't want the user to select/choose it's own user, I guess I'd like to set the username during the procedure the form was sent by the user (without any user object). (Note: I'd like to use this in a couple of forms, so I'll need a general solution.)

What I've done now was setting up an EventListener after I've read this: http://symfony.com/doc/current/cookbook/service_container/event_listener.html

class PostListener
{
    protected $container;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }


    public function prePersist(LifeCycleEventArgs $args)
    {
        $entity = $args->getEntity();

        //Get user
        $securityContext = $this->container->get('security.context');
        $user = $securityContext->getToken()->getUser();

        //Set authenticated user as autor
        $entity->setUser($user);
    }
}

Including service:

post.listener:
  class: Backender\BlogBundle\Listener\PostListener
  calls:
    - [ setContainer, [ @service_container ] ]
  tags:
    - { name: doctrine.event_listener, event: prePersist }

Not sure now, if this is the right approach, because I wan't to specify the form where I want to set the user. (This one will want to set user on every form right?)

With some more research it seems like I've to use an Event Subscriber like this: http://symfony.com/doc/2.0/cookbook/form/dynamic_form_generation.html In this example they use FormEvents::PRE_SET_DATA, I guess in my case I have to use POST_SET_DATA.

Here I've some problems!:

1: I'm quiet new to SonataAdminBundle and there we use protected function configureFormFields(FormMapper $formMapper)... where ->addEventSubscriber() isn't available?

2: Is this the right way?, I really didn't find any examples like what I need here for sonata-admin.

I'm thankful for every help! Best regards...

3

3 Answers

5
votes

Try with $formMapper->getFormBuilder()->addEventSubscriber($subscriber);

1
votes

In the end I found 2 possible solutions for my problem. I'd like to describe these possibilities here because there isn't that much stuff to find about.

Event listener with query of instance of Call as service:

   blog.post.listener:
      class: Acme\BlogBundle\Listener\PostListener
      arguments: ['@service_container']
      tags: 
        - { name: doctrine.event_listener, event: prePersist }

The listener class:

class PostListener
{
    protected $container;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }


    public function prePersist(LifeCycleEventArgs $args)
    {
        $entity = $args->getEntity();

        //Get user
        $securityContext = $this->container->get('security.context');
        $user = $securityContext->getToken()->getUser();

        if ($entity instanceof Post) {

            //Set authenticated user as autor
            $entity->setUser($user);

        }
    }
}

The second way (and maybe the easier) is to use prePersist in Admin Class of SonataAdminBundle

Call as service (use service container or security context as argument):

blog.admin.post:
  class: Acme\BlogBundle\Admin\PostAdmin
  tags:
    - { name: sonata.admin, manager_type: orm, group: Article Handling, label: Posts }
  arguments: [null, Acme\BlogBundle\Entity\Post, SonataAdminBundle:CRUD, @service_container]

PostAdmin: (Note, i use container because i need further stuff in the future)

class PostAdmin extends Admin
{
    protected $securityContext;

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

    protected function configureFormFields(FormMapper $formMapper)
    {
        $formMapper
        ->add('title')
        ->add('content')
        ;

    }


    public function prePersist($post)
    {
        $user = $this->container->get('security.context')->getToken()->getUser();
        $post->setUser($user);
    }

}
0
votes

I solved adding events to the Admin Class by injecting the Event Dispatcher:

    <service id="acme.listener.contract"
             class="Acme\AppBundle\Event\ContractListener">
         <argument type="service" id="twig"></argument>   
         <argument type="service" id="mailer"></argument>   
        <tag name="kernel.event_listener" event="contract.created" method="onContractCreated" />
    </service>

Then in my admin class I add the event to an existing method:

use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Security\Core\SecurityContextInterface;

class ContractAdmin extends Admin
{
    protected $dispatcher;

/**
 * Security Context
 * @var \Symfony\Component\Security\Core\SecurityContextInterface
 */
protected $securityContext;

public function setEventDispatcher(EventDispatcherInterface $dispatcher)
{
    $this->dispatcher = $dispatcher;
}

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

public function prePersist($contract)
{
    $user = $this->securityContext->getToken()->getUser();
    $contract->setUser($user);

    $event = new ContractEvent($contract);

    $dispatcher = $this->dispatcher;
    $dispatcher->dispatch(
        ContractEvents::CONTRACT_CREATED,
        $event
    );
}

This allows me to add extra events I am sharing across my app at other places too.

In your case you can simply inject the Security Context only:

    sonata.admin.contract:
    class: Acme\AppBundle\Admin\ContractAdmin
    tags:
        - { name: sonata.admin, manager_type: orm, group: "Contracts", label_catalogue: "messages", label: "Auftragsübersicht" }
    arguments:
        - ~
        - Acme\AppBundle\Entity\Contract
        - ~         
    calls:
        - [ setSecurityContext, [@security.context]]
        - [ setEventDispatcher, [@event_dispatcher]]