diff --git a/src/Compiler/CompileApp.php b/src/Compiler/CompileApp.php new file mode 100644 index 00000000..59531ae2 --- /dev/null +++ b/src/Compiler/CompileApp.php @@ -0,0 +1,123 @@ + 0, + 'method' => 0, + 'time' => 0 + ]; + + /** + * Compile application + * + * DI+AOP script file + * Parameter meta information + * (No annotation cached) + * + * @param list $extraContexts + * + * @return array{class: int, method: int, time: float} + */ + public function compile(CompileInjector $injector, array $extraContexts = []): array + { + $start = microtime(true); + $reader = $injector->getInstance(Reader::class); + assert($reader instanceof Reader); + $namedParams = $injector->getInstance(NamedParameterInterface::class); + assert($namedParams instanceof NamedParameterInterface); + // create DI factory class and AOP compiled class for all resources and save $app cache. + $app = $injector->getInstance(AppInterface::class); + assert($app instanceof AppInterface); + $meta = $injector->getInstance(AbstractAppMeta::class); + // check resource injection and create annotation cache + $resources = $meta->getResourceListGenerator(); + foreach ($resources as $resourc) { + $this->logs['class']++; + [$className] = $resourc; + $this->saveMeta($namedParams, new ReflectionClass($className)); + } + + $this->compileExtraContexts($extraContexts, $meta); + $this->logs['time'] = (float) sprintf('%.3f', microtime(true) - $start); + + return $this->logs; + } + + /** + * Save annotation and method meta information + * + * @param ReflectionClass $class + */ + private function saveMeta(NamedParameterInterface $namedParams, ReflectionClass $class): void + { + $instance = $class->newInstanceWithoutConstructor(); + + $methods = $class->getMethods(); + $log = sprintf('%s: ', $class->getName()); + foreach ($methods as $method) { + $methodName = $method->getName(); + + if (! str_starts_with($methodName, 'on')) { + continue; + } + + $this->logs['method']++; + + $log .= sprintf(' %s()', $methodName); + $this->saveNamedParam($namedParams, $instance, $methodName); + } + } + + private function saveNamedParam(NamedParameterInterface $namedParameter, object $instance, string $method): void + { + // named parameter + if (! in_array($method, ['onGet', 'onPost', 'onPut', 'onPatch', 'onDelete', 'onHead'], true)) { + return; // @codeCoverageIgnore + } + + $callable = [$instance, $method]; + if (! is_callable($callable)) { + return; // @codeCoverageIgnore + } + + try { + $namedParameter->getParameters($callable, []); + } catch (ParameterException) { + return; + } + } + + /** @param list $extraContexts */ + public function compileExtraContexts(array $extraContexts, AbstractAppMeta $meta): void + { + $cache = (new LocalCacheProvider())->get(); + foreach ($extraContexts as $context) { + $contextualMeta = new Meta($meta->name, $context, $meta->appDir); + PackageInjector::getInstance($contextualMeta, $context, $cache)->getInstance(AppInterface::class); + } + } +} diff --git a/tests/CompileAppTest.php b/tests/CompileAppTest.php new file mode 100644 index 00000000..139e10f7 --- /dev/null +++ b/tests/CompileAppTest.php @@ -0,0 +1,22 @@ +compile($injector, ['prod-api-app']); + $this->assertSame(1, $logs['method']); + } +}