ComposerClassMap.php
3.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
<?php
namespace Facade\Ignition\Support;
use Illuminate\Support\Str;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;
class ComposerClassMap
{
    /** @var \Composer\Autoload\ClassLoader|FakeComposer */
    protected $composer;
    /** @var string */
    protected $basePath;
    public function __construct(?string $autoloaderPath = null)
    {
        $autoloaderPath = $autoloaderPath ?? base_path('/vendor/autoload.php');
        if (file_exists($autoloaderPath)) {
            $this->composer = require $autoloaderPath;
        } else {
            $this->composer = new FakeComposer();
        }
        $this->basePath = app_path();
    }
    public function listClasses(): array
    {
        $classes = $this->composer->getClassMap();
        return array_merge($classes, $this->listClassesInPsrMaps());
    }
    public function searchClassMap(string $missingClass): ?string
    {
        foreach ($this->composer->getClassMap() as $fqcn => $file) {
            $basename = basename($file, '.php');
            if ($basename === $missingClass) {
                return $fqcn;
            }
        }
        return null;
    }
    public function listClassesInPsrMaps(): array
    {
        // TODO: This is incorrect. Doesnt list all fqcns. Need to parse namespace? e.g. App\LoginController is wrong
        $prefixes = array_merge(
            $this->composer->getPrefixes(),
            $this->composer->getPrefixesPsr4()
        );
        $classes = [];
        foreach ($prefixes as $namespace => $directories) {
            foreach ($directories as $directory) {
                if (file_exists($directory)) {
                    $files = (new Finder())
                        ->in($directory)
                        ->files()
                        ->name('*.php');
                    foreach ($files as $file) {
                        if ($file instanceof SplFileInfo) {
                            $fqcn = $this->getFullyQualifiedClassNameFromFile($namespace, $file);
                            $classes[$fqcn] = $file->getRelativePathname();
                        }
                    }
                }
            }
        }
        return $classes;
    }
    public function searchPsrMaps(string $missingClass): ?string
    {
        $prefixes = array_merge(
            $this->composer->getPrefixes(),
            $this->composer->getPrefixesPsr4()
        );
        foreach ($prefixes as $namespace => $directories) {
            foreach ($directories as $directory) {
                if (file_exists($directory)) {
                    $files = (new Finder())
                        ->in($directory)
                        ->files()
                        ->name('*.php');
                    foreach ($files as $file) {
                        if ($file instanceof SplFileInfo) {
                            $basename = basename($file->getRelativePathname(), '.php');
                            if ($basename === $missingClass) {
                                return $namespace.basename($file->getRelativePathname(), '.php');
                            }
                        }
                    }
                }
            }
        }
        return null;
    }
    protected function getFullyQualifiedClassNameFromFile(string $rootNamespace, SplFileInfo $file): string
    {
        $class = trim(str_replace($this->basePath, '', $file->getRealPath()), DIRECTORY_SEPARATOR);
        $class = str_replace(
            [DIRECTORY_SEPARATOR, 'App\\'],
            ['\\', app()->getNamespace()],
            ucfirst(Str::replaceLast('.php', '', $class))
        );
        return $rootNamespace.$class;
    }
}