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 — master ( ab602a...3093d7 )
by Henrique
03:42
created

Factory::withParameterStringifier()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 6
ccs 1
cts 1
cp 1
crap 1
rs 10
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 ReflectionClass;
17
use ReflectionException;
18
use ReflectionObject;
19
use Respect\Validation\Exceptions\ComponentException;
20
use Respect\Validation\Exceptions\InvalidClassException;
21
use Respect\Validation\Exceptions\ValidationException;
22
use Respect\Validation\Message\Formatter;
23
use Respect\Validation\Message\ParameterStringifier;
24
use Respect\Validation\Message\Stringifier\KeepOriginalStringName;
25
use function lcfirst;
26
use function sprintf;
27
use function trim;
28
use function ucfirst;
29
30
/**
31
 * Factory of objects.
32
 *
33
 * @author Augusto Pascutti <[email protected]>
34
 * @author Henrique Moody <[email protected]>
35
 */
36
final class Factory
37
{
38
    /**
39
     * Default instance of the Factory.
40
     *
41
     * @var Factory
42
     */
43
    private static $defaultInstance;
44
45
    /**
46
     * @var string[]
47
     */
48
    private $rulesNamespaces = ['Respect\\Validation\\Rules'];
49
50
    /**
51
     * @var string[]
52
     */
53
    private $exceptionsNamespaces = ['Respect\\Validation\\Exceptions'];
54
55
    /**
56
     * @var callable
57
     */
58
    private $translator = 'strval';
59
60
    /**
61
     * @var ParameterStringifier
62
     */
63
    private $parameterStringifier;
64
65
    public function __construct()
66
    {
67
        $this->parameterStringifier = new KeepOriginalStringName();
68
    }
69
70
    public function withRuleNamespace(string $rulesNamespace): self
71
    {
72
        $clone = clone $this;
73
        $clone->rulesNamespaces[] = trim($rulesNamespace, '\\');
74
75
        return $clone;
76
    }
77
78
    public function withExceptionNamespace(string $exceptionsNamespace): self
79 197
    {
80
        $clone = clone $this;
81
        $clone->exceptionsNamespaces[] = trim($exceptionsNamespace, '\\');
82
83
        return $clone;
84 197
    }
85 197
86 197
    public function withTranslator(callable $translator): self
87
    {
88 197
        $clone = clone $this;
89 197
        $clone->translator = $translator;
90 197
91
        return $clone;
92 197
    }
93 197
94
    public function withParameterStringifier(ParameterStringifier $parameterStringifier): self
95
    {
96
        $clone = clone $this;
97
        $clone->parameterStringifier = $parameterStringifier;
98 4
99
        return $clone;
100 4
    }
101 4
102
    /**
103
     * Define the default instance of the Factory.
104
     */
105
    public static function setDefaultInstance(self $defaultInstance): void
106 186
    {
107
        self::$defaultInstance = $defaultInstance;
108 186
    }
109 181
110 181
    /**
111 181
     * Returns the default instance of the Factory.
112
     */
113 175
    public static function getDefaultInstance(): self
114 181
    {
115
        if (self::$defaultInstance === null) {
116
            self::$defaultInstance = new self();
117
        }
118 186
119
        return self::$defaultInstance;
120
    }
121
122
    /**
123
     * Creates a rule.
124
     *
125
     * @param mixed[] $arguments
126
     *
127
     * @throws ComponentException
128 189
     */
129
    public function rule(string $ruleName, array $arguments = []): Validatable
130 189
    {
131
        foreach ($this->rulesNamespaces as $namespace) {
132
            try {
133
                /** @var Validatable $rule */
134 189
                $rule = $this
135 186
                    ->createReflectionClass($namespace.'\\'.ucfirst($ruleName), Validatable::class)
136
                    ->newInstanceArgs($arguments);
137 186
138 4
                return $rule;
139 2
            } catch (ReflectionException $exception) {
140
                continue;
141
            }
142
        }
143 1
144
        throw new ComponentException(sprintf('"%s" is not a valid rule name', $ruleName));
145
    }
146
147
    /**
148
     * Creates an exception.
149
     *
150
     * @param mixed $input
151
     * @param mixed[] $extraParams
152
     *
153
     * @throws ComponentException
154 184
     */
155
    public function exception(Validatable $validatable, $input, array $extraParams = []): ValidationException
156 184
    {
157 184
        $formatter = new Formatter($this->translator, $this->parameterStringifier);
158 184
        $reflection = new ReflectionObject($validatable);
159 184
        $ruleName = $reflection->getShortName();
160 184
        $params = ['input' => $input] + $extraParams + $this->extractPropertiesValues($validatable, $reflection);
161 20
        $id = lcfirst($ruleName);
162
        if ($validatable->getName()) {
163 184
            $id = $params['name'] = $validatable->getName();
164
        }
165 184
        foreach ($this->exceptionsNamespaces as $namespace) {
166 4
            try {
167 4
                return $this->createValidationException(
168
                    $namespace.'\\'.$ruleName.'Exception',
169
                    $id,
170
                    $input,
171 1
                    $params,
172
                    $formatter
173
                );
174
            } catch (ReflectionException $exception) {
175
                continue;
176
            }
177
        }
178
179
        return new ValidationException($input, $id, $params, $formatter);
180 196
    }
181
182 196
    /**
183 194
     * Creates a reflection based on class name.
184 1
     *
185
     * @throws InvalidClassException
186
     * @throws ReflectionException
187 193
     */
188 1
    private function createReflectionClass(string $name, string $parentName): ReflectionClass
189
    {
190
        $reflection = new ReflectionClass($name);
191 192
        if (!$reflection->isSubclassOf($parentName) && $parentName !== $name) {
192
            throw new InvalidClassException(sprintf('"%s" must be an instance of "%s"', $name, $parentName));
193
        }
194
195
        if (!$reflection->isInstantiable()) {
196
            throw new InvalidClassException(sprintf('"%s" must be instantiable', $name));
197
        }
198
199
        return $reflection;
200
    }
201
202
    /**
203
     * Creates a Validation exception.
204 197
     *
205
     * @param mixed $input
206
     * @param mixed[] $params
207 197
     *
208 197
     * @throws InvalidClassException
209
     * @throws ReflectionException
210 197
     */
211 197
    private function createValidationException(
212 197
        string $exceptionName,
213 197
        string $id,
214
        $input,
215
        array $params,
216
        Formatter $formatter
217
    ): ValidationException {
218
        /** @var ValidationException $exception */
219
        $exception = $this
220
            ->createReflectionClass($exceptionName, ValidationException::class)
221
            ->newInstance($input, $id, $params, $formatter);
222
        if (isset($params['template'])) {
223
            $exception->updateTemplate($params['template']);
224
        }
225
226
        return $exception;
227 184
    }
228
229
    /**
230
     * @return mixed[]
231
     */
232
    private function extractPropertiesValues(Validatable $validatable, ReflectionClass $reflection): array
233
    {
234 184
        $values = [];
235 183
        foreach ($reflection->getProperties() as $property) {
236 183
            $property->setAccessible(true);
237 7
238
            $propertyValue = $property->getValue($validatable);
239
            if ($propertyValue === null) {
240 183
                continue;
241
            }
242
243
            $values[$property->getName()] = $propertyValue;
244
        }
245
246 184
        $parentReflection = $reflection->getParentClass();
247
        if ($parentReflection !== false) {
248 184
            return $values + $this->extractPropertiesValues($validatable, $parentReflection);
249 184
        }
250 184
251
        return $values;
252 184
    }
253
}
254