Completed
Push — master ( 872ac5...951b37 )
by Andres
03:04 queued 13s
created

AbstractValidator::map()   B

Complexity

Conditions 6
Paths 3

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 6
eloc 9
c 1
b 0
f 1
nc 3
nop 1
dl 0
loc 17
rs 8.8571
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
     * Map value to key in array and grab associated array value, or
141
     * feed value into callable and use returned value
142
     *
143
     * @param array|callable $mapper
144
     * @return $this
145
     * @throws DiscomfortException
146
     */
147
    public function map($mapper)
148
    {
149
        if (!is_callable($mapper) && !is_array($mapper)) {
150
            throw new DiscomfortException('$mapValues must be an array or callable');
151
        }
152
153
        $mapper = is_callable($mapper) ? $mapper : function($value) use ($mapper) {
154
            if (array_key_exists($value, $mapper)) {
155
                return $mapper[$value];
156
            }
157
        };
158
159
        return $this->add(function($value) use ($mapper) {
160
            $mappedVal = $mapper($value);
161
            return $mappedVal === null ? $value : $mappedVal;
162
        });
163
    }
164
165
    /**
166
     * On validation failure whether to return false or a validation error
167
     *
168
     * @param bool $val
169
     * @return $this
170
     */
171
    public function toBool($val = true)
172
    {
173
        $this->toBool = (boolean)$val;
174
175
        return $this;
176
    }
177
178
    /**
179
     * Set default value
180
     *
181
     * @param $value
182
     * @return $this
183
     */
184
    public function defaultValue($value)
185
    {
186
        $this->defaultValue = $value;
187
188
        return $this;
189
    }
190
191
    /**
192
     * Set error messages
193
     *
194
     * @param array $errorMessages
195
     * @return $this
196
     */
197
    public function errorMessages(array $errorMessages)
198
    {
199
        $errorMessages = array_map(function ($errorMessage) {
200
            if (is_string($errorMessage)) {
201
                $errorMessage = ['message' => $errorMessage];
202
            }
203
204
            return $errorMessage;
205
        }, $errorMessages);
206
207
        $this->errorHandlers = array_merge($this->errorHandlers, $errorMessages);
208
        return $this;
209
    }
210
211
    /**
212
     * Create an error with a formatted message
213
     *
214
     * @param string $key
215
     * @param null|string $value
216
     * @param null|string $valueKey
217
     * @param mixed $validationValue
218
     * @throws DiscomfortException
219
     * @throws ValidationException
220
     */
221
    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...
222
    {
223
        if (!array_key_exists($key, $this->errorHandlers)) {
224
            throw new ValidationException(
225
                $key,
226
                $this->errorHandlers['default']['message']
227
            );
228
        }
229
230
        $errorHandler = $this->errorHandlers[$key];
231
        if (!array_key_exists('message_formatter', $errorHandler)) {
232
            $messageFormatter = function ($template, $value, $validationValue = null) {
233
                return sprintf($template, $value, $validationValue);
234
            };
235
        } else {
236
            $messageFormatter = $errorHandler['message_formatter'];
237
            if (!is_callable($messageFormatter)) {
238
                throw new DiscomfortException('"message_formatter" must be callable');
239
            }
240
        }
241
242
        if (!is_null($valueKey)) {
243
            $templateValue = $valueKey;
244
        } else {
245
            if (!is_string($value)) {
246
                $valueType = gettype($value);
247
                $templateValue = "'{$valueType}'";
248
            } else {
249
                $templateValue = "'{$value}'";
250
            }
251
        }
252
253
        $errorMessage = $messageFormatter(
254
            $errorHandler['message'],
255
            $templateValue ?: $errorHandler['value']
256
        );
257
258
        throw new ValidationException($key, $errorMessage);
259
    }
260
}
261