Passed
Push — compile_injector ( fb8411 )
by Akihito
11:57
created

PackageInjector::getInstance()   B

Complexity

Conditions 7
Paths 15

Size

Total Lines 19
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 11
c 1
b 0
f 0
dl 0
loc 19
rs 8.8333
cc 7
nc 15
nop 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BEAR\Package\Injector;
6
7
use BEAR\AppMeta\AbstractAppMeta;
8
use BEAR\Package\LazyModule;
9
use BEAR\Package\Module;
10
use BEAR\Sunday\Extension\Application\AppInterface;
11
use Ray\Compiler\Annotation\Compile;
12
use Ray\Compiler\CompileInjector;
13
use Ray\Compiler\ScriptInjector;
14
use Ray\Di\AbstractModule;
15
use Ray\Di\Injector as RayInjector;
16
use Ray\Di\InjectorInterface;
17
use Symfony\Component\Cache\Adapter\AdapterInterface;
18
use Symfony\Contracts\Cache\CacheInterface;
19
20
use function assert;
21
use function is_bool;
22
use function is_dir;
23
use function mkdir;
24
use function str_replace;
25
26
final class PackageInjector
27
{
28
    /**
29
     * Serialized injector instances
30
     *
31
     * @var array<string, InjectorInterface>
32
     */
33
    private static array $instances;
34
35
    /** @var array<string, AbstractModule> */
36
    private static array $modules;
37
38
    /**
39
     * @codeCoverageIgnore
40
     */
41
    private function __construct()
42
    {
43
    }
44
45
    public static function getInstance(AbstractAppMeta $meta, string $context, ?CacheInterface $cache, bool $strict = false): InjectorInterface
46
    {
47
        $injectorId = str_replace('\\', '_', $meta->name) . $context;
48
        if (isset(self::$instances[$injectorId])) {
49
            return self::$instances[$injectorId];
50
        }
51
52
        assert($cache instanceof AdapterInterface);
53
        /** @psalm-suppress all */
54
        [$injector, $fileUpdate] = $cache->getItem($injectorId)->get(); // @phpstan-ignore-line
55
        $isCacheableInjector = $injector instanceof ScriptInjector || $injector instanceof CompileInjector || ($injector instanceof InjectorInterface && $fileUpdate instanceof FileUpdate && $fileUpdate->isNotUpdated($meta));
56
        if (! $isCacheableInjector) {
57
            $injector = self::factory($meta, $context, null, $strict);
58
            $cache->save($cache->getItem($injectorId)->set([$injector, new FileUpdate($meta)]));
59
        }
60
61
        self::$instances[$injectorId] = $injector;
62
63
        return $injector;
64
    }
65
66
    public static function factory(AbstractAppMeta $meta, string $context, ?AbstractModule $overideModule = null, bool $strict = false): InjectorInterface
67
    {
68
        $scriptDir = $meta->tmpDir . '/di';
69
        ! is_dir($scriptDir) && ! @mkdir($scriptDir) && ! is_dir($scriptDir);
70
        $moduleId = $meta->appDir . $context;
71
        if (! isset(self::$modules[$moduleId])) {
72
            self::$modules[$moduleId] = (new Module())($meta, $context);
73
        }
74
75
        $module = self::$modules[$moduleId];
76
        if ($overideModule instanceof AbstractModule) {
77
            $module->override($overideModule);
78
        }
79
80
        $injector = new RayInjector($module, $scriptDir);
81
        $isProd = $injector->getInstance('', Compile::class);
82
        assert(is_bool($isProd));
83
        if ($isProd) {
84
            $injector = $strict ? new CompileInjector($scriptDir, new LazyModule($meta, $context, $scriptDir, true)) :
85
                new ScriptInjector($scriptDir, new LazyModule($meta, $context, $scriptDir));
86
        }
87
88
        $injector->getInstance(AppInterface::class);
89
90
        return $injector;
91
    }
92
}
93