ok
Direktori : /home2/selectio/public_html/fms-worksuite/vendor/nunomaduro/collision/src/ |
Current File : /home2/selectio/public_html/fms-worksuite/vendor/nunomaduro/collision/src/Writer.php |
<?php declare(strict_types=1); namespace NunoMaduro\Collision; use Closure; use NunoMaduro\Collision\Contracts\RenderableOnCollisionEditor; use NunoMaduro\Collision\Contracts\RenderlessEditor; use NunoMaduro\Collision\Contracts\RenderlessTrace; use NunoMaduro\Collision\Contracts\SolutionsRepository; use NunoMaduro\Collision\Exceptions\TestException; use NunoMaduro\Collision\SolutionsRepositories\NullSolutionsRepository; use Symfony\Component\Console\Output\ConsoleOutput; use Symfony\Component\Console\Output\OutputInterface; use Throwable; use Whoops\Exception\Frame; use Whoops\Exception\Inspector; /** * @internal * * @see \Tests\Unit\WriterTest */ final class Writer { /** * The number of frames if no verbosity is specified. */ public const VERBOSITY_NORMAL_FRAMES = 1; /** * Holds an instance of the solutions repository. */ private SolutionsRepository $solutionsRepository; /** * Holds an instance of the Output. */ private OutputInterface $output; /** * Holds an instance of the Argument Formatter. */ private ArgumentFormatter $argumentFormatter; /** * Holds an instance of the Highlighter. */ private Highlighter $highlighter; /** * Ignores traces where the file string matches one * of the provided regex expressions. * * @var array<int, string|Closure> */ private array $ignore = []; /** * Declares whether or not the trace should appear. */ private bool $showTrace = true; /** * Declares whether or not the title should appear. */ private bool $showTitle = true; /** * Declares whether the editor should appear. */ private bool $showEditor = true; /** * Creates an instance of the writer. */ public function __construct( SolutionsRepository $solutionsRepository = null, OutputInterface $output = null, ArgumentFormatter $argumentFormatter = null, Highlighter $highlighter = null ) { $this->solutionsRepository = $solutionsRepository ?: new NullSolutionsRepository(); $this->output = $output ?: new ConsoleOutput(); $this->argumentFormatter = $argumentFormatter ?: new ArgumentFormatter(); $this->highlighter = $highlighter ?: new Highlighter(); } public function write(Inspector $inspector): void { $this->renderTitleAndDescription($inspector); $frames = $this->getFrames($inspector); $exception = $inspector->getException(); if ($exception instanceof RenderableOnCollisionEditor) { $editorFrame = $exception->toCollisionEditor(); } else { $editorFrame = array_shift($frames); } if ($this->showEditor && $editorFrame !== null && ! $exception instanceof RenderlessEditor ) { $this->renderEditor($editorFrame); } $this->renderSolution($inspector); if ($this->showTrace && ! empty($frames) && ! $exception instanceof RenderlessTrace) { $this->renderTrace($frames); } elseif (! $exception instanceof RenderlessEditor) { $this->output->writeln(''); } } public function ignoreFilesIn(array $ignore): self { $this->ignore = $ignore; return $this; } public function showTrace(bool $show): self { $this->showTrace = $show; return $this; } public function showTitle(bool $show): self { $this->showTitle = $show; return $this; } public function showEditor(bool $show): self { $this->showEditor = $show; return $this; } public function setOutput(OutputInterface $output): self { $this->output = $output; return $this; } public function getOutput(): OutputInterface { return $this->output; } /** * Returns pertinent frames. * * @return array<int, Frame> */ private function getFrames(Inspector $inspector): array { return $inspector->getFrames() ->filter( function ($frame) { // If we are in verbose mode, we always // display the full stack trace. if ($this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { return true; } foreach ($this->ignore as $ignore) { if (is_string($ignore)) { // Ensure paths are linux-style (like the ones on $this->ignore) $sanitizedPath = (string) str_replace('\\', '/', $frame->getFile()); if (preg_match($ignore, $sanitizedPath)) { return false; } } if ($ignore instanceof Closure) { if ($ignore($frame)) { return false; } } } return true; } ) ->getArray(); } /** * Renders the title of the exception. */ private function renderTitleAndDescription(Inspector $inspector): self { /** @var Throwable|TestException $exception */ $exception = $inspector->getException(); $message = rtrim($exception->getMessage()); $class = $exception instanceof TestException ? $exception->getClassName() : $inspector->getExceptionName(); if ($this->showTitle) { $this->render("<bg=red;options=bold> $class </>"); $this->output->writeln(''); } $this->output->writeln("<fg=default;options=bold> $message</>"); return $this; } /** * Renders the solution of the exception, if any. */ private function renderSolution(Inspector $inspector): self { $throwable = $inspector->getException(); $solutions = $throwable instanceof Throwable ? $this->solutionsRepository->getFromThrowable($throwable) : []; // @phpstan-ignore-line foreach ($solutions as $solution) { /** @var \Spatie\Ignition\Contracts\Solution $solution */ $title = $solution->getSolutionTitle(); $description = $solution->getSolutionDescription(); $links = $solution->getDocumentationLinks(); $description = trim((string) preg_replace("/\n/", "\n ", $description)); $this->render(sprintf( '<fg=cyan;options=bold>i</> <fg=default;options=bold>%s</>: %s %s', rtrim($title, '.'), $description, implode(', ', array_map(function (string $link) { return sprintf("\n <fg=gray>%s</>", $link); }, $links)) )); } return $this; } /** * Renders the editor containing the code that was the * origin of the exception. */ private function renderEditor(Frame $frame): self { if ($frame->getFile() !== 'Unknown') { $file = $this->getFileRelativePath((string) $frame->getFile()); // getLine() might return null so cast to int to get 0 instead $line = (int) $frame->getLine(); $this->render('at <fg=green>'.$file.'</>'.':<fg=green>'.$line.'</>'); $content = $this->highlighter->highlight((string) $frame->getFileContents(), (int) $frame->getLine()); $this->output->writeln($content); } return $this; } /** * Renders the trace of the exception. */ private function renderTrace(array $frames): self { $vendorFrames = 0; $userFrames = 0; if (! empty($frames)) { $this->output->writeln(['']); } foreach ($frames as $i => $frame) { if ($this->output->getVerbosity() < OutputInterface::VERBOSITY_VERBOSE && strpos($frame->getFile(), '/vendor/') !== false) { $vendorFrames++; continue; } if ($userFrames > self::VERBOSITY_NORMAL_FRAMES && $this->output->getVerbosity() < OutputInterface::VERBOSITY_VERBOSE) { break; } $userFrames++; $file = $this->getFileRelativePath($frame->getFile()); $line = $frame->getLine(); $class = empty($frame->getClass()) ? '' : $frame->getClass().'::'; $function = $frame->getFunction(); $args = $this->argumentFormatter->format($frame->getArgs()); $pos = str_pad((string) ((int) $i + 1), 4, ' '); if ($vendorFrames > 0) { $this->output->writeln( sprintf(" \e[2m+%s vendor frames \e[22m", $vendorFrames) ); $vendorFrames = 0; } $this->render("<fg=yellow>$pos</><fg=default;options=bold>$file</>:<fg=default;options=bold>$line</>", (bool) $class && $i > 0); if ($class) { $this->render("<fg=gray> $class$function($args)</>", false); } } if (! empty($frames)) { $this->output->writeln(['']); } return $this; } /** * Renders a message into the console. */ private function render(string $message, bool $break = true): self { if ($break) { $this->output->writeln(''); } $this->output->writeln(" $message"); return $this; } /** * Returns the relative path of the given file path. */ private function getFileRelativePath(string $filePath): string { $cwd = (string) getcwd(); if (! empty($cwd)) { return str_replace("$cwd".DIRECTORY_SEPARATOR, '', $filePath); } return $filePath; } }