Skip to content

Commit

Permalink
[Framework] added a new Session component.
Browse files Browse the repository at this point in the history
  • Loading branch information
Hugo Hamon committed Jan 18, 2016
1 parent af0824e commit 3a130df
Show file tree
Hide file tree
Showing 10 changed files with 582 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@
/coverage
!/app/cache/.gitkeep
/app/cache
!/app/sessions/.gitkeep
/app/sessions
/app/config/settings.yml
88 changes: 88 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1121,6 +1121,94 @@ Dans l'application de blog, des instances des classes `ErrorHandler` et
comme écouteurs de l'événement `kernel.exception`. Le répartiteur d'événements
est quant à lui enregistré comme service dans le registre de services.

### Le Composant `Session`

Le composant `Session` fournit une fine couche d'abstraction par dessus le
mécanisme de session de base de PHP. Grâce à cette abstraction, il est désormais
plus facile d'adapter le stockage des données de la session utilisateur dans
différentes technologies : système de fichier, Redis, Memcached, APC, etc.

La classe `Framework\Session\Session` agit comme une sorte de façade et offre
une API simplifiée pour manipuler la session. Cette classe implémente le contrat
de l'interface `Framework\Session\SessionInterface` qui définit des méthodes
publiques pour démarrer la session, la détruire, stocker des valeurs à
l'intérieur ou bien récupérer ces dernières.

```php
namespace Framework\Session;
interface SessionInterface
{
/**
* Starts the session.
*
* @return bool True if the session is already started, false otherwise
*/
public function start();
/**
* Destroys the session.
*
* @return bool True if the session was correctly destroyed, false otherwise.
*/
public function destroy();
/**
* Stores new data into the session.
*
* @param string $key The session variable name
* @param mixed $value The session variable value (must be serializable at some point)
*
* @return bool True if succeeded, false otherwise.
*/
public function store($key, $value);
/**
* Fetches a data from the session.
*
* @param string $key The session variable name
* @param mixed $default The default value to return
*
* @return mixed|null
*/
public function fetch($key, $default = null);
/**
* Returns the session's unique identifier.
*
* @return string
*/
public function getId();
/**
* Saves the session data to the persistent storage.
*
* @return bool True if successful, false otherwise
*/
public function save();
}
```
Pour implémenter complètement ce contrat, la classe `Session` dépend d'un
adaptateur de système de stockage. Il s'agit d'un objet qui répond au contrat de
l'interface `Framework\Session\Driver\DriverInterface`. Cette définit les
méthodes publiques qui permettent de manipuler le système de stockage des
données et offrir une abstraction des fonctions natives de PHP de manipulation
des fichiers, de bases de données ou bien de cache clé/valeur comme Redis, APCu
ou Memcached.

Le composant vient avec deux implémentations par défaut de cette interface. La
première est la classe `ArrayDriver`. Son usage est uniquement réservé aux tests
unitaires puisque cet objet simule une session non persistente dans un tableau
de données. C'est la raison pour laquelle sa documentation d'API utilise le
marqueur `@internal` pour signifier son usage strictement interne. La seconde
implémentation de la `DriverInterface` est la classe `NativeDriver`. Il s'agit
d'une classe qui encapsule les appels au système natif de gestion des sessions
de PHP.

> Dans l'application du blog suivant le principe MVC, la classe `Session` est
> définie dans le registre de services comme un service configuré avec son
> adaptateur natif.

Application de Blog suivant le patron MVC
-----------------------------------------

Expand Down
10 changes: 10 additions & 0 deletions bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
use Framework\Routing\Loader\PhpFileLoader;
use Framework\Routing\Loader\XmlFileLoader;
use Framework\ServiceLocator\ServiceLocator;
use Framework\Session\Driver\NativeDriver;
use Framework\Session\Session;
use Framework\Templating\TwigRendererAdapter;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
Expand All @@ -37,6 +39,10 @@
'debug' => true,
]);
$dic->setParameter('logger.log_file', __DIR__.'/app/cache/app.log');
$dic->setParameter('session.options', [
'session.name' => 'lpdim2016',
'session.save_path' => __DIR__.'/app/sessions',
]);

