Passed
Push — master ( 3dea92...932a4d )
by Atanas
02:02
created

ConditionFactory   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 182
Duplicated Lines 0 %

Test Coverage

Coverage 96.08%

Importance

Changes 0
Metric Value
eloc 48
dl 0
loc 182
rs 10
c 0
b 0
f 0
ccs 49
cts 51
cp 0.9608
wmc 23

11 Methods

Rating   Name   Duplication   Size   Complexity  
A makeFromClosure() 0 2 1
A getConditionTypeClass() 0 6 2
A parseNegatedCondition() 0 6 1
A makeFromArray() 0 17 4
A isNegatedCondition() 0 5 2
A makeFromArrayOfConditions() 0 2 1
A make() 0 14 4
A makeFromUrl() 0 2 1
A conditionTypeRegistered() 0 6 2
A __construct() 0 2 1
A parseConditionOptions() 0 17 4
1
<?php
2
3
namespace WPEmerge\Routing\Conditions;
4
5
use Closure;
6
use ReflectionClass;
7
use ReflectionException;
8
use WPEmerge\Exceptions\Exception;
9
10
/**
11
 * Check against the current url
12
 */
13
class ConditionFactory {
14
	const NEGATE_CONDITION_PREFIX = '!';
15
16
	/**
17
	 * Registered condition types.
18
	 *
19
	 * @var array<string, string>
20
	 */
21
	protected $condition_types = [];
22
23
	/**
24
	 * Constructor.
25
	 *
26
	 * @codeCoverageIgnore
27
	 * @param array<string, string> $condition_types
28
	 */
29
	public function __construct( $condition_types ) {
30
		$this->condition_types = $condition_types;
31
	}
32
33
	/**
34
	 * Create a new condition.
35
	 *
36
	 * @throws Exception
37
	 * @throws InvalidRouteConditionException
38
	 * @param  string|array|Closure           $options
39
	 * @return ConditionInterface
40
	 */
41 13
	public function make( $options ) {
42 13
		if ( is_string( $options ) ) {
43 2
			return $this->makeFromUrl( $options );
44
		}
45
46 11
		if ( is_array( $options ) ) {
47 9
			return $this->makeFromArray( $options );
48
		}
49
50 2
		if ( $options instanceof Closure ) {
51 1
			return $this->makeFromClosure( $options );
52
		}
53
54 1
		throw new InvalidRouteConditionException( 'Invalid condition options supplied.' );
55
	}
56
57
	/**
58
	 * Get condition class for condition type.
59
	 *
60
	 * @param  string      $condition_type
61
	 * @return string|null
62
	 */
63 2
	protected function getConditionTypeClass( $condition_type ) {
64 2
		if ( ! isset( $this->condition_types[ $condition_type ] ) ) {
65 1
			return null;
66
		}
67
68 1
		return $this->condition_types[ $condition_type ];
69
	}
70
71
	/**
72
	 * Check if the passed argument is a registered condition type.
73
	 *
74
	 * @param  mixed   $condition_type
75
	 * @return boolean
76
	 */
77 6
	protected function conditionTypeRegistered( $condition_type ) {
78 6
		if ( ! is_string( $condition_type ) ) {
79 1
			return false;
80
		}
81
82 5
		return $this->getConditionTypeClass( $condition_type ) !== null;
83
	}
84
85
	/**
86
	 * Check if a condition is negated.
87
	 *
88
	 * @param  mixed   $condition
89
	 * @return boolean
90
	 */
91 1
	protected function isNegatedCondition( $condition ) {
92
		return (
93 1
			is_string( $condition )
94
			&&
95 1
			strpos( $condition, static::NEGATE_CONDITION_PREFIX ) === 0
96
		);
97
	}
98
99
	/**
100
	 * Parse a negated condition and its arguments.
101
	 *
102
	 * @param  string $type
103
	 * @param  array  $arguments
104
	 * @return array
105
	 */
106 1
	protected function parseNegatedCondition( $type, $arguments ) {
107 1
		$negated_type = substr( $type, strlen( static::NEGATE_CONDITION_PREFIX ) );
108 1
		$arguments = array_merge( [ $negated_type ], $arguments );
109 1
		$type = 'negate';
110
111 1
		return ['type' => $type, 'arguments' => $arguments];
112
	}
113
114
	/**
115
	 * Parse the condition type and its arguments from an options array.
116
	 *
117
	 * @throws Exception
118
	 * @param  array $options
119
	 * @return array
120
	 */
121 7
	protected function parseConditionOptions( $options ) {
122 7
		$type = $options[0];
123 7
		$arguments = array_values( array_slice( $options, 1 ) );
124
125 7
		if ( $this->isNegatedCondition( $type ) ) {
126 1
			return $this->parseNegatedCondition( $type, $arguments );
127
		}
128
129 7
		if ( ! $this->conditionTypeRegistered( $type ) ) {
130 3
			if ( is_callable( $type ) ) {
131 2
				return ['type' => 'custom', 'arguments' => $options];
132
			}
133
134 1
			throw new Exception( 'Unknown condition type specified: ' . $type );
135
		}
136
137 4
		return ['type' => $type, 'arguments' => $arguments ];
138
	}
139
140
	/**
141
	 * Create a new condition from a url.
142
	 *
143
	 * @param  string             $url
144
	 * @return ConditionInterface
145
	 */
146 1
	protected function makeFromUrl( $url ) {
147 1
		return new UrlCondition( $url );
148
	}
149
150
	/**
151
	 * Create a new condition from an array.
152
	 *
153
	 * @throws Exception
154
	 * @param  array               $options
155
	 * @return ConditionInterface
156
	 */
157 9
	protected function makeFromArray( $options ) {
158 9
		if ( count( $options ) === 0 ) {
159 1
			throw new Exception( 'No condition type specified.' );
160
		}
161
162 8
		if ( is_array( $options[0] ) ) {
163 1
			return $this->makeFromArrayOfConditions( $options );
164
		}
165
166 8
		$condition_options = $this->parseConditionOptions( $options );
167 7
		$condition_class = $this->getConditionTypeClass( $condition_options['type'] );
168
169
		try {
170 7
			$reflection = new ReflectionClass( $condition_class );
171 7
			return $reflection->newInstanceArgs( $condition_options['arguments'] );
172
		} catch ( ReflectionException $e ) {
173
			throw new Exception( 'Condition class "' . $condition_class . '" does not exist.' );
174
		}
175
	}
176
177
	/**
178
	 * Create a new condition from an array of conditions.
179
	 *
180
	 * @param  array               $options
181
	 * @return ConditionInterface
182
	 */
183 1
	protected function makeFromArrayOfConditions( $options ) {
184 1
		return new MultipleCondition( $options );
185
	}
186
187
	/**
188
	 * Create a new condition from a closure.
189
	 *
190
	 * @param  Closure            $closure
191
	 * @return ConditionInterface
192
	 */
193 1
	protected function makeFromClosure( Closure $closure ) {
194 1
		return new CustomCondition( $closure );
195
	}
196
}
197