Completed
Push — master ( 437edc...95d310 )
by Piotr
03:36
created

XMLProvider::generate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 9
rs 9.6666
cc 1
eloc 7
nc 1
nop 0
1
<?php
2
/**
3
 * Copyright (C) 2013-2016
4
 * Piotr Olaszewski <[email protected]>
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
 * SOFTWARE.
23
 */
24
namespace WSDL\XML;
25
26
use DOMDocument;
27
use DOMElement;
28
use Ouzo\Utilities\Arrays;
29
use WSDL\Builder\Parameter;
30
use WSDL\Builder\WSDLBuilder;
31
use WSDL\Parser\Node;
32
use WSDL\XML\XMLSoapVersion\XMLSoapVersion;
33
use WSDL\XML\XMLStyle\XMLStyle;
34
use WSDL\XML\XMLStyle\XMLStyleFactory;
35
use WSDL\XML\XMLUse\XMLUse;
36
use WSDL\XML\XMLUse\XMLUseFactory;
37
38
/**
39
 * XMLProvider
40
 *
41
 * @author Piotr Olaszewski <[email protected]>
42
 */
43
class XMLProvider
44
{
45
    /**
46
     * @var WSDLBuilder
47
     */
48
    private $builder;
49
    /**
50
     * @var XMLStyle
51
     */
52
    private $XMLStyle;
53
    /**
54
     * @var XMLUse
55
     */
56
    private $XMLUse;
57
    /**
58
     * @var string
59
     */
60
    private $XMLSoapVersion;
61
    /**
62
     * @var DOMDocument
63
     */
64
    private $DOMDocument;
65
    /**
66
     * @var string
67
     */
68
    private $xml;
69
    /**
70
     * @var DOMElement
71
     */
72
    private $definitionsRootNode;
73
74
    /**
75
     * @param WSDLBuilder $builder
76
     */
77
    public function __construct(WSDLBuilder $builder)
78
    {
79
        $this->builder = $builder;
80
        $this->XMLStyle = XMLStyleFactory::create($builder->getStyle());
81
        $this->XMLUse = XMLUseFactory::create($builder->getUse());
82
        $this->XMLSoapVersion = XMLSoapVersion::getTagFor($builder->getSoapVersion());
83
        $this->DOMDocument = new DOMDocument("1.0", "UTF-8");
84
        $this->DOMDocument->formatOutput = true;
85
    }
86
87
    /**
88
     * @return string
89
     */
90
    public function getXml()
91
    {
92
        $this->xml = $this->DOMDocument->saveXML();
93
        return $this->xml;
94
    }
95
96
    /**
97
     * @return void
98
     */
99
    public function generate()
100
    {
101
        $this->definitions()
102
            ->types()
103
            ->message()
104
            ->portType()
105
            ->binding()
106
            ->service();
107
    }
108
109
    /**
110
     * @return $this
111
     */
112
    private function definitions()
113
    {
114
        $targetNamespace = $this->builder->getTargetNamespace();
115
        $definitionsElement = $this->createElementWithAttributes('definitions', array(
116
            'name' => $this->builder->getName(),
117
            'targetNamespace' => $targetNamespace,
118
            'xmlns:tns' => $targetNamespace,
119
            'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema',
120
            'xmlns:' . $this->XMLSoapVersion => 'http://schemas.xmlsoap.org/wsdl/' . $this->XMLSoapVersion . '/',
121
            'xmlns:soapenc' => "http://schemas.xmlsoap.org/soap/encoding/",
122
            'xmlns' => 'http://schemas.xmlsoap.org/wsdl/',
123
            'xmlns:ns' => $this->builder->getNs()
124
        ));
125
        $this->DOMDocument->appendChild($definitionsElement);
126
        $this->definitionsRootNode = $definitionsElement;
127
        return $this;
128
    }
129
130
    /**
131
     * @return $this
132
     */
133
    private function service()
134
    {
135
        $name = $this->builder->getName();
136
        $serviceElement = $this->createElementWithAttributes('service', array('name' => $name . 'Service'));
137
138
        $portElement = $this->createElementWithAttributes('port', array('name' => $name . 'Port', 'binding' => 'tns:' . $name . 'Binding'));
139
140
        $soapAddressElement = $this
141
            ->createElementWithAttributes($this->XMLSoapVersion . ':address', array('location' => $this->builder->getLocation()));
142
        $portElement->appendChild($soapAddressElement);
143
144
        $serviceElement->appendChild($portElement);
145
        $this->definitionsRootNode->appendChild($serviceElement);
146
        return $this;
147
    }
148
149
    /**
150
     * @return $this
151
     */
152
    private function binding()
153
    {
154
        $name = $this->builder->getName();
155
        $targetNamespace = $this->builder->getTargetNamespace();
156
        $bindingElement = $this->createElementWithAttributes('binding', array('name' => $name . 'Binding', 'type' => 'tns:' . $name . 'PortType'));
157
158
        $soapBindingElement = $this->XMLStyle->generateBinding($this->DOMDocument, $this->XMLSoapVersion);
159
        $bindingElement->appendChild($soapBindingElement);
160
161
        foreach ($this->builder->getMethods() as $method) {
162
            $methodName = $method->getName();
163
            $operationElement = $this->createElementWithAttributes('operation', array('name' => $methodName));
164
            $soapOperationElement = $this->createElementWithAttributes($this->XMLSoapVersion . ':operation', array(
165
                'soapAction' => $targetNamespace . '/#' . $methodName
166
            ));
167
            $operationElement->appendChild($soapOperationElement);
168
169
            $soapBodyElement = $this->XMLUse->generateSoapBody($this->DOMDocument, $targetNamespace, $this->XMLSoapVersion);
170
            $this->bindingElement($methodName, $soapBodyElement, $operationElement, 'input', 'RequestHeader', $method->getHeaderParameter());
171
            $this->bindingElement($methodName, $soapBodyElement, $operationElement, 'output', 'ResponseHeader', $method->getHeaderReturn());
172
173
            $bindingElement->appendChild($operationElement);
174
        }
175
176
        $this->definitionsRootNode->appendChild($bindingElement);
177
        return $this;
178
    }
179
180
    /**
181
     * @param string $methodName
182
     * @param DOMElement $soapBodyElement
183
     * @param DOMElement $element
184
     * @param string $elementName
185
     * @param string $headerName
186
     * @param Parameter|null $header
187
     */
188
    private function bindingElement($methodName, DOMElement $soapBodyElement, DOMElement $element, $elementName, $headerName, Parameter $header = null)
189
    {
190
        $targetNamespace = $this->builder->getTargetNamespace();
191
        $inputElement = $this->createElement($elementName);
192
        $inputElement->appendChild($soapBodyElement->cloneNode());
193
194
        $soapHeaderMessage = 'tns:' . $methodName . $headerName;
195
        $soapHeaderElement = $this->XMLUse
196
            ->generateSoapHeaderIfNeeded($this->DOMDocument, $targetNamespace, $soapHeaderMessage, $header, $this->XMLSoapVersion);
197
        if ($soapHeaderElement) {
198
            $inputElement->appendChild($soapHeaderElement);
199
        }
200
201
        $element->appendChild($inputElement);
202
    }
203
204
    /**
205
     * @return $this
206
     */
207
    private function portType()
208
    {
209
        $name = $this->builder->getName();
210
        $portTypeElement = $this->createElementWithAttributes('portType', array('name' => $name . 'PortType'));
211
212
        foreach ($this->builder->getMethods() as $method) {
213
            $methodName = $method->getName();
214
            $operationElement = $this->createElementWithAttributes('operation', array('name' => $methodName));
215
216
            $inputElement = $this->createElementWithAttributes('input', array('message' => 'tns:' . $methodName . 'Request'));
217
            $operationElement->appendChild($inputElement);
218
219
            $outputElement = $this->createElementWithAttributes('output', array('message' => 'tns:' . $methodName . 'Response'));
220
            $operationElement->appendChild($outputElement);
221
222
            $portTypeElement->appendChild($operationElement);
223
        }
224
225
        $this->definitionsRootNode->appendChild($portTypeElement);
226
        return $this;
227
    }
228
229
    /**
230
     * @return $this
231
     */
232
    private function message()
233
    {
234
        foreach ($this->builder->getMethods() as $method) {
235
            $name = $method->getName();
236
237
            $this->messageHeaderIfNeeded($name, 'RequestHeader', $method->getHeaderParameter());
238
            $messageInputElement = $this->messageParts($name . 'Request', $method->getNoHeaderParametersNodes());
239
            $this->definitionsRootNode->appendChild($messageInputElement);
240
241
            $this->messageHeaderIfNeeded($name, 'ResponseHeader', $method->getHeaderReturn());
242
            $messageOutputElement = $this->messageParts($name . 'Response', $method->getReturnNode());
243
            $this->definitionsRootNode->appendChild($messageOutputElement);
244
        }
245
        return $this;
246
    }
247
248
    /**
249
     * @param string $methodName
250
     * @param string $headerSuffix
251
     * @param Parameter|null $parameter
252
     */
253
    private function messageHeaderIfNeeded($methodName, $headerSuffix, Parameter $parameter = null)
254
    {
255
        if ($parameter) {
256
            $messageHeaderElement = $this->messageParts($methodName . $headerSuffix, $parameter->getNode());
257
            $this->definitionsRootNode->appendChild($messageHeaderElement);
258
        }
259
    }
260
261
    /**
262
     * @param string $methodName
263
     * @param Node|Node[] $nodes
264
     * @return DOMElement
265
     */
266
    private function messageParts($methodName, $nodes)
267
    {
268
        $nodes = Arrays::toArray($nodes);
269
        $messageElement = $this->createElementWithAttributes('message', array('name' => $methodName));
270
        $parts = $this->XMLStyle->generateMessagePart($this->DOMDocument, $nodes);
271
        foreach ($parts as $part) {
272
            $messageElement->appendChild($part);
273
        }
274
        return $messageElement;
275
    }
276
277
    /**
278
     * @return $this
279
     */
280
    private function types()
281
    {
282
        $ns = $this->builder->getNs();
283
        $typesElement = $this->createElement('types');
284
285
        $schemaElement = $this->createElementWithAttributes('xsd:schema', array('targetNamespace' => $ns, 'xmlns' => $ns));
286
        foreach ($this->builder->getMethods() as $method) {
287
            $typesForParameters = $this->XMLStyle->generateTypes($this->DOMDocument, $method->getParameters(), $this->XMLSoapVersion);
288
            $typesForReturn = $this->XMLStyle->generateTypes($this->DOMDocument, Arrays::toArray($method->getReturn()), $this->XMLSoapVersion);
289
            $types = array_merge($typesForParameters, $typesForReturn);
290
            foreach ($types as $type) {
291
                $schemaElement->appendChild($type);
292
            }
293
        }
294
        $typesElement->appendChild($schemaElement);
295
296
        $this->definitionsRootNode->appendChild($typesElement);
297
        return $this;
298
    }
299
300
    /**
301
     * @param string $elementName
302
     * @param array $attributes
303
     * @param string $value
304
     * @return DOMElement
305
     */
306
    private function createElementWithAttributes($elementName, $attributes, $value = '')
307
    {
308
        return XMLAttributeHelper::forDOM($this->DOMDocument)->createElementWithAttributes($elementName, $attributes, $value);
309
    }
310
311
    /**
312
     * @param string $elementName
313
     * @param string $value
314
     * @return DOMElement
315
     */
316
    private function createElement($elementName, $value = '')
317
    {
318
        return XMLAttributeHelper::forDOM($this->DOMDocument)->createElement($elementName, $value);
319
    }
320
}
321