|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace Obsidian\Routing\Conditions; |
|
4
|
|
|
|
|
5
|
|
|
use Obsidian\Framework; |
|
6
|
|
|
use Obsidian\Routing\Conditions\Custom as CustomCondition; |
|
7
|
|
|
use Obsidian\Routing\Conditions\Multiple as MultipleCondition; |
|
8
|
|
|
use Obsidian\Routing\Conditions\Url as UrlCondition; |
|
9
|
|
|
use Closure; |
|
10
|
|
|
use Exception; |
|
11
|
|
|
use ReflectionClass; |
|
12
|
|
|
|
|
13
|
|
|
/** |
|
14
|
|
|
* Check against the current url |
|
15
|
|
|
*/ |
|
16
|
|
|
class Factory { |
|
17
|
|
|
/** |
|
18
|
|
|
* Create a new condition |
|
19
|
|
|
* |
|
20
|
|
|
* @param string|array|Closure $options |
|
21
|
|
|
* @return ConditionInterface |
|
22
|
|
|
*/ |
|
23
|
12 |
|
public static function make( $options ) { |
|
24
|
12 |
|
if ( is_string( $options ) ) { |
|
25
|
2 |
|
return static::makeFromUrl( $options ); |
|
26
|
|
|
} |
|
27
|
|
|
|
|
28
|
10 |
|
if ( is_array( $options ) ) { |
|
29
|
8 |
|
return static::makeFromArray( $options ); |
|
30
|
|
|
} |
|
31
|
|
|
|
|
32
|
2 |
|
if ( is_a( $options, Closure::class ) ) { |
|
33
|
1 |
|
return static::makeFromClosure( $options ); |
|
34
|
|
|
} |
|
35
|
|
|
|
|
36
|
1 |
|
if ( is_a( $options, ConditionInterface::class ) ) { |
|
37
|
|
|
return $options; |
|
|
|
|
|
|
38
|
|
|
} |
|
39
|
|
|
|
|
40
|
1 |
|
throw new InvalidRouteConditionException( 'Invalid condition options supplied.' ); |
|
41
|
|
|
} |
|
42
|
|
|
|
|
43
|
|
|
/** |
|
44
|
|
|
* Check if the passed argument is a registered condition type |
|
45
|
|
|
* |
|
46
|
|
|
* @param mixed $condition_type |
|
47
|
|
|
* @return boolean |
|
48
|
|
|
*/ |
|
49
|
6 |
|
protected static function conditionTypeRegistered( $condition_type ) { |
|
50
|
6 |
|
if ( ! is_string( $condition_type ) ) { |
|
51
|
1 |
|
return false; |
|
52
|
|
|
} |
|
53
|
|
|
|
|
54
|
5 |
|
$condition_class = Framework::resolve( 'framework.routing.conditions.' . $condition_type ); |
|
55
|
5 |
|
return ( $condition_class !== null ); |
|
56
|
|
|
} |
|
57
|
|
|
|
|
58
|
|
|
/** |
|
59
|
|
|
* Resolve the condition type and its arguments from an options array |
|
60
|
|
|
* |
|
61
|
|
|
* @param array $options |
|
62
|
|
|
* @return array |
|
63
|
|
|
*/ |
|
64
|
6 |
|
protected static function getConditionTypeAndArguments( $options ) { |
|
65
|
6 |
|
$type = $options[0]; |
|
66
|
6 |
|
$arguments = array_slice( $options, 1 ); |
|
67
|
|
|
|
|
68
|
6 |
|
if ( ! static::conditionTypeRegistered( $type ) ) { |
|
69
|
3 |
|
if ( is_callable( $type ) ) { |
|
70
|
2 |
|
$type = 'custom'; |
|
71
|
2 |
|
$arguments = $options; |
|
72
|
|
|
} else { |
|
73
|
1 |
|
throw new Exception( 'Unknown condition type specified: ' . $type ); |
|
74
|
|
|
} |
|
75
|
|
|
} |
|
76
|
|
|
|
|
77
|
|
|
return array( |
|
78
|
5 |
|
'type' => $type, |
|
79
|
5 |
|
'arguments' => $arguments, |
|
80
|
|
|
); |
|
81
|
|
|
} |
|
82
|
|
|
|
|
83
|
|
|
/** |
|
84
|
|
|
* Create a new condition from a url |
|
85
|
|
|
* |
|
86
|
|
|
* @param string $url |
|
87
|
|
|
* @return ConditionInterface |
|
88
|
|
|
*/ |
|
89
|
1 |
|
protected static function makeFromUrl( $url ) { |
|
90
|
1 |
|
return new UrlCondition( $url ); |
|
91
|
|
|
} |
|
92
|
|
|
|
|
93
|
|
|
/** |
|
94
|
|
|
* Create a new condition from an array of conditions |
|
95
|
|
|
* |
|
96
|
|
|
* @param array $options |
|
97
|
|
|
* @return ConditionInterface |
|
98
|
|
|
*/ |
|
99
|
1 |
|
protected static function makeFromArrayOfConditions( $options ) { |
|
100
|
1 |
|
return new MultipleCondition( $options ); |
|
101
|
|
|
} |
|
102
|
|
|
|
|
103
|
|
|
/** |
|
104
|
|
|
* Create a new condition from an array |
|
105
|
|
|
* |
|
106
|
|
|
* @param array $options |
|
107
|
|
|
* @return ConditionInterface |
|
108
|
|
|
*/ |
|
109
|
8 |
|
protected static function makeFromArray( $options ) { |
|
110
|
8 |
|
if ( count( $options ) === 0 ) { |
|
111
|
1 |
|
throw new Exception( 'No condition type specified.' ); |
|
112
|
|
|
} |
|
113
|
|
|
|
|
114
|
7 |
|
if ( is_array( $options[0] ) ) { |
|
115
|
1 |
|
return static::makeFromArrayOfConditions( $options ); |
|
116
|
|
|
} |
|
117
|
|
|
|
|
118
|
7 |
|
$condition_options = static::getConditionTypeAndArguments( $options ); |
|
119
|
6 |
|
$condition_class = Framework::resolve( 'framework.routing.conditions.' . $condition_options['type'] ); |
|
120
|
|
|
|
|
121
|
6 |
|
$reflection = new ReflectionClass( $condition_class ); |
|
122
|
6 |
|
$condition = $reflection->newInstanceArgs( $condition_options['arguments'] ); |
|
123
|
6 |
|
return $condition; |
|
124
|
|
|
} |
|
125
|
|
|
|
|
126
|
|
|
/** |
|
127
|
|
|
* Create a new condition from a closure |
|
128
|
|
|
* |
|
129
|
|
|
* @param Closure $closure |
|
130
|
|
|
* @return ConditionInterface |
|
131
|
|
|
*/ |
|
132
|
1 |
|
protected static function makeFromClosure( Closure $closure ) { |
|
133
|
1 |
|
return new CustomCondition( $closure ); |
|
134
|
|
|
} |
|
135
|
|
|
} |
|
136
|
|
|
|
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_functionexpects aPostobject, and outputs the author of the post. The base classPostreturns a simple string and outputting a simple string will work just fine. However, the child classBlogPostwhich is a sub-type ofPostinstead decided to return anobject, and is therefore violating the SOLID principles. If aBlogPostwere passed tomy_function, PHP would not complain, but ultimately fail when executing thestrtouppercall in its body.