GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

XMLGenerator::extractClassName()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
ccs 3
cts 3
cp 1
cc 1
eloc 3
nc 1
nop 1
crap 1
1
<?php
2
/**
3
 * Copyright (C) 2013-2015
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 ReflectionClass;
28
use WSDL\Parser\MethodParser;
29
use WSDL\Utilities\Strings;
30
use WSDL\XML\Styles\DocumentLiteralWrapped;
31
use WSDL\XML\Styles\Style;
32
use WSDL\XML\Styles\TypesComplex;
33
use WSDL\XML\Styles\TypesElement;
34
35
/**
36
 * XMLGenerator
37
 *
38
 * @author Piotr Olaszewski <[email protected]>
39
 * @see http://www.xfront.com/GlobalVersusLocal.html
40
 */
41
class XMLGenerator
42
{
43
    private $_name;
44
    private $_location;
45
    private $_targetNamespace;
46
    private $_targetNamespaceTypes;
47
    /**
48
     * @var DOMDocument
49
     */
50
    private $_DOMDocument;
51
    /**
52
     * @var DOMDocument
53
     */
54
    private $_definitionsRootNode;
55
    /**
56
     * @var DOMDocument
57
     */
58
    private $_generatedXML;
59
    /**
60
     * @var MethodParser[]
61
     */
62
    private $_WSDLMethods;
63
    /**
64
     * @var Style
65
     */
66
    private $_bindingStyle;
67
68
    public static $alreadyGeneratedComplexTypes = array();
69
70 7
    public function __construct($name, $namespace, $location)
71
    {
72 7
        $this->_name = $this->extractClassName($name);
73 7
        $this->_location = $location;
74
75 7
        $this->_targetNamespace = $this->sanitizeClassName($namespace, $name);
76 7
        $this->_targetNamespaceTypes = $this->_targetNamespace . '/types';
77
78 7
        $this->_DOMDocument = new DOMDocument("1.0", "UTF-8");
79 7
        $this->_DOMDocument->formatOutput = true;
80 7
        $this->_saveXML();
81 7
    }
82
83 7
    public function sanitizeClassName($namespace, $class)
84
    {
85 7
        return Strings::sanitizedNamespaceWithClass($namespace, $class);
86
    }
87
88 7
    public function extractClassName($name)
89
    {
90 7
        $reflectedClass = new ReflectionClass($name);
91 7
        return $reflectedClass->getShortName();
92
    }
93
94 7
    public function setWSDLMethods($WSDLMethods)
95
    {
96 7
        $this->_WSDLMethods = $WSDLMethods;
97 7
        return $this;
98
    }
99
100 7
    public function setBindingStyle(Style $_bindingStyle)
101
    {
102 7
        $this->_bindingStyle = $_bindingStyle;
103 7
        return $this;
104
    }
105
106 7
    public function generate()
107
    {
108 7
        $this->_definitions()
109 7
            ->_types()
110
            ->_message()->_portType()->_binding()->_service();
111
    }
112
113
    /**
114
     * @return XMLGenerator
115
     */
116 7
    private function _definitions()
117
    {
118 7
        $definitionsElement = $this->createElementWithAttributes('definitions', array(
119 7
            'name' => $this->_name,
120 7
            'targetNamespace' => $this->_targetNamespace,
121 7
            'xmlns:tns' => $this->_targetNamespace,
122 7
            'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema',
123 7
            'xmlns:soap' => 'http://schemas.xmlsoap.org/wsdl/soap/',
124 7
            'xmlns:soapenc' => "http://schemas.xmlsoap.org/soap/encoding/",
125 7
            'xmlns' => 'http://schemas.xmlsoap.org/wsdl/',
126 7
            'xmlns:ns' => $this->_targetNamespaceTypes
127 7
        ));
128 7
        $this->_DOMDocument->appendChild($definitionsElement);
129 7
        $this->_definitionsRootNode = $definitionsElement;
0 ignored issues
show
Documentation Bug introduced by
It seems like $definitionsElement of type object<DOMElement> is incompatible with the declared type object<DOMDocument> of property $_definitionsRootNode.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
130 7
        $this->_saveXML();
131 7
        return $this;
132
    }
133
134
    /**
135
     * @return XMLGenerator
136
     */
137 7
    private function _types()
138
    {
139 7
        $typesElement = $this->_createElement('types');
140
141 7
        $schemaElement = $this->createElementWithAttributes('xsd:schema', array(
142 7
            'targetNamespace' => $this->_targetNamespaceTypes,
143 7
            'xmlns' => $this->_targetNamespaceTypes
144 7
        ));
145
146 7
        foreach ($this->_WSDLMethods as $method) {
147 7
            $typeParameters = $this->_bindingStyle->typeParameters($method);
148 7
            if ($typeParameters) {
149 7
                $this->_typesParameters($typeParameters, $schemaElement);
150 7
            }
151
152 7
            $typeReturning = $this->_bindingStyle->typeReturning($method);
153
            $this->_generateComplexType($typeReturning, $schemaElement);
154
        }
155
156
        $typesElement->appendChild($schemaElement);
157
        $this->_definitionsRootNode->appendChild($typesElement);
158
        $this->_saveXML();
159
        return $this;
160
    }
161
162 7
    private function _typesParameters($parameters, $schemaElement)
163
    {
164 7
        foreach ($parameters as $parameter) {
165 7
            $this->_generateComplexType($parameter, $schemaElement);
166 7
        }
167 7
    }
168
169 7
    private function _generateComplexType($parameter, $schemaElement)
170
    {
171 7
        if ($parameter instanceof TypesComplex) {
172
            if (!$this->_bindingStyle instanceof DocumentLiteralWrapped) {
173
                $this->_generateArray($parameter, $schemaElement);
174
            } else {
175
                $this->_generateTypedArray($parameter, $schemaElement);
176
            }
177
        }
178 7
        if ($parameter instanceof TypesElement) {
179
            $this->_generateObject($parameter, $schemaElement);
180
        }
181 7
    }
182
183
    private function _generateObject(TypesElement $parameter, $schemaElement)
184
    {
185
        $name = $parameter->getName();
186
187
        if (self::isAlreadyGenerated($name)) {
188
            return;
189
        }
190
191
        $element = $this->createElementWithAttributes('xsd:element', array(
192
            'name' => $name,
193
            'nillable' => 'true',
194
            'type' => 'ns:' . $name
195
        ));
196
        $complexTypeElement = $this->createElementWithAttributes('xsd:complexType', array(
197
            'name' => $name
198
        ));
199
        $sequenceElement = $this->_createElement('xsd:sequence');
200
201
        $types = $parameter->getElementAttributes();
202
        foreach ($types as $complexType) {
203
            $params = array(
204
                'name' => $complexType['name'],
205
                'type' => $complexType['value']
206
            );
207
            // Optional element
208
            if ($complexType['optional']) {
209
                $params['minOccurs'] = 0;
210
                $params['maxOccurs'] = 1;
211
            }
212
            $elementPartElement = $this->createElementWithAttributes('xsd:element', $params);
213
            $sequenceElement->appendChild($elementPartElement);
214
        }
215
216
        $complex = $parameter->getComplex();
217
        if ($complex) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $complex of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
218
            foreach ($complex as $complexElement) {
219
                $this->_generateComplexType($complexElement, $schemaElement);
220
            }
221
        }
222
223
        $complexTypeElement->appendChild($sequenceElement);
224
225
        $schemaElement->appendChild($complexTypeElement);
226
        $schemaElement->appendChild($element);
227
    }
