Skip to content

Render exception class PHPDoc description in HTML debug output#167

Open
dbuhonov wants to merge 1 commit intoyiisoft:masterfrom
dbuhonov:feature/104-render-exception-description
Open

Render exception class PHPDoc description in HTML debug output#167
dbuhonov wants to merge 1 commit intoyiisoft:masterfrom
dbuhonov:feature/104-render-exception-description

Conversation

@dbuhonov
Copy link

@dbuhonov dbuhonov commented Mar 6, 2026

Q A
Is bugfix? ✔️
New feature? ✔️
Breaks BC?
Fixed issues #104
CleanShot 2026-03-06 at 18 00 02@2x

@codecov
Copy link

codecov bot commented Mar 6, 2026

Codecov Report

❌ Patch coverage is 94.44444% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.49%. Comparing base (32c8a4e) to head (8918890).

Files with missing lines Patch % Lines
src/Renderer/HtmlRenderer.php 94.44% 2 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master     #167      +/-   ##
============================================
+ Coverage     79.39%   85.49%   +6.10%     
- Complexity      196      208      +12     
============================================
  Files            19       19              
  Lines           626      662      +36     
============================================
+ Hits            497      566      +69     
+ Misses          129       96      -33     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@dbuhonov dbuhonov force-pushed the feature/104-render-exception-description branch 2 times, most recently from 7cd35a2 to fe553f4 Compare March 6, 2026 14:40
@dbuhonov dbuhonov force-pushed the feature/104-render-exception-description branch from fe553f4 to 8918890 Compare March 6, 2026 14:42
@samdark samdark requested a review from Copilot March 6, 2026 16:52
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support for showing an exception class’ PHPDoc summary/details in the verbose HTML debug page, including basic rendering of inline {@see ...} / {@link ...} annotations, for exceptions that don’t implement FriendlyExceptionInterface.

Changes:

  • Extract throwable class description from PHPDoc and pass it into the verbose template.
  • Render the extracted description in templates/development.php using the existing markdown pipeline.
  • Add PHPUnit coverage and supporting test exception classes.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/Renderer/HtmlRenderer.php Adds PHPDoc description extraction + inline tag normalization and passes result to the verbose template.
templates/development.php Renders the new $exceptionDescription block in verbose HTML output.
tests/Renderer/HtmlRendererTest.php Adds tests covering rendering behavior for docblock/no-docblock/friendly-exception cases.
tests/Support/TestDocBlockException.php New fixture exception with PHPDoc containing inline tags.
tests/Support/TestExceptionWithoutDocBlock.php New fixture exception without a PHPDoc.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +563 to +609
private function getThrowableDescription(Throwable $throwable): ?string
{
$docComment = (new ReflectionClass($throwable))->getDocComment();
if ($docComment === false) {
return null;
}

$descriptionLines = [];
foreach (preg_split('/\R/', $docComment) ?: [] as $line) {
$line = trim($line);
$line = preg_replace('/^\/\*\*?/', '', $line) ?? $line;
$line = preg_replace('/\*\/$/', '', $line) ?? $line;
$line = preg_replace('/^\*/', '', $line) ?? $line;
$line = trim($line);

if ($line !== '' && str_starts_with($line, '@')) {
break;
}

$descriptionLines[] = $line;
}

$description = trim(implode("\n", $descriptionLines));
if ($description === '') {
return null;
}

return preg_replace_callback(
'/\{@(see|link)\s+([^\s}]+)(?:\s+([^}]+))?\}/i',
static function (array $matches): string {
$target = $matches[2];
$label = trim($matches[3] ?? '');

if (preg_match('/^https?:\/\//i', $target) === 1) {
$text = $label !== '' ? $label : $target;
return '[' . $text . '](' . $target . ')';
}

if ($label !== '') {
return $label . ' (`' . $target . '`)';
}

return '`' . $target . '`';
},
$description,
) ?? $description;
}
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getThrowableDescription() returns raw PHPDoc text (with inline tag substitutions) that can contain arbitrary HTML/Markdown. Because parseMarkdown() does not sanitize attributes/URL schemes, a PHPDoc containing HTML like <img onerror=...> or markdown links to javascript: could result in XSS when rendered. Consider escaping/removing raw HTML in the extracted description and validating link/image URL schemes before handing it to the markdown renderer.

Copilot uses AI. Check for mistakes.
</div>

<?php if ($exceptionDescription !== null): ?>
<div class="exception-description solution"><?= $this->parseMarkdown($exceptionDescription) ?></div>
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$exceptionDescription ultimately gets rendered via parseMarkdown(), which allows raw HTML output from the Markdown parser and keeps tags like <a>/<img> without stripping unsafe attributes (e.g. onerror, onclick) or javascript: URLs. Since the description is sourced from third‑party exception class PHPDoc, it should be treated as untrusted and sanitized/escaped before rendering to avoid XSS in the debug page (e.g. escape HTML before parsing markdown and/or sanitize allowed tags/attributes + URL schemes).

Suggested change
<div class="exception-description solution"><?= $this->parseMarkdown($exceptionDescription) ?></div>
<div class="exception-description solution"><?= $this->parseMarkdown($this->htmlEncode($exceptionDescription)) ?></div>

Copilot uses AI. Check for mistakes.
@samdark
Copy link
Member

samdark commented Mar 6, 2026

Overall, a very nice addition. Would be good to address the security part. I think that plain HTML should be either escaped or stripped before rendering but markdown part should be converted to HTML.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants