Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
 
3
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
4
 
5
// LICENSE AGREEMENT. If folded, press za here to unfold and read license {{{
6
 
7
/**
8
* +-----------------------------------------------------------------------------+
9
* | Copyright (c) 2004-2006 Sergio Gonalves Carvalho                                |
10
* +-----------------------------------------------------------------------------+
11
* | This file is part of XML_RPC2.                                              |
12
* |                                                                             |
13
* | XML_RPC2 is free software; you can redistribute it and/or modify            |
14
* | it under the terms of the GNU Lesser General Public License as published by |
15
* | the Free Software Foundation; either version 2.1 of the License, or         |
16
* | (at your option) any later version.                                         |
17
* |                                                                             |
18
* | XML_RPC2 is distributed in the hope that it will be useful,                 |
19
* | but WITHOUT ANY WARRANTY; without even the implied warranty of              |
20
* | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               |
21
* | GNU Lesser General Public License for more details.                         |
22
* |                                                                             |
23
* | You should have received a copy of the GNU Lesser General Public License    |
24
* | along with XML_RPC2; if not, write to the Free Software                     |
25
* | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA                    |
26
* | 02111-1307 USA                                                              |
27
* +-----------------------------------------------------------------------------+
28
* | Author: Sergio Carvalho <sergio.carvalho@portugalmail.com>                  |
29
* +-----------------------------------------------------------------------------+
30
*
31
* @category   XML
32
* @package    XML_RPC2
33
* @author     Sergio Carvalho <sergio.carvalho@portugalmail.com>
34
* @copyright  2004-2006 Sergio Carvalho
35
* @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
36
* @version    CVS: $Id: Method.php 308638 2011-02-24 20:32:21Z sergiosgc $
37
* @link       http://pear.php.net/package/XML_RPC2
38
*/
39
 
40
// }}}
41
 
42
// dependencies {{{
43
require_once 'XML/RPC2/Exception.php';
44
// }}}
45
 
46
/**
47
 * Class representing an XML-RPC exported method.
48
 *
49
 * This class is used internally by XML_RPC2_Server. External users of the
50
 * package should not need to ever instantiate XML_RPC2_Server_Method
51
 *
52
 * @category   XML
53
 * @package    XML_RPC2
54
 * @author     Sergio Carvalho <sergio.carvalho@portugalmail.com>
55
 * @copyright  2004-2006 Sergio Carvalho
56
 * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
57
 * @link       http://pear.php.net/package/XML_RPC2
58
 */