$dic->register('repository.blog_post', function (ServiceLocator $dic) {
return new BlogPostRepository($dic->getService('database'));
Expand Down Expand Up @@ -78,6 +84,10 @@
);
});

$dic->register('session', function (ServiceLocator $dic) {
return new Session(new NativeDriver(), $dic->getParameter('session.options'));
});

$dic->register('logger', function (ServiceLocator $dic) {
$level = $dic->getParameter('app.debug') ? Logger::WARNING : Logger::CRITICAL;

Expand Down
50 changes: 50 additions & 0 deletions src/Framework/Session/Driver/ArrayDriver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace Framework\Session\Driver;

/**
* This class is only used for unit tests.
*
* @internal
*/
class ArrayDriver implements DriverInterface
{
private $data;

public function __construct()
{
$this->data = [];
}

public function clear($id)
{
if (isset($this->data[$id])) {
unset($this->data[$id]);

return true;
}

return false;
}

public function store($id, $key, $value)
{
$this->data[$id][$key] = $value;

return true;
}

public function fetch($id, $key, $default = null)
{
if (isset($this->data[$id][$key])) {
return $this->data[$id][$key];
}

return $default;
}

public function save($id)
{
return true;
}
}
8 changes: 8 additions & 0 deletions src/Framework/Session/Driver/DriverException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Framework\Session\Driver;

class DriverException extends \RuntimeException
{

}
54 changes: 54 additions & 0 deletions src/Framework/Session/Driver/DriverInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

namespace Framework\Session\Driver;

interface DriverInterface
{
/**
* Clear session data.
*
* @param string $id The unique session ID
*
* @return bool True if successful, false otherwise
*
* @throws DriverException
*/
public function clear($id);

/**
* Stores new data into the session.
*
* @param string $id The unique session ID
* @param string $key The session variable name
* @param mixed $value The session variable value (must be serializable at some point)
*
* @return bool True if succeeded, false otherwise.
*
* @throws DriverException
*/
public function store($id, $key, $value);

/**
* Fetches data from the session.
*
* @param string $id The unique session ID
* @param string $key The session variable name
* @param mixed $default The default value to return
*
* @return mixed|null
*
* @throws DriverException
*/
public function fetch($id, $key, $default = null);

/**
* Saves the session data to the persistent storage.
*
* @param string $id The unique session ID
*
* @return bool True if succeeded, false otherwise.
*
* @throws DriverException
*/
public function save($id);
}
58 changes: 58 additions & 0 deletions src/Framework/Session/Driver/NativeDriver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

namespace Framework\Session\Driver;

class NativeDriver implements DriverInterface
{
const DEFAULT_NS = 'FKNS';

private $namespace;
private $allowOverride;

public function __construct($allowOverride = true, $namespace = self::DEFAULT_NS)
{
$this->allowOverride = (bool) $allowOverride;
$this->namespace = $namespace;
$_SESSION = [];
}

public function clear($id)
{
$_SESSION[$this->namespace] = [];

return true;
}

public function store($id, $key, $value)
{
$fetched = $this->doFetch($id, $key);
if (null !== $fetched && !$this->allowOverride) {
throw new DriverException(sprintf('Overriding session variable "%s" is not permitted.', $key));
}

$_SESSION[$this->namespace][$key] = $value;

return true;
}

public function fetch($id, $key, $default = null)
{
if (null !== $value = $this->doFetch($id, $key)) {
return $value;
}

return $default;
}

private function doFetch($id, $key)
{
if (array_key_exists($key, $_SESSION[$this->namespace])) {
return $_SESSION[$this->namespace][$key];
}
}

public function save($id)
{
return true;
}
}
Loading

0 comments on commit 3a130df

Please sign in to comment.