Passed
Push — develop ( d757ee...b01563 )
by Brent
02:43
created

Htaccess::findHeaderBlockByModName()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 6
nc 3
nop 1
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Brendt\Stitcher\Site\Http;
4
5
use Brendt\Stitcher\Exception\ConfigurationException;
6
use Brendt\Stitcher\Site\Page;
7
use Symfony\Component\Filesystem\Filesystem;
8
use Tivie\HtaccessParser\HtaccessContainer;
9
use Tivie\HtaccessParser\Parser;
10
use Tivie\HtaccessParser\Token\Block;
11
12
class Htaccess
13
{
14
    /**
15
     * @var Filesystem
16
     */
17
    private $fs;
18
19
    /**
20
     * @var Parser
21
     */
22
    private $parser;
23
24
    /**
25
     * @var array|\ArrayAccess|HtaccessContainer
26
     */
27
    private $contents;
28
29
    /**
30
     * Htaccess constructor.
31
     *
32
     * @param string $path
33
     *
34
     * @throws ConfigurationException
35
     */
36
    public function __construct(string $path) {
37
        $this->fs = new Filesystem();
38
39
        if (!$this->fs->exists($path)) {
40
            $this->fs->dumpFile($path, file_get_contents(__DIR__ . '/../../../../.htaccess'));
41
        }
42
43
        $this->parser = new Parser(new \SplFileObject($path));
44
        $this->parser->ignoreWhitelines(false);
45
        $this->contents = $this->parser->parse();
46
    }
47
48
    /**
49
     * Parse the modified .htaccess
50
     *
51
     * @return string
52
     */
53
    public function parse() : string {
54
        return (string) $this->contents;
55
    }
56
57
    /**
58
     * Get or create the headers block
59
     *
60
     * @return Block
61
     */
62
    public function &getHeaderBlock() : Block {
63
        $headerBlock = $this->findHeaderBlockByModName('mod_headers.c');
64
65
        if (!$headerBlock) {
66
            $headerBlock = new Block('ifmodule');
67
            $headerBlock->addArgument('mod_headers.c');
68
69
            if ($this->contents instanceof HtaccessContainer) {
70
                $this->contents->append($headerBlock);
71
            }
72
        }
73
74
        return $headerBlock;
75
    }
76
77
    /**
78
     * Get or create a page block within the headers block
79
     *
80
     * @param Page $page
81
     *
82
     * @return Block
83
     */
84
    public function &getPageBlock(Page $page) : Block {
85
        $headerBlock = $this->getHeaderBlock();
86
        $pageId = trim($page->getId(), '/') ?? 'index';
87
        $pageId = pathinfo($pageId !== '' ? "{$pageId}" : 'index', PATHINFO_BASENAME);
88
        $pageName = '"^' . $pageId . '\.html$"';
89
90
        $pageBlock = $this->findPageBlockByParentAndName($headerBlock, $pageName);
91
92
        if (!$pageBlock) {
93
            $pageBlock = new Block('filesmatch');
94
            $pageBlock->addArgument($pageName);
95
            $headerBlock->addChild($pageBlock);
96
        }
97
98
        return $pageBlock;
99
    }
100
101
    /**
102
     * Clear all page header blocks
103
     */
104
    public function clearPageBlocks() : void {
105
        $headerBlock = $this->getHeaderBlock();
106
107
        foreach ($headerBlock as $content) {
108
            if ($content instanceof Block && strtolower($content->getName()) === 'filesmatch') {
109
                $headerBlock->removeChild($content);
110
            }
111
        }
112
    }
113
114
    /**
115
     * @param Block  $headerBlock
116
     * @param string $pageName
117
     *
118
     * @return null|Block
119
     */
120
    private function findPageBlockByParentAndName(Block $headerBlock, string $pageName) : ?Block {
121
        foreach ($headerBlock as $content) {
122
            $arguments = $content->getArguments();
123
124
            if (reset($arguments) === $pageName) {
125
                return $content;
126
            }
127
        }
128
129
        return null;
130
    }
131
132
    /**
133
     * @param string $modName
134
     *
135
     * @return null|Block
136
     */
137
    private function findHeaderBlockByModName(string $modName) : ?Block {
138
        foreach ($this->contents as $content) {
139
            $arguments = $content->getArguments();
140
            if (reset($arguments) === $modName) {
141
                return $content;
142
            }
143
        }
144
145
        return null;
146
    }
147
}
148