Skip to content
This repository has been archived by the owner on Apr 28, 2020. It is now read-only.

Commit

Permalink
Merge branch 'hotfix/xmlrpc' of https://github.com/sasezaki/zf2 into …
Browse files Browse the repository at this point in the history
…hotfix/xmlrpc-zf1-sync
  • Loading branch information
Show file tree
Hide file tree
Showing 6 changed files with 302 additions and 69 deletions.
29 changes: 19 additions & 10 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ public function doRequest($request, $response = null)
}

$this->_lastResponse = $response;
$this->_lastResponse->loadXml($httpResponse->getBody());
$this->_lastResponse->loadXml(trim($httpResponse->getBody()));
}

/**
Expand Down Expand Up @@ -296,21 +296,30 @@ public function call($method, $params=array())
$params = array($params);
}
foreach ($params as $key => $param) {

if ($param instanceof Value) {
continue;
}

$type = Value::AUTO_DETECT_TYPE;
foreach ($signatures as $signature) {
if (!is_array($signature)) {
continue;
if (count($signatures) > 1) {
$type = Value::getXmlRpcTypeByValue($param);
foreach ($signatures as $signature) {
if (!is_array($signature)) {
continue;
}
if (isset($signature['parameters'][$key])) {
if ($signature['parameters'][$key] == $type) {
break;
}
}
}
} elseif (isset($signatures[0]['parameters'][$key])) {
$type = $signatures[0]['parameters'][$key];
} else {
$type = null;
}

if (isset($signature['parameters'][$key])) {
$type = $signature['parameters'][$key];
$type = in_array($type, $validTypes) ? $type : Value::AUTO_DETECT_TYPE;
}
if (empty($type) || !in_array($type, $validTypes)) {
$type = Value::AUTO_DETECT_TYPE;
}

$params[$key] = Value::getXmlRpcValue($param, $type);
Expand Down
122 changes: 79 additions & 43 deletions src/Value.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@

namespace Zend\XmlRpc;

use DateTime;
use Zend\Date;
use Zend\Math\BigInteger;

/**
* Represent a native XML-RPC value entity, used as parameters for the methods
* called by the Zend\XmlRpc\Client object and as the return value for those calls.
Expand All @@ -41,7 +45,7 @@ abstract class Value
* The native XML-RPC representation of this object's value
*
* If the native type of this object is array or struct, this will be an array
* of Zend_XmlRpc_Value objects
* of Value objects
*/
protected $_value;

Expand Down Expand Up @@ -89,7 +93,7 @@ abstract class Value
const XMLRPC_TYPE_APACHENIL = 'ex:nil';

/**
* Get the native XML-RPC type (the type is one of the Zend_XmlRpc_Value::XMLRPC_TYPE_* constants)
* Get the native XML-RPC type (the type is one of the Value::XMLRPC_TYPE_* constants)
*
* @return string
*/
Expand Down Expand Up @@ -173,12 +177,12 @@ public function generateXml()
}

