1 | <?php |
||
22 | final class Compiler |
||
23 | { |
||
24 | private $classes = []; |
||
25 | |||
26 | private $files = []; |
||
27 | |||
28 | /** |
||
29 | * Compile application |
||
30 | * |
||
31 | * @param string $appName application name "MyVendor|MyProject" |
||
32 | * @param string $context application context "prod-app" |
||
33 | * @param string $appDir application path |
||
34 | */ |
||
35 | 1 | public function __invoke(string $appName, string $context, string $appDir) : string |
|
36 | { |
||
37 | 1 | $loader = $this->compileLoader($appName, $context, $appDir); |
|
38 | 1 | $log = $this->compileDiScripts($appName, $context, $appDir); |
|
39 | 1 | $msg = sprintf("Compile Log: %s\nautload.php: %s", $log, $loader); |
|
40 | |||
41 | 1 | return $msg; |
|
42 | } |
||
43 | |||
44 | 1 | public function compileDiScripts(string $appName, string $context, string $appDir) : string |
|
45 | { |
||
46 | 1 | $appMeta = new AppMeta($appName, $context, $appDir); |
|
47 | 1 | (new Unlink)->force($appMeta->tmpDir); |
|
48 | 1 | $injector = new AppInjector($appName, $context); |
|
49 | 1 | $cache = $injector->getInstance(Cache::class); |
|
50 | 1 | $reader = $injector->getInstance(AnnotationReader::class); |
|
51 | /* @var $reader \Doctrine\Common\Annotations\Reader */ |
||
52 | 1 | $namedParams = $injector->getInstance(NamedParameterInterface::class); |
|
53 | /* @var $namedParams NamedParameterInterface */ |
||
54 | |||
55 | // create DI factory class and AOP compiled class for all resources and save $app cache. |
||
56 | 1 | (new Bootstrap)->newApp($appMeta, $context, $cache); |
|
57 | |||
58 | // check resource injection and create annotation cache |
||
59 | 1 | foreach ($appMeta->getResourceListGenerator() as list($className)) { |
|
60 | 1 | $this->scanClass($injector, $reader, $namedParams, $className); |
|
61 | } |
||
62 | 1 | $logFile = realpath($appMeta->logDir) . '/compile.log'; |
|
63 | 1 | $this->saveCompileLog($appMeta, $context, $logFile); |
|
64 | |||
65 | 1 | return $logFile; |
|
66 | } |
||
67 | |||
68 | 1 | private function compileLoader(string $appName, string $context, string $appDir) : string |
|
69 | { |
||
70 | 1 | $loaderFile = $appDir . '/vendor/autoload.php'; |
|
71 | 1 | if (! file_exists($loaderFile)) { |
|
72 | 1 | return ''; |
|
73 | } |
||
74 | $loaderFile = require $loaderFile; |
||
75 | spl_autoload_register( |
||
76 | function ($class) use ($loaderFile) { |
||
77 | $loaderFile->loadClass($class); |
||
78 | if ($class !== NullPage::class) { |
||
79 | $this->classes[] = $class; |
||
80 | } |
||
81 | }, |
||
82 | false, |
||
83 | true |
||
84 | ); |
||
85 | |||
86 | $this->invokeTypicalReuqest($appName, $context); |
||
87 | $fies = '<?php' . PHP_EOL; |
||
88 | foreach ($this->classes as $class) { |
||
89 | $isAutoloadFailed = ! class_exists($class, false) && ! interface_exists($class, false) && ! trait_exists($class, false); // could be phpdoc tag by anotation loader |
||
90 | if ($isAutoloadFailed) { |
||
91 | continue; |
||
92 | } |
||
93 | $fies .= sprintf( |
||
94 | "require %s';\n", |
||
95 | $this->getRelaticePath($appDir, (new \ReflectionClass($class))->getFileName()) |
||
96 | ); |
||
97 | } |
||
98 | $fies .= "require __DIR__ . '/vendor/autoload.php';" . PHP_EOL . PHP_EOL; |
||
99 | $loaderFile = realpath($appDir . '/autoload.php'); |
||
100 | file_put_contents($loaderFile, $fies); |
||
101 | |||
102 | return $loaderFile; |
||
103 | } |
||
104 | |||
105 | private function getRelaticePath(string $rootDir, string $file) |
||
113 | |||
114 | private function invokeTypicalReuqest(string $appName, string $context) |
||
121 | |||
122 | 1 | private function scanClass(InjectorInterface $injector, Reader $reader, NamedParameterInterface $namedParams, string $className) |
|
123 | { |
||
124 | try { |
||
144 | |||
145 | 1 | private function isMagicMethod($method) : bool |
|
149 | |||
150 | 1 | private function saveNamedParam(NamedParameterInterface $namedParameter, $instance, string $method) |
|
162 | |||
163 | 1 | private function saveCompileLog(AbstractAppMeta $appMeta, string $context, string $logFile) |
|
173 | } |
||
174 |
If you access a property on an interface, you most likely code against a concrete implementation of the interface.
Available Fixes
Adding an additional type check:
Changing the type hint: