1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace LaraCrafts\GeoRoutes; |
4
|
|
|
|
5
|
|
|
use BadMethodCallException; |
6
|
|
|
use Illuminate\Routing\Route; |
7
|
|
|
use Illuminate\Support\Str; |
8
|
|
|
|
9
|
|
|
/** |
10
|
|
|
* @mixin \Illuminate\Routing\Route |
11
|
|
|
*/ |
12
|
|
|
class GeoRoute |
13
|
|
|
{ |
14
|
|
|
/** |
15
|
|
|
* Rule is applied. |
16
|
|
|
* |
17
|
|
|
* @var bool |
18
|
|
|
*/ |
19
|
|
|
protected $applied; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* The callback to execute if the visitor |
23
|
|
|
* is not allowed. |
24
|
|
|
* |
25
|
|
|
* @var array |
26
|
|
|
*/ |
27
|
|
|
protected $callback; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* The countries to apply the rule for. |
31
|
|
|
* |
32
|
|
|
* @var array |
33
|
|
|
*/ |
34
|
|
|
protected $countries; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* The callbacks' proxies. |
38
|
|
|
* |
39
|
|
|
* @var array |
40
|
|
|
*/ |
41
|
|
|
protected static $proxies; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* The route. |
45
|
|
|
* |
46
|
|
|
* @var \Illuminate\Routing\Route |
47
|
|
|
*/ |
48
|
|
|
protected $route; |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* The rule's strategy. |
52
|
|
|
* |
53
|
|
|
* @var string |
54
|
|
|
*/ |
55
|
|
|
protected $strategy; |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* Create a new GeoRoute instance. |
59
|
|
|
* |
60
|
|
|
* @param \Illuminate\Routing\Route $route |
61
|
|
|
* @param array $countries |
62
|
|
|
* @param string $strategy |
63
|
|
|
* @throws \InvalidArgumentException |
64
|
|
|
*/ |
65
|
142 |
|
public function __construct(Route $route, array $countries, string $strategy) |
66
|
|
|
{ |
67
|
142 |
|
$this->applied = false; |
68
|
142 |
|
$this->countries = array_map('strtoupper', $countries); |
69
|
142 |
|
$this->route = $route; |
70
|
142 |
|
$this->strategy = $strategy; |
71
|
|
|
|
72
|
142 |
|
static::loadProxies(); |
73
|
142 |
|
} |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* Dynamically call the underlying route. |
77
|
|
|
* |
78
|
|
|
* @param string $method |
79
|
|
|
* @param array $arguments |
80
|
|
|
* |
81
|
|
|
* @return mixed |
82
|
|
|
*/ |
83
|
|
|
public function __call(string $method, array $arguments) |
84
|
|
|
{ |
85
|
|
|
if (method_exists($this->route, $method)) { |
86
|
|
|
return $this->route->$method(...$arguments); |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
if (array_key_exists($method, static::$proxies)) { |
90
|
|
|
return $this->setCallback(static::$proxies[$method], $arguments); |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
throw new BadMethodCallException("Undefined method '$method'"); |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
/** |
97
|
|
|
* Destruct the GeoRoute instance and apply the middleware. |
98
|
|
|
*/ |
99
|
142 |
|
public function __destruct() |
100
|
|
|
{ |
101
|
142 |
|
$this->applyMiddleware(); |
102
|
142 |
|
} |
103
|
|
|
|
104
|
|
|
/** |
105
|
|
|
* Generate a middleware string. |
106
|
|
|
* |
107
|
|
|
* @return string |
108
|
|
|
*/ |
109
|
115 |
|
public function __toString() |
110
|
|
|
{ |
111
|
115 |
|
return 'geo:' . $this->strategy . ',' . implode('&', $this->countries) . |
112
|
115 |
|
($this->callback ? ',' . serialize($this->callback) : ''); |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
/** |
116
|
|
|
* Allow given countries. |
117
|
|
|
* |
118
|
|
|
* @return $this |
119
|
|
|
*/ |
120
|
27 |
|
public function allow() |
121
|
|
|
{ |
122
|
27 |
|
$this->strategy = 'allow'; |
123
|
|
|
|
124
|
27 |
|
return $this; |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
/** |
128
|
|
|
* Apply the middleware to the route. |
129
|
|
|
*/ |
130
|
142 |
|
protected function applyMiddleware() |
131
|
|
|
{ |
132
|
142 |
|
if ($this->applied || !$this->countries) { |
|
|
|
|
133
|
27 |
|
return; |
134
|
|
|
} |
135
|
|
|
|
136
|
115 |
|
$action = $this->route->getAction(); |
137
|
115 |
|
$action['middleware'][] = (string)$this; |
138
|
|
|
|
139
|
115 |
|
$this->applied = true; |
140
|
115 |
|
$this->route->setAction($action); |
|
|
|
|
141
|
115 |
|
} |
142
|
|
|
|
143
|
|
|
/** |
144
|
|
|
* Deny given countries. |
145
|
|
|
* |
146
|
|
|
* @return $this |
147
|
|
|
*/ |
148
|
27 |
|
public function deny() |
149
|
|
|
{ |
150
|
27 |
|
$this->strategy = 'deny'; |
151
|
|
|
|
152
|
27 |
|
return $this; |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
/** |
156
|
|
|
* Load the available proxies. |
157
|
|
|
*/ |
158
|
142 |
|
protected static function loadProxies() |
159
|
|
|
{ |
160
|
142 |
|
if (static::$proxies !== null) { |
|
|
|
|
161
|
142 |
|
return; |
162
|
|
|
} |
163
|
|
|
|
164
|
27 |
|
static::$proxies = []; |
165
|
27 |
|
$callbacks = config('geo-routes.callbacks'); |
166
|
|
|
|
167
|
27 |
|
foreach ($callbacks as $key => $callback) { |
168
|
|
|
static::$proxies['or' . Str::studly($key)] = $callback; |
169
|
|
|
} |
170
|
27 |
|
} |
171
|
|
|
|
172
|
|
|
/** |
173
|
|
|
* Return a HTTP 404 error if access is denied. |
174
|
|
|
* |
175
|
|
|
* @return $this |
176
|
|
|
*/ |
177
|
26 |
|
public function orNotFound() |
178
|
|
|
{ |
179
|
26 |
|
return $this->setCallback('LaraCrafts\GeoRoutes\Callbacks::notFound', func_get_args()); |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
/** |
183
|
|
|
* Redirect to given route if access is denied. |
184
|
|
|
* |
185
|
|
|
* @param string $routeName |
186
|
|
|
* |
187
|
|
|
* @return $this |
188
|
|
|
*/ |
189
|
26 |
|
public function orRedirectTo(string $routeName) |
190
|
|
|
{ |
191
|
26 |
|
return $this->setCallback('LaraCrafts\GeoRoutes\Callbacks::redirectTo', func_get_args()); |
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
/** |
195
|
|
|
* Return a HTTP 401 error if access is denied (this is the default behavior). |
196
|
|
|
* |
197
|
|
|
* @return $this |
198
|
|
|
*/ |
199
|
|
|
public function orUnauthorized() |
200
|
|
|
{ |
201
|
|
|
$this->callback = null; |
202
|
|
|
|
203
|
|
|
return $this; |
204
|
|
|
} |
205
|
|
|
|
206
|
|
|
/** |
207
|
|
|
* Set the callback. |
208
|
|
|
* |
209
|
|
|
* @param callable $callback |
210
|
|
|
* @param array $arguments |
211
|
|
|
* |
212
|
|
|
* @return $this |
213
|
|
|
*/ |
214
|
52 |
|
protected function setCallback(callable $callback, array $arguments) |
215
|
|
|
{ |
216
|
52 |
|
if (is_string($callback) && Str::contains($callback, '@')) { |
217
|
|
|
$callback = Str::parseCallback($callback, '__invoke'); |
218
|
|
|
$callback[0] = resolve($callback[0]); |
219
|
|
|
} |
220
|
|
|
|
221
|
52 |
|
$this->callback = [$callback, $arguments]; |
222
|
|
|
|
223
|
52 |
|
return $this; |
224
|
|
|
} |
225
|
|
|
} |
226
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.