Completed
Pull Request — master (#79)
by Jan Philipp
01:36
created

XmlConfigFileLoader::setConfigData()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.7333
c 0
b 0
f 0
cc 2
nc 2
nop 2
1
<?php declare(strict_types=1);
2
3
namespace Shopware\Psh\Config;
4
5
use DOMElement;
6
use DOMXPath;
7
use Symfony\Component\Config\Util\XmlUtils;
8
9
/**
10
 * Load the config data from an xml file
11
 */
12
class XmlConfigFileLoader extends ConfigFileLoader
13
{
14
    const NODE_HEADER = 'header';
15
16
    const NODE_PLACEHOLDER = 'placeholder';
17
18
    const NODE_PLACEHOLDER_DYNAMIC = 'dynamic';
19
20
    const NODE_PLACEHOLDER_CONST = 'const';
21
22
    const NODE_PATH = 'path';
23
24
    const NODE_ENVIRONMENT = 'environment';
25
26
    const NODE_TEMPLATE = 'template';
27
28
    const NODE_TEMPLATE_SOURCE = 'source';
29
30
    const NODE_TEMPLATE_DESTINATION = 'destination';
31
32
    /**
33
     * @var ConfigBuilder
34
     */
35
    private $configBuilder;
36
37
    /**
38
     * @var string
39
     */
40
    private $applicationRootDirectory;
41
42
    /**
43
     * @param ConfigBuilder $configBuilder
44
     * @param string $applicationRootDirectory
45
     */
46
    public function __construct(ConfigBuilder $configBuilder, string $applicationRootDirectory)
47
    {
48
        $this->configBuilder = $configBuilder;
49
        $this->applicationRootDirectory = $applicationRootDirectory;
50
    }
51
52
    /**
53
     * @inheritdoc
54
     */
55
    public function isSupported(string $file): bool
56
    {
57
        return in_array(pathinfo($file, PATHINFO_BASENAME), ['.psh.xml', '.psh.xml.dist', '.psh.xml.override'], true);
58
    }
59
60
    /**
61
     * @inheritdoc
62
     */
63 View Code Duplication
    public function load(string $file, array $params): Config
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
64
    {
65
        $pshConfigNode = $this->loadXmlRoot($file);
66
        $this->configBuilder->start();
67
68
        $headers = $this->extractNodes(self::NODE_HEADER, $pshConfigNode);
69
70
        foreach ($headers as $header) {
71
            $this->configBuilder
72
                ->setHeader($header->nodeValue);
73
        }
74
75
        $this->setConfigData($file, $pshConfigNode);
76
77
        $environments = $this->extractNodes(self::NODE_ENVIRONMENT, $pshConfigNode);
78
79
        foreach ($environments as $node) {
80
            $this->configBuilder->start($node->getAttribute('name'));
81
            $this->setConfigData($file, $node);
82
        }
83
84
        return $this->configBuilder
85
            ->create($params);
86
    }
87
88
    /**
89
     * @param string $file
90
     * @param array $pshConfigNode
91
     */
92
    private function setConfigData(string $file, DOMElement $pshConfigNode)
93
    {
94
        $this->configBuilder->setCommandPaths(
95
            $this->extractCommandPaths($file, $pshConfigNode)
96
        );
97
98
        $placeholders = $this->extractNodes(self::NODE_PLACEHOLDER, $pshConfigNode);
99
100
        foreach ($placeholders as $placeholder) {
101
            $this->extractPlaceholders($placeholder);
102
        }
103
104
        $this->configBuilder->setTemplates(
105
            $this->extractTemplates($file, $pshConfigNode)
106
        );
107
    }
108
109
    /**
110
     * @param string $key
111
     * @param DOMElement $parent
112
     * @return DOMElement[]
113
     */
114
    private function extractNodes(string $key, DOMElement $parent): array
115
    {
116
        $nodes = [];
117
118
        foreach ($parent->childNodes as $childNode) {
119
            if ($childNode instanceof DOMElement && $childNode->localName === $key) {
120
                $nodes[] = $childNode;
121
            }
122
        }
123
124
        if (count($nodes) === 0) {
125
            return [];
126
        }
127
128
        return $nodes;
129
    }
130
131
    /**
132
     * @param string $file
133
     * @param $pshConfigNode
134
     * @return array
135
     */
136
    private function extractCommandPaths(string $file, DOMElement $pshConfigNode): array
137
    {
138
        $pathNodes = $this->extractNodes(self::NODE_PATH, $pshConfigNode);
139
140
        return array_map(function (DOMElement $path) use ($file) {
141
            return $this->fixPath($this->applicationRootDirectory, $path->nodeValue, $file);
142
        }, $pathNodes);
143
    }
144
145
    /**
146
     * @param string $file
147
     * @param array $pshConfigNodes
148
     * @return array
149
     */
150
    private function extractTemplates(string $file, DOMElement $pshConfigNodes): array
151
    {
152
        $templates = $this->extractNodes(self::NODE_TEMPLATE, $pshConfigNodes);
153
154
        return array_map(function (DOMElement $template) use ($file) {
155
            return [
156
                'source' => $this->fixPath(
157
                    $this->applicationRootDirectory,
158
                    $template->getAttribute(self::NODE_TEMPLATE_SOURCE),
159
                    $file
160
                ),
161
                'destination' => $this->makeAbsolutePath(
162
                    $file,
163
                    $template->getAttribute(self::NODE_TEMPLATE_DESTINATION)
164
                )
165
            ];
166
        }, $templates);
167
    }
168
169
    /**
170
     * @param DOMElement $placeholder
171
     */
172
    private function extractPlaceholders(DOMElement $placeholder)
173
    {
174
        foreach ($this->extractNodes(self::NODE_PLACEHOLDER_DYNAMIC, $placeholder) as $dynamic) {
175
            $this->configBuilder->setDynamicVariable($dynamic->getAttribute('name'), $dynamic->nodeValue);
176
        }
177
178
        foreach ($this->extractNodes(self::NODE_PLACEHOLDER_CONST, $placeholder) as $dynamic) {
179
            $this->configBuilder->setConstVariable($dynamic->getAttribute('name'), $dynamic->nodeValue);
180
        }
181
    }
182
183
    /**
184
     * @param string $file
185
     * @return DOMElement
186
     */
187
    private function loadXmlRoot(string $file): DOMElement
188
    {
189
        $xml = XmlUtils::loadFile($file, __DIR__ . '/../../resource/config.xsd');
190
        $xPath = new DOMXPath($xml);
191
192
        /** @var \DOMNodeList $pshConfigNodes */
193
        $pshConfigNodes = $xPath->query('//psh');
194
195
        return $pshConfigNodes[0];
196
    }
197
}
198