Passed
Push — master ( b678cc...5a9a7b )
by Pieter
03:14
created

ErrorBag::hasErrors()   A

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
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
4
namespace W2w\Lib\ApieObjectAccessNormalizer\Errors;
5
6
use ReflectionClass;
7
use Throwable;
8
use W2w\Lib\ApieObjectAccessNormalizer\Normalizers\ApieObjectAccessNormalizer;
9
10
/**
11
 * Maps all found exceptions to an error map.
12
 *
13
 * @internal
14
 * @see ApieObjectAccessNormalizer
15
 */
16
class ErrorBag
17
{
18
    /**
19
     * @var string
20
     */
21
    private $prefix;
22
23
    /**
24
     * @var string[][]
25
     */
26
    private $errors = [];
27
28
    /**
29
     * @var Throwable[][]
30
     */
31
    private $exceptions = [];
32
33
    public function __construct(string $prefix)
34
    {
35
        $this->prefix = $prefix;
36
    }
37
38
    /**
39
     * Adds error messages to the errors from an exception/error.
40
     * If it is a validation error, the mapping is taken over.
41
     *
42
     * @param string $fieldName
43
     * @param Throwable $throwable
44
     */
45
    public function addThrowable(string $fieldName, Throwable $throwable)
46
    {
47
        $prefix = $this->prefix ? ($this->prefix . '.' . $fieldName) : $fieldName;
48
        if ($validationErrors = $this->extractValidationErrors($throwable)) {
49
            $expectedPrefix = $prefix . '.';
50
            foreach ($validationErrors as $key => $validationError) {
51
                if ($key !== $prefix && strpos($key, $expectedPrefix) !== 0) {
52
                    $key = $expectedPrefix . $key;
53
                }
54
                if (!is_array($validationError)) {
55
                    $validationError = [$validationError];
56
                }
57
                foreach ($validationError as $error) {
58
                    $this->errors[$key][] = $error;
59
                    $this->exceptions[$key][] = $throwable;
60
                }
61
            }
62
            return;
63
        }
64
        $this->errors[$prefix][] = $throwable->getMessage();
65
        $this->exceptions[$prefix][] = $throwable;
66
    }
67
68
    /**
69
     * Returns a list of error messages.
70
     *
71
     * @return string[][]
72
     */
73
    public function getErrors(): array
74
    {
75
        return $this->errors;
76
    }
77
78
    /**
79
     * Since ApieObjectAccessNormalizer catches all exceptions for debugging reasons we keep a record of the exceptions
80
     * too.
81
     *
82
     * @return Throwable[][]
83
     */
84
    public function getExceptions(): array
85
    {
86
        return $this->exceptions;
87
    }
88
89
    /**
90
     * @return bool
91
     */
92
    public function hasErrors(): bool
93
    {
94
        return !empty($this->errors);
95
    }
96
97
    /**
98
     * Tries to guess if the class is a validationexception for any arbitrary library. Most popular libraries
99
     * just have a ValidationException in use.
100
     *
101
     * @param Throwable $throwable
102
     * @return array|null
103
     */
104
    private function extractValidationErrors(Throwable $throwable): ?array
105
    {
106
        $refl = new ReflectionClass($throwable);
107
        if ($refl->getShortName() === 'ValidationException') {
108
            if (method_exists($throwable, 'getErrors')) {
109
                return (array) $throwable->getErrors();
110
            }
111
            if (method_exists($throwable, 'getError')) {
112
                return [$throwable->getError()];
113
            }
114
            if (method_exists($throwable, 'errors')) {
115
                return (array) $throwable->errors();
116
            }
117
        }
118
        return null;
119
    }
120
}
121