Completed
Pull Request — master (#201)
by
unknown
01:19
created

IgnitionServiceProvider::registerLogRecorder()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.9332
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Facade\Ignition;
4
5
use Throwable;
6
use Monolog\Logger;
7
use Illuminate\Support\Arr;
8
use Facade\FlareClient\Flare;
9
use Illuminate\Log\LogManager;
10
use Illuminate\Queue\QueueManager;
11
use Illuminate\Support\Collection;
12
use Facade\FlareClient\Http\Client;
13
use Illuminate\Support\Facades\Log;
14
use Whoops\Handler\HandlerInterface;
15
use Illuminate\Support\Facades\Route;
16
use Illuminate\Database\Query\Builder;
17
use Illuminate\Foundation\Application;
18
use Facade\Ignition\ErrorPage\Renderer;
19
use Facade\Ignition\Middleware\AddLogs;
20
use Illuminate\Support\ServiceProvider;
21
use Facade\Ignition\Logger\FlareHandler;
22
use Facade\Ignition\Middleware\AddDumps;
23
use Illuminate\Log\Events\MessageLogged;
24
use Facade\Ignition\Commands\TestCommand;
25
use Facade\Ignition\Middleware\AddQueries;
26
use Symfony\Component\VarDumper\VarDumper;
27
use Facade\Ignition\LogRecorder\LogRecorder;
28
use Facade\Ignition\Middleware\AddSolutions;
29
use Facade\Ignition\Views\Engines\PhpEngine;
30
use Facade\Ignition\Exceptions\InvalidConfig;
31
use Facade\Ignition\DumpRecorder\DumpRecorder;
32
use Facade\Ignition\Middleware\SetNotifierName;
33
use Facade\Ignition\QueryRecorder\QueryRecorder;
34
use Facade\Ignition\Commands\SolutionMakeCommand;
35
use Facade\Ignition\Middleware\AddGitInformation;
36
use Facade\Ignition\Views\Engines\CompilerEngine;
37
use Facade\Ignition\Context\LaravelContextDetector;
38
use Facade\Ignition\ErrorPage\IgnitionWhoopsHandler;
39
use Facade\Ignition\Http\Middleware\IgnitionEnabled;
40
use Facade\Ignition\Http\Controllers\StyleController;
41
use Facade\Ignition\Http\Controllers\ScriptController;
42
use Facade\Ignition\Middleware\AddEnvironmentInformation;
43
use Illuminate\View\Engines\PhpEngine as LaravelPhpEngine;
44
use Facade\Ignition\Http\Controllers\HealthCheckController;
45
use Facade\Ignition\Http\Controllers\ShareReportController;
46
use Facade\Ignition\Http\Controllers\ExecuteSolutionController;
47
use Facade\Ignition\Http\Middleware\IgnitionConfigValueEnabled;
48
use Facade\Ignition\SolutionProviders\SolutionProviderRepository;
49
use Facade\Ignition\SolutionProviders\ViewNotFoundSolutionProvider;
50
use Facade\Ignition\SolutionProviders\BadMethodCallSolutionProvider;
51
use Facade\Ignition\SolutionProviders\DefaultDbNameSolutionProvider;
52
use Facade\Ignition\SolutionProviders\MergeConflictSolutionProvider;
53
use Facade\Ignition\SolutionProviders\MissingAppKeySolutionProvider;
54
use Facade\Ignition\SolutionProviders\MissingColumnSolutionProvider;
55
use Facade\Ignition\SolutionProviders\MissingImportSolutionProvider;
56
use Facade\Ignition\SolutionProviders\TableNotFoundSolutionProvider;
57
use Illuminate\View\Engines\CompilerEngine as LaravelCompilerEngine;
58
use Facade\Ignition\SolutionProviders\MissingPackageSolutionProvider;
59
use Facade\Ignition\SolutionProviders\UndefinedVariableSolutionProvider;
60
use Facade\Ignition\SolutionProviders\UnknownValidationSolutionProvider;
61
use Facade\Ignition\SolutionProviders\InvalidRouteActionSolutionProvider;
62
use Facade\Ignition\SolutionProviders\RunningLaravelDuskInProductionProvider;
63
use Facade\Ignition\SolutionProviders\IncorrectValetDbCredentialsSolutionProvider;
64
use Facade\IgnitionContracts\SolutionProviderRepository as SolutionProviderRepositoryContract;
65
66
class IgnitionServiceProvider extends ServiceProvider
67
{
68
    public function boot()
69
    {
70
        if ($this->app->runningInConsole()) {
71
            $this->publishes([
72
                __DIR__.'/../config/flare.php' => config_path('flare.php'),
73
            ], 'flare-config');
74
75
            $this->publishes([
76
                __DIR__.'/../config/ignition.php' => config_path('ignition.php'),
77
            ], 'ignition-config');
78
        }
79
80
        $this
81
            ->registerViewEngines()
82
            ->registerHousekeepingRoutes()
83
            ->registerLogHandler()
84
            ->registerCommands()
85
            ->registerMacros()
86
            ->setupQueue($this->app->queue);
0 ignored issues
show
Bug introduced by
Accessing queue on the interface Illuminate\Contracts\Foundation\Application suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
87
88
        $this->app->make(QueryRecorder::class)->register();
89
        $this->app->make(LogRecorder::class)->register();
90
        $this->app->make(DumpRecorder::class)->register();
91
    }
92
93
    public function register()
94
    {
95
        $this->mergeConfigFrom(__DIR__.'/../config/flare.php', 'flare');
96
        $this->mergeConfigFrom(__DIR__.'/../config/ignition.php', 'ignition');
97
98
        $this
99
            ->registerSolutionProviderRepository()
100
            ->registerExceptionRenderer()
101
            ->registerWhoopsHandler()
102
            ->registerIgnitionConfig()
103
            ->registerFlare()
104
            ->registerLogRecorder()
105
            ->registerDumpCollector();
106
107
        if (config('flare.reporting.report_queries')) {
108
            $this->registerQueryRecorder();
109
        }
110
111
        if (config('flare.reporting.anonymize_ips')) {
112
            $this->app->get('flare.client')->anonymizeIp();
113
        }
114
115
        $this->registerBuiltInMiddleware();
116
    }
117
118
    protected function registerViewEngines()
119
    {
120
        if (! $this->hasCustomViewEnginesRegistered()) {
121
            return $this;
122
        }
123
124
        $this->app->make('view.engine.resolver')->register('php', function () {
125
            return new PhpEngine();
126
        });
127
128
        $this->app->make('view.engine.resolver')->register('blade', function () {
129
            return new CompilerEngine($this->app['blade.compiler']);
130
        });
131
132
        return $this;
133
    }
134
135
    protected function registerHousekeepingRoutes()
136
    {
137
        if ($this->app->runningInConsole()) {
138
            return $this;
139
        }
140
141
        Route::group([
142
            'prefix' => config('ignition.housekeeping_endpoint_prefix', '_ignition'),
143
            'middleware' => [IgnitionEnabled::class],
144
        ], function () {
145
            Route::get('health-check', HealthCheckController::class);
146
147
            Route::post('execute-solution', ExecuteSolutionController::class)
148
                ->middleware(IgnitionConfigValueEnabled::class.':enableRunnableSolutions');
149
150
            Route::post('share-report', ShareReportController::class)
151
                ->middleware(IgnitionConfigValueEnabled::class.':enableShareButton');
152
153
            Route::get('scripts/{script}', ScriptController::class);
154
            Route::get('styles/{style}', StyleController::class);
155
        });
156
157
        return $this;
158
    }
159
160
    protected function registerSolutionProviderRepository()
161
    {
162
        $this->app->singleton(SolutionProviderRepositoryContract::class, function () {
163
            $defaultSolutions = $this->getDefaultSolutions();
164
165
            return new SolutionProviderRepository($defaultSolutions);
166
        });
167
168
        return $this;
169
    }
170
171
    protected function registerExceptionRenderer()
172
    {
173
        $this->app->bind(Renderer::class, function () {
174
            return new Renderer(__DIR__.'/../resources/views/');
175
        });
176
177
        return $this;
178
    }
179
180
    protected function registerWhoopsHandler()
181
    {
182
        $this->app->bind(HandlerInterface::class, function (Application $app) {
183
            return $app->make(IgnitionWhoopsHandler::class);
184
        });
185
186
        return $this;
187
    }
188
189
    protected function registerIgnitionConfig()
190
    {
191
        $this->app->singleton(IgnitionConfig::class, function () {
192
            $options = [];
193
194
            try {
195
                if ($configPath = $this->getConfigFileLocation()) {
196
                    $options = require $configPath;
197
                }
198
            } catch (Throwable $e) {
199
                // possible open_basedir restriction
200
            }
201
202
            return new IgnitionConfig($options);
203
        });
204
205
        return $this;
206
    }
207
208
    protected function registerFlare()
209
    {
210
        $this->app->singleton('flare.http', function () {
211
            return new Client(
212
                config('flare.key'),
213
                config('flare.secret'),
214
                config('flare.base_url', 'https://flareapp.io/api')
215
            );
216
        });
217
218
        $this->app->alias('flare.http', Client::class);
219
220
        $this->app->singleton('flare.client', function () {
221
            $client = new Flare($this->app->get('flare.http'), new LaravelContextDetector, $this->app);
222
            $client->applicationPath(base_path());
223
            $client->stage(config('app.env'));
224
225
            return $client;
226
        });
227
228
        $this->app->alias('flare.client', Flare::class);
229
230
        return $this;
231
    }
232
233
    protected function registerLogHandler()
234
    {
235
        $this->app->singleton('flare.logger', function ($app) {
236
            $handler = new FlareHandler($app->make('flare.client'));
237
238
            $logLevelString = config('logging.channels.flare.level', 'error');
239
240
            $logLevel = $this->getLogLevel($logLevelString);
241
242
            $handler->setMinimumReportLogLevel($logLevel);
243
244
            $logger = new Logger('Flare');
245
            $logger->pushHandler($handler);
246
247
            return $logger;
248
        });
249
250
        if ($this->app['log'] instanceof LogManager) {
251
            Log::extend('flare', function ($app) {
252
                return $app['flare.logger'];
253
            });
254
        } else {
255
            $this->bindLogListener();
256
        }
257
258
        return $this;
259
    }
260
261
    protected function getLogLevel(string $logLevelString): int
262
    {
263
        $logLevel = Logger::getLevels()[strtoupper($logLevelString)] ?? null;
264
265
        if (! $logLevel) {
266
            throw InvalidConfig::invalidLogLevel($logLevelString);
267
        }
268
269
        return $logLevel;
270
    }
271
272
    protected function registerLogRecorder()
273
    {
274
        $logCollector = $this->app->make(LogRecorder::class);
275
276
        $this->app->singleton(LogRecorder::class);
277
278
        $this->app->instance(LogRecorder::class, $logCollector);
279
280
        return $this;
281
    }
282
283
    protected function registerDumpCollector()
284
    {
285
        $dumpCollector = $this->app->make(DumpRecorder::class);
286
287
        $this->app->singleton(DumpRecorder::class);
288
289
        $this->app->instance(DumpRecorder::class, $dumpCollector);
290
291
        return $this;
292
    }
293
294
    protected function registerCommands()
295
    {
296
        $this->app->bind('command.flare:test', TestCommand::class);
297
        $this->app->bind('command.make:solution', SolutionMakeCommand::class);
298
299
        if ($this->app['config']->get('flare.key')) {
300
            $this->commands(['command.flare:test']);
301
        }
302
303
        if ($this->app['config']->get('ignition.register_commands', false)) {
304
            $this->commands(['command.make:solution']);
305
        }
306
307
        return $this;
308
    }
309
310
    protected function registerMacros()
311
    {
312
        return $this
313
            ->registerBuilderMacro()
314
            ->registerCollectionMacro();
315
    }
316
317
    protected function registerBuilderMacro()
318
    {
319
        Builder::macro('ddd', function () {
320
            ddd($this->toSql(), $this->getBindings());
0 ignored issues
show
Bug introduced by
The method toSql() does not seem to exist on object<Facade\Ignition\IgnitionServiceProvider>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Bug introduced by
The method getBindings() does not seem to exist on object<Facade\Ignition\IgnitionServiceProvider>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
321
        });
322
323
        return $this;
324
    }
325
326
    protected function registerCollectionMacro()
327
    {
328
        Collection::macro('ddd', function () {
329
            $items = (new static(func_get_args()))->push($this);
0 ignored issues
show
Documentation introduced by
func_get_args() is of type array, but the function expects a object<Illuminate\Contra...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...
Bug introduced by
The method push() does not seem to exist on object<Facade\Ignition\IgnitionServiceProvider>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
330
331
            $last = $items->pop();
332
333
            $items->each(function ($item) {
334
                VarDumper::dump($item);
335
            });
336
337
            ddd($last);
338
        });
339
340
        return $this;
341
    }
342
343
    protected function registerQueryRecorder()
344
    {
345
        $queryCollector = $this->app->make(QueryRecorder::class);
346
347
        $this->app->singleton(QueryRecorder::class);
348
349
        $this->app->instance(QueryRecorder::class, $queryCollector);
350
351
        return $this;
352
    }
353
354
    protected function registerBuiltInMiddleware()
355
    {
356
        $middleware = collect([
357
            SetNotifierName::class,
358
            AddEnvironmentInformation::class,
359
            AddLogs::class,
360
            AddDumps::class,
361
            AddQueries::class,
362
            AddSolutions::class,
363
        ])
364
        ->map(function (string $middlewareClass) {
365
            return $this->app->make($middlewareClass);
366
        });
367
368
        if (config('flare.reporting.collect_git_information')) {
369
            $middleware[] = (new AddGitInformation());
370
        }
371
372
        foreach ($middleware as $singleMiddleware) {
373
            $this->app->get('flare.client')->registerMiddleware($singleMiddleware);
374
        }
375
376
        return $this;
377
    }
378
379
    protected function getDefaultSolutions(): array
380
    {
381
        return [
382
            IncorrectValetDbCredentialsSolutionProvider::class,
383
            MissingAppKeySolutionProvider::class,
384
            DefaultDbNameSolutionProvider::class,
385
            BadMethodCallSolutionProvider::class,
386
            TableNotFoundSolutionProvider::class,
387
            MissingImportSolutionProvider::class,
388
            MissingPackageSolutionProvider::class,
389
            InvalidRouteActionSolutionProvider::class,
390
            ViewNotFoundSolutionProvider::class,
391
            UndefinedVariableSolutionProvider::class,
392
            MergeConflictSolutionProvider::class,
393
            RunningLaravelDuskInProductionProvider::class,
394
            MissingColumnSolutionProvider::class,
395
            UnknownValidationSolutionProvider::class,
396
        ];
397
    }
398
399
    protected function hasCustomViewEnginesRegistered()
400
    {
401
        $resolver = $this->app->make('view.engine.resolver');
402
403
        if (! $resolver->resolve('php') instanceof LaravelPhpEngine) {
404
            return false;
405
        }
406
407
        if (! $resolver->resolve('blade') instanceof LaravelCompilerEngine) {
408
            return false;
409
        }
410
411
        return true;
412
    }
413
414
    protected function bindLogListener()
415
    {
416
        $this->app['log']->listen(function (MessageLogged $messageLogged) {
417
            if (config('flare.key')) {
418
                try {
419
                    $this->app['flare.logger']->log(
420
                        $messageLogged->level,
421
                        $messageLogged->message,
422
                        $messageLogged->context
423
                    );
424
                } catch (Exception $exception) {
0 ignored issues
show
Bug introduced by
The class Facade\Ignition\Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
425
                    return;
426
                }
427
            }
428
        });
429
    }
430
431
    protected function getConfigFileLocation(): ?string
432
    {
433
        $configFullPath = base_path().DIRECTORY_SEPARATOR.'.ignition';
434
435
        if (file_exists($configFullPath)) {
436
            return $configFullPath;
437
        }
438
439
        $configFullPath = Arr::get($_SERVER, 'HOME', '').DIRECTORY_SEPARATOR.'.ignition';
440
441
        if (file_exists($configFullPath)) {
442
            return $configFullPath;
443
        }
444
445
        return null;
446
    }
447
448
    protected function setupQueue(QueueManager $queue)
449
    {
450
        $queue->looping(function () {
451
            $this->app->get('flare.client')->reset();
452
453
            if (config('flare.reporting.report_queries')) {
454
                $this->app->make(QueryRecorder::class)->reset();
455
            }
456
457
            $this->app->make(LogRecorder::class)->reset();
458
459
            $this->app->make(DumpRecorder::class)->reset();
460
        });
461
    }
462
}
463