228
229
    private function _generateArray(TypesComplex $parameter, $schemaElement)
230
    {
231
        $name = $parameter->getName();
232
        $type = $parameter->getArrayType();
233
234
        if (self::isAlreadyGenerated($name)) {
235
            return;
236
        }
237
238
        $complexTypeElement = $this->createElementWithAttributes('xsd:complexType', array('name' => $name));
239
        $complexContentElement = $this->_createElement('xsd:complexContent');
240
        $restrictionElement = $this->createElementWithAttributes('xsd:restriction', array('base' => 'soapenc:Array'));
241
        $attributeElement = $this->createElementWithAttributes('xsd:attribute', array(
242
            'ref' => 'soapenc:arrayType',
243
            'soap:arrayType' => $type
244
        ));
245
        $restrictionElement->appendChild($attributeElement);
246
        $complexContentElement->appendChild($restrictionElement);
247
        $complexTypeElement->appendChild($complexContentElement);
248
        $schemaElement->appendChild($complexTypeElement);
249
250
        if ($parameter->getComplex()) {
251
            $this->_generateComplexType($parameter->getComplex(), $schemaElement);
252
        }
253
    }
254
255
    private function _generateTypedArray(TypesComplex $parameter, $schemaElement)
256
    {
257
        $name = $parameter->getName();
258
        $type = $parameter->getArrayType();
259
        $typeName = $parameter->getArrayTypeName();
260
261
        if (self::isAlreadyGenerated($name)) {
262
            return;
263
        }
264
265
        $complexTypeElement = $this->createElementWithAttributes('xsd:complexType', array('name' => $name));
266
        $sequence = $this->_createElement('xsd:sequence');
267
        $element = $this->createElementWithAttributes('xsd:element', array(
268
            'minOccurs' => 0,
269
            'maxOccurs' => 'unbounded',
270
            'name' => $typeName,
271
            'nillable' => 'true',
272
            'type' => str_replace('[]', '', $type)
273
        ));
274
        $sequence->appendChild($element);
275
        $complexTypeElement->appendChild($sequence);
276
        $schemaElement->appendChild($complexTypeElement);
277
278
        if ($parameter->getComplex()) {
279
            $this->_generateComplexType($parameter->getComplex(), $schemaElement);
280
        }
281
    }
