Spec   A
last analyzed

Complexity

Total Complexity 31

Size/Duplication

Total Lines 382
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 1

Test Coverage

Coverage 94.44%

Importance

Changes 2
Bugs 0 Features 1
Metric Value
wmc 31
c 2
b 0
f 1
lcom 2
cbo 1
dl 0
loc 382
ccs 68
cts 72
cp 0.9444
rs 9.8

19 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A __invoke() 0 8 1
A field() 0 5 1
A asSoftRule() 0 4 1
A asHardRule() 0 4 1
A asStopRule() 0 4 1
A setMessage() 0 5 1
A isStopRule() 0 4 1
A isHardRule() 0 4 1
A isSoftRule() 0 4 1
A getField() 0 4 1
A getArgs() 0 4 1
A init() 0 6 1
A getDefaultMessage() 0 4 1
A subjectFieldIsBlank() 0 18 4
A setFailureMode() 0 8 2
A getMessage() 0 7 2
B argToString() 0 17 6
A argsToString() 0 12 3
1
<?php
2
/**
3
 *
4
 * This file is part of Aura for PHP.
5
 *
6
 * @license http://opensource.org/licenses/bsd-license.php BSD
7
 *
8
 */
9
namespace Aura\Filter\Spec;
10
11
use Aura\Filter\Locator\Locator;
12
use Exception;
13
use Closure;
14
15
/**
16
 *
17
 * A generic rule specification.
18
 *
19
 * @package Aura.Filter
20
 *
21
 */
