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
Pull Request — master (#899)
by Henrique
03:03
created

Factory::getReflection()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 6
nc 3
nop 2
dl 0
loc 12
ccs 7
cts 7
cp 1
crap 3
rs 9.4285
c 0
b 0
f 0
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
declare(strict_types=1);
13
14
namespace Respect\Validation;
15
16
use function array_map;
17
use function array_merge;
18
use function array_unique;
19
use function array_unshift;
20
use function class_exists;
21
use function in_array;
22
use function lcfirst;
23
use function Respect\Stringifier\stringify;
0 ignored issues
show
introduced by
The function Respect\Stringifier\stringify was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
24
use ReflectionClass;
25
use ReflectionObject;
26
use Respect\Validation\Exceptions\ComponentException;
27
use Respect\Validation\Exceptions\InvalidClassException;
28
use Respect\Validation\Exceptions\ValidationException;
29
use function sprintf;
30
use function trim;
31
32
/**
33
 * Factory of objects.
34
 *
35
 * @author Henrique Moody <[email protected]>
36
 *
37
 * @since 0.8.0
38
 */
39
final class Factory
40
{
41
    public const DEFAULT_RULES_NAMESPACES = [
42
        'Respect\\Validation\\Rules',
43
        'Respect\\Validation\\Rules\\Locale',
44
        'Respect\\Validation\\Rules\\SubdivisionCode',
45
    ];
46
47
    public const DEFAULT_EXCEPTIONS_NAMESPACES = [
48
        'Respect\\Validation\\Exceptions',
49
        'Respect\\Validation\\Exceptions\\Locale',
50
        'Respect\\Validation\\Exceptions\\SubdivisionCode',
51
    ];
52
53
    /**
54
     * Default instance of the Factory.
55
     *
56
     * @var Factory
57
     */
58
    private static $defaultInstance;
59
60
    /**
61
     * @var string[]
62
     */
63
    private $rulesNamespaces = [];
64
65
    /**
66
     * @var string[]
67
     */
68
    private $exceptionsNamespaces = [];
69
70
    /**
71
     * Initializes the factory with the defined namespaces.
72
     *
73
     * If the default namespace is not in the array, it will be add to the end
74
     * of the array.
75
     *
76
     * @param string[] $rulesNamespaces
77
     * @param string[] $exceptionsNamespaces
78
     */
79 302
    public function __construct(array $rulesNamespaces, array $exceptionsNamespaces)
80
    {
81 302
        $this->rulesNamespaces = $this->filterNamespaces($rulesNamespaces, self::DEFAULT_RULES_NAMESPACES);
82 302
        $this->exceptionsNamespaces = $this->filterNamespaces($exceptionsNamespaces, self::DEFAULT_EXCEPTIONS_NAMESPACES);
83 302
    }
84
85
    /**
86
     * Define the default instance of the Factory.
87
     *
88
     * @param Factory $defaultInstance
89
     */
90 1
    public static function setDefaultInstance(self $defaultInstance): void
91
    {
92 1
        self::$defaultInstance = $defaultInstance;
93 1
    }
94
95
    /**
96
     * Returns the default instance of the Factory.
97
     *
98
     * @return Factory
99
     */
100 293
    public static function getDefaultInstance(): self
101
    {
102 293
        if (!self::$defaultInstance instanceof self) {
0 ignored issues
show
introduced by
The condition ! self::defaultInstance instanceof self can never be true.
Loading history...
103 289
            self::$defaultInstance = new self(self::DEFAULT_RULES_NAMESPACES, self::DEFAULT_EXCEPTIONS_NAMESPACES);
104
        }
105
106 293
        return self::$defaultInstance;
107
    }
108
109
    /**
110
     * Creates a rule.
111
     *
112
     * @param string $ruleName
113
     * @param array $arguments
114
     *
115
     * @throws ComponentException
116
     *
117
     * @return Validatable
118
     */
119 297
    public function rule(string $ruleName, array $arguments = []): Validatable
120
    {
121 297
        foreach ($this->rulesNamespaces as $namespace) {
122 297
            $className = sprintf('%s\\%s', $namespace, ucfirst($ruleName));
123 297
            if (!class_exists($className)) {
124 3
                continue;
125
            }
126
127 295
            return $this->getReflection($className, Validatable::class)->newInstanceArgs($arguments);
128
        }
129
130 2
        throw new ComponentException(sprintf('"%s" is not a valid rule name', $ruleName));
131
    }
132
133
    /**
134
     * Creates an exception.
135
     *
136
     * @param Validatable $validatable
137
     * @param mixed $input
138
     * @param array $extraParams
139
     *
140
     * @throws ComponentException
141
     *
142
     * @return ValidationException
143
     */
144 223
    public function exception(Validatable $validatable, $input, array $extraParams = []): ValidationException
145
    {
146 223
        $reflection = new ReflectionObject($validatable);
147 223
        $ruleName = $reflection->getShortName();
148 223
        foreach ($this->exceptionsNamespaces as $namespace) {
149 223
            $exceptionName = sprintf('%s\\%sException', $namespace, $ruleName);
150 223
            if (!class_exists($exceptionName)) {
151 6
                continue;
152
            }
153
154 222
            $params = ['input' => $input] + $extraParams;
155 222
            foreach ($reflection->getProperties() as $property) {
156 222
                $property->setAccessible(true);
157 222
                $params += [$property->getName() => $property->getValue($validatable)];
158
            }
159
160 222
            $exception = $this->getReflection($exceptionName, ValidationException::class)->newInstance();
161 222
            $exception->configure($validatable->getName() ?: stringify($input), $params);
162 222
            if (isset($params['template'])) {
163 5
                $exception->setTemplate($params['template']);
164
            }
165
166 222
            return $exception;
167
        }
168
169 1
        throw new ComponentException(sprintf('Cannot find exception for "%s" rule', lcfirst($ruleName)));
170
    }
171
172
    /**
173
     * @param string $className
174
     * @param string $parentClassName
175
     *
176
     * @return ReflectionClass
177
     *
178
     * @throws InvalidClassException
179
     */
180 300
    private function getReflection(string $className, string $parentClassName): ReflectionClass
181
    {
182 300
        $reflection = new ReflectionClass($className);
183 300
        if (!$reflection->isSubclassOf($parentClassName)) {
184 1
            throw new InvalidClassException(sprintf('"%s" must be an instance of "%s"' , $className, $parentClassName));
185
        }
186
187 299
        if (!$reflection->isInstantiable()) {
188 1
            throw new InvalidClassException(sprintf('"%s" must be instantiable' , $className));
189
        }
190
191 298
        return $reflection;
192
    }
193
194
    /**
195
     * @param array $namespaces
196
     * @param array $defaultNamespaces
197
     * @return array
198
     */
199
    private function filterNamespaces(array $namespaces, array $defaultNamespaces): array
200
    {
201 302
        $filter = function (string $namespace): string {
202 302
            return trim($namespace, '\\');
203 302
        };
204
205 302
        return array_unique(
206 302
            array_merge(
207 302
                array_map($filter, $namespaces),
208 302
                array_map($filter, $defaultNamespaces)
209
            )
210
        );
211
    }
212
}
213