<?php 
 
/* 
 * This file is part of Chevere. 
 * 
 * (c) Rodolfo Berrios <[email protected]> 
 * 
 * For the full copyright and license information, please view the LICENSE 
 * file that was distributed with this source code. 
 */ 
 
declare(strict_types=1); 
 
namespace Chevere\Xr; 
 
use Chevere\ThrowableHandler\Formats\ThrowableHandlerHtmlFormat; 
use Chevere\ThrowableHandler\Interfaces\ThrowableHandlerFormatInterface; 
use Chevere\ThrowableHandler\Interfaces\ThrowableReadInterface; 
use Chevere\ThrowableHandler\ThrowableRead; 
use Chevere\Trace\TraceDocument; 
use Throwable; 
 
class XrThrowableParser 
{ 
    private string $topic = ''; 
 
    private string $body = ''; 
 
    private string $emote = '??Throwable'; 
 
    private ThrowableHandlerFormatInterface $format; 
 
    private int $index = 0; 
 
    public const OPEN_TEMPLATE = '<div class="throwable">'; 
 
    public const CLOSE_TEMPLATE = '</div>'; 
 
    public const ITEM_TEMPLATE = <<<HTML 
        <div class="throwable-item"> 
            <h2 class="throwable-title">%title%</h2> 
            <div class="throwable-code">%code%</div> 
            <div class="throwable-message">%message%</div> 
            %extra% 
            <div class="throwable-backtrace backtrace">%trace%</div> 
        </div> 
    HTML; 
 
    public function __construct( 
        private Throwable $throwable, 
        private string $extra = '', 
    ) { 
        $this->throwableRead = new ThrowableRead($throwable); 
        $this->format = new ThrowableHandlerHtmlFormat(); 
        $this->topic = basename( 
            str_replace( 
                '\\', 
                DIRECTORY_SEPARATOR, 
                $this->throwableRead->className() 
            ) 
        ); 
        $this->appendBodyLine(static::OPEN_TEMPLATE); 
        do { 
            $this->index++; 
        } while ($throwable = $this->parse($throwable)); 
        $this->appendBodyLine(static::CLOSE_TEMPLATE); 
    } 
 
    public function body(): string 
    { 
        return $this->body; 
    } 
 
    public function topic(): string 
    { 
        return $this->topic; 
    } 
 
    public function emote(): string 
    { 
        return $this->emote; 
    } 
 
    public function throwableRead(): ThrowableReadInterface 
    { 
        return $this->throwableRead; 
    } 
 
    private function appendBodyLine(string $body): void 
    { 
        $this->body .= $body . "\n"; 
    } 
 
    private function parse(Throwable $throwable): ?Throwable 
    { 
        if ($this->index === 1) { 
            $read = $this->throwableRead; 
            $trace = $this->throwableRead->trace(); 
        } else { 
            $read = new ThrowableRead($throwable); 
            $trace = [ 
                [ 
                    'function' => '{main}', 
                    'file' => $read->file(), 
                    'line' => $read->line(), 
                ] 
            ]; 
        } 
        $traceDocument = new TraceDocument($trace, $this->format); 
        $translate = [ 
                '%title%' => $read->className(), 
                '%code%' => $read->code(), 
                '%message%' => $read->message(), 
                '%extra%' => $this->index === 1 
                    ? $this->extra 
                    : '', 
                '%trace%' => $traceDocument->__toString(), 
            ]; 
        $this->appendBodyLine(strtr(static::ITEM_TEMPLATE, $translate)); 
 
        return $throwable->getPrevious(); 
    } 
} 
 
 |