/**
* Creates a Zend_XmlRpc_Value* object, representing a native XML-RPC value
* Creates a Value* object, representing a native XML-RPC value
* A XmlRpcValue object can be created in 3 ways:
* 1. Autodetecting the native type out of a PHP variable
* (if $type is not set or equal to Zend_XmlRpc_Value::AUTO_DETECT_TYPE)
* 2. By specifing the native type ($type is one of the Zend_XmlRpc_Value::XMLRPC_TYPE_* constants)
* 3. From a XML string ($type is set to Zend_XmlRpc_Value::XML_STRING)
* (if $type is not set or equal to Value::AUTO_DETECT_TYPE)
* 2. By specifing the native type ($type is one of the Value::XMLRPC_TYPE_* constants)
* 3. From a XML string ($type is set to Value::XML_STRING)
*
* By default the value type is autodetected according to it's PHP type
*
Expand Down Expand Up @@ -238,72 +242,104 @@ public static function getXmlRpcValue($value, $type = self::AUTO_DETECT_TYPE)
}
}

/**
* Get XML-RPC type for a PHP native variable
*
* @static
* @param mixed $value
* @return string
*/
public static function getXmlRpcTypeByValue($value)
{
if (is_object($value)) {
if ($value instanceof Value) {
return $value->getType();
} elseif (($value instanceof Date\Date) || ($value instanceof DateTime)) {
return self::XMLRPC_TYPE_DATETIME;
}
return self::getXmlRpcTypeByValue(get_object_vars($value));
} elseif (is_array($value)) {
if (!empty($value) && is_array($value) && (array_keys($value) !== range(0, count($value) - 1))) {
return self::XMLRPC_TYPE_STRUCT;
}
return self::XMLRPC_TYPE_ARRAY;
} elseif (is_int($value)) {
return ($value > PHP_INT_MAX) ? self::XMLRPC_TYPE_I8 : self::XMLRPC_TYPE_INTEGER;
} elseif (is_double($value)) {
return self::XMLRPC_TYPE_DOUBLE;
} elseif (is_bool($value)) {
return self::XMLRPC_TYPE_BOOLEAN;
} elseif (is_null($value)) {
return self::XMLRPC_TYPE_NIL;
} elseif (is_string($value)) {
return self::XMLRPC_TYPE_STRING;
}
throw new Exception\InvalidArgumentException(sprintf(
'No matching XMLRPC type found for php type %s.',
gettype($value)
));
}

