Completed
Push — master ( 0ada29...ecc437 )
by Richard
03:53 queued 11s
created

CssToXpath::splitOnToken()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 7

Duplication

Lines 9
Ratio 100 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 9
loc 9
rs 9.6666
cc 3
eloc 7
nc 3
nop 2
1
<?php
2
/* @description     Transformation Style Sheets - Revolutionising PHP templating    *
3
 * @author          Tom Butler [email protected]                                             *
4
 * @copyright       2015 Tom Butler <[email protected]> | https://r.je/                      *
5
 * @license         http://www.opensource.org/licenses/bsd-license.php  BSD License *
6
 * @version         1.0                                                             */
7
namespace Transphporm\Parser;
8
class CssToXpath {
9
	private $specialChars = [Tokenizer::WHITESPACE, Tokenizer::DOT, Tokenizer::GREATER_THAN,
10
		'~', Tokenizer::NUM_SIGN, Tokenizer::COLON, Tokenizer::OPEN_SQUARE_BRACKET];
11
	private $translators = [];
12
	private static $instances = [];
13
	private $functionSet;
14
15
16
	public function __construct(\Transphporm\FunctionSet $functionSet, $prefix = '') {
17
		$hash = $this->registerInstance();
18
		$this->functionSet = $functionSet;
19
20
		$this->translators = [
21
			Tokenizer::WHITESPACE => function($string) use ($prefix) { return '//' . $prefix . $string;	},
22
			'' => function($string) use ($prefix) { return '/' . $prefix . $string;	},
23
			Tokenizer::GREATER_THAN => function($string) use ($prefix) { return '/' . $prefix  . $string; },
24
			Tokenizer::NUM_SIGN => function($string) { return '[@id=\'' . $string . '\']'; },
25
			Tokenizer::DOT => function($string) { return '[contains(concat(\' \', normalize-space(@class), \' \'), \' ' . $string . ' \')]'; },
26
			Tokenizer::OPEN_SQUARE_BRACKET => function($string) use ($hash) { return '[' .'php:function(\'\Transphporm\Parser\CssToXpath::processAttr\', \'' . base64_encode(serialize($string)) . '\', ., "' . $hash . '")' . ']';	}
27
		];
28
	}
29
30
	private function registerInstance() {
31
		$hash = spl_object_hash($this);
32
		self::$instances[$hash] = $this;
33
		return $hash;
34
	}
35
36
	private function createSelector() {
37
		$selector = new \stdclass;
38
		$selector->type = '';
39
		$selector->string = '';
40
		return $selector;
41
	}
42
43
	//XPath only allows registering of static functions... this is a hacky workaround for that
44
	public static function processAttr($attr, $element, $hash) {
45
		$attr = unserialize(base64_decode($attr));
46
		$functionSet = self::$instances[$hash]->functionSet;
47
		$functionSet->setElement($element[0]);
48
49
		$attributes = array();
50
        foreach($element[0]->attributes as $attribute_name => $attribute_node) {
51
            $attributes[$attribute_name] = $attribute_node->nodeValue;
52
        }
53
54
        $parser = new \Transphporm\Parser\Value($functionSet, true);
55
		$return = $parser->parseTokens($attr, $attributes);
56
57
		return $return[0] === '' ? false : $return[0];
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];
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 = [];
92
		foreach ($css->splitOnToken(Tokenizer::GREATER_THAN) as $token) {
93
			foreach ($token->trim() as $t) $tokens[]  = $t;
94
			$tokens[] = ['type' => Tokenizer::GREATER_THAN];
95
		}
96
		return new Tokens(array_slice($tokens, 0, -1));
97
	}
98
99
100
	public function getDepth($css) {
101
		return count($this->split($css));
102
	}
103
104
	public function getPseudo($css) {
105
		$parts = $css->splitOnToken(Tokenizer::COLON);
106
		array_shift($parts);
107
		return $parts;
108
	}
109
}
110