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;
13
14use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;
15use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBagInterface;
16use Symfony\Component\HttpFoundation\Session\Flash\FlashBag;
17use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
18use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
19use Symfony\Component\HttpFoundation\Session\Storage\SessionStorageInterface;
20
21/**
22 * @author Fabien Potencier <fabien@symfony.com>
23 * @author Drak <drak@zikula.org>
24 */
25class Session implements SessionInterface, \IteratorAggregate, \Countable
26{
27    protected $storage;
28
29    private $flashName;
30    private $attributeName;
31    private $data = [];
32    private $usageIndex = 0;
33
34    /**
35     * @param SessionStorageInterface $storage    A SessionStorageInterface instance
36     * @param AttributeBagInterface   $attributes An AttributeBagInterface instance, (defaults null for default AttributeBag)
37     * @param FlashBagInterface       $flashes    A FlashBagInterface instance (defaults null for default FlashBag)
38     */
39    public function __construct(SessionStorageInterface $storage = null, AttributeBagInterface $attributes = null, FlashBagInterface $flashes = null)
40    {
41        $this->storage = $storage ?: new NativeSessionStorage();
42
43        $attributes = $attributes ?: new AttributeBag();
44        $this->attributeName = $attributes->getName();
45        $this->registerBag($attributes);
46
47        $flashes = $flashes ?: new FlashBag();
48        $this->flashName = $flashes->getName();
49        $this->registerBag($flashes);
50    }
51
52    /**
53     * {@inheritdoc}
54     */
55    public function start()
56    {
57        return $this->storage->start();
58    }
59
60    /**
61     * {@inheritdoc}
62     */
63    public function has($name)
64    {
65        return $this->getAttributeBag()->has($name);
66    }
67
68    /**
69     * {@inheritdoc}
70     */
71    public function get($name, $default = null)
72    {
73        return $this->getAttributeBag()->get($name, $default);
74    }
75
76    /**
77     * {@inheritdoc}
78     */
79    public function set($name, $value)
80    {
81        $this->getAttributeBag()->set($name, $value);
82    }
83
84    /**
85     * {@inheritdoc}
86     */
87    public function all()
88    {
89        return $this->getAttributeBag()->all();
90    }
91
92    /**
93     * {@inheritdoc}
94     */
95    public function replace(array $attributes)
96    {
97        $this->getAttributeBag()->replace($attributes);
98    }
99
100    /**
101     * {@inheritdoc}
102     */
103    public function remove($name)
104    {
105        return $this->getAttributeBag()->remove($name);
106    }
107
108    /**
109     * {@inheritdoc}
110     */
111    public function clear()
112    {
113        $this->getAttributeBag()->clear();
114    }
115
116    /**
117     * {@inheritdoc}
118     */
119    public function isStarted()
120    {
121        return $this->storage->isStarted();
122    }
123
124    /**
125     * Returns an iterator for attributes.
126     *
127     * @return \ArrayIterator An \ArrayIterator instance
128     */
129    public function getIterator()
130    {
131        return new \ArrayIterator($this->getAttributeBag()->all());
132    }
133
134    /**
135     * Returns the number of attributes.
136     *
137     * @return int The number of attributes
138     */
139    public function count()
140    {
141        return \count($this->getAttributeBag()->all());
142    }
143
144    /**
145     * @return int
146     *
147     * @internal
148     */
149    public function getUsageIndex()
150    {
151        return $this->usageIndex;
152    }
153
154    /**
155     * @return bool
156     *
157     * @internal
158     */
159    public function isEmpty()
160    {
161        if ($this->isStarted()) {
162            ++$this->usageIndex;
163        }
164        foreach ($this->data as &$data) {
165            if (!empty($data)) {
166                return false;
167            }
168        }
169
170        return true;
171    }
172
173    /**
174     * {@inheritdoc}
175     */
176    public function invalidate($lifetime = null)
177    {
178        $this->storage->clear();
179
180        return $this->migrate(true, $lifetime);
181    }
182
183    /**
184     * {@inheritdoc}
185     */
186    public function migrate($destroy = false, $lifetime = null)
187    {
188        return $this->storage->regenerate($destroy, $lifetime);
189    }
190
191    /**
192     * {@inheritdoc}
193     */
194    public function save()
195    {
196        $this->storage->save();
197    }
198
199    /**
200     * {@inheritdoc}
201     */
202    public function getId()
203    {
204        return $this->storage->getId();
205    }
206
207    /**
208     * {@inheritdoc}
209     */
210    public function setId($id)
211    {
212        if ($this->storage->getId() !== $id) {
213            $this->storage->setId($id);
214        }
215    }
216
217    /**
218     * {@inheritdoc}
219     */
220    public function getName()
221    {
222        return $this->storage->getName();
223    }
224
225    /**
226     * {@inheritdoc}
227     */
228    public function setName($name)
229    {
230        $this->storage->setName($name);
231    }
232
233    /**
234     * {@inheritdoc}
235     */
236    public function getMetadataBag()
237    {
238        ++$this->usageIndex;
239
240        return $this->storage->getMetadataBag();
241    }
242
243    /**
244     * {@inheritdoc}
245     */
246    public function registerBag(SessionBagInterface $bag)
247    {
248        $this->storage->registerBag(new SessionBagProxy($bag, $this->data, $this->usageIndex));
249    }
250
251    /**
252     * {@inheritdoc}
253     */
254    public function getBag($name)
255    {
256        $bag = $this->storage->getBag($name);
257
258        return method_exists($bag, 'getBag') ? $bag->getBag() : $bag;
259    }
260
261    /**
262     * Gets the flashbag interface.
263     *
264     * @return FlashBagInterface
265     */
266    public function getFlashBag()
267    {
268        return $this->getBag($this->flashName);
269    }
270
271    /**
272     * Gets the attributebag interface.
273     *
274     * Note that this method was added to help with IDE autocompletion.
275     *
276     * @return AttributeBagInterface
277     */
278    private function getAttributeBag()
279    {
280        return $this->getBag($this->attributeName);
281    }
282}
283