|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace Charcoal\View; |
|
4
|
|
|
|
|
5
|
|
|
use InvalidArgumentException; |
|
6
|
|
|
|
|
7
|
|
|
/** |
|
8
|
|
|
* Dynamic Template Registry |
|
9
|
|
|
*/ |
|
10
|
|
|
class DynamicTemplateRegistry extends AbstractTemplateRegistry |
|
11
|
|
|
{ |
|
12
|
|
|
/** |
|
13
|
|
|
* Store of registered template keys. |
|
14
|
|
|
* |
|
15
|
|
|
* @var boolean[] |
|
16
|
|
|
*/ |
|
17
|
|
|
private $registered = []; |
|
18
|
|
|
|
|
19
|
|
|
/** |
|
20
|
|
|
* Store of template views. |
|
21
|
|
|
* |
|
22
|
|
|
* @var boolean[] |
|
23
|
|
|
*/ |
|
24
|
|
|
private $templates = []; |
|
25
|
|
|
|
|
26
|
|
|
/** |
|
27
|
|
|
* Store of protected template keys. |
|
28
|
|
|
* |
|
29
|
|
|
* @var boolean[] |
|
30
|
|
|
*/ |
|
31
|
|
|
private $protected = []; |
|
32
|
|
|
|
|
33
|
|
|
/** |
|
34
|
|
|
* Store of single-use templates. |
|
35
|
|
|
* |
|
36
|
|
|
* @var {string|boolean}[] |
|
37
|
|
|
*/ |
|
38
|
|
|
private $once = []; |
|
39
|
|
|
|
|
40
|
|
|
/** |
|
41
|
|
|
* Create new dynamic template collection |
|
42
|
|
|
* |
|
43
|
|
|
* @param array $templates Pre-populate collection with these templates. |
|
44
|
|
|
*/ |
|
45
|
|
|
public function __construct(array $templates = []) |
|
46
|
|
|
{ |
|
47
|
|
|
$this->replace($templates); |
|
48
|
|
|
} |
|
49
|
|
|
|
|
50
|
|
|
/** |
|
51
|
|
|
* Set the template for the given key. |
|
52
|
|
|
* |
|
53
|
|
|
* @param string $key The template key. |
|
54
|
|
|
* @param string $template The template view. |
|
55
|
|
|
* @throws InvalidArgumentException If the template is protected. |
|
56
|
|
|
* @return void |
|
57
|
|
|
*/ |
|
58
|
|
|
public function set($key, $template) |
|
59
|
|
|
{ |
|
60
|
|
View Code Duplication |
if (isset($this->protected[$key])) { |
|
|
|
|
|
|
61
|
|
|
if (isset($this->templates[$key]) || isset($this->once[$key])) { |
|
62
|
|
|
throw new InvalidArgumentException( |
|
63
|
|
|
sprintf('Cannot remove protected dynamic template "%s".', $key) |
|
64
|
|
|
); |
|
65
|
|
|
} |
|
66
|
|
|
} |
|
67
|
|
|
|
|
68
|
|
|
$this->templates[$key] = $template; |
|
69
|
|
|
$this->registered[$key] = true; |
|
70
|
|
|
} |
|
71
|
|
|
|
|
72
|
|
|
/** |
|
73
|
|
|
* Retrieve the template by key. |
|
74
|
|
|
* |
|
75
|
|
|
* @param string $key The template key. |
|
76
|
|
|
* @return string|null The view assigned to the $key or NULL if template is missing. |
|
77
|
|
|
*/ |
|
78
|
|
|
public function get($key) |
|
79
|
|
|
{ |
|
80
|
|
|
if (!isset($this->registered[$key])) { |
|
81
|
|
|
return null; |
|
82
|
|
|
} |
|
83
|
|
|
|
|
84
|
|
|
if (isset($this->once[$key])) { |
|
85
|
|
|
$template = $this->once[$key]; |
|
86
|
|
|
if ($template !== true) { |
|
87
|
|
|
if (isset($this->protected[$key])) { |
|
88
|
|
|
$this->once[$key] = true; |
|
89
|
|
|
} elseif (isset($this->templates[$key])) { |
|
90
|
|
|
unset($this->once[$key]); |
|
91
|
|
|
} else { |
|
92
|
|
|
unset($this->registered[$key], $this->once[$key]); |
|
93
|
|
|
} |
|
94
|
|
|
|
|
95
|
|
|
return $template; |
|
96
|
|
|
} else { |
|
97
|
|
|
return null; |
|
98
|
|
|
} |
|
99
|
|
|
} |
|
100
|
|
|
|
|
101
|
|
|
return $this->templates[$key]; |
|
|
|
|
|
|
102
|
|
|
} |
|
103
|
|
|
|
|
104
|
|
|
/** |
|
105
|
|
|
* Determine if a template exists in the collection by key. |
|
106
|
|
|
* |
|
107
|
|
|
* @param string $key The template key. |
|
108
|
|
|
* @return boolean |
|
109
|
|
|
*/ |
|
110
|
|
|
public function has($key) |
|
111
|
|
|
{ |
|
112
|
|
|
return isset($this->registered[$key]); |
|
113
|
|
|
} |
|
114
|
|
|
|
|
115
|
|
|
/** |
|
116
|
|
|
* Remove template from collection by key. |
|
117
|
|
|
* |
|
118
|
|
|
* @param string $key The template key. |
|
119
|
|
|
* @param boolean $force To remove protected templates. |
|
120
|
|
|
* @throws InvalidArgumentException If the template is protected. |
|
121
|
|
|
* @return void |
|
122
|
|
|
*/ |
|
123
|
|
|
public function remove($key, $force = false) |
|
124
|
|
|
{ |
|
125
|
|
|
if (!isset($this->registered[$key])) { |
|
126
|
|
|
return; |
|
127
|
|
|
} |
|
128
|
|
|
|
|
129
|
|
|
if ($force === true) { |
|
130
|
|
|
unset($this->registered[$key], $this->templates[$key], $this->once[$key], $this->protected[$key]); |
|
131
|
|
|
return; |
|
132
|
|
|
} |
|
133
|
|
|
|
|
134
|
|
|
if (isset($this->protected[$key])) { |
|
135
|
|
|
throw new InvalidArgumentException( |
|
136
|
|
|
sprintf('Cannot remove protected dynamic template "%s".', $key) |
|
137
|
|
|
); |
|
138
|
|
|
} |
|
139
|
|
|
|
|
140
|
|
|
unset($this->registered[$key], $this->templates[$key], $this->once[$key]); |
|
141
|
|
|
} |
|
142
|
|
|
|
|
143
|
|
|
/** |
|
144
|
|
|
* Protects the template from being replaced or removed. |
|
145
|
|
|
* |
|
146
|
|
|
* Note: The template view can be assigned after enabling protection. |
|
147
|
|
|
* |
|
148
|
|
|
* @param string $key The template key to protect from being changed. |
|
149
|
|
|
* @param string|null $template Optional. The template view to protect. |
|
150
|
|
|
* @return void |
|
151
|
|
|
*/ |
|
152
|
|
|
public function protect($key, $template = null) |
|
153
|
|
|
{ |
|
154
|
|
|
$this->protected[$key] = true; |
|
155
|
|
|
|
|
156
|
|
|
if ($template !== null) { |
|
157
|
|
|
$this->set($key, $template); |
|
158
|
|
|
} |
|
159
|
|
|
} |
|
160
|
|
|
|
|
161
|
|
|
/** |
|
162
|
|
|
* Set the template for the given key to be is used at most once. |
|
163
|
|
|
* |
|
164
|
|
|
* The `once()` method is identical to `set()`, except that the template |
|
165
|
|
|
* is unbound after its first retrieval. |
|
166
|
|
|
* |
|
167
|
|
|
* Note: If the template is protected, the template cannot be rebound. |
|
168
|
|
|
* |
|
169
|
|
|
* @param string $key The template key to limit. |
|
170
|
|
|
* @param string|null $template Optional. The template view to limit. |
|
171
|
|
|
* @throws InvalidArgumentException If the template is protected. |
|
172
|
|
|
* @return void |
|
173
|
|
|
*/ |
|
174
|
|
|
public function once($key, $template = null) |
|
175
|
|
|
{ |
|
176
|
|
View Code Duplication |
if (isset($this->protected[$key]) && isset($this->once[$key])) { |
|
|
|
|
|
|
177
|
|
|
throw new InvalidArgumentException( |
|
178
|
|
|
sprintf('Cannot remove protected dynamic template "%s".', $key) |
|
179
|
|
|
); |
|
180
|
|
|
} |
|
181
|
|
|
|
|
182
|
|
|
$this->once[$key] = $template; |
|
183
|
|
|
$this->registered[$key] = true; |
|
184
|
|
|
} |
|
185
|
|
|
|
|
186
|
|
|
/** |
|
187
|
|
|
* Add template(s) to collection, replacing existing templates with the same key. |
|
188
|
|
|
* |
|
189
|
|
|
* @param array $templates Key-value array of templates to replace to this collection. |
|
190
|
|
|
* @return void |
|
191
|
|
|
*/ |
|
192
|
|
|
public function replace(array $templates) |
|
193
|
|
|
{ |
|
194
|
|
|
foreach ($templates as $key => $template) { |
|
195
|
|
|
$this->set($key, $template); |
|
196
|
|
|
} |
|
197
|
|
|
} |
|
198
|
|
|
|
|
199
|
|
|
/** |
|
200
|
|
|
* Retrieve all registered template keys. |
|
201
|
|
|
* |
|
202
|
|
|
* @return string[] |
|
203
|
|
|
*/ |
|
204
|
|
|
public function registeredTemplates() |
|
205
|
|
|
{ |
|
206
|
|
|
return array_keys($this->templates); |
|
207
|
|
|
} |
|
208
|
|
|
|
|
209
|
|
|
/** |
|
210
|
|
|
* Remove all templates from collection. |
|
211
|
|
|
* |
|
212
|
|
|
* @param boolean $force If TRUE, protected templates are also removed. |
|
213
|
|
|
* @return void |
|
214
|
|
|
*/ |
|
215
|
|
|
public function clear($force = false) |
|
216
|
|
|
{ |
|
217
|
|
|
if ($force === true) { |
|
218
|
|
|
$this->registered = []; |
|
219
|
|
|
$this->protected = []; |
|
220
|
|
|
$this->templates = []; |
|
221
|
|
|
$this->once = []; |
|
222
|
|
|
} else { |
|
223
|
|
|
$this->registered = array_intersect_key($this->registered, $this->protected); |
|
224
|
|
|
$this->templates = array_intersect_key($this->templates, $this->protected); |
|
225
|
|
|
$this->once = array_intersect_key($this->once, $this->protected); |
|
226
|
|
|
} |
|
227
|
|
|
} |
|
228
|
|
|
} |
|
229
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.