Completed
Push — master ( a2c8cc...da7387 )
by Josh
04:02
created

FoldConstantXPathExpressions   A

Complexity

Total Complexity 8

Size/Duplication

Total Lines 101
Duplicated Lines 0 %

Test Coverage

Coverage 95.45%

Importance

Changes 0
Metric Value
wmc 8
eloc 41
dl 0
loc 101
ccs 21
cts 22
cp 0.9545
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A evaluate() 0 7 1
A getOptimizationPasses() 0 4 1
A isConstantExpression() 0 14 2
A foldConstantXPathExpression() 0 21 4
1
<?php
2
3
/**
4
* @package   s9e\TextFormatter
5
* @copyright Copyright (c) 2010-2019 The s9e Authors
6
* @license   http://www.opensource.org/licenses/mit-license.php The MIT License
7
*/
8
namespace s9e\TextFormatter\Configurator\TemplateNormalizations;
9
10
use Exception;
11
use s9e\TextFormatter\Utils\XPath;
12
13
class FoldConstantXPathExpressions extends AbstractConstantFolding
14
{
15
	/**
16
	* @var string[] List of supported XPath functions
17
	*/
18
	protected $supportedFunctions = [
19
		'boolean',
20
		'ceiling',
21
		'concat',
22
		'contains',
23
		'false',
24
		'floor',
25
		'normalize-space',
26
		'not',
27
		'number',
28
		'round',
29
		'starts-with',
30
		'string',
31
		'string-length',
32
		'substring',
33
		'substring-after',
34
		'substring-before',
35
		'sum',
36
		'translate',
37
		'true'
38
	];
39
40
	/**
41
	* {@inheritdoc}
42
	*/
43 27
	protected function getOptimizationPasses()
44
	{
45
		return [
46 27
			'(^(?:"[^"]*"|\'[^\']*\'|\\.[0-9]|[^"$&\'./:<=>@[\\]])++$)' => 'foldConstantXPathExpression'
47
		];
48
	}
49
50
	/**
51
	* Evaluate given expression without raising any warnings
52
	*
53
	* @param  string $expr
54
	* @return mixed
55
	*/
56 12
	protected function evaluate($expr)
57
	{
58 12
		$useErrors = libxml_use_internal_errors(true);
59 12
		$result    = $this->xpath->evaluate($expr);
60 12
		libxml_use_internal_errors($useErrors);
61
62 12
		return $result;
63
	}
64
65
	/**
66
	* Evaluate and replace a constant XPath expression
67
	*
68
	* @param  array  $m
69
	* @return string
70
	*/
71 22
	protected function foldConstantXPathExpression(array $m)
72
	{
73 22
		$expr = $m[0];
74 22
		if ($this->isConstantExpression($expr))
75
		{
76
			try
77
			{
78 12
				$result     = $this->evaluate($expr);
79 12
				$foldedExpr = XPath::export($result);
80 12
				if (strlen($foldedExpr) < strlen($expr))
81
				{
82 12
					$expr = $foldedExpr;
83
				}
84
			}
85
			catch (Exception $e)
86
			{
87
				// Do nothing
88
			}
89
		}
90
91 22
		return $expr;
92
	}
93
94
	/**
95
	* Test whether given expression seems to be constant
96
	*
97
	* @param  string $expr
98
	* @return bool
99
	*/
100 22
	protected function isConstantExpression($expr)
101
	{
102
		// Replace strings to avoid false-positives
103 22
		$expr = preg_replace('("[^"]*"|\'[^\']*\')', '0', $expr);
104
105
		// Match function calls against the list of supported functions
106 22
		preg_match_all('(\\w[-\\w]+(?=\\())', $expr, $m);
107 22
		if (count(array_diff($m[0], $this->supportedFunctions)) > 0)
108
		{
109 3
			return false;
110
		}
111
112
		// Match unsupported characters and keywords, as well as function calls without arguments
113 19
		return !preg_match('([^\\s\\-0-9a-z\\(-.]|\\.(?![0-9])|\\b[-a-z](?![-\\w]+\\()|\\(\\s*\\))i', $expr);
114
	}
115
}