Completed
Pull Request — 1.x (#357)
by Akihito
03:02 queued 01:33
created

Compiler   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 146
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 14

Test Coverage

Coverage 55.56%

Importance

Changes 0
Metric Value
wmc 17
lcom 2
cbo 14
dl 0
loc 146
ccs 45
cts 81
cp 0.5556
rs 10
c 0
b 0
f 0

6 Methods

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