Completed
Pull Request — master (#125)
by
unknown
01:43
created

findPossibleMethod()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.9666
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
namespace Facade\Ignition\SolutionProviders;
4
5
use BadMethodCallException;
6
use Facade\IgnitionContracts\BaseSolution;
7
use Facade\IgnitionContracts\HasSolutionsForThrowable;
8
use Illuminate\Support\Collection;
9
use Illuminate\Validation\Validator;
10
use ReflectionClass;
11
use ReflectionMethod;
12
use Throwable;
13
14
class UnknownValidationSolutionProvider implements HasSolutionsForThrowable
15
{
16
    protected const REGEX = '/Illuminate\\\\Validation\\\\Validator::(?P<method>validate(?!(Attribute|UsingCustomRule))[A-Z][a-zA-Z]+)/m';
17
18
    public function canSolve(Throwable $throwable): bool
19
    {
20
        if (! $throwable instanceof BadMethodCallException) {
21
            return false;
22
        }
23
24
        return ! is_null($this->getMethodFromExceptionMessage($throwable->getMessage()));
25
    }
26
27
    public function getSolutions(Throwable $throwable): array
28
    {
29
        return [
30
            BaseSolution::create('Unknown Validation Rule')
31
                ->setSolutionDescription($this->getSolutionDescription($throwable)),
32
        ];
33
    }
34
35
    protected function getSolutionDescription(Throwable $throwable): string
36
    {
37
        $method = $this->getMethodFromExceptionMessage($throwable->getMessage());
38
39
        $possibleMethod = $this->findPossibleMethod($method);
40
        $rule = lcfirst(str_replace('validate', '', $possibleMethod));
41
42
        return "Did you mean `{$rule}` ?";
43
    }
44
45
    protected function getMethodFromExceptionMessage(string $message): ?string
46
    {
47
        if (! preg_match(self::REGEX, $message, $matches)) {
48
            return null;
49
        }
50
51
        return $matches['method'];
52
    }
53
54
    protected function findPossibleMethod(string $invalidMethodName)
55
    {
56
        return $this->getAvailableMethods()
57
            ->sortByDesc(function (string $method) use ($invalidMethodName) {
58
                similar_text($invalidMethodName, $method, $percentage);
59
60
                return $percentage;
61
            })->first();
62
    }
63
64
    protected function getAvailableMethods(): Collection
65
    {
66
        $class = new ReflectionClass(Validator::class);
67
68
        $extensions = Collection::make((\Illuminate\Support\Facades\Validator::make([], []))->extensions)
0 ignored issues
show
Bug introduced by
Accessing extensions on the interface Illuminate\Contracts\Validation\Validator suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
69
            ->keys()
70
            ->map(function (string $extension) {
71
                return 'validate' . ucfirst($extension);
72
            });
73
74
        return Collection::make($class->getMethods())
75
            ->filter(function (ReflectionMethod $method) {
76
                return preg_match('/(validate(?!(Attribute|UsingCustomRule))[A-Z][a-zA-Z]+)/', $method->name);
77
            })
78
            ->map(function (ReflectionMethod $method) {
79
                return $method->name;
80
            })
81
            ->merge($extensions);
82
    }
83
}
84