ServiceProvider::getAppUrl()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace PragmaRX\Tracker\Vendor\Laravel;
4
5
use PragmaRX\Support\GeoIp\GeoIp;
6
use PragmaRX\Support\PhpSession;
7
use PragmaRX\Support\ServiceProvider as PragmaRXServiceProvider;
8
use PragmaRX\Tracker\Data\Repositories\Agent;
9
use PragmaRX\Tracker\Data\Repositories\Connection;
10
use PragmaRX\Tracker\Data\Repositories\Cookie;
11
use PragmaRX\Tracker\Data\Repositories\Device;
12
use PragmaRX\Tracker\Data\Repositories\Domain;
13
use PragmaRX\Tracker\Data\Repositories\Error;
14
use PragmaRX\Tracker\Data\Repositories\Event;
15
use PragmaRX\Tracker\Data\Repositories\EventLog;
16
use PragmaRX\Tracker\Data\Repositories\GeoIp as GeoIpRepository;
17
use PragmaRX\Tracker\Data\Repositories\Language;
18
use PragmaRX\Tracker\Data\Repositories\Log;
19
use PragmaRX\Tracker\Data\Repositories\Path;
20
use PragmaRX\Tracker\Data\Repositories\Query;
21
use PragmaRX\Tracker\Data\Repositories\QueryArgument;
22
use PragmaRX\Tracker\Data\Repositories\Referer;
23
use PragmaRX\Tracker\Data\Repositories\Route;
24
use PragmaRX\Tracker\Data\Repositories\RoutePath;
25
use PragmaRX\Tracker\Data\Repositories\RoutePathParameter;
26
use PragmaRX\Tracker\Data\Repositories\Session;
27
use PragmaRX\Tracker\Data\Repositories\SqlQuery;
28
use PragmaRX\Tracker\Data\Repositories\SqlQueryBinding;
29
use PragmaRX\Tracker\Data\Repositories\SqlQueryBindingParameter;
30
use PragmaRX\Tracker\Data\Repositories\SqlQueryLog;
31
use PragmaRX\Tracker\Data\Repositories\SystemClass;
32
use PragmaRX\Tracker\Data\RepositoryManager;
33
use PragmaRX\Tracker\Eventing\EventStorage;
34
use PragmaRX\Tracker\Repositories\Message as MessageRepository;
35
use PragmaRX\Tracker\Services\Authentication;
36
use PragmaRX\Tracker\Support\Cache;
37
use PragmaRX\Tracker\Support\CrawlerDetector;
38
use PragmaRX\Tracker\Support\Exceptions\Handler as TrackerExceptionHandler;
39
use PragmaRX\Tracker\Support\LanguageDetect;
40
use PragmaRX\Tracker\Support\MobileDetect;
41
use PragmaRX\Tracker\Support\UserAgentParser;
42
use PragmaRX\Tracker\Tracker;
43
use PragmaRX\Tracker\Vendor\Laravel\Artisan\Tables as TablesCommand;
44
use PragmaRX\Tracker\Vendor\Laravel\Artisan\UpdateGeoIp;
45
46
class ServiceProvider extends PragmaRXServiceProvider
47
{
48
    protected $packageVendor = 'pragmarx';
49
50
    protected $packageName = 'tracker';
51
52
    protected $packageNameCapitalized = 'Tracker';
53
54
    protected $repositoryManagerIsBooted = false;
55
56
    /**
57
     * Indicates if loading of the provider is deferred.
58
     *
59
     * @var bool
60
     */
61
    protected $defer = false;
62
63
    protected $userChecked = false;
64
65
    protected $tracker;
66
67
    /**
68
     * Bootstrap the application events.
69
     *
70
     * @return void
71
     */
72
    public function boot()
73
    {
74
        parent::boot();
75
76
        if (!$this->getConfig('enabled')) {
77
            return false;
78
        }
79
80
        $this->loadRoutes();
81
82
        $this->registerErrorHandler();
83
84
        if (!$this->getConfig('use_middleware')) {
85
            $this->bootTracker();
86
        }
87
88
        $this->loadTranslations();
89
    }
90
91
    /**
92
     * Check if the service provider is full booted.
93
     *
94
     * @return void
95
     */
96
    public function isFullyBooted()
97
    {
98
        return $this->repositoryManagerIsBooted;
99
    }
100
101
    /**
102
     * Register the service provider.
103
     *
104
     * @return void
105
     */
106
    public function register()
107
    {
108
        parent::register();
109
110
        if ($this->getConfig('enabled')) {
111
            $this->registerAuthentication();
112
113
            $this->registerCache();
114
115
            $this->registerRepositories();
116
117
            $this->registerTracker();
118
119
            $this->registerTablesCommand();
120
121
            $this->registerUpdateGeoIpCommand();
122
123
            $this->registerExecutionCallback();
124
125
            $this->registerUserCheckCallback();
126
127
            $this->registerSqlQueryLogWatcher();
128
129
            $this->registerGlobalEventLogger();
130
131
            $this->registerDatatables();
132
133
            $this->registerMessageRepository();
134
135
            $this->registerGlobalViewComposers();
136
        }
137
    }
138
139
    /**
140
     * Get the services provided by the provider.
141
     *
142
     * @return string[]
143
     */
144
    public function provides()
145
    {
146
        return ['tracker'];
147
    }
148
149
    /**
150
     * Takes all the components of Tracker and glues them
151
     * together to create Tracker.
152
     *
153
     * @return void
154
     */
155
    protected function registerTracker()
156
    {
157
        $this->app->singleton('tracker', function ($app) {
158
            $app['tracker.loaded'] = true;
159
160
            return new Tracker(
161
                $app['tracker.config'],
162
                $app['tracker.repositories'],
163
                $app['request'],
164
                $app['router'],
165
                $app['log'],
166
                $app,
0 ignored issues
show
Documentation introduced by
$app is of type array<string,boolean,{"t...ker.loaded":"boolean"}>, but the function expects a object<Illuminate\Foundation\Application>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
167
                $app['tracker.messages']
168
            );
169
        });
170
    }
171
172
    public function registerRepositories()
173
    {
174
        $this->app->singleton('tracker.repositories', function ($app) {
175
            try {
176
                $uaParser = new UserAgentParser($app->make('path.base'));
177
            } catch (\Exception $exception) {
178
                $uaParser = null;
179
            }
180
181
            $sessionModel = $this->instantiateModel('session_model');
182
183
            $logModel = $this->instantiateModel('log_model');
184
185
            $agentModel = $this->instantiateModel('agent_model');
186
187
            $deviceModel = $this->instantiateModel('device_model');
188
189
            $cookieModel = $this->instantiateModel('cookie_model');
190
191
            $pathModel = $this->instantiateModel('path_model');
192
193
            $queryModel = $this->instantiateModel('query_model');
194
195
            $queryArgumentModel = $this->instantiateModel('query_argument_model');
196
197
            $domainModel = $this->instantiateModel('domain_model');
198
199
            $refererModel = $this->instantiateModel('referer_model');
200
201
            $refererSearchTermModel = $this->instantiateModel('referer_search_term_model');
202
203
            $routeModel = $this->instantiateModel('route_model');
204
205
            $routePathModel = $this->instantiateModel('route_path_model');
206
207
            $routePathParameterModel = $this->instantiateModel('route_path_parameter_model');
208
209
            $errorModel = $this->instantiateModel('error_model');
210
211
            $geoipModel = $this->instantiateModel('geoip_model');
212
213
            $sqlQueryModel = $this->instantiateModel('sql_query_model');
214
215
            $sqlQueryBindingModel = $this->instantiateModel('sql_query_binding_model');
216
217
            $sqlQueryBindingParameterModel = $this->instantiateModel('sql_query_binding_parameter_model');
218
219
            $sqlQueryLogModel = $this->instantiateModel('sql_query_log_model');
220
221
            $connectionModel = $this->instantiateModel('connection_model');
222
223
            $eventModel = $this->instantiateModel('event_model');
224
225
            $eventLogModel = $this->instantiateModel('event_log_model');
226
227
            $systemClassModel = $this->instantiateModel('system_class_model');
228
229
            $languageModel = $this->instantiateModel('language_model');
230
231
            $logRepository = new Log($logModel);
232
233
            $connectionRepository = new Connection($connectionModel);
234
235
            $sqlQueryBindingRepository = new SqlQueryBinding($sqlQueryBindingModel);
236
237
            $sqlQueryBindingParameterRepository = new SqlQueryBindingParameter($sqlQueryBindingParameterModel);
238
239
            $sqlQueryLogRepository = new SqlQueryLog($sqlQueryLogModel);
240
241
            $sqlQueryRepository = new SqlQuery(
242
                $sqlQueryModel,
243
                $sqlQueryLogRepository,
244
                $sqlQueryBindingRepository,
245
                $sqlQueryBindingParameterRepository,
246
                $connectionRepository,
247
                $logRepository,
248
                $app['tracker.config']
249
            );
250
251
            $eventLogRepository = new EventLog($eventLogModel);
252
253
            $systemClassRepository = new SystemClass($systemClassModel);
254
255
            $eventRepository = new Event(
256
                $eventModel,
257
                $app['tracker.events'],
258
                $eventLogRepository,
259
                $systemClassRepository,
260
                $logRepository,
261
                $app['tracker.config']
262
            );
263
264
            $routeRepository = new Route(
265
                $routeModel,
266
                $app['tracker.config']
267
            );
268
269
            $crawlerDetect = new CrawlerDetector(
270
                $app['request']->headers->all(),
271
                $app['request']->server('HTTP_USER_AGENT')
272
            );
273
274
            $manager = new RepositoryManager(
275
                new GeoIp($this->getConfig('geoip_database_path')),
276
                new MobileDetect(),
277
                $uaParser,
278
                $app['tracker.authentication'],
279
                $app['session.store'],
280
                $app['tracker.config'],
281
                new Session(
282
                    $sessionModel,
283
                    $app['tracker.config'],
284
                    new PhpSession()
285
                ),
286
                $logRepository,
287
                new Path($pathModel),
288
                new Query($queryModel),
289
                new QueryArgument($queryArgumentModel),
290
                new Agent($agentModel),
291
                new Device($deviceModel),
292
                new Cookie(
293
                    $cookieModel,
294
                    $app['tracker.config'],
295
                    $app['request'],
296
                    $app['cookie']
297
                ),
298
                new Domain($domainModel),
299
                new Referer(
300
                    $refererModel,
301
                    $refererSearchTermModel,
302
                    $this->getAppUrl(),
303
                    $app->make('PragmaRX\Tracker\Support\RefererParser')
304
                ),
305
                $routeRepository,
306
                new RoutePath($routePathModel),
307
                new RoutePathParameter($routePathParameterModel),
308
                new Error($errorModel),
309
                new GeoIpRepository($geoipModel),
310
                $sqlQueryRepository,
311
                $sqlQueryBindingRepository,
312
                $sqlQueryBindingParameterRepository,
313
                $sqlQueryLogRepository,
314
                $connectionRepository,
315
                $eventRepository,
316
                $eventLogRepository,
317
                $systemClassRepository,
318
                $crawlerDetect,
319
                new Language($languageModel),
320
                new LanguageDetect()
321
            );
322
323
            $this->repositoryManagerIsBooted = true;
324
325
            return $manager;
326
        });
327
    }
328
329
    public function registerAuthentication()
330
    {
331
        $this->app->singleton('tracker.authentication', function ($app) {
332
            return new Authentication($app['tracker.config'], $app);
333
        });
334
    }
335
336
    public function registerCache()
337
    {
338
        $this->app->singleton('tracker.cache', function ($app) {
339
            return new Cache($app['tracker.config'], $app);
340
        });
341
    }
342
343
    protected function registerTablesCommand()
344
    {
345
        $this->app->singleton('tracker.tables.command', function ($app) {
0 ignored issues
show
Unused Code introduced by
The parameter $app 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...
346
            return new TablesCommand();
347
        });
348
349
        $this->commands('tracker.tables.command');
350
    }
351
352
    protected function registerExecutionCallback()
353
    {
354
        $me = $this;
355
356
        $mathingEvents = [
357
            'router.matched',
358
            'Illuminate\Routing\Events\RouteMatched',
359
        ];
360
361
        $this->app['events']->listen($mathingEvents, function () use ($me) {
362
            $me->getTracker()->routerMatched($me->getConfig('log_routes'));
363
        });
364
    }
365
366
    protected function registerErrorHandler()
367
    {
368
        if ($this->getConfig('log_exceptions')) {
369
            $illuminateHandler = 'Illuminate\Contracts\Debug\ExceptionHandler';
370
371
            $handler = new TrackerExceptionHandler(
372
                $this->getTracker(),
373
                $this->app[$illuminateHandler]
374
            );
375
376
            // Replace original Illuminate Exception Handler by Tracker's
377
            $this->app[$illuminateHandler] = $handler;
378
        }
379
    }
380
381
    /**
382
     * @param string $modelName
383
     */
384
    protected function instantiateModel($modelName)
385
    {
386
        $model = $this->getConfig($modelName);
387
388
        if (!$model) {
389
            $message = "Tracker: Model not found for '$modelName'.";
390
391
            $this->app['log']->error($message);
392
393
            throw new \Exception($message);
394
        }
395
396
        $model = new $model();
397
398
        $model->setConfig($this->app['tracker.config']);
399
400
        if ($connection = $this->getConfig('connection')) {
401
            $model->setConnection($connection);
402
        }
403
404
        return $model;
405
    }
406
407
    protected function registerSqlQueryLogWatcher()
408
    {
409
        $me = $this;
410
411
        if (!class_exists('Illuminate\Database\Events\QueryExecuted')) {
412
            $this->app['events']->listen('illuminate.query', function (
413
                $query,
414
                $bindings,
415
                $time,
416
                $name
417
            ) use ($me) {
418
                $me->logSqlQuery($query, $bindings, $time, $name);
419
            });
420
        } else {
421
            $this->app['events']->listen('Illuminate\Database\Events\QueryExecuted', function ($query) use ($me) {
422
                $me->logSqlQuery($query);
423
            });
424
        }
425
    }
426
427
    /**
428
     * @param $query
429
     * @param $bindings
430
     * @param $time
431
     * @param $name
432
     * @param $me
433
     */
434
    public function logSqlQuery($query, $bindings = null, $time = null, $connectionName = null)
435
    {
436
        if ($this->getTracker()->isEnabled()) {
437
            if ($query instanceof \Illuminate\Database\Events\QueryExecuted) {
438
                $bindings = $query->bindings;
439
                $time = $query->time;
440
                $connectionName = $query->connectionName;
441
                $query = $query->sql;
442
            }
443
444
            $this->getTracker()->logSqlQuery($query, $bindings, $time, $connectionName);
445
        }
446
    }
447
448
    protected function registerGlobalEventLogger()
449
    {
450
        $me = $this;
451
452
        $this->app->singleton('tracker.events', function ($app) {
0 ignored issues
show
Unused Code introduced by
The parameter $app 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...
453
            return new EventStorage();
454
        });
455
456
        $this->app['events']->listen('*', function ($object = null) use ($me) {
0 ignored issues
show
Unused Code introduced by
The parameter $object 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...
457
            if ($me->app['tracker.events']->isOff() || !$me->isFullyBooted()) {
458
                return;
459
            }
460
461
            // To avoid infinite recursion, event tracking while logging events
462
            // must be turned off
463
            $me->app['tracker.events']->turnOff();
464
465
            // Log events even before application is ready
466
            // $me->app['tracker.events']->logEvent(
467
            //    $me->app['events']->firing(),
468
            //    $object
469
            // );
470
            // TODO: we have to investigate a way of doing this
471
472
            // Can only send events to database after application is ready
473
            if (isset($me->app['tracker.loaded'])) {
474
                $me->getTracker()->logEvents();
475
            }
476
477
            // Turn the event tracking to on again
478
            $me->app['tracker.events']->turnOn();
479
        });
480
    }
481
482
    protected function loadRoutes()
483
    {
484
        if (!$this->getConfig('stats_panel_enabled')) {
485
            return false;
486
        }
487
488
        $prefix = $this->getConfig('stats_base_uri');
489
490
        $namespace = $this->getConfig('stats_controllers_namespace');
491
492
        $filters = [];
493
494
        if ($before = $this->getConfig('stats_routes_before_filter')) {
495
            $filters['before'] = $before;
496
        }
497
498
        if ($after = $this->getConfig('stats_routes_after_filter')) {
499
            $filters['after'] = $after;
500
        }
501
502
        if ($middleware = $this->getConfig('stats_routes_middleware')) {
503
            $filters['middleware'] = $middleware;
504
        }
505
506
        $router = $this->app->make('router');
507
508
        $router->group(['namespace' => $namespace], function () use ($prefix, $router, $filters) {
509
            $router->group($filters, function () use ($prefix, $router) {
510
                $router->group(['prefix' => $prefix], function ($router) {
511
                    $router->get('/', ['as' => 'tracker.stats.index', 'uses' => 'Stats@index']);
512
513
                    $router->get('log/{uuid}', ['as' => 'tracker.stats.log', 'uses' => 'Stats@log']);
514
515
                    $router->get('api/pageviews', ['as' => 'tracker.stats.api.pageviews', 'uses' => 'Stats@apiPageviews']);
516
517
                    $router->get('api/pageviewsbycountry', ['as' => 'tracker.stats.api.pageviewsbycountry', 'uses' => 'Stats@apiPageviewsByCountry']);
518
519
                    $router->get('api/log/{uuid}', ['as' => 'tracker.stats.api.log', 'uses' => 'Stats@apiLog']);
520
521
                    $router->get('api/errors', ['as' => 'tracker.stats.api.errors', 'uses' => 'Stats@apiErrors']);
522
523
                    $router->get('api/events', ['as' => 'tracker.stats.api.events', 'uses' => 'Stats@apiEvents']);
524
525
                    $router->get('api/users', ['as' => 'tracker.stats.api.users', 'uses' => 'Stats@apiUsers']);
526
527
                    $router->get('api/visits', ['as' => 'tracker.stats.api.visits', 'uses' => 'Stats@apiVisits']);
528
                });
529
            });
530
        });
531
    }
532
533
    protected function registerDatatables()
534
    {
535
        $this->registerServiceProvider('Bllim\Datatables\DatatablesServiceProvider');
536
537
        $this->registerServiceAlias('Datatable', 'Bllim\Datatables\Facade\Datatables');
538
    }
539
540
    /**
541
     * Get the current package directory.
542
     *
543
     * @return string
544
     */
545
    public function getPackageDir()
546
    {
547
        return __DIR__.DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.'..';
548
    }
549
550
    /**
551
     * Boot & Track.
552
     */
553
    protected function bootTracker()
554
    {
555
        $this->getTracker()->boot();
556
    }
557
558
    /**
559
     * Register global view composers.
560
     */
561
    protected function registerGlobalViewComposers()
562
    {
563
        $me = $this;
564
565
        $this->app->make('view')->composer('pragmarx/tracker::*', function ($view) use ($me) {
566
            $view->with('stats_layout', $me->getConfig('stats_layout'));
567
568
            $template_path = url('/').$me->getConfig('stats_template_path');
569
570
            $view->with('stats_template_path', $template_path);
571
        });
572
    }
573
574
    protected function registerUpdateGeoIpCommand()
575
    {
576
        $this->app->singleton('tracker.updategeoip.command', function ($app) {
0 ignored issues
show
Unused Code introduced by
The parameter $app 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...
577
            return new UpdateGeoIp();
578
        });
579
580
        $this->commands('tracker.updategeoip.command');
581
    }
582
583
    protected function registerUserCheckCallback()
584
    {
585
        $me = $this;
586
587
        $this->app['events']->listen('router.before', function ($object = null) use ($me) {
0 ignored issues
show
Unused Code introduced by
The parameter $object 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...
588
589
            // get auth bindings to check
590
            $bindings = $me->getConfig('authentication_ioc_binding');
591
592
            // check if all bindings are resolved
593
            $checked_bindings = array_map(function ($abstract) use ($me) {
594
                return $me->app->resolved($abstract);
595
            }, $bindings);
596
597
            $all_bindings_resolved =
598
                (!in_array(false, $checked_bindings, true)) ?: false;
599
600
            if ($me->tracker &&
601
                !$me->userChecked &&
602
                $me->getConfig('log_users') &&
603
                $all_bindings_resolved
604
            ) {
605
                $me->userChecked = $me->getTracker()->checkCurrentUser();
606
            }
607
        });
608
    }
609
610
    /**
611
     * @return Tracker
612
     */
613
    public function getTracker()
614
    {
615
        if (!$this->tracker) {
616
            $this->tracker = $this->app['tracker'];
617
        }
618
619
        return $this->tracker;
620
    }
621
622
    public function getRootDirectory()
623
    {
624
        return __DIR__.'/../..';
625
    }
626
627
    protected function getAppUrl()
628
    {
629
        return $this->app['request']->url();
630
    }
631
632
    public function loadTranslations()
633
    {
634
        $this->loadTranslationsFrom(__DIR__.'/../../lang', 'tracker');
635
    }
636
637
    /**
638
     * Register the message repository.
639
     */
640
    protected function registerMessageRepository()
641
    {
642
        $this->app->singleton('tracker.messages', function () {
643
            return new MessageRepository();
644
        });
645
    }
646
}
647