59
class XML_RPC2_Server_Method
60
{
61
    // {{{ properties
62
 
63
    /**
64
     * Method signature parameters
65
     *
66
     * @var array
67
     */
68
    private $_parameters;
69
 
70
    /**
71
     * Method signature return type
72
     *
73
     * @var string
74
     */
75
    private $_returns ;
76
 
77
    /**
78
     * Method help, for introspection
79
     *
80
     * @var string
81
     */
82
    private $_help;
83
 
84
    /**
85
     * internalMethod field : method name in PHP-land
86
     *
87
     * @var string
88
     */
89
    private $_internalMethod;
90
 
91
    /**
92
     * hidden field : true if the method is hidden
93
     *
94
     * @var boolean
95
     */
96
    private $_hidden;
97
 
98
    /**
99
     * name Field : external method name
100
     *
101
     * @var string
102
     */
103
    private $_name;
104
 
105
    /**
106
     * Number of required parameters
107
     *
108
     * @var int
109
     */
110
    private $_numberOfRequiredParameters;
111
 
112
    // }}}
113
    // {{{ getInternalMethod()
114
 
115
    /**
116
     * internalMethod getter
117
     *
118
     * @return string internalMethod
119
     */
120
    public function getInternalMethod()
121
    {
122
        return $this->_internalMethod;
123
    }
124
 
125
    // }}}
126
    // {{{ isHidden()
127
 
128
    /**
129
     * hidden getter
130
     *
131
     * @return boolean hidden value
132
     */
133
    public function isHidden()
134
    {
135
        return $this->_hidden;
136
    }
137
 
138
    // }}}
139
    // {{{ getName()
140
 
141
    /**
142
     * name getter
143
     *
144
     * @return string name
145
     */
146
    public function getName()
147
    {
148
        return $this->_name;
149
    }
150
 
151
    // }}}
152
    // {{{ constructor
153
 
154
    /**
155
     * Create a new XML-RPC method by introspecting a PHP method
156
     *
157
     * @param ReflectionMethod The PHP method to introspect
158
     * @param string default prefix
159
     */
160
    public function __construct(ReflectionMethod $method, $defaultPrefix)
161
    {
162
        $hidden = false;
163
        $docs = $method->getDocComment();
164
        if (!$docs) {
165
            $hidden = true;
166
        }
167
        $docs = explode("\n", $docs);
168
 
169
        $parameters = array();
170
        $methodname = null;
171
        $returns = 'mixed';
172
        $shortdesc = '';
173
        $paramcount = -1;
174
        $prefix = $defaultPrefix;
175
 
176
        // Extract info from Docblock
177
        $paramDocs = array();
178
        foreach ($docs as $i => $doc) {
179
            $doc = trim($doc, " \r\t/*");
180
            if (strlen($doc) && strpos($doc, '@') !== 0) {
181
                if ($shortdesc) {
182
                    $shortdesc .= "\n";
183
                }
184
                $shortdesc .= $doc;
185
                continue;
186
            }
187
            if (strpos($doc, '@xmlrpc.hidden') === 0) {
188
                $hidden = true;
189
            }
190
            if ((strpos($doc, '@xmlrpc.prefix') === 0) && preg_match('/@xmlrpc.prefix( )*(.*)/', $doc, $matches)) {
191
                $prefix = $matches[2];
192
            }
193
            if ((strpos($doc, '@xmlrpc.methodname') === 0) && preg_match('/@xmlrpc.methodname( )*(.*)/', $doc, $matches)) {
194
                $methodname = $matches[2];
195
            }
196
            if (strpos($doc, '@param') === 0) { // Save doctag for usage later when filling parameters
197
                $paramDocs[] = $doc;
198
            }
199
 
200
            if (strpos($doc, '@return') === 0) {
201
                $param = preg_split("/\s+/", $doc);
202
                if (isset($param[1])) {
203
                    $param = $param[1];
204
                    $returns = $param;
205
                }
206
            }
207
        }
208
        $this->_numberOfRequiredParameters = $method->getNumberOfRequiredParameters(); // we don't use isOptional() because of bugs in the reflection API
209
        // Fill in info for each method parameter
210
        foreach ($method->getParameters() as $parameterIndex => $parameter) {
211
            // Parameter defaults
212
            $newParameter = array('type' => 'mixed');
213
 
214
            // Attempt to extract type and doc from docblock
215
            if (array_key_exists($parameterIndex, $paramDocs) &&
216
                preg_match('/@param\s+(\S+)(\s+(.+))/', $paramDocs[$parameterIndex], $matches)) {
217
                if (strpos($matches[1], '|')) {
218
                    $newParameter['type'] = XML_RPC2_Server_Method::_limitPHPType(explode('|', $matches[1]));
219
                } else {
220
                    $newParameter['type'] = XML_RPC2_Server_Method::_limitPHPType($matches[1]);
221
                }
222
                $tmp = '$' . $parameter->getName() . ' ';
223
                if (strpos($matches[3], '$' . $tmp) === 0) {
224
                    $newParameter['doc'] = $matches[3];
225
                } else {
226
                    // The phpdoc comment is something like "@param string $param description of param"
227
                    // Let's keep only "description of param" as documentation (remove $param)
228
                    $newParameter['doc'] = substr($matches[3], strlen($tmp));
229
                }
230
                $newParameter['doc'] = preg_replace('_^\s*_', '', $newParameter['doc']);
231
            }
232
 
233
            $parameters[$parameter->getName()] = $newParameter;
234
        }
235
 
236
        if (is_null($methodname)) {
237
            $methodname = $prefix . $method->getName();
238
        }
239
 
240
        $this->_internalMethod = $method->getName();
241
        $this->_parameters = $parameters;
242
        $this->_returns  = $returns;
243
        $this->_help = $shortdesc;
244
        $this->_name = $methodname;
245
        $this->_hidden = $hidden;
246
    }
247
 
248
    // }}}
249
    // {{{ matchesSignature()
250
 
251
    /**
252
     * Check if method matches provided call signature
253
     *
254
     * Compare the provided call signature with this methods' signature and
255
     * return true iff they match.
256
     *
257
     * @param  string Signature to compare method name
258
     * @param  array  Array of parameter values for method call.
259
     * @return boolean True if call matches signature, false otherwise
260
     */
261
    public function matchesSignature($methodName, $callParams)
262
    {
263
        if ($methodName != $this->_name) return false;
264
        if (count($callParams) < $this->_numberOfRequiredParameters) return false;
265
        if (count($callParams) > $this->_parameters) return false;
266
        $paramIndex = 0;
267
        foreach($this->_parameters as $param) {
268
            $paramIndex++;
269
            if ($paramIndex <= $this->_numberOfRequiredParameters) {
270
                // the parameter is not optional
271
                $callParamType = XML_RPC2_Server_Method::_limitPHPType(gettype($callParams[$paramIndex-1]));
272
                if ((!($param['type'] == 'mixed')) and ($param['type'] != $callParamType)) {
273
                    return false;
274
                }
275
            }
276
        }
277
        return true;
278
    }
279
 
280
    // }}}
281
    // {{{ getHTMLSignature()
282
 
283
    /**
284
     * Return a HTML signature of the method
285
     *
286
     * @return string HTML signature
287
     */
288
    public function getHTMLSignature()
289
    {
290
        $name = $this->_name;
291
        $returnType = $this->_returns;
292
        $result  = "<span class=\"type\">($returnType)</span> ";
293
        $result .= "<span class=\"name\">$name</span>";
294
        $result  .= "<span class=\"other\">(</span>";
295
        $first = true;
296
        $nbr = 0;
297
        while (list($name, $parameter) = each($this->_parameters)) {
298
            $nbr++;
299
            if ($nbr == $this->_numberOfRequiredParameters + 1) {
300
                $result .= "<span class=\"other\"> [ </span>";
301
            }
302
            if ($first) {
303
                $first = false;
304
            } else {
305
                $result .= ', ';
306
            }
307
            $type = $parameter['type'];
308
            $result .= "<span class=\"paratype\">($type) </span>";
309
            $result .= "<span class=\"paraname\">$name</span>";
310
        }
311
        reset($this->_parameters);
312
        if ($nbr > $this->_numberOfRequiredParameters) {
313
            $result .= "<span class=\"other\"> ] </span>";
314
        }
315
        $result .= "<span class=\"other\">)</span>";
316
        return $result;
317
    }
318
 
319
    // }}}
320
    // {{{ autoDocument()
321
    /**
322
     * Print a complete HTML description of the method
323
     */
324
    public function autoDocument()
325
    {
326
        $name = $this->getName();
327
        $signature = $this->getHTMLSignature();
328
        $id = md5($name);
329
        $help = nl2br(htmlentities($this->_help));
330
        print "      <h3><a name=\"$id\">$signature</a></h3>\n";
331
        print "      <p><b>Description :</b></p>\n";
332
        print "      <div class=\"description\">\n";
333
        print "        $help\n";
334
        print "      </div>\n";
335
        if (count($this->_parameters)>0) {
336
            print "      <p><b>Parameters : </b></p>\n";
337
            if (count($this->_parameters)>0) {
338
                print "      <table>\n";
339
                print "        <tr><td><b>Type</b></td><td><b>Name</b></td><td><b>Documentation</b></td></tr>\n";
340
                while (list($name, $parameter) = each($this->_parameters)) {
341
                    $type = $parameter['type'];
342
                    $doc = isset($parameter['doc']) ? htmlentities($parameter['doc']) : 'Method is not documented. No PHPDoc block was found associated with the method in the source code.';
343
                    print "        <tr><td>$type</td><td>$name</td><td>$doc</td></tr>\n";
344
                }
345
                reset($this->_parameters);
346
                print "      </table>\n";
347
            }
348
        }
349
    }
350
 
351
    // }}}
352
    // {{{ _limitPHPType()
353
    /**
354
     * standardise type names between gettype php function and phpdoc comments (and limit to xmlrpc available types)
355
     *
356
     * @var string $type
357
     * @return string standardised type
358
     */
359
    private static function _limitPHPType($type)
360
    {
361
        $tmp = strtolower($type);
362
        $convertArray = array(
363
            'int' => 'integer',
364
            'i4' => 'integer',
365
            'integer' => 'integer',
366
            'string' => 'string',
367
            'str' => 'string',
368
            'char' => 'string',
369
            'bool' => 'boolean',
370
            'boolean' => 'boolean',
371
            'array' => 'array',
372
            'float' => 'double',
373
            'double' => 'double',
374
            'array' => 'array',
375
            'struct' => 'array',
376
            'assoc' => 'array',
377
            'structure' => 'array',
378
            'datetime' => 'mixed',
379
            'datetime.iso8601' => 'mixed',
380
            'iso8601' => 'mixed',
381
            'base64' => 'string'
382
        );
383
        if (isset($convertArray[$tmp])) {
384
            return $convertArray[$tmp];
385
        }
386
        return 'mixed';
387
    }
388
 
389
}
390
 
391
?>