Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

Completed
Push — 2.0 ( e6a123 )
by Henrique
05:00
created

Validator::setFactory()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 4
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 2
1
<?php
2
3
/*
4
 * This file is part of Respect/Validation.
5
 *
6
 * (c) Alexandre Gomes Gaigalas <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the "LICENSE.md"
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Respect\Validation;
13
14
use finfo;
15
use ReflectionClass;
16
use Respect\Validation\Exceptions\AllOfException;
17
use Respect\Validation\Exceptions\ComponentException;
18
use Respect\Validation\Exceptions\ValidationException;
19
use Respect\Validation\Rules\AllOf;
20
use Respect\Validation\Rules\Key;
21
22
/**
23
 * @method static Validator age(int $minAge = null, int $maxAge = null)
24
 * @method static Validator allOf()
25
 * @method static Validator alnum(string $additionalChars = null)
26
 * @method static Validator alpha(string $additionalChars = null)
27
 * @method static Validator alwaysInvalid()
28
 * @method static Validator alwaysValid()
29
 * @method static Validator arrayVal()
30
 * @method static Validator arrayType()
31
 * @method static Validator attribute(string $attributeName, Rule $rule = null, bool $mandatory = true)
32
 * @method static Validator bank(string $countryCode)
33
 * @method static Validator bankAccount(string $countryCode)
34
 * @method static Validator base()
35
 * @method static Validator between(mixed $min = null, mixed $max = null, bool $inclusive = true)
36
 * @method static Validator bic(string $countryCode)
37
 * @method static Validator boolType()
38
 * @method static Validator boolVal()
39
 * @method static Validator bsn()
40
 * @method static Validator call(callable $callable, Rule $rule)
41
 * @method static Validator callableType()
42
 * @method static Validator callback(mixed $callback)
43
 * @method static Validator charset(mixed $charset)
44
 * @method static Validator cnh()
45
 * @method static Validator cnpj()
46
 * @method static Validator consonant(string $additionalChars = null)
47
 * @method static Validator contains(mixed $containsValue, bool $identical = false)
48
 * @method static Validator countable()
49
 * @method static Validator countryCode()
50
 * @method static Validator currencyCode()
51
 * @method static Validator cpf()
52
 * @method static Validator creditCard(string $brand = null)
53
 * @method static Validator date(string $format = null)
54
 * @method static Validator digit(string $additionalChars = null)
55
 * @method static Validator directory()
56
 * @method static Validator domain(bool $tldCheck = true)
57
 * @method static Validator each(Validatable $itemValidator = null, Validatable $keyValidator = null)
58
 * @method static Validator email()
59
 * @method static Validator endsWith(mixed $endValue, bool $identical = false)
60
 * @method static Validator equals(mixed $compareTo)
61
 * @method static Validator even()
62
 * @method static Validator executable()
63
 * @method static Validator exists()
64
 * @method static Validator extension(string $extension)
65
 * @method static Validator factor(int $dividend)
66
 * @method static Validator falseVal()
67
 * @method static Validator fibonacci()
68
 * @method static Validator file()
69
 * @method static Validator filterVar(int $filter, mixed $options = null)
70
 * @method static Validator finite()
71
 * @method static Validator floatVal()
72
 * @method static Validator floatType()
73
 * @method static Validator graph(string $additionalChars = null)
74
 * @method static Validator hexRgbColor()
75
 * @method static Validator identical(mixed $value)
76
 * @method static Validator identityCard(string $countryCode)
77
 * @method static Validator image(finfo $fileInfo = null)
78
 * @method static Validator imei()
79
 * @method static Validator in(mixed $haystack, bool $compareIdentical = false)
80
 * @method static Validator infinite()
81
 * @method static Validator instance(string $instanceName)
82
 * @method static Validator intVal()
83
 * @method static Validator intType()
84
 * @method static Validator ip(mixed $ipOptions = null)
85
 * @method static Validator iterableType()
86
 * @method static Validator json()
87
 * @method static Validator key(mixed $key, Rule $rule = null, bool $mandatory = true)
88
 * @method static Validator keyNested(string $reference, Validatable $referenceValidator = null, bool $mandatory = true)
89
 * @method static Validator keySet(Key $rule...)
90
 * @method static Validator keyValue(string $comparedKey, string $ruleName, string $baseKey)
91
 * @method static Validator languageCode(string $set)
92
 * @method static Validator leapDate(string $format)
93
 * @method static Validator leapYear()
94
 * @method static Validator length(int $min = null, int $max = null, bool $inclusive = true)
95
 * @method static Validator lowercase()
96
 * @method static Validator macAddress()
97
 * @method static Validator max(mixed $maxValue, bool $inclusive = true)
98
 * @method static Validator mimetype(string $mimetype)
99
 * @method static Validator min(mixed $minValue, bool $inclusive = true)
100
 * @method static Validator minimumAge(int $age)
101
 * @method static Validator multiple(int $multipleOf)
102
 * @method static Validator negative()
103
 * @method static Validator nif()
104
 * @method static Validator no($useLocale = false)
105
 * @method static Validator noneOf()
106
 * @method static Validator not(Validatable $rule)
107
 * @method static Validator notBlank()
108
 * @method static Validator notEmpty()
109
 * @method static Validator notOptional()
110
 * @method static Validator noWhitespace()
111
 * @method static Validator nullType()
112
 * @method static Validator numericVal()
113
 * @method static Validator objectType()
114
 * @method static Validator odd()
115
 * @method static Validator oneOf()
116
 * @method static Validator optional(Validatable $rule)
117
 * @method static Validator perfectSquare()
118
 * @method static Validator pesel()
119
 * @method static Validator phone()
120
 * @method static Validator phpLabel()
121
 * @method static Validator positive()
122
 * @method static Validator postalCode(string $countryCode)
123
 * @method static Validator primeNumber()
124
 * @method static Validator prnt(string $additionalChars = null)
125
 * @method static Validator punct(string $additionalChars = null)
126
 * @method static Validator readable()
127
 * @method static Validator regex(string $regex)
128
 * @method static Validator resourceType()
129
 * @method static Validator roman()
130
 * @method static Validator scalarVal()
131
 * @method static Validator sf(string $name, array $params = null)
132
 * @method static Validator size(string $minSize = null, string $maxSize = null)
133
 * @method static Validator slug()
134
 * @method static Validator space(string $additionalChars = null)
135
 * @method static Validator startsWith(mixed $startValue, bool $identical = false)
136
 * @method static Validator stringType()
137
 * @method static Validator subdivisionCode(string $countryCode)
138
 * @method static Validator symbolicLink()
139
 * @method static Validator tld()
140
 * @method static Validator trueVal()
141
 * @method static Validator type(string $type)
142
 * @method static Validator uploaded()
143
 * @method static Validator uppercase()
144
 * @method static Validator url()
145
 * @method static Validator vatin(string $countryCode)
146
 * @method static Validator version()
147
 * @method static Validator videoUrl(string $service = null)
148
 * @method static Validator vowel()
149
 * @method static Validator when(Validatable $if, Validatable $then, Validatable $when = null)
150
 * @method static Validator writable()
151
 * @method static Validator xdigit(string $additionalChars = null)
152
 * @method static Validator yes($useLocale = false)
153
 * @method static Validator zend(mixed $validator, array $params = null)
154
 */
