Completed
Push — master ( 324c41...7edbdc )
by Richard
06:27
created

Value::processComparator()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 8
rs 9.4285
cc 3
eloc 5
nc 2
nop 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\Parser;
8
/** Parses "string" and function(args) e.g. data(foo) or iteration(bar) */
9
class Value {
10
	private $baseData;
11
	private $autoLookup;
12
	/*
13
		Stores the last value e.g.
14
			"a" + "b"
15
		Will store "a" before reading the token for the + and perfoming the concatenate operation
16
	*/
17
	private $last;
18
	private $data;
19
	private $result;
20
	private $traversing = false;
21
	private $allowNullResult;
22
23
	private $tokenFuncs = [
24
			Tokenizer::NOT => 'processComparator',
25
			Tokenizer::EQUALS => 'processComparator',
26
			Tokenizer::DOT => 'processDot',
27
			Tokenizer::OPEN_SQUARE_BRACKET => 'processSquareBracket',
28
			Tokenizer::ARG => 'processSeparator',
29
			Tokenizer::CONCAT => 'processSeparator',
30
			Tokenizer::SUBTRACT => 'processSeparator',
31
			Tokenizer::MULTIPLY => 'processSeparator',
32
			Tokenizer::DIVIDE => 'processSeparator',
33
			Tokenizer::NAME => 'processScalar',
34
			Tokenizer::NUMERIC => 'processString',
35
			Tokenizer::BOOL => 'processString',
36
			Tokenizer::STRING => 'processString',
37
			Tokenizer::OPEN_BRACKET => 'processBrackets'
38
	];
39
40
	public function __construct($data, $autoLookup = false, $allowNullResult = false) {
41
		$this->baseData = $data;
42
		$this->autoLookup = $autoLookup;
43
		$this->allowNullResult = $allowNullResult;
44
	}
45
46
	public function parse($str) {
47
		$tokenizer = new Tokenizer($str);
48
		$tokens = $tokenizer->getTokens();
49
		$this->result = $this->parseTokens($tokens, $this->baseData);
50
		return $this->result;
51
	}
52
53
	public function parseTokens($tokens, $data = null) {
54
		$this->result = new ValueResult();
55
		$this->data = new ValueData($data ? $data : $this->baseData);
56
		$this->last = new Last($this->data, $this->result, $this->autoLookup);
57
		$this->traversing = false;
58
59
		if (count($tokens) <= 0) return [$data];
60
61
		foreach (new TokenFilterIterator($tokens, [Tokenizer::WHITESPACE, Tokenizer::NEW_LINE]) as $token) {
62
			$this->{$this->tokenFuncs[$token['type']]}($token);
63
		}
64
65
		$this->last->process();
66
		return $this->result->getResult();
67
	}
68
69
	private function processComparator($token) {
70
		$this->last->process();
71
72
		if (!(in_array($this->result->getMode(), array_keys($this->tokenFuncs, 'processComparator')) && $token['type'] == Tokenizer::EQUALS)) {
73
			$this->result->setMode($token['type']);
74
			$this->last->clear();
75
		}
76
	}
77
78
	//Reads the last selected value from $data regardless if it's an array or object and overrides $this->data with the new value
79
	//Dot moves $data to the next object in $data foo.bar moves the $data pointer from `foo` to `bar`
80
	private function processDot($token) {
0 ignored issues
show
Unused Code introduced by
The parameter $token 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...
81
		$lastResult = $this->last->traverse();
82
83
		//When . is not preceeded by anything, treat it as part of the string instead of an operator
84
		// foo.bar is treated as looking up `bar` in `foo` whereas .foo is treated as the string ".foo"
85
		if ($lastResult) {
86
			$this->last->makeTraversing();
87
		}
88
		else if ($this->last->isEmpty())  {
89
			$this->processString(['value' => '.']);
90
			$this->result->setMode(Tokenizer::CONCAT);
91
		}
92
93
		$this->last->clear();
94
	}
95
96
	private function hasFunction($name) {
97
		return $this->baseData instanceof \Transphporm\Functionset && $this->baseData->hasFunction($name);
98
	}
99
100
	private function processSquareBracket($token) {
101
		if ($this->hasFunction($this->last->read())) {
102
			$this->callTransphpormFunctions($token);
103
		}
104
		else {
105
			$this->last->traverse();
106
			$this->last->set($this->getNewParser()->parseTokens($token['value'], null)[0]);
107
			if (!is_bool($this->last->read())) $this->last->makeTraversing();
108
		}
109
	}
110
111
	private function processSeparator($token) {
112
		$this->result->setMode($token['type']);
113
	}
114
115
	private function processScalar($token) {
116
		if (is_scalar($this->last->read())) {
117
			$this->result->processValue($this->last->read());
118
		}
119
		$this->last->set($token['value']);
120
	}
121
122
	private function processString($token) {
123
		$this->result->processValue($token['value']);
124
	}
125
126
	private function processBrackets($token) {
127
		if ($this->hasFunction($this->last->read())
128
			&& !$this->data->methodExists($this->last->read())) {
129
			$this->callTransphpormFunctions($token);
130
		}
131
		else {
132
			$this->last->processNested($this->getNewParser(), $token);
133
		}
134
	}
135
136
	private function getNewParser() {
137
		return new Value($this->baseData, $this->autoLookup);
138
	}
139
140
	private function callTransphpormFunctions($token, $parse = true) {
0 ignored issues
show
Unused Code introduced by
The parameter $parse 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...
141
		$val = $this->baseData->{$this->last->read()}($token['value']);
142
		$this->result->processValue($val);
143
144
		if ($this->autoLookup) {
145
			$parser = new Value($this->data->getData());
146
			$parsedArr = $parser->parse($val);
147
			$parsedVal = isset($parsedArr[0]) ? $parsedArr[0] : null;
148
		}
149
		else $parsedVal = null;
150
        
151
        $this->result->postProcess($this->data, $val, $parsedVal, $this->allowNullResult);
152
153
		$this->last->clear();
154
	}
155
}
156