ConfigReader::readModuleDetectors()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
c 0
b 0
f 0
rs 9.4285
cc 2
eloc 7
nc 2
nop 2
1
<?php
2
/**
3
 * @copyright 2018 Aleksander Stelmaczonek <[email protected]>
4
 * @license   MIT License, see license file distributed with this source code
5
 */
6
7
namespace Koriit\PHPDeps\Config;
8
9
use DOMDocument;
10
use DOMElement;
11
use Koriit\PHPDeps\Config\Exceptions\InvalidConfig;
12
use Koriit\PHPDeps\Config\Exceptions\InvalidSchema;
13
use Koriit\PHPDeps\Modules\Module;
14
use Koriit\PHPDeps\Modules\ModuleDetector;
15
16
class ConfigReader
17
{
18
    /** @var ConfigValidator */
19
    private $validator;
20
21
    const SCHEMA_LOCATION = __DIR__ . '/../../../phpdeps.xsd';
22
23
    public function __construct(ConfigValidator $validator)
24
    {
25
        $this->validator = $validator;
26
    }
27
28
    /**
29
     * @param string $filePath Path to XML config file
30
     *
31
     * @throws InvalidSchema
32
     * @throws InvalidConfig
33
     *
34
     * @return Config
35
     */
36
    public function readConfig($filePath)
37
    {
38
        $document = new DOMDocument();
39
        $document->load($filePath);
40
41
        $this->validateSchema($document);
42
43
        $dir = \realpath(\dirname($filePath));
44
45
        $modules = $this->readModules($document, $dir);
46
        $moduleDetectors = $this->readModuleDetectors($document, $dir);
47
48
        $config = new Config($modules, $moduleDetectors);
49
50
        $this->validator->check($config);
51
52
        return $config;
53
    }
54
55
    /**
56
     * @param DOMDocument $document
57
     *
58
     * @throws InvalidSchema
59
     */
60
    private function validateSchema(DOMDocument $document)
61
    {
62
        $libxmlUseInternalErrors = \libxml_use_internal_errors(true);
63
        if (!$document->schemaValidate(self::SCHEMA_LOCATION)) {
64
            throw new InvalidSchema();
65
        }
66
        \libxml_use_internal_errors($libxmlUseInternalErrors);
67
    }
68
69
    /**
70
     * @param DOMDocument $document
71
     * @param string      $dir      Absolute path to relative directory
72
     *
73
     * @return Module[]
74
     */
75
    private function readModules(DOMDocument $document, $dir)
76
    {
77
        $modules = [];
78
        /** @var DOMElement $module */
79
        foreach ($document->getElementsByTagName('Module') as $module) {
80
            $name = $module->getElementsByTagName('Name')->item(0)->nodeValue;
81
            $namespace = $module->getElementsByTagName('Namespace')->item(0)->nodeValue;
82
            $path = $this->toAbsolutePath($module->getElementsByTagName('Path')->item(0)->nodeValue, $dir);
83
84
            $modules[] = new Module($name, $namespace, $path);
85
        }
86
87
        return $modules;
88
    }
89
90
    /**
91
     * @param DOMDocument $document
92
     * @param string      $dir      Absolute path to relative directory
93
     *
94
     * @return ModuleDetector[]
95
     */
96
    private function readModuleDetectors(DOMDocument $document, $dir)
97
    {
98
        $moduleDetectors = [];
99
        /** @var DOMElement $moduleDetector */
100
        foreach ($document->getElementsByTagName('ModuleDetector') as $moduleDetector) {
101
            $namespace = $moduleDetector->getElementsByTagName('Namespace')->item(0)->nodeValue;
102
            $path = $this->toAbsolutePath($moduleDetector->getElementsByTagName('Path')->item(0)->nodeValue, $dir);
103
104
            $moduleDetectors[] = new ModuleDetector($namespace, $path);
105
        }
106
107
        return $moduleDetectors;
108
    }
109
110
    /**
111
     * @param string $path
112
     * @param string $dir  Absolute path to relative directory
113
     *
114
     * @return string
115
     *
116
     * @see https://github.com/sebastianbergmann/phpunit/blob/976b986778e2962577440b93d481e67576124e0d/src/Util/Configuration.php#L1156
117
     */
118
    private function toAbsolutePath($path, $dir)
119
    {
120
        $path = \trim($path);
121
        if ($path[0] === '/') {
122
            return $path;
123
        }
124
125
        // Matches the following on Windows:
126
        //  - \\NetworkComputer\Path
127
        //  - \\.\D:
128
        //  - \\.\c:
129
        //  - C:\Windows
130
        //  - C:\windows
131
        //  - C:/windows
132
        //  - c:/windows
133
        if (\defined('PHP_WINDOWS_VERSION_BUILD') &&
134
              ($path[0] === '\\' || (\strlen($path) >= 3 && \preg_match('#^[A-Z]\:[/\\\]#i', \substr($path, 0, 3))))) {
135
            return $path;
136
        }
137
        // Stream
138
        if (\strpos($path, '://') !== false) {
139
            return $path;
140
        }
141
142
        return $dir . DIRECTORY_SEPARATOR . $path;
143
    }
144
}
145