app->hasBeenBootstrapped()) { $this->app->bootstrapWith($this->bootstrappers()); } $this->app->loadDeferredProviders(); if (! $this->commandsLoaded) { $this->commands(); if ($this->shouldDiscoverCommands()) { $this->discoverCommands(); } $this->commandsLoaded = true; } } /** * Handle an incoming console command. * * @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(); } if ($domain = $input->getParameterOption('--domain')) { $this->setDomain($domain); } $this->bootstrap(); self::dispatch_event('console.bootstrapped', ['kernel' => $this, 'command' => $input]); return $this->getArtisan()->run($input, $output); } catch (\Throwable $e) { $this->reportException($e); $this->renderException($output, $e); return 1; } } // We need to overwrite this because for some reason Laravel decided to only do command discovery if being called // from the original kernel protected function shouldDiscoverCommands() { return get_class($this) === __CLASS__; } protected function discoverCommands() { // Update standard commandPath $this->commandPaths = [ APP_ROOT.'/app/Command/', ]; foreach ($this->commandPaths as $path) { $this->load($path); } // Load Dynamic command paths for leantime $ltCommands = collect(glob(APP_ROOT.'/app/Domain/**/Command/')); // Load commands from enabled plugins try { $pluginService = app()->make(\Leantime\Core\Plugins\Plugins::class); $enabledPluginPaths = $pluginService->getEnabledPluginPaths(); foreach ($enabledPluginPaths as $pluginInfo) { $commandPath = $pluginInfo['path'].'/Command/'; if (is_dir($commandPath)) { if ($pluginInfo['format'] == 'phar') { include_once $pluginInfo['path']; $this->loadPhar($commandPath, $pluginInfo['foldername'].'.phar'); } $this->load($commandPath); } } } catch (\Exception $e) { // Fallback to scanning all plugin directories if service unavailable $ltPluginCommands = collect(glob(APP_ROOT.'/app/Plugins/**/Command/')); foreach ($ltPluginCommands as $pluginPath) { $this->load($pluginPath); } } foreach ($this->commandRoutePaths as $path) { if (file_exists($path)) { require $path; } } } public function call($command, array $parameters = [], $outputBuffer = null) { if (array_key_exists('--domain', $parameters)) { $this->setDomain($parameters['--domain']); } if (in_array($command, ['env:encrypt', 'env:decrypt'], true)) { $this->bootstrapWithoutBootingProviders(); } $this->bootstrap(); self::dispatch_event('console.bootstrapped', ['kernel' => $this, 'command' => $command]); return $this->getArtisan()->call($command, $parameters, $outputBuffer); } public function getArtisan() { if (is_null($this->artisan)) { $this->artisan = (new LeantimeCli($this->app, $this->events, $this->app->version())) ->resolveCommands($this->commands) ->setContainerCommandLoader(); if ($this->symfonyDispatcher instanceof EventDispatcher) { $this->artisan->setDispatcher($this->symfonyDispatcher); $this->artisan->setSignalsToDispatchEvent(); } } return $this->artisan; } protected function schedule(Schedule $schedule) { // Set default timezone // config(['app.timezone' => config('defaultTimezone')]); config(['schedule_timezone' => 'UTC']); self::dispatch_event('cron', ['schedule' => $schedule], 'schedule'); } public function setDomain(string $domain) { if ($domain) { putenv('LEAN_APP_URL='.$domain); putenv('APP_URL='.$domain); // When calling commands inside the app we can switch domains if (isset($this->app['config'])) { config(['app.url' => $domain]); config(['appUrl' => $domain]); } } } protected function loadPhar($paths, $pharName) { $paths = array_unique(Arr::wrap($paths)); $paths = array_filter($paths, function ($path) { return is_dir($path); }); if (empty($paths)) { return; } $this->loadedPaths = array_values( array_unique(array_merge($this->loadedPaths, $paths)) ); $namespace = $this->app->getNamespace(); foreach (Finder::create()->in($paths)->files() as $file) { $command = $namespace.str_replace( ['/', '.php', '\\'.$pharName], ['\\', '', ''], Str::after($file->getPath().DIRECTORY_SEPARATOR.$file->getFilename(), 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); }); } } } }