Passed
Push — compileapp ( b35988 )
by Akihito
11:39
created

CompileApp::compileExtraContexts()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 4
c 1
b 0
f 0
dl 0
loc 6
rs 10
cc 2
nc 2
nop 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BEAR\Package\Compiler;
6
7
use BEAR\AppMeta\AbstractAppMeta;
8
use BEAR\AppMeta\Meta;
9
use BEAR\Package\Injector\PackageInjector;
10
use BEAR\Resource\Exception\ParameterException;
11
use BEAR\Resource\NamedParameterInterface;
12
use BEAR\Sunday\Extension\Application\AppInterface;
13
use Doctrine\Common\Annotations\Reader;
14
use Ray\Compiler\CompileInjector;
15
use Ray\PsrCacheModule\LocalCacheProvider;
16
use ReflectionClass;
17
18
use function assert;
19
use function in_array;
20
use function is_callable;
21
use function microtime;
22
use function sprintf;
23
use function str_starts_with;
24
25
final class CompileApp
26
{
27
    /** @var array{class: int, method: int, time: float} */
28
    private array $logs = [
29
        'class' => 0,
30
        'method' => 0,
31
        'time' => 0
32
    ];
33
34
    /**
35
     * Compile application
36
     *
37
     * DI+AOP script file
38
     * Parameter meta information
39
     * (No annotation cached)
40
     *
41
     * @param list<string> $extraContexts
0 ignored issues
show
Bug introduced by
The type BEAR\Package\Compiler\list was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
42
     *
43
     * @return array{class: int, method: int, time: float}
44
     */
45
    public function compile(CompileInjector $injector, array $extraContexts = []): array
46
    {
47
        $start = microtime(true);
48
        $reader = $injector->getInstance(Reader::class);
49
        assert($reader instanceof Reader);
50
        $namedParams = $injector->getInstance(NamedParameterInterface::class);
51
        assert($namedParams instanceof NamedParameterInterface);
52
        // create DI factory class and AOP compiled class for all resources and save $app cache.
53
        $app = $injector->getInstance(AppInterface::class);
54
        assert($app instanceof AppInterface);
55
        $meta = $injector->getInstance(AbstractAppMeta::class);
56
        // check resource injection and create annotation cache
57
        $resources = $meta->getResourceListGenerator();
58
        foreach ($resources as $resourc) {
59
            $this->logs['class']++;
60
            [$className] = $resourc;
61
            $this->saveMeta($namedParams, new ReflectionClass($className));
62
        }
63
64
        $this->compileExtraContexts($extraContexts, $meta);
65
        $this->logs['time'] = (float) sprintf('%.3f', microtime(true) - $start);
66
67
        return $this->logs;
68
    }
69
70
    /**
71
     * Save annotation and method meta information
72
     *
73
     * @param ReflectionClass<object> $class
74
     */
75
    private function saveMeta(NamedParameterInterface $namedParams, ReflectionClass $class): void
76
    {
77
        $instance = $class->newInstanceWithoutConstructor();
78
79
        $methods = $class->getMethods();
80
        $log = sprintf('%s: ', $class->getName());
81
        foreach ($methods as $method) {
82
            $methodName = $method->getName();
83
84
            if (! str_starts_with($methodName, 'on')) {
85
                continue;
86
            }
87
88
            $this->logs['method']++;
89
90
            $log .= sprintf(' %s()', $methodName);
91
            $this->saveNamedParam($namedParams, $instance, $methodName);
92
        }
93
    }
94
95
    private function saveNamedParam(NamedParameterInterface $namedParameter, object $instance, string $method): void
96
    {
97
        // named parameter
98
        if (! in_array($method, ['onGet', 'onPost', 'onPut', 'onPatch', 'onDelete', 'onHead'], true)) {
99
            return;  // @codeCoverageIgnore
100
        }
101
102
        $callable = [$instance, $method];
103
        if (! is_callable($callable)) {
104
            return;  // @codeCoverageIgnore
105
        }
106
107
        try {
108
            $namedParameter->getParameters($callable, []);
109
        } catch (ParameterException) {
110
            return;
111
        }
112
    }
113
114
    /** @param list<string> $extraContexts */
115
    public function compileExtraContexts(array $extraContexts, AbstractAppMeta $meta): void
116
    {
117
        $cache = (new LocalCacheProvider())->get();
118
        foreach ($extraContexts as $context) {
119
            $contextualMeta = new Meta($meta->name, $context, $meta->appDir);
120
            PackageInjector::getInstance($contextualMeta, $context, $cache)->getInstance(AppInterface::class);
121
        }
122
    }
123
}
124