Symfony automatically manages user sessions and is able to keep persistent data between requests for users. It uses the built-in PHP session-handling mechanisms and enhances them to make them more configurable and easier to use.

6.4.1. Accessing the User Session

The session object for the current user is accessed in the action with the getUser() method and is an instance of the sfUser class. This class contains a parameter holder that allows you to store any user attribute in it. This data will be available to other requests until the end of the user session, as shown in Listing 6-15. User attributes can store any type of data (strings, arrays, and associative arrays). They can be set for every individual user, even if that user is not identified.

Listing 6-15 - The sfUser Object Can Hold Custom User Attributes Existing Across Requests

class mymoduleActions extends sfActions
{
  public function executeFirstPage($request)
  {
    $nickname = $request->getParameter('nickname');

    // Store data in the user session
    $this->getUser()->setAttribute('nickname', $nickname);
  }

  public function executeSecondPage()
  {
    // Retrieve data from the user session with a default value
    $nickname = $this->getUser()->getAttribute('nickname', 'Anonymous Coward');
  }
}

Caution You can store objects in the user session, but it is strongly discouraged. This is because the session object is serialized between requests. When the session is deserialized, the class of the stored objects must already be loaded, and that's not always the case. In addition, there can be "stalled" objects if you store Propel objects.

Like many getters in symfony, the getAttribute() method accepts a second argument, specifying the default value to be used when the attribute is not defined. To check whether an attribute has been defined for a user, use the hasAttribute() method. The attributes are stored in a parameter holder that can be accessed by the getAttributeHolder() method. It allows for easy cleanup of the user attributes with the usual parameter holder methods, as shown in Listing 6-16.

Listing 6-16 - Removing Data from the User Session

class mymoduleActions extends sfActions
{
  public function executeRemoveNickname()
  {
    $this->getUser()->getAttributeHolder()->remove('nickname');
  }

  public function executeCleanup()
  {
    $this->getUser()->getAttributeHolder()->clear();
  }
}

The user session attributes are also available in the templates by default via the $sf_user variable, which stores the current sfUser object, as shown in Listing 6-17.

Listing 6-17 - Templates Also Have Access to the User Session Attributes

<p>
  Hello, <?php echo $sf_user->getAttribute('nickname') ?>
</p>

Note If you need to store information just for the duration of the current request — for instance, to pass information through a chain of action calls — you may prefer the sfRequest class, which also has getAttribute() and setAttribute() methods. Only the attributes of the sfUser object are persistent between requests.

6.4.2. Flash Attributes

A recurrent problem with user attributes is the cleaning of the user session once the attribute is not needed anymore. For instance, you may want to display a confirmation after updating data via a form. As the form-handling action makes a redirect, the only way to pass information from this action to the action it redirects to is to store the information in the user session. But once the confirmation message is displayed, you need to clear the attribute; otherwise, it will remain in the session until it expires.

The flash attribute is an ephemeral attribute that you can define and forget, knowing that it will disappear after the very next request and leave the user session clean for the future. In your action, define the flash attribute like this:

$this->getUser()->setFlash('notice', $value);

The template will be rendered and delivered to the user, who will then make a new request to another action. In this second action, just get the value of the flash attribute like this:

$value = $this->getUser()->getFlash('notice');

Then forget about it. After delivering this second page, the notice flash attribute will be flushed. And even if you don't require it during this second action, the flash will disappear from the session anyway.

If you need to access a flash attribute from a template, use the $sf_user object:

<?php if ($sf_user->hasFlash('notice')): ?>
  <?php echo $sf_user->getFlash('notice') ?>
<?php endif; ?>

or just:

<?php echo $sf_user->getFlash('notice') ?>

Flash attributes are a clean way of passing information to the very next request.

6.4.3. Session Management

Symfony's session-handling feature completely masks the client and server storage of the session IDs to the developer. However, if you want to modify the default behaviors of the session-management mechanisms, it is still possible. This is mostly for advanced users.

On the client side, sessions are handled by cookies. The symfony session cookie is called symfony, but you can change its name by editing the factories.yml configuration file, as shown in Listing 6-18.

Listing 6-18 - Changing the Session Cookie Name, in apps/frontend/config/factories.yml

all:
  storage:
    class: sfSessionStorage
    param:
      session_name: my_cookie_name

Tip The session is started (with the PHP function session_start()) only if the auto_start parameter is set to true in factories.yml (which is the case by default). If you want to start the user session manually, disable this setting of the storage factory.

Symfony's session handling is based on PHP sessions. This means that if you want the client-side management of sessions to be handled by URL parameters instead of cookies, you just need to change the use_trans_sid setting in your php.ini. Be aware that this is not recommended.

session.use_trans_sid = 1

On the server side, symfony stores user sessions in files by default. You can store them in your database by changing the value of the class parameter in factories.yml, as shown in Listing 6-19.

Listing 6-19 - Changing the Server Session Storage, in apps/frontend/config/factories.yml

all:
  storage:
    class: sfMySQLSessionStorage
    param:
      db_table:    session              # Name of the table storing the sessions
      database:    propel               # Name of the database connection to use
      # Optional parameters
      db_id_col:   sess_id              # Name of the column storing the session id
      db_data_col: sess_data            # Name of the column storing the session data
      db_time_col: sess_time            # Name of the column storing the session timestamp

The database setting defines the database connection to be used. Symfony will then use databases.yml (see Chapter 8) to determine the connection settings (host, database name, user, and password) for this connection.

The available session storage classes are sfMySQLSessionStorage, sfMySQLiSessionStorage, sfPostgreSQLSessionStorage, and sfPDOSessionStorage; the latter is preferred. To disable session storage completely, you can use the sfNoStorage class.

Session expiration occurs automatically after 30 minutes. This default setting can be modified for each environment in the same factories.yml configuration file, but this time in the user factory, as shown in Listing 6-20.

Listing 6-20 - Changing Session Lifetime, in apps/frontend/config/factories.yml

all:
  user:
    class:       myUser
    param:
      timeout:   1800           # Session lifetime in seconds

To learn more about factories, refer to Chapter 19.