Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
/**
18
 * WSDL generator for the SOAP web service.
19
 *
20
 * @package    webservice_soap
21
 * @copyright  2016 Jun Pataleta
22
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 */
24
namespace webservice_soap;
25
 
26
/**
27
 * WSDL generator for the SOAP web service.
28
 *
29
 * @package    webservice_soap
30
 * @copyright  2016 Jun Pataleta
31
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
32
 */
33
class wsdl {
34
    /** Namespace URI for the WSDL framework. */
35
    const NS_WSDL = 'http://schemas.xmlsoap.org/wsdl/';
36
 
37
    /** Encoding namespace URI as defined by SOAP 1.1 */
38
    const NS_SOAP_ENC = 'http://schemas.xmlsoap.org/soap/encoding/';
39
 
40
    /** Namespace URI for the WSDL SOAP binding. */
41
    const NS_SOAP = 'http://schemas.xmlsoap.org/wsdl/soap/';
42
 
43
    /** Schema namespace URI as defined by XSD. */
44
    const NS_XSD = 'http://www.w3.org/2001/XMLSchema';
45
 
46
    /** WSDL namespace for the WSDL HTTP GET and POST binding. */
47
    const NS_SOAP_TRANSPORT = 'http://schemas.xmlsoap.org/soap/http';
48
 
49
    /** BINDING - string constant attached to the service class name to identify binding nodes. */
50
    const BINDING = 'Binding';
51
 
52
    /** IN - string constant attached to the function name to identify input nodes. */
53
    const IN = 'In';
54
 
55
    /** OUT - string constant attached to the function name to identify output nodes. */
56
    const OUT = 'Out';
57
 
58
    /** PORT - string constant attached to the service class name to identify port nodes. */
59
    const PORT = 'Port';
60
 
61
    /** SERVICE string constant attached to the service class name to identify service nodes. */
62
    const SERVICE = 'Service';
63
 
64
    /** @var string The name of the service class. */
65
    private $serviceclass;
66
 
67
    /** @var string The WSDL namespace. */
68
    private $namespace;
69
 
70
    /** @var array The WSDL's message nodes. */
71
    private $messagenodes;
72
 
73
    /** @var \SimpleXMLElement The WSDL's binding node. */
74
    private $nodebinding;
75
 
76
    /** @var \SimpleXMLElement The WSDL's definitions node. */
77
    private $nodedefinitions;
78
 
79
    /** @var \SimpleXMLElement The WSDL's portType node. */
80
    private $nodeporttype;
81
 
82
    /** @var \SimpleXMLElement The WSDL's service node. */
83
    private $nodeservice;
84
 
85
    /** @var \SimpleXMLElement The WSDL's types node. */
86
    private $nodetypes;
87
 
88
    /**
89
     * webservice_soap_wsdl constructor.
90
     *
91
     * @param string $serviceclass The service class' name.
92
     * @param string $namespace The WSDL namespace.
93
     */
94
    public function __construct($serviceclass, $namespace) {
95
        $this->serviceclass = $serviceclass;
96
        $this->namespace = $namespace;
97
 
98
        // Initialise definitions node.
99
        $this->nodedefinitions = new \SimpleXMLElement('<definitions />');
100
        $this->nodedefinitions->addAttribute('xmlns', self::NS_WSDL);
101
        $this->nodedefinitions->addAttribute('x:xmlns:tns', $namespace);
102
        $this->nodedefinitions->addAttribute('x:xmlns:soap', self::NS_SOAP);
103
        $this->nodedefinitions->addAttribute('x:xmlns:xsd', self::NS_XSD);
104
        $this->nodedefinitions->addAttribute('x:xmlns:soap-enc', self::NS_SOAP_ENC);
105
        $this->nodedefinitions->addAttribute('x:xmlns:wsdl', self::NS_WSDL);
106
        $this->nodedefinitions->addAttribute('name', $serviceclass);
107
        $this->nodedefinitions->addAttribute('targetNamespace', $namespace);
108
 
109
        // Initialise types node.
110
        $this->nodetypes = $this->nodedefinitions->addChild('types');
111
        $typeschema = $this->nodetypes->addChild('x:xsd:schema');
112
        $typeschema->addAttribute('targetNamespace', $namespace);
113
 
114
        // Initialise the portType node.
115
        $this->nodeporttype = $this->nodedefinitions->addChild('portType');
116
        $this->nodeporttype->addAttribute('name', $serviceclass . self::PORT);
117
 
118
        // Initialise the binding node.
119
        $this->nodebinding = $this->nodedefinitions->addChild('binding');
120
        $this->nodebinding->addAttribute('name', $serviceclass . self::BINDING);
121
        $this->nodebinding->addAttribute('type', 'tns:' . $serviceclass . self::PORT);
122
        $soapbinding = $this->nodebinding->addChild('x:soap:binding');
123
        $soapbinding->addAttribute('style', 'rpc');
124
        $soapbinding->addAttribute('transport', self::NS_SOAP_TRANSPORT);
125
 
126
        // Initialise the service node.
127
        $this->nodeservice = $this->nodedefinitions->addChild('service');
128
        $this->nodeservice->addAttribute('name', $serviceclass . self::SERVICE);
129
        $serviceport = $this->nodeservice->addChild('port');
130
        $serviceport->addAttribute('name', $serviceclass . self::PORT);
131
        $serviceport->addAttribute('binding', 'tns:' . $serviceclass . self::BINDING);
132
        $soapaddress = $serviceport->addChild('x:soap:address');
133
        $soapaddress->addAttribute('location', $namespace);
134
 
135
        // Initialise message nodes.
136
        $this->messagenodes = array();
137
    }
138
 
139
    /**
140
     * Adds a complex type to the WSDL.
141
     *
142
     * @param string $classname The complex type's class name.
143
     * @param array $properties An associative array containing the properties of the complex type class.
144
     */
145
    public function add_complex_type($classname, $properties) {
146
        $typeschema = $this->nodetypes->children();
147
        // Append the complex type.
148
        $complextype = $typeschema->addChild('x:xsd:complexType');
149
        $complextype->addAttribute('name', $classname);
150
        $child = $complextype->addChild('x:xsd:all');
151
        foreach ($properties as $name => $options) {
152
            $param = $child->addChild('x:xsd:element');
153
            $param->addAttribute('name', $name);
154
            $param->addAttribute('type', $this->get_soap_type($options['type']));
155
            if (!empty($options['nillable'])) {
156
                $param->addAttribute('nillable', 'true');
157
            }
158
        }
159
    }
160
 
161
    /**
162
     * Registers the external service method to the WSDL.
163
     *
164
     * @param string $functionname The name of the web service function to be registered.
165
     * @param array $inputparams Contains the function's input parameters with their associated types.
166
     * @param array $outputparams Contains the function's output parameters with their associated types.
167
     * @param string $documentation The function's description.
168
     */
169
    public function register($functionname, $inputparams = array(), $outputparams = array(), $documentation = '') {
170
        // Process portType operation nodes.
171
        $porttypeoperation = $this->nodeporttype->addChild('operation');
172
        $porttypeoperation->addAttribute('name', $functionname);
173
        // Documentation node.
174
        $porttypeoperation->addChild('documentation', $documentation);
175
 
176
        // Process binding operation nodes.
177
        $bindingoperation = $this->nodebinding->addChild('operation');
178
        $bindingoperation->addAttribute('name', $functionname);
179
        $soapoperation = $bindingoperation->addChild('x:soap:operation');
180
        $soapoperation->addAttribute('soapAction', $this->namespace . '#' . $functionname);
181
 
182
        // Input nodes.
183
        $this->process_params($functionname, $porttypeoperation, $bindingoperation, $inputparams);
184
 
185
        // Output nodes.
186
        $this->process_params($functionname, $porttypeoperation, $bindingoperation, $outputparams, true);
187
    }
188
 
189
    /**
190
     * Outputs the WSDL in XML format.
191
     *
192
     * @return mixed The string value of the WSDL in XML format. False, otherwise.
193
     */
194
    public function to_xml() {
195
        // Return WSDL in XML format.
196
        return $this->nodedefinitions->asXML();
197
    }
198
 
199
    /**
200
     * Utility method that returns the encoded SOAP type based on the given type string.
201
     *
202
     * @param string $type The input type string.
203
     * @return string The encoded type for the WSDL.
204
     */
205
    private function get_soap_type($type) {
206
        switch($type) {
207
            case 'int':
208
            case 'double':
209
            case 'string':
210
                return 'xsd:' . $type;
211
            case 'array':
212
                return 'soap-enc:Array';
213
            default:
214
                return 'tns:' . $type;
215
        }
216
    }
217
 
218
    /**
219
     * Utility method that creates input/output nodes from input/output params.
220
     *
221
     * @param string $functionname The name of the function being registered.
222
     * @param \SimpleXMLElement $porttypeoperation The port type operation node.
223
     * @param \SimpleXMLElement $bindingoperation The binding operation node.
224
     * @param array $params The function's input/output parameters.
225
     * @param bool $isoutput Flag to indicate if the nodes to be generated are for input or for output.
226
     */
227
    private function process_params($functionname, \SimpleXMLElement $porttypeoperation, \SimpleXMLElement $bindingoperation,
228
                                    array $params = null, $isoutput = false) {
229
        // Do nothing if parameter array is empty.
230
        if (empty($params)) {
231
            return;
232
        }
233
 
234
        $postfix = self::IN;
235
        $childtype = 'input';
236
        if ($isoutput) {
237
            $postfix = self::OUT;
238
            $childtype = 'output';
239
        }
240
 
241
        // For portType operation node.
242
        $child = $porttypeoperation->addChild($childtype);
243
        $child->addAttribute('message', 'tns:' . $functionname . $postfix);
244
 
245
        // For binding operation node.
246
        $child = $bindingoperation->addChild($childtype);
247
        $soapbody = $child->addChild('x:soap:body');
248
        $soapbody->addAttribute('use', 'encoded');
249
        $soapbody->addAttribute('encodingStyle', self::NS_SOAP_ENC);
250
        $soapbody->addAttribute('namespace', $this->namespace);
251
 
252
        // Process message nodes.
253
        $messagein = $this->nodedefinitions->addChild('message');
254
        $messagein->addAttribute('name', $functionname . $postfix);
255
        foreach ($params as $name => $options) {
256
            $part = $messagein->addChild('part');
257
            $part->addAttribute('name', $name);
258
            $part->addAttribute('type', $this->get_soap_type($options['type']));
259
        }
260
    }
261
}