Completed
Push — master ( 96a72e...fc1a4b )
by Tom
02:23
created

CssToXpath::processAttr()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 0
loc 15
rs 9.4286
cc 3
eloc 11
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 = [' ', '.', '>', '~', '#', ':', '[', ']'];
10
	private $translators = [];
11
	private $css;
12
	private $depth;
13
	private static $valueParser;
14
15
	public function __construct($css, Value $valueParser, $prefix = '') {
16
		self::$valueParser = $valueParser;
17
		$this->css = str_replace([' >', '> '],['>', '>'], trim($css));
18
		$this->translators = [
19
			' ' => function($string) use ($prefix) { return '//' . $prefix . $string;	},
20
			'' => function($string) use ($prefix) { return '/' . $prefix . $string;	},
21
			'>' => function($string) use ($prefix) { return '/' . $prefix  . $string; },
22
			'#' => function($string) { return '[@id=\'' . $string . '\']'; },
23
			'.' => function($string) { return '[contains(concat(\' \', normalize-space(@class), \' \'), \' ' . $string . ' \')]'; }, 
24
			'[' => function($string, $xpath) { return '[' .'php:function(\'\Transphporm\Parser\CssToXpath::processAttr\', \'' . $string . '\', .)' . ']';	},
0 ignored issues
show
Unused Code introduced by
The parameter $xpath is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
25
			']' => function() {	return ''; }
26
		];
27
	}
28
29
	private function createSelector() {
30
		$selector = new \stdclass;
31
		$selector->type = '';
32
		$selector->string = '';
33
		return $selector;
34
	}
35
36
	//XPath only allows registering of static functions... this is a hacky workaround for that
37
	public static function processAttr($attr, $element) {
38
		$comparators = ['!=', '='];
39
		$valueParser = self::$valueParser;
40
		foreach ($comparators as $comparator) {
41
			if (strpos($attr, $comparator) !== false) {
42
				$parts = explode($comparator, $attr);
43
				$parts = array_map(function($val) use ($valueParser, $element) {
44
					return $valueParser->parse($val, $element[0])[0];
45
				}, $parts);
46
				
47
				return self::compare($comparator, $element[0]->getAttribute($parts[0]), $parts[1]);
48
			}
49
		}
50
		return $attr;
51
	}
52
53
	private static function compare($comparator, $a, $b) {
54
		if ($comparator == '=') return $a == $b;
55
		else if ($comparator == '!=') return $a != $b;
56
	}
57
58
	//split the css into indivudal functions
59
	private function split($css) {
60
		$selectors = [];
61
		$selector = $this->createSelector();
62
		$selectors[] = $selector;
63
64
		for ($i = 0; $i < strlen($css); $i++) {
65
			if (in_array($css[$i], $this->specialChars)) {
66
				$selector = $this->createSelector();
67
				$selector->type = $css[$i];
68
				$selectors[] = $selector;
69
			}
70
			else $selector->string .= $css[$i];			
71
		}
72
		return $selectors;
73
	}
74
75
	public function getXpath() {
76
		$css = explode(':', $this->css)[0];
77
		$selectors = $this->split($css);
78
		$this->depth = count($selectors);
79
		$xpath = '/';
80
		foreach ($selectors as $selector) {
81
			if (isset($this->translators[$selector->type])) $xpath .= $this->translators[$selector->type]($selector->string, $xpath);
82
		}
83
84
		$xpath = str_replace('/[', '/*[', $xpath);
85
86
		return $xpath;
87
	}
88
89
	public function getDepth() {
90
		return $this->depth;
91
	}
92
	
93
	public function getPseudo() {
94
		$parts = explode(':', $this->css);
95
		array_shift($parts);
96
		return $parts;
97
	}
98
}