Passed
Push — master ( d9621e...d05da4 )
by Peter
02:34
created

Template::addOccurence()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 25
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 9
c 0
b 0
f 0
nc 4
nop 5
dl 0
loc 25
rs 9.9666
1
<?php
2
3
declare(strict_types=1);
4
5
namespace AbterPhp\Framework\Template;
6
7
class Template
8
{
9
    /** @var string */
10
    protected $rawContent = '';
11
12
    /** @var ParsedTemplate[][][] */
13
    protected $parsedTemplates = [];
14
15
    /** @var string[] */
16
    protected $vars = [];
17
18
    /** @var array */
19
    protected $types = ['block'];
20
21
    /**
22
     * Template constructor.
23
     *
24
     * @param string   $rawContent
25
     * @param string[] $vars
26
     * @param string[] $types
27
     */
28
    public function __construct(string $rawContent = '', array $vars = [], array $types = ['block'])
29
    {
30
        $this->rawContent = $rawContent;
31
        $this->vars       = $vars;
32
        $this->types      = $types;
33
    }
34
35
    /**
36
     * @param string $rawContent
37
     *
38
     * @return Template
39
     */
40
    public function setRawContent(string $rawContent): Template
41
    {
42
        $this->rawContent = $rawContent;
43
44
        return $this;
45
    }
46
47
    /**
48
     * @param string[] $vars
49
     *
50
     * @return Template
51
     */
52
    public function setVars(array $vars): Template
53
    {
54
        $this->vars = $vars;
55
56
        return $this;
57
    }
58
59
    /**
60
     * @param string[] $types
61
     *
62
     * @return Template
63
     */
64
    public function setTypes(array $types): Template
65
    {
66
        $this->types = $types;
67
68
        return $this;
69
    }
70
71
    /**
72
     * @return ParsedData[][][]
73
     */
74
    public function parse(): array
75
    {
76
        if (!$this->rawContent) {
77
            return [];
78
        }
79
80
        $this->replaceVars();
81
82
        $this->parsedTemplates = $this->parseTemplates();
83
84
        return $this->parsedTemplates;
85
    }
86
87
    /**
88
     * Replaces is {{var/xxx}} occurances in the content
89
     */
90
    private function replaceVars()
91
    {
92
        $matches = [];
93
        preg_match_all('/\{\{\s*var\/([\w-]+)\s*\}\}/', $this->rawContent, $matches);
94
95
        foreach ($matches[1] as $idx => $varName) {
96
            $search      = $matches[0][$idx];
97
            $replaceWith = '';
98
            if (array_key_exists($varName, $this->vars)) {
99
                $replaceWith = $this->vars[$varName];
100
            }
101
102
            $this->rawContent = str_replace($search, $replaceWith, $this->rawContent);
103
        }
104
    }
105
106
    /**
107
     * @return ParsedTemplate[][][]
108
     */
109
    private function parseTemplates(): array
110
    {
111
        $matches = [];
112
        $pattern = sprintf('/\{\{\s*(%s)\/([\w-]+)(\s+[^}]*)?\s*\}\}/Ums', implode('|', $this->types));
113
        preg_match_all($pattern, $this->rawContent, $matches);
114
115
        $parsedTemplates = [];
116
        foreach ($matches[0] as $idx => $occurrence) {
117
            $type       = $matches[1][$idx];
118
            $identifier = $matches[2][$idx];
119
            $attributes = $this->parseAttributes($matches[3][$idx]);
120
121
            $this->addOccurence($parsedTemplates, $type, $identifier, $attributes, $occurrence);
122
        }
123
124
        return $parsedTemplates;
125
    }
126
127
    /**
128
     * @param string $rawAttributes
129
     *
130
     * @return string[]
131
     */
132
    private function parseAttributes(string $rawAttributes): array
133
    {
134
        if (trim($rawAttributes) === '') {
135
            return [];
136
        }
137
138
        $matches = [];
139
        $pattern = '/\s*(\w*)\s*\=\s*\"([^"]*)\"\s*/Ums';
140
        preg_match_all($pattern, $rawAttributes, $matches);
141
142
        $attributes = [];
143
        foreach ($matches[0] as $idx => $match) {
144
            $attributes[$matches[1][$idx]] = $matches[2][$idx];
145
        }
146
147
        return $attributes;
148
    }
149
150
    /**
151
     * @param ParsedTemplate[][][] &$parsedTemplates
152
     * @param string                $type
153
     * @param string                $identifier
154
     * @param array                 $attributes
155
     * @param string                $occurence
156
     */
157
    private function addOccurence(
158
        array &$parsedTemplates,
159
        string $type,
160
        string $identifier,
161
        array $attributes,
162
        string $occurence
163
    ): void {
164
        if (!isset($parsedTemplates[$type][$identifier])) {
165
            $parsedTemplates[$type][$identifier][] = new ParsedTemplate($type, $identifier, $attributes, [$occurence]);
166
167
            return;
168
        }
169
170
        foreach ($parsedTemplates[$type][$identifier] as $parsedTemplate) {
171
            // Note: == is used on purpose here!
172
            if ($parsedTemplate->getAttributes() != $attributes) {
173
                continue;
174
            }
175
176
            $parsedTemplate->addOccurence($occurence);
177
178
            return;
179
        }
180
181
        $parsedTemplates[$type][$identifier][] = new ParsedTemplate($type, $identifier, $attributes, [$occurence]);
182
    }
183
184
    /**
185
     * @param string[][] $subTemplateValues
186
     *
187
     * @return string
188
     */
189
    public function render(array $subTemplateValues): string
190
    {
191
        $content = $this->rawContent;
192
193
        foreach ($this->parsedTemplates as $type => $typeTemplates) {
194
            if (!array_key_exists($type, $subTemplateValues)) {
195
                $subTemplateValues[$type] = [];
196
            }
197
            foreach ($typeTemplates as $identifier => $identifierTemplates) {
198
                $replace = '';
199
                if (array_key_exists($identifier, $subTemplateValues[$type])) {
200
                    $replace = $subTemplateValues[$type][$identifier];
201
                }
202
203
                foreach ($identifierTemplates as $parsedTemplate) {
204
                    $content = str_replace($parsedTemplate->getOccurences(), $replace, $content);
205
                }
206
            }
207
        }
208
209
        return $content;
210
    }
211
}
212