Passed
Push — trunk ( 0e4c2d...148418 )
by Christian
12:04 queued 12s
created

ConfigReader::addOptionsToElementData()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 25
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 12
c 0
b 0
f 0
nc 5
nop 2
dl 0
loc 25
rs 9.5555
1
<?php declare(strict_types=1);
2
3
namespace Shopware\Core\System\SystemConfig\Util;
4
5
use Shopware\Core\Framework\Bundle;
6
use Shopware\Core\Framework\Log\Package;
7
use Shopware\Core\Framework\Util\XmlReader;
8
use Shopware\Core\System\SystemConfig\Exception\BundleConfigNotFoundException;
9
10
#[Package('system-settings')]
11
class ConfigReader extends XmlReader
12
{
13
    private const FALLBACK_LOCALE = 'en-GB';
14
15
    /**
16
     * @var string
17
     */
18
    protected $xsdFile = __DIR__ . '/../Schema/config.xsd';
19
20
    /**
21
     * @throws BundleConfigNotFoundException
22
     */
23
    public function getConfigFromBundle(Bundle $bundle, ?string $bundleConfigName = null): array
24
    {
25
        if ($bundleConfigName === null) {
26
            $bundleConfigName = 'Resources/config/config.xml';
27
        } else {
28
            $bundleConfigName = 'Resources/config/' . preg_replace('/\\.xml$/i', '', $bundleConfigName) . '.xml';
29
        }
30
        $configPath = $bundle->getPath() . '/' . ltrim($bundleConfigName, '/');
31
32
        if (!is_file($configPath)) {
33
            throw new BundleConfigNotFoundException($bundleConfigName, $bundle->getName());
34
        }
35
36
        return $this->read($configPath);
37
    }
38
39
    /**
40
     * This method is the main entry point to parse a xml file.
41
     */
42
    protected function parseFile(\DOMDocument $xml): array
43
    {
44
        return $this->getCardDefinitions($xml);
45
    }
46
47
    private function getCardDefinitions(\DOMDocument $xml): array
48
    {
49
        $cardDefinitions = [];
50
51
        foreach ($xml->getElementsByTagName('card') as $index => $element) {
52
            $cardDefinitions[] = [
53
                'title' => $this->getCardTitles($element),
54
                'name' => $this->getCardName($element),
55
                'elements' => $this->getElements($element),
56
            ];
57
58
            if ($this->getCardFlag($element) !== null) {
59
                $cardDefinitions[$index]['flag'] = $this->getCardFlag($element);
60
            }
61
        }
62
63
        return $cardDefinitions;
64
    }
65
66
    private function getCardTitles(\DOMElement $element): array
67
    {
68
        $titles = [];
69
        foreach ($element->getElementsByTagName('title') as $title) {
70
            $titles[$this->getLocaleCodeFromElement($title)] = $title->nodeValue;
71
        }
72
73
        return $titles;
74
    }
75
76
    private function getElements(\DOMElement $xml): array
77
    {
78
        $elements = [];
79
        $count = 0;
80
        /** @var \DOMElement $element */
81
        foreach (static::getAllChildren($xml) as $element) {
82
            $nodeName = $element->nodeName;
83
            if ($nodeName === 'title' || $nodeName === 'name' || $nodeName === 'flag') {
84
                continue;
85
            }
86
87
            $elements[$count] = $this->elementToArray($element);
88
            ++$count;
89
        }
90
91
        return $elements;
92
    }
93
94
    private function getCardName(\DOMElement $element): ?string
95
    {
96
        foreach ($element->getElementsByTagName('name') as $name) {
97
            $parentNode = $name->parentNode;
98
            if (($parentNode !== null) && $parentNode->nodeName !== 'card') {
99
                continue;
100
            }
101
102
            return $name->nodeValue;
103
        }
104
105
        return null;
106
    }
107
108
    private function getCardFlag(\DOMElement $element): ?string
109
    {
110
        foreach ($element->getElementsByTagName('flag') as $flag) {
111
            $parentNode = $flag->parentNode;
112
            if (($parentNode !== null) && $parentNode->nodeName !== 'card') {
113
                continue;
114
            }
115
116
            return $flag->nodeValue;
117
        }
118
119
        return null;
120
    }
121
122
    private function elementToArray(\DOMElement $element): array
123
    {
124
        $options = static::getAllChildren($element);
125
126
        if ($element->nodeName === 'component') {
127
            return $this->getElementDataForComponent($element, $options);
128
        }
129
130
        return $this->getElementDataForInputField($element, $options);
131
    }
132
133
    /**
134
     * @param array<\DOMElement> $options
135
     */
136
    private function getElementDataForComponent(\DOMElement $element, array $options): array
137
    {
138
        $elementData = [
139
            'componentName' => $element->getAttribute('name'),
140
        ];
141
142
        return $this->addOptionsToElementData($options, $elementData);
143
    }
144
145
    private function getElementDataForInputField(\DOMElement $element, array $options): array
146
    {
147
        $swFieldType = $element->getAttribute('type') ?: 'text';
148
149
        $elementData = [
150
            'type' => $swFieldType,
151
        ];
152
153
        return $this->addOptionsToElementData($options, $elementData);
154
    }
155
156
    /**
157
     * @param array<\DOMElement> $options
158
     * @param array<string, mixed> $elementData
159
     *
160
     * @return array<string, mixed>
161
     */
162
    private function addOptionsToElementData(array $options, array $elementData): array
163
    {
164
        foreach ($options as $option) {
165
            if ($this->isTranslateAbleOption($option)) {
166
                $elementData[$option->nodeName][$this->getLocaleCodeFromElement($option)] = $option->nodeValue;
167
168
                continue;
169
            }
170
171
            if ($this->isBoolOption($option)) {
172
                $elementData[$option->nodeName] = filter_var($option->nodeValue, \FILTER_VALIDATE_BOOLEAN);
173
174
                continue;
175
            }
176
177
            if ($this->elementIsOptions($option)) {
178
                $elementData['options'] = $this->optionsToArray($option);
179
180
                continue;
181
            }
182
183
            $elementData[$option->nodeName] = $option->nodeValue;
184
        }
185
186
        return $elementData;
187
    }
188
189
    private function optionsToArray(\DOMElement $element): array
190
    {
191
        $options = [];
192
193
        foreach ($element->getElementsByTagName('option') as $option) {
194
            $idTag = $option->getElementsByTagName('id')->item(0);
195
            if ($idTag === null) {
196
                continue;
197
            }
198
199
            $options[] = [
200
                'id' => $idTag->nodeValue,
201
                'name' => $this->getOptionLabels($option),
202
            ];
203
        }
204
205
        return $options;
206
    }
207
208
    private function getOptionLabels(\DOMElement $option): array
209
    {
210
        $optionLabels = [];
211
212
        foreach ($option->getElementsByTagName('name') as $label) {
213
            $optionLabels[$this->getLocaleCodeFromElement($label)] = $label->nodeValue;
214
        }
215
216
        return $optionLabels;
217
    }
218
219
    private function getLocaleCodeFromElement(\DOMElement $element): string
220
    {
221
        return $element->getAttribute('lang') ?: self::FALLBACK_LOCALE;
222
    }
223
224
    private function isTranslateAbleOption(\DOMElement $option): bool
225
    {
226
        return \in_array($option->nodeName, ['label', 'placeholder', 'helpText'], true);
227
    }
228
229
    private function isBoolOption(\DOMElement $option): bool
230
    {
231
        return \in_array($option->nodeName, ['copyable', 'disabled', 'required'], true);
232
    }
233
234
    private function elementIsOptions(\DOMElement $option): bool
235
    {
236
        return $option->nodeName === 'options';
237
    }
238
}
239