Completed
Branch XPathConvertorRefactor (245ee2)
by Josh
12:06
created

Runner   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 183
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Importance

Changes 0
Metric Value
wmc 17
lcom 1
cbo 9
dl 0
loc 183
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A convert() 0 15 4
A getDefaultConvertors() 0 17 2
A setConvertors() 0 22 3
A setDefaultConvertors() 0 4 1
A addConvertor() 0 17 3
A getArguments() 0 12 2
A insertCaptureNames() 0 12 1
A sortRegexps() 0 10 1
1
<?php
2
3
/**
4
* @package   s9e\TextFormatter
5
* @copyright Copyright (c) 2010-2018 The s9e Authors
6
* @license   http://www.opensource.org/licenses/mit-license.php The MIT License
7
*/
8
namespace s9e\TextFormatter\Configurator\RendererGenerators\PHP\XPathConvertor;
9
10
use RuntimeException;
11
use s9e\TextFormatter\Configurator\RendererGenerators\PHP\XPathConvertor\Convertors\AbstractConvertor;
12
use s9e\TextFormatter\Configurator\RendererGenerators\PHP\XPathConvertor\Convertors\BooleanFunctions;
13
use s9e\TextFormatter\Configurator\RendererGenerators\PHP\XPathConvertor\Convertors\BooleanOperators;
14
use s9e\TextFormatter\Configurator\RendererGenerators\PHP\XPathConvertor\Convertors\Comparisons;
15
use s9e\TextFormatter\Configurator\RendererGenerators\PHP\XPathConvertor\Convertors\Core;
16
use s9e\TextFormatter\Configurator\RendererGenerators\PHP\XPathConvertor\Convertors\Math;
17
use s9e\TextFormatter\Configurator\RendererGenerators\PHP\XPathConvertor\Convertors\MultiByteStringManipulation;
18
use s9e\TextFormatter\Configurator\RendererGenerators\PHP\XPathConvertor\Convertors\SingleByteStringFunctions;
19
use s9e\TextFormatter\Configurator\RendererGenerators\PHP\XPathConvertor\Convertors\SingleByteStringManipulation;
20
21
class Runner
22
{
23
	/**
24
	* @var array
25
	*/
26
	protected $callbacks;
27
28
	/**
29
	* @var array
30
	*/
31
	protected $groups;
32
33
	/**
34
	* @var string
35
	*/
36
	protected $regexp = '((?!))';
37
38
	/**
39
	* @var array
40
	*/
41
	protected $regexps;
42
43
	/**
44
	* Convert given XPath expression to PHP
45
	*
46
	* @param  string $expr
47
	* @return string
48
	*/
49
	public function convert($expr)
50
	{
51
		if (preg_match($this->regexp, $expr, $m))
52
		{
53
			foreach (array_reverse(array_keys($m)) as $name)
54
			{
55
				if (isset($this->callbacks[$name]))
56
				{
57
					return call_user_func_array($this->callbacks[$name], $this->getArguments($m, $name));
58
				}
59
			}
60
		}
61
62
		throw new RuntimeException('Cannot convert ' . $expr);
63
	}
64
65
	/**
66
	* 
67
	*
68
	* @return AbstractConvertor[]
69
	*/
70
	public function getDefaultConvertors()
71
	{
72
		$convertors   = [];
73
		$convertors[] = new BooleanFunctions($this);
74
		$convertors[] = new BooleanOperators($this);
75
		$convertors[] = new Comparisons($this);
76
		$convertors[] = new Core($this);
77
		$convertors[] = new Math($this);
78
		if (extension_loaded('mbstring'))
79
		{
80
			$convertors[] = new MultiByteStringManipulation($this);
81
		}
82
		$convertors[] = new SingleByteStringFunctions($this);
83
		$convertors[] = new SingleByteStringManipulation($this);
84
85
		return $convertors;
86
	}
87
88
	/**
89
	* 
90
	*
91
	* @return void
92
	*/
93
	public function setConvertors(array $convertors)
94
	{
95
		$this->callbacks = [];
96
		$this->groups    = [];
97
		$this->regexps   = [];
98
		foreach ($convertors as $convertor)
99
		{
100
			$this->addConvertor($convertor);
101
		}
102
103
		// Sort regexps by length to keep their order consistent
104
		$this->sortRegexps();
105
106
		// Add regexp groups
107
		foreach ($this->groups as $group => $captures)
108
		{
109
			sort($captures);
110
			$this->regexps[$group] = '(?<' . $group . '>' . implode('|', $captures) . ')';
111
		}
112
113
		$this->regexp = '(^(?:' . implode('|', $this->regexps) . ')$)';
114
	}
115
116
	/**
117
	* 
118
	*
119
	* @return void
120
	*/
121
	public function setDefaultConvertors()
122
	{
123
		$this->setConvertors($this->getDefaultConvertors());
124
	}
125
126
	/**
127
	* 
128
	*
129
	* @param  AbstractConvertor $convertor
130
	* @return void
131
	*/
132
	protected function addConvertor(AbstractConvertor $convertor)
133
	{
134
		foreach ($convertor->getRegexpGroups() as $name => $group)
135
		{
136
			$this->groups[$group][] = '(?&' . $name . ')';
137
		}
138
139
		foreach ($convertor->getRegexps() as $name => $regexp)
140
		{
141
			$regexp = $this->insertCaptureNames($name, $regexp);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $regexp is correct as $this->insertCaptureNames($name, $regexp) (which targets s9e\TextFormatter\Config...r::insertCaptureNames()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
142
			$regexp = str_replace(' ', '\\s*', $regexp);
143
			$regexp = '(?<' . $name . '>' . $regexp . ')';
144
145
			$this->callbacks[$name] = [$convertor, 'convert' . $name];
146
			$this->regexps[$name]   = $regexp;
147
		}
148
	}
149
150
	/**
151
	* 
152
	*
153
	* @param  array    $matches
154
	* @param  string   $name
155
	* @return string[]
156
	*/
157
	protected function getArguments(array $matches, $name)
158
	{
159
		$args = [];
160
		$i    = 0;
161
		while (isset($matches[$name . $i]))
162
		{
163
			$args[] = $matches[$name . $i];
164
			++$i;
165
		}
166
167
		return $args;
168
	}
169
170
	/**
171
	* 
172
	*
173
	* @return void
174
	*/
175
	protected function insertCaptureNames($name, $regexp)
176
	{
177
		$i = 0;
178
		return preg_replace_callback(
179
			'((?<!\\\\)\\((?!\\?))',
180
			function ($m) use (&$i, $name)
181
			{
182
				return '(?<' . $name . $i++ . '>';
183
			},
184
			$regexp
185
		);
186
	}
187
188
	/**
189
	* Sort regexps by length
190
	*
191
	* @return void
192
	*/
193
	protected function sortRegexps()
194
	{
195
		uasort(
196
			$this->regexps,
197
			function ($a, $b)
198
			{
199
				return strlen($b) - strlen($a);
200
			}
201
		);
202
	}
203
}