Explorar o código

[ZF-8580] SystemLookup in Zend_Xmlrpc_Client selects wrong signature

git-svn-id: http://framework.zend.com/svn/framework/standard/trunk@23385 44c647ce-9c0f-0410-b52a-842ac1e357ba
jan %!s(int64=15) %!d(string=hai) anos
pai
achega
fdd03053a3

+ 20 - 9
library/Zend/XmlRpc/Client.php

@@ -333,22 +333,33 @@ class Zend_XmlRpc_Client
                 if (!is_array($params)) {
                     $params = array($params);
                 }
-                foreach ($params as $key => $param) {
 
+                foreach ($params as $key => $param)
+                {
                     if ($param instanceof Zend_XmlRpc_Value) {
                         continue;
                     }
 
-                    $type = Zend_XmlRpc_Value::AUTO_DETECT_TYPE;
-                    foreach ($signatures as $signature) {
-                        if (!is_array($signature)) {
-                            continue;
+                    if (count($signatures) > 1) {
+                        $type = Zend_XmlRpc_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 : Zend_XmlRpc_Value::AUTO_DETECT_TYPE;
-                        }
+                    if (empty($type) || !in_array($type, $validTypes)) {
+                        $type = Zend_XmlRpc_Value::AUTO_DETECT_TYPE;
                     }
 
                     $params[$key] = Zend_XmlRpc_Value::getXmlRpcValue($param, $type);

+ 68 - 40
library/Zend/XmlRpc/Value.php

@@ -252,6 +252,43 @@ abstract class Zend_XmlRpc_Value
         }
     }
 
+    /**
+     * 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 Zend_XmlRpc_Value) {
+                return $value->getType();
+            } elseif (($value instanceof Zend_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 Zend_XmlRpc_Value_Exception(sprintf(
+            'No matching XMLRPC type found for php type %s.',
+            gettype($value)
+        ));
+    }
 
     /**
      * Transform a PHP native variable into a XML-RPC native value
@@ -263,61 +300,52 @@ abstract class Zend_XmlRpc_Value
      */
     protected static function _phpVarToNativeXmlRpc($value)
     {
-        switch (gettype($value)) {
-            case 'object':
-                // Check to see if it's an XmlRpc value
-                if ($value instanceof Zend_XmlRpc_Value) {
-                    return $value;
-                }
-
-                // @see http://framework.zend.com/issues/browse/ZF-8623
-                if ($value instanceof Zend_Crypt_Math_BigInteger) {
-                    require_once 'Zend/XmlRpc/Value/Exception.php';
-                    throw new Zend_XmlRpc_Value_Exception(
-                        'Using Zend_Crypt_Math_BigInteger to get an ' .
-                        'instance of Zend_XmlRpc_Value_BigInteger is not ' .
-                        'available anymore.'
-                    );
-                }
-
-                if ($value instanceof Zend_Date or $value instanceof DateTime) {
-                    require_once 'Zend/XmlRpc/Value/DateTime.php';
-                    return new Zend_XmlRpc_Value_DateTime($value);
-                }
+        // @see http://framework.zend.com/issues/browse/ZF-8623
+        if (is_object($value)) {
+            if ($value instanceof Zend_XmlRpc_Value) {
+                return $value;
+            }
+            if ($value instanceof Zend_Crypt_Math_BigInteger) {
+                require_once 'Zend/XmlRpc/Value/Exception.php';
+                throw new Zend_XmlRpc_Value_Exception(
+                    'Using Zend_Crypt_Math_BigInteger to get an ' .
+                    'instance of Zend_XmlRpc_Value_BigInteger is not ' .
+                    'available anymore.'
+                );
+            }
+        }
+        
+        switch (self::getXmlRpcTypeByValue($value))
+        {
+            case self::XMLRPC_TYPE_DATETIME:
+                require_once 'Zend/XmlRpc/Value/DateTime.php';
+                return new Zend_XmlRpc_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'
+            case self::XMLRPC_TYPE_ARRAY:
                 require_once 'Zend/XmlRpc/Value/Array.php';
-                $obj = 'Zend_XmlRpc_Value_Array';
+                return new Zend_XmlRpc_Value_Array($value);
 
-                // Determine if this is an associative array
-                if (!empty($value) && is_array($value) && (array_keys($value) !== range(0, count($value) - 1))) {
-                    require_once 'Zend/XmlRpc/Value/Struct.php';
-                    $obj = 'Zend_XmlRpc_Value_Struct';
-                }
-                return new $obj($value);
+            case self::XMLRPC_TYPE_STRUCT:
+                require_once 'Zend/XmlRpc/Value/Struct.php';
+                return new Zend_XmlRpc_Value_Struct($value);
 
-            case 'integer':
+            case self::XMLRPC_TYPE_INTEGER:
                 require_once 'Zend/XmlRpc/Value/Integer.php';
                 return new Zend_XmlRpc_Value_Integer($value);
 
-            case 'double':
+            case self::XMLRPC_TYPE_DOUBLE:
                 require_once 'Zend/XmlRpc/Value/Double.php';
                 return new Zend_XmlRpc_Value_Double($value);
 
-            case 'boolean':
+            case self::XMLRPC_TYPE_BOOLEAN:
                 require_once 'Zend/XmlRpc/Value/Boolean.php';
                 return new Zend_XmlRpc_Value_Boolean($value);
 
-            case 'NULL':
-            case 'null':
+            case self::XMLRPC_TYPE_NIL:
                 require_once 'Zend/XmlRpc/Value/Nil.php';
-                return new Zend_XmlRpc_Value_Nil();
+                return new Zend_XmlRpc_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

+ 33 - 0
tests/Zend/XmlRpc/ClientTest.php

@@ -685,6 +685,39 @@ class Zend_XmlRpc_ClientTest extends PHPUnit_Framework_TestCase
             $this->assertEquals('Invalid signature for method "add"', $e->getMessage());
         }
     }
+    
+    /**
+     * @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))
+          );
+    }
 
     // Helpers
     public function setServerResponseTo($nativeVars)

+ 77 - 0
tests/Zend/XmlRpc/ValueTest.php

@@ -912,6 +912,83 @@ class Zend_XmlRpc_ValueTest extends PHPUnit_Framework_TestCase
         $xmlRpcValue = new Zend_XmlRpc_Value_String('foo');
         $this->assertSame($xmlRpcValue, Zend_XmlRpc_Value::getXmlRpcValue($xmlRpcValue));
     }
+    
+    public function testGetXmlRpcTypeByValue()
+    {
+        $this->assertSame(
+            Zend_XmlRpc_Value::XMLRPC_TYPE_NIL,
+            Zend_XmlRpc_Value::getXmlRpcTypeByValue(new Zend_XmlRpc_Value_Nil)
+        );
+        
+        $this->assertEquals(
+            Zend_XmlRpc_Value::XMLRPC_TYPE_DATETIME,
+            Zend_XmlRpc_Value::getXmlRpcTypeByValue(new DateTime)
+        );
+        
+        $this->assertEquals(
+            Zend_XmlRpc_Value::XMLRPC_TYPE_DATETIME,
+            Zend_XmlRpc_Value::getXmlRpcTypeByValue(new Zend_Date)
+        );
+        
+        $this->assertEquals(
+            Zend_XmlRpc_Value::XMLRPC_TYPE_STRUCT,
+            Zend_XmlRpc_Value::getXmlRpcTypeByValue(array('foo' => 'bar'))
+        );
+        
+        $object = new stdClass;
+        $object->foo = 'bar';
+        
+        $this->assertEquals(
+            Zend_XmlRpc_Value::XMLRPC_TYPE_STRUCT,
+            Zend_XmlRpc_Value::getXmlRpcTypeByValue($object)
+        );
+        
+        $this->assertEquals(
+            Zend_XmlRpc_Value::XMLRPC_TYPE_ARRAY,
+            Zend_XmlRpc_Value::getXmlRpcTypeByValue(new stdClass)
+        );
+        
+        $this->assertEquals(
+            Zend_XmlRpc_Value::XMLRPC_TYPE_ARRAY,
+            Zend_XmlRpc_Value::getXmlRpcTypeByValue(array(1, 3, 3, 7))
+        );
+        
+        $this->assertEquals(
+            Zend_XmlRpc_Value::XMLRPC_TYPE_INTEGER,
+            Zend_XmlRpc_Value::getXmlRpcTypeByValue(42)
+        );
+        
+        $this->assertEquals(
+            Zend_XmlRpc_Value::XMLRPC_TYPE_DOUBLE,
+            Zend_XmlRpc_Value::getXmlRpcTypeByValue(13.37)
+        );
+        
+        $this->assertEquals(
+            Zend_XmlRpc_Value::XMLRPC_TYPE_BOOLEAN,
+            Zend_XmlRpc_Value::getXmlRpcTypeByValue(true)
+        );
+        
+        $this->assertEquals(
+            Zend_XmlRpc_Value::XMLRPC_TYPE_BOOLEAN,
+            Zend_XmlRpc_Value::getXmlRpcTypeByValue(false)
+        );
+        
+        $this->assertEquals(
+            Zend_XmlRpc_Value::XMLRPC_TYPE_NIL,
+            Zend_XmlRpc_Value::getXmlRpcTypeByValue(null)
+        );
+        
+        $this->assertEquals(
+            Zend_XmlRpc_Value::XMLRPC_TYPE_STRING,
+            Zend_XmlRpc_Value::getXmlRpcTypeByValue('Zend Framework')
+        );
+    }
+    
+    public function testGetXmlRpcTypeByValueThrowsExceptionOnInvalidValue()
+    {
+        $this->setExpectedException('Zend_XmlRpc_Value_Exception');
+        Zend_XmlRpc_Value::getXmlRpcTypeByValue(fopen(__FILE__, 'r'));
+    }
 
     // Custom Assertions and Helper Methods