Completed
Pull Request — master (#61)
by
unknown
01:35
created

RuleFactory   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 234
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 91.87%

Importance

Changes 0
Metric Value
dl 0
loc 234
ccs 113
cts 123
cp 0.9187
c 0
b 0
f 0
wmc 30
lcom 1
cbo 1
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
B registerDefaultRules() 0 61 2
A register() 0 14 4
A createRule() 0 18 6
A setMessages() 0 11 3
A getSuggestedMessageTemplate() 0 11 6
B construcRuleByNameAndOptions() 0 33 8
1
<?php
2
3
namespace Sirius\Validation;
4
5
use Sirius\Validation\Rule\Callback as CallbackRule;
6
7
class RuleFactory
8
{
9
    /**
10
     * Validator map allows for flexibility when creating a validation rule
11
     * You can use 'required' instead of 'required' for the name of the rule
12
     * or 'minLength'/'minlength' instead of 'MinLength'
13
     *
14
     * @var array
15
     */
16
    protected $validatorsMap = array();
17
18
    /**
19
     * @var array
20
     */
21
    protected $errorMessages = array();
22
23
    /**
24
     * @var array
25
     */
26
    protected $labeledErrorMessages = array();
27
28
    /**
29
     * Constructor
30
     */
31 29
    public function __construct()
32
    {
33 29
        $this->registerDefaultRules();
34 29
    }
35
36
    /**
37
     * Set up the default rules that come with the library
38
     */
39 29
    protected function registerDefaultRules()
40
    {
41
        $rulesClasses = array(
42 29
            'Alpha',
43 29
            'AlphaNumeric',
44 29
            'AlphaNumHyphen',
45 29
            'ArrayLength',
46 29
            'ArrayMaxLength',
47 29
            'ArrayMinLength',
48 29
            'Between',
49 29
            'Callback',
50 29
            'Date',
51 29
            'DateTime',
52 29
            'Email',
53 29
            'EmailDomain',
54 29
            'Equal',
55 29
            'FullName',
56 29
            'GreaterThan',
57 29
            'InList',
58 29
            'Integer',
59 29
            'IpAddress',
60 29
            'Length',
61 29
            'LessThan',
62 29
            'Match',
63 29
            'MaxLength',
64 29
            'MinLength',
65 29
            'NotEqual',
66 29
            'NotInList',
67 29
            'NotMatch',
68 29
            'NotRegex',
69 29
            'Number',
70 29
            'Regex',
71 29
            'Required',
72 29
            'RequiredWhen',
73 29
            'RequiredWith',
74 29
            'RequiredWithout',
75 29
            'Time',
76 29
            'Url',
77 29
            'Website',
78 29
            'File\Extension',
79 29
            'File\Image',
80 29
            'File\ImageHeight',
81 29
            'File\ImageRatio',
82 29
            'File\ImageWidth',
83 29
            'File\Size',
84 29
            'Upload\Required',
85 29
            'Upload\Extension',
86 29
            'Upload\Image',
87 29
            'Upload\ImageHeight',
88 29
            'Upload\ImageRatio',
89 29
            'Upload\ImageWidth',
90 29
            'Upload\Size',
91 29
        );
92 29
        foreach ($rulesClasses as $class) {
93 29
            $fullClassName       = '\\' . __NAMESPACE__ . '\Rule\\' . $class;
94 29
            $name                = strtolower(str_replace('\\', '', $class));
95 29
            $errorMessage        = constant($fullClassName . '::MESSAGE');
96 29
            $labeledErrorMessage = constant($fullClassName . '::LABELED_MESSAGE');
97 29
            $this->register($name, $fullClassName, $errorMessage, $labeledErrorMessage);
98 29
        }
99 29
    }
100
101
102
    /**
103
     * Register a class to be used when creating validation rules
104
     *
105
     * @param string $name
106
     * @param string $class
107
     *
108
     * @return \Sirius\Validation\RuleFactory
109
     */
110 29
    public function register($name, $class, $errorMessage = '', $labeledErrorMessage = '')
111
    {
112 29
        if (is_subclass_of($class, '\Sirius\Validation\Rule\AbstractRule')) {
113 29
            $this->validatorsMap[$name] = $class;
114 29
        }
115 29
        if ($errorMessage) {
116 29
            $this->errorMessages[$name] = $errorMessage;
117 29
        }
118 29
        if ($labeledErrorMessage) {
119 29
            $this->labeledErrorMessages[$name] = $labeledErrorMessage;
120 29
        }
121
122 29
        return $this;
123
    }
124
125
    /**
126
     * Factory method to construct a validator based on options that are used most of the times
127
     *
128
     * @param string|callable $name
129
     *            name of a validator class or a callable object/function
130
     * @param string|array $options
131
     *            validator options (an array, JSON string or QUERY string)
132
     * @param string $messageTemplate
133
     *            error message template
134
     * @param string $label
135
     *            label of the form input field or model attribute
136
     *
137
     * @throws \InvalidArgumentException
138
     * @return \Sirius\Validation\Rule\AbstractValidator
139
     */
140 26
    public function createRule($name, $options = null, $messageTemplate = null, $label = null)
141
    {
142 26
        $validator = $this->construcRuleByNameAndOptions($name, $options);
143
144
        // no message template, try to get it from the registry
145 24
        if (!$messageTemplate) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $messageTemplate 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...
146 21
            $messageTemplate = $this->getSuggestedMessageTemplate($name, !!$label);
0 ignored issues
show
Documentation introduced by
$name is of type callable, but the function expects a string.

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...
147 21
        }
148
149 24
        if (is_string($messageTemplate) && $messageTemplate !== '') {
150 21
            $validator->setMessageTemplate($messageTemplate);
151 21
        }
152 24
        if (is_string($label) && $label !== '') {
153 8
            $validator->setOption('label', $label);
154 8
        }
155
156 24
        return $validator;
157
    }
158
159
    /**
160
     * Set default error message for a rule
161
     *
162
     * @param string $rule
163
     * @param string|null $messageWithoutLabel
164
     * @param string|null $messageWithLabel
165
     *
166
     * @return $this
167
     */
168
    public function setMessages($rule, $messageWithoutLabel = null, $messageWithLabel = null)
169
    {
170
        if ($messageWithoutLabel) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $messageWithoutLabel of type string|null is loosely compared to true; 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...
171
            $this->errorMessages[$rule] = $messageWithoutLabel;
172
        }
173
        if ($messageWithLabel) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $messageWithLabel of type string|null is loosely compared to true; 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...
174
            $this->labeledErrorMessages[$rule] = $messageWithLabel;
175
        }
