Current File : //opt/RZphp72/includes/XML/RPC2/Server/Method.php |
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
// LICENSE AGREEMENT. If folded, press za here to unfold and read license {{{
/**
* +-----------------------------------------------------------------------------+
* | Copyright (c) 2004-2006 Sergio Gonalves Carvalho |
* +-----------------------------------------------------------------------------+
* | This file is part of XML_RPC2. |
* | |
* | XML_RPC2 is free software; you can redistribute it and/or modify |
* | it under the terms of the GNU Lesser General Public License as published by |
* | the Free Software Foundation; either version 2.1 of the License, or |
* | (at your option) any later version. |
* | |
* | XML_RPC2 is distributed in the hope that it will be useful, |
* | but WITHOUT ANY WARRANTY; without even the implied warranty of |
* | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
* | GNU Lesser General Public License for more details. |
* | |
* | You should have received a copy of the GNU Lesser General Public License |
* | along with XML_RPC2; if not, write to the Free Software |
* | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
* | 02111-1307 USA |
* +-----------------------------------------------------------------------------+
* | Author: Sergio Carvalho <sergio.carvalho@portugalmail.com> |
* +-----------------------------------------------------------------------------+
*
* @category XML
* @package XML_RPC2
* @author Sergio Carvalho <sergio.carvalho@portugalmail.com>
* @copyright 2004-2006 Sergio Carvalho
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version CVS: $Id$
* @link http://pear.php.net/package/XML_RPC2
*/
// }}}
// dependencies {{{
require_once 'XML/RPC2/Exception.php';
// }}}
/**
* Class representing an XML-RPC exported method.
*
* This class is used internally by XML_RPC2_Server. External users of the
* package should not need to ever instantiate XML_RPC2_Server_Method
*
* @category XML
* @package XML_RPC2
* @author Sergio Carvalho <sergio.carvalho@portugalmail.com>
* @copyright 2004-2006 Sergio Carvalho
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear.php.net/package/XML_RPC2
*/
class XML_RPC2_Server_Method
{
// {{{ properties
/**
* Method signature parameters
*
* @var array
*/
private $_parameters;
/**
* Method signature return type
*
* @var string
*/
private $_returns ;
/**
* Method help, for introspection
*
* @var string
*/
private $_help;
/**
* internalMethod field : method name in PHP-land
*
* @var string
*/
private $_internalMethod;
/**
* hidden field : true if the method is hidden
*
* @var boolean
*/
private $_hidden;
/**
* name Field : external method name
*
* @var string
*/
private $_name;
/**
* Number of required parameters
*
* @var int
*/
private $_numberOfRequiredParameters;
// }}}
// {{{ getInternalMethod()
/**
* internalMethod getter
*
* @return string internalMethod
*/
public function getInternalMethod()
{
return $this->_internalMethod;
}
// }}}
// {{{ isHidden()
/**
* hidden getter
*
* @return boolean hidden value
*/
public function isHidden()
{
return $this->_hidden;
}
// }}}
// {{{ getName()
/**
* name getter
*
* @return string name
*/
public function getName()
{
return $this->_name;
}
// }}}
// {{{ constructor
/**
* Create a new XML-RPC method by introspecting a PHP method
*
* @param ReflectionMethod The PHP method to introspect
* @param string default prefix
*/
public function __construct(ReflectionMethod $method, $defaultPrefix)
{
$hidden = false;
$docs = $method->getDocComment();
if (!$docs) {
$hidden = true;
}
$docs = explode("\n", $docs);
$parameters = array();
$methodname = null;
$returns = 'mixed';
$shortdesc = '';
$paramcount = -1;
$prefix = $defaultPrefix;
// Extract info from Docblock
$paramDocs = array();
foreach ($docs as $i => $doc) {
$doc = trim($doc, " \r\t/*");
if (strlen($doc) && strpos($doc, '@') !== 0) {
if ($shortdesc) {
$shortdesc .= "\n";
}
$shortdesc .= $doc;
continue;
}
if (strpos($doc, '@xmlrpc.hidden') === 0) {
$hidden = true;
}
if ((strpos($doc, '@xmlrpc.prefix') === 0) && preg_match('/@xmlrpc.prefix( )*(.*)/', $doc, $matches)) {
$prefix = $matches[2];
}
if ((strpos($doc, '@xmlrpc.methodname') === 0) && preg_match('/@xmlrpc.methodname( )*(.*)/', $doc, $matches)) {
$methodname = $matches[2];
}
if (strpos($doc, '@param') === 0) { // Save doctag for usage later when filling parameters
$paramDocs[] = $doc;
}
if (strpos($doc, '@return') === 0) {
$param = preg_split("/\s+/", $doc);
if (isset($param[1])) {
$param = $param[1];
$returns = $param;
}
}
}
$this->_numberOfRequiredParameters = $method->getNumberOfRequiredParameters(); // we don't use isOptional() because of bugs in the reflection API
// Fill in info for each method parameter
foreach ($method->getParameters() as $parameterIndex => $parameter) {
// Parameter defaults
$newParameter = array('type' => 'mixed');
// Attempt to extract type and doc from docblock
if (array_key_exists($parameterIndex, $paramDocs) &&
preg_match('/@param\s+(\S+)(\s+(.+))/', $paramDocs[$parameterIndex], $matches)) {
if (strpos($matches[1], '|')) {
$newParameter['type'] = XML_RPC2_Server_Method::_limitPHPType(explode('|', $matches[1]));
} else {
$newParameter['type'] = XML_RPC2_Server_Method::_limitPHPType($matches[1]);
}
$tmp = '$' . $parameter->getName() . ' ';
if (strpos($matches[3], '$' . $tmp) === 0) {
$newParameter['doc'] = $matches[3];
} else {
// The phpdoc comment is something like "@param string $param description of param"
// Let's keep only "description of param" as documentation (remove $param)
$newParameter['doc'] = substr($matches[3], strlen($tmp));
}
$newParameter['doc'] = preg_replace('_^\s*_', '', $newParameter['doc']);
}
$parameters[$parameter->getName()] = $newParameter;
}
if (is_null($methodname)) {
$methodname = $prefix . $method->getName();
}
$this->_internalMethod = $method->getName();
$this->_parameters = $parameters;
$this->_returns = $returns;
$this->_help = $shortdesc;
$this->_name = $methodname;
$this->_hidden = $hidden;
}
// }}}
// {{{ matchesSignature()
/**
* Check if method matches provided call signature
*
* Compare the provided call signature with this methods' signature and
* return true iff they match.
*
* @param string Signature to compare method name
* @param array Array of parameter values for method call.
* @return boolean True if call matches signature, false otherwise
*/
public function matchesSignature($methodName, $callParams)
{
if ($methodName != $this->_name) return false;
if (count($callParams) < $this->_numberOfRequiredParameters) return false;
if (count($callParams) > $this->_parameters) return false;
$paramIndex = 0;
foreach($this->_parameters as $param) {
$paramIndex++;
if ($paramIndex <= $this->_numberOfRequiredParameters) {
// the parameter is not optional
$callParamType = XML_RPC2_Server_Method::_limitPHPType(gettype($callParams[$paramIndex-1]));
if ((!($param['type'] == 'mixed')) and ($param['type'] != $callParamType)) {
return false;
}
}
}
return true;
}
// }}}
// {{{ getHTMLSignature()
/**
* Return a HTML signature of the method
*
* @return string HTML signature
*/
public function getHTMLSignature()
{
$name = $this->_name;
$returnType = $this->_returns;
$result = "<span class=\"type\">($returnType)</span> ";
$result .= "<span class=\"name\">$name</span>";
$result .= "<span class=\"other\">(</span>";
$first = true;
$nbr = 0;
while (list($name, $parameter) = each($this->_parameters)) {
$nbr++;
if ($nbr == $this->_numberOfRequiredParameters + 1) {
$result .= "<span class=\"other\"> [ </span>";
}
if ($first) {
$first = false;
} else {
$result .= ', ';
}
$type = $parameter['type'];
$result .= "<span class=\"paratype\">($type) </span>";
$result .= "<span class=\"paraname\">$name</span>";
}
reset($this->_parameters);
if ($nbr > $this->_numberOfRequiredParameters) {
$result .= "<span class=\"other\"> ] </span>";
}
$result .= "<span class=\"other\">)</span>";
return $result;
}
// }}}
// {{{ autoDocument()
/**
* Print a complete HTML description of the method
*/
public function autoDocument()
{
$name = $this->getName();
$signature = $this->getHTMLSignature();
$id = md5($name);
$help = nl2br(htmlentities($this->_help));
print " <h3><a name=\"$id\">$signature</a></h3>\n";
print " <p><b>Description :</b></p>\n";
print " <div class=\"description\">\n";
print " $help\n";
print " </div>\n";
if (count($this->_parameters)>0) {
print " <p><b>Parameters : </b></p>\n";
if (count($this->_parameters)>0) {
print " <table>\n";
print " <tr><td><b>Type</b></td><td><b>Name</b></td><td><b>Documentation</b></td></tr>\n";
while (list($name, $parameter) = each($this->_parameters)) {
$type = $parameter['type'];
$doc = isset($parameter['doc']) ? htmlentities($parameter['doc']) : 'Method is not documented. No PHPDoc block was found associated with the method in the source code.';
print " <tr><td>$type</td><td>$name</td><td>$doc</td></tr>\n";
}
reset($this->_parameters);
print " </table>\n";
}
}
}
// }}}
// {{{ _limitPHPType()
/**
* standardise type names between gettype php function and phpdoc comments (and limit to xmlrpc available types)
*
* @var string $type
* @return string standardised type
*/
private static function _limitPHPType($type)
{
$tmp = strtolower($type);
$convertArray = array(
'int' => 'integer',
'i4' => 'integer',
'integer' => 'integer',
'string' => 'string',
'str' => 'string',
'char' => 'string',
'bool' => 'boolean',
'boolean' => 'boolean',
'array' => 'array',
'float' => 'double',
'double' => 'double',
'array' => 'array',
'struct' => 'array',
'assoc' => 'array',
'structure' => 'array',
'datetime' => 'mixed',
'datetime.iso8601' => 'mixed',
'iso8601' => 'mixed',
'base64' => 'string'
);
if (isset($convertArray[$tmp])) {
return $convertArray[$tmp];
}
return 'mixed';
}
}
?>