TypeErrorExceptionMapper::getType()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace FRZB\Component\RequestMapper\ExceptionMapper\Mapper;
6
7
use FRZB\Component\DependencyInjection\Attribute\AsService;
8
use FRZB\Component\DependencyInjection\Attribute\AsTagged;
9
use FRZB\Component\RequestMapper\Data\ErrorInterface;
10
use FRZB\Component\RequestMapper\Data\TypeError;
11
use FRZB\Component\RequestMapper\Data\ValidationError;
12
use FRZB\Component\RequestMapper\Helper\ClassHelper;
13
use Symfony\Component\Validator\Constraints\Type;
14
15
#[AsService, AsTagged(ExceptionMapperInterface::class)]
16
class TypeErrorExceptionMapper implements ExceptionMapperInterface
17
{
18
    public const TYPE_ERROR_MESSAGE_TEMPLATE = 'Invalid parameter "%s" type, expected "%s", proposed "%s"';
19
    public const ARGUMENT_ERROR_MESSAGE_TEMPLATE = 'Argument with position "%s" not exists';
20
    private const TYPE_ERROR_REGEX = '/((?<where>(?<class>(?:\\w+\\\\)*(?:\\w+))?(?:\\::)?(?<method>\\w+)\\(\\)): Argument #(?<position>\\d+) (?:\\((?<parameter>\\$\\w+)\\)) (?:must be of type) (?<expected>(?:\\w+\\\\)*\\w+),(?: instance of)? (?<proposed>(?:\\w+\\\\)*\\w+) given)/';
21
22
    /**
23
     * @throws \TypeError
24
     * @throws \InvalidArgumentException
25
     */
26
    public function __invoke(\TypeError $exception, array $payload): ErrorInterface
27
    {
28
        if (!preg_match(self::TYPE_ERROR_REGEX, $exception->getMessage(), $matches)) {
29
            throw new \TypeError($exception->getMessage(), (int) $exception->getCode(), $exception);
30
        }
31
32
        $error = TypeError::fromArray($matches);
33
        $parameters = ClassHelper::getMethodParameters($error->class, $error->method);
34
        $parameter = $parameters[$error->position - 1] ?? throw new \InvalidArgumentException(sprintf(self::ARGUMENT_ERROR_MESSAGE_TEMPLATE, $error->position));
35
        $parameterName = "[{$parameter->name}]";
36
37
        $expectedClass = ClassHelper::getShortName($error->expected);
38
        $proposedClass = ClassHelper::getShortName($error->proposed);
39
40
        return new ValidationError(Type::class, $parameterName, sprintf(self::TYPE_ERROR_MESSAGE_TEMPLATE, $parameterName, $expectedClass, $proposedClass));
41
    }
42
43
    public static function getType(): string
44
    {
45
        return \TypeError::class;
46
    }
47
}
48