Completed
Push — master ( 06252b...52b075 )
by Tom
03:06
created

PseudoMatcher::not()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 18
rs 8.8571
cc 5
eloc 12
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\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
		$functions = ['attribute', 'nth', 'not'];
21
22
		foreach ($this->pseudo as $pseudo) {			
23
			foreach ($functions as $func) {
24
				$matches = $matches && $this->$func($pseudo, $element);
25
			}
26
		}		
27
		return $matches;
28
	}
29
30
	private function attribute($pseudo, $element) {
31
		$pos = strpos($pseudo, '[');
32
		if ($pos === false) return true;
33
		
34
		$name = substr($pseudo, 0, $pos);
35
		if (!is_callable([$this->dataFunction, $name])) return true;
36
37
		$bracketMatcher = new \Transphporm\Parser\BracketMatcher($pseudo);
38
		$criteria = $bracketMatcher->match('[', ']');
39
40
		if (strpos($pseudo, '=') === false) {
41
			$lookupValue = $this->dataFunction->$name([$criteria], $element);
42
			return $lookupValue !== null;
43
		}
44
		list ($field, $value) = explode('=', $criteria);
45
46
		$operator = $this->getOperator($field);
47
		$lookupValue = $this->dataFunction->$name([trim($field, $operator)], $element);
48
49
		return $this->processOperator($operator, $lookupValue, $this->parseValue(trim($value, '"')));
50
	}
51
52
	//Currently only not is supported, but this is separated out to support others in future
53
	private function processOperator($operator, $lookupValue, $value) {
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
			$bracketMatcher = new \Transphporm\Parser\BracketMatcher($pseudo);
74
			$criteria = $bracketMatcher->match('(', ')');
75
		
76
			$bracketMatcher = new \Transphporm\Parser\BracketMatcher($element->getNodePath());
77
			$num = $bracketMatcher->match('[', ']');
78
			
79
			if (is_callable([$this, $criteria])) return $this->$criteria($num);
80
			else return $num == $criteria;			
81
		}
82
		return true;
83
	}
84
85
	private function not($pseudo, $element) {
86
		if (strpos($pseudo, 'not') === 0) {
87
			$valueParser = new \Transphporm\Parser\Value($this->dataFunction);
88
			$bracketMatcher = new \Transphporm\Parser\BracketMatcher($pseudo);
89
			$css = explode(',', $bracketMatcher->match('(', ')'));
90
91
			foreach ($css as $selector) {
92
				$cssToXpath = new \Transphporm\Parser\CssToXpath($selector, $valueParser);
93
				$xpathString = $cssToXpath->getXpath();	
94
				$xpath = new \DomXpath($element->ownerDocument);
95
				
96
				foreach ($xpath->query($xpathString) as $matchedElement) {
97
					if ($element->isSameNode($matchedElement)) return false;
98
				}
99
			}
100
		}
101
		return true;
102
	}
103
104
	public function attr() {
105 View Code Duplication
		foreach ($this->pseudo as $pseudo) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
106
			if (strpos($pseudo, 'attr') === 0) {
107
				$bracketMatcher = new \Transphporm\Parser\BracketMatcher($pseudo);
108
				$criteria = trim($bracketMatcher->match('(', ')'));
109
				return $criteria;
110
			}
111
		}
112
113
		return false;
114
	}
115
116
	public function header($element)  {
117
		if ($this->matches($element)) {
118 View Code Duplication
			foreach ($this->pseudo as $pseudo) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
119
				if (strpos($pseudo, 'header') === 0) {
120
					$bracketMatcher = new \Transphporm\Parser\BracketMatcher($pseudo);
121
					return $bracketMatcher->match('[', ']');
122
				}
123
			}
124
		}
125
	}
126
127
	private function odd($num) {
128
		return $num % 2 === 1;
129
	}
130
131
	private function even($num) {
132
		return $num % 2 === 0;
133
	}
134
135
	public function getPseudo() {
136
		return $this->pseudo;
137
	}
138
}