155
class Validator extends AllOf
156
{
157
    protected static $factory;
158
159
    /**
160
     * @return Factory
161
     */
162
    protected static function getFactory()
163
    {
164
        if (!static::$factory instanceof Factory) {
165
            static::$factory = new Factory();
166
        }
167
168
        return static::$factory;
169
    }
170
171
    /**
172
     * @param Factory $factory
173
     */
174
    public static function setFactory($factory)
175
    {
176
        static::$factory = $factory;
177
    }
178
179
    /**
180
     * @param string $rulePrefix
181
     * @param bool   $prepend
182
     */
183
    public static function with($rulePrefix, $prepend = false)
184
    {
185
        if (false === $prepend) {
186
            self::getFactory()->appendRulePrefix($rulePrefix);
187
        } else {
188
            self::getFactory()->prependRulePrefix($rulePrefix);
189
        }
190
    }
191
192
    public function check($input)
193
    {
194
        try {
195
            return parent::check($input);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Respect\Validation\Rules\AllOf as the method check() does only exist in the following sub-classes of Respect\Validation\Rules\AllOf: Respect\Validation\Validator. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
196
        } catch (ValidationException $exception) {
197
            if (count($this->getRules()) == 1 && $this->template) {
0 ignored issues
show
Documentation Bug introduced by
The method getRules does not exist on object<Respect\Validation\Validator>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
198
                $exception->setTemplate($this->template);
0 ignored issues
show
Bug introduced by
The property template does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
199
            }
200
201
            throw $exception;
202
        }
203
    }
204
205
    /**
206
     * @param string $ruleName
207
     * @param array  $arguments
208
     *
209
     * @return Validator
210
     */
211
    public static function __callStatic($ruleName, $arguments)
212
    {
213
        if ('allOf' === $ruleName) {
214
            return static::buildRule($ruleName, $arguments);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return static::buildRule($ruleName, $arguments); (Respect\Validation\Validatable) is incompatible with the return type documented by Respect\Validation\Validator::__callStatic of type Respect\Validation\Validator.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
215
        }
216
217
        $validator = new static();
218
219
        return $validator->__call($ruleName, $arguments);
220
    }
221
222
    /**
223
     * @param mixed $ruleSpec
224
     * @param array $arguments
225
     *
226
     * @return Validatable
227
     */
228
    public static function buildRule($ruleSpec, $arguments = [])
229
    {
230
        try {
231
            return static::getFactory()->rule($ruleSpec, $arguments);
232
        } catch (\Exception $exception) {
233
            throw new ComponentException($exception->getMessage(), $exception->getCode(), $exception);
234
        }
235
    }
236
237
    /**
238
     * @param string $method
239
     * @param array  $arguments
240
     *
241
     * @return self
242
     */
243
    public function __call($method, $arguments)
244
    {
245
        return $this->addRule(static::buildRule($method, $arguments));
0 ignored issues
show
Documentation Bug introduced by
The method addRule does not exist on object<Respect\Validation\Validator>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
246
    }
247
248
    protected function createException()
249
    {
250
        return new AllOfException();
251
    }
252
253
    /**
254
     * Create instance validator.
255
     *
256
     * @return Validator
257
     */
258
    public static function create()
259
    {
260
        $ref = new ReflectionClass(__CLASS__);
261
262
        return $ref->newInstanceArgs(func_get_args());
263
    }
264
}
265