%PDF- %PDF-
Direktori : /home/silvzytp/crm-ind-code/vendor/laravel/framework/src/Illuminate/Foundation/Console/ |
Current File : //home/silvzytp/crm-ind-code/vendor/laravel/framework/src/Illuminate/Foundation/Console/DocsCommand.php |
<?php namespace Illuminate\Foundation\Console; use Carbon\CarbonInterval; use Illuminate\Console\Command; use Illuminate\Contracts\Cache\Repository as Cache; use Illuminate\Http\Client\Factory as Http; use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Support\Env; use Illuminate\Support\Str; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Process\Exception\ProcessFailedException; use Symfony\Component\Process\ExecutableFinder; use Symfony\Component\Process\Process; use Throwable; #[AsCommand(name: 'docs')] class DocsCommand extends Command { /** * The name and signature of the console command. * * @var string */ protected $signature = 'docs {page? : The documentation page to open} {section? : The section of the page to open}'; /** * The name of the console command. * * This name is used to identify the command during lazy loading. * * @var string|null * * @deprecated */ protected static $defaultName = 'docs'; /** * The console command description. * * @var string */ protected $description = 'Access the Laravel documentation'; /** * The console command help text. * * @var string */ protected $help = 'If you would like to perform a content search against the documention, you may call: <fg=green>php artisan docs -- </><fg=green;options=bold;>search query here</>'; /** * The HTTP client instance. * * @var \Illuminate\Http\Client\Factory */ protected $http; /** * The cache repository implementation. * * @var \Illuminate\Contracts\Cache\Repository */ protected $cache; /** * The custom URL opener. * * @var callable|null */ protected $urlOpener; /** * The custom documentation version to open. * * @var string|null */ protected $version; /** * The operating system family. * * @var string */ protected $systemOsFamily = PHP_OS_FAMILY; /** * Create a new command instance. * * @param \Illuminate\Http\Client\Factory $http * @param \Illuminate\Contracts\Cache\Repository $cache * @return void */ public function __construct(Http $http, Cache $cache) { parent::__construct(); $this->http = $http; $this->cache = $cache; } /** * Configure the current command. * * @return void */ protected function configure() { parent::configure(); if ($this->isSearching()) { $this->ignoreValidationErrors(); } } /** * Execute the console command. * * @return int */ public function handle() { try { $this->openUrl(); } catch (ProcessFailedException $e) { if ($e->getProcess()->getExitCodeText() === 'Interrupt') { return $e->getProcess()->getExitCode(); } throw $e; } $this->refreshDocs(); return Command::SUCCESS; } /** * Open the documentation URL. * * @return void */ protected function openUrl() { with($this->url(), function ($url) { $this->components->info("Opening the docs to: <fg=yellow>{$url}</>"); $this->open($url); }); } /** * The URL to the documentation page. * * @return string */ protected function url() { if ($this->isSearching()) { return "https://laravel.com/docs/{$this->version()}?".Arr::query([ 'q' => $this->searchQuery(), ]); } return with($this->page(), function ($page) { return trim("https://laravel.com/docs/{$this->version()}/{$page}#{$this->section($page)}", '#/'); }); } /** * The page the user is opening. * * @return string */ protected function page() { return with($this->resolvePage(), function ($page) { if ($page === null) { $this->components->warn('Unable to determine the page you are trying to visit.'); return '/'; } return $page; }); } /** * Determine the page to open. * * @return ?string */ protected function resolvePage() { if ($this->option('no-interaction') && $this->didNotRequestPage()) { return '/'; } return $this->didNotRequestPage() ? $this->askForPage() : $this->guessPage(); } /** * Determine if the user requested a specific page when calling the command. * * @return bool */ protected function didNotRequestPage() { return $this->argument('page') === null; } /** * Ask the user which page they would like to open. * * @return ?string */ protected function askForPage() { return $this->askForPageViaCustomStrategy() ?? $this->askForPageViaAutocomplete(); } /** * Ask the user which page they would like to open via a custom strategy. * * @return ?string */ protected function askForPageViaCustomStrategy() { try { $strategy = require Env::get('ARTISAN_DOCS_ASK_STRATEGY'); } catch (Throwable $e) { return null; } if (! is_callable($strategy)) { return null; } return $strategy($this) ?? '/'; } /** * Ask the user which page they would like to open using autocomplete. * * @return ?string */ protected function askForPageViaAutocomplete() { $choice = $this->components->choice( 'Which page would you like to open?', $this->pages()->mapWithKeys(fn ($option) => [ Str::lower($option['title']) => $option['title'], ])->all(), 'installation', 3 ); return $this->pages()->filter( fn ($page) => $page['title'] === $choice || Str::lower($page['title']) === $choice )->keys()->first() ?: null; } /** * Guess the page the user is attempting to open. * * @return ?string */ protected function guessPage() { return $this->pages() ->filter(fn ($page) => str_starts_with( Str::slug($page['title'], ' '), Str::slug($this->argument('page'), ' ') ))->keys()->first() ?? $this->pages()->map(fn ($page) => similar_text( Str::slug($page['title'], ' '), Str::slug($this->argument('page'), ' '), )) ->filter(fn ($score) => $score >= min(3, Str::length($this->argument('page')))) ->sortDesc() ->keys() ->sortByDesc(fn ($slug) => Str::contains( Str::slug($this->pages()[$slug]['title'], ' '), Str::slug($this->argument('page'), ' ') ) ? 1 : 0) ->first(); } /** * The section the user specifically asked to open. * * @param string $page * @return ?string */ protected function section($page) { return $this->didNotRequestSection() ? null : $this->guessSection($page); } /** * Determine if the user requested a specific section when calling the command. * * @return bool */ protected function didNotRequestSection() { return $this->argument('section') === null; } /** * Guess the section the user is attempting to open. * * @param string $page * @return ?string */ protected function guessSection($page) { return $this->sectionsFor($page) ->filter(fn ($section) => str_starts_with( Str::slug($section['title'], ' '), Str::slug($this->argument('section'), ' ') ))->keys()->first() ?? $this->sectionsFor($page)->map(fn ($section) => similar_text( Str::slug($section['title'], ' '), Str::slug($this->argument('section'), ' '), )) ->filter(fn ($score) => $score >= min(3, Str::length($this->argument('section')))) ->sortDesc() ->keys() ->sortByDesc(fn ($slug) => Str::contains( Str::slug($this->sectionsFor($page)[$slug]['title'], ' '), Str::slug($this->argument('section'), ' ') ) ? 1 : 0) ->first(); } /** * Open the URL in the user's browser. * * @param string $url * @return void */ protected function open($url) { ($this->urlOpener ?? function ($url) { if (Env::get('ARTISAN_DOCS_OPEN_STRATEGY')) { $this->openViaCustomStrategy($url); } elseif (in_array($this->systemOsFamily, ['Darwin', 'Windows', 'Linux'])) { $this->openViaBuiltInStrategy($url); } else { $this->components->warn('Unable to open the URL on your system. You will need to open it yourself or create a custom opener for your system.'); } })($url); } /** * Open the URL via a custom strategy. * * @param string $url * @return void */ protected function openViaCustomStrategy($url) { try { $command = require Env::get('ARTISAN_DOCS_OPEN_STRATEGY'); } catch (Throwable $e) { $command = null; } if (! is_callable($command)) { $this->components->warn('Unable to open the URL with your custom strategy. You will need to open it yourself.'); return; } $command($url); } /** * Open the URL via the built in strategy. * * @param string $url * @return void */ protected function openViaBuiltInStrategy($url) { if ($this->systemOsFamily === 'Windows') { $process = tap(Process::fromShellCommandline(escapeshellcmd("start {$url}")))->run(); if (! $process->isSuccessful()) { throw new ProcessFailedException($process); } return; } $binary = Collection::make(match ($this->systemOsFamily) { 'Darwin' => ['open'], 'Linux' => ['xdg-open', 'wslview'], })->first(fn ($binary) => (new ExecutableFinder)->find($binary) !== null); if ($binary === null) { $this->components->warn('Unable to open the URL on your system. You will need to open it yourself or create a custom opener for your system.'); return; } $process = tap(Process::fromShellCommandline(escapeshellcmd("{$binary} {$url}")))->run(); if (! $process->isSuccessful()) { throw new ProcessFailedException($process); } } /** * The available sections for the page. * * @param string $page * @return \Illuminate\Support\Collection */ public function sectionsFor($page) { return new Collection($this->pages()[$page]['sections']); } /** * The pages available to open. * * @return \Illuminate\Support\Collection */ public function pages() { return new Collection($this->docs()['pages']); } /** * Get the documentation index as a collection. * * @return \Illuminate\Support\Collection */ public function docs() { return $this->cache->remember( "artisan.docs.{{$this->version()}}.index", CarbonInterval::months(2), fn () => $this->fetchDocs()->throw()->collect() ); } /** * Refresh the cached copy of the documentation index. * * @return void */ protected function refreshDocs() { with($this->fetchDocs(), function ($response) { if ($response->successful()) { $this->cache->put("artisan.docs.{{$this->version()}}.index", $response->collect(), CarbonInterval::months(2)); } }); } /** * Fetch the documentation index from the Laravel website. * * @return \Illuminate\Http\Client\Response */ protected function fetchDocs() { return $this->http->get("https://laravel.com/docs/{$this->version()}/index.json"); } /** * Determine the version of the docs to open. * * @return string */ protected function version() { return Str::before(($this->version ?? $this->laravel->version()), '.').'.x'; } /** * The search query the user provided. * * @return string */ protected function searchQuery() { return Collection::make($_SERVER['argv'])->skip(3)->implode(' '); } /** * Determine if the command is intended to perform a search. * * @return bool */ protected function isSearching() { return ($_SERVER['argv'][2] ?? null) === '--'; } /** * Set the documentation version. * * @param string $version * @return $this */ public function setVersion($version) { $this->version = $version; return $this; } /** * Set a custom URL opener. * * @param callable|null $opener * @return $this */ public function setUrlOpener($opener) { $this->urlOpener = $opener; return $this; } /** * Set the system operating system family. * * @param string $family * @return $this */ public function setSystemOsFamily($family) { $this->systemOsFamily = $family; return $this; } }