Revision 148 | Blame | Vergleich mit vorheriger | Letzte Änderung | Log anzeigen | RSS feed
<?phpnamespace Illuminate\Foundation\Console;use Carbon\CarbonInterval;use Closure;use DateTimeInterface;use Illuminate\Console\Application as Artisan;use Illuminate\Console\Command;use Illuminate\Console\Scheduling\Schedule;use Illuminate\Contracts\Console\Kernel as KernelContract;use Illuminate\Contracts\Debug\ExceptionHandler;use Illuminate\Contracts\Events\Dispatcher;use Illuminate\Contracts\Foundation\Application;use Illuminate\Support\Arr;use Illuminate\Support\Carbon;use Illuminate\Support\Env;use Illuminate\Support\InteractsWithTime;use Illuminate\Support\Str;use ReflectionClass;use Symfony\Component\Finder\Finder;use Throwable;class Kernel implements KernelContract{use InteractsWithTime;/*** The application implementation.** @var \Illuminate\Contracts\Foundation\Application*/protected $app;/*** The event dispatcher implementation.** @var \Illuminate\Contracts\Events\Dispatcher*/protected $events;/*** The Artisan application instance.** @var \Illuminate\Console\Application|null*/protected $artisan;/*** The Artisan commands provided by the application.** @var array*/protected $commands = [];/*** Indicates if the Closure commands have been loaded.** @var bool*/protected $commandsLoaded = false;/*** All of the registered command duration handlers.** @var array*/protected $commandLifecycleDurationHandlers = [];/*** When the currently handled command started.** @var \Illuminate\Support\Carbon|null*/protected $commandStartedAt;/*** The bootstrap classes for the application.** @var string[]*/protected $bootstrappers = [\Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,\Illuminate\Foundation\Bootstrap\LoadConfiguration::class,\Illuminate\Foundation\Bootstrap\HandleExceptions::class,\Illuminate\Foundation\Bootstrap\RegisterFacades::class,\Illuminate\Foundation\Bootstrap\SetRequestForConsole::class,\Illuminate\Foundation\Bootstrap\RegisterProviders::class,\Illuminate\Foundation\Bootstrap\BootProviders::class,];/*** Create a new console kernel instance.** @param \Illuminate\Contracts\Foundation\Application $app* @param \Illuminate\Contracts\Events\Dispatcher $events* @return void*/public function __construct(Application $app, Dispatcher $events){if (! defined('ARTISAN_BINARY')) {define('ARTISAN_BINARY', 'artisan');}$this->app = $app;$this->events = $events;$this->app->booted(function () {$this->defineConsoleSchedule();});}/*** Define the application's command schedule.** @return void*/protected function defineConsoleSchedule(){$this->app->singleton(Schedule::class, function ($app) {return tap(new Schedule($this->scheduleTimezone()), function ($schedule) {$this->schedule($schedule->useCache($this->scheduleCache()));});});}/*** Get the name of the cache store that should manage scheduling mutexes.** @return string*/protected function scheduleCache(){return $this->app['config']->get('cache.schedule_store', Env::get('SCHEDULE_CACHE_DRIVER'));}/*** Run the console application.** @param \Symfony\Component\Console\Input\InputInterface $input* @param \Symfony\Component\Console\Output\OutputInterface|null $output* @return int*/public function handle($input, $output = null){$this->commandStartedAt = Carbon::now();try {if (in_array($input->getFirstArgument(), ['env:encrypt', 'env:decrypt'], true)) {$this->bootstrapWithoutBootingProviders();}$this->bootstrap();return $this->getArtisan()->run($input, $output);} catch (Throwable $e) {$this->reportException($e);$this->renderException($output, $e);return 1;}}/*** Terminate the application.** @param \Symfony\Component\Console\Input\InputInterface $input* @param int $status* @return void*/public function terminate($input, $status){$this->app->terminate();foreach ($this->commandLifecycleDurationHandlers as ['threshold' => $threshold, 'handler' => $handler]) {$end ??= Carbon::now();if ($this->commandStartedAt->diffInMilliseconds($end) > $threshold) {$handler($this->commandStartedAt, $input, $status);}}$this->commandStartedAt = null;}/*** Register a callback to be invoked when the command lifecycle duration exceeds a given amount of time.** @param \DateTimeInterface|\Carbon\CarbonInterval|float|int $threshold* @param callable $handler* @return void*/public function whenCommandLifecycleIsLongerThan($threshold, $handler){$threshold = $threshold instanceof DateTimeInterface? $this->secondsUntil($threshold) * 1000: $threshold;$threshold = $threshold instanceof CarbonInterval? $threshold->totalMilliseconds: $threshold;$this->commandLifecycleDurationHandlers[] = ['threshold' => $threshold,'handler' => $handler,];}/*** When the command being handled started.** @return \Illuminate\Support\Carbon|null*/public function commandStartedAt(){return $this->commandStartedAt;}/*** Define the application's command schedule.** @param \Illuminate\Console\Scheduling\Schedule $schedule* @return void*/protected function schedule(Schedule $schedule){//}/*** Get the timezone that should be used by default for scheduled events.** @return \DateTimeZone|string|null*/protected function scheduleTimezone(){$config = $this->app['config'];return $config->get('app.schedule_timezone', $config->get('app.timezone'));}/*** Register the commands for the application.** @return void*/protected function commands(){//}/*** Register a Closure based command with the application.** @param string $signature* @param \Closure $callback* @return \Illuminate\Foundation\Console\ClosureCommand*/public function command($signature, Closure $callback){$command = new ClosureCommand($signature, $callback);Artisan::starting(function ($artisan) use ($command) {$artisan->add($command);});return $command;}/*** Register all of the commands in the given directory.** @param array|string $paths* @return void*/protected function load($paths){$paths = array_unique(Arr::wrap($paths));$paths = array_filter($paths, function ($path) {return is_dir($path);});if (empty($paths)) {return;}$namespace = $this->app->getNamespace();foreach ((new Finder)->in($paths)->files() as $command) {$command = $namespace.str_replace(['/', '.php'],['\\', ''],Str::after($command->getRealPath(), realpath(app_path()).DIRECTORY_SEPARATOR));if (is_subclass_of($command, Command::class) &&! (new ReflectionClass($command))->isAbstract()) {Artisan::starting(function ($artisan) use ($command) {$artisan->resolve($command);});}}}/*** Register the given command with the console application.** @param \Symfony\Component\Console\Command\Command $command* @return void*/public function registerCommand($command){$this->getArtisan()->add($command);}/*** Run an Artisan console command by name.** @param string $command* @param array $parameters* @param \Symfony\Component\Console\Output\OutputInterface|null $outputBuffer* @return int** @throws \Symfony\Component\Console\Exception\CommandNotFoundException*/public function call($command, array $parameters = [], $outputBuffer = null){if (in_array($command, ['env:encrypt', 'env:decrypt'], true)) {$this->bootstrapWithoutBootingProviders();}$this->bootstrap();return $this->getArtisan()->call($command, $parameters, $outputBuffer);}/*** Queue the given console command.** @param string $command* @param array $parameters* @return \Illuminate\Foundation\Bus\PendingDispatch*/public function queue($command, array $parameters = []){return QueuedCommand::dispatch(func_get_args());}/*** Get all of the commands registered with the console.** @return array*/public function all(){$this->bootstrap();return $this->getArtisan()->all();}/*** Get the output for the last run command.** @return string*/public function output(){$this->bootstrap();return $this->getArtisan()->output();}/*** Bootstrap the application for artisan commands.** @return void*/public function bootstrap(){if (! $this->app->hasBeenBootstrapped()) {$this->app->bootstrapWith($this->bootstrappers());}$this->app->loadDeferredProviders();if (! $this->commandsLoaded) {$this->commands();$this->commandsLoaded = true;}}/*** Bootstrap the application without booting service providers.** @return void*/public function bootstrapWithoutBootingProviders(){$this->app->bootstrapWith(collect($this->bootstrappers())->reject(function ($bootstrapper) {return $bootstrapper === \Illuminate\Foundation\Bootstrap\BootProviders::class;})->all());}/*** Get the Artisan application instance.** @return \Illuminate\Console\Application*/protected function getArtisan(){if (is_null($this->artisan)) {$this->artisan = (new Artisan($this->app, $this->events, $this->app->version()))->resolveCommands($this->commands)->setContainerCommandLoader();}return $this->artisan;}/*** Set the Artisan application instance.** @param \Illuminate\Console\Application $artisan* @return void*/public function setArtisan($artisan){$this->artisan = $artisan;}/*** Get the bootstrap classes for the application.** @return array*/protected function bootstrappers(){return $this->bootstrappers;}/*** Report the exception to the exception handler.** @param \Throwable $e* @return void*/protected function reportException(Throwable $e){$this->app[ExceptionHandler::class]->report($e);}/*** Render the given exception.** @param \Symfony\Component\Console\Output\OutputInterface $output* @param \Throwable $e* @return void*/protected function renderException($output, Throwable $e){$this->app[ExceptionHandler::class]->renderForConsole($output, $e);}}