ModelFinder::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
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
Bug introduced by
$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
Bug introduced by
$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
Bug introduced by
The constant PhpParser\ParserFactory::PREFER_PHP7 was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
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
Bug introduced by
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
Bug introduced by
$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
Bug introduced by
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