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

    }
}
 

Tuesday, May 13, 2014

Doctrine2 optimization with APC cache and Symfony2

Some parts of a website are common to every pages and needs to request data from database. To put this data in a cache system is often a first step for optimization. Here is my return on experience about caching data with Doctrine2 in a Symfony2 project.


Before caching data, deal with metadata

Doctrine metadata store informations about entities structure, relations and so on. It's really safe to put in cache memory because it's nearly never changed. Have a look to the config in app/config/config_prod.yml :

# Doctrine Configuration
doctrine:
    dbal:
        ...
    orm:
        metadata_cache_driver: apc

(Still) Before caching data, deal with queries

Doctrine2 uses DQL, its own meta language to generate SQL queries. When you use a QueryBuilder or directly writes your queries in DQL, SQL query is generated each time data are requested. Next config allows Doctrine2 to put generated SQL in cache too. Have a look to the config in app/config/config_prod.yml :

# Doctrine Configuration
doctrine:
    dbal:
        ...
    orm:
        metadata_cache_driver: apc
        query_cache_driver: apc

Finally caching data !

Tuesday, April 22, 2014

Trace IP with Gedmo IpTraceable behavior

As a strong user of Doctrine2 since I'm working with Symfony2, I also use Gedmo DoctrineExtensions. This library provides a great set of useful features we commonly need when developping web project :
  • Timestampable entities (created_at and updated_at columns on tables),
  • Sluggable entities,
  • Trace creators and modificators on contents (Blameable behavior)
  • ...
Since I more often work for sensitive e-commerce project, I needed a feature to trace IPs on some data (mainly orders and payments). So I decided to develop this functionality, based on existing work from Timestampable and Blameable in Gedmo DoctrineExtensions.

This is called IpTraceable and it is well explained in the Github repository documentation.

Symfony bundle implementation is under merge review in Stof DoctrineExtensionsBundle project, and you can use it with your own listener yet. Feel free to comment and add your support to  this PR on github : http://github.com/stof/StofDoctrineExtensionsBundle/pull/233