Session::resetSessionUuid()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 14
rs 9.7998
c 0
b 0
f 0
cc 2
nc 2
nop 1
1
<?php
2
3
namespace PragmaRX\Tracker\Data\Repositories;
4
5
use Carbon\Carbon;
6
use PragmaRX\Support\Config;
7
use PragmaRX\Support\PhpSession;
8
use Ramsey\Uuid\Uuid as UUID;
9
10
class Session extends Repository
11
{
12
    private $config;
13
14
    private $session;
15
16
    private $sessionInfo;
17
18
    protected $relations = ['device', 'user', 'log', 'language', 'agent', 'referer', 'geoIp', 'cookie'];
19
20
    public function __construct($model, Config $config, PhpSession $session)
21
    {
22
        $this->config = $config;
23
24
        $this->session = $session;
25
26
        parent::__construct($model);
27
    }
28
29
    public function findByUuid($uuid)
30
    {
31
        list($model, $cacheKey) = $this->cache->findCached($uuid, 'uuid', 'PragmaRX\Tracker\Vendor\Laravel\Models\Session');
32
33
        if (!$model) {
34
            $model = $this->newQuery()->where('uuid', $uuid)->with($this->relations)->first();
35
36
            $this->cache->cachePut($cacheKey, $model);
37
        }
38
39
        return $model;
40
    }
41
42
    public function getCurrentId($sessionInfo)
43
    {
44
        $this->setSessionData($sessionInfo);
45
46
        return $this->sessionGetId($sessionInfo);
0 ignored issues
show
Unused Code introduced by
The call to Session::sessionGetId() has too many arguments starting with $sessionInfo.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
47
    }
48
49
    public function setSessionData($sessinInfo)
50
    {
51
        $this->generateSession($sessinInfo);
52
53
        if ($this->sessionIsKnownOrCreateSession()) {
54
            $this->ensureSessionDataIsComplete();
55
        }
56
    }
57
58
    private function generateSession($sessionInfo)
59
    {
60
        $this->sessionInfo = $sessionInfo;
61
62
        if (!$this->sessionIsReliable()) {
63
            $this->regenerateSystemSession();
64
        }
65
66
        $this->checkSessionUuid();
67
    }
68
69
    private function sessionIsReliable()
70
    {
71
        $data = $this->getSessionData();
72
73
        if (isset($data['user_id'])) {
74
            if ($data['user_id'] !== $this->sessionInfo['user_id']) {
75
                return false;
76
            }
77
        }
78
79
        if (isset($data['client_ip'])) {
80
            if ($data['client_ip'] !== $this->sessionInfo['client_ip']) {
81
                return false;
82
            }
83
        }
84
85
        if (isset($data['user_agent'])) {
86
            if ($data['user_agent'] !== $this->sessionInfo['user_agent']) {
87
                return false;
88
            }
89
        }
90
91
        return true;
92
    }
93
94
    private function sessionIsKnownOrCreateSession()
95
    {
96
        if (!$known = $this->sessionIsKnown()) {
97
            $this->sessionSetId($this->findOrCreate($this->sessionInfo, ['uuid']));
98
        } else {
99
            $session = $this->find($this->getSessionData('id'));
100
101
            $session->updated_at = Carbon::now();
102
103
            $session->save();
104
105
            $this->sessionInfo['id'] = $this->getSessionData('id');
106
        }
107
108
        return $known;
109
    }
110
111
    private function sessionIsKnown()
112
    {
113
        if (!$this->session->has($this->getSessionKey())) {
114
            return false;
115
        }
116
117
        if (!$this->getSessionData('uuid') == $this->getSystemSessionId()) {
118
            return false;
119
        }
120
121
        if (!$this->findByUuid($this->getSessionData('uuid'))) {
122
            return false;
123
        }
124
125
        return true;
126
    }
127
128
    private function ensureSessionDataIsComplete()
129
    {
130
        $sessionData = $this->getSessionData();
131
132
        $wasComplete = true;
133
134
        foreach ($this->sessionInfo as $key => $value) {
135
            if ($key === 'user_agent') {
136
                continue;
137
            }
138
            if ($sessionData[$key] !== $value) {
139
                if (!isset($model)) {
140
                    $model = $this->find($this->sessionInfo['id']);
141
                }
142
143
                $model->setAttribute($key, $value);
144
145
                $model->save();
146
147
                $wasComplete = false;
148
            }
149
        }
150
151
        if (!$wasComplete) {
152
            $this->storeSession();
153
        }
154
    }
155
156
    private function sessionGetId()
157
    {
158
        return $this->sessionInfo['id'];
159
    }
160
161
    private function sessionSetId($id)
162
    {
163
        $this->sessionInfo['id'] = $id;
164
165
        $this->storeSession();
166
    }
167
168
    private function storeSession()
169
    {
170
        $this->putSessionData($this->sessionInfo);
171
    }
172
173
    private function getSystemSessionId()
174
    {
175
        $sessionData = $this->getSessionData();
176
177
        if (isset($sessionData['uuid'])) {
178
            return $sessionData['uuid'];
179
        }
180
181
        return UUID::uuid4()->toString();
182
    }
183
184
    private function regenerateSystemSession($data = null)
185
    {
186
        $data = $data ?: $this->getSessionData();
187
188
        if (!$data) {
189
            $this->resetSessionUuid($data);
190
191
            $this->sessionIsKnownOrCreateSession();
192
        }
193
194
        return $this->sessionInfo;
195
    }
196
197
    /**
198
     * @param string $variable
199
     */
200
    private function getSessionData($variable = null)
201
    {
202
        $data = $this->session->get($this->getSessionKey());
203
204
        return $variable
205
                ? (isset($data[$variable]) ? $data[$variable] : null)
206
                : $data;
207
    }
208
209
    private function putSessionData($data)
210
    {
211
        $this->session->put($this->getSessionKey(), $data);
212
    }
213
214
    private function getSessionKey()
215
    {
216
        return $this->config->get('tracker_session_name');
217
    }
218
219
    private function getSessions()
220
    {
221
        return $this
222
                ->newQuery()
223
                ->with($this->relations)
224
                ->orderBy('updated_at', 'desc');
225
    }
226
227
    public function all()
228
    {
229
        return $this->getSessions()->get();
230
    }
231
232
    public function last($minutes, $returnResults)
233
    {
234
        $query = $this
235
            ->getSessions()
236
            ->period($minutes);
237
238
        if ($returnResults) {
239
            $cacheKey = 'last-sessions';
240
241
            $result = $this->cache->findCachedWithKey($cacheKey);
242
243
            if (!$result) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $result of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
244
                $result = $query->get();
245
246
                $this->cache->cachePut($cacheKey, $result, 1); // cache only for 1 minute
0 ignored issues
show
Unused Code introduced by
The call to Cache::cachePut() has too many arguments starting with 1.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
247
248
                return $result;
249
            }
250
251
            return $result;
252
        }
253
254
        return $query;
255
    }
