Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
47 / 47
100.00% covered (success)
100.00%
13 / 13
CRAP
100.00% covered (success)
100.00%
1 / 1
SessionNamespace
100.00% covered (success)
100.00%
47 / 47
100.00% covered (success)
100.00%
13 / 13
21
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 setNamespace
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getNamespace
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setTimedValue
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 setRequestValue
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 sweep
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 init
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
3
 kill
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 toArray
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 __set
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 __get
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 __isset
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 __unset
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2declare(strict_types=1);
3/**
4 * Pop PHP Framework (https://www.popphp.org/)
5 *
6 * @link       https://github.com/popphp/popphp-framework
7 * @author     Nick Sagona, III <nick@popphp.org>
8 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
9 * @license    https://www.popphp.org/license     New BSD License
10 */
11
12/**
13 * @namespace
14 */
15namespace Pop\Session;
16
17/**
18 * Session namespace class
19 *
20 * @category   Pop
21 * @package    Pop\Session
22 * @author     Nick Sagona, III <nick@popphp.org>
23 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
24 * @license    https://www.popphp.org/license     New BSD License
25 * @version    5.0.0
26 */
27class SessionNamespace extends AbstractSession
28{
29
30    /**
31     * Session namespace
32     * @var ?string
33     */
34    private ?string $namespace = null;
35
36    /**
37     * Constructor
38     *
39     * Private method to instantiate the session object
40     *
41     * @param  string $namespace
42     * @throws Exception
43     */
44    public function __construct(string $namespace)
45    {
46        if ($namespace == '_POP_SESSION_') {
47            throw new Exception("Error: Cannot use the reserved namespace '_POP_SESSION_'.");
48        }
49        $this->setNamespace($namespace);
50        $sess = Session::getInstance();
51        if (!isset($sess[$namespace])) {
52            $sess[$namespace] = [];
53        }
54        $this->init();
55    }
56
57    /**
58     * Set current namespace
59     *
60     * @param  string $namespace
61     * @return SessionNamespace
62     */
63    public function setNamespace(string $namespace): SessionNamespace
64    {
65        $this->namespace = $namespace;
66        return $this;
67    }
68
69    /**
70     * Get current namespace
71     *
72     * @return string
73     */
74    public function getNamespace(): string
75    {
76        return $this->namespace;
77    }
78
79    /**
80     * Set a time-based value
81     *
82     * @param  string $key
83     * @param  mixed  $value
84     * @param  int    $expire
85     * @return SessionNamespace
86     */
87    public function setTimedValue(string $key, mixed $value, int $expire = 300): SessionNamespace
88    {
89        $_SESSION[$this->namespace][$key] = $value;
90        $_SESSION['_POP_SESSION_'][$this->namespace]['expirations'][$key] = time() + (int)$expire;
91        return $this;
92    }
93
94    /**
95     * Set a request-based value
96     *
97     * @param  string $key
98     * @param  mixed  $value
99     * @param  int    $hops
100     * @return SessionNamespace
101     */
102    public function setRequestValue(string $key, mixed $value, int $hops = 1): SessionNamespace
103    {
104        $_SESSION[$this->namespace][$key] = $value;
105        $_SESSION['_POP_SESSION_'][$this->namespace]['requests'][$key] = [
106            'current' => 0,
107            'limit'   => (int)$hops
108        ];
109        return $this;
110    }
111
112    /**
113     * Manually check request-based and time-based values, removing any that have
114     * expired or exceeded their hop limit
115     *
116     * @return SessionNamespace
117     */
118    public function sweep(): SessionNamespace
119    {
120        if (isset($_SESSION[$this->namespace], $_SESSION['_POP_SESSION_'][$this->namespace])) {
121            $this->checkRequestValues($_SESSION[$this->namespace], $_SESSION['_POP_SESSION_'][$this->namespace]);
122            $this->checkExpirationValues($_SESSION[$this->namespace], $_SESSION['_POP_SESSION_'][$this->namespace]);
123        }
124        return $this;
125    }
126
127    /**
128     * Init the session
129     *
130     * @return void
131     */
132    private function init(): void
133    {
134        if (!isset($_SESSION['_POP_SESSION_'])) {
135            $_SESSION['_POP_SESSION_'] = [
136                $this->namespace => [
137                    'requests'    => [],
138                    'expirations' => []
139                ]
140            ];
141        } else if (!isset($_SESSION['_POP_SESSION_'][$this->namespace])) {
142            $_SESSION['_POP_SESSION_'][$this->namespace] = [
143                'requests'    => [],
144                'expirations' => []
145            ];
146        } else {
147            $this->sweep();
148        }
149    }
150
151    /**
152     * Kill the session namespace
153     *
154     * @param  bool $all
155     * @return void
156     */
157    public function kill(bool $all = false): void
158    {
159        if ($all) {
160            $sess = Session::getInstance();
161            $sess->kill();
162        } else if (isset($_SESSION[$this->namespace])) {
163            unset($_SESSION['_POP_SESSION_'][$this->namespace], $_SESSION[$this->namespace]);
164        }
165    }
166
167    /**
168     * Get the session values as an array
169     *
170     * @return array
171     */
172    public function toArray(): array
173    {
174        return $_SESSION[$this->namespace] ?? [];
175    }
176
177    /**
178     * Set a property in the session object that is linked to the $_SESSION global variable
179     *
180     * @param  string $name
181     * @param  mixed $value
182     * @return void
183     */
184    public function __set(string $name, mixed $value): void
185    {
186        $_SESSION[$this->namespace][$name] = $value;
187    }
188
189    /**
190     * Get method to return the value of the $_SESSION global variable
191     *
192     * @param  string $name
193     * @return mixed
194     */
195    public function __get(string $name): mixed
196    {
197        return (isset($_SESSION[$this->namespace][$name])) ? $_SESSION[$this->namespace][$name] : null;
198    }
199
200    /**
201     * Return the isset value of the $_SESSION global variable
202     *
203     * @param  string $name
204     * @return bool
205     */
206    public function __isset(string $name): bool
207    {
208        return isset($_SESSION[$this->namespace][$name]);
209    }
210
211    /**
212     * Unset the $_SESSION global variable
213     *
214     * @param  string $name
215     * @return void
216     */
217    public function __unset(string $name): void
218    {
219        $_SESSION[$this->namespace][$name] = null;
220        unset($_SESSION[$this->namespace][$name]);
221    }
222
223}