Passed
Push — master ( 3b6341...8a007f )
by Christopher
02:34
created

WriterContext::write()   A

Complexity

Conditions 6
Paths 24

Size

Total Lines 25
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 6
eloc 15
nc 24
nop 2
dl 0
loc 25
rs 9.2222
c 2
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace AlgoWeb\ODataMetadata\Writer;
6
7
use AlgoWeb\ODataMetadata\MetadataV3\DomBase;
8
use AlgoWeb\ODataMetadata\MetadataV3\Edm\EdmBase;
9
use AlgoWeb\ODataMetadata\OdataVersions;
10
use DOMDocument;
11
use DOMElement;
12
13
class WriterContext
14
{
15
    private $namespaceContainer;
16
17
    private $odataVersion;
18
    /**
19
     * @var DOMDocument
20
     */
21
    private $baseDocument;
22
    /**
23
     * @var array<string,string>
24
     */
25
    private $namespaceRegister = [];
26
27
    public function __construct(OdataVersions $version, DOMDocument $document = null)
28
    {
29
        $this->odataVersion       = $version;
30
        $this->baseDocument       = $document ?? new DOMDocument();
31
        $this->namespaceContainer = new Namespaces($version);
32
        $this->registerNamespace('edmx', $this->getEdmxNamespace());
33
        $this->registerNamespaces();
34
    }
35
36
    public function getBaseDocument(): DOMDocument
37
    {
38
        return $this->baseDocument;
39
    }
40
41
    public function getEdmNamespace()
42
    {
43
        return $this->namespaceContainer->getEdmNamespace();
44
    }
45
    public function getEdmxNamespace()
46
    {
47
        return $this->namespaceContainer->getEdmxNamespace();
48
    }
49
    public function getMetadataNamespace()
50
    {
51
        return $this->namespaceContainer->getMetadataNamespace();
52
    }
53
    public function getDataServiceNamespace()
54
    {
55
        return $this->namespaceContainer->getDataServiceNamespace();
56
    }
57
    public function getAnnotationsNamespace()
58
    {
59
        return $this->namespaceContainer->getAnnotationsNamespace();
60
    }
61
    public function getOdataVersion(): string
62
    {
63
        return strval($this->odataVersion);
64
    }
65
66
    public function registerNamespace($prefix, $namespace)
67
    {
68
        $this->namespaceRegister[$prefix] = $namespace;
69
    }
70
71
    public function getNamespaceForPrefix($prefix)
72
    {
73
        return $this->namespaceRegister[$prefix];
74
    }
75
76
    protected function createElement($namespace, $name): DOMElement
77
    {
78
        return $this->baseDocument->createElementNS($namespace, $name);
79
    }
80
81
    public function createEdmElement(string $name): DOMElement
82
    {
83
        return $this->createElement($this->getEdmNamespace(), $name);
84
    }
85
    public function createEdmxElement(string $name): DOMElement
86
    {
87
        return $this->createElement($this->getEdmxNamespace(), $name);
88
    }
89
90
    public function shouldWriteV2(): bool
91
    {
92
        return
93
            $this->odataVersion == OdataVersions::TWO() ||
94
            $this->odataVersion == OdataVersions::THREE();
95
    }
96
    public function shouldWriteV3(): bool
97
    {
98
        return $this->odataVersion == OdataVersions::THREE();
99
    }
100
    public function getXml()
101
    {
102
        return $this->baseDocument->saveXML();
103
    }
104
105
    /**
106
     * @param  DomBase    $rootNode
107
     * @param  bool       $isTopLevel
108
     * @return DOMElement
109
     */
110
    public function write(DomBase $rootNode, bool $isTopLevel = true): DOMElement
111
    {
112
        $prefix        = null;
113
        $qualifiedName = $rootNode->getDomName();
114
        if (strpos($qualifiedName, ':') !== false) {
115
            $prefix = substr($qualifiedName, 0, strpos($qualifiedName, ':'));
116
        }
117
        $domElement = $this->baseDocument->createElementNS($this->getNamespaceForPrefix($prefix), $qualifiedName);
118
        if ($isTopLevel) {
119
            $this->setUpNamespaces($domElement);
120
        }
121
122
        $domElement->textContent = $rootNode->getTextContent();
123
//TODO: gotta find a better way to special case this in DataService.
124
        foreach ($rootNode->/** @scrutinizer ignore-call */ getAttributes($this) as $attribute) {
125
            if ($this->shouldWrite($attribute)) {
126
                $attribute->apply($domElement, $this);
127
            }
128
        }
129
        foreach (array_filter($rootNode->getChildElements()) as $childNode) {
130
            $childElement = $this->write($childNode, false);
131
132
            $domElement->appendChild($childElement);
133
        }
134
        return $domElement;
135
    }
136
137
    protected function shouldWrite(IAttribute $attribute)
138
    {
139
        return
140
            (
141
                OdataVersions::TWO() == $attribute->getAttributeForVersion() && $this->shouldWriteV2() ||
142
                OdataVersions::THREE() == $attribute->getAttributeForVersion() && $this->shouldWriteV3() ||
143
                OdataVersions::ONE() == $attribute->getAttributeForVersion()
144
            ) &&
145
            !in_array($this->getOdataVersion(), $attribute->getAttributeProhibitedVersion());
146
    }
147
148
    private function registerNamespaces()
149
    {
150
        $this->registerNamespace(null, $this->getEdmNamespace());
151
        $this->registerNamespace('annotations', $this->getAnnotationsNamespace());
152
        $this->registerNamespace('metadata', $this->getMetadataNamespace());
153
        $this->registerNamespace('edmx', $this->getEdmxNamespace());
154
    }
155
156
    private function setUpNamespaces(DOMElement $rootElement)
157
    {
158
        foreach ($this->namespaceRegister as $prefix => $namespace) {
159
            $qualifiedName = $prefix === '' ? 'xmlns' : 'xmlns:' . $prefix;
160
            $rootElement->setAttributeNS(
161
                'http://www.w3.org/2000/xmlns/',
162
                $qualifiedName,
163
                $namespace
164
            );
165
        }
166
    }
167
}
168