Completed
Push — develop ( c9e495...9fe602 )
by Bradley
03:10 queued 01:05
created

Logical   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 177
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 6
Bugs 3 Features 2
Metric Value
wmc 27
lcom 1
cbo 6
dl 0
loc 177
rs 10
c 6
b 3
f 2

3 Methods

Rating   Name   Duplication   Size   Complexity  
C decodeLogicStatements() 0 53 13
A executeLogicStatement() 0 19 4
D execute() 0 40 10
1
<?php namespace Cornford\Logical;
2
3
use Cornford\Logical\Contracts\LogicalInterface;
4
use Cornford\Logical\Exceptions\LogicalDecodingException;
5
use Cornford\Logical\Exceptions\LogicalExecutionException;
6
use Cornford\Logical\Exceptions\LogicalFieldValueException;
7
use Exception;
8
9
class Logical extends LogicalAbstract implements LogicalInterface {
10
11
	/**
12
	 * The temporary logic method.
13
	 *
14
	 * @var string
15
	 */
16
	protected $tempLogic;
17
18
	/**
19
	 * The temporary logic method.
20
	 *
21
	 * @var string
22
	 */
23
	protected $tempMethod;
24
25
	/**
26
	 * The temporary logic expected.
27
	 *
28
	 * @var string|array
29
	 */
30
	protected $tempExpected;
31
32
	/**
33
	 * The temporary logic field.
34
	 *
35
	 * @var string
36
	 */
37
	protected $tempField;
38
39
	/**
40
	 * The temporary results.
41
	 *
42
	 * @var array
43
	 */
44
	protected $tempResults;
45
46
	/**
47
	 * Decode the logic string into an array of logical statements.
48
	 *
49
	 * @return boolean
50
	 */
51
	protected function decodeLogicStatements()
52
	{
53
		if (!$this->getLogic()) {
54
			return true;
55
		}
56
57
		$orStatements = preg_split("/.OR./", $this->getLogic());
58
59
		foreach ($orStatements as $orKey => $orStatement) {
60
			$andStatements = preg_split("/.AND./", $orStatement);
61
62
			foreach ($andStatements as $andStatement) {
63
				$items = preg_split("/\./", $andStatement, 2);
64
				$decodedStatement = [];
65
66
				foreach ($items as $item) {
67
					$matches = null;
68
					if (stristr($item, 'where')) {
69
						if (!preg_match("/\((?<field>.*)\)/", $item, $matches)) {
70
							return false;
71
						}
72
73
						$this->tempField = trim(trim($matches['field'], '\''), '"');
74
75
						continue;
76
					}
77
78
					if (!preg_match("/^(?<method>[a-zA-Z]{1,})\((?<expected>[\'\"]*.*[\'\"]*)\)/", $item, $matches)) {
79
						return false;
80
					} else {
81
						$this->tempMethod = trim(trim($matches['method'], '\''), '"');
82
						$this->tempExpected = trim(trim($matches['expected'], '\''), '"');
83
					}
84
85
					if (stristr($this->tempExpected, ',') && !stristr($this->tempExpected, '{') && !stristr($this->tempExpected, '}')) {
86
						$this->tempExpected = explode(', ', $this->tempExpected);
87
					}
88
89
					if (stristr($this->tempExpected, '{') && stristr($this->tempExpected, '}')) {
90
						$this->tempExpected = eval(str_replace('{', 'print_r(', str_replace('}', ', true);', $this->tempExpected)));
91
					}
92
93
					$decodedStatement[$orKey]['method'] = $this->tempMethod;
94
					$decodedStatement[$orKey]['expected'] = $this->tempExpected;
95
					$decodedStatement[$orKey]['field'] = $this->tempField;
96
				}
97
98
				$this->setDecodedLogicStatement($decodedStatement);
99
			}
100
		}
101
102
		return true;
103
	}
104
105
	/**
106
	 * Execute a logic statement method on an input value against an expected value.
107
	 *
108
	 * @param string                 $method
109
	 * @param string|integer|boolean $input
110
	 * @param string|integer|boolean $expected
111
	 *
112
	 * @throws LogicalExecutionException
113
	 *
114
	 * @return boolean
115
	 */
116
	protected function executeLogicStatement($method, $input, $expected = null)
117
	{
118
		$logicalStatementInstance = $this->getLogicalStatementInstance();
119
		$result = null;
120
121
		if (method_exists($logicalStatementInstance, $method)) {
122
			$result = $logicalStatementInstance->$method($input, $expected);
123
		}
124
125
		if ($logicalStatementInstance->customStatementExists($method)) {
126
			$result = $logicalStatementInstance->callCustomStatement($method, $input, $expected);
127
		}
128
129
		if (is_null($result)) {
130
			throw new LogicalExecutionException("Unable to execute logic statement method: {$method}().");
131
		}
132
133
		return $result;
134
	}
135
136
	/**
137
	 * Decodes logic input into statements and executes each statement removing un-matching results.
138
	 *
139
	 * @throws LogicalDecodingException
140
	 * @throws LogicalFieldValueException
141
	 *
142
	 * @return self
143
	 */
144
	public function execute()
145
	{
146
		if (!$this->decodeLogicStatements()) {
147
			throw new LogicalDecodingException('Unable to decode logic input.');
148
		}
149
150
		foreach ($this->getDecodedLogicStatements() as $orStatement) {
151
			$this->tempResults = $this->getInput();
152
153
			foreach ($this->getInput() as $key => $input) {
154
				foreach ($orStatement as $andStatement) {
155
					switch (gettype($input)) {
156
						case 'object':
157
							break;
158
						case 'array':
159
						default:
160
							$andStatement['field'] = '[' . $andStatement['field'] . ']';
161
					}
162
163
					try {
164
						$value = $this->getPropertyAccessorInstance()->getValue($input, $andStatement['field']);
165
					} catch (Exception $exception) {
166
						throw new LogicalFieldValueException('Unable to locate logical statement field value.');
167
					}
168
169
					if (!isset($value)) {
170
						throw new LogicalFieldValueException('Unable to locate logical statement field value.');
171
					}
172
173
					if (!$this->executeLogicStatement($andStatement['method'], $value, $andStatement['expected'])) {
174
						unset($this->tempResults[$key]);
175
					}
176
				}
177
			}
178
179
			$this->mergeResults($this->tempResults);
180
		}
181
182
		return $this;
183
	}
184
185
}