Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
74.29% covered (warning)
74.29%
26 / 35
37.50% covered (danger)
37.50%
3 / 8
CRAP
50.00% covered (danger)
50.00%
1 / 2
CookieStore
73.53% covered (warning)
73.53%
25 / 34
28.57% covered (danger)
28.57%
2 / 7
16.13
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isChanged
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 apply
93.75% covered (success)
93.75%
15 / 16
0.00% covered (danger)
0.00%
0 / 1
4.00
 set
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 remove
66.67% covered (warning)
66.67%
4 / 6
0.00% covered (danger)
0.00%
0 / 1
2.15
 getOr
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 tryGet
50.00% covered (danger)
50.00%
2 / 4
0.00% covered (danger)
0.00%
0 / 1
2.50
LocalCookieData
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5namespace PeServer\Core\Store;
6
7use PeServer\Core\Collection\Arr;
8use PeServer\Core\Text;
9use PeServer\Core\Store\CookieOptions;
10use PeServer\Core\Store\SpecialStore;
11
12/**
13 * Cookie 管理処理。
14 *
15 * セッション側と違い、都度取得する感じ。
16 *
17 * アプリケーション側で明示的に使用しない想定。
18 */
19class CookieStore
20{
21    #region variable
22
23    /**
24     * cookie 一時設定データ。
25     *
26     * @var array<string,LocalCookieData>
27     */
28    private array $values = [];
29    /**
30     * 削除データ(キー項目)。
31     *
32     * @var string[]
33     * @phpstan-var array-key[]
34     */
35    private array $removes = [];
36
37    /**
38     * クッキーの値に変更があったか。
39     */
40    private bool $isChanged = false;
41
42    #endregion
43
44    /**
45     * 生成
46     *
47     * @param SpecialStore $special
48     * @param CookieOptions $options
49     */
50    public function __construct(
51        protected readonly SpecialStore $special,
52        public readonly CookieOptions $options
53    ) {
54    }
55
56    #region function
57
58    /**
59     * クッキーは変更されているか。
60     *
61     * @return boolean
62     */
63    public function isChanged(): bool
64    {
65        return $this->isChanged;
66    }
67
68    /**
69     * 一時クッキーデータをセッションに反映。
70     *
71     * @return void
72     */
73    public function apply(): void
74    {
75        foreach ($this->removes as $key) {
76            if ($this->special->containsCookieName($key)) {
77                setcookie($key, Text::EMPTY, time() - 60, '/');
78            }
79        }
80
81        foreach ($this->values as $key => $cookie) {
82            setcookie(
83                $key,
84                $cookie->value,
85                [
86                    'expires' => $cookie->options->getExpires(),
87                    'path' => $cookie->options->path,
88                    'domain' => Text::EMPTY,
89                    'secure' => $cookie->options->secure,
90                    'httponly' => $cookie->options->httpOnly,
91                    'samesite' => $cookie->options->sameSite
92                ]
93            );
94        }
95    }
96
97    /**
98     * クッキーデータ設定。
99     *
100     * @param string $key
101     * @param string $value
102     * @param CookieOptions|null $options nullの場合コンストラクタで渡された設定値が使用される
103     * @return void
104     */
105    public function set(string $key, string $value, CookieOptions $options = null): void
106    {
107        $this->values[$key] = new LocalCookieData($value, $options ?? $this->options);
108
109        unset($this->removes[$key]);
110
111        $this->isChanged = true;
112    }
113
114    /**
115     * クッキーデータ破棄。
116     *
117     * @param string $key キー。空白指定ですべて削除。
118     * @return void
119     */
120    public function remove(string $key): void
121    {
122        if (Text::isNullOrEmpty($key)) {
123            $this->values = [];
124            $this->removes = $this->special->getCookieNames();
125        } else {
126            unset($this->values[$key]);
127            $this->removes[] = $key;
128        }
129
130        $this->isChanged = true;
131    }
132
133    /**
134     * クッキーデータ取得。
135     *
136     * @param string $key
137     * @param string $fallbackValue
138     * @return string 取得データ。
139     */
140    public function getOr(string $key, string $fallbackValue): string
141    {
142        if (Arr::tryGet($this->values, $key, $data)) {
143            /** @var LocalCookieData $data */
144            return $data->value;
145        }
146
147        /** @var string */
148        return $this->special->getCookie($key, $fallbackValue);
149    }
150
151    /**
152     * クッキーデータ取得。
153     *
154     * @param string $key
155     * @param string $result
156     * @return boolean 取得できたか。
157     */
158    public function tryGet(string $key, ?string &$result): bool
159    {
160        if (Arr::tryGet($this->values, $key, $data)) {
161            /** @var LocalCookieData $data */
162            $result = $data->value;
163            return true;
164        }
165
166        return $this->special->tryGetCookie($key, $result);
167    }
168
169    #endregion
170}
171
172//phpcs:ignore PSR1.Classes.ClassDeclaration.MultipleClasses
173final class LocalCookieData
174{
175    public function __construct(
176        public string $value,
177        public CookieOptions $options
178    ) {
179    }
180}