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 12namespace Symfony\Component\HttpFoundation\Session\Storage; 13 14use 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 */ 28class 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 = []; 54 55 /** 56 * @var MetadataBag 57 */ 58 protected $metadataBag; 59 60 /** 61 * @var array|SessionBagInterface[] 62 */ 63 protected $bags = []; 64 65 public function __construct(string $name = 'MOCKSESSID', MetadataBag $metaBag = null) 66 { 67 $this->name = $name; 68 $this->setMetadataBag($metaBag); 69 } 70 71 public function setSessionData(array $array) 72 { 73 $this->data = $array; 74 } 75 76 /** 77 * {@inheritdoc} 78 */ 79 public function start() 80 { 81 if ($this->started) { 82 return true; 83 } 84 85 if (empty($this->id)) { 86 $this->id = $this->generateId(); 87 } 88 89 $this->loadSession(); 90 91 return true; 92 } 93 94 /** 95 * {@inheritdoc} 96 */ 97 public function regenerate(bool $destroy = false, int $lifetime = null) 98 { 99 if (!$this->started) { 100 $this->start(); 101 } 102 103 $this->metadataBag->stampNew($lifetime); 104 $this->id = $this->generateId(); 105 106 return true; 107 } 108 109 /** 110 * {@inheritdoc} 111 */ 112 public function getId() 113 { 114 return $this->id; 115 } 116 117 /** 118 * {@inheritdoc} 119 */ 120 public function setId(string $id) 121 { 122 if ($this->started) { 123 throw new \LogicException('Cannot set session ID after the session has started.'); 124 } 125 126 $this->id = $id; 127 } 128 129 /** 130 * {@inheritdoc} 131 */ 132 public function getName() 133 { 134 return $this->name; 135 } 136 137 /** 138 * {@inheritdoc} 139 */ 140 public function setName(string $name) 141 { 142 $this->name = $name; 143 } 144 145 /** 146 * {@inheritdoc} 147 */ 148 public function save() 149 { 150 if (!$this->started || $this->closed) { 151 throw new \RuntimeException('Trying to save a session that was not started yet or was already closed.'); 152 } 153 // nothing to do since we don't persist the session data 154 $this->closed = false; 155 $this->started = false; 156 } 157 158 /** 159 * {@inheritdoc} 160 */ 161 public function clear() 162 { 163 // clear out the bags 164 foreach ($this->bags as $bag) { 165 $bag->clear(); 166 } 167 168 // clear out the session 169 $this->data = []; 170 171 // reconnect the bags to the session 172 $this->loadSession(); 173 } 174 175 /** 176 * {@inheritdoc} 177 */ 178 public function registerBag(SessionBagInterface $bag) 179 { 180 $this->bags[$bag->getName()] = $bag; 181 } 182 183 /** 184 * {@inheritdoc} 185 */ 186 public function getBag(string $name) 187 { 188 if (!isset($this->bags[$name])) { 189 throw new \InvalidArgumentException(sprintf('The SessionBagInterface "%s" is not registered.', $name)); 190 } 191 192 if (!$this->started) { 193 $this->start(); 194 } 195 196 return $this->bags[$name]; 197 } 198 199 /** 200 * {@inheritdoc} 201 */ 202 public function isStarted() 203 { 204 return $this->started; 205 } 206 207 public function setMetadataBag(MetadataBag $bag = null) 208 { 209 if (null === $bag) { 210 $bag = new MetadataBag(); 211 } 212 213 $this->metadataBag = $bag; 214 } 215 216 /** 217 * Gets the MetadataBag. 218 * 219 * @return MetadataBag 220 */ 221 public function getMetadataBag() 222 { 223 return $this->metadataBag; 224 } 225 226 /** 227 * Generates a session ID. 228 * 229 * This doesn't need to be particularly cryptographically secure since this is just 230 * a mock. 231 * 232 * @return string 233 */ 234 protected function generateId() 235 { 236 return hash('sha256', uniqid('ss_mock_', true)); 237 } 238 239 protected function loadSession() 240 { 241 $bags = array_merge($this->bags, [$this->metadataBag]); 242 243 foreach ($bags as $bag) { 244 $key = $bag->getStorageKey(); 245 $this->data[$key] = isset($this->data[$key]) ? $this->data[$key] : []; 246 $bag->initialize($this->data[$key]); 247 } 248 249 $this->started = true; 250 $this->closed = false; 251 } 252} 253