Completed
Push — master ( aeb11c...f98da5 )
by Adrian
02:32
created

ValueValidator::getMessages()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
3
namespace Sirius\Validation;
4
5
use Sirius\Validation\Rule\AbstractRule;
6
7
class ValueValidator
8
{
9
10
    /**
11
     * The error messages generated after validation or set manually
12
     *
13
     * @var array
14
     */
15
    protected $messages = array();
16
17
    /**
18
     * Will be used to construct the rules
19
     *
20
     * @var \Sirius\Validation\RuleFactory
21
     */
22
    protected $ruleFactory;
23
24
    /**
25
     * The prototype that will be used to generate the error message
26
     *
27
     * @var \Sirius\Validation\ErrorMessage
28
     */
29
    protected $errorMessagePrototype;
30
31
    /**
32
     * The rule collections for the validation
33
     *
34
     * @var \Sirius\Validation\RuleCollection
35
     */
36
    protected $rules;
37
38
    /**
39
     * The label of the value to be validated
40
     *
41
     * @var string
42
     */
43
    protected $label;
44
45
46 22
    function __construct(RuleFactory $ruleFactory = null, ErrorMessage $errorMessagePrototype = null, $label = null)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
47
    {
48 22
        if ( ! $ruleFactory) {
49 6
            $ruleFactory = new RuleFactory();
50 6
        }
51 22
        $this->ruleFactory = $ruleFactory;
52 22
        if ( ! $errorMessagePrototype) {
53 6
            $errorMessagePrototype = new ErrorMessage();
54 6
        }
55 22
        $this->errorMessagePrototype = $errorMessagePrototype;
56 22
        if ($label) {
57 2
            $this->label = $label;
58 2
        }
59 22
        $this->rules = new RuleCollection;
60 22
    }
61
62 1
    public function setLabel($label = null)
63
    {
64 1
        $this->label = $label;
65
66 1
        return $this;
67
    }
68
69
    /**
70
     * Add 1 or more validation rules
71
     *
72
     * @example // add multiple rules at once
73
     *          $validator->add(array(
74
     *          'required',
75
     *          array('required', array('email', null, '{label} must be an email', 'Field B')),
76
     *          ));
77
     *          // add multiple rules using a string
78
     *          $validator->add('required | email');
79
     *          // add validator with options
80
     *          $validator->add('minlength', array('min' => 2), '{label} should have at least {min} characters', 'Field label');
81
     *          // add validator with string and parameters as JSON string
82
     *          $validator->add('minlength({"min": 2})({label} should have at least {min} characters)(Field label)');
83
     *          // add validator with string and parameters as query string
84
     *          $validator->add('minlength(min=2)({label} should have at least {min} characters)(Field label)');
85
     *
86
     * @param string|callback $name
87
     * @param string|array $options
88
     * @param string $messageTemplate
89
     * @param string $label
90
     *
91
     * @return ValueValidator
92
     */
93 22
    public function add($name, $options = null, $messageTemplate = null, $label = null)
94
    {
95 22
        if (is_array($name) && ! is_callable($name)) {
96
            return $this->addMultiple($name);
97
        }
98 22
        if (is_string($name)) {
99
            // rule was supplied like 'required | email'
100 22
            if (strpos($name, ' | ') !== false) {
101 4
                return $this->addMultiple(explode(' | ', $name));
102
            }
103
            // rule was supplied like this 'length(2,10)(error message template)(label)'
104 22
            if (strpos($name, '(') !== false) {
105 5
                list ($name, $options, $messageTemplate, $label) = $this->parseRule($name);
106 5
            }
107 22
        }
108
109
        // check for the default label
110 22
        if ( ! $label && $this->label) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $label of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
111 2
            $label = $this->label;
112 2
        }
113
114 22
        $validator = $this->ruleFactory->createRule($name, $options, $messageTemplate, $label);
115
116 20
        return $this->addRule($validator);
117
    }
118
119
    /**
120
     * @param array $rules
121
     *
122
     * @return ValueValidator
123
     */
124 4
    public function addMultiple($rules)
125
    {
126 4
        foreach ($rules as $singleRule) {
127
            // make sure the rule is an array (the parameters of subsequent calls);
128 4
            $singleRule = is_array($singleRule) ? $singleRule : array(
129
                $singleRule
130 4
            );
131 4
            call_user_func_array(
132
                array(
133 4
                    $this,
134
                    'add'
135 4
                ),
136
                $singleRule
137 4
            );
138 4
        }
139
140 4
        return $this;
141
    }
