MockArraySessionStorage

class MockArraySessionStorage implements SessionStorageInterface

MockArraySessionStorage mocks the session for unit tests.

No PHP session is actually started since a session can be initialized and shutdown only once per PHP execution cycle.

When doing functional testing, you should use MockFileSessionStorage instead.

Properties

protected string $id
protected string $name
protected bool $started
protected bool $closed
protected array $data
protected MetadataBag $metadataBag
protected array|SessionBagInterface[] $bags

Methods

public __construct(string $name = 'MOCKSESSID', MetadataBag $metaBag = null) No description
public setSessionData(array $array) No description
public bool start() Starts the session.
public bool regenerate(bool $destroy = false, int $lifetime = null) Regenerates id that represents this storage.
public string getId() Returns the session ID.
public setId(string $id) Sets the session ID.
public mixed getName() Returns the session name.
public setName(string $name) Sets the session name.
public save() Force the session to be saved and closed.
public clear() Clear all session data in memory.
public registerBag(SessionBagInterface $bag) Registers a SessionBagInterface for use.
public SessionBagInterface getBag(string $name) Gets a SessionBagInterface by name.
public bool isStarted() Checks if the session is started.
public setMetadataBag(MetadataBag $bag = null) No description
public MetadataBag getMetadataBag() Gets the MetadataBag.
protected string generateId() Generates a session ID.
protected loadSession() No description

Details

at line 65

__construct()

public __construct(string $name = 'MOCKSESSID', MetadataBag $metaBag = null)

Parameters

string $name
MetadataBag $metaBag
at line 71

setSessionData()

public setSessionData(array $array)

Parameters

array $array
at line 79

start()

public bool start()

Starts the session.

Return Value

bool True if started

Exceptions

RuntimeException if something goes wrong starting the session
at line 97

regenerate()

public bool regenerate(bool $destroy = false, int $lifetime = null)

Regenerates id that represents this storage.

This method must invoke session_regenerate_id($destroy) unless this interface is used for a storage object designed for unit or functional testing where a real PHP session would interfere with testing.

Note regenerate+destroy should not clear the session data in memory only delete the session data from persistent storage.

Care: When regenerating the session ID no locking is involved in PHP's session design. See https://bugs.php.net/bug.php?id=61470 for a discussion. So you must make sure the regenerated session is saved BEFORE sending the headers with the new ID. Symfony's HttpKernel offers a listener for this. See Symfony\Component\HttpKernel\EventListener\SaveSessionListener. Otherwise session data could get lost again for concurrent requests with the new ID. One result could be that you get logged out after just logging in.

Parameters

bool $destroy Destroy session when regenerating?
int $lifetime Sets the cookie lifetime for the session cookie. A null value will leave the system settings unchanged, 0 sets the cookie to expire with browser session. Time is in seconds, and is not a Unix timestamp.

Return Value

bool True if session regenerated, false if error

Exceptions

RuntimeException If an error occurs while regenerating this storage
at line 112

getId()

public string getId()

Returns the session ID.

Return Value

string The session ID or empty
at line 120

setId()

public setId(string $id)

Sets the session ID.

Parameters

string $id
at line 132

getName()

public mixed getName()

Returns the session name.

Return Value

mixed The session name
at line 140

setName()

public setName(string $name)

Sets the session name.

Parameters

string $name
at line 148

save()

public save()

Force the session to be saved and closed.

This method must invoke session_write_close() unless this interface is used for a storage object design for unit or functional testing where a real PHP session would interfere with testing, in which case it should actually persist the session data if required.

Exceptions

RuntimeException if the session is saved without being started, or if the session is already closed
at line 161

clear()

public clear()

Clear all session data in memory.

at line 178

registerBag()

public registerBag(SessionBagInterface $bag)

Registers a SessionBagInterface for use.

Parameters

SessionBagInterface $bag
at line 186

getBag()

public SessionBagInterface getBag(string $name)

Gets a SessionBagInterface by name.

Parameters

string $name

Return Value

SessionBagInterface

Exceptions

InvalidArgumentException If the bag does not exist
at line 202

isStarted()

public bool isStarted()

Checks if the session is started.

Return Value

bool True if started, false otherwise
at line 207

setMetadataBag()

public setMetadataBag(MetadataBag $bag = null)

Parameters

MetadataBag $bag
at line 221

getMetadataBag()

public MetadataBag getMetadataBag()

Gets the MetadataBag.

