1: <?php
2:
3: /*
4: * This file is part of the Symfony package.
5: *
6: * (c) Fabien Potencier <fabien@symfony.com>
7: *
8: * For the full copyright and license information, please view the LICENSE
9: * file that was distributed with this source code.
10: */
11:
12: namespace Symfony\Component\HttpFoundation\Session\Storage;
13:
14: use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
15:
16: /**
17: * MockArraySessionStorage mocks the session for unit tests.
18: *
19: * No PHP session is actually started since a session can be initialized
20: * and shutdown only once per PHP execution cycle.
21: *
22: * When doing functional testing, you should use MockFileSessionStorage instead.
23: *
24: * @author Fabien Potencier <fabien@symfony.com>
25: * @author Bulat Shakirzyanov <mallluhuct@gmail.com>
26: * @author Drak <drak@zikula.org>
27: */
28: class MockArraySessionStorage implements SessionStorageInterface
29: {
30: /**
31: * @var string
32: */
33: protected $id = '';
34:
35: /**
36: * @var string
37: */
38: protected $name;
39:
40: /**
41: * @var bool
42: */
43: protected $started = false;
44:
45: /**
46: * @var bool
47: */
48: protected $closed = false;
49:
50: /**
51: * @var array
52: */
53: protected $data = array();
54:
55: /**
56: * @var MetadataBag
57: */
58: protected $metadataBag;
59:
60: /**
61: * @var array
62: */
63: protected $bags;
64:
65: /**
66: * Constructor.
67: *
68: * @param string $name Session name
69: * @param MetadataBag $metaBag MetadataBag instance.
70: */
71: public function __construct($name = 'MOCKSESSID', MetadataBag $metaBag = null)
72: {
73: $this->name = $name;
74: $this->setMetadataBag($metaBag);
75: }
76:
77: /**
78: * Sets the session data.
79: *
80: * @param array $array
81: */
82: public function setSessionData(array $array)
83: {
84: $this->data = $array;
85: }
86:
87: /**
88: * {@inheritdoc}
89: */
90: public function start()
91: {
92: if ($this->started) {
93: return true;
94: }
95:
96: if (empty($this->id)) {
97: $this->id = $this->generateId();
98: }
99:
100: $this->loadSession();
101:
102: return true;
103: }
104:
105: /**
106: * {@inheritdoc}
107: */
108: public function regenerate($destroy = false, $lifetime = null)
109: {
110: if (!$this->started) {
111: $this->start();
112: }
113:
114: $this->metadataBag->stampNew($lifetime);
115: $this->id = $this->generateId();
116:
117: return true;
118: }
119:
120: /**
121: * {@inheritdoc}
122: */
123: public function getId()
124: {
125: return $this->id;
126: }
127:
128: /**
129: * {@inheritdoc}
130: */
131: public function setId($id)
132: {
133: if ($this->started) {
134: throw new \LogicException('Cannot set session ID after the session has started.');
135: }
136:
137: $this->id = $id;
138: }
139:
140: /**
141: * {@inheritdoc}
142: */
143: public function getName()
144: {
145: return $this->name;
146: }
147:
148: /**
149: * {@inheritdoc}
150: */
151: public function setName($name)
152: {
153: $this->name = $name;
154: }
155:
156: /**
157: * {@inheritdoc}
158: */
159: public function save()
160: {
161: if (!$this->started || $this->closed) {
162: throw new \RuntimeException("Trying to save a session that was not started yet or was already closed");
163: }
164: // nothing to do since we don't persist the session data
165: $this->closed = false;
166: $this->started = false;
167: }
168:
169: /**
170: * {@inheritdoc}
171: */
172: public function clear()
173: {
174: // clear out the bags
175: foreach ($this->bags as $bag) {
176: $bag->clear();
177: }
178:
179: // clear out the session
180: $this->data = array();
181:
182: // reconnect the bags to the session
183: $this->loadSession();
184: }
185:
186: /**
187: * {@inheritdoc}
188: */
189: public function registerBag(SessionBagInterface $bag)
190: {
191: $this->bags[$bag->getName()] = $bag;
192: }
193:
194: /**
195: * {@inheritdoc}
196: */
197: public function getBag($name)
198: {
199: if (!isset($this->bags[$name])) {
200: throw new \InvalidArgumentException(sprintf('The SessionBagInterface %s is not registered.', $name));
201: }
202:
203: if (!$this->started) {
204: $this->start();
205: }
206:
207: return $this->bags[$name];
208: }
209:
210: /**
211: * {@inheritdoc}
212: */
213: public function isStarted()
214: {
215: return $this->started;
216: }
217:
218: /**
219: * Sets the MetadataBag.
220: *
221: * @param MetadataBag $bag
222: */
223: public function setMetadataBag(MetadataBag $bag = null)
224: {
225: if (null === $bag) {
226: $bag = new MetadataBag();
227: }
228:
229: $this->metadataBag = $bag;
230: }
231:
232: /**
233: * Gets the MetadataBag.
234: *
235: * @return MetadataBag
236: */
237: public function getMetadataBag()
238: {
239: return $this->metadataBag;
240: }
241:
242: /**
243: * Generates a session ID.
244: *
245: * This doesn't need to be particularly cryptographically secure since this is just
246: * a mock.
247: *
248: * @return string
249: */
250: protected function generateId()
251: {
252: return hash('sha256', uniqid(mt_rand()));
253: }
254:
255: protected function loadSession()
256: {
257: $bags = array_merge($this->bags, array($this->metadataBag));
258:
259: foreach ($bags as $bag) {
260: $key = $bag->getStorageKey();
261: $this->data[$key] = isset($this->data[$key]) ? $this->data[$key] : array();
262: $bag->initialize($this->data[$key]);
263: }
264:
265: $this->started = true;
266: $this->closed = false;
267: }
268: }
269: