AbstractSpec::subjectFieldIsBlank()   A
last analyzed

Complexity

Conditions 6
Paths 7

Size

Total Lines 20
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 8
nc 7
nop 1
dl 0
loc 20
ccs 9
cts 9
cp 1
crap 6
rs 9.2222
c 0
b 0
f 0
1
<?php
2
3
namespace Mbright\Validation\Spec;
4
5
use Mbright\Validation\Exception\RuleClassNotDefinedException;
6
use Mbright\Validation\Rule\Sanitize\SanitizeRuleInterface;
7
use Mbright\Validation\Rule\Validate\ValidateRuleInterface;
8
9
abstract class AbstractSpec
10
{
11
    /**
12
     * Failure Mode for a halting failure.
13
     *
14
     * @var string
15
     */
16
    const HALTING_FAILURE = 'HALTING_FAILURE';
17
18
    /**
19
     * Failure Mode for a hard failure.
20
     *
21
     * @var string
22
     */
23
    const HARD_FAILURE = 'HARD_FAILURE';
24
25
    /**
26
     * Failure Mode for a soft failure.
27
     *
28
     * @var string
29
     */
30
    const SOFT_FAILURE = 'SOFT_FAILURE';
31
32
    /**
33
     * Field name for the spec to operate on.
34
     *
35
     * @var string
36
     */
37
    protected $field;
38
39
    /**
40
     * Rule to invoke.
41
     *
42
     * @var callable
43
     */
44
    protected $rule;
45
46
    /**
47
     * Arguments supplied to the rule
48
     *
49
     * @var array
50
     */
51
    protected $args = [];
52
53
    /**
54
     * Failure message to be used instead of the default message.
55
     *
56
     * @var string
57
     */
58
    protected $message;
59
60
    /**
61
     * Name of the rule to execute.
62
     *
63
     * @var string
64
     */
65
    protected $ruleClass;
66
67
    /**
68
     * Flag that determines the allowance of blank values.
69
     *
70
     * @var bool
71
     */
72
    protected $allowBlanks = false;
73
74
    /**
75
     * An array of values to be considered blank.
76
     *
77
     * @var array
78
     */
79
    protected $blankWhiteList = [];
80
81
    /**
82
     * AbstractSpec constructor.
83
     *
84
     * @param string $field
85
     */
86 117
    public function __construct(string $field)
87
    {
88 117
        $this->field = $field;
89 117
    }
90
91
    /**
92
     * Invokes the rule that this spec is configured for.
93
     *
94
     * @param object $subject
95
     *
96
     * @return bool
97
     */
98 33
    public function __invoke($subject): bool
99
    {
100 33
        return ($this->rule)($subject, $this->field, ...array_values($this->args));
101
    }
102
103
    /**
104
     * Set a custom message.
105
     *
106
     * @param string $message
107
     *
108
     * @return self
109
     */
110 3
    public function setMessage(string $message): self
111
    {
112 3
        $this->message = $message;
113
114 3
        return $this;
115
    }
116
117
    /**
118
     * Returns the field this spec applies to.
119
     *
120
     * @return string
121
     */
122 54
    public function getField(): string
123
    {
124 54
        return $this->field;
125
    }
126
127
    /**
128
     * Returns the failure message for this rule specification.
129
     *
130
     * @return string
131
     */
132 27
    public function getMessage(): string
133
    {
134 27
        if (!$this->message) {
135 24
            $this->message = $this->getDefaultMessage();
136
        }
137
138 27
        return $this->message;
139
    }
140
141
    /**
142
     * Returns the args this spec is configured to use.
143
     *
144
     * @return array
145
     */
146 24
    public function getArgs(): array
147
    {
148 24
        return $this->args;
149
    }
150
151
    /**
152
     * Returns the name of the rule that was ran.
153
     *
154
     * @return string
155
     */
156 24
    public function getRuleClass(): string
157
    {
158 24
        return $this->ruleClass;
159
    }
160
161
    /**
162
     * Sets the white list of values that should be considered blank.
163
     *
164
     * @param array $blankWhiteList
165
     *
166
     * @return ValidateSpec
167
     */
168 12
    public function setBlankValues(array $blankWhiteList): self
169
    {
170 12
        $this->blankWhiteList = $blankWhiteList;
171
172 12
        return $this;
173
    }
174
175
    /**
176
     * Sets the rule to halt the entire validation process on the subject.
177
     *
178
     * @return AbstractSpec
179
     */
180 3
    public function asHaltingRule(): self
181
    {
182 3
        $this->failureMode = self::HALTING_FAILURE;
0 ignored issues
show
Bug Best Practice introduced by
The property failureMode does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
183
184 3
        return $this;
185
    }
186
187
    /**
188
     * Sets the rule to stop further rules from applying to the same field.
189
     *
190
     * @return AbstractSpec
191
     */
192 3
    public function asHardRule(): self
193
    {
194 3
        $this->failureMode = self::HARD_FAILURE;
0 ignored issues
show
Bug Best Practice introduced by
The property failureMode does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
195
196 3
        return $this;
197
    }
198
199
    /**
200
     * Sets the rule to allow other rules to operate on the same field.
201
     *
202
     * @return AbstractSpec
203
     */
204 3
    public function asSoftRule(): self
205
    {
206 3
        $this->failureMode = self::SOFT_FAILURE;
0 ignored issues
show
Bug Best Practice introduced by
The property failureMode does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
207
208 3
        return $this;
209
    }
210
211
    /**
212
     * Returns the current failure mode.
213
     *
214
     * @return string
215
     */
216 24
    public function getFailureMode(): string
217
    {
218 24
        return $this->failureMode;
219
    }
220
221
    /**
222
     * Determines if the field is a `valid` blank value.
223
     *
224
     * Values are considered blank if they are, not sent, null, or strings that trim down to nothing. integers, floats,
225
     * arrays, resources, objects, etc., are never considered blank. Even a value of `(int) 0` will *not* evaluate as
226
     * blank.
227
     * The optional second argument is used to supply an array of white listed items that should be considered blank.
228
     *
229
     * @param mixed $subject
230
     * @param array $blankWhiteList
231
     *
232
     * @return bool
233
     */
234 81
    public function subjectFieldIsBlank($subject): bool
235
    {
236 81
        foreach ($this->blankWhiteList as $item) {
237 9
            if ($subject->{$this->field} === $item) {
238 9
                return true;
239
            }
240
        }
241
242
        // not set, or null, means it is blank
243 72
        if (!isset($subject->{$this->field}) || $subject->{$this->field} === null) {
244 33
            return true;
245
        }
246
247
        // non-strings are not blank: int, float, object, array, resource, etc
248 39
        if (!is_string($subject->{$this->field})) {
249 18
            return false;
250
        }
251
252
        // strings that trim down to exactly nothing are blank
253 21
        return trim($subject->{$this->field}) === '';
254
    }
255
256
    /**
257
     * Returns the default failure message for this rule specification.
258
     *
259
     * @return string
260
     */
261 24
    protected function getDefaultMessage(): string
262
    {
263 24
        return $this->ruleClass . $this->argsTostring();
264
    }
265
266
    /**
267
     * Converts the args to a string.
268
     *
269
     * @return string
270
     */
271 24
    protected function argsTostring(): string
272
    {
273 24
        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...
274 21
            return '()';
275
        }
276
277 3
        return '(' . implode(', ', $this->args) . ')';
278
    }
279
}
280