22
class Spec
23
{
24
    /**
25
     * Stop filtering on a field when a rule for that field fails.
26
     */
27
    const HARD_RULE = 'HARD_RULE';
28
29
    /**
30
     * Continue filtering on a field even when a rule for that field fails.
31
     */
32
    const SOFT_RULE = 'SOFT_RULE';
33
34
    /**
35
     * Stop filtering on all fields when a rule fails.
36
     */
37
    const STOP_RULE = 'STOP_RULE';
38
39
    /**
40
     *
41
     * The field name to be filtered.
42
     *
43
     * @var string
44
     *
45
     */
46
    protected $field;
47
48
    /**
49
     *
50
     * The rule name to be applied.
51
     *
52
     * @var string
53
     *
54
     */
55
    protected $rule;
56
57
    /**
58
     *
59
     * Arguments to pass to the rule.
60
     *
61
     * @var array
62
     *
63
     */
64
    protected $args = array();
65
66
    /**
67
     *
68
     * The message to use on failure.
69
     *
70
     * @var string
71
     *
72
     */
73
    protected $message;
74
75
    /**
76
     *
77
     * Allow the field to be blank?
78
     *
79
     * @var bool
80
     *
81
     */
82
    protected $allow_blank = false;
83
84
    /**
85
     *
86
     * The failure mode to use.
87
     *
88
     * @var string
89
     *
90
     */
91
    protected $failure_mode = self::HARD_RULE;
92
93
    /**
94
     *
95
     * The rule locator to use.
96
     *
97
     * @var Locator
98
     *
99
     */
100
    protected $locator;
101
102
    /**
103
     *
104
     * Constructor.
105
     *
106
     * @param Locator $locator The "sanitize" rules.
107
     *
108
     * @return self
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
109
     *
110
     */
111 31
    public function __construct(Locator $locator)
112
    {
113 31
        $this->locator = $locator;
114 31
    }
115
116
    /**
117
     *
118
     * Applies the rule specification to a subject.
119
     *
120
     * @param mixed $subject The filter subject.
121
     *
122
     * @return bool True on success, false on failure.
123
     *
124
     */
125 15
    public function __invoke($subject)
126
    {
127 15
        $rule = $this->locator->get($this->rule);
128 15
        $args = $this->args;
129 15
        array_unshift($args, $this->field);
130 15
        array_unshift($args, $subject);
131 15
        return call_user_func_array($rule, $args);
132
    }
133
134
    /**
135
     *
136
     * Sets the subject field name.
137
     *
138
     * @param string $field The subject field name.
139
     *
140
     * @return self
141
     *
142
     */
143 25
    public function field($field)
144
    {
145 25
        $this->field = $field;
146 25
        return $this;
147
    }
148
149
    /**
150
     *
151
     * Sets this specification as a "soft" rule.
152
     *
153
     * @param string $message The failure message.
154
     *
155
     * @return self
156
     *
157
     */
158 7
    public function asSoftRule($message = null)
159
    {
160 7
        return $this->setFailureMode(self::SOFT_RULE, $message);
161
    }
162
163
    /**
164
     *
165
     * Sets this specification as a "hard" rule.
166
     *
167
     * @param string $message The failure message.
168
     *
169
     * @return self
170
     *
171
     */
172 5
    public function asHardRule($message = null)
173
    {
174 5
        return $this->setFailureMode(self::HARD_RULE, $message);
175
    }
176
177
    /**
178
     *
179
     * Sets this specification as a "stop" rule.
180
     *
181
     * @param string $message The failure message.
182
     *
183
     * @return self
184
     *
185
     */
186 3
    public function asStopRule($message = null)
187
    {
188 3
        return $this->setFailureMode(self::STOP_RULE, $message);
189
    }
190
191
    /**
192
     *
193
     * Sets the failure mode for this rule specification.
194
     *
195
     * @param string $failure_mode The failure mode.
196
     *
197
     * @param string $message The failure message.
198
     *
199
     * @return self
200
     *
201
     */
202 8
    protected function setFailureMode($failure_mode, $message)
203
    {
204 8
        $this->failure_mode = $failure_mode;
205 8
        if ($message) {
206 2
            $this->setMessage($message);
207
        }
208 8
        return $this;
209
    }
210
211
    /**
212
     *
213
     * Sets the failure message for this rule specification.
214
     *
215
     * @param string $message The failure message.
216
     *
217
     * @return self
218
     *
219
     */
220 2
    public function setMessage($message)
221
    {
222 2
        $this->message = $message;
223 2
        return $this;
224
    }
225
226
    /**
227
     *
228
     * On failure, should the subject filter stop processing all fields?
229
     *
230
     * @return bool
231
     *
232
     */
233 9
    public function isStopRule()
234
    {
235 9
        return $this->failure_mode === self::STOP_RULE;
236
    }
237
238
    /**
239
     *
240
     * On failure, should the subject filter stop processing the current field?
241
     *
242
     * @return bool
243
     *
244
     */
245 9
    public function isHardRule()
246
    {
247 9
        return $this->failure_mode === self::HARD_RULE;
248
    }
249
250
    /**
251
     *
252
     * On failure, should the subject filter keep processing the current field?
253
     *
254
     * @return bool
255
     *
256
     */
257 2
    public function isSoftRule()
258
    {
259 2
        return $this->failure_mode === self::SOFT_RULE;
260
    }
261
262
    /**
263
     *
264
     * Returns the field name for this rule specification.
265
     *
266
     * @return string
267
     *
268
     */
269 11
    public function getField()
270
    {
271 11
        return $this->field;
272
    }
273
274
    /**
275
     *
276
     * Returns the failure message for this rule specification.
277
     *
278
     * @return string
279
     *
280
     */
281 16
    public function getMessage()
282
    {
283 16
        if (! $this->message) {
284 14
            $this->message = $this->getDefaultMessage();
285
        }
286 16
        return $this->message;
287
    }
288
289
    /**
290
     *
291
     * Returns the arguments for this rule specification.
292
     *
293
     * @return array
294
     *
295
     */
296 7
    public function getArgs()
297
    {
298 7
        return $this->args;
299
    }
300
301
    /**
302
     *
303
     * Initializes this specification.
304
     *
305
     * @param array $args Arguments for the rule.
306
     *
307
     * @return self
308
     *
309
     */
310 23
    protected function init($args)
311
    {
312 23
        $this->args = $args;
313 23
        $this->rule = array_shift($this->args);
314 23
        return $this;
315
    }
316
317
    /**
318
     *
319
     * Returns the default failure message for this rule specification.
320
     *
321
     * @return string
322
     *
323
     */
324 12
    protected function getDefaultMessage()
325
    {
326 12
        return $this->rule . $this->argsToString();
327
    }
328
329
    /**
330
     *
331
     * Converts the args to a string.
332
     *
333
     * @return string
334
     *
335
     */
336 12
    protected function argsToString()
337
    {
338 12
        if (! $this->args) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->args of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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.

Loading history...
339 6
            return '';
340
        }
341
342 11
        $vals = array();
343 11
        foreach ($this->args as $arg) {
344 11
            $vals[] = $this->argToString($arg);
345
        }
346 11
        return '(' . implode(', ', $vals) . ')';
347
    }
348
349
    /**
350
     *
351
     * Converts one arg to a string.
352
     *
353
     * @param mixed $arg The arg.
354
     *
355
     * @return string
356
     *
357
     */
358 11
    protected function argToString($arg)
359
    {
360
        switch (true) {
361 11
            case $arg instanceof Closure:
362 1
                return '*Closure*';
363 10
            case is_object($arg):
364
                return '*' . get_class($arg) . '*';
365 10
            case is_array($arg):
366
                return '*array*';
367 10
            case is_resource($arg):
368
                return '*resource*';
369 10
            case is_null($arg):
370
                return '*null*';
371
            default:
372 10
                return $arg;
373
        }
374
    }
375
376
    /**
377
     *
378
     * Is the subject field blank?
379
     *
380
     * @param mixed $subject The filter subject.
381
     *
382
     * @return bool
383
     *
384
     */
385 19
    protected function subjectFieldIsBlank($subject)
386
    {
387
        // the field name
388 19
        $field = $this->field;
389
390
        // not set, or null, means it is blank
391 19
        if (! isset($subject->$field) || $subject->$field === null) {
392 9
            return true;
393
        }
394
395
        // non-strings are not blank: int, float, object, array, resource, etc
396 17
        if (! is_string($subject->$field)) {
397 6
            return false;
398
        }
399
400
        // strings that trim down to exactly nothing are blank
401 17
        return trim($subject->$field) === '';
402
    }
403
}
404