Passed
Push — master ( a14261...5f8bab )
by Gabor
05:22
created

AbstractAdapter::getServiceConfiguration()   D

Complexity

Conditions 9
Paths 7

Size

Total Lines 38
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 9

Importance

Changes 0
Metric Value
dl 0
loc 38
ccs 18
cts 18
cp 1
rs 4.909
c 0
b 0
f 0
cc 9
eloc 18
nc 7
nop 2
crap 9
1
<?php
2
/**
3
 * WebHemi.
4
 *
5
 * PHP version 7.1
6
 *
7
 * @copyright 2012 - 2017 Gixx-web (http://www.gixx-web.com)
8
 * @license   https://opensource.org/licenses/MIT The MIT License (MIT)
9
 *
10
 * @link      http://www.gixx-web.com
11
 */
12
declare(strict_types = 1);
13
14
namespace WebHemi\DependencyInjection\ServiceAdapter;
15
16
use Exception;
17
use RuntimeException;
18
use InvalidArgumentException;
19
use WebHemi\Configuration\ServiceInterface as ConfigurationInterface;
20
use WebHemi\DependencyInjection\ServiceInterface;
21
22
/**
23
 * Class AbstractAdapter
24
 */
25
abstract class AbstractAdapter implements ServiceInterface
26
{
27
    public const SERVICE_SOURCE_MODULE = 'source_module';
28
    public const SERVICE_CLASS = 'class';
29
    public const SERVICE_ARGUMENTS = 'arguments';
30
    public const SERVICE_METHOD_CALL = 'calls';
31
    public const SERVICE_SHARE = 'shared';
32
    public const SERVICE_SYNTHETIC = 'synthetic';
33
    public const SERVICE_INHERIT = 'inherits';
34
    public const SERVICE_INITIALIZED = 'initialized';
35
36
    /** @var ConfigurationInterface */
37
    protected $configuration;
38
    /** @var array */
39
    protected $registeredModules = [];
40
    /** @var array */
41
    protected $serviceLibrary = [];
42
    /** @var array */
43
    protected $serviceConfiguration = [];
44
45
    /**
46
     * AbstractAdapter constructor.
47
     *
48
     * @param ConfigurationInterface $configuration
49
     */
50 19
    public function __construct(ConfigurationInterface $configuration)
51
    {
52 19
        $this->configuration = $configuration->getConfig('dependencies');
53 19
    }
54
55
    /**
56
     * Returns true if the given service is registered.
57
     *
58
     * @param string $identifier
59
     * @return bool
60
     */
61
    abstract public function has(string $identifier) : bool;
62
63
    /**
64
     * Gets a service.
65
     *
66
     * @param string $identifier
67
     * @return object
68
     */
69
    abstract public function get(string $identifier);
70
71
    /**
72
     * Register the service.
73
     *
74
     * @param string $identifier
75
     * @param string $moduleName
76
     * @return ServiceInterface
77
     */
78 19
    public function registerService(string $identifier, string $moduleName = 'Global') : ServiceInterface
79
    {
80
        // Check if the service is not initialized yet.
81 19
        if (!$this->serviceIsInitialized($identifier)) {
82
            // overwrite if it was registered earlier.
83 19
            $this->serviceLibrary[$identifier] = [
84 19
                self::SERVICE_SOURCE_MODULE => $moduleName,
85
                self::SERVICE_INITIALIZED => false,
86 19
                self::SERVICE_ARGUMENTS => $this->resolveServiceArguments($identifier, $moduleName),
87 19
                self::SERVICE_METHOD_CALL => $this->resolveMethodCalls($identifier, $moduleName),
88 19
                self::SERVICE_SHARE => $this->resolveShares($identifier, $moduleName),
89 19
                self::SERVICE_CLASS => $this->resolveServiceClassName($identifier, $moduleName),
90
            ];
91
        }
92
93 19
        return $this;
94
    }
95
96
    /**
97
     * Checks if the service has been already initialized.
98
     *
99
     * @param string $identifier
100
     * @return bool
101
     */
102 19
    protected function serviceIsInitialized(string $identifier) : bool
103
    {
104 19
        return isset($this->serviceLibrary[$identifier])
105 19
            && $this->serviceLibrary[$identifier][self::SERVICE_INITIALIZED];
106
    }
107
108
    /**
109
     * Retrieves configuration for a service.
110
     *
111
     * @param string $identifier
112
     * @param string $moduleName
113
     * @return array
114
     */
115 19
    protected function getServiceConfiguration(string $identifier, string $moduleName = null) : array
116
    {
117 19
        $configuration = $this->serviceLibrary[$identifier] ?? [];
118
119 19
        if (isset($configuration[self::SERVICE_SOURCE_MODULE])
120 19
            && ($configuration[self::SERVICE_SOURCE_MODULE] == $moduleName || is_null($moduleName))
121
        ) {
122 9
            return $configuration;
123
        }
124
125
        // Get all registered module configurations and merge them together.
126 19
        if ($this->configuration->has($moduleName.'/'.$identifier)) {
127 19
            $moduleConfig = $this->configuration->getData($moduleName.'/'.$identifier);
128 19
            $configuration = merge_array_overwrite($configuration, $moduleConfig);
129
        }
130
131
        // Resolve inheritance.
132 19
        if (isset($configuration[self::SERVICE_INHERIT])) {
133 8
            $parentConfiguration = $this->getServiceConfiguration($configuration[self::SERVICE_INHERIT]);
134
135 8
            foreach ($configuration as $key => $value) {
136 8
                $parentConfiguration[$key] = $value;
137
            }
138
139
            // If the class name is not explicitly defined but the identifier is a class, the inherited class name
140
            // should be overwritten.
141 8
            if (!isset($configuration[self::SERVICE_CLASS]) && class_exists($identifier)) {
142 8
                $parentConfiguration[self::SERVICE_CLASS] = $identifier;
143
            }
144
145 8
            $configuration = $parentConfiguration;
146 8
            unset($parentConfiguration, $configuration[self::SERVICE_INHERIT]);
147
        }
148
149 19
        $this->serviceConfiguration[$identifier] = $configuration;
150
151 19
        return $configuration;
152
    }
153
154
    /**
155
     * Retrieves real service class name.
156
     *
157
     * @param string $identifier
158
     * @param string $moduleName
159
     * @return string
160
     */
161 19
    protected function resolveServiceClassName(string $identifier, string $moduleName) : string
162
    {
163 19
        $serviceConfiguration = $this->getServiceConfiguration($identifier, $moduleName);
164 19
        $className = $serviceConfiguration[self::SERVICE_CLASS] ?? $identifier;
165
166 19
        if (!class_exists($className)) {
167 1
            throw new RuntimeException(
168 1
                sprintf('The resolved class "%s" cannot be found.', $className),
169 1
                1002
170
            );
171
        }
172
173 19
        return $className;
174
    }
175
176
    /**
177
     * Gets argument list and resolves alias references.
178
     *
179
     * @param string $identifier
180
     * @param string $moduleName
181
     * @return array
182
     */
183 19
    protected function resolveServiceArguments(string $identifier, string $moduleName) : array
184
    {
185 19
        $serviceConfiguration = $this->getServiceConfiguration($identifier, $moduleName);
186
187 19
        return $serviceConfiguration[self::SERVICE_ARGUMENTS] ?? [];
188
    }
189
190
    /**
191
     * Returns the service post-init method calls.
192
     *
193
     * @param string $identifier
194
     * @param string $moduleName
195
     * @return array
196
     */
197 19
    protected function resolveMethodCalls(string $identifier, string $moduleName) : array
198
    {
199 19
        $serviceConfiguration = $this->getServiceConfiguration($identifier, $moduleName);
200
201 19
        return $serviceConfiguration[self::SERVICE_METHOD_CALL] ?? [];
202
    }
203
204
    /**
205
     * Returns the service share status.
206
     *
207
     * @param string $identifier
208
     * @param string $moduleName
209
     * @return bool
210
     */
211 19
    protected function resolveShares(string $identifier, string $moduleName) : bool
212
    {
213 19
        $serviceConfiguration = $this->getServiceConfiguration($identifier, $moduleName);
214
215 19
        return $serviceConfiguration[self::SERVICE_SHARE] ?? false;
216
    }
217
218
    /**
219
     * Register the service.
220
     *
221
     * @param string  $identifier
222
     * @param object  $serviceInstance
223
     * @return ServiceInterface
224
     */
225
    abstract public function registerServiceInstance(string $identifier, $serviceInstance) : ServiceInterface;
226
227
    /**
228
     * Register module specific services.
229
     * If a service is already registered in the Global namespace, it will be skipped.
230
     *
231
     * @param string $moduleName
232
     * @return ServiceInterface
233
     */
234 19
    public function registerModuleServices(string $moduleName) : ServiceInterface
235
    {
236 19
        if (!$this->configuration->has($moduleName)) {
237 1
            throw new InvalidArgumentException(
238 1
                sprintf('\'%s\' is not a valid module name', $moduleName),
239 1
                1002
240
            );
241
        }
242
243 19
        $this->registeredModules[] = $moduleName;
244 19
        $services = array_keys($this->configuration->getData($moduleName));
245
246 19
        while (key($services) !== null) {
247 19
            $this->registerService(current($services), $moduleName);
248 19
            next($services);
249
        }
250 19
        return $this;
251
    }
252
}
253