Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Spatie\Ignition\Solutions\SolutionProviders;
4
 
5
use ErrorException;
6
use Illuminate\Support\Collection;
7
use ReflectionClass;
8
use ReflectionProperty;
9
use Spatie\Ignition\Contracts\BaseSolution;
10
use Spatie\Ignition\Contracts\HasSolutionsForThrowable;
11
use Throwable;
12
 
13
class UndefinedPropertySolutionProvider implements HasSolutionsForThrowable
14
{
15
    protected const REGEX = '/([a-zA-Z\\\\]+)::\$([a-zA-Z]+)/m';
16
    protected const MINIMUM_SIMILARITY = 80;
17
 
18
    public function canSolve(Throwable $throwable): bool
19
    {
20
        if (! $throwable instanceof ErrorException) {
21
            return false;
22
        }
23
 
24
        if (is_null($this->getClassAndPropertyFromExceptionMessage($throwable->getMessage()))) {
25
            return false;
26
        }
27
 
28
        if (! $this->similarPropertyExists($throwable)) {
29
            return false;
30
        }
31
 
32
        return true;
33
    }
34
 
35
    public function getSolutions(Throwable $throwable): array
36
    {
37
        return [
38
            BaseSolution::create('Unknown Property')
39
            ->setSolutionDescription($this->getSolutionDescription($throwable)),
40
        ];
41
    }
42
 
43
    public function getSolutionDescription(Throwable $throwable): string
44
    {
45
        if (! $this->canSolve($throwable) || ! $this->similarPropertyExists($throwable)) {
46
            return '';
47
        }
48
 
49
        extract(
50
            /** @phpstan-ignore-next-line */
51
            $this->getClassAndPropertyFromExceptionMessage($throwable->getMessage()),
52
            EXTR_OVERWRITE,
53
        );
54
 
55
        $possibleProperty = $this->findPossibleProperty($class ?? '', $property ?? '');
56
 
57
        $class = $class ?? '';
58
 
59
        return "Did you mean {$class}::\${$possibleProperty->name} ?";
60
    }
61
 
62
    protected function similarPropertyExists(Throwable $throwable): bool
63
    {
64
        /** @phpstan-ignore-next-line  */
65
        extract($this->getClassAndPropertyFromExceptionMessage($throwable->getMessage()), EXTR_OVERWRITE);
66
 
67
        $possibleProperty = $this->findPossibleProperty($class ?? '', $property ?? '');
68
 
69
        return $possibleProperty !== null;
70
    }
71
 
72
    /**
73
     * @param string $message
74
     *
75
     * @return null|array<string, string>
76
     */
77
    protected function getClassAndPropertyFromExceptionMessage(string $message): ?array
78
    {
79
        if (! preg_match(self::REGEX, $message, $matches)) {
80
            return null;
81
        }
82
 
83
        return [
84
            'class' => $matches[1],
85
            'property' => $matches[2],
86
        ];
87
    }
88
 
89
    /**
90
     * @param class-string $class
91
     * @param string $invalidPropertyName
92
     *
93
     * @return mixed
94
     */
95
    protected function findPossibleProperty(string $class, string $invalidPropertyName): mixed
96
    {
97
        return $this->getAvailableProperties($class)
98
            ->sortByDesc(function (ReflectionProperty $property) use ($invalidPropertyName) {
99
                similar_text($invalidPropertyName, $property->name, $percentage);
100
 
101
                return $percentage;
102
            })
103
            ->filter(function (ReflectionProperty $property) use ($invalidPropertyName) {
104
                similar_text($invalidPropertyName, $property->name, $percentage);
105
 
106
                return $percentage >= self::MINIMUM_SIMILARITY;
107
            })->first();
108
    }
109
 
110
    /**
111
     * @param class-string $class
112
     *
113
     * @return Collection<int, ReflectionProperty>
114
     */
115
    protected function getAvailableProperties(string $class): Collection
116
    {
117
        $class = new ReflectionClass($class);
118
 
119
        return Collection::make($class->getProperties());
120
    }
121
}