8

How can I define a constructor in Symfony2 controller. I want to get the the logged in user data available in all the methods of my controller, Currently I do something like this in every action of my controller to get the logged in user.

$em = $this->getDoctrine()->getEntityManager("pp_userdata");
$user = $this->get("security.context")->getToken()->getUser();

I want to do it once in a constructor and make this logged in user available on all my actions

3 Answers 3

12

For a general solution for executing code before every controller action you can attach an event listener to the kernel.controller event like so:

<service id="your_app.listener.before_controller" class="App\CoreBundle\EventListener\BeforeControllerListener" scope="request">
    <tag name="kernel.event_listener" event="kernel.controller" method="onKernelController"/>
    <argument type="service" id="security.context"/>
</service>

Then in your BeforeControllerListener you will check the controller to see if it implements an interface, if it does, you will call a method from the interface and pass in the security context.

<?php

namespace App\CoreBundle\EventListener;

use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\Security\Core\SecurityContextInterface;
use App\CoreBundle\Model\InitializableControllerInterface;

/**
 * @author Matt Drollette <[email protected]>
 */
class BeforeControllerListener
{

    protected $security_context;

    public function __construct(SecurityContextInterface $security_context)
    {
        $this->security_context = $security_context;
    }

    public function onKernelController(FilterControllerEvent $event)
    {
        $controller = $event->getController();

        if (!is_array($controller)) {
            // not a object but a different kind of callable. Do nothing
            return;
        }

        $controllerObject = $controller[0];

        // skip initializing for exceptions
        if ($controllerObject instanceof ExceptionController) {
            return;
        }

        if ($controllerObject instanceof InitializableControllerInterface) {
            // this method is the one that is part of the interface.
            $controllerObject->initialize($event->getRequest(), $this->security_context);
        }
    }
}

Then, any controllers that you want to have the user always available you will just implement that interface and set the user like so:

use App\CoreBundle\Model\InitializableControllerInterface;

class DefaultController implements InitializableControllerInterface
{
    /**
     * Current user.
     *
     * @var User
     */
    private $user;

    /**
     * {@inheritdoc}
     */
    public function initialize(Request $request, SecurityContextInterface $security_context)
    {
        $this->user = $security_context->getToken()->getUser();
    }
// ....
}

The interface is nothing more than

namespace App\CoreBundle\Model;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\SecurityContextInterface;

interface InitializableControllerInterface
{
    public function initialize(Request $request, SecurityContextInterface $security_context);
}
Sign up to request clarification or add additional context in comments.

3 Comments

someone know the way to write the config in yaml? we use yaml, and I don't know how to add the argument . I read this: symfony.com/doc/current/cookbook/service_container/… as well with no help obviously
@Toskan you can just do something like: arguments: ["@em", "@some_service"]
app.listener.constructor_listener: class: AppBundle\EventListener\ConstructorListener scope: request arguments: - { type: service, id: security.context } tags: - { name: kernel.event_listener, event: kernel.controller, method: onKernelController } pastebin.com/NTySb68a
4

I'm runnig a bit late, but in a controller you can just access the user:

$this->getUser();

Should be working since 2.1

Comments

2

My approach to this was:

  1. Make an empty Interface InitializableControllerInterface
  2. Make event Listener for
namespace ACMEBundle\Event;

use Symfony\Component\HttpKernel\Event\FilterControllerEvent;

class ControllerConstructor
{
    public function onKernelController(FilterControllerEvent $event)
    {
        $controller = $event->getController();
        if (!is_array($controller)) {
            // not a object but a different kind of callable. Do nothing
            return;
        }

        $controllerObject = $controller[0];
        if ($controllerObject instanceof InitializableControllerInterface) {
            $controllerObject->__init($event->getRequest());
        }
    }
}
  1. In your controller add:
class ProfileController extends Controller implements
        InitializableControllerInterface
{
public function __init()
    {
$this->user = $security_context->getToken()->getUser();
}

And you will be able to get the $this->user in each action.

Regards

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.