282
283
    public static function isAlreadyGenerated($name)
284
    {
285
        if (in_array($name, self::$alreadyGeneratedComplexTypes)) {
286
            return true;
287
        } else {
288
            self::$alreadyGeneratedComplexTypes[] = $name;
289
            return false;
290
        }
291
    }
292
293
    /**
294
     * @return XMLGenerator
295
     */
296
    private function _message()
297
    {
298
        foreach ($this->_WSDLMethods as $method) {
299
            $messageInputElement = $this->_messageInput($method);
300
            $this->_definitionsRootNode->appendChild($messageInputElement);
301
302
            $messageOutputElement = $this->_messageOutput($method);
303
            $this->_definitionsRootNode->appendChild($messageOutputElement);
304
        }
305
        return $this;
306
    }
307
308
    private function _messageInput(MethodParser $method)
309
    {
310
        $messageInputElement = $this->createElementWithAttributes('message', array(
311
            'name' => $method->getName() . 'Request'
312
        ));
313
        $partsInput = $this->_bindingStyle->methodInput($method);
314
        $obj = $this;
315
        $partsInput = array_map(function ($attributes) use ($obj) {
316
            return $obj->createElementWithAttributes('part', $attributes);
317
        }, $partsInput);
318
        foreach ($partsInput as $part) {
319
            $messageInputElement->appendChild($part);
320
        }
321
        return $messageInputElement;
322
    }
323
324
    private function _messageOutput(MethodParser $method)
325
    {
326
        $messageOutputElement = $this->createElementWithAttributes('message', array(
327
            'name' => $method->getName() . 'Response'
328
        ));
329
        $partsOutput = $this->_bindingStyle->methodOutput($method);
330
        $partsOutput = $this->createElementWithAttributes('part', $partsOutput);
331
        $messageOutputElement->appendChild($partsOutput);
332
        return $messageOutputElement;
333
    }
334
335
    /**
336
     * @return XMLGenerator
337
     */
338
    private function _portType()
339
    {
340
        $portTypeElement = $this->createElementWithAttributes('portType', array(
341
            'name' => $this->_name . 'PortType'
342
        ));
343
344
        foreach ($this->_WSDLMethods as $method) {
345
            $operationElement = $this->createElementWithAttributes('operation', array('name' => $method->getName()));
346
347
            if ($method->description()) {
348
                $documentationElement = $this->_createElement('documentation', $method->description());
349
                $operationElement->appendChild($documentationElement);
350
            }
351
352
            $inputElement = $this->createElementWithAttributes('input', array('message' => 'tns:' . $method->getName() . 'Request'));
353
            $operationElement->appendChild($inputElement);
354
355
            $outputElement = $this->createElementWithAttributes('output', array('message' => 'tns:' . $method->getName() . 'Response'));
356
            $operationElement->appendChild($outputElement);
357
358
            $portTypeElement->appendChild($operationElement);
359
        }
360
        $this->_definitionsRootNode->appendChild($portTypeElement);
361
        $this->_saveXML();
362
        return $this;
363
    }