142
143
    /**
144
     * @param AbstractValidator $validationRule
145
     *
146
     * @return ValueValidator
147
     */
148 20
    public function addRule(AbstractRule $validationRule)
149
    {
150 20
        $validationRule->setErrorMessagePrototype($this->errorMessagePrototype);
151 20
        $this->rules->attach($validationRule);
152
153 20
        return $this;
154
    }
155
156
    /**
157
     * Remove validation rule
158
     *
159
     * @param mixed $name
160
     *            rule name or true if all rules should be deleted for that selector
161
     * @param mixed $options
162
     *            rule options, necessary for rules that depend on params for their ID
163
     *
164
     * @throws \InvalidArgumentException
165
     * @internal param string $selector data selector
166
     * @return self
167
     */
168 4
    public function remove($name = true, $options = null)
169
    {
170 4
        if ($name === true) {
171 2
            $this->rules = new RuleCollection();
172
173 2
            return $this;
174
        }
175 2
        $validator = $this->ruleFactory->createRule($name, $options);
0 ignored issues
show
Documentation introduced by
$name is of type *, but the function expects a callable.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
176 2
        $this->rules->detach($validator);
177
178 2
        return $this;
179
    }
180
181
    /**
182
     * Converts a rule that was supplied as string into a set of options that define the rule
183
     *
184
     * @example 'minLength({"min":2})({label} must have at least {min} characters)(Street)'
185
     *
186
     *          will be converted into
187
     *
188
     *          array(
189
     *          'minLength', // validator name
190
     *          array('min' => 2'), // validator options
191
     *          '{label} must have at least {min} characters',
192
     *          'Street' // label
193
     *          )
194
     *
195
     * @param string $ruleAsString
196
     *
197
     * @return array
198
     */
199 5
    protected function parseRule($ruleAsString)
200
    {
201 5
        $ruleAsString    = trim($ruleAsString);
202 5
        $options         = array();
203 5
        $messageTemplate = null;
204 5
        $label           = null;
205
206 5
        $name         = substr($ruleAsString, 0, strpos($ruleAsString, '('));
207 5
        $ruleAsString = substr($ruleAsString, strpos($ruleAsString, '('));
208 5
        $matches      = array();
209 5
        preg_match_all('/\(([^\)]*)\)/', $ruleAsString, $matches);
210
211 5
        if (isset($matches[1])) {
212 5
            if (isset($matches[1][0]) && $matches[1][0]) {
213 5
                $options = $matches[1][0];
214 5
            }
215 5
            if (isset($matches[1][1]) && $matches[1][1]) {
216 2
                $messageTemplate = $matches[1][1];
217 2
            }
218 5
            if (isset($matches[1][2]) && $matches[1][2]) {
219 2
                $label = $matches[1][2];
220 2
            }
221 5
        }
222
223
        return array(
224 5
            $name,
225 5
            $options,
226 5
            $messageTemplate,
227
            $label
228 5
        );
229
    }
230
231
232 20
    public function validate($value, $valueIdentifier = null, DataWrapper\WrapperInterface $context = null)
233
    {
234 20
        $this->messages = array();
235 20
        $isRequired     = false;
236 20
        foreach ($this->rules as $rule) {
237 20
            if ($rule instanceof Rule\Required) {
238 14
                $isRequired = true;
239 14
                break;
240
            }
241 20
        }
242
243 20
        if ( ! $isRequired && $value === null) {
244 5
            return true;
245
        }
246
247
        /* @var $rule \Sirius\Validation\Rule\AbstractValidator */
248 19
        foreach ($this->rules as $rule) {
249 19
            $rule->setContext($context);
250 19
            if ( ! $rule->validate($value, $valueIdentifier)) {
251 19
                $this->addMessage($rule->getMessage());
252 19
            }
253
            // if field is required and we have an error,
254
            // do not continue with the rest of rules
255 19
            if ($isRequired && count($this->messages)) {
256 13
                break;
257
            }
258 19
        }
259
260 19
        return count($this->messages) === 0;
261
    }
262
263 18
    public function getMessages()
264
    {
265 18
        return $this->messages;
266
    }
267
268 19
    public function addMessage($message)
269
    {
270 19
        array_push($this->messages, $message);
271
272 19
        return $this;
273
    }
274
275 1
    public function getRules()
276
    {
277 1
        return $this->rules;
278
    }
279
280
}
281