CssToXpath   A
last analyzed

Complexity

Total Complexity 20

Size/Duplication

Total Lines 110
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 2

Importance

Changes 0
Metric Value
wmc 20
lcom 2
cbo 2
dl 0
loc 110
rs 10
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A createSelector() 0 6 1
A processAttr() 0 15 4
A split() 0 15 4
A getXpath() 0 12 3
A __construct() 0 15 1
A cleanup() 0 3 1
A removeSpacesFromDirectDecend() 0 14 4
A getDepth() 0 4 1
A getPseudo() 0 5 1
1
<?php
2
/* @description     Transformation Style Sheets - Revolutionising PHP templating    *
3
 * @author          Tom Butler [email protected]                                             *
4
 * @copyright       2017 Tom Butler <[email protected]> | https://r.je/                      *
5
 * @license         http://www.opensource.org/licenses/bsd-license.php  BSD License *
6
 * @version         1.2                                                             */
7
namespace Transphporm\Parser;
8
class CssToXpath {
9
	private $specialChars = [Tokenizer::WHITESPACE, Tokenizer::DOT, Tokenizer::GREATER_THAN,
10
		'~', Tokenizer::NUM_SIGN, Tokenizer::OPEN_SQUARE_BRACKET, Tokenizer::MULTIPLY];
11
	private $translators = [];
12
	private static $instances = [];
13
	private $functionSet;
14
	private $id;
15
16
	public function __construct(\Transphporm\FunctionSet $functionSet, $prefix = '', $id = null) {
17
		$this->id = $id;
18
		self::$instances[$this->id] = $this;
19
		$this->functionSet = $functionSet;
20
21
		$this->translators = [
22
			Tokenizer::WHITESPACE => function($string) use ($prefix) { return '//' . $prefix . $string;	},
23
			Tokenizer::MULTIPLY => function () { return '*'; },
24
			'' => function($string) use ($prefix) { return '/' . $prefix . $string;	},
25
			Tokenizer::GREATER_THAN => function($string) use ($prefix) { return '/' . $prefix  . $string; },
26
			Tokenizer::NUM_SIGN => function($string) { return '[@id=\'' . $string . '\']'; },
27
			Tokenizer::DOT => function($string) { return '[contains(concat(\' \', normalize-space(@class), \' \'), \' ' . $string . ' \')]'; },
28
			Tokenizer::OPEN_SQUARE_BRACKET => function($string) { return '[' .'php:function(\'\Transphporm\Parser\CssToXpath::processAttr\', \'' . base64_encode(serialize($string)) . '\', ., "' .  $this->id . '")' . ']';	}
29
		];
30
	}
31
32
	private function createSelector() {
33
		$selector = new \stdclass;
34
		$selector->type = '';
35
		$selector->string = '';
36
		return $selector;
37
	}
38
39
	//XPath only allows registering of static functions... this is a hacky workaround for that
40
	public static function processAttr($attr, $element, $hash) {
41
		$attr = unserialize(base64_decode($attr));
42
43
		$functionSet = self::$instances[$hash]->functionSet;
44
		$functionSet->setElement($element[0]);
45
46
		$attributes = [];
47
		foreach($element[0]->attributes as $name => $node) {
48
			$attributes[$name] = $node->nodeValue;
49
		}
50
51
		$parser = new \Transphporm\Parser\Value($functionSet, true);
52
		$return = $parser->parseTokens($attr, $attributes);
53
		return is_array($return[0]) || $return[0] === '' ? false : $return[0];
54
	}
55
56
	public function cleanup() {
57
		unset(self::$instances[$this->id]);
58
	}
59
60
	//split the css into indivudal functions
61
	private function split($css) {
62
		$selectors = [];
63
		$selector = $this->createSelector();
64
		$selectors[] = $selector;
65
66
		foreach ($css as $token) {
67
			if (in_array($token['type'], $this->specialChars)) {
68
				$selector = $this->createSelector();
69
				$selector->type = $token['type'];
70
				$selectors[] = $selector;
71
			}
72
			if (isset($token['value'])) $selectors[count($selectors)-1]->string = $token['value'];
73
		}
74
		return $selectors;
75
	}
76
77
	public function getXpath($css) {
78
		$css = $this->removeSpacesFromDirectDecend($css)->splitOnToken(Tokenizer::COLON)[0]->trim();
79
		$selectors = $this->split($css);
80
		$xpath = '/';
81
		foreach ($selectors as $selector) {
82
			if (isset($this->translators[$selector->type])) $xpath .= $this->translators[$selector->type]($selector->string, $xpath);
83
		}
84
85
		$xpath = str_replace('/[', '/*[', $xpath);
86
87
		return $xpath;
88
	}
89
90
	private function removeSpacesFromDirectDecend($css) {
91
		$tokens = new Tokens;
92
		$split = $css->splitOnToken(Tokenizer::GREATER_THAN);
93
		$numSplits = count($split);
94
95
		if ($numSplits <= 1) return $css;
96
97
		for ($i = 0; $i < $numSplits; $i++) {
98
			$tokens->add($split[$i]->trim());
99
			if (isset($split[$i+1])) $tokens->add(['type' => Tokenizer::GREATER_THAN]);
100
		}
101
102
		return $tokens;
103
	}
104
105
106
	public function getDepth($css) {
107
		$parts = $css->splitOnToken(Tokenizer::COLON);
108
		return count($this->split($parts[0]));
109
	}
110
111
112
	public function getPseudo($css) {
113
		$parts = $css->splitOnToken(Tokenizer::COLON);
114
		array_shift($parts);
115
		return $parts;
116
	}
117
}
118