@@ -378,5 +378,230 @@ abstracts the hard work behind a simple API::
378
378
Session
379
379
-------
380
380
381
- TBD -- This part has not been written yet as it will probably be refactored
382
- soon in Symfony 2.1.
381
+ The Symfony2 HttpFoundation Component has a very powerful and flexible session
382
+ subsystem which is designed to provide session management through a simple
383
+ object-oriented interface using a variety of session storage drivers.
384
+
385
+ Quick example:
386
+
387
+ use Symfony\\ Component\\ HttpFoundation\\ Session\\ Session;
388
+
389
+ $session = new Session();
390
+ $session->start();
391
+
392
+ // set and get session attributes
393
+ $session->set('name', 'Drak');
394
+ $session->get('name');
395
+
396
+ // set and retrieve flash messages
397
+ $session->getFlashBag()->set('notice', 'Profile updated');
398
+
399
+ echo $session->getFlashBag()->get('notice');
400
+
401
+ Save Handlers
402
+ ~~~~~~~~~~~~~
403
+
404
+ The PHP session workflow has 6 possible operations that may occur. The normal
405
+ session follows `open `, `read `, `write ` and `close `, with the possibility of
406
+ `destroy ` and `gc ` (garbage collection which will expire any old sessions: `gc `
407
+ is called randomly according to PHP's configuration and if called, it is invoked
408
+ after the `open ` operation). You can read more about this at
409
+ http://php.net/session.customhandler
410
+
411
+ Native PHP Save Handlers
412
+ ~~~~~~~~~~~~~~~~~~~~~~~~
413
+
414
+ So-called 'native' handlers are session handlers are either compiled into PHP or
415
+ provided by PHP extensions, such as PHP-Sqlite, PHP-Memcached and so on. The
416
+ handlers are compiled and can be activated directly in PHP using
417
+ `ini_set('session.save_handler', $name); ` and are usually configured with
418
+ `ini_set('session.save_path', $path); ` and sometimes, a variety of other PHP
419
+ `ini ` directives.
420
+
421
+ Symfony2 provides drivers for native handlers which are easy to configure, these are:
422
+
423
+ * `Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\NativeFileSessionHandler `
424
+ * `Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\NativeSqliteSessionHandler `
425
+ * `Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\NativeMemcacheSessionHandler `
426
+ * `Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\NativeMemcachedSessionHandler `
427
+
428
+ Example of use:
429
+
430
+ use Symfony\\ Component\\ HttpFoundation\\ Session\\ Session;
431
+ use Symfony\\ Component\\ HttpFoundation\\ Session\\ Storage\\ NativeSessionStorage;
432
+ use Symfony\\ Component\\ HttpFoundation\\ Session\\ Storage\\ Handler\\ NativeMemcachedSessionHandler;
433
+
434
+ $storage = new NativeSessionStorage(array(), new NativeMemcachedSessionHandler());
435
+ $session = new Session($storage);
436
+
437
+ Custom Save Handlers
438
+ ~~~~~~~~~~~~~~~~~~~~
439
+
440
+ Custom handlers are those which completely replace PHP's built in session save
441
+ handlers by providing six callback functions which PHP calls internally at
442
+ various points in the session workflow.
443
+
444
+ Symfony2 HttpFoudation provides some by default and these can easily serve as
445
+ examples if you wish to write your own.
446
+
447
+ * `Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\PdoSessionHandler `
448
+ * `Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\MemcacheSessionHandler `
449
+ * `Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\MemcachedSessionHandler `
450
+ * `Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\NullSessionHandler `
451
+
452
+ Example:
453
+
454
+ use Symfony\\ Component\\ HttpFoundation\\ Session\\ Session;
455
+ use Symfony\\ Component\\ HttpFoundation\\ Session\\ Storage\\ SessionStorage;
456
+ use Symfony\\ Component\\ HttpFoundation\\ Session\\ Storage\\ Handler\\ PdoSessionHandler;
457
+
458
+ $storage = new NativeSessionStorage(array(), new PdoSessionHandler());
459
+ $session = new Session($storage);
460
+
461
+ Session Bags
462
+ ------------
463
+
464
+ PHP's session management requires the use of the `$_SESSION ` super-global,
465
+ however, this interferes somewhat with code testability and encapsulation in a
466
+ OOP paradigm. To help overcome this Symfony2 uses 'session bags' linked to the
467
+ session to encapsulate a specific dataset like 'attributes' or 'flash messages'.
468
+
469
+ This approach also mitigates namespace pollution within the `$_SESSION `
470
+ super-global because each bag stores all it's data under a unique namespace.
471
+ This allows Symfony2 to peacefully co-exist with other applications or libraries
472
+ that might use the `$_SESSION ` super-global and all data remains completely
473
+ compatible with Symfony2's session management.
474
+
475
+ Symfony2 provides 2 kinds of bags, with two separate implementations.
476
+ Everything is written against interfaces so you may extend or create your own
477
+ bag types if necessary.
478
+
479
+ Attributes
480
+ ~~~~~~~~~~
481
+
482
+ The purpose of the bags implementing the `AttributeBagInterface ` is to handle
483
+ session attribute storage. This might include things like user ID, and remember
484
+ me login settings or other user based state information.
485
+
486
+ * `AttributeBag ` - this is the standard default implementation.
487
+ * `NamespacedAttributeBag ` - this implementation allows for attributes to be
488
+ stored in a structured namespace.
489
+
490
+ Any plain `key => value ` storage system is limited in the extent to which
491
+ complex data can be stored since each key must be unique. You can achieve
492
+ namespacing by introducing a naming convention to the keys so different parts of
493
+ your application could operate without clashing. For example, `module1.foo ` and
494
+ `module2.foo `. However, sometimes this is not very practical when the attributes
495
+ data is an array, for example a set of tokens. In this case, managing the array
496
+ becomes a burden because you have to retrieve the array then process it and
497
+ store it again.
498
+
499
+ 'tokens' => array('a' => 'a6c1e0b6',
500
+ 'b' => 'f4a7b1f3')
501
+
502
+ So any processing of this might quickly get ugly, even simply adding a token to
503
+ the array:
504
+
505
+ $tokens = $session->get('tokens');
506
+ $tokens['c'] = $value;
507
+ $session->set('tokens', $tokens);
508
+
509
+ With structured namespacing, the the key can be translated to the array
510
+ structure like this using a namespace character (defaults to `/ `).
511
+
512
+ $session->set('tokens/c', $value);
513
+
514
+ This way you can easily access a key within the stored array directly and easily.
515
+
516
+ Flash messages
517
+ ~~~~~~~~~~~~~~
518
+
519
+ The purpose of the `FlashBagInterface ` is to provide a way of settings and
520
+ retrieving messages on a per session basis. The usual workflow for flash
521
+ messages would be set in an request, and displayed on page redirect. For
522
+ example, a user submits a form which hits an update controller, and after
523
+ processing the controller redirects the page to either the updated page or a
524
+ error page. Flash messages set in the previous page request would be displayed
525
+ immediately on the subsequent page load for that session. This is however just
526
+ one application for flash messages.
527
+
528
+ * `AutoExpireFlashBag ` - This implementation messages set in one page-load will
529
+ be available for display only on the next page load. These messages will auto
530
+ expire regardless of if they are retrieved or not.
531
+ * `FlashBag ` - In this implementation, messages will remain in the session until
532
+ they are explicitly retrieved or cleared. This makes it possible to use ESI
533
+ caching.
534
+
535
+ Testability
536
+ -----------
537
+
538
+ Symfony2 is designed from the ground up with code-testability in mind. In order
539
+ to make your code which utilises session easily testable we provide two separate
540
+ mock storage mechanisms for both unit testing and functional testing.
541
+
542
+ Testing code using real sessions is trick because PHP's workflow state is global
543
+ and it is not possible to have multiple concurrent sessions in the same PHP
544
+ process.
545
+
546
+ The mock storage engines simulate the PHP session workflow without actually
547
+ starting one allowing you to test your code without complications. You may also
548
+ run multiple instances in the same PHP process.
549
+
550
+ The only caveat, `session_id() ` is global, so the session ID should be read
551
+ using `$session->getId() ` but generally this is of no relevance during testing.
552
+
553
+ Unit Testing
554
+ ~~~~~~~~~~~~
555
+
556
+ For unit testing where it is not necessary to persist the session, you should
557
+ simply swap out the default storage engine with
558
+ `Symfony\\Component\\HttpFoundation\\Session\\Storage\\MockArraySessionStorage `.
559
+
560
+ use Symfony\\ Component\\ HttpFoundation\\ Session\\ Storage\\ MockArraySessionStorage;
561
+ use Symfony\\ Component\\ HttpFoundation\\ Session\\ Session;
562
+
563
+ $session = new Session(new MockArraySessionStorage());
564
+
565
+ Functional Testing
566
+ ~~~~~~~~~~~~~~~~~~
567
+
568
+ For functional testing where you may need to persist session data across
569
+ separate PHP processes, simply change the storage engine to
570
+ `Symfony\\Component\\HttpFoundation\\SessionMockFileSessionStorage `.
571
+
572
+ use Symfony\\ Component\\ HttpFoundation\\ Session\\ Session;
573
+ use Symfony\\ Component\\ HttpFoundation\\ Session\\ Storage\\ MockFileessionStorage;
574
+
575
+ $session = new Session(new MockFileSessionStorage());
576
+
577
+ PHP 5.4 compatibility
578
+ ~~~~~~~~~~~~~~~~~~~~~
579
+
580
+ Since PHP 5.4.0, `\SessionHandler ` and `\SessionHandlerInterface ` are available.
581
+ Symfony 2.1 provides forward compatibility for the `\SessionHandlerInterface ` so
582
+ it can be used under PHP 5.3. This greatly improves inter-operability with other
583
+ libraries.
584
+
585
+ `\SessionHandler ` is a special PHP internal class which exposes native save
586
+ handlers to PHP user-space. You can read more about it at
587
+ http://php.net/sessionhandler.
588
+
589
+ In order to provide a solution for those using PHP 5.4, Symfony2 has a special
590
+ class called `Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\NativeSessionHandler `
591
+ which under PHP 5.4, extends from `\SessionHandler ` and under PHP 5.3 is just a
592
+ empty base class. This provides some interesting opportunities to leverage
593
+ PHP 5.4 functionality if it is available.
594
+
595
+ Handler Proxy
596
+ ~~~~~~~~~~~~~
597
+
598
+ `SessionStorage ` injects storage handlers into a handler proxy. The reason for
599
+ this is that under PHP 5.4, all handlers implement `\SessionHandlerInterface `
600
+ including native handlers (those which activate internal PHP/PHP-extension
601
+ handlers. Native handlers under PHP 5.4 will be children of
602
+ `\SessionHandler ` which allows one to intercept and modify even native session
603
+ handlers.
604
+
605
+ In order to manage all of this, Symfony2 uses a proxy handler object. It means
606
+ that you could write a single adapter, that for example encrypts the session
607
+ data, and it will work regardless of the save handler in use, custom, or native.
0 commit comments