Return Value

MetadataBag
at line 234

generateId()

protected string generateId()

Generates a session ID.

This doesn't need to be particularly cryptographically secure since this is just a mock.

Return Value

string
at line 239

loadSession()

protected loadSession()

Source code

<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\HttpFoundation\Session\Storage;

use Symfony\Component\HttpFoundation\Session\SessionBagInterface;

/**
 * MockArraySessionStorage mocks the session for unit tests.
 *
 * No PHP session is actually started since a session can be initialized
 * and shutdown only once per PHP execution cycle.
 *
 * When doing functional testing, you should use MockFileSessionStorage instead.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Bulat Shakirzyanov <mallluhuct@gmail.com>
 * @author Drak <drak@zikula.org>
 */
class MockArraySessionStorage implements SessionStorageInterface
{
    /**
     * @var string
     */
    protected $id = '';

    /**
     * @var string
     */
    protected $name;

    /**
     * @var bool
     */
    protected $started = false;

    /**
     * @var bool
     */
    protected $closed = false;

    /**
     * @var array
     */
    protected $data = array();

    /**
     * @var MetadataBag
     */
    protected $metadataBag;

    /**
     * @var array|SessionBagInterface[]
     */
    protected $bags = array();

    public function __construct(string $name = 'MOCKSESSID', MetadataBag $metaBag = null)
    {
        $this->name = $name;
        $this->setMetadataBag($metaBag);
    }

    public function setSessionData(array $array)
    {
        $this->data = $array;
    }

    /**
     * {@inheritdoc}
     */
    public function start()
    {
        if ($this->started) {
            return true;
        }

        if (empty($this->id)) {
            $this->id = $this->generateId();
        }

        $this->loadSession();

        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function regenerate($destroy = false, $lifetime = null)
    {
        if (!$this->started) {
            $this->start();
        }

        $this->metadataBag->stampNew($lifetime);
        $this->id = $this->generateId();

        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * {@inheritdoc}
     */
    public function setId($id)
    {
        if ($this->started) {
            throw new \LogicException('Cannot set session ID after the session has started.');
        }

        $this->id = $id;
    }

    /**
     * {@inheritdoc}
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * {@inheritdoc}
     */
    public function setName($name)
    {
        $this->name = $name;
    }

    /**
     * {@inheritdoc}
     */
    public function save()
    {
        if (!$this->started || $this->closed) {
            throw new \RuntimeException('Trying to save a session that was not started yet or was already closed');
        }
        // nothing to do since we don't persist the session data
        $this->closed = false;
        $this->started = false;
    }

    /**
     * {@inheritdoc}
     */
    public function clear()
    {
        // clear out the bags
        foreach ($this->bags as $bag) {
            $bag->clear();
        }

        // clear out the session
        $this->data = array();

        // reconnect the bags to the session
        $this->loadSession();
    }

    /**
     * {@inheritdoc}
     */
    public function registerBag(SessionBagInterface $bag)
    {
        $this->bags[$bag->getName()] = $bag;
    }

    /**
     * {@inheritdoc}
     */
    public function getBag($name)
    {
        if (!isset($this->bags[$name])) {
            throw new \InvalidArgumentException(sprintf('The SessionBagInterface %s is not registered.', $name));
        }

        if (!$this->started) {
            $this->start();
        }

        return $this->bags[$name];
    }

    /**
     * {@inheritdoc}
     */
    public function isStarted()
    {
        return $this->started;
    }

    public function setMetadataBag(MetadataBag $bag = null)
    {
        if (null === $bag) {
            $bag = new MetadataBag();
        }

        $this->metadataBag = $bag;
    }

    /**
     * Gets the MetadataBag.
     *
     * @return MetadataBag
     */
    public function getMetadataBag()
    {
        return $this->metadataBag;
    }

    /**
     * Generates a session ID.
     *
     * This doesn't need to be particularly cryptographically secure since this is just
     * a mock.
     *
     * @return string
     */
    protected function generateId()
    {
        return hash('sha256', uniqid('ss_mock_', true));
    }

    protected function loadSession()
    {
        $bags = array_merge($this->bags, array($this->metadataBag));

        foreach ($bags as $bag) {
            $key = $bag->getStorageKey();
            $this->data[$key] = isset($this->data[$key]) ? $this->data[$key] : array();
            $bag->initialize($this->data[$key]);
        }

        $this->started = true;
        $this->closed = false;
    }
}