1
|
|
|
<?php |
|
|
|
|
2
|
|
|
/** |
3
|
|
|
* Nucleus - XMPP Library for PHP |
4
|
|
|
* |
5
|
|
|
* Copyright (C) 2016, Some rights reserved. |
6
|
|
|
* |
7
|
|
|
* @author Kacper "Kadet" Donat <[email protected]> |
8
|
|
|
* |
9
|
|
|
* Contact with author: |
10
|
|
|
* Xmpp: [email protected] |
11
|
|
|
* E-mail: [email protected] |
12
|
|
|
* |
13
|
|
|
* From Kadet with love. |
14
|
|
|
*/ |
15
|
|
|
|
16
|
|
|
namespace Kadet\Xmpp\Utils\filter; |
17
|
|
|
|
18
|
|
|
require __DIR__ . '/Filter/element.php'; |
19
|
|
|
require __DIR__ . '/Filter/stanza.php'; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* Predicate used to check if argument is equal (loosely) to specified value. |
23
|
|
|
* |
24
|
|
|
* ```php |
25
|
|
|
* $predicate = equals(10); |
26
|
|
|
* |
27
|
|
|
* $predicate(10); // true, as 10 == 10 |
28
|
|
|
* $predicate("10abc"); // true, as 10 == "10abc" |
29
|
|
|
* $predicate("abc"); // false, as 10 != "abc" |
30
|
|
|
* ``` |
31
|
|
|
* |
32
|
|
|
* @param $value |
33
|
|
|
* @return \Closure |
34
|
|
|
*/ |
35
|
|
|
function equals($value) : \Closure |
36
|
|
|
{ |
37
|
|
|
return function ($argument) use ($value) { |
38
|
2 |
|
return $argument == $value; |
39
|
2 |
|
}; |
40
|
|
|
} |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* Predicate used to check if argument is same as specified value. (strict comparision) |
44
|
|
|
* |
45
|
|
|
* ```php |
46
|
|
|
* $predicate = equals(10); |
47
|
|
|
* |
48
|
|
|
* $predicate(10); // true, as 10 === 10 |
49
|
|
|
* $predicate("10abc"); // false, as 10 !== "10abc" |
50
|
|
|
* $predicate("abc"); // false, as 10 !== "abc" |
51
|
|
|
* ``` |
52
|
|
|
* |
53
|
|
|
* @param $value |
54
|
|
|
* @return \Closure |
55
|
|
|
*/ |
56
|
|
|
function same($value) : \Closure |
57
|
|
|
{ |
58
|
|
|
return function ($argument) use ($value) { |
59
|
1 |
|
return $argument === $value; |
60
|
1 |
|
}; |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* Predicate used to check if argument is an instance of specified class. |
65
|
|
|
* |
66
|
|
|
* ```php |
67
|
|
|
* $predicate = instance(Foo::class); |
68
|
|
|
* |
69
|
|
|
* $predicate(new Foo); // true |
70
|
|
|
* $predicate(new \DateTime); // false |
71
|
|
|
* $predicate(new class extends Foo {}); // true, as anonymous class extends Foo |
72
|
|
|
* ``` |
73
|
|
|
* |
74
|
|
|
* @param string $class Desired class name. |
75
|
|
|
* |
76
|
|
|
* @return \Closure |
77
|
|
|
*/ |
78
|
|
|
function instance($class) : \Closure |
79
|
|
|
{ |
80
|
|
|
return function ($object) use ($class) { |
81
|
3 |
|
return $object instanceof $class; |
82
|
3 |
|
}; |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* Predicate used to match value against some regex. |
87
|
|
|
* |
88
|
|
|
* ```php |
89
|
|
|
* $predicate = regex('/^https?:\/\//'); |
90
|
|
|
* |
91
|
|
|
* $predicate('http://google.com'); // true |
92
|
|
|
* $predicate('https://google.com'); // true |
93
|
|
|
* $predicate('google.com'); // false |
94
|
|
|
* ``` |
95
|
|
|
* |
96
|
|
|
* You can also pass additional arguments for preg_match call (starting from $flags) |
97
|
|
|
* |
98
|
|
|
* @see preg_match() |
99
|
|
|
* |
100
|
|
|
* @param string $regex |
101
|
|
|
* @param array ...$options |
102
|
|
|
* @return \Closure |
103
|
|
|
*/ |
104
|
|
|
function matches($regex, ...$options) : \Closure |
105
|
|
|
{ |
106
|
|
|
return function ($value) use ($regex, $options) { |
107
|
1 |
|
return preg_match($regex, $value, $null, ...$options) > 0; |
108
|
1 |
|
}; |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* Returns constant function, that always returns specified value. |
113
|
|
|
* |
114
|
|
|
* ```php |
115
|
|
|
* $true = constant(true); |
116
|
|
|
* $string = constant("foo"); |
117
|
|
|
* |
118
|
|
|
* $true(); // true |
119
|
|
|
* $string(); // string(3) "foo" |
120
|
|
|
* ``` |
121
|
|
|
* |
122
|
|
|
* @param mixed $return |
123
|
|
|
* @return \Closure |
124
|
|
|
*/ |
125
|
|
|
function constant($return) : \Closure |
126
|
|
|
{ |
127
|
|
|
return function() use ($return) { |
128
|
7 |
|
return $return; |
129
|
7 |
|
}; |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
/** |
133
|
|
|
* Returns always true predicate. |
134
|
|
|
* |
135
|
|
|
* ```php |
136
|
|
|
* $predicate = pass(); |
137
|
|
|
* $predicate(); // true |
138
|
|
|
* ``` |
139
|
|
|
* |
140
|
|
|
* @return \Closure |
141
|
|
|
*/ |
142
|
|
|
function pass() |
143
|
|
|
{ |
144
|
2 |
|
return constant(true); |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
/** |
148
|
|
|
* Returns always false predicate. |
149
|
|
|
* |
150
|
|
|
* ```php |
151
|
|
|
* $predicate = fail(); |
152
|
|
|
* $predicate(); // false |
153
|
|
|
* ``` |
154
|
|
|
* |
155
|
|
|
* @return \Closure |
156
|
|
|
*/ |
157
|
|
|
function fail() |
158
|
|
|
{ |
159
|
1 |
|
return constant(false); |
160
|
|
|
} |
161
|
|
|
|
162
|
|
|
/** |
163
|
|
|
* Predicate used to check if arguments matches all specified predicates. It mimics and operator behaviour. |
164
|
|
|
* |
165
|
|
|
* ```php |
166
|
|
|
* $instance = instance(Foo::class); |
167
|
|
|
* $true = constant(true); |
168
|
|
|
* |
169
|
|
|
* $foo = new Foo; |
170
|
|
|
* |
171
|
|
|
* $predicate = all($instance, $true); |
172
|
|
|
* $predicate($foo); // true, it's virtually same as $instance($foo) && $true($foo) |
173
|
|
|
* ``` |
174
|
|
|
* |
175
|
|
|
* @param \callable[] ...$functions |
176
|
|
|
* @return \Closure |
177
|
|
|
*/ |
178
|
|
|
function all(callable ...$functions) : \Closure |
179
|
|
|
{ |
180
|
|
|
return function (...$args) use ($functions) { |
181
|
2 |
|
foreach ($functions as $function) { |
182
|
2 |
|
if (!$function(...$args)) { |
183
|
2 |
|
return false; |
184
|
|
|
} |
185
|
|
|
} |
186
|
|
|
|
187
|
2 |
|
return true; |
188
|
2 |
|
}; |
189
|
|
|
} |
190
|
|
|
|
191
|
|
|
/** |
192
|
|
|
* Predicate used to check if arguments matches any of specified predicates. It mimics or operator behaviour. |
193
|
|
|
* |
194
|
|
|
* ```php |
195
|
|
|
* $instance = instance(Foo::class); |
196
|
|
|
* $false = constant(false); |
197
|
|
|
* |
198
|
|
|
* $foo = new Foo; |
199
|
|
|
* |
200
|
|
|
* $predicate = any($instance, $false); |
201
|
|
|
* $predicate($foo); // true, it's virtually same as $instance($foo) || $false($foo) |
202
|
|
|
* ``` |
203
|
|
|
* |
204
|
|
|
* @param \callable[] ...$functions |
205
|
|
|
* @return \Closure |
206
|
|
|
*/ |
207
|
|
|
function any(callable ...$functions) : \Closure |
208
|
|
|
{ |
209
|
|
|
return function (...$args) use ($functions) { |
210
|
2 |
|
foreach ($functions as $function) { |
211
|
2 |
|
if ($function(...$args)) { |
212
|
2 |
|
return true; |
213
|
|
|
} |
214
|
|
|
} |
215
|
|
|
|
216
|
2 |
|
return false; |
217
|
2 |
|
}; |
218
|
|
|
} |
219
|
|
|
|
220
|
|
|
/** |
221
|
|
|
* Tries to figure best predicate for specified argument. |
222
|
|
|
* |
223
|
|
|
* For predicates returns that predicate, for class names returns `instance($predicate)`, and for other values returns |
224
|
|
|
* `equals($predicate)` or `same($predicate)`, depending on $strict argument. |
225
|
|
|
* |
226
|
|
|
* @param $predicate |
227
|
|
|
* @param bool $strict Set to true if value has to be matched strictly. |
228
|
|
|
* @return \Closure |
229
|
|
|
*/ |
230
|
|
|
function predicate($predicate, bool $strict = false) : \Closure |
231
|
|
|
{ |
232
|
|
|
if ($predicate instanceof \Closure) { |
233
|
|
|
return $predicate; |
234
|
|
|
} elseif (class_exists($predicate)) { |
235
|
|
|
return instance($predicate); |
236
|
|
|
} else { |
237
|
|
|
return $strict ? same($predicate) : equals($predicate); |
238
|
|
|
} |
239
|
|
|
} |
240
|
|
|
|
241
|
|
|
/** |
242
|
|
|
* Negates predicate specified in argument. |
243
|
|
|
* |
244
|
|
|
* ```php |
245
|
|
|
* not(constant(false))() // true, as !false === true |
246
|
|
|
* ``` |
247
|
|
|
* |
248
|
|
|
* @param callable $predicate |
249
|
|
|
* @return \Closure |
250
|
|
|
*/ |
251
|
|
|
function not(callable $predicate) : \Closure |
252
|
|
|
{ |
253
|
|
|
return function (...$arguments) use ($predicate) { |
254
|
1 |
|
return !$predicate(...$arguments); |
255
|
1 |
|
}; |
256
|
|
|
} |
257
|
|
|
|
258
|
|
|
/** |
259
|
|
|
* Helper function used to bind argument to predicate. It can be used when called arguments order do not match arguments |
260
|
|
|
* that expected by predicate. |
261
|
|
|
* |
262
|
|
|
* For example, `instance` predicate checks if first argument is instance of specified class, but argument we need to |
263
|
|
|
* check is the second one, so we need to wrap it with `argument` helper: |
264
|
|
|
* |
265
|
|
|
* ```php |
266
|
|
|
* $predicate = argument(instance(Foo::class), 1); |
267
|
|
|
* var_dump($predicate("smth", new Foo)); // true as second argument matches instance predicate |
268
|
|
|
* var_dump($predicate(new Foo, "smth")); // true as second argument does not match instance predicate |
269
|
|
|
* ``` |
270
|
|
|
* |
271
|
|
|
* @param int $offset Argument offset, 0 based |
272
|
|
|
* @param callable $predicate Predicate to match on specified offset |
273
|
|
|
* @param bool|int $length [optional] |
274
|
|
|
* `true`: will return ONLY argument at $offset |
275
|
|
|
* `false`: will return all arguments from $offset |
276
|
|
|
* int: will return $length arguments from $offset |
277
|
|
|
* @return \Closure |
278
|
|
|
*/ |
279
|
|
|
function argument(int $offset, callable $predicate, $length = true) : \Closure |
280
|
|
|
{ |
281
|
|
|
if($length === true) { |
282
|
|
|
$length = 1; |
283
|
|
|
} elseif($length === false) { |
284
|
|
|
$length = null; |
285
|
|
|
} |
286
|
|
|
|
287
|
|
|
return function (...$arguments) use ($predicate, $offset, $length) { |
288
|
3 |
|
return $predicate(...array_slice($arguments, $offset, $length, false)); |
289
|
|
|
}; |
290
|
|
|
} |
291
|
|
|
|
292
|
|
|
/** |
293
|
|
|
* Assigns predicates to arguments in relation one to one. |
294
|
|
|
* |
295
|
|
|
* ```php |
296
|
|
|
* $first = equals("foo"); |
297
|
|
|
* $second = equals("bar"); |
298
|
|
|
* |
299
|
|
|
* $predicate = consecutive($first, $second); |
300
|
|
|
* |
301
|
|
|
* $predicate("foo", "bar"); // true, as "foo" matches $first predicate, and "bar" matches $second predicate |
302
|
|
|
* $predicate("foo", "foo"); // true, as "foo" matches $first predicate, but "foo" doesn't match $second predicate |
303
|
|
|
* ``` |
304
|
|
|
* |
305
|
|
|
* @param \callable[] ...$predicates Predicates matching order of call |
306
|
|
|
* @return \Closure |
307
|
|
|
*/ |
308
|
|
|
function consecutive(callable ...$predicates) |
309
|
|
|
{ |
310
|
|
|
return function (...$arguments) use ($predicates) { |
311
|
1 |
|
foreach ($arguments as $index => $value) { |
312
|
1 |
|
if(!$predicates[$index]($value)) { |
313
|
1 |
|
return false; |
314
|
|
|
} |
315
|
|
|
} |
316
|
|
|
|
317
|
1 |
|
return true; |
318
|
1 |
|
}; |
319
|
|
|
} |
320
|
|
|
|
321
|
|
|
|
322
|
|
|
/** |
323
|
|
|
* Shorthand for calling |
324
|
|
|
* |
325
|
|
|
* ```php |
326
|
|
|
* all(element\name($name), element\xmlns($uri)) |
327
|
|
|
* ``` |
328
|
|
|
* |
329
|
|
|
* @see \Kadet\Xmpp\Utils\filter\element\name($name) |
330
|
|
|
* @see \Kadet\Xmpp\Utils\filter\element\xmlns($uri) |
331
|
|
|
* |
332
|
|
|
* @param string $name Element name |
333
|
|
|
* @param string $uri Element namespace |
334
|
|
|
* @return \Closure |
335
|
|
|
*/ |
336
|
|
|
function element(string $name, string $uri) |
337
|
|
|
{ |
338
|
|
|
return all(element\name($name), element\xmlns($uri)); |
339
|
|
|
} |
340
|
|
|
|
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.