Subversion-Projekte lars-tiefland.laravel_shop

Revision

Revision 148 | Details | Vergleich mit vorheriger | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Illuminate\Foundation\Console;
4
 
5
use Carbon\CarbonInterval;
6
use Closure;
7
use DateTimeInterface;
8
use Illuminate\Console\Application as Artisan;
9
use Illuminate\Console\Command;
10
use Illuminate\Console\Scheduling\Schedule;
11
use Illuminate\Contracts\Console\Kernel as KernelContract;
12
use Illuminate\Contracts\Debug\ExceptionHandler;
13
use Illuminate\Contracts\Events\Dispatcher;
14
use Illuminate\Contracts\Foundation\Application;
15
use Illuminate\Support\Arr;
16
use Illuminate\Support\Carbon;
17
use Illuminate\Support\Env;
18
use Illuminate\Support\InteractsWithTime;
19
use Illuminate\Support\Str;
20
use ReflectionClass;
21
use Symfony\Component\Finder\Finder;
22
use Throwable;
23
 
24
class Kernel implements KernelContract
25
{
26
    use InteractsWithTime;
27
 
28
    /**
29
     * The application implementation.
30
     *
31
     * @var \Illuminate\Contracts\Foundation\Application
32
     */
33
    protected $app;
34
 
35
    /**
36
     * The event dispatcher implementation.
37
     *
38
     * @var \Illuminate\Contracts\Events\Dispatcher
39
     */
40
    protected $events;
41
 
42
    /**
43
     * The Artisan application instance.
44
     *
45
     * @var \Illuminate\Console\Application|null
46
     */
47
    protected $artisan;
48
 
49
    /**
50
     * The Artisan commands provided by the application.
51
     *
52
     * @var array
53
     */
54
    protected $commands = [];
55
 
56
    /**
57
     * Indicates if the Closure commands have been loaded.
58
     *
59
     * @var bool
60
     */
61
    protected $commandsLoaded = false;
62
 
63
    /**
64
     * All of the registered command duration handlers.
65
     *
66
     * @var array
67
     */
68
    protected $commandLifecycleDurationHandlers = [];
69
 
70
    /**
71
     * When the currently handled command started.
72
     *
73
     * @var \Illuminate\Support\Carbon|null
74
     */
75
    protected $commandStartedAt;
76
 
77
    /**
78
     * The bootstrap classes for the application.
79
     *
80
     * @var string[]
81
     */
82
    protected $bootstrappers = [
83
        \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
84
        \Illuminate\Foundation\Bootstrap\LoadConfiguration::class,
85
        \Illuminate\Foundation\Bootstrap\HandleExceptions::class,
86
        \Illuminate\Foundation\Bootstrap\RegisterFacades::class,
87
        \Illuminate\Foundation\Bootstrap\SetRequestForConsole::class,
88
        \Illuminate\Foundation\Bootstrap\RegisterProviders::class,
89
        \Illuminate\Foundation\Bootstrap\BootProviders::class,
90
    ];
91
 
92
    /**
93
     * Create a new console kernel instance.
94
     *
95
     * @param  \Illuminate\Contracts\Foundation\Application  $app
96
     * @param  \Illuminate\Contracts\Events\Dispatcher  $events
97
     * @return void
98
     */
99
    public function __construct(Application $app, Dispatcher $events)
100
    {
101
        if (! defined('ARTISAN_BINARY')) {
102
            define('ARTISAN_BINARY', 'artisan');
103
        }
104
 
105
        $this->app = $app;
106
        $this->events = $events;
107
 
108
        $this->app->booted(function () {
109
            $this->defineConsoleSchedule();
110
        });
111
    }
112
 
113
    /**
114
     * Define the application's command schedule.
115
     *
116
     * @return void
117
     */
118
    protected function defineConsoleSchedule()
119
    {
120
        $this->app->singleton(Schedule::class, function ($app) {
121
            return tap(new Schedule($this->scheduleTimezone()), function ($schedule) {
122
                $this->schedule($schedule->useCache($this->scheduleCache()));
123
            });
124
        });
125
    }
126
 
127
    /**
128
     * Get the name of the cache store that should manage scheduling mutexes.
129
     *
130
     * @return string
131
     */
132
    protected function scheduleCache()
133
    {
134
        return $this->app['config']->get('cache.schedule_store', Env::get('SCHEDULE_CACHE_DRIVER'));
135
    }
136
 
137
    /**
138
     * Run the console application.
139
     *
140
     * @param  \Symfony\Component\Console\Input\InputInterface  $input
141
     * @param  \Symfony\Component\Console\Output\OutputInterface|null  $output
142
     * @return int
143
     */
144
    public function handle($input, $output = null)
145
    {
146
        $this->commandStartedAt = Carbon::now();
147
 
148
        try {
149
            if (in_array($input->getFirstArgument(), ['env:encrypt', 'env:decrypt'], true)) {
150
                $this->bootstrapWithoutBootingProviders();
151
            }
152
 
153
            $this->bootstrap();
154
 
155
            return $this->getArtisan()->run($input, $output);
156
        } catch (Throwable $e) {
157
            $this->reportException($e);
158
 
159
            $this->renderException($output, $e);
160
 
161
            return 1;
162
        }
163
    }
164
 
165
    /**
166
     * Terminate the application.
167
     *
168
     * @param  \Symfony\Component\Console\Input\InputInterface  $input
169
     * @param  int  $status
170
     * @return void
171
     */
172
    public function terminate($input, $status)
173
    {
174
        $this->app->terminate();
175
 
176
        foreach ($this->commandLifecycleDurationHandlers as ['threshold' => $threshold, 'handler' => $handler]) {
177
            $end ??= Carbon::now();
178
 
179
            if ($this->commandStartedAt->diffInMilliseconds($end) > $threshold) {
180
                $handler($this->commandStartedAt, $input, $status);
181
            }
182
        }
183
 
184
        $this->commandStartedAt = null;
185
    }
186
 
187
    /**
399 lars 188
     * Register a callback to be invoked when the command lifecycle duration exceeds a given amount of time.
148 lars 189
     *
190
     * @param  \DateTimeInterface|\Carbon\CarbonInterval|float|int  $threshold
191
     * @param  callable  $handler
192
     * @return void
193
     */
194
    public function whenCommandLifecycleIsLongerThan($threshold, $handler)
195
    {
196
        $threshold = $threshold instanceof DateTimeInterface
197
            ? $this->secondsUntil($threshold) * 1000
198
            : $threshold;
199
 
200
        $threshold = $threshold instanceof CarbonInterval
201
            ? $threshold->totalMilliseconds
202
            : $threshold;
203
 
204
        $this->commandLifecycleDurationHandlers[] = [
205
            'threshold' => $threshold,
206
            'handler' => $handler,
207
        ];
208
    }
209
 
210
    /**
211
     * When the command being handled started.
212
     *
213
     * @return \Illuminate\Support\Carbon|null
214
     */
215
    public function commandStartedAt()
216
    {
217
        return $this->commandStartedAt;
218
    }
219
 
220
    /**
221
     * Define the application's command schedule.
222
     *
223
     * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
224
     * @return void
225
     */
226
    protected function schedule(Schedule $schedule)
227
    {
228
        //
229
    }
230
 
231
    /**
232
     * Get the timezone that should be used by default for scheduled events.
233
     *
234
     * @return \DateTimeZone|string|null
235
     */
236
    protected function scheduleTimezone()
237
    {
238
        $config = $this->app['config'];
239
 
240
        return $config->get('app.schedule_timezone', $config->get('app.timezone'));
241
    }
242
 
243
    /**
244
     * Register the commands for the application.
245
     *
246
     * @return void
247
     */
248
    protected function commands()
249
    {
250
        //
251
    }
252
 
253
    /**
254
     * Register a Closure based command with the application.
255
     *
256
     * @param  string  $signature
257
     * @param  \Closure  $callback
258
     * @return \Illuminate\Foundation\Console\ClosureCommand
259
     */
260
    public function command($signature, Closure $callback)
261
    {
262
        $command = new ClosureCommand($signature, $callback);
263
 
264
        Artisan::starting(function ($artisan) use ($command) {
265
            $artisan->add($command);
266
        });
267
 
268
        return $command;
269
    }
270
 
271
    /**
272
     * Register all of the commands in the given directory.
273
     *
274
     * @param  array|string  $paths
275
     * @return void
276
     */
277
    protected function load($paths)
278
    {
279
        $paths = array_unique(Arr::wrap($paths));
280
 
281
        $paths = array_filter($paths, function ($path) {
282
            return is_dir($path);
283
        });
284
 
285
        if (empty($paths)) {
286
            return;
287
        }
288
 
289
        $namespace = $this->app->getNamespace();
290
 
291
        foreach ((new Finder)->in($paths)->files() as $command) {
292
            $command = $namespace.str_replace(
293
                ['/', '.php'],
294
                ['\\', ''],
295
                Str::after($command->getRealPath(), realpath(app_path()).DIRECTORY_SEPARATOR)
296
            );
297
 
298
            if (is_subclass_of($command, Command::class) &&
299
                ! (new ReflectionClass($command))->isAbstract()) {
300
                Artisan::starting(function ($artisan) use ($command) {
301
                    $artisan->resolve($command);
302
                });
303
            }
304
        }
305
    }
306
 
307
    /**
308
     * Register the given command with the console application.
309
     *
310
     * @param  \Symfony\Component\Console\Command\Command  $command
311
     * @return void
312
     */
313
    public function registerCommand($command)
314
    {
315
        $this->getArtisan()->add($command);
316
    }
317
 
318
    /**
319
     * Run an Artisan console command by name.
320
     *
321
     * @param  string  $command
322
     * @param  array  $parameters
323
     * @param  \Symfony\Component\Console\Output\OutputInterface|null  $outputBuffer
324
     * @return int
325
     *
326
     * @throws \Symfony\Component\Console\Exception\CommandNotFoundException
327
     */
328
    public function call($command, array $parameters = [], $outputBuffer = null)
329
    {
330
        if (in_array($command, ['env:encrypt', 'env:decrypt'], true)) {
331
            $this->bootstrapWithoutBootingProviders();
332
        }
333
 
334
        $this->bootstrap();
335
 
336
        return $this->getArtisan()->call($command, $parameters, $outputBuffer);
337
    }
338
 
339
    /**
340
     * Queue the given console command.
341
     *
342
     * @param  string  $command
343
     * @param  array  $parameters
344
     * @return \Illuminate\Foundation\Bus\PendingDispatch
345
     */
346
    public function queue($command, array $parameters = [])
347
    {
348
        return QueuedCommand::dispatch(func_get_args());
349
    }
350
 
351
    /**
352
     * Get all of the commands registered with the console.
353
     *
354
     * @return array
355
     */
356
    public function all()
357
    {
358
        $this->bootstrap();
359
 
360
        return $this->getArtisan()->all();
361
    }
362
 
363
    /**
364
     * Get the output for the last run command.
365
     *
366
     * @return string
367
     */
368
    public function output()
369
    {
370
        $this->bootstrap();
371
 
372
        return $this->getArtisan()->output();
373
    }
374
 
375
    /**
376
     * Bootstrap the application for artisan commands.
377
     *
378
     * @return void
379
     */
380
    public function bootstrap()
381
    {
382
        if (! $this->app->hasBeenBootstrapped()) {
383
            $this->app->bootstrapWith($this->bootstrappers());
384
        }
385
 
386
        $this->app->loadDeferredProviders();
387
 
388
        if (! $this->commandsLoaded) {
389
            $this->commands();
390
 
391
            $this->commandsLoaded = true;
392
        }
393
    }
394
 
395
    /**
396
     * Bootstrap the application without booting service providers.
397
     *
398
     * @return void
399
     */
400
    public function bootstrapWithoutBootingProviders()
401
    {
402
        $this->app->bootstrapWith(
403
            collect($this->bootstrappers())->reject(function ($bootstrapper) {
404
                return $bootstrapper === \Illuminate\Foundation\Bootstrap\BootProviders::class;
405
            })->all()
406
        );
407
    }
408
 
409
    /**
410
     * Get the Artisan application instance.
411
     *
412
     * @return \Illuminate\Console\Application
413
     */
414
    protected function getArtisan()
415
    {
416
        if (is_null($this->artisan)) {
417
            $this->artisan = (new Artisan($this->app, $this->events, $this->app->version()))
418
                                    ->resolveCommands($this->commands)
419
                                    ->setContainerCommandLoader();
420
        }
421
 
422
        return $this->artisan;
423
    }
424
 
425
    /**
426
     * Set the Artisan application instance.
427
     *
428
     * @param  \Illuminate\Console\Application  $artisan
429
     * @return void
430
     */
431
    public function setArtisan($artisan)
432
    {
433
        $this->artisan = $artisan;
434
    }
435
 
436
    /**
437
     * Get the bootstrap classes for the application.
438
     *
439
     * @return array
440
     */
441
    protected function bootstrappers()
442
    {
443
        return $this->bootstrappers;
444
    }
445
 
446
    /**
447
     * Report the exception to the exception handler.
448
     *
449
     * @param  \Throwable  $e
450
     * @return void
451
     */
452
    protected function reportException(Throwable $e)
453
    {
454
        $this->app[ExceptionHandler::class]->report($e);
455
    }
456
 
457
    /**
458
     * Render the given exception.
459
     *
460
     * @param  \Symfony\Component\Console\Output\OutputInterface  $output
461
     * @param  \Throwable  $e
462
     * @return void
463
     */
464
    protected function renderException($output, Throwable $e)
465
    {
466
        $this->app[ExceptionHandler::class]->renderForConsole($output, $e);
467
    }
468
}