Completed
Push — master ( e15e2a...7544f0 )
by Andres
02:10
created

AbstractValidator::invalid()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 8
Ratio 100 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 1
nop 1
dl 8
loc 8
rs 9.4285
c 0
b 0
f 0
1
<?php
2
namespace Comfort\Validator;
3
4
use Comfort\Comfort;
5
use Comfort\Error;
6
use Comfort\Exception\DiscomfortException;
7
use Comfort\Exception\ValidationException;
8
use Comfort\ValidationError;
9
use Comfort\Validator\Helper\AlternativesTrait;
10
use Comfort\Validator\Helper\ExecutorTrait;
11
12
/**
13
 * Class AbstractValidator
14
 * @package Comfort\Validator
15
 */
16
abstract class AbstractValidator
17
{
18
    use AlternativesTrait;
19
    use ExecutorTrait;
20
21
    /**
22
     * @var \Closure[]
23
     */
24
    protected $validationStack = [];
25
    /**
26
     * @var Comfort
27
     */
28
    private $comfort;
29
    /**
30
     * @var boolean
31
     */
32
    private $toBool = false;
33
    /**
34
     * @var bool
35
     */
36
    private $optional = true;
37
    /**
38
     * @var mixed
39
     */
40
    private $defaultValue;
41
    /**
42
     * @var array
43
     */
44
    protected $errorHandlers = [
45
        'default' => [
46
            'message' => 'There was a validation error'
47
        ],
48
        'required' => [
49
            'message' => '%s is required',
50
            'default' => 'value'
51
        ]
52
    ];
53
54
    public function __construct(Comfort $comfort)
55
    {
56
57
        $this->comfort = $comfort;
58
    }
59
60
    /**
61
     * Execute validation stack
62
     *
63
     * @param mixed $value
64
     * @param null|string $key
65
     * @return bool|ValidationError|null
66
     */
67
    public function __invoke($value, $key = null)
68
    {
69
        return $this->validate($value, $key);
0 ignored issues
show
Bug introduced by
It seems like $key defined by parameter $key on line 67 can also be of type string; however, Comfort\Validator\Helper\ExecutorTrait::validate() does only seem to accept null, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
70
    }
71
72
    public function __call($name, $arguments)
73
    {
74
        return call_user_func_array([$this->comfort, $name], $arguments);
75
    }
76
77
    /**
78
     * Declare the value as being required
79
     *
80
     * @return $this
81
     */
82
    public function required()
83
    {
84
        $this->optional = false;
85
86
        $this->add(function ($value, $nameKey) {
87
            if (is_null($value)) {
88
                $this->createError('required', $value, $nameKey);
89
            }
90
        });
91
92
93
        return $this;
94
    }
95
96
97
    /**
98
     * Declare data is optional
99
     *
100
     * @return $this
101
     */
102
    public function optional()
103
    {
104
        $this->optional = true;
105
106
        return $this;
107
    }
108
109
    /**
110
     * Add adhoc validator to validation stack
111
     *
112
     * @param callable $validation
113
     * @return $this
114
     */
115
    public function add(callable $validation)
116
    {
117
        $this->validationStack[] = $validation;
118
119
        return $this;
120
    }
121
122
    /**
123
     * Validate given value matches any of the provided strings
124
     *
125
     * @param array $vals
126
     * @return $this
127
     */
128 View Code Duplication
    public function anyOf(array $vals)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
129
    {
130
        $this->add(function ($value, $nameKey) use ($vals) {
131
            if (!in_array($value, $vals)) {
132
                return $this->createError('anyof', $value, $nameKey);
133
            }
134
        });
135
136
        return $this;
137
    }
138
139
    /**
140
     * Validate given value is _not_ in $vals
141
     *
142
     * @param array $vals
143
     * @return AbstractValidator
144
     */
145 View Code Duplication
    public function invalid(array $vals)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
146
    {
147
        return $this->add(function ($value, $nameKey) use ($vals) {
148
            if (in_array($value, $vals)) {
149
                return $this->createError('invalid', $value, $nameKey);
150
            }
151
        });
152
    }
153
154
    /**
155
     * Map value to key in array and grab associated array value, or
156
     * feed value into callable and use returned value
157
     *
158
     * @param array|callable $mapper
159
     * @return $this
160
     * @throws DiscomfortException
161
     */
162
    public function map($mapper)
163
    {
164
        if (!is_callable($mapper) && !is_array($mapper)) {
165
            throw new DiscomfortException('$mapValues must be an array or callable');
166
        }
167
168
        $mapper = is_callable($mapper) ? $mapper : function($value) use ($mapper) {
169
            if (array_key_exists($value, $mapper)) {
170
                return $mapper[$value];
171
            }
172
        };
173
174
        return $this->add(function($value) use ($mapper) {
175
            $mappedVal = $mapper($value);
176
            return $mappedVal === null ? $value : $mappedVal;
177
        });
178
    }
179
180
    /**
181
     * On validation failure whether to return false or a validation error
182
     *
183
     * @param bool $val
184
     * @return $this
185
     */
186
    public function toBool($val = true)
187
    {
188
        $this->toBool = (boolean)$val;
189
190
        return $this;
191
    }
192
193
    /**
194
     * Set default value
195
     *
196
     * @param $value
197
     * @return $this
198
     */
199
    public function defaultValue($value)
200
    {
201
        $this->defaultValue = $value;
202
203
        return $this;
204
    }
205
206
    /**
207
     * Set error messages
208
     *
209
     * @param array $errorMessages
210
     * @return $this
211
     */
212
    public function errorMessages(array $errorMessages)
213
    {
214
        $errorMessages = array_map(function ($errorMessage) {
215
            if (is_string($errorMessage)) {
216
                $errorMessage = ['message' => $errorMessage];
217
            }
218
219
            return $errorMessage;
220
        }, $errorMessages);
221
222
        $this->errorHandlers = array_merge($this->errorHandlers, $errorMessages);
223
        return $this;
224
    }
225
226
    /**
227
     * Create an error with a formatted message
228
     *
229
     * @param string $key
230
     * @param null|string $value
231
     * @param null|string $valueKey
232
     * @param mixed $validationValue
233
     * @throws DiscomfortException
234
     * @throws ValidationException
235
     */
236
    protected function createError($key, $value = null, $valueKey = null, $validationValue = null)
0 ignored issues
show
Unused Code introduced by
The parameter $validationValue is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
237
    {
238
        if (!array_key_exists($key, $this->errorHandlers)) {
239
            throw new ValidationException(
240
                $key,
241
                $this->errorHandlers['default']['message']
242
            );
243
        }
244
245
        $errorHandler = $this->errorHandlers[$key];
246
        if (!array_key_exists('message_formatter', $errorHandler)) {
247
            $messageFormatter = function ($template, $value, $validationValue = null) {
248
                return sprintf($template, $value, $validationValue);
249
            };
250
        } else {
251
            $messageFormatter = $errorHandler['message_formatter'];
252
            if (!is_callable($messageFormatter)) {
253
                throw new DiscomfortException('"message_formatter" must be callable');
254
            }
255
        }
256
257
        if (!is_null($valueKey)) {
258
            $templateValue = $valueKey;
259
        } else {
260
            if (!is_string($value)) {
261
                $valueType = gettype($value);
262
                $templateValue = "'{$valueType}'";
263
            } else {
264
                $templateValue = "'{$value}'";
265
            }
266
        }
267
268
        $errorMessage = $messageFormatter(
269
            $errorHandler['message'],
270
            $templateValue ?: $errorHandler['value']
271
        );
272
273
        throw new ValidationException($key, $errorMessage);
274
    }
275
}
276