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

RuleFactory   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 230
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 91.53%

Importance

Changes 13
Bugs 4 Features 2
Metric Value
wmc 30
c 13
b 4
f 2
lcom 1
cbo 1
dl 0
loc 230
ccs 108
cts 118
cp 0.9153
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A registerDefaultRules() 0 58 2
A register() 0 14 4
B createRule() 0 18 6
A setMessages() 0 11 3
B getSuggestedMessageTemplate() 0 9 6
C 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 27
    function __construct()
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...
32
    {
33 27
        $this->registerDefaultRules();
34 27
    }
35
36
    /**
37
     * Set up the default rules that come with the library
38
     */
39 27
    protected function registerDefaultRules()
40
    {
41
        $rulesClasses = array(
42 27
            'Alpha',
43 27
            'AlphaNumeric',
44 27
            'AlphaNumHyphen',
45 27
            'ArrayLength',
46 27
            'ArrayMaxLength',
47 27
            'ArrayMinLength',
48 27
            'Between',
49 27
            'Callback',
50 27
            'Date',
51 27
            'DateTime',
52 27
            'Email',
53 27
            'EmailDomain',
54 27
            'Equal',
55 27
            'FullName',
56 27
            'GreaterThan',
57 27
            'InList',
58 27
            'Integer',
59 27
            'IpAddress',
60 27
            'Length',
61 27
            'LessThan',
62 27
            'Match',
63 27
            'MaxLength',
64 27
            'MinLength',
65 27
            'NotInList',
66 27
            'NotRegex',
67 27
            'Number',
68 27
            'Regex',
69 27
            'Required',
70 27
            'RequiredWhen',
71 27
            'RequiredWith',
72 27
            'RequiredWithout',
73 27
            'Time',
74 27
            'Url',
75 27
            'Website',
76 27
            'File\Extension',
77 27
            'File\Image',
78 27
            'File\ImageHeight',
79 27
            'File\ImageRatio',
80 27
            'File\ImageWidth',
81 27
            'File\Size',
82 27
            'Upload\Extension',
83 27
            'Upload\Image',
84 27
            'Upload\ImageHeight',
85 27
            'Upload\ImageRatio',
86 27
            'Upload\ImageWidth',
87 27
            'Upload\Size',
88 27
        );
89 27
        foreach ($rulesClasses as $class) {
90 27
            $fullClassName       = '\\' . __NAMESPACE__ . '\Rule\\' . $class;
91 27
            $name                = strtolower(str_replace('\\', '', $class));
92 27
            $errorMessage        = constant($fullClassName . '::MESSAGE');
93 27
            $labeledErrorMessage = constant($fullClassName . '::LABELED_MESSAGE');
94 27
            $this->register($name, $fullClassName, $errorMessage, $labeledErrorMessage);
95 27
        }
96 27
    }
97
98
99
    /**
100
     * Register a class to be used when creating validation rules
101
     *
102
     * @param string $name
103
     * @param string $class
104
     *
105
     * @return \Sirius\Validation\RuleFactory
106
     */
107 27
    public function register($name, $class, $errorMessage = '', $labeledErrorMessage = '')
108
    {
109 27
        if (is_subclass_of($class, '\Sirius\Validation\Rule\AbstractRule')) {
110 27
            $this->validatorsMap[$name] = $class;
111 27
        }
112 27
        if ($errorMessage) {
113 27
            $this->errorMessages[$name] = $errorMessage;
114 27
        }
115 27
        if ($labeledErrorMessage) {
116 27
            $this->labeledErrorMessages[$name] = $labeledErrorMessage;
117 27
        }
118
119 27
        return $this;
120
    }
121
122
    /**
123
     * Factory method to construct a validator based on options that are used most of the times
124
     *
125
     * @param string|callable $name
126
     *            name of a validator class or a callable object/function
127
     * @param string|array $options
128
     *            validator options (an array, JSON string or QUERY string)
129
     * @param string $messageTemplate
130
     *            error message template
131
     * @param string $label
132
     *            label of the form input field or model attribute
133
     *
134
     * @throws \InvalidArgumentException
135
     * @return \Sirius\Validation\Rule\AbstractValidator
136
     */
137 24
    public function createRule($name, $options = null, $messageTemplate = null, $label = null)
138
    {
139 24
        $validator = $this->construcRuleByNameAndOptions($name, $options);
140
141
        // no message template, try to get it from the registry
142 22
        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...
143 19
            $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...
144 19
        }
145
146 22
        if (is_string($messageTemplate) && $messageTemplate !== '') {
147 20
            $validator->setMessageTemplate($messageTemplate);
148 20
        }
149 22
        if (is_string($label) && $label !== '') {
150 8
            $validator->setOption('label', $label);
151 8
        }
152
153 22
        return $validator;
154
    }
155
156
    /**
157
     * Set default error message for a rule
158
     *
159
     * @param string $rule
160
     * @param string|null $messageWithoutLabel
161
     * @param string|null $messageWithLabel
162
     *
163
     * @return $this
164
     */
165
    public function setMessages($rule, $messageWithoutLabel = null, $messageWithLabel = null)
166
    {
167
        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...
168
            $this->errorMessages[$rule] = $messageWithoutLabel;
169
        }
170
        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...
171
            $this->labeledErrorMessages[$rule] = $messageWithLabel;
172
        }
173
174
        return $this;
175
    }
176
177
    /**
178
     * Get the error message saved in the registry for a rule, where the message
179
     * is with or without a the label
180
     *
181
     * @param string $name name of the rule
182
     * @param bool $withLabel
183
     *
184
     * @return string|NULL
185
     */
186 19
    protected function getSuggestedMessageTemplate($name, $withLabel)
187
    {
188 19
        $noLabelMessage = is_string($name) && isset($this->errorMessages[$name]) ? $this->errorMessages[$name] : null;
189 19
        if ($withLabel) {
190 3
            return is_string($name) && isset($this->labeledErrorMessages[$name]) ? $this->labeledErrorMessages[$name] : $noLabelMessage;
191
        }
192
193 18
        return $noLabelMessage;
194
    }
195
196
    /**
197
     * @param $name
198
     * @param $options
199
     *
200
     * @return CallbackRule
201
     */
202 24
    protected function construcRuleByNameAndOptions($name, $options)
203
    {
204 24
        if (is_callable($name)) {
205 1
            $validator = new CallbackRule(
206
                array(
207 1
                    'callback'  => $name,
208
                    'arguments' => $options
209 1
                )
210 1
            );
211 24
        } elseif (is_string($name)) {
212 23
            $name = trim($name);
213
            // use the validator map
214 23
            if (isset($this->validatorsMap[strtolower($name)])) {
215 22
                $name = $this->validatorsMap[strtolower($name)];
216 22
            }
217
            // try if the validator is the name of a class in the package
218 23
            if (class_exists('\Sirius\Validation\Rule\\' . $name, false)) {
219
                $name = '\Sirius\Validation\Rule\\' . $name;
220
            }
221
            // at this point we should have a class that can be instanciated
222 23
            if (class_exists($name) && is_subclass_of($name, '\Sirius\Validation\Rule\AbstractRule')) {
223 22
                $validator = new $name($options);
224 21
            }
225 22
        }
226
227 23
        if ( ! isset($validator)) {
228 1
            throw new \InvalidArgumentException(
229 1
                sprintf('Impossible to determine the validator based on the name: %s', (string) $name)
230 1
            );
231
        }
232
233 22
        return $validator;
234
    }
235
236
}
237