Passed
Pull Request — master (#117)
by
unknown
02:03
created

Flash   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 223
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 68
dl 0
loc 223
ccs 0
cts 106
cp 0
rs 10
c 2
b 0
f 0
wmc 29

11 Methods

Rating   Name   Duplication   Size   Complexity  
A save() 0 3 1
A updateCounters() 0 23 6
A __construct() 0 9 2
A fetch() 0 3 1
A remove() 0 10 2
A getAll() 0 22 5
A add() 0 14 4
A removeAll() 0 3 1
A get() 0 19 4
A has() 0 4 1
A set() 0 6 2
1
<?php
2
3
namespace Yiisoft\Yii\Web;
4
5
use Yiisoft\Yii\Web\Session\SessionInterface;
6
7
class Flash
8
{
9
    private const COUNTERS = '__counters';
10
11
    /**
12
     * @var string the name of the session variable that stores the flash message data.
13
     */
14
    public $flashParam = '__flash';
15
16
    /**
17
     * @var SessionInterface
18
     */
19
    private $session;
20
21
    private static $init;
22
23
    public function __construct(SessionInterface $session)
24
    {
25
        $this->session = $session;
26
27
        // todo: not sure if it's ok
28
        $this->session->open();
29
        if (self::$init !== $this->session->getId()) {
30
            self::$init = $this->session->getId();
31
            $this->updateCounters();
32
        }
33
    }
34
35
    /**
36
     * Returns a flash message.
37
     * @param string $key the key identifying the flash message
38
     * @param mixed $defaultValue value to be returned if the flash message does not exist.
39
     * @param bool $delete whether to delete this flash message right after this method is called.
40
     * If false, the flash message will be automatically deleted in the next request.
41
     * @return mixed the flash message or an array of messages if addFlash was used
42
     */
43
    public function get(string $key, $defaultValue = null, bool $delete = false)
44
    {
45
        $flashes = $this->fetch();
46
47
        if (isset($flashes[$key], $flashes[self::COUNTERS][$key])) {
48
            $value = $flashes[$key];
49
50
            if ($delete) {
51
                $this->remove($key);
52
            } elseif ($flashes[self::COUNTERS][$key] < 0) {
53
                // mark for deletion in the next request
54
                $flashes[self::COUNTERS][$key] = 1;
55
                $this->save($flashes);
56
            }
57
58
            return $value;
59
        }
60
61
        return $defaultValue;
62
    }
63
64
    /**
65
     * Returns all flash messages.
66
     *
67
     * You may use this method to display all the flash messages in a view file:
68
     *
69
     * ```php
70
     * <?php
71
     * foreach ($flash->getAllFlashes() as $key => $message) {
72
     *     echo '<div class="alert alert-' . $key . '">' . $message . '</div>';
73
     * } ?>
74
     * ```
75
     *
76
     * With the above code you can use the [bootstrap alert][] classes such as `success`, `info`, `danger`
77
     * as the flash message key to influence the color of the div.
78
     *
79
     * Note that if you use [[addFlash()]], `$message` will be an array, and you will have to adjust the above code.
80
     *
81
     * [bootstrap alert]: http://getbootstrap.com/components/#alerts
82
     *
83
     * @param bool $delete whether to delete the flash messages right after this method is called.
84
     * If false, the flash messages will be automatically deleted in the next request.
85
     * @return array flash messages (key => message or key => [message1, message2]).
86
     */
87
    public function getAll(bool $delete = false): array
88
    {
89
        $flashes = $this->fetch();
90
91
        $list = [];
92
        foreach ($flashes as $key => $value) {
93
            if ($key === self::COUNTERS) {
94
                continue;
95
            }
96
97
            $list[$key] = $value;
98
            if ($delete) {
99
                unset($flashes[self::COUNTERS][$key], $flashes[$key]);
100
            } elseif ($flashes[self::COUNTERS][$key] < 0) {
101
                // mark for deletion in the next request
102
                $flashes[self::COUNTERS][$key] = 1;
103
            }
104
        }
105
106
        $this->save($flashes);
107
108
        return $list;
109
    }
110
111
    /**
112
     * Sets a flash message.
113
     * A flash message will be automatically deleted after it is accessed in a request and the deletion will happen
114
     * in the next request.
115
     * If there is already an existing flash message with the same key, it will be overwritten by the new one.
116
     * @param string $key the key identifying the flash message.
117
     * @param mixed $value flash message
118
     * @param bool $removeAfterAccess whether the flash message should be automatically removed only if
119
     * it is accessed. If false, the flash message will be automatically removed after the next request,
120
     * regardless if it is accessed or not. If true (default value), the flash message will remain until after
121
     * it is accessed.
122
     */
123
    public function set(string $key, $value = true, bool $removeAfterAccess = true): void
124
    {
125
        $flashes = $this->fetch();
126
        $flashes[self::COUNTERS][$key] = $removeAfterAccess ? -1 : 0;
127
        $flashes[$key] = $value;
128
        $this->save($flashes);
129
    }
130
131
    /**
132
     * Adds a flash message.
133
     * If there are existing flash messages with the same key, the new one will be appended to the existing message array.
134
     * @param string $key the key identifying the flash message.
135
     * @param mixed $value flash message
136
     * @param bool $removeAfterAccess whether the flash message should be automatically removed only if
137
     * it is accessed. If false, the flash message will be automatically removed after the next request,
138
     * regardless if it is accessed or not. If true (default value), the flash message will remain until after
139
     * it is accessed.
140
     */
141
    public function add(string $key, $value = true, bool $removeAfterAccess = true): void
142
    {
143
        $flashes = $this->fetch();
144
        $flashes[self::COUNTERS][$key] = $removeAfterAccess ? -1 : 0;
145
146
        if (empty($flashes[$key])) {
147
            $flashes[$key] = [$value];
148
        } elseif (is_array($flashes[$key])) {
149
            $flashes[$key][] = $value;
150
        } else {
151
            $flashes[$key] = [$flashes[$key], $value];
152
        }
153
154
        $this->save($flashes);
155
    }
156
157
    /**
158
     * Removes a flash message.
159
     * @param string $key the key identifying the flash message.
160
     * @return mixed the removed flash message. Null if the flash message does not exist.
161
     */
162
    public function remove(string $key)
163
    {
164
        $flashes = $this->fetch();
165
166
        $value = isset($flashes[$key], $flashes[self::COUNTERS][$key]) ? $flashes[$key] : null;
167
        unset($flashes[$key], $flashes[self::COUNTERS][$key]);
168
169
        $this->save($flashes);
170
171
        return $value;
172
    }
173
174
    /**
175
     * Removes all flash messages.
176
     */
177
    public function removeAll(): void
178
    {
179
        $this->save([self::COUNTERS => []]);
180
    }
181
182
    /**
183
     * Returns a value indicating whether there are flash messages associated with the specified key.
184
     * @param string $key key identifying the flash message type
185
     * @return bool whether any flash messages exist under specified key
186
     */
187
    public function has(string $key): bool
188
    {
189
        $flashes = $this->fetch();
190
        return isset($flashes[$key], $flashes[self::COUNTERS][$key]);
191
    }
192
193
    /**
194
     * Updates the counters for flash messages and removes outdated flash messages.
195
     * This method should be called once after session initialization.
196
     */
197
    private function updateCounters(): void
198
    {
199
        $flashes = $this->session->get($this->flashParam, []);
200
        if (!is_array($flashes)) {
201
            $flashes = [self::COUNTERS => []];
202
        }
203
204
        $counters = $flashes[self::COUNTERS] ?? [];
205
        if (!is_array($counters)) {
206
            $counters = [];
207
        }
208
209
210
        foreach ($counters as $key => $count) {
211
            if ($count > 0) {
212
                unset($counters[$key], $flashes[$key]);
213
            } elseif ($count === 0) {
214
                $counters[$key]++;
215
            }
216
        }
217
218
        $flashes[self::COUNTERS] = $counters;
219
        $this->save($flashes);
220
    }
221
222
    private function fetch(): array
223
    {
224
        return $this->session->get($this->flashParam, []);
225
    }
226
227
    private function save(array $flashes): void
228
    {
229
        $this->session->set($this->flashParam, $flashes);
230
    }
231
}
232