256
257
    public function userDevices($minutes, $user_id, $results)
258
    {
259
        if (!$user_id) {
260
            return [];
261
        }
262
263
        $sessions = $this
264
            ->getSessions()
265
            ->period($minutes)
266
            ->where('user_id', $user_id);
267
268
        if ($results) {
269
            $sessions = $sessions->get()->pluck('device')->unique();
270
        }
271
272
        return $sessions;
273
    }
274
275
    public function users($minutes, $results)
276
    {
277
        return $this->getModel()->users($minutes, $results);
278
    }
279
280
    public function getCurrent()
281
    {
282
        return $this->getModel();
283
    }
284
285
    public function updateSessionData($data)
286
    {
287
        $session = $this->checkIfUserChanged($data, $this->find($this->getSessionData('id')));
288
289
        foreach ($session->getAttributes() as $name => $value) {
290
            if (isset($data[$name]) && $name !== 'id' && $name !== 'uuid') {
291
                $session->{$name} = $data[$name];
292
            }
293
        }
294
295
        $session->save();
296
297
        return $data;
298
    }
299
300
    private function checkIfUserChanged($data, $model)
301
    {
302
        if (!is_null($model->user_id) && !is_null($data['user_id']) && $data['user_id'] !== $model->user_id) {
303
            $newSession = $this->regenerateSystemSession($data);
304
305
            $model = $this->findByUuid($newSession['uuid']);
306
        }
307
308
        return $model;
309
    }
310
311
    private function checkSessionUuid()
312
    {
313
        if (!isset($this->sessionInfo['uuid']) || !$this->sessionInfo['uuid']) {
314
            $this->sessionInfo['uuid'] = $this->getSystemSessionId();
315
        }
316
    }
317
318
    private function resetSessionUuid($data = null)
319
    {
320
        $this->sessionInfo['uuid'] = null;
321
322
        $data = $data ?: $this->sessionInfo;
323
324
        unset($data['uuid']);
325
326
        $this->putSessionData($data);
327
328
        $this->checkSessionUuid();
329
330
        return $data;
331
    }
332
}
333