MagiumConfigurationFactory   B
last analyzed

Complexity

Total Complexity 50

Size/Duplication

Total Lines 271
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 8

Test Coverage

Coverage 93.84%

Importance

Changes 0
Metric Value
wmc 50
lcom 2
cbo 8
dl 0
loc 271
ccs 137
cts 146
cp 0.9384
rs 8.4
c 0
b 0
f 0

20 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 30 8
B overrideWithEnvironmentVariables() 0 37 8
A getXml() 0 4 1
A getMagiumConfigurationFilePath() 0 4 1
A getInstance() 0 7 2
A configurationFactory() 0 5 1
A builderFactory() 0 5 1
A managerFactory() 0 5 1
A getConfiguration() 0 4 1
A setContext() 0 4 1
A getEnvironmentVariableOverride() 0 9 2
A buildContextFile() 0 19 4
A getContextFile() 0 7 2
A validateConfigurationFile() 0 12 2
A getCache() 0 5 1
A getBuilderFactory() 0 16 4
A getBuilder() 0 7 2
A getRemoteCache() 0 6 1
A getLocalCache() 0 9 2
A getManager() 0 25 5

How to fix   Complexity   

Complex Class

Complex classes like MagiumConfigurationFactory often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use MagiumConfigurationFactory, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Magium\Configuration;
4
5
use Magium\Configuration\Config\BuilderFactory;
6
use Magium\Configuration\Config\BuilderFactoryInterface;
7
use Magium\Configuration\Config\BuilderInterface;
8
use Magium\Configuration\Config\Context;
9
use Magium\Configuration\Config\MissingConfigurationException;
10
use Magium\Configuration\Config\Repository\ConfigurationRepository;
11
use Magium\Configuration\File\Context\AbstractContextConfigurationFile;
12
use Magium\Configuration\Manager\CacheFactory;
13
use Magium\Configuration\Manager\Manager;
14
use Magium\Configuration\Manager\ManagerInterface;
15
16
class MagiumConfigurationFactory implements MagiumConfigurationFactoryInterface
17
{
18
19
    protected $file;
20
    protected $xml;
21
22
    protected $manager;
23
    protected $builder;
24
    protected $baseDir;
25
    protected $contextFile;
26
    protected $builderFactory;
27
    protected $context = ConfigurationRepository::CONTEXT_DEFAULT;
28
29
    protected static $me;
30
31 18
    public function __construct($magiumConfigurationFile = null, $context = ConfigurationRepository::CONTEXT_DEFAULT, $cwd = __DIR__)
32
    {
33 18
        self::$me = $this;
34 18
        if ($context instanceof Context) {
35 1
            $context = $context->getContext();
36
        }
37 18
        $this->context = $context;
38 18
        if (!$magiumConfigurationFile) {
39 9
            $baseDir = realpath(DIRECTORY_SEPARATOR);
40 9
            while ($cwd && $cwd != $baseDir && file_exists($cwd)) {
41 9
                $checkFile = $cwd . DIRECTORY_SEPARATOR . 'magium-configuration.xml';
42 9
                if (file_exists($checkFile)) {
43 8
                    $magiumConfigurationFile = $checkFile;
44 8
                    break;
45
                }
46 9
                $lastPos = strrpos($cwd, DIRECTORY_SEPARATOR);
47 9
                $cwd = substr($cwd, 0, $lastPos);
48
            }
49
        }
50
51 18
        if (file_exists($magiumConfigurationFile)) {
52 17
            $this->file = realpath($magiumConfigurationFile);
53
        } else {
54 1
            throw new InvalidConfigurationFileException('Unable to file configuration file: ' . $magiumConfigurationFile);
55
        }
56 17
        $this->baseDir = dirname($this->file);
57 17
        chdir($this->baseDir);
58 17
        $this->xml = simplexml_load_file($magiumConfigurationFile);
59 17
        $this->overrideWithEnvironmentVariables();
60 17
    }
61
62 17
    protected function overrideWithEnvironmentVariables()
63
    {
64 17
        $document = dom_import_simplexml($this->xml)->ownerDocument;
65 17
        $xpath = new \DOMXPath($document);
66 17
        $elements = $xpath->query('//*');
67 17
        foreach ($elements as $element) {
68 17
            if ($element instanceof \DOMElement) {
69 17
                $paths = [];
70
                do {
71 17
                    $paths[] = $element->nodeName;
72 17
                } while ($element = $element->parentNode);
73
74
                // Get rid of the base node and base document.  They mean nothing to us.
75 17
                array_pop($paths);
76 17
                array_pop($paths);
77 17
                if (!empty($paths)) {
78 14
                    $paths = array_reverse($paths);
79 14
                    $path = implode('/', $paths);
80 14
                    $value = $this->getEnvironmentVariableOverride($path);
81 14
                    if ($value !== null) {
82 1
                        foreach ($paths as &$path) {
83 1
                            $path = 's:' . $path;
84
                        }
85 1
                        $path = implode('/', $paths);
86 1
                        $xpathExpression = '/s:magiumBase/' . $path;
87 1
                        $this->xml->registerXPathNamespace('s', 'http://www.magiumlib.com/BaseConfiguration');
88 1
                        $simpleXmlElement = $this->xml->xpath($xpathExpression);
89 1
                        if (!empty($simpleXmlElement)) {
90 1
                            $simpleXmlElement = $simpleXmlElement[0];
91 1
                            $simpleXmlElement[0] = $value; // self reference
92
                        }
93
                    }
94
                }
95
96
            }
97
        }
98 17
    }
99
100
    /**
101
     * @return \SimpleXMLElement
102
     */
103
104 1
    public function getXml()
105
    {
106 1
        return $this->xml;
107
    }
108
109 2
    public function getMagiumConfigurationFilePath()
110
    {
111 2
        return $this->file;
112
    }
113
114 2
    protected static function getInstance($magiumConfigurationFile = null, $context = ConfigurationRepository::CONTEXT_DEFAULT)
115
    {
116 2
        if (!self::$me instanceof self) {
117
            new self($magiumConfigurationFile, $context);
118
        }
119 2
        return self::$me;
120
    }
121
122
    public static function configurationFactory($magiumConfigurationFile = null, $context = ConfigurationRepository::CONTEXT_DEFAULT)
123
    {
124
        $me = self::getInstance($magiumConfigurationFile, $context);
125
        return $me->getConfiguration($context);
126
    }
127
128 1
    public static function builderFactory($magiumConfigurationFile = null, $context = ConfigurationRepository::CONTEXT_DEFAULT)
129
    {
130 1
        $me = self::getInstance($magiumConfigurationFile, $context);
131 1
        return $me->getBuilder();
132
    }
133
134 1
    public static function managerFactory($magiumConfigurationFile = null, $context = ConfigurationRepository::CONTEXT_DEFAULT)
135
    {
136 1
        $me = self::getInstance($magiumConfigurationFile, $context);
137 1
        return $me->getManager();
138
    }
139
140
    public function getConfiguration($context = ConfigurationRepository::CONTEXT_DEFAULT)
141
    {
142
        return $this->getManager()->getConfiguration($context);
143
    }
144
145
    public function setContext($context)
146
    {
147
        $this->context = $context;
148
    }
149
150 15
    public function getEnvironmentVariableOverride($path)
151
    {
152 15
        $pathTranslated = 'MCM_' . str_replace('/', '_', strtoupper($path));
153 15
        $value = getenv($pathTranslated);
154 15
        if (!$value) {
155 14
            return null;
156
        }
157 2
        return $value;
158
    }
159
160 5
    protected function buildContextFile()
161
    {
162 5
        chdir($this->baseDir);
163 5
        $contextFileCheck = (string)$this->xml->contextConfigurationFile['file'];
164 5
        $contextFileType = (string)$this->xml->contextConfigurationFile['type'];
165 5
        $contextFile = realpath($contextFileCheck);
166 5
        if (!$contextFile) {
167 1
            throw new MissingConfigurationException('Unable to find context file: ' . $contextFileCheck);
168
        }
169 4
        $class = 'Magium\Configuration\File\Context\\' . ucfirst($contextFileType) . 'File';
170 4
        $reflectionClass = new \ReflectionClass($class);
171 4
        if ($reflectionClass->isSubclassOf(AbstractContextConfigurationFile::class)) {
172 3
            $instance = $reflectionClass->newInstance($contextFile);
173 3
            if ($instance instanceof AbstractContextConfigurationFile) {
174 3
                return $instance;
175
            }
176
        }
177 1
        throw new InvalidConfigurationException('Unable to load context configuration file: ' . $contextFileCheck);
178
    }
179
180 5
    public function getContextFile()
181
    {
182 5
        if (!$this->contextFile instanceof AbstractContextConfigurationFile) {
183 5
            $this->contextFile = $this->buildContextFile();
184
        }
185 3
        return $this->contextFile;
186
    }
187
188 2
    public function validateConfigurationFile()
189
    {
190 2
        $result = false;
191
        try {
192 2
            $doc = new \DOMDocument();
193 2
            $doc->load($this->file);
194 2
            $result = $doc->schemaValidate(__DIR__ . '/../assets/magium-configuration.xsd');
195 1
        } catch (\Exception $e) {
196
            // $result value is already set
197
        }
198 2
        return $result;
199
    }
200
201
    /**
202
     * Retrieves an instance of the cache based off of the XML cache configuration
203
     *
204
     * @param \SimpleXMLElement $element
205
     * @return \Zend\Cache\Storage\StorageInterface
206
     */
207
208 3
    protected function getCache(\SimpleXMLElement $element)
209
    {
210 3
        $cacheFactory = new CacheFactory();
211 3
        return $cacheFactory->getCache($element);
212
    }
213
214 4
    public function getBuilderFactory()
215
    {
216 4
        if (!$this->builderFactory instanceof BuilderFactoryInterface) {
217 4
            $builderFactoryConfig = $this->xml->builderFactory;
218 4
            $class = (string)$builderFactoryConfig['class'];
219 4
            if (!$class) {
220 3
                $class = BuilderFactory::class; // das default
221
            }
222 4
            $reflection = new \ReflectionClass($class);
223 4
            if (!$reflection->implementsInterface(BuilderFactoryInterface::class)) {
224 1
                throw new InvalidConfigurationException($class . ' must implement ' . BuilderFactoryInterface::class);
225
            }
226 3
            $this->builderFactory = $reflection->newInstance(new \SplFileInfo($this->baseDir), $this->xml, $this->getContextFile());
227
        }
228 3
        return $this->builderFactory;
229
    }
230
231
    /**
232
     * @return BuilderInterface
233
     */
234
235 4
    public function getBuilder()
236
    {
237 4
        if (!$this->builder instanceof BuilderInterface) {
238 3
            $this->builder = $this->getBuilderFactory()->getBuilder();
239
        }
240 3
        return $this->builder;
241
    }
242
243 5
    protected function getRemoteCache()
244
    {
245 5
        $cacheConfig = $this->xml->cache;
246 5
        $globalAdapter = $this->getCache($cacheConfig);
247 5
        return $globalAdapter;
248
    }
249
250 4
    protected function getLocalCache()
251
    {
252 4
        $localCache = null;
253 4
        $localCacheConfig = $this->xml->localCache;
254 4
        if ($localCacheConfig) {
255 2
            $localCache = $this->getCache($localCacheConfig);
256
        }
257 4
        return $localCache;
258
    }
259
260 7
    public function getManager()
261
    {
262 7
        if (!$this->manager instanceof ManagerInterface) {
263 6
            $managerClass = Manager::class;
264 6
            if (isset($this->xml->manager['class'])) {
265 2
                $managerClass = (string)$this->xml->manager['class'];
266
            }
267 6
            $reflectionClass = new \ReflectionClass($managerClass);
268 6
            if ($managerClass == Manager::class) {
269
                // just a shortcut so I don't have to rewrite some complicated unit tests.  I'm just lazy.
270 4
                $this->manager = new Manager($this->getRemoteCache(), $this->getBuilder(), $this->getLocalCache());
271 3
                return $this->manager;
272
            }
273 2
            if (!$reflectionClass->implementsInterface(ManagerInterface::class)) {
274 1
                throw new InvalidConfigurationException('Manager class must implement ' . ManagerInterface::class);
275
            }
276 1
            $manager = $reflectionClass->newInstance();
277
            /* @var $manager ManagerInterface */
278 1
            $manager->setBuilder($this->getBuilder());
279 1
            $manager->setLocalCache($this->getLocalCache());
280 1
            $manager->setRemoteCache($this->getRemoteCache());
281 1
            $this->manager = $manager;
282
        }
283 2
        return $this->manager;
284
    }
285
286
}
287