Passed
Push — master ( 7aef5f...5de379 )
by Josh
02:35
created

XSLT::__serialize()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 5
c 1
b 0
f 0
dl 0
loc 11
ccs 4
cts 4
cp 1
rs 10
cc 2
nc 2
nop 0
crap 2
1
<?php
2
3
/**
4
* @package   s9e\TextFormatter
5
* @copyright Copyright (c) The s9e authors
6
* @license   http://www.opensource.org/licenses/mit-license.php The MIT License
7
*/
8
namespace s9e\TextFormatter\Renderers;
9
10
use s9e\TextFormatter\Renderer;
11
use XSLTProcessor;
12
13
class XSLT extends Renderer
14
{
15
	/**
16
	* @var XSLTProcessor The lazy-loaded XSLTProcessor instance used by this renderer
17
	*/
18
	protected $proc;
19
20
	/**
21
	* @var bool Whether parameters need to be reloaded
22
	*/
23
	protected $reloadParams = false;
24
25
	/**
26
	* @var string The stylesheet used by this renderer
27
	*/
28
	protected $stylesheet;
29
30
	/**
31
	* Constructor
32
	*
33
	* @param  string $stylesheet The stylesheet used to render intermediate representations
34
	*/
35 30
	public function __construct($stylesheet)
36
	{
37 30
		$this->stylesheet = $stylesheet;
38
39
		// Capture the parameters' values from the stylesheet
40 30
		preg_match_all('#<xsl:param name="([^"]+)"(?>/>|>([^<]+))#', $stylesheet, $matches);
41 30
		foreach ($matches[1] as $k => $paramName)
42
		{
43 8
			$this->params[$paramName] = htmlspecialchars_decode($matches[2][$k]);
44
		}
45
	}
46
47
	public function __serialize(): array
48
	{
49
		$props = get_object_vars($this);
50
		unset($props['proc']);
51
52 4
		if (empty($props['reloadParams']))
53
		{
54 4
			unset($props['reloadParams']);
55 4
		}
56
57 4
		return $props;
58
	}
59 3
60
	public function __unserialize(array $data): void
61
	{
62 4
		foreach ($data as $k => $v)
63
		{
64
			$this->$k = $v;
65
		}
66
		if (!empty($this->reloadParams))
67
		{
68
			$this->setParameters($this->params);
69
			$this->reloadParams = false;
70
		}
71
	}
72 2
73
	/**
74 2
	* {@inheritdoc}
75
	*/
76 1
	public function setParameter($paramName, $paramValue)
77 1
	{
78
		/**
79
		* @link https://bugs.php.net/64137
80
		*/
81
		if (strpos($paramValue, '"') !== false && strpos($paramValue, "'") !== false)
82
		{
83
			$paramValue = str_replace('"', "\xEF\xBC\x82", $paramValue);
84 6
		}
85
		else
86
		{
87
			$paramValue = (string) $paramValue;
88
		}
89 6
90
		if (!isset($this->params[$paramName]) || $this->params[$paramName] !== $paramValue)
91 1
		{
92
			$this->load();
93
			$this->proc->setParameter('', $paramName, $paramValue);
94
			$this->params[$paramName] = $paramValue;
95 5
			$this->reloadParams = true;
96
		}
97
	}
98 6
99
	/**
100 6
	* {@inheritdoc}
101 6
	*/
102 6
	protected function renderRichText($xml)
103 6
	{
104
		// Load the intermediate representation
105
		$dom = $this->loadXML($xml);
106
107
		// Load the stylesheet
108
		$this->load();
109
110 17
		// Perform the transformation and cast it as a string because it may return NULL if the
111
		// transformation didn't output anything
112
		$this->setLocale();
113 17
		$output = (string) $this->proc->transformToXml($dom);
114
		$this->restoreLocale();
115
116 13
		// XSLTProcessor does not correctly identify <embed> as a void element. We fix it by
117
		// removing </embed> end tags
118
		$output = str_replace('</embed>', '', $output);
119
120 13
		// Remove the \n that XSL adds at the end of the output, if applicable
121 13
		if (substr($output, -1) === "\n")
122 13
		{
123
			$output = substr($output, 0, -1);
124
		}
125
126 13
		// Force HTML attributes to use double quotes to be consistent with the PHP renderer
127
		if (strpos($output, "='") !== false)
128
		{
129 13
			$output = $this->normalizeAttributes($output);
130
		}
131 13
132
		return $output;
133
	}
134
135 13
	/**
136
	* Create an XSLTProcessor and load the stylesheet
137 2
	*
138
	* @return void
139
	*/
140 13
	protected function load()
141
	{
142
		if (!isset($this->proc))
143
		{
144
			$xsl = $this->loadXML($this->stylesheet);
145
146
			$this->proc = new XSLTProcessor;
147
			$this->proc->importStylesheet($xsl);
148 16
		}
149
	}
150 16
151
	/**
152 16
	* Normalize given attribute's value to use double quotes
153
	*
154 16
	* @param  string[] $m
155 16
	* @return string
156
	*/
157
	protected function normalizeAttribute(array $m)
158
	{
159
		if ($m[0][0] === '"')
160
		{
161
			return $m[0];
162
		}
163
164
		return '"' . str_replace('"', '&quot;', substr($m[0], 1, -1)) . '"';
165 2
	}
166
167 2
	/**
168
	* Normalize all attributes in given HTML to use double quotes
169 2
	*
170
	* @param  string $html
171
	* @return string
172 1
	*/
173
	protected function normalizeAttributes($html)
174
	{
175
		return preg_replace_callback('(<\\S++ [^>]++>)', $this->normalizeElement(...), $html);
176
	}
177
178
	/**
179
	* Normalize attributes in given element to use double quotes
180
	*
181 2
	* @param  string[] $m
182
	* @return string
183 2
	*/
184
	protected function normalizeElement(array $m)
185
	{
186
		if (strpos($m[0], "='") === false)
187
		{
188
			return $m[0];
189
		}
190
191
		return preg_replace_callback('((?:"[^"]*"|\'[^\']*\'))S', $this->normalizeAttribute(...), $m[0]);
192
	}
193
}