176
177
        return $this;
178
    }
179
180
    /**
181
     * Get the error message saved in the registry for a rule, where the message
182
     * is with or without a the label
183
     *
184
     * @param string $name name of the rule
185
     * @param bool $withLabel
186
     *
187
     * @return string|NULL
188
     */
189 21
    protected function getSuggestedMessageTemplate($name, $withLabel)
190
    {
191 21
        $noLabelMessage = is_string($name) && isset($this->errorMessages[$name]) ? $this->errorMessages[$name] : null;
192 21
        if ($withLabel) {
193 3
            return is_string($name) && isset($this->labeledErrorMessages[$name]) ?
194 3
                $this->labeledErrorMessages[$name] :
195 3
                $noLabelMessage;
196
        }
197
198 20
        return $noLabelMessage;
199
    }
200
201
    /**
202
     * @param $name
203
     * @param $options
204
     *
205
     * @return CallbackRule
206
     */
207 26
    protected function construcRuleByNameAndOptions($name, $options)
208
    {
209 26
        if (is_callable($name)) {
210 1
            $validator = new CallbackRule(
211
                array(
212 1
                    'callback'  => $name,
213
                    'arguments' => $options
214 1
                )
215 1
            );
216 26
        } elseif (is_string($name)) {
217 25
            $name = trim($name);
218
            // use the validator map
219 25
            if (isset($this->validatorsMap[strtolower($name)])) {
220 24
                $name = $this->validatorsMap[strtolower($name)];
221 24
            }
222
            // try if the validator is the name of a class in the package
223 25
            if (class_exists('\Sirius\Validation\Rule\\' . $name, false)) {
224
                $name = '\Sirius\Validation\Rule\\' . $name;
225
            }
226
            // at this point we should have a class that can be instanciated
227 25
            if (class_exists($name) && is_subclass_of($name, '\Sirius\Validation\Rule\AbstractRule')) {
228 24
                $validator = new $name($options);
229 23
            }
230 24
        }
231
232 25
        if (!isset($validator)) {
233 1
            throw new \InvalidArgumentException(
234 1
                sprintf('Impossible to determine the validator based on the name: %s', (string) $name)
235 1
            );
236
        }
237
238 24
        return $validator;
239
    }
240
}
241