Completed
Push — master ( 140cce...303161 )
by Antonio Carlos
02:33
created

Tracker::track()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 8
rs 9.4285
cc 2
eloc 4
nc 2
nop 0
1
<?php
2
3
namespace PragmaRX\Tracker;
4
5
use Illuminate\Foundation\Application as Laravel;
6
use Illuminate\Http\Request;
7
use Illuminate\Log\Writer as Logger;
8
use Illuminate\Routing\Router;
9
use PragmaRX\Support\Config;
10
use PragmaRX\Tracker\Data\RepositoryManager as DataRepositoryManager;
11
use PragmaRX\Tracker\Support\Minutes;
12
13
class Tracker
14
{
15
    protected $config;
16
17
    /**
18
     * @var \Illuminate\Routing\Router
19
     */
20
    protected $route;
21
22
    protected $logger;
23
    /**
24
     * @var \Illuminate\Foundation\Application
25
     */
26
    protected $laravel;
27
28
    protected $enabled = true;
29
30
    protected $sessionData;
31
32
    private $loggedItems = [];
33
34
    public function __construct(
35
        Config $config,
36
        DataRepositoryManager $dataRepositoryManager,
37
        Request $request,
0 ignored issues
show
Bug introduced by
You have injected the Request via parameter $request. This is generally not recommended as there might be multiple instances during a request cycle (f.e. when using sub-requests). Instead, it is recommended to inject the RequestStack and retrieve the current request each time you need it via getCurrentRequest().
Loading history...
38
        Router $route,
39
        Logger $logger,
40
        Laravel $laravel
41
    ) {
42
        $this->config = $config;
43
44
        $this->dataRepositoryManager = $dataRepositoryManager;
0 ignored issues
show
Bug introduced by
The property dataRepositoryManager does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
45
46
        $this->request = $request;
0 ignored issues
show
Bug introduced by
The property request does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
47
48
        $this->route = $route;
49
50
        $this->logger = $logger;
51
52
        $this->laravel = $laravel;
53
    }
54
55
    public function allSessions()
56
    {
57
        return $this->dataRepositoryManager->getAllSessions();
58
    }
59
60
    public function boot()
61
    {
62
        if ($this->isTrackable()) {
63
            $this->track();
64
        }
65
    }
66
67
    public function checkCurrentUser()
68
    {
69
        if (!$this->sessionData['user_id'] && $user_id = $this->getUserId()) {
70
            return true;
71
        }
72
73
        return false;
74
    }
75
76
    public function currentSession()
77
    {
78
        return $this->dataRepositoryManager->sessionRepository->getCurrent();
79
    }
80
81
    protected function deleteCurrentLog()
82
    {
83
        $this->dataRepositoryManager->logRepository->delete();
84
    }
85
86
    public function errors($minutes, $results = true)
87
    {
88
        return $this->dataRepositoryManager->errors(Minutes::make($minutes), $results);
89
    }
90
91
    public function events($minutes, $results = true)
92
    {
93
        return $this->dataRepositoryManager->events(Minutes::make($minutes), $results);
94
    }
95
96
    protected function getAgentId()
97
    {
98
        return $this->config->get('log_user_agents')
99
            ? $this->dataRepositoryManager->getAgentId()
100
            : null;
101
    }
102
103
    public function getConfig($key)
104
    {
105
        return $this->config->get($key);
106
    }
107
108
    public function getCookieId()
109
    {
110
        return $this->config->get('store_cookie_tracker')
111
            ? $this->dataRepositoryManager->getCookieId()
112
            : null;
113
    }
114
115
    public function getDeviceId()
116
    {
117
        return $this->config->get('log_devices')
118
            ? $this->dataRepositoryManager->findOrCreateDevice(
119
                $this->dataRepositoryManager->getCurrentDeviceProperties()
120
            )
121
            : null;
122
    }
123
124
    public function getLanguageId()
125
    {
126
        return $this->config->get('log_languages')
127
            ? $this->dataRepositoryManager->findOrCreateLanguage($this->dataRepositoryManager->getCurrentLanguage())
128
            : null;
129
    }
130
131
    public function getDomainId($domain)
132
    {
133
        return $this->dataRepositoryManager->getDomainId($domain);
134
    }
135
136
    protected function getGeoIpId()
137
    {
138
        return $this->config->get('log_geoip')
139
            ? $this->dataRepositoryManager->getGeoIpId($this->request->getClientIp())
140
            : null;
141
    }
142
143
    /**
144
     * @return array
145
     */
146
    protected function getLogData()
147
    {
148
        return [
149
            'session_id' => $this->getSessionId(true),
150
            'method'     => $this->request->method(),
151
            'path_id'    => $this->getPathId(),
152
            'query_id'   => $this->getQueryId(),
153
            'referer_id' => $this->getRefererId(),
154
            'is_ajax'    => $this->request->ajax(),
155
            'is_secure'  => $this->request->isSecure(),
156
            'is_json'    => $this->request->isJson(),
157
            'wants_json' => $this->request->wantsJson(),
158
        ];
159
    }
160
161
    private function getLogger()
162
    {
163
        return $this->logger;
164
    }
165
166
    public function getPathId()
167
    {
168
        return $this->config->get('log_paths')
169
            ? $this->dataRepositoryManager->findOrCreatePath(
170
                [
171
                    'path' => $this->request->path(),
172
                ]
173
            )
174
            : null;
175
    }
176
177
    public function getQueryId()
178
    {
179
        if ($this->config->get('log_queries')) {
180
            if (count($arguments = $this->request->query())) {
181
                return $this->dataRepositoryManager->getQueryId(
182
                    [
183
                        'query'     => array_implode('=', '|', $arguments),
184
                        'arguments' => $arguments,
185
                    ]
186
                );
187
            }
188
        }
189
    }
190
191
    protected function getRefererId()
192
    {
193
        return $this->config->get('log_referers')
194
            ? $this->dataRepositoryManager->getRefererId(
195
                $this->request->headers->get('referer')
196
            )
197
            : null;
198
    }
199
200
    protected function getRoutePathId()
201
    {
202
        return $this->dataRepositoryManager->getRoutePathId($this->route, $this->request);
203
    }
204
205
    private function logUntrackable($item)
206
    {
207
        if ($this->config->get('log_untrackable_sessions') && !isset($this->loggedItems[$item])) {
208
            $this->getLogger()->warning('TRACKER (unable to track item): '.$item);
209
210
            $this->loggedItems[$item] = $item;
211
        }
212
    }
213
214
    /**
215
     * @return array
216
     */
217
    protected function makeSessionData()
218
    {
219
        $sessionData = [
220
            'user_id'      => $this->getUserId(),
221
            'device_id'    => $this->getDeviceId(),
222
            'client_ip'    => $this->request->getClientIp(),
223
            'geoip_id'     => $this->getGeoIpId(),
224
            'agent_id'     => $this->getAgentId(),
225
            'referer_id'   => $this->getRefererId(),
226
            'cookie_id'    => $this->getCookieId(),
227
            'language_id'  => $this->getLanguageId(),
228
            'is_robot'     => $this->isRobot(),
229
230
            // The key user_agent is not present in the sessions table, but
231
            // it's internally used to check if the user agent changed
232
            // during a session.
233
            'user_agent' => $this->dataRepositoryManager->getCurrentUserAgent(),
234
        ];
235
236
        return $this->sessionData = $this->dataRepositoryManager->checkSessionData($sessionData, $this->sessionData);
237
    }
238
239
    public function getSessionId($updateLastActivity = false)
240
    {
241
        return $this->dataRepositoryManager->getSessionId(
242
            $this->makeSessionData(),
243
            $updateLastActivity
244
        );
245
    }
246
247
    public function getUserId()
248
    {
249
        return $this->config->get('log_users')
250
            ? $this->dataRepositoryManager->getCurrentUserId()
251
            : null;
252
    }
253
254
    /**
255
     * @param \Exception $exception
256
     */
257
    public function handleException($exception)
258
    {
259
        if ($this->config->get('log_enabled')) {
260
            $this->dataRepositoryManager->handleException($exception);
261
        }
262
    }
263
264
    public function isEnabled()
265
    {
266
        return $this->enabled;
267
    }
268
269
    public function isRobot()
270
    {
271
        return $this->dataRepositoryManager->isRobot();
272
    }
273
274
    protected function isSqlQueriesLoggableConnection($name)
275
    {
276
        return !in_array(
277
            $name,
278
            $this->config->get('do_not_log_sql_queries_connections')
279
        );
280
    }
281
282
    protected function isTrackable()
283
    {
284
        return $this->config->get('enabled') &&
285
                $this->logIsEnabled() &&
286
                $this->allowConsole() &&
287
                $this->parserIsAvailable() &&
288
                $this->isTrackableIp() &&
289
                $this->isTrackableEnvironment() &&
290
                $this->routeIsTrackable() &&
291
                $this->pathIsTrackable() &&
292
                $this->notRobotOrTrackable();
293
    }
294
295
    protected function isTrackableEnvironment()
296
    {
297
        $trackable = !in_array(
298
            $this->laravel->environment(),
299
            $this->config->get('do_not_track_environments')
300
        );
301
302
        if (!$trackable) {
303
            $this->logUntrackable('environment '.$this->laravel->environment().' is not trackable.');
304
        }
305
306
        return $trackable;
307
    }
308
309
    protected function isTrackableIp()
310
    {
311
        $trackable = !ipv4_in_range(
312
            $ipAddress = $this->request->getClientIp(),
313
            $this->config->get('do_not_track_ips')
314
        );
315
316
        if (!$trackable) {
317
            $this->logUntrackable($ipAddress.' is not trackable.');
318
        }
319
320
        return $trackable;
321
    }
322
323
    public function logByRouteName($name, $minutes = null)
324
    {
325
        if ($minutes) {
326
            $minutes = Minutes::make($minutes);
327
        }
328
329
        return $this->dataRepositoryManager->logByRouteName($name, $minutes);
330
    }
331
332
    public function logEvents()
333
    {
334
        if (
335
            $this->isTrackable() &&
336
            $this->config->get('log_enabled') &&
337
            $this->config->get('log_events')
338
        ) {
339
            $this->dataRepositoryManager->logEvents();
340
        }
341
    }
342
343
    protected function logIsEnabled()
344
    {
345
        $enabled =
346
            $this->config->get('log_enabled') ||
347
            $this->config->get('log_sql_queries') ||
348
            $this->config->get('log_sql_queries_bindings') ||
349
            $this->config->get('log_events') ||
350
            $this->config->get('log_geoip') ||
351
            $this->config->get('log_user_agents') ||
352
            $this->config->get('log_users') ||
353
            $this->config->get('log_devices') ||
354
            $this->config->get('log_languages') ||
355
            $this->config->get('log_referers') ||
356
            $this->config->get('log_paths') ||
357
            $this->config->get('log_queries') ||
358
            $this->config->get('log_routes') ||
359
            $this->config->get('log_exceptions');
360
361
        if (!$enabled) {
362
            $this->logUntrackable('there are no log items enabled.');
363
        }
364
365
        return $enabled;
366
    }
367
368
    public function logSqlQuery($query, $bindings, $time, $name)
369
    {
370
        if (
371
            $this->isTrackable() &&
372
            $this->config->get('log_enabled') &&
373
            $this->config->get('log_sql_queries') &&
374
            $this->isSqlQueriesLoggableConnection($name)
375
        ) {
376
            $this->dataRepositoryManager->logSqlQuery($query, $bindings, $time, $name);
377
        }
378
    }
379
380
    protected function notRobotOrTrackable()
381
    {
382
        $trackable =
383
            !$this->isRobot() ||
384
            !$this->config->get('do_not_track_robots');
385
386
        if (!$trackable) {
387
            $this->logUntrackable('tracking of robots is disabled.');
388
        }
389
390
        return $trackable;
391
    }
392
393
    public function pageViews($minutes, $results = true)
394
    {
395
        return $this->dataRepositoryManager->pageViews(Minutes::make($minutes), $results);
396
    }
397
398
    public function pageViewsByCountry($minutes, $results = true)
399
    {
400
        return $this->dataRepositoryManager->pageViewsByCountry(Minutes::make($minutes), $results);
401
    }
402
403
    public function allowConsole()
404
    {
405
        return
406
            (! $this->laravel->runningInConsole()) ||
407
            $this->config->get('console_log_enabled', false)
408
        ;
409
    }
410
411
    public function parserIsAvailable()
412
    {
413
        if (!$this->dataRepositoryManager->parserIsAvailable()) {
414
            $this->logger->error(trans('tracker::tracker.regex_file_not_available'));
415
416
            return false;
417
        }
418
419
        return true;
420
    }
421
422
    private function routeIsTrackable()
423
    {
424
        if (!$this->route) {
425
            return false;
426
        }
427
428
        if (!$trackable = $this->dataRepositoryManager->routeIsTrackable($this->route)) {
429
            $this->logUntrackable('route '.$this->route->getCurrentRoute()->getName().' is not trackable.');
430
        }
431
432
        return $trackable;
433
    }
434
435
    private function pathIsTrackable()
436
    {
437
        if (!$trackable = $this->dataRepositoryManager->pathIsTrackable($this->request->path())) {
438
            $this->logUntrackable('path '.$this->request->path().' is not trackable.');
439
        }
440
441
        return $trackable;
442
    }
443
444
    public function routerMatched($log)
445
    {
446
        if ($this->dataRepositoryManager->routeIsTrackable($this->route)) {
447
            if ($log) {
448
                $this->dataRepositoryManager->updateRoute(
449
                    $this->getRoutePathId()
450
                );
451
            }
452
        }
453
        // Router was matched but this route is not trackable
454
        // Let's just delete the stored data, because There's not a
455
        // realy clean way of doing this because if a route is not
456
        // matched, and this happens ages after the app is booted,
457
        // we till need to store data from the request.
458
        else {
459
            $this->turnOff();
460
461
            $this->deleteCurrentLog();
462
        }
463
    }
464
465
    public function sessionLog($uuid, $results = true)
466
    {
467
        return $this->dataRepositoryManager->getSessionLog($uuid, $results);
468
    }
469
470
    public function sessions($minutes = 1440, $results = true)
471
    {
472
        return $this->dataRepositoryManager->getLastSessions(Minutes::make($minutes), $results);
473
    }
474
475
    public function onlineUsers($minutes = 3, $results = true)
0 ignored issues
show
Unused Code introduced by
The parameter $minutes is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $results is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
476
    {
477
        return $this->sessions(3);
478
    }
479
480
    public function track()
481
    {
482
        $log = $this->getLogData();
483
484
        if ($this->config->get('log_enabled')) {
485
            $this->dataRepositoryManager->createLog($log);
486
        }
487
    }
488
489
    public function trackEvent($event)
490
    {
491
        $this->dataRepositoryManager->trackEvent($event);
492
    }
493
494
    public function trackVisit($route, $request)
495
    {
496
        $this->dataRepositoryManager->trackRoute($route, $request);
497
    }
498
499
    protected function turnOff()
500
    {
501
        $this->enabled = false;
502
    }
503
504
    public function userDevices($minutes, $user_id = null, $results = true)
505
    {
506
        return $this->dataRepositoryManager->userDevices(
507
            Minutes::make($minutes),
508
            $user_id,
509
            $results
510
        );
511
    }
512
513
    public function users($minutes, $results = true)
514
    {
515
        return $this->dataRepositoryManager->users(Minutes::make($minutes), $results);
516
    }
517
}
518