diff --git a/components/http_foundation.rst b/components/http_foundation.rst index a12bc3a37f7..2a51a743c80 100644 --- a/components/http_foundation.rst +++ b/components/http_foundation.rst @@ -378,5 +378,405 @@ abstracts the hard work behind a simple API:: Session ------- -TBD -- This part has not been written yet as it will probably be refactored -soon in Symfony 2.1. +The Symfony2 HttpFoundation Component has a very powerful and flexible session +subsystem which is designed to provide session management through a simple +object-oriented interface using a variety of session storage drivers. + +Sessions are used via the simple :class:`Symfony\\Component\\HttpFoundation\\Session\\Session` +implementation of :class:`Symfony\\Component\\HttpFoundation\\Session\\SessionInterface` interface. + +Quick example:: + + use Symfony\\Component\\HttpFoundation\\Session\\Session; + + $session = new Session(); + $session->start(); + + // set and get session attributes + $session->set('name', 'Drak'); + $session->get('name'); + + // set and retrieve flash messages + $session->getFlashBag()->set('notice', 'Profile updated'); + + echo $session->getFlashBag()->get('notice'); + +Session API +~~~~~~~~~~~ + +The :class:`Symfony\\Component\\HttpFoundation\\Session\\Session` implements +:class:`Symfony\\Component\\HttpFoundation\\Session\\SessionInterface. + +The :class:`Symfony\\Component\\HttpFoundation\\Session\\Session` has a simple API +as follows divided into a couple of groups. + +Session workflow + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Session::start`: + Starts the session - do not use `session_start()`. + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Session::migrate`: + Starts the session - do not use `session_start()`. + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Session::invalidate`: + Starts the session - do not use `session_start()`. + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Session::getId`: Gets the + session ID. + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Session::setId`: Gets the + session ID. + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Session::getName`: Gets the + session name. + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Session::setName`: Sets the + session name. + +Session attributes + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Session::set`: + Sets an attribute by key; + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Session::get`: + Gets an attribute by key; + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Session::all`: + Gets all attributes as an array of key => value; + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Session::has`: + Returns true if the attribute exists; + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Session::keys`: + Returns an array of stored attribute keys; + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Session::replace`: + Sets multiple attributes at once: takes a keyed array and sets each key => value pair. + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Session::remove`: + Deletes an attribute by key; + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Session::clear`: + Clear the bag; + +Bag management + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Session::registerBag`: + Registers a `Symfony\\Component\\HttpFoundation\\Session\\SessionBagInterface` + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Session::getBag`: + Gets a `Symfony\\Component\\HttpFoundation\\Session\\SessionBagInterface` by + bag name. + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Session::getFlashBag`: + Gets the `Symfony\\Component\\HttpFoundation\\Session\\Flash\\FlashBagInterface`. + This is just a shortcut for convenience. + + + + +Save Handlers +~~~~~~~~~~~~~ + +The PHP session workflow has 6 possible operations that may occur. The normal +session follows `open`, `read`, `write` and `close`, with the possibility of +`destroy` and `gc` (garbage collection which will expire any old sessions: `gc` +is called randomly according to PHP's configuration and if called, it is invoked +after the `open` operation). You can read more about this at +http://php.net/session.customhandler + + +Native PHP Save Handlers +~~~~~~~~~~~~~~~~~~~~~~~~ + +So-called 'native' handlers, are session handlers which are either compiled into +PHP or provided by PHP extensions, such as PHP-Sqlite, PHP-Memcached and so on. +The handlers are compiled and can be activated directly in PHP using +`ini_set('session.save_handler', $name);` and are usually configured with +`ini_set('session.save_path', $path);` and sometimes, a variety of other PHP +`ini` directives. + +Symfony2 provides drivers for native handlers which are easy to configure, these are: + + * :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\NativeFileSessionHandler`; + * :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\NativeSqliteSessionHandler`; + * :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\NativeMemcacheSessionHandler`; + * :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\NativeMemcachedSessionHandler`; + +Example of use:: + + use Symfony\\Component\\HttpFoundation\\Session\\Session; + use Symfony\\Component\\HttpFoundation\\Session\\Storage\\NativeSessionStorage; + use Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\NativeMemcachedSessionHandler; + + $storage = new NativeSessionStorage(array(), new NativeMemcachedSessionHandler()); + $session = new Session($storage); + +Custom Save Handlers +~~~~~~~~~~~~~~~~~~~~ + +Custom handlers are those which completely replace PHP's built in session save +handlers by providing six callback functions which PHP calls internally at +various points in the session workflow. + +Symfony2 HttpFoudation provides some by default and these can easily serve as +examples if you wish to write your own. + + * :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\PdoSessionHandler`; + * :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\MemcacheSessionHandler`; + * :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\MemcachedSessionHandler`; + * :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\NullSessionHandler`; + +Example:: + + use Symfony\\Component\\HttpFoundation\\Session\\Session; + use Symfony\\Component\\HttpFoundation\\Session\\Storage\\SessionStorage; + use Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\PdoSessionHandler; + + $storage = new NativeSessionStorage(array(), new PdoSessionHandler()); + $session = new Session($storage); + +Session Bags +------------ + +PHP's session management requires the use of the `$_SESSION` super-global, +however, this interferes somewhat with code testability and encapsulation in a +OOP paradigm. To help overcome this Symfony2 uses 'session bags' linked to the +session to encapsulate a specific dataset like 'attributes' or 'flash messages'. + +This approach also mitigates namespace pollution within the `$_SESSION` +super-global because each bag stores all its data under a unique namespace. +This allows Symfony2 to peacefully co-exist with other applications or libraries +that might use the `$_SESSION` super-global and all data remains completely +compatible with Symfony2's session management. + +Symfony2 provides 2 kinds of bags, with two separate implementations. +Everything is written against interfaces so you may extend or create your own +bag types if necessary. + +:class:`Symfony\\Component\\HttpFoundation\\Session\\SessionBagInterface` has +the following API which is intended mainly for internal purposes: + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\SessionBagInterface::getStorageKey`: + Returns the key which the bag will ultimately store its array under in `$_SESSION`. + Generally this value can be left at its default and is for internal use. + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\SessionBagInterface::initialize`: + This is called internally by Symfony2 session storage classes to link bag data + to the session. + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\SessionBagInterface::getName`: + Returns the name of the session bag. + +Attributes +~~~~~~~~~~ + +The purpose of the bags implementing the :class:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBagInterface` +is to handle session attribute storage. This might include things like user ID, +and remember me login settings or other user based state information. + +* :class:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBag` + This is the standard default implementation. +* :class:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\NamespacedAttributeBag` + This implementation allows for attributes to be stored in a structured namespace. + +Any plain `key => value` storage system is limited in the extent to which +complex data can be stored since each key must be unique. You can achieve +namespacing by introducing a naming convention to the keys so different parts of +your application could operate without clashing. For example, `module1.foo` and +`module2.foo`. However, sometimes this is not very practical when the attributes +data is an array, for example a set of tokens. In this case, managing the array +becomes a burden because you have to retrieve the array then process it and +store it again. + + 'tokens' => array('a' => 'a6c1e0b6', + 'b' => 'f4a7b1f3') + +So any processing of this might quickly get ugly, even simply adding a token to +the array:: + + $tokens = $session->get('tokens'); + $tokens['c'] = $value; + $session->set('tokens', $tokens); + +With structured namespacing, the the key can be translated to the array +structure like this using a namespace character (defaults to `/`):: + + $session->set('tokens/c', $value); + +This way you can easily access a key within the stored array directly and easily. + +:class:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBagInterface` +has a simple API + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBagInterface::set`: + Sets an attribute by key; + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBagInterface::get`: + Gets an attribute by key; + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBagInterface::all`: + Gets all attributes as an array of key => value; + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBagInterface::has`: + Returns true if the attribute exists; + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBagInterface::keys`: + Returns an array of stored attribute keys; + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBagInterface::replace`: + Sets multiple attributes at once: takes a keyed array and sets each key => value pair. + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBagInterface::remove`: + Deletes an attribute by key; + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBagInterface::clear`: + Clear the bag; + +Flash messages +~~~~~~~~~~~~~~ + +The purpose of the :class:`Symfony\\Component\\HttpFoundation\\Session\\Flash\\FlashBagInterface` +is to provide a way of settings and retrieving messages on a per session basis. +The usual workflow for flash messages would be set in an request, and displayed +on page redirect. For example, a user submits a form which hits an update +controller, and after processing the controller redirects the page to either the +updated page or a error page. Flash messages set in the previous page request +would be displayed immediately on the subsequent page load for that session. +This is however just one application for flash messages. + +* :class:`Symfony\\Component\\HttpFoundation\\Session\\Flash\\AutoExpireFlashBag` + This implementation messages set in one page-load will + be available for display only on the next page load. These messages will auto + expire regardless of if they are retrieved or not. +* :class:`Symfony\\Component\\HttpFoundation\\Session\\Flash\\FlashBag` + In this implementation, messages will remain in the session until + they are explicitly retrieved or cleared. This makes it possible to use ESI + caching. + +:class:`Symfony\\Component\\HttpFoundation\\Session\\Flash\\FlashBagInterface` +has a simple API + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Flash\\FlashBagInterface::set`: + Sets a flash by type; + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Flash\\FlashBagInterface::get`: + Gets a flash by type and clears the flash from the bag; + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Flash\\FlashBagInterface::setAll`: + Sets an array of flashes by type => message; + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Flash\\FlashBagInterface::all`: + Gets all flashes and clears the flashes from the bag; + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Flash\\FlashBagInterface::peek`: + Gets a flash by type (read only); + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Flash\\FlashBagInterface::peekAll`: + Gets all flashes (readoly); + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Flash\\FlashBagInterface::has`: + Returns true if the type exists; + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Flash\\FlashBagInterface::keys`: + Returns an array of stored types; + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\Flash\\FlashBagInterface::clear`: + Clear the bag; + +Testability +----------- + +Symfony2 is designed from the ground up with code-testability in mind. In order +to make your code which utilises session easily testable we provide two separate +mock storage mechanisms for both unit testing and functional testing. + +Testing code using real sessions is tricky because PHP's workflow state is global +and it is not possible to have multiple concurrent sessions in the same PHP +process. + +The mock storage engines simulate the PHP session workflow without actually +starting one allowing you to test your code without complications. You may also +run multiple instances in the same PHP process. + +The mock storage drivers do not read or write the system globals +`session_id()` or `session_name()`. Methods are provided to simulate this if +required: + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\SessionStorageInterface::getId`: Gets the + session ID. + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\SessionStorageInterface::setId`: Gets the + session ID. + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\SessionStorageInterface::getName`: Gets the + session name. + +* :method:`Symfony\\Component\\HttpFoundation\\Session\\SessionStorageInterface::setName`: Sets the + session name. + +Unit Testing +~~~~~~~~~~~~ + +For unit testing where it is not necessary to persist the session, you should +simply swap out the default storage engine with +:class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\MockArraySessionStorage`:: + + use Symfony\\Component\\HttpFoundation\\Session\\Storage\\MockArraySessionStorage; + use Symfony\\Component\\HttpFoundation\\Session\\Session; + + $session = new Session(new MockArraySessionStorage()); + +Functional Testing +~~~~~~~~~~~~~~~~~~ + +For functional testing where you may need to persist session data across +separate PHP processes, simply change the storage engine to +:class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\MockFileSessionStorage`:: + + use Symfony\\Component\\HttpFoundation\\Session\\Session; + use Symfony\\Component\\HttpFoundation\\Session\\Storage\\MockFileSessionStorage; + + $session = new Session(new MockFileSessionStorage()); + +PHP 5.4 compatibility +~~~~~~~~~~~~~~~~~~~~~ + +Since PHP 5.4.0, :phpclass:`SessionHandler` and :phpclass:`SessionHandlerInterface` +are available. Symfony 2.1 provides forward compatibility for the :phpclass:`SessionHandlerInterface` +so it can be used under PHP 5.3. This greatly improves inter-operability with other +libraries. + +:phpclass:`SessionHandler` is a special PHP internal class which exposes native save +handlers to PHP user-space. + +In order to provide a solution for those using PHP 5.4, Symfony2 has a special +class called :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\NativeSessionHandler` +which under PHP 5.4, extends from `\SessionHandler` and under PHP 5.3 is just a +empty base class. This provides some interesting opportunities to leverage +PHP 5.4 functionality if it is available. + +Save Handler Proxy +~~~~~~~~~~~~~~~~~~ + +There are two kinds of save handler classes proxy which inherit from +:class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\AbstractProxy`, +they are :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\NativeProxy` +and :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\SessionHandlerProxy`. + +:class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\NativeSessionStorage` +automatically injects storage handlers into a save handler proxy unless already +wrapped by one. + +:class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\NativeProxy` +is used automatically under PHP 5.3 when internal PHP save handlers are specified +using the `Native*SessionHandler` classes, while +:class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\SessionHandlerProxy` +will be used to wrap any custom save handlers, that implement :phpclass:`SessionHandlerInterface`. + +Under PHP 5.4 and above, all session handlers implement :phpclass:`SessionHandlerInterface` +including `Native*SessionHandler` classes which inherit from :phpclass:`SessionHandler`. + +The proxy mechanism allow you to get more deeply involved in session save handler +classes. A proxy for example could be used to encrypt any session transaction +without knowledge of the specific save handler.
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: