Completed
Push — master ( 2d3a59...a6566c )
by Dmitry
9s
created

RemoteCartStorage::mergeCartData()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 2
1
<?php
2
3
namespace hipanel\modules\finance\cart\storage;
4
5
use hipanel\components\SettingsStorage;
6
use hipanel\helpers\StringHelper;
7
use Yii;
8
use yii\base\NotSupportedException;
9
use yii\caching\CacheInterface;
10
use yii\helpers\Json;
11
use yii\web\MultiFieldSession;
12
use yii\web\Session;
13
use yii\web\User;
14
15
/**
16
 * Class RemoteCartStorage
17
 *
18
 * @author Dmytro Naumenko <[email protected]>
19
 */
20
class RemoteCartStorage extends MultiFieldSession implements CartStorageInterface
21
{
22
    /**
23
     * To marge sesstion and remote cart storage
24
     * @var string
25
     */
26
    public $sessionCartId;
27
28
    const CACHE_DURATION = 60 * 60; // 1 hour
29
    /**
30
     * @var array
31
     */
32
    protected $data = [];
33
    /**
34
     * @var array
35
     */
36
    protected $oldData = [];
37
    /**
38
     * @var SettingsStorage
39
     */
40
    private $settingsStorage;
41
    /**
42
     * @var CacheInterface
43
     */
44
    private $cache;
45
    /**
46
     * @var User
47
     */
48
    private $user;
49
50
    /**
51
     * @var Session
52
     */
53
    private $session;
54
55
    public function __construct(Session $session, User $user, SettingsStorage $settingsStorage, CacheInterface $cache, array $config = [])
56
    {
57
        parent::__construct($config);
58
59
        $this->settingsStorage = $settingsStorage;
60
        $this->cache = $cache;
61
        $this->user = $user;
62
        $this->session = $session;
63
    }
64
65
    protected function read()
66
    {
67
        try {
68
            $this->data = $this->cache->getOrSet($this->getCacheKey(), function () {
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->cache->getOrSet($..., self::CACHE_DURATION) of type * is incompatible with the declared type array of property $data.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
69
                $data = $this->settingsStorage->getBounded($this->getStorageKey());
70
                $sessionCartData = $this->getSessionCartData();
71
                if ($data === [] && $sessionCartData === []) {
72
                    return [];
73
                }
74
75
                return $this->mergeCartData($data, $sessionCartData);
76
            }, self::CACHE_DURATION);
77
        } catch (\Exception $exception) {
78
            Yii::error('Failed to read cart: ' . $exception->getMessage(), __METHOD__);
79
        }
80
    }
81
82
    protected function getSessionCartData()
83
    {
84
        $result = [];
85
        if (isset($this->session[$this->sessionCartId])) {
86
            $result = unserialize($this->session[$this->sessionCartId]);
87
        }
88
89
        return $result;
90
    }
91
92
    protected function mergeCartData($remoteData, $sessionData)
93
    {
94
        $data = Json::decode(base64_decode($remoteData));
95
        $rawData = array_merge(unserialize($data[$this->sessionCartId]), $sessionData);
96
97
        return [$this->sessionCartId => serialize($rawData)];
98
    }
99
100
    protected function getCacheKey()
101
    {
102
        return [__CLASS__, $this->user->getId(), session_id()];
103
    }
104
105
    protected function getStorageKey()
106
    {
107
        return StringHelper::basename(__CLASS__);
108
    }
109
110
    protected function write()
111
    {
112
        if ($this->data === $this->oldData) {
113
            return;
114
        }
115
116
        try {
117
            $this->cache->set($this->getCacheKey(), $this->data);
118
            $this->settingsStorage->setBounded($this->getStorageKey(), base64_encode(Json::encode($this->data)));
119
        } catch (\Exception $exception) {
120
            Yii::error('Failed to save cart: ' . $exception->getMessage(), __METHOD__);
121
        }
122
    }
123
124
    /**
125
     * @var bool
126
     */
127
    private $_isActive;
128
129
    public function getIsActive()
130
    {
131
        return $this->_isActive;
132
    }
133
134
    /** {@inheritdoc} */
135
    public function open()
136
    {
137
        if ($this->getIsActive()) {
138
            return;
139
        }
140
141
        $this->read();
142
        $this->oldData = $this->data;
143
        $this->_isActive = true;
144
        $this->registerShutdownFunction();
145
    }
146
147
    /** {@inheritdoc} */
148
    public function offsetExists($offset)
149
    {
150
        $this->open();
151
152
        return isset($this->data[$offset]);
153
    }
154
155
    /** {@inheritdoc} */
156
    public function offsetGet($offset)
157
    {
158
        $this->open();
159
160
        return $this->data[$offset] ?? null;
161
    }
162
163
    /** {@inheritdoc} */
164
    public function offsetSet($offset, $item)
165
    {
166
        $this->open();
167
168
        $this->data[$offset] = $item;
169
    }
170
171
    /** {@inheritdoc} */
172
    public function offsetUnset($offset)
173
    {
174
        $this->open();
175
        unset($this->data[$offset]);
176
    }
177
178
    /**
179
     * @throws NotSupportedException
180
     * @void
181
     */
182
    private function throwShouldNotBeCalledException()
183
    {
184
        throw new NotSupportedException('Remote cart storage extends yii\web\Session, but it is not a session actually. This method should be never called.');
185
    }
186
187
    /** {@inheritdoc} */
188
    public function regenerateID($deleteOldSession = false)
189
    {
190
        $this->throwShouldNotBeCalledException();
191
    }
192
193
    /** {@inheritdoc} */
194
    public function readSession($id)
195
    {
196
        return $this->throwShouldNotBeCalledException();
197
    }
198
199
    /** {@inheritdoc} */
200
    public function writeSession($id, $data)
201
    {
202
        return $this->throwShouldNotBeCalledException();
203
    }
204
205
    /** {@inheritdoc} */
206
    public function destroySession($id)
207
    {
208
        return $this->throwShouldNotBeCalledException();
209
    }
210
211
    /** {@inheritdoc} */
212
    public function gcSession($maxLifetime)
213
    {
214
        return $this->throwShouldNotBeCalledException();
215
    }
216
217
    private function registerShutdownFunction()
218
    {
219
        register_shutdown_function(\Closure::fromCallable([$this, 'write']));
220
    }
221
}
222