Completed
Push — master ( 235894...a808f6 )
by Tom
03:19
created

PseudoMatcher   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 116
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 8
Bugs 0 Features 0
Metric Value
wmc 33
c 8
b 0
f 0
lcom 1
cbo 0
dl 0
loc 116
rs 9.4

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A matches() 0 8 4
A betweenBrackets() 0 9 3
B attribute() 0 24 5
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
		$pos = strpos($pseudo, '[');
39
		if ($pos === false) return true;
40
		
41
		$name = substr($pseudo, 0, $pos);
42
		if (!is_callable([$this->dataFunction, $name])) return true;
43
44
		$criteria = $this->betweenBrackets($pseudo, '[', ']');
45
46
		if (strpos($pseudo, '=') === false) {
47
			$lookupValue = $this->dataFunction->$name([$criteria], $element);
48
			return $lookupValue !== null;
49
		}
50
		list ($field, $value) = explode('=', $criteria);
51
52
		$operator = $this->getOperator($field);
53
54
		$field = trim($field, $operator);		
55
		$value = $this->parseValue(trim($value, '"'));
56
57
		$lookupValue = $this->dataFunction->$name([$field], $element);
58
		$matched = $lookupValue == $value;
59
		return $operator === '!' ? !$matched : $matched;		
60
	}
61
62
	private function parseValue($value) {
63
		if ($value == 'true') return true;
64
		else if ($value == 'false') return false;
65
		else return $value;
66
	}
67
68
	private function getOperator($field) {
69
		if ($field[strlen($field)-1] == '!') {
70
			return '!';
71
		}
72
		else return '';
73
	}
74
75
	private function nth($pseudo, $element) {
76
		if (strpos($pseudo, 'nth-child') === 0) {	
77
			$criteria = $this->getBetween($pseudo, '(', ')');
78
			$num = $this->getBetween($element->getNodePath(), '[', ']');
79
			
80
			if (is_callable([$this, $criteria])) return $this->$criteria($num);
81
			else return $num == $criteria;
82
			
83
		}
84
		return true;
85
	}
86
87
	public function attr() {
88
		foreach ($this->pseudo as $pseudo) {
89
			if (strpos($pseudo, 'attr') === 0) {
90
				$criteria = trim($this->getBetween($pseudo, '(', ')'));
91
				return $criteria;
92
			}
93
		}
94
95
		return false;
96
	}
97
98
	public function header($element)  {
99
		if ($this->matches($element)) {
100
			foreach ($this->pseudo as $pseudo) {
101
				if (strpos($pseudo, 'header') === 0) return $this->getBetween($pseudo, '[', ']');
102
			}
103
		}
104
	}
105
106
	private function odd($num) {
107
		return $num % 2 === 1;
108
	}
109
110
	private function even($num) {
111
		return $num % 2 === 0;
112
	}
113
114
	private function getBetween($string, $start, $end) {
115
		$open = strpos($string, $start);
116
		if ($open === false) return false;
117
		$close = strpos($string, $end, $open);
118
		return substr($string, $open+1, $close-$open-1);
119
	}
120
121
	public function getPseudo() {
122
		return $this->pseudo;
123
	}
124
}