Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

Completed
Push — master ( 6ccf62...b6decb )
by Dan
19s queued 16s
created

Template::doAn()   A

Complexity

Conditions 6
Paths 2

Size

Total Lines 6
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 5
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 6
rs 9.2222
1
<?php declare(strict_types=1);
2
3
class Template {
4
	private $data = array();
5
	private $ignoreMiddle = false;
6
	private $nestedIncludes = 0;
7
	private $ajaxJS = array();
8
	protected $jsAlerts = array();
9
	private $displayCalled = false;
10
	private $listjsInclude = null;
11
	private $jsSources = [];
12
13
	public function __destruct() {
14
		if (!$this->displayCalled && !empty($this->data)) {
15
			error_log('Template destroyed before displaying the following assigned keys: ' . join(', ', array_keys($this->data)));
16
		}
17
	}
18
19
	public function hasTemplateVar($var) {
20
		return isset($this->data[$var]);
21
	}
22
23
	public function assign($var, $value) {
24
		if (!isset($this->data[$var])) {
25
			$this->data[$var] = $value;
26
		} else {
27
			// We insist that template variables not change once they are set
28
			throw new Exception("Cannot re-assign template variable '$var'!");
29
		}
30
	}
31
32
	public function unassign($var) {
33
		unset($this->data[$var]);
34
	}
35
36
	/**
37
	 * Displays the template HTML. Stores any ajax-enabled elements for future
38
	 * comparison, and outputs modified elements in XML for ajax if requested.
39
	 */
40
	public function display($templateName, $outputXml = false) {
41
		// If we already started output buffering before calling `display`,
42
		// we may have unwanted content in the buffer that we need to remove
43
		// before we send the Content-Type headers below.
44
		// Skip this for debug builds to help discover offending output.
45
		if (!ENABLE_DEBUG) {
46
			if (ob_get_length() > 0) {
47
				ob_clean();
48
			}
49
		}
50
		ob_start();
51
		$this->includeTemplate($templateName);
52
		$output = ob_get_clean();
53
54
		$ajaxEnabled = ($this->data['AJAX_ENABLE_REFRESH'] ?? false) !== false;
55
		if ($ajaxEnabled) {
56
			$ajaxXml = $this->convertHtmlToAjaxXml($output, $outputXml);
57
			if ($outputXml) {
58
				/* Left out for size: <?xml version="1.0" encoding="ISO-8859-1"?>*/
59
				$output = '<all>' . $ajaxXml . '</all>';
60
			}
61
			SmrSession::saveAjaxReturns();
62
		}
63
64
		// Now that we are completely done processing, we can output
65
		if ($outputXml) {
66
			header('Content-Type: text/xml; charset=utf-8');
67
		} else {
68
			header('Content-Type: text/html; charset=utf-8');
69
		}
70
		echo $output;
71
72
		// Record that display was called for error-checking in dtor
73
		$this->displayCalled = true;
74
	}
75
76
77
	protected function getTemplateLocation($templateName) {
78
		$templateDir = TEMPLATES_DIR;
79
		if (isset($this->data['ThisAccount']) && is_object($this->data['ThisAccount']) && $this->data['ThisAccount'] instanceof SmrAccount) {
80
			$templateDir .= $this->data['ThisAccount']->getTemplate() . '/';
81
		} else {
82
			$templateDir .= 'Default/';
83
		}
84
85
		if (SmrSession::hasGame()) {
86
			$gameDir = Globals::getGameType(SmrSession::getGameID()) . '/';
87
		} else {
88
			$gameDir = 'Default/';
89
		}
90
91
		if (file_exists($templateDir . 'engine/' . $gameDir . $templateName)) {
92
			return $templateDir . 'engine/' . $gameDir . $templateName;
93
		} elseif (file_exists($templateDir . 'engine/Default/' . $templateName)) {
94
			return $templateDir . 'engine/Default/' . $templateName;
95
		} elseif (file_exists(TEMPLATES_DIR . 'Default/engine/' . $gameDir . $templateName)) {
96
			return TEMPLATES_DIR . 'Default/engine/' . $gameDir . $templateName;
97
		} elseif (file_exists(TEMPLATES_DIR . 'Default/engine/Default/' . $templateName)) {
98
			return TEMPLATES_DIR . 'Default/engine/Default/' . $templateName;
99
		} elseif (file_exists($templateDir . 'admin/' . $gameDir . $templateName)) {
100
			return $templateDir . 'admin/' . $gameDir . $templateName;
101
		} elseif (file_exists($templateDir . 'admin/Default/' . $templateName)) {
102
			return $templateDir . 'admin/Default/' . $templateName;
103
		} elseif (file_exists(TEMPLATES_DIR . 'Default/admin/' . $gameDir . $templateName)) {
104
			return TEMPLATES_DIR . 'Default/admin/' . $gameDir . $templateName;
105
		} elseif (file_exists(TEMPLATES_DIR . 'Default/admin/Default/' . $templateName)) {
106
			return TEMPLATES_DIR . 'Default/admin/Default/' . $templateName;
107
		} elseif (file_exists($templateDir . $templateName)) {
108
			return $templateDir . $templateName;
109
		} elseif (file_exists(TEMPLATES_DIR . 'Default/' . $templateName)) {
110
			return TEMPLATES_DIR . 'Default/' . $templateName;
111
		} else {
112
			throw new Exception('No template found for ' . $templateName);
113
		}
114
	}
115
116
	protected function includeTemplate($templateName, array $assignVars = null) {
117
		if ($this->nestedIncludes > 15) {
118
			throw new Exception('Nested more than 15 template includes, is something wrong?');
119
		}
120
		foreach ($this->data as $key => $value) {
121
			$$key = $value;
122
		}
123
		if ($assignVars !== null) {
124
			foreach ($assignVars as $key => $value) {
125
				$$key = $value;
126
			}
127
		}
128
		$this->nestedIncludes++;
129
		require($this->getTemplateLocation($templateName));
130
		$this->nestedIncludes--;
131
	}
132
133
	protected function checkDisableAJAX($html) {
134
		return preg_match('/<input' . '[^>]*' . '[^(submit)(hidden)(image)]' . '[^>]*' . '>/i', $html) != 0;
135
	}
136
137
	protected function doDamageTypeReductionDisplay(&$damageTypes) {
138
		if ($damageTypes == 3) {
139
			echo ', ';
140
		} elseif ($damageTypes == 2) {
141
			echo ' and ';
142
		}
143
		$damageTypes--;
144
	}
145
146
	protected function doAn($wordAfter) {
147
		$char = strtoupper($wordAfter[0]);
148
		if ($char == 'A' || $char == 'E' || $char == 'I' || $char == 'O' || $char == 'U') {
149
			echo 'an';
150
		} else {
151
			echo 'a';
152
		}
153
	}
154
155
	/**
156
	 * Sets a listjs_include.js function to call at the end of the HTML body.
157
	 */
158
	public function setListjsInclude($func) {
159
		$this->listjsInclude = $func;
160
	}
161
162
	/*
163
	 * EVAL is special (well, will be when needed and implemented in the javascript).
164
	 */
165
	public function addJavascriptForAjax($varName, $obj) {
166
		if ($varName == 'EVAL') {
167
			if (!isset($this->ajaxJS['EVAL'])) {
168
				return $this->ajaxJS['EVAL'] = $obj;
169
			}
170
			return $this->ajaxJS['EVAL'] .= ';' . $obj;
171
		}
172
173
		if (isset($this->ajaxJS[$varName])) {
174
			throw new Exception('Trying to set javascript val twice: ' . $varName);
175
		}
176
		return $this->ajaxJS[$varName] = json_encode($obj);
177
	}
178
179
	protected function addJavascriptAlert($string) {
180
		if (!SmrSession::addAjaxReturns('ALERT:' . $string, $string)) {
181
			$this->jsAlerts[] = $string;
182
		}
183
	}
184
185
	/**
186
	 * Registers a JS target for inclusion at the end of the HTML body.
187
	 */
188
	protected function addJavascriptSource($src) {
189
		array_push($this->jsSources, $src);
190
	}
191
192
	protected function convertHtmlToAjaxXml($str, $returnXml) {
193
		if (empty($str)) {
194
			return '';
195
		}
196
197
		// To get inner html, we need to construct a separate DOMDocument.
198
		// See PHP Bug #76285.
199
		$getInnerHTML = function(DOMNode $node) {
200
			$dom = new DOMDocument();
201
			$dom->formatOutput = false;
202
			foreach ($node->childNodes as $child) {
203
				$dom->appendChild($dom->importNode($child, true));
204
			}
205
			// Trim to remove trailing newlines
206
			return trim(@$dom->saveHTML());
207
		};
208
209
		$xml = '';
210
		$dom = new DOMDocument();
211
		$dom->loadHTML($str);
212
		$xpath = new DOMXpath($dom);
213
		$ajaxSelectors = array('//span[@id]', '//*[contains(@class,"ajax")]');
214
		foreach ($ajaxSelectors as $selector) {
215
			$matchNodes = $xpath->query($selector);
216
			foreach ($matchNodes as $node) {
217
				$id = $node->getAttribute('id');
218
				$inner = $getInnerHTML($node);
219
				if (!SmrSession::addAjaxReturns($id, $inner) && $returnXml) {
220
					$xml .= '<' . $id . '>' . xmlify($inner) . '</' . $id . '>';
221
				}
222
			}
223
		}
224
225
		if (!$this->ignoreMiddle) {
226
			$mid = $dom->getElementById('middle_panel');
227
228
			$doAjaxMiddle = true;
229
			if ($mid === null) {
230
				// Skip if there is no middle_panel.
231
				$doAjaxMiddle = false;
232
			} else {
233
				// Skip if middle_panel has ajax-enabled children.
234
				$domMid = new DOMDocument();
235
				$domMid->appendChild($domMid->importNode($mid, true));
236
				$xpathMid = new DOMXpath($domMid);
237
				foreach ($ajaxSelectors as $selector) {
238
					if (count($xpathMid->query($selector)) > 0) {
239
						$doAjaxMiddle = false;
240
						break;
241
					}
242
				}
243
			}
244
245
			if ($doAjaxMiddle) {
246
				$inner = $getInnerHTML($mid);
247
				if (!$this->checkDisableAJAX($inner)) {
248
					$id = $mid->getAttribute('id');
249
					if (!SmrSession::addAjaxReturns($id, $inner) && $returnXml) {
250
						$xml .= '<' . $id . '>' . xmlify($inner) . '</' . $id . '>';
251
					}
252
				}
253
			}
254
		}
255
256
		$js = '';
257
		foreach ($this->ajaxJS as $varName => $JSON) {
258
			if (!SmrSession::addAjaxReturns('JS:' . $varName, $JSON) && $returnXml) {
259
				$js .= '<' . $varName . '>' . xmlify($JSON) . '</' . $varName . '>';
260
			}
261
		}
262
		if ($returnXml && count($this->jsAlerts) > 0) {
263
			$js = '<ALERT>' . json_encode($this->jsAlerts) . '</ALERT>';
264
		}
265
		if (strlen($js) > 0) {
266
			$xml .= '<JS>' . $js . '</JS>';
267
		}
268
		return $xml;
269
	}
270
271
	public function ignoreMiddle() {
272
		$this->ignoreMiddle = true;
273
	}
274
}
275