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

Failed Conditions
Push — master ( c670fd...b18f1a )
by Dan
20s queued 16s
created

Template::getTemplateLocation()   C

Complexity

Conditions 15
Paths 44

Size

Total Lines 37
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 15
eloc 32
nc 44
nop 1
dl 0
loc 37
rs 5.9166
c 1
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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