Completed
Push — 0.x ( 7dff88...0d9d7c )
by Andrew
02:09
created

ModuleLoader::injectRequiredModule()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 14
ccs 9
cts 9
cp 1
rs 9.2
cc 4
eloc 8
nc 4
nop 2
crap 4
1
<?php
2
namespace Cadre\Module;
3
4
use Aura\Di\Container;
5
use Aura\Di\ContainerConfigInterface;
6
7
class ModuleLoader implements ModuleLoaderInterface
8
{
9
    protected $modules = [];
10
    protected $environment;
11
    protected $context;
12
    protected $isResolved = false;
13
    protected $containerConfigs = [];
14
    protected $conflictsWith = [];
15
    protected $replacedWith = [];
16
    protected $touchedModules = [];
17
18 17
    public function __construct(array $modules, $environment = '', $context = '')
19
    {
20 17
        $this->modules = $modules;
21 17
        $this->environment = $environment;
22 17
        $this->context = $context;
23 17
    }
24
25 15
    public function define(Container $di)
26
    {
27 15
        $this->resolveDependencies();
28 9
        foreach ($this->containerConfigs as $containerConfig) {
29 9
            if ($containerConfig instanceof ContainerConfigInterface) {
0 ignored issues
show
Bug introduced by
The class Aura\Di\ContainerConfigInterface does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
30 9
                $containerConfig->define($di);
31
            }
32
        }
33 9
    }
34
35 9
    public function modify(Container $di)
36
    {
37 9
        $this->resolveDependencies();
38 9
        foreach ($this->containerConfigs as $containerConfig) {
39 9
            if ($containerConfig instanceof ContainerConfigInterface) {
0 ignored issues
show
Bug introduced by
The class Aura\Di\ContainerConfigInterface does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
40 9
                $containerConfig->modify($di);
41
            }
42
        }
43 9
    }
44
45 2
    public function loaded($name)
46
    {
47 2
        $this->resolveDependencies();
48 2
        return isset($this->containerConfigs[$name]);
49
    }
50
51 1
    public function isEnv($environment)
52
    {
53 1
        return 0 === strcmp($environment, $this->environment);
54
    }
55
56 1
    public function isContext($context)
57
    {
58 1
        return 0 === strcmp($context, $this->context);
59
    }
60
61 15
    protected function resolveDependencies()
62
    {
63 15
        if ($this->isResolved) {
64 9
            return;
65
        }
66
67 15
        $idx = 0;
68
69 15
        while ($idx < count($this->modules)) {
70 15
            $module = $this->getModule($this->modules[$idx]);
71 14
            $name = get_class($module);
72
73 14
            if (isset($this->containerConfigs[$name])) {
74 1
                $idx++;
75 1
                continue;
76
            }
77
78 14
            if (isset($this->replacedWith[$name])) {
79 1
                $idx++;
80 1
                continue;
81
            }
82
83 14
            if (isset($this->conflictsWith[$name])) {
84 1
                throw new ConflictingModuleException($name, $this->conflictsWith[$name]);
85
            }
86
87 14
            if (empty($this->touchedModules[$name])) {
88 14
                $this->touchedModules[$name] = 0;
89
            }
90
91 14
            if (1 < $this->touchedModules[$name]) {
92 1
                throw new CircularReferenceException($name, $this->touchedModules[$name]);
93
            }
94
95 14
            $this->touchedModules[$name]++;
96
97 14
            $this->resolveRequire($idx, $module);
98 14
            $this->resolveRequireEnv($idx, $module);
99 14
            $this->resolveConflict($module, $name);
100 14
            $this->resolveReplace($module, $name);
101
102 14
            $module = $this->getModule($this->modules[$idx]);
103 14
            if (0 === strcmp($name, get_class($module))) {
104
                // No new modules were inserted
105 13
                $this->containerConfigs[$name] = $module;
106
            } else {
107
                // Do not increment $idx, reprocess this $idx
108 7
                continue;
109
            }
110
111 13
            $idx++;
112
        }
113
114 9
        $this->isResolved = true;
115 9
    }
116
117 14
    protected function injectRequiredModule($idx, $requiredModules)
118
    {
119 14
        foreach ($requiredModules as $requiredModule) {
120 7
            $foundIdx = array_search($requiredModule, $this->modules);
121 7
            if (false === $foundIdx) {
122
                // New module, not found yet
123 5
                array_splice($this->modules, $idx, 0, $requiredModule);
124 7
            } elseif ($idx < $foundIdx) {
125
                // Found module after us in list. Move up
126 2
                array_splice($this->modules, $foundIdx, 1);
127 7
                array_splice($this->modules, $idx, 0, $requiredModule);
128
            }
129
        }
130 14
    }
131
132 14
    protected function resolveRequire($idx, $module)
133
    {
134 14
        $requiredModules = $module->require();
135 14
        $this->injectRequiredModule($idx, $requiredModules);
136 14
    }
137
138 14
    protected function resolveRequireEnv($idx, $module)
139
    {
140 14
        $envMethod = 'require' . str_replace(' ', '', ucwords(
141 14
            strtolower(str_replace('_', ' ', trim($this->environment)))
142
        ));
143 14
        if ('require' !== $envMethod && method_exists($module, $envMethod)) {
144 2
            $requiredModules = $module->$envMethod();
145 2
            $this->injectRequiredModule($idx, $requiredModules);
146
        }
147 14
    }
148
149 14
    protected function resolveConflict($module, $name)
150
    {
151 14
        $conflictingModules = $module->conflict();
152 14
        foreach ($conflictingModules as $conflictingModule) {
153 3
            $this->conflictsWith[$conflictingModule] = $name;
154 3
            if (isset($this->containerConfigs[$conflictingModule])) {
155 3
                throw new ConflictingModuleException($conflictingModule, $name);
156
            }
157
        }
158 14
    }
159
160 14
    protected function resolveReplace($module, $name)
161
    {
162 14
        $replacesModules = $module->replace();
163 14
        foreach ($replacesModules as $replacesModule) {
164 3
            if (isset($this->replacedWith[$replacesModule])) {
165 1
                throw new AlreadyReplacedException(
166 1
                    $name,
167 1
                    $replacesModule,
168 1
                    $this->replacedWith[$replacesModule]
169
                );
170
            }
171 3
            if (isset($this->containerConfigs[$replacesModule])) {
172 1
                throw new AlreadyLoadedException(
173 1
                    $name,
174 1
                    'replace',
175 1
                    $replacesModule
176
                );
177
            }
178 2
            $this->replacedWith[$replacesModule] = $name;
179
        }
180 14
    }
181
182 15
    protected function getModule($module)
183
    {
184 15
        if (is_string($module)) {
185 15
            $module = new $module($this);
186
        }
187
188 15
        if (! $module instanceof ModuleInterface) {
189 1
            throw new \InvalidArgumentException(
190 1
                'Modules must implement ModuleInterface'
191
            );
192
        }
193
194 14
        return $module;
195
    }
196
}
197