Lines 84.00% 21 / 25
Methods 50.00% 3 / 6
Classes 0.00% 0 / 1
Covered by tests of size
Name Lines Methods CRAP
 __construct 100.00% 1 / 1 100.00% 1 / 1 1
 getHtaccessPath 100.00% 1 / 1 100.00% 1 / 1 1
 getServerPath 100.00% 2 / 2 100.00% 1 / 1 4
 getRewriteBase 80.00% 4 / 5 0.00% 0 / 1 2.03
 adjustRewriteBaseHtaccess 83.33% 10 / 12 0.00% 0 / 1 4.07
 readHtaccess 75.00% 3 / 4 0.00% 0 / 1 2.06
25readonly class EnvironmentConfigurator
26{
27    private string $htaccessPath;
28
29    public function __construct(
30        private Configuration $configuration,
31    ) {
32        $this->htaccessPath = $this->configuration->getRootPath() . '/.htaccess';
33    }
34
35    public function getHtaccessPath(): string
36    {
37        return $this->htaccessPath;
38    }
39
40    public function getServerPath(): string
41    {
42        $path = parse_url($this->configuration->getDefaultUrl(), PHP_URL_PATH);
43
44        return $path === null || $path === false || $path === '' ? '/' : $path;
45    }
46
47    /**
48     * @throws Exception
49     */
50    public function getRewriteBase(): string
51    {
52        $content = $this->readHtaccess();
53
54        $matches = [];
55        if (preg_match('/^\s*RewriteBase\s+(\S+)/mi', $content, $matches) !== 1) {
56            throw new Exception('RewriteBase directive not found in .htaccess file');
57        }
58
59        return $matches[1];
60    }
61
62    /**
63     * Adjusts the RewriteBase and ErrorDocument 404 in the .htaccess file for the user's environment.
64     *
65     * This method ensures that URL routing works correctly and 404 errors are properly handled.
66     *
67     * - RewriteBase is set to the application's installation path (e.g., /faq/)
68     * - ErrorDocument 404 is configured to route errors to the application's error handler (e.g., /faq/index.php?action=404)
69     *
70     * @return bool Returns true if the .htaccess file was successfully modified, false otherwise.
71     * @throws Exception If the .htaccess file does not exist or cannot be read.
72     */
73    public function adjustRewriteBaseHtaccess(): bool
74    {
75        if (!file_exists($this->htaccessPath)) {
76            throw new Exception(sprintf('The %s/.htaccess file does not exist!', $this->getServerPath()));
77        }
78
79        $content = $this->readHtaccess();
80
81        $serverPath = $this->getServerPath();
82        $new404Path = rtrim($serverPath, characters: '/') . '/index.php?action=404';
83
84        $updated = preg_replace('/^(\s*RewriteBase\s+)\S+/mi', '${1}' . $serverPath, $content);
85        if ($updated === null) {
86            throw new Exception('Failed to update RewriteBase directive');
87        }
88
89        $updated = preg_replace('/^(\s*ErrorDocument\s+404\s+)\S+/mi', '${1}' . $new404Path, $updated);
90        if ($updated === null) {
91            throw new Exception('Failed to update ErrorDocument 404 directive');
92        }
93
94        return (bool) file_put_contents($this->htaccessPath, $updated);
95    }
96
97    /**
98     * @throws Exception
99     */
100    /* @mago-expect lint:no-error-control-operator - the read failure is handled explicitly on the next line */
101    private function readHtaccess(): string
102    {
103        $content = @file_get_contents($this->htaccessPath);
104        if ($content === false) {
105            throw new Exception(sprintf('Cannot read .htaccess file: %s', $this->htaccessPath));
106        }
107
108        return $content;
109    }
110}