Friday, October 10, 2014

Redirection after registration

Symfony Security bundle provides everything to deal with redirections after login. The most used is based on referer as many pages may require an authentication, and this way you just redirect to the pages that asked for identification. But what happens when user has no account, he needs to register and create its account. Here is a proper way to achieve redirection after registration, dealing with multiple firewalls sharing a common context

This solution implies that all your firewalls are named like {name}_area.

 
class RegistrationController
{

    protected function getFirewallCallingForAuthentication()
    {
        $session = $this->get('session');

        $firewall = null;

        $securityKeys = array_filter(array_keys($session->all()), function ($key) {
            return preg_match('/^_security\.[\w]+_area\.target_path$/', $key);
        });
        $securityKey = empty($securityKeys) ? null : end($securityKeys);

        if ($securityKey) {
            $matches = [];
            $match = preg_match('/^_security\.([\w]+_area)\.target_path$/', $securityKey, $matches);

            if (isset($matches[1])) {
                $firewall = $matches[1];
            }
        }

        return $firewall;
    }

    // ...

    public function registrationAction()
    {

        // Get firewall name
        $firewallCallingForAuth = $this->getFirewallCallingForAuthentication();

        // ... prepare form ...

        $form->handleRequest($request);

        if ($form->isValid()) {

            // ... process registration, account creation, flash message, etc ...

            // Programmatically log user
            $token = new UsernamePasswordToken($user, null, $firewallCallingForAuth, $user->getRoles());
            $this->get('security.context')->setToken($token);

            // Redirects to the last _security.{firewall}.target_path found in session
            //  (last attempt of visiting a page protected by firewall requiring authentication)
            if (isset($firewallCallingForAuth)) {
                $redirectUrl = $session->get('_security.' . $firewallCallingForAuth . '.target_path');
                return $this->redirect($redirectUrl);
            } else {
                return $this->redirect($this->generateUrl('route_to_account_index'));
            }
        }

        // ... return Response

    }
}