TypeErrorExceptionMapper   A
last analyzed

Complexity

Total Complexity 3

Size/Duplication

Total Lines 31
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 15
dl 0
loc 31
rs 10
c 0
b 0
f 0
wmc 3

2 Methods

Rating   Name   Duplication   Size   Complexity  
A __invoke() 0 15 2
A getType() 0 3 1
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