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 ( 314542...f7a57a )
by Henrique
03:23
created

library/Factory.php (2 issues)

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