Completed
Push — 1.x ( fd0c91...cdd807 )
by Akihito
03:35
created

Compiler::saveAutoloadFile()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 0
cts 0
cp 0
rs 9.568
c 0
b 0
f 0
cc 2
nc 2
nop 2
crap 6
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BEAR\Package;
6
7
use ArrayObject;
8
use BEAR\AppMeta\Meta;
9
use BEAR\Package\Compiler\CompileAutoload;
10
use BEAR\Package\Compiler\CompileClassMetaInfo;
11
use BEAR\Package\Compiler\CompileDependencies;
12
use BEAR\Package\Compiler\CompileDiScripts;
13
use BEAR\Package\Compiler\CompileObjectGraph;
14
use BEAR\Package\Compiler\CompilePreload;
15
use BEAR\Package\Compiler\FilePutContents;
16
use BEAR\Package\Compiler\NewInstance;
17
use BEAR\Package\Provide\Error\NullPage;
18
use Composer\Autoload\ClassLoader;
19
use Ray\Di\InjectorInterface;
20
use RuntimeException;
21
22
use function assert;
23
use function count;
24
use function file_exists;
25
use function is_float;
26
use function memory_get_peak_usage;
27
use function microtime;
28
use function number_format;
29
use function printf;
30
use function realpath;
31
use function spl_autoload_register;
32
33
use const PHP_EOL;
34
35 1
final class Compiler
36
{
37 1
    /** @var ArrayObject<int, string> */
38 1
    private $classes;
39 1
40
    /** @var InjectorInterface */
41 1
    private $injector;
42
43
    /** @var string */
44 1
    private $context;
45
46 1
    /** @var Meta */
47 1
    private $appMeta;
48 1
49 1
    /** @var CompileDiScripts */
50 1
    private $compilerDiScripts;
51 1
52
    /** @var NewInstance */
53 1
    private $newInstance;
54
55
    /** @var CompileAutoload */
56
    private $dumpAutoload;
57 1
58
    /** @var CompilePreload */
59
    private $compilePreload;
60 1
61 1
    /** @var CompileObjectGraph */
62
    private $compilerObjectGraph;
63 1
64 1
    /** @var CompileDependencies */
65
    private $compileDependencies;
66 1
67
    /**
68
     * @param string $appName application name "MyVendor|MyProject"
69 1
     * @param string $context application context "prod-app"
70
     * @param string $appDir  application path
71 1
     */
72 1
    public function __construct(string $appName, string $context, string $appDir)
73 1
    {
74
        $this->registerLoader($appDir);
75
        $this->hookNullObjectClass($appDir);
76
        $this->context = $context;
77
        $this->appMeta = new Meta($appName, $context, $appDir);
78
        /** @psalm-suppress MixedAssignment (?) */
79
        $this->injector = Injector::getInstance($appName, $context, $appDir);
80
        $this->compilerDiScripts = new CompileDiScripts(new CompileClassMetaInfo(), $this->injector);
81
        $this->newInstance = new NewInstance($this->injector);
82
        /** @var ArrayObject<int, string> $overWritten */
83
        $overWritten = new ArrayObject();
84
        /** @var ArrayObject<int, string> $classes */
85
        $classes = new ArrayObject();
86
        $this->classes = $classes;
87
        $filePutContents = new FilePutContents($overWritten);
88
        $this->dumpAutoload = new CompileAutoload($this->injector, $filePutContents, $this->appMeta, $overWritten, $classes, $appDir, $context);
89
        $this->compilePreload = new CompilePreload($this->newInstance, $this->dumpAutoload, $filePutContents, $classes, $context);
90
        $this->compilerObjectGraph = new CompileObjectGraph($filePutContents, $appDir);
91
        $this->compileDependencies = new CompileDependencies($this->newInstance);
92
    }
93
94
    /**
95
     * Compile application
96
     *
97
     * @return 0|1 exit code
0 ignored issues
show
Documentation introduced by
The doc-type 0|1 could not be parsed: Unknown type name "0" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
98
     */
99
    public function compile(): int
100
    {
101
        $preload = ($this->compilePreload)($this->appMeta, $this->context);
102
        $module = (new Module())($this->appMeta, $this->context);
103
        ($this->compileDependencies)($module);
104
        echo PHP_EOL;
105
        ($this->compilerDiScripts)($this->appMeta);
106
        $failed = $this->newInstance->getFailed();
107
        $dot = $failed ? '' : ($this->compilerObjectGraph)($module);
108
        $start = $_SERVER['REQUEST_TIME_FLOAT'];
109
        assert(is_float($start));
110
        $time = number_format(microtime(true) - $start, 2);
111
        $memory = number_format(memory_get_peak_usage() / (1024 * 1024), 3);
112
        echo PHP_EOL;
113
        printf("Compilation (1/2) took %f seconds and used %fMB of memory\n", $time, $memory);
114
        printf("Success: %d Failed: %d\n", $this->newInstance->getCompiled(), count($this->newInstance->getFailed()));
115
        printf("preload.php: %s\n", $this->dumpAutoload->getFileInfo($preload));
116
        printf("module.dot: %s\n", $dot ? $this->dumpAutoload->getFileInfo($dot) : 'n/a');
117
        foreach ($this->newInstance->getFailed() as $depedencyIndex => $error) {
118
            printf("UNBOUND: %s for %s \n", $error, $depedencyIndex);
119
        }
120
121
        return $failed ? 1 : 0;
122
    }
123
124 1
    public function dumpAutoload(): int
125
    {
126
        return ($this->dumpAutoload)();
127 1
    }
128
129
    private function registerLoader(string $appDir): void
130
    {
131
        $loaderFile = $appDir . '/vendor/autoload.php';
132
        if (! file_exists($loaderFile)) {
133 1
            throw new RuntimeException('no loader');
134 1
        }
135 1
136 1
        $loader = require $loaderFile;
137 1
        assert($loader instanceof ClassLoader);
138 1
        spl_autoload_register(
139 1
            /** @var class-string $class */
0 ignored issues
show
Documentation introduced by
The doc-type class-string could not be parsed: Unknown type name "class-string" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
140
            function (string $class) use ($loader): void {
141 1
                $loader->loadClass($class);
142
                if ($class !== NullPage::class) {
143 1
                    /** @psalm-suppress NullArgument */
144
                    $this->classes[] = $class;
145 1
                }
146
            }
147 1
        );
148
    }
149 1
150
    private function hookNullObjectClass(string $appDir): void
151
    {
152 1
        $compileScript = realpath($appDir) . '/.compile.php';
153
        if (file_exists($compileScript)) {
154
            require $compileScript;
155 1
        }
156 1
    }
157
}
158