Passed
Pull Request — master (#117)
by
unknown
01:53
created

Flash::has()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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