Вход Регистрация
Файл: vendor/nunomaduro/collision/src/Writer.php
Строк: 395
<?php

declare(strict_types=1);

namespace 
NunoMaduroCollision;

use 
NunoMaduroCollisionContractsArgumentFormatter as ArgumentFormatterContract;
use 
NunoMaduroCollisionContractsHighlighter as HighlighterContract;
use 
NunoMaduroCollisionContractsRenderlessEditor;
use 
NunoMaduroCollisionContractsRenderlessTrace;
use 
NunoMaduroCollisionContractsSolutionsRepository;
use 
NunoMaduroCollisionContractsWriter as WriterContract;
use 
NunoMaduroCollisionSolutionsRepositoriesNullSolutionsRepository;
use 
SymfonyComponentConsoleOutputConsoleOutput;
use 
SymfonyComponentConsoleOutputOutputInterface;
use 
WhoopsExceptionFrame;
use 
WhoopsExceptionInspector;

/**
 * @internal
 *
 * @see TestsUnitWriterTest
 */
final class Writer implements WriterContract
{
    
/**
     * The number of frames if no verbosity is specified.
     */
    
public const VERBOSITY_NORMAL_FRAMES 1;

    
/**
     * Holds an instance of the solutions repository.
     *
     * @var NunoMaduroCollisionContractsSolutionsRepository
     */
    
private $solutionsRepository;

    
/**
     * Holds an instance of the Output.
     *
     * @var SymfonyComponentConsoleOutputOutputInterface
     */
    
protected $output;

    
/**
     * Holds an instance of the Argument Formatter.
     *
     * @var NunoMaduroCollisionContractsArgumentFormatter
     */
    
protected $argumentFormatter;

    
/**
     * Holds an instance of the Highlighter.
     *
     * @var NunoMaduroCollisionContractsHighlighter
     */
    
protected $highlighter;

    
/**
     * Ignores traces where the file string matches one
     * of the provided regex expressions.
     *
     * @var string[]
     */
    
protected $ignore = [];

    
/**
     * Declares whether or not the trace should appear.
     *
     * @var bool
     */
    
protected $showTrace true;

    
/**
     * Declares whether or not the title should appear.
     *
     * @var bool
     */
    
protected $showTitle true;

    
/**
     * Declares whether or not the editor should appear.
     *
     * @var bool
     */
    
protected $showEditor true;

    
/**
     * Creates an instance of the writer.
     */
    
public function __construct(
        
SolutionsRepository $solutionsRepository null,
        
OutputInterface $output null,
        
ArgumentFormatterContract $argumentFormatter null,
        
HighlighterContract $highlighter null
    
) {
        
$this->solutionsRepository $solutionsRepository ?: new NullSolutionsRepository();
        
$this->output $output ?: new ConsoleOutput();
        
$this->argumentFormatter $argumentFormatter ?: new ArgumentFormatter();
        
$this->highlighter $highlighter ?: new Highlighter();
    }

    
/**
     * {@inheritdoc}
     */
    
public function write(Inspector $inspector): void
    
{
        
$this->renderTitleAndDescription($inspector);

        
$frames $this->getFrames($inspector);

        
$editorFrame array_shift($frames);

        
$exception $inspector->getException();

        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('');
        }
    }

    
/**
     * {@inheritdoc}
     */
    
public function ignoreFilesIn(array $ignore): WriterContract
    
{
        
$this->ignore $ignore;

        return 
$this;
    }

    
/**
     * {@inheritdoc}
     */
    
public function showTrace(bool $show): WriterContract
    
{
        
$this->showTrace $show;

        return 
$this;
    }

    
/**
     * {@inheritdoc}
     */
    
public function showTitle(bool $show): WriterContract
    
{
        
$this->showTitle $show;

        return 
$this;
    }

    
/**
     * {@inheritdoc}
     */
    
public function showEditor(bool $show): WriterContract
    
{
        
$this->showEditor $show;

        return 
$this;
    }

    
/**
     * {@inheritdoc}
     */
    
public function setOutput(OutputInterface $output): WriterContract
    
{
        
$this->output $output;

        return 
$this;
    }

    
/**
     * {@inheritdoc}
     */
    
public function getOutput(): OutputInterface
    
{
        return 
$this->output;
    }

    
/**
     * Returns pertinent frames.
     */
    
protected 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) {
                        
// Ensure paths are linux-style (like the ones on $this->ignore)
                        // @phpstan-ignore-next-line
                        
$sanitizedPath = (string) str_replace('\', '/', $frame->getFile());
                        if (preg_match($ignore, $sanitizedPath)) {
                            return false;
                        }
                    }

                    return true;
                }
            )
            ->getArray();
    }

    /**
     * Renders the title of the exception.
     */
    protected function renderTitleAndDescription(Inspector $inspector): WriterContract
    {
        $exception = $inspector->getException();
        $message = rtrim($exception->getMessage());
        $class = $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.
     */
    protected function renderSolution(Inspector $inspector): WriterContract
    {
        $throwable = $inspector->getException();
        $solutions = $this->solutionsRepository->getFromThrowable($throwable);

        foreach ($solutions as $solution) {
            /** @var SpatieIgnitionContractsSolution $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',
                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.
     */
    protected function renderEditor(Frame $frame): WriterContract
    {
        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.
     */
    protected function renderTrace(array $frames): WriterContract
    {
        $vendorFrames = 0;
        $userFrames = 0;
        foreach ($frames as $i => $frame) {
            if ($this->output->getVerbosity() < OutputInterface::VERBOSITY_VERBOSE && strpos($frame->getFile(), '
/vendor/') !== false) {
                $vendorFrames++;

                continue;
            }

            if ($userFrames > static::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->write(
                    sprintf("n      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</>");
            $this->render("<fg=gray>    $class$function($args)</>", false);
        }

        return $this;
    }

    /**
     * Renders an message into the console.
     *
     * @return $this
     */
    protected function render(string $message, bool $break = true): WriterContract
    {
        if ($break) {
            $this->output->writeln('');
        }

        $this->output->writeln("  $message");

        return $this;
    }

    /**
     * Returns the relative path of the given file path.
     */
    protected function getFileRelativePath(string $filePath): string
    {
        $cwd = (string) getcwd();

        if (! empty($cwd)) {
            return str_replace("$cwd/", '', $filePath);
        }

        return $filePath;
    }
}
Онлайн: 0
Реклама