Completed
Push — app-factory ( 09c0dc )
by Akihito
06:00
created

AppInjector::__construct()   B

Complexity

Conditions 6
Paths 16

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 23
ccs 19
cts 19
cp 1
rs 8.9297
c 0
b 0
f 0
cc 6
nc 16
nop 5
crap 6
1
<?php
2
/**
3
 * This file is part of the BEAR.Package package.
4
 *
5
 * @license http://opensource.org/licenses/MIT MIT
6
 */
7
namespace BEAR\Package;
8
9
use BEAR\AppMeta\AbstractAppMeta;
10
use BEAR\AppMeta\Meta;
11
use Doctrine\Common\Cache\FilesystemCache;
12
use josegonzalez\Dotenv\Loader;
13
use Ray\Compiler\ScriptInjector;
14
use Ray\Di\AbstractModule;
15
use Ray\Di\Bind;
16
use Ray\Di\Injector;
17
use Ray\Di\InjectorInterface;
18
use Ray\Di\Name;
19
20
final class AppInjector implements InjectorInterface
21
{
22
    /**
23
     * @var AbstractAppMeta
24
     */
25
    private $appMeta;
26
27
    /**
28
     * @var string
29
     */
30
    private $context;
31
32
    /**
33
     * @var string
34
     */
35
    private $scriptDir;
36
37
    /**
38
     * @var string
39
     */
40
    private $appDir;
41
42
    /**
43
     * @var ScriptInjector
44
     */
45
    private $injector;
46
47
    /**
48
     * @var string
49
     */
50
    private $cacheSpace;
51
52
    /**
53
     * @var AbstractModule|null
54
     */
55
    private $module;
56
57
    /**
58
     * @param string               $name       application name      'MyVendor\MyProject'
59
     * @param string               $context    application context   'prod-app'
60
     * @param AbstractAppMeta|null $appMeta    application meta
61
     * @param string               $cacheSpace cache namespace
62
     * @param string               $envFile    .env file path        '/path/to/project/.env'
63
     */
64 37
    public function __construct(string $name, string $context, AbstractAppMeta $appMeta = null, string $cacheSpace = '', string $envFile = '')
65
    {
66 37
        $this->context = $context;
67 37
        $this->appMeta = $appMeta instanceof AbstractAppMeta ? $appMeta : new Meta($name, $context);
68 37
        $this->cacheSpace = $cacheSpace;
69 37
        $scriptDir = $this->appMeta->tmpDir . '/di';
70 37
        ! \file_exists($scriptDir) && \mkdir($scriptDir);
71 37
        $this->scriptDir = $scriptDir;
72 37
        $appDir = $this->appMeta->tmpDir . '/app';
73 37
        ! \file_exists($appDir) && \mkdir($appDir);
74 37
        touch($appDir . '/.do_not_clear');
75 37
        $this->appDir = $appDir;
76 37
        $this->injector = new ScriptInjector($this->scriptDir, function () use ($envFile) {
77 27
            if (file_exists($envFile)) {
78 1
                (new Loader($envFile))->parse()->toEnv(true);
79
            }
80
81 27
            return $this->getModule();
82 37
        });
83 37
        if (! $cacheSpace) {
84 19
            $this->clear();
85
        }
86 36
    }
87
88
    /**
89
     * {@inheritdoc}
90
     */
91 18
    public function getInstance($interface, $name = Name::ANY)
92
    {
93 18
        return $this->injector->getInstance($interface, $name);
94
    }
95
96 1
    public function getOverrideInstance(AbstractModule $module, $interface, $name = Name::ANY)
97
    {
98 1
        $appModule = clone $this->getModule();
99 1
        $appModule->override($module);
0 ignored issues
show
Documentation introduced by
$module is of type object<Ray\Di\AbstractModule>, but the function expects a object<self>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
100
101 1
        return (new Injector($appModule, $this->scriptDir))->getInstance($interface, $name);
102
    }
103
104 35
    public function clear()
105
    {
106 35
        if ((new Unlink)->once($this->appMeta->tmpDir)) {
107 30
            return;
108
        }
109 6
        ! is_dir($this->appMeta->tmpDir . '/di') && \mkdir($this->appMeta->tmpDir . '/di');
110 6
        file_put_contents($this->scriptDir . ScriptInjector::MODULE, serialize($this->getModule()));
111 5
    }
112
113 18
    public function getCachedInstance($interface, $name = Name::ANY)
114
    {
115 18
        $lockFile = $this->appMeta->appDir . '/composer.lock';
116 18
        $this->cacheSpace .= file_exists($lockFile) ? (string) filemtime($lockFile) : '';
117 18
        $cache = new FilesystemCache($this->appDir);
118 18
        $id = $interface . $name . $this->context . $this->cacheSpace;
119 18
        $instance = $cache->fetch($id);
120 18
        if ($instance) {
121 6
            return $instance;
122
        }
123 18
        $instance = $this->injector->getInstance($interface, $name);
124 16
        $cache->save($id, $instance);
125
126 16
        return $instance;
127
    }
128
129 28
    private function getModule() : AbstractModule
130
    {
131 28
        if ($this->module instanceof AbstractModule) {
132 19
            return $this->module;
133
        }
134 28
        $module = (new Module)($this->appMeta, $this->context);
135
        /* @var AbstractModule $module */
136 25
        $container = $module->getContainer();
137 25
        (new Bind($container, InjectorInterface::class))->toInstance($this->injector);
138 25
        (new Bind($container, ''))->annotatedWith('cache_namespace')->toInstance($this->cacheSpace);
139 25
        $this->module = $module;
140
141 25
        return $module;
142
    }
143
}
144