Completed
Push — 1.x ( f90c20...192b3e )
by Akihito
26s queued 14s
created

PackageInjector::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Importance

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