Completed
Push — compiler ( 5bd2e3...2cb518 )
by Akihito
09:43
created

CompileAutoload::isNotCompileFile()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BEAR\Package\Compiler;
6
7
use ArrayObject;
8
use BEAR\AppMeta\Meta;
9
use Ray\Di\InjectorInterface;
10
use ReflectionClass;
11
12
use function assert;
13
use function class_exists;
14
use function file_exists;
15
use function in_array;
16
use function interface_exists;
17
use function is_float;
18
use function is_int;
19
use function memory_get_peak_usage;
20
use function microtime;
21
use function number_format;
22
use function preg_quote;
23
use function preg_replace;
24
use function printf;
25
use function realpath;
26
use function sprintf;
27
use function strpos;
28
use function trait_exists;
29
30
class CompileAutoload
31
{
32
    /** @var string */
33
    private $appDir;
34
35
    /** @var string */
36
    private $context;
37
38
    /** @var Meta */
39
    private $appMeta;
40
41
    /** @var ArrayObject<int, string> */
42
    private $overwritten;
43
44
    /** @var ArrayObject<int, string> */
45
    private $classes;
46
47
    /** @var InjectorInterface */
48
    private $injector;
49
50
    /** @var FilePutContents */
51
    private $filePutContents;
52
53
    /** @var FakeRun */
54
    private $fakeRun;
55
56
    /**
57
     * @param ArrayObject<int, string> $overwritten
58
     * @param ArrayObject<int, string> $classes
59
     */
60
    public function __construct(
61
        FakeRun $fakeRun,
62
        InjectorInterface $injector,
63
        FilePutContents $filePutContents,
64
        Meta $appMeta,
65
        ArrayObject $overwritten,
66
        ArrayObject $classes,
67
        string $appDir,
68
        string $context,
69
    ) {
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected ')', expecting T_VARIABLE
Loading history...
70
        $this->appDir = $appDir;
71
        $this->context = $context;
72
        $this->appMeta = $appMeta;
73
        $this->overwritten = $overwritten;
74
        $this->classes = $classes;
75
        $this->injector = $injector;
76
        $this->filePutContents = $filePutContents;
77
        $this->fakeRun = $fakeRun;
78
    }
79
80
    public function getFileInfo(string $filename): string
81
    {
82
        if (in_array($filename, (array) $this->overwritten, true)) {
83
            return $filename . ' (overwritten)';
84
        }
85
86
        return $filename;
87
    }
88
89
    public function __invoke(): int
90
    {
91
        ($this->fakeRun)($this->injector, $this->context, $this->appMeta);
92
        /** @var list<string> $classes */
93
        $classes = (array) $this->classes;
94
        $paths = $this->getPaths($classes);
95
        $autolaod = $this->saveAutoloadFile($this->appMeta->appDir, $paths);
96
        $start = $_SERVER['REQUEST_TIME_FLOAT'];
97
        assert(is_float($start));
98
        $time = number_format(microtime(true) - $start, 2);
99
        $memory = number_format(memory_get_peak_usage() / (1024 * 1024), 3);
100
        printf("Compilation (2/2) took %f seconds and used %fMB of memory\n", $time, $memory);
101
        printf("autoload.php: %s\n", $this->getFileInfo($autolaod));
102
103
        return 0;
104
    }
105
106
    /**
107
     * @param array<string> $classes
108
     *
109
     * @return array<string>
110
     */
111
    public function getPaths(array $classes): array
112
    {
113
        $paths = [];
114
        foreach ($classes as $class) {
115
            // could be phpdoc tag by annotation loader
116
            if ($this->isNotAutoloadble($class)) {
117
                continue;
118
            }
119
120
            /** @var class-string $class */
121
            $filePath = (string) (new ReflectionClass($class))->getFileName();
122
            if (! $this->isNotCompileFile($filePath)) {
123
                continue; // @codeCoverageIgnore
124
            }
125
126
            $paths[] = $this->getRelativePath($this->appDir, $filePath);
127
        }
128
129
        return $paths;
130
    }
131
132
    /**
133
     * @param array<string> $paths
134
     */
135
    public function saveAutoloadFile(string $appDir, array $paths): string
136
    {
137
        $requiredFile = '';
138
        foreach ($paths as $path) {
139
            $requiredFile .= sprintf(
140
                "require %s;\n",
141
                $path
142
            );
143
        }
144
145
        $autoloadFile = sprintf("<?php
146
147
// %s autoload
148
149
%s
150
require __DIR__ . '/vendor/autoload.php';
151
", $this->context, $requiredFile);
152
        $fileName = realpath($appDir) . '/autoload.php';
153
154
        ($this->filePutContents)($fileName, $autoloadFile);
155
156
        return $fileName;
157
    }
158
159
    private function isNotAutoloadble(string $class): bool
160
    {
161
        return ! class_exists($class, false) && ! interface_exists($class, false) && ! trait_exists($class, false);
162
    }
163
164
    private function isNotCompileFile(string $filePath): bool
165
    {
166
        return file_exists($filePath) || is_int(strpos($filePath, 'phar'));
167
    }
168
169
    private function getRelativePath(string $rootDir, string $file): string
170
    {
171
        $dir = (string) realpath($rootDir);
172
        if (strpos($file, $dir) !== false) {
173
            return (string) preg_replace('#^' . preg_quote($dir, '#') . '#', "__DIR__ . '", $file) . "'";
174
        }
175
176
        return sprintf("'%s'", $file);
177
    }
178
}
179