Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
BaseChangelogHelper
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 3
30
0.00% covered (danger)
0.00%
0 / 1
 getChangelogPath
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0
 getChangelogHtml
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
12
 fetchChangelogFromLocal
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3namespace BO\Slim\Helper;
4
5use League\CommonMark\CommonMarkConverter;
6use HTMLPurifier;
7use HTMLPurifier_Config;
8
9abstract class BaseChangelogHelper
10{
11    abstract protected function getChangelogPath(): string;
12    public function getChangelogHtml(): string
13    {
14        try {
15            $markdown = $this->fetchChangelogFromLocal();
16            $converter = new CommonMarkConverter();
17            $unsafeHtml = $converter->convert($markdown)->getContent();
18            // Post-process headers to move dates in parentheses to <small>(date)</small>
19            $unsafeHtml = preg_replace_callback(
20                '/<(h[1-3])>(.*?) \((\d{2}\.\d{2}\.\d{4})\)<\/h[1-3]>/',
21                function ($matches) {
22                    return '<' . $matches[1] . '>' . htmlspecialchars(trim($matches[2]), ENT_QUOTES, 'UTF-8') . ' <small>(' . htmlspecialchars($matches[3], ENT_QUOTES, 'UTF-8') . ')</small></' . $matches[1] . '>';
23                },
24                $unsafeHtml
25            );
26            $purifier = new HTMLPurifier(HTMLPurifier_Config::createDefault());
27            $safeHtml = $purifier->purify($unsafeHtml);
28            return $safeHtml;
29        } catch (\Exception $e) {
30            if (isset(\App::$log)) {
31                \App::$log->error('Failed to fetch changelog: ' . $e->getMessage());
32            }
33            return '';
34        }
35    }
36
37    private function fetchChangelogFromLocal(): string
38    {
39        $localFile = $this->getChangelogPath();
40        if (!file_exists($localFile)) {
41            throw new \Exception('Local changelog file not found: ' . $localFile);
42        }
43        return file_get_contents($localFile);
44    }
45}