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

Compiler   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 145
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 13

Test Coverage

Coverage 60.81%

Importance

Changes 0
Metric Value
wmc 17
lcom 2
cbo 13
dl 0
loc 145
ccs 45
cts 74
cp 0.6081
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 22 1
B compile() 0 32 6
A dumpAutoload() 0 4 1
A registerLoader() 0 25 5
A hookNullObjectClass() 0 7 2
A unregisterComposerLoader() 0 7 2
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\FakeRun;
16
use BEAR\Package\Compiler\FilePutContents;
17
use BEAR\Package\Compiler\NewInstance;
18
use BEAR\Package\Exception\InvalidContextException;
19
use BEAR\Package\Provide\Error\NullPage;
20
use Composer\Autoload\ClassLoader;
21
use Ray\Di\InjectorInterface;
22
use RuntimeException;
23
24
use function assert;
25
use function count;
26
use function file_exists;
27
use function is_float;
28
use function is_int;
29
use function memory_get_peak_usage;
30
use function microtime;
31
use function number_format;
32
use function ob_clean;
33
use function printf;
34
use function realpath;
35 1
use function spl_autoload_functions;
36
use function spl_autoload_register;
37 1
use function spl_autoload_unregister;
38 1
use function strpos;
39
40 1
use const PHP_EOL;
41
42
final class Compiler
43 1
{
44
    /** @var ArrayObject<int, string> */
45 1
    private $classes;
46 1
47 1
    /** @var InjectorInterface */
48 1
    private $injector;
49 1
50
    /** @var string */
51 1
    private $context;
52
53
    /** @var Meta */
54
    private $appMeta;
55 1
56
    /** @var CompileDiScripts */
57
    private $compilerDiScripts;
58 1
59 1
    /** @var NewInstance */
60
    private $newInstance;
61 1
62 1
    /** @var CompileAutoload */
63
    private $dumpAutoload;
64 1
65
    /** @var CompilePreload */
66
    private $compilePreload;
67 1
68
    /** @var CompileObjectGraph */
69 1
    private $compilerObjectGraph;
70 1
71 1
    /** @var CompileDependencies */
72
    private $compileDependencies;
73
74
    /**
75
     * @param string $appName application name "MyVendor|MyProject"
76
     * @param string $context application context "prod-app"
77
     * @param string $appDir  application path
78
     */
79
    public function __construct(string $appName, string $context, string $appDir)
80
    {
81
        $classes = new ArrayObject();
82
        $this->classes = $classes;
83
        $this->registerLoader($appDir);
84
        $this->hookNullObjectClass($appDir);
85
        $this->context = $context;
86
        $this->appMeta = new Meta($appName, $context, $appDir);
87
        /** @psalm-suppress MixedAssignment (?) */
88
        $this->injector = Injector::getInstance($appName, $context, $appDir);
89
        $this->compilerDiScripts = new CompileDiScripts(new CompileClassMetaInfo(), $this->injector);
90
        $this->newInstance = new NewInstance($this->injector);
91
        /** @var ArrayObject<int, string> $overWritten */
92
        $overWritten = new ArrayObject();
93
        /** @var ArrayObject<int, string> $classes */
94
        $filePutContents = new FilePutContents($overWritten);
95
        $fakeRun = new FakeRun($this->injector, $context, $this->appMeta);
96
        $this->dumpAutoload = new CompileAutoload($fakeRun, $this->injector, $filePutContents, $this->appMeta, $overWritten, $this->classes, $appDir, $context);
97
        $this->compilePreload = new CompilePreload($fakeRun, $this->newInstance, $this->dumpAutoload, $filePutContents, $classes, $context);
98
        $this->compilerObjectGraph = new CompileObjectGraph($filePutContents, $appDir);
99
        $this->compileDependencies = new CompileDependencies($this->newInstance);
100
    }
101
102
    /**
103
     * Compile application
104
     *
105
     * @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...
106
     */
107
    public function compile(): int
108
    {
109
        try {
110
            $preload = ($this->compilePreload)($this->appMeta, $this->context);
111
            $module = (new Module())($this->appMeta, $this->context);
112
            ($this->compileDependencies)($module);
113
        } catch (InvalidContextException $e) {
114
            printf("Invalid context %s\n", $e->getMessage());
115
            ob_clean();
116
117 1
            return 1;
118
        }
119 1
120 1
        echo PHP_EOL;
121 1
        ($this->compilerDiScripts)($this->appMeta);
122 1
        $failed = $this->newInstance->getFailed();
123 1
        $dot = $failed ? '' : ($this->compilerObjectGraph)($module);
124 1
        $start = $_SERVER['REQUEST_TIME_FLOAT'];
125 1
        assert(is_float($start));
126 1
        $time = number_format(microtime(true) - $start, 2);
127
        $memory = number_format(memory_get_peak_usage() / (1024 * 1024), 3);
128 1
        echo PHP_EOL;
129
        printf("Compilation (1/2) took %f seconds and used %fMB of memory\n", $time, $memory);
130 1
        printf("Success: %d Failed: %d\n", $this->newInstance->getCompiled(), count($this->newInstance->getFailed()));
131
        printf("preload.php: %s\n", $this->dumpAutoload->getFileInfo($preload));
132 1
        printf("module.dot: %s\n", $dot ? $this->dumpAutoload->getFileInfo($dot) : 'n/a');
133
        foreach ($this->newInstance->getFailed() as $depedencyIndex => $error) {
134 1
            printf("UNBOUND: %s for %s \n", $error, $depedencyIndex);
135
        }
136 1
137
        return $failed ? 1 : 0;
138
    }
139 1
140
    public function dumpAutoload(): int
141
    {
142 1
        return ($this->dumpAutoload)();
143 1
    }
144
145
    private function registerLoader(string $appDir): void
146 1
    {
147 1
        $this->unregisterComposerLoader();
148 1
        $loaderFile = $appDir . '/vendor/autoload.php';
149
        if (! file_exists($loaderFile)) {
150 1
            throw new RuntimeException('no loader');
151
        }
152 1
153
        $loader = require $loaderFile;
154 1
        assert($loader instanceof ClassLoader);
155
        spl_autoload_register(
156 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...
157 1
            function (string $class) use ($loader): void {
158 1
                $loader->loadClass($class);
159
                if (
160 1
                    $class !== NullPage::class
161 1
                    && ! is_int(strpos($class, 'BEAR\Package\Compiler'))
162
                    && ! is_int(strpos($class, NullPage::class))
163
                ) {
164
                    /** @psalm-suppress NullArgument */
165
                    $this->classes[] = $class;
166
                }
167
            }
168
        );
169
    }
170
171
    private function hookNullObjectClass(string $appDir): void
172
    {
173
        $compileScript = realpath($appDir) . '/.compile.php';
174
        if (file_exists($compileScript)) {
175
            require $compileScript;
176
        }
177
    }
178
179
    private function unregisterComposerLoader(): void
180
    {
181
        $autoload = spl_autoload_functions();
182
        if (isset($autoload[0])) {
183
            spl_autoload_unregister($autoload[0]);
184
        }
185
    }
186
}
187