Issues (19)

src/ModelFinder.php (7 issues)

1
<?php
2
3
namespace BeyondCode\ErdGenerator;
4
5
use Illuminate\Database\Eloquent\Model as EloquentModel;
6
use Illuminate\Filesystem\Filesystem;
7
use Illuminate\Support\Collection;
8
use Illuminate\Support\Str;
9
use PhpParser\Node\Stmt\Class_;
10
use PhpParser\Node\Stmt\Namespace_;
11
use PhpParser\NodeTraverser;
12
use PhpParser\NodeVisitor\NameResolver;
13
use PhpParser\ParserFactory;
14
use ReflectionClass;
15
16
class ModelFinder
17
{
18
19
    /** @var Filesystem */
20
    protected $filesystem;
21
22
    public function __construct(Filesystem $filesystem)
23
    {
24
        $this->filesystem = $filesystem;
25
    }
26
27
    public function getModelsInDirectory(string $directory): Collection
28
    {
29
        $files = config('erd-generator.recursive') ?
30
            $this->filesystem->allFiles($directory) :
31
            $this->filesystem->files($directory);
32
33
        $ignoreModels = array_filter(config('erd-generator.ignore', []), 'is_string');
34
        $whitelistModels = array_filter(config('erd-generator.whitelist', []), 'is_string');
35
36
        $collection = Collection::make($files)->filter(function ($path) {
0 ignored issues
show
$files of type Symfony\Component\Finder\SplFileInfo[] is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $items of Illuminate\Support\Collection::make(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

36
        $collection = Collection::make(/** @scrutinizer ignore-type */ $files)->filter(function ($path) {
Loading history...
37
            return Str::endsWith($path, '.php');
38
        })->map(function ($path) {
39
            return $this->getFullyQualifiedClassNameFromFile($path);
40
        })->filter(function (string $className) {
41
            return !empty($className)
42
                && is_subclass_of($className, EloquentModel::class)
43
                && ! (new ReflectionClass($className))->isAbstract();
44
        });
45
46
        if(!count($whitelistModels)) {
47
          return $collection->diff($ignoreModels)->sort();
0 ignored issues
show
$ignoreModels of type array is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $items of Illuminate\Support\Collection::diff(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

47
          return $collection->diff(/** @scrutinizer ignore-type */ $ignoreModels)->sort();
Loading history...
48
        }
49
50
        return $collection->filter(function (string $className) use ($whitelistModels) {
51
            return in_array($className, $whitelistModels);
52
        });
53
    }
54
55
    protected function getFullyQualifiedClassNameFromFile(string $path): string
56
    {
57
        $factory = new ParserFactory();
58
        $parser = method_exists($factory, 'createForHostVersion')
59
            ? $factory->createForHostVersion()
60
            : $factory->create(ParserFactory::PREFER_PHP7);
0 ignored issues
show
The constant PhpParser\ParserFactory::PREFER_PHP7 was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
The method create() does not exist on PhpParser\ParserFactory. Did you maybe mean createForNewestSupportedVersion()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

60
            : $factory->/** @scrutinizer ignore-call */ create(ParserFactory::PREFER_PHP7);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
61
62
        $traverser = new NodeTraverser();
63
        $traverser->addVisitor(new NameResolver());
64
65
        $code = file_get_contents($path);
66
67
        $statements = $parser->parse($code);
68
        $statements = $traverser->traverse($statements);
0 ignored issues
show
It seems like $statements can also be of type null; however, parameter $nodes of PhpParser\NodeTraverser::traverse() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

68
        $statements = $traverser->traverse(/** @scrutinizer ignore-type */ $statements);
Loading history...
69
70
        // get the first namespace declaration in the file
71
        $root_statement = collect($statements)->first(function ($statement) {
0 ignored issues
show
$statements of type array is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $value of collect(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

71
        $root_statement = collect(/** @scrutinizer ignore-type */ $statements)->first(function ($statement) {
Loading history...
72
            return $statement instanceof Namespace_;
73
        });
74
75
        if (! $root_statement) {
76
            return '';
77
        }
78
79
        return collect($root_statement->stmts)
80
                ->filter(function ($statement) {
81
                    return $statement instanceof Class_;
82
                })
83
                ->map(function (Class_ $statement) {
84
                    return $statement->namespacedName->toString();
0 ignored issues
show
The method toString() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

84
                    return $statement->namespacedName->/** @scrutinizer ignore-call */ toString();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
85
                })
86
                ->first() ?? '';
87
    }
88
}
89