Completed
Push — master ( f8e36b...235894 )
by Tom
02:30
created

PseudoMatcher   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 112
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 7
Bugs 0 Features 0
Metric Value
wmc 32
c 7
b 0
f 0
lcom 1
cbo 0
dl 0
loc 112
rs 9.6

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A matches() 0 8 4
A betweenBrackets() 0 9 3
A attribute() 0 20 4
A parseValue() 0 5 3
A getOperator() 0 6 2
A nth() 0 11 3
A attr() 0 10 3
A header() 0 7 4
A odd() 0 3 1
A even() 0 3 1
A getBetween() 0 6 2
A getPseudo() 0 3 1
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\Hook;
8
/** Determines whether $element matches the pseudo rule such as nth-child() or [attribute="value"] */
9
class PseudoMatcher {
10
	private $pseudo;
11
	private $dataFunction;
12
13
	public function __construct($pseudo, DataFunction $dataFunction) {
14
		$this->pseudo = $pseudo;
15
		$this->dataFunction = $dataFunction;
16
	}
17
18
	public function matches($element) {
19
		$matches = true;
20
21
		foreach ($this->pseudo as $pseudo) {			
22
			$matches = $matches && $this->attribute($pseudo, $element) && $this->nth($pseudo, $element);			
23
		}		
24
		return $matches;
25
	}
26
27
	private function betweenBrackets($string, $openChr, $closingChr, $start = 0) {
28
		$open = strpos($string, $openChr, $start);
29
		$close = strpos($string, $closingChr, $open);
30
31
		$cPos = $open+1;
32
		while (($cPos = strpos($string, $openChr, $cPos+1)) !== false && $cPos < $close) $close = strpos($string, $closingChr, $close+1);
33
34
		return substr($string, $open+1, $close-$open-1);
35
	}
36
	
37
	private function attribute($pseudo, $element) {
38
		if (strpos($pseudo, '=') === false) return true;
39
40
		$pos = strpos($pseudo, '[');
41
		if ($pos === false) return true;
42
		
43
		$name = substr($pseudo, 0, $pos);
44
		$criteria = $this->betweenBrackets($pseudo, '[', ']');
45
		
46
		list ($field, $value) = explode('=', $criteria);
47
48
		$operator = $this->getOperator($field);
49
50
		$field = trim($field, $operator);		
51
		$value = $this->parseValue(trim($value, '"'));
52
53
		$lookupValue = $this->dataFunction->$name([$field], $element);
54
		$matched = $lookupValue == $value;
55
		return $operator === '!' ? !$matched : $matched;		
56
	}
57
58
	private function parseValue($value) {
59
		if ($value == 'true') return true;
60
		else if ($value == 'false') return false;
61
		else return $value;
62
	}
63
64
	private function getOperator($field) {
65
		if ($field[strlen($field)-1] == '!') {
66
			return '!';
67
		}
68
		else return '';
69
	}
70
71
	private function nth($pseudo, $element) {
72
		if (strpos($pseudo, 'nth-child') === 0) {	
73
			$criteria = $this->getBetween($pseudo, '(', ')');
74
			$num = $this->getBetween($element->getNodePath(), '[', ']');
75
			
76
			if (is_callable([$this, $criteria])) return $this->$criteria($num);
77
			else return $num == $criteria;
78
			
79
		}
80
		return true;
81
	}
82
83
	public function attr() {
84
		foreach ($this->pseudo as $pseudo) {
85
			if (strpos($pseudo, 'attr') === 0) {
86
				$criteria = trim($this->getBetween($pseudo, '(', ')'));
87
				return $criteria;
88
			}
89
		}
90
91
		return false;
92
	}
93
94
	public function header($element)  {
95
		if ($this->matches($element)) {
96
			foreach ($this->pseudo as $pseudo) {
97
				if (strpos($pseudo, 'header') === 0) return $this->getBetween($pseudo, '[', ']');
98
			}
99
		}
100
	}
101
102
	private function odd($num) {
103
		return $num % 2 === 1;
104
	}
105
106
	private function even($num) {
107
		return $num % 2 === 0;
108
	}
109
110
	private function getBetween($string, $start, $end) {
111
		$open = strpos($string, $start);
112
		if ($open === false) return false;
113
		$close = strpos($string, $end, $open);
114
		return substr($string, $open+1, $close-$open-1);
115
	}
116
117
	public function getPseudo() {
118
		return $this->pseudo;
119
	}
120
}