Lines 0.00% 0 / 24
Methods 0.00% 0 / 2
Classes 0.00% 0 / 1
Name Lines Methods CRAP
 getChangelogPath n/a 0 / 0 n/a 0 / 0 0
 getChangelogHtml 0.00% 0 / 17 0.00% 0 / 1 12
 fetchChangelogFromLocal 0.00% 0 / 7 0.00% 0 / 1 12
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        $contents = file_get_contents($localFile);
44        if ($contents === false) {
45            throw new \Exception('Local changelog file not found: ' . $localFile);
46        }
47        return $contents;
48    }
49}