Completed
Push — master ( 8cebaa...0cc554 )
by Josh
03:33
created

Renderer::getParameter()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 2
eloc 2
nc 2
nop 1
crap 6
1
<?php
2
3
/**
4
* @package   s9e\TextFormatter
5
* @copyright Copyright (c) 2010-2017 The s9e Authors
6
* @license   http://www.opensource.org/licenses/mit-license.php The MIT License
7
*/
8
namespace s9e\TextFormatter;
9
10
use DOMDocument;
11
use InvalidArgumentException;
12
13
abstract class Renderer
14
{
15
	/**
16
	* @var array Associative array of [paramName => paramValue]
17
	*/
18
	protected $params = [];
19
20
	/**
21
	* Create a return a new DOMDocument loaded with given XML
22
	*
23
	* @param  string      $xml Source XML
24
	* @return DOMDocument
25
	*/
26 1
	protected function loadXML($xml)
27
	{
28 1
		$this->checkUnsupported($xml);
29
30
		// Activate small nodes allocation and relax LibXML's hardcoded limits if applicable. Limits
31
		// on tags can be set during configuration
32 1
		$flags = (LIBXML_VERSION >= 20700) ? LIBXML_COMPACT | LIBXML_PARSEHUGE : 0;
33
34 1
		$dom = new DOMDocument;
35 1
		$dom->loadXML($xml, $flags);
36
37 1
		return $dom;
38
	}
39
40
	/**
41
	* Render an intermediate representation
42
	*
43
	* @param  string $xml Intermediate representation
44
	* @return string      Rendered result
45
	*/
46
	public function render($xml)
47
	{
48
		if (substr($xml, 0, 3) === '<t>')
49
		{
50
			return $this->renderPlainText($xml);
51
		}
52
		else
53
		{
54
			return $this->renderRichText(preg_replace('(<[eis]>[^<]*</[eis]>)', '', $xml));
55
		}
56
	}
57
58
	/**
59
	* Render an intermediate representation of plain text
60
	*
61
	* @param  string $xml Intermediate representation
62
	* @return string      Rendered result
63
	*/
64
	protected function renderPlainText($xml)
65
	{
66
		// Remove the <t> and </t> tags
67
		$html = substr($xml, 3, -4);
68
69
		// Replace all <br/> with <br>
70
		$html = str_replace('<br/>', '<br>', $html);
71
72
		// Decode encoded characters from the Supplementary Multilingual Plane
73
		$html = $this->decodeSMP($html);
74
75
		return $html;
76
	}
77
78
	/**
79
	* Render an intermediate representation of rich text
80
	*
81
	* @param  string $xml Intermediate representation
82
	* @return string      Rendered result
83
	*/
84
	abstract protected function renderRichText($xml);
85
86
	/**
87
	* Get the value of a parameter
88
	*
89
	* @param  string $paramName
90
	* @return string
91
	*/
92
	public function getParameter($paramName)
93
	{
94
		return (isset($this->params[$paramName])) ? $this->params[$paramName] : '';
95
	}
96
97
	/**
98
	* Get the values of all parameters
99
	*
100
	* @return array Associative array of parameter names and values
101
	*/
102
	public function getParameters()
103
	{
104
		return $this->params;
105
	}
106
107
	/**
108
	* Set the value of a parameter from the stylesheet
109
	*
110
	* @param  string $paramName  Parameter name
111
	* @param  mixed  $paramValue Parameter's value
112
	* @return void
113
	*/
114
	public function setParameter($paramName, $paramValue)
115
	{
116
		$this->params[$paramName] = (string) $paramValue;
117
	}
118
119
	/**
120
	* Set the values of several parameters from the stylesheet
121
	*
122
	* @param  string $params Associative array of [parameter name => parameter value]
123
	* @return void
124
	*/
125
	public function setParameters(array $params)
126
	{
127
		foreach ($params as $paramName => $paramValue)
128
		{
129
			$this->setParameter($paramName, $paramValue);
130
		}
131
	}
132
133
	/**
134
	* Test for the presence of unsupported XML and throw an exception if found
135
	*
136
	* @param  string $xml XML
137
	* @return void
138
	*/
139 1
	protected function checkUnsupported($xml)
140
	{
141 1
		if (strpos($xml, '<!') !== false)
142
		{
143
			throw new InvalidArgumentException('DTDs, CDATA nodes and comments are not allowed');
144
		}
145 1
		if (strpos($xml, '<?') !== false)
146
		{
147
			throw new InvalidArgumentException('Processing instructions are not allowed');
148
		}
149 1
	}
150
151
	/**
152
	* Decode encoded characters from the Supplementary Multilingual Plane
153
	*
154
	* @param  string $str Encoded string
155
	* @return string      Decoded string
156
	*/
157
	protected function decodeSMP($str)
158
	{
159
		if (strpos($str, '&#') === false)
160
		{
161
			return $str;
162
		}
163
164
		return preg_replace_callback('(&#(?:x[0-9A-Fa-f]+|[0-9]+);)', __CLASS__ . '::decodeEntity', $str);
165
	}
166
167
	/**
168
	* Decode a matched SGML entity
169
	*
170
	* @param  string[] $m Captures from PCRE
171
	* @return string      Decoded entity
172
	*/
173
	protected static function decodeEntity(array $m)
174
	{
175
		return htmlspecialchars(html_entity_decode($m[0], ENT_QUOTES, 'UTF-8'), ENT_COMPAT);
176
	}
177
}