/**
* Transform a PHP native variable into a XML-RPC native value
*
* @param mixed $value The PHP variable for convertion
*
* @return Zend\XmlRpc\Value
* @return Value
* @static
*/
protected static function _phpVarToNativeXmlRpc($value)
{
switch (gettype($value)) {
case 'object':
// Check to see if it's an XmlRpc value
if ($value instanceof Value) {
return $value;
}

if ($value instanceof \Zend\Math\BigInteger) {
return new Value\BigInteger($value);
}
// @see http://framework.zend.com/issues/browse/ZF-8623
if (is_object($value)) {
if ($value instanceof Value) {
return $value;
}
if ($value instanceof BigInteger) {
throw new Exception\InvalidArgumentException(
'Using Zend\Math\BigInteger to get an ' .
'instance of Value_BigInteger is not ' .
'available anymore.'
);
}
}

if ($value instanceof \Zend\Date\Date or $value instanceof \DateTime) {
return new Value\DateTime($value);
}
switch (self::getXmlRpcTypeByValue($value))
{
case self::XMLRPC_TYPE_DATETIME:
return new Value\DateTime($value);

// Otherwise, we convert the object into a struct
$value = get_object_vars($value);
// Break intentionally omitted
case 'array':
// Default native type for a PHP array (a simple numeric array) is 'array'
$obj = 'Zend\\XmlRpc\\Value\\ArrayValue';
case self::XMLRPC_TYPE_ARRAY:
return new Value\ArrayValue($value);

// Determine if this is an associative array
if (!empty($value) && is_array($value) && (array_keys($value) !== range(0, count($value) - 1))) {
$obj = 'Zend\\XmlRpc\\Value\\Struct';
}
return new $obj($value);
case self::XMLRPC_TYPE_STRUCT:
return new Value\Struct($value);

case 'integer':
case self::XMLRPC_TYPE_INTEGER:
return new Value\Integer($value);

case 'double':
case self::XMLRPC_TYPE_DOUBLE:
return new Value\Double($value);

case 'boolean':
case self::XMLRPC_TYPE_BOOLEAN:
return new Value\Boolean($value);

case 'NULL':
case 'null':
return new Value\Nil();
case self::XMLRPC_TYPE_NIL:
return new Value\Nil;

case 'string':
case self::XMLRPC_TYPE_STRING:
// Fall through to the next case
default:
// If type isn't identified (or identified as string), it treated as string
return new Value\String($value);
}
}


/**
* Transform an XML string into a XML-RPC native value
*
* @param string|SimpleXMLElement $xml A SimpleXMLElement object represent the XML string
* It can be also a valid XML string for convertion
* It can be also a valid XML string for convertion
*
* @return Zend\XmlRpc\Value\Value
* @static
Expand Down Expand Up @@ -363,7 +399,7 @@ protected static function _xmlStringToNativeXmlRpc($xml)
}
$values = array();
// Parse all the elements of the array from the XML string
// (simple xml element) to Zend_XmlRpc_Value objects
// (simple xml element) to Value objects
foreach ($data->value as $element) {
$values[] = self::_xmlStringToNativeXmlRpc($element);
}
Expand All @@ -372,13 +408,13 @@ protected static function _xmlStringToNativeXmlRpc($xml)
case self::XMLRPC_TYPE_STRUCT:
$values = array();
// Parse all the memebers of the struct from the XML string
// (simple xml element) to Zend_XmlRpc_Value objects
// (simple xml element) to Value objects
foreach ($value->member as $member) {
// @todo? If a member doesn't have a <value> tag, we don't add it to the struct
// Maybe we want to throw an exception here ?
if (!isset($member->value) or !isset($member->name)) {
continue;
//throw new Zend_XmlRpc_Value_Exception('Member of the '. self::XMLRPC_TYPE_STRUCT .' XML-RPC native type must contain a VALUE tag');
//throw new Value_Exception('Member of the '. self::XMLRPC_TYPE_STRUCT .' XML-RPC native type must contain a VALUE tag');
}
$values[(string)$member->name] = self::_xmlStringToNativeXmlRpc($member->value);
}
Expand Down
11 changes: 6 additions & 5 deletions src/Value/DateTime.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class DateTime extends Scalar
*
* @var string
*/
protected $_isoFormatString = 'YYYYMMddTHH:mm:ss';
protected $_isoFormatString = 'yyyyMMddTHH:mm:ss';

/**
* Set the value of a dateTime.iso8601 native type
Expand All @@ -64,12 +64,13 @@ public function __construct($value)
} elseif (is_numeric($value)) { // The value is numeric, we make sure it is an integer
$this->_value = date($this->_phpFormatString, (int)$value);
} else {
$timestamp = strtotime($value);
if ($timestamp === false || $timestamp == -1) { // cannot convert the value to a timestamp
throw new Exception\ValueException('Cannot convert given value \''. $value .'\' to a timestamp');
try {
$dateTime = new \DateTime($value);
} catch (\Exception $e) {
throw new Exception\ValueException($e->getMessage(), $e->getCode(), $e);
}

$this->_value = date($this->_phpFormatString, $timestamp); // Convert the timestamp to iso8601 format
$this->_value = $dateTime->format($this->_phpFormatString); // Convert the DateTime to iso8601 format
}
}

Expand Down
52 changes: 52 additions & 0 deletions test/ClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,58 @@ public function testPythonSimpleXMLRPCServerWithUnsupportedMethodSignatures()
$signature = $introspector->getMethodSignature('add');
}


/**
* @group ZF-8580
*/
public function testCallSelectsCorrectSignatureIfMoreThanOneIsAvailable()
{
$this->mockIntrospector();

$this->mockedIntrospector
->expects($this->exactly(2))
->method('getMethodSignature')
->with('get')
->will($this->returnValue(array(
array('parameters' => array('int')),
array('parameters' => array('array'))
)));

$expectedResult = 'array';
$this->setServerResponseTo($expectedResult);

$this->assertSame(
$expectedResult,
$this->xmlrpcClient->call('get', array(array(1)))
);

$expectedResult = 'integer';
$this->setServerResponseTo($expectedResult);

$this->assertSame(
$expectedResult,
$this->xmlrpcClient->call('get', array(1))
);
}

/**
* @group ZF-1897
*/
public function testHandlesLeadingOrTrailingWhitespaceInChunkedResponseProperly()
{
$baseUri = "http://foo:80";
$this->httpAdapter = new Adapter\Test();
$this->httpClient = new Http\Client(null, array('adapter' => $this->httpAdapter));

$respBody = file_get_contents(dirname(__FILE__) . "/_files/ZF1897-response-chunked.txt");
$this->httpAdapter->setResponse($respBody);

$this->xmlrpcClient = new Client($baseUri);
$this->xmlrpcClient->setHttpClient($this->httpClient);

$this->assertEquals('FOO', $this->xmlrpcClient->call('foo'));
}

// Helpers
public function setServerResponseTo($nativeVars)
{
Expand Down
Loading

0 comments on commit 561ef2b

Please sign in to comment.