Lines 97.50% 39 / 40
Methods 80.00% 4 / 5
Classes 0.00% 0 / 1
Name Lines Methods CRAP
 __invoke 100.00% 8 / 8 100.00% 1 / 1 2
 parseLogEntries 100.00% 16 / 16 100.00% 1 / 1 5
 readLines 100.00% 7 / 7 100.00% 1 / 1 3
 openEntry 100.00% 3 / 3 100.00% 1 / 1 2
 closeEntry 83.33% 5 / 6 0.00% 0 / 1 3.04
16class LogviewController extends BaseController
17{
18    public function __invoke(
19        #[Autowire('%kernel.project_dir%')] string $projectDir,
20    ): Response {
21        $entries = [];
22
23        try {
24            $entries = $this->parseLogEntries($projectDir.'/var/log/deploy.log');
25        } catch (IOException $ioException) {
26            $this->addFlash('danger', $ioException->getMessage());
27        }
28
29        return $this->render('system/logview.html.twig', [
30            'project_dir' => $projectDir,
31            'logEntries' => \array_reverse($entries),
32        ]);
33    }
34
35    /**
36     * @return array<string, string>
37     */
38    private function parseLogEntries(string $filename): array
39    {
40        $entries = [];
41        $entry = null;
42        $dateTime = null;
43
44        foreach ($this->readLines($filename) as $line) {
45            if (\str_starts_with($line, '>>>==============')) {
46                $entry = $this->openEntry($entry);
47                continue;
48            }
49
50            if (\str_starts_with($line, '<<<===========')) {
51                [$entries, $entry] = $this->closeEntry($entries, $entry, $dateTime);
52                continue;
53            }
54
55            if ('' === $entry) {
56                // The first line contains the dateTime string
57                $dateTime = $line;
58                $entry = $line."\n";
59                continue;
60            }
61
62            $entry .= $line."\n";
63        }
64
65        return $entries;
66    }
67
68    /**
69     * @return array<int, string>
70     */
71    private function readLines(string $filename): array
72    {
73        $filesystem = new Filesystem();
74
75        if (false === $filesystem->exists($filename)) {
76            throw new IOException('Log file not found!');
77        }
78
79        return \array_filter(
80            \array_map(trim(...), \explode("\n", $filesystem->readFile($filename))),
81            static fn (string $l): bool => '' !== $l && '0' !== $l,
82        );
83    }
84
85    private function openEntry(?string $current): string
86    {
87        if (null !== $current) {
88            throw new \LogicException('Entry finished string not found');
89        }
90
91        return '';
92    }
93
94    /**
95     * @param array<string, string> $entries
96     *
97     * @return array{array<string, string>, null}
98     */
99    private function closeEntry(array $entries, ?string $entry, ?string $dateTime): array
100    {
101        if (null === $entry) {
102            throw new \LogicException('Entry not started.');
103        }
104
105        if (null === $dateTime) {
106            throw new \LogicException('Entry has no dateTime.');
107        }
108
109        $entries[$dateTime] = $entry;
110
111        return [$entries, null];
112    }
113}