364
365
    /**
366
     * @return XMLGenerator
367
     */
368
    private function _binding()
369
    {
370
        $bindingElement = $this->createElementWithAttributes('binding', array(
371
            'name' => $this->_name . 'Binding',
372
            'type' => 'tns:' . $this->_name . 'PortType'
373
        ));
374
375
        $soapBindingElement = $this->createElementWithAttributes('soap:binding', array(
376
            'style' => $this->_bindingStyle->bindingStyle(),
377
            'transport' => 'http://schemas.xmlsoap.org/soap/http'
378
        ));
379
        $bindingElement->appendChild($soapBindingElement);
380
381
        foreach ($this->_WSDLMethods as $method) {
382
            $soapBodyElement = $this->createElementWithAttributes('soap:body', array(
383
                'use' => $this->_bindingStyle->bindingUse(),
384
                'namespace' => $this->_targetNamespace
385
            ));
386
387
            if ($this->_bindingStyle instanceof \WSDL\XML\Styles\RpcEncoded) {
388
                $encodingUri = $this->_createAttributeWithValue('encodingStyle', 'http://schemas.xmlsoap.org/soap/encoding/');
389
                $soapBodyElement->appendChild($encodingUri);
390
            }
391
392
            $operationElement = $this->createElementWithAttributes('operation', array(
393
                'name' => $method->getName()
394
            ));
395
396
            $soapOperationElement = $this->createElementWithAttributes('soap:operation', array(
397
                'soapAction' => $this->_targetNamespace . '/#' . $method->getName()
398
            ));
399
            $operationElement->appendChild($soapOperationElement);
400
401
            $inputElement = $this->_createElement('input');
402
            $inputElement->appendChild($soapBodyElement);
403
            $operationElement->appendChild($inputElement);
404
405
            $outputElement = $this->_createElement('output');
406
            $outputElement->appendChild($soapBodyElement->cloneNode());
407
            $operationElement->appendChild($outputElement);
408
409
            $bindingElement->appendChild($operationElement);
410
        }
411
        $this->_definitionsRootNode->appendChild($bindingElement);
412
        $this->_saveXML();
413
        return $this;
414
    }
415
416
    /**
417
     * @return XMLGenerator
418
     */
419
    private function _service()
420
    {
421
        $serviceElement = $this->createElementWithAttributes('service', array('name' => $this->_name . 'Service'));
422
423
        $portElement = $this->createElementWithAttributes('port', array(
424
            'name' => $this->_name . 'Port',
425
            'binding' => 'tns:' . $this->_name . 'Binding'
426
        ));
427
428
        $soapAddressElement = $this->createElementWithAttributes('soap:address', array('location' => $this->_location));
429
        $portElement->appendChild($soapAddressElement);
430
431
        $serviceElement->appendChild($portElement);
432
        $this->_definitionsRootNode->appendChild($serviceElement);
433
        $this->_saveXML();
434
    }
435
436 7
    private function _createElement($elementName, $value = '')
437
    {
438 7
        return $this->_DOMDocument->createElement($elementName, $value);
439
    }
440
441 7
    private function _createAttributeWithValue($attributeName, $value)
442
    {
443 7
        $attribute = $this->_DOMDocument->createAttribute($attributeName);
444 7
        $attribute->value = $value;
445 7
        return $attribute;
446
    }
447
448 7
    public function createElementWithAttributes($elementName, $attributes, $value = '')
449
    {
450 7
        $element = $this->_createElement($elementName, $value);
451 7
        foreach ($attributes as $attributeName => $attributeValue) {
452 7
            $tmpAttr = $this->_createAttributeWithValue($attributeName, $attributeValue);
453 7
            $element->appendChild($tmpAttr);
454 7
        }
455 7
        return $element;
456
    }
457
458 7
    private function _saveXML()
459
    {
460 7
        $this->_generatedXML = $this->_DOMDocument->saveXML();
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->_DOMDocument->saveXML() of type string is incompatible with the declared type object<DOMDocument> of property $_generatedXML.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
461 7
    }
462
463
    public function getGeneratedXML()
464
    {
465
        return $this->_generatedXML;
466
    }
467
468
    public function render()
469
    {
470
        echo $this->_generatedXML;
471
    }
472
}
473