Jelajahi Sumber

ZF-6130: cast request values to objects when possible

- Added method _castParameters(); introspects prototypes to determine if a
  passed parameter should be cast to an object. If so, creates instance of
  object and loops over parameter assigning values.
- Last prototype parameter definition wins (so if multiple types can be
  specified, the last one specified will be used)
- Requires that parameter types are provided in docblocks

git-svn-id: http://framework.zend.com/svn/framework/standard/trunk@24543 44c647ce-9c0f-0410-b52a-842ac1e357ba
matthew 14 tahun lalu
induk
melakukan
5120080667

+ 84 - 0
library/Zend/Amf/Server.php

@@ -323,6 +323,7 @@ class Zend_Amf_Server implements Zend_Server_Interface
                     throw new Zend_Amf_Server_Exception('Class "' . $className . '" does not exist: '.$e->getMessage(), 0, $e);
                 }
                 // Add the new loaded class to the server.
+                    require_once 'Zend/Amf/Server/Exception.php';
                 $this->setClass($className, $source);
             }
 
@@ -340,6 +341,8 @@ class Zend_Amf_Server implements Zend_Server_Interface
             $params = array_merge($params, $argv);
         }
 
+        $params = $this->_castParameters($info, $params);
+
         if ($info instanceof Zend_Server_Reflection_Function) {
             $func = $info->getName();
             $this->_checkAcl(null, $func);
@@ -961,4 +964,85 @@ class Zend_Amf_Server implements Zend_Server_Interface
     {
         return array_keys($this->_table);
     }
+
+    /**
+     * Cast parameters
+     *
+     * Takes the provided parameters from the request, and attempts to cast them
+     * to objects, if the prototype defines any as explicit object types
+     * 
+     * @param  Reflection $reflectionMethod 
+     * @param  array $params 
+     * @return array
+     */
+    protected function _castParameters($reflectionMethod, array $params)
+    {
+        $prototypes = $reflectionMethod->getPrototypes();
+        $nonObjectTypes = array(
+            'null',
+            'mixed',
+            'void',
+            'unknown',
+            'bool',
+            'boolean',
+            'number',
+            'int',
+            'integer',
+            'double',
+            'float',
+            'string',
+            'array',
+            'object',
+            'stdclass',
+        );
+        $types      = array();
+        foreach ($prototypes as $prototype) {
+            foreach ($prototype->getParameters() as $parameter) {
+                $type = $parameter->getType();
+                if (in_array(strtolower($type), $nonObjectTypes)) {
+                    continue;
+                }
+                $position = $parameter->getPosition();
+                $types[$position] = $type;
+            }
+        }
+
+        if (empty($types)) {
+            return $params;
+        }
+
+        foreach ($params as $position => $value) {
+            if (!isset($types[$position])) {
+                // No specific type to cast to? done
+                continue;
+            }
+
+            $type = $types[$position];
+
+            if (!class_exists($type)) {
+                // Not a class, apparently. done
+                continue;
+            }
+
+            if ($value instanceof $type) {
+                // Already of the right type? done
+                continue;
+            }
+
+            if (!is_array($value) && !is_object($value)) {
+                // Can't cast scalars to objects easily; done
+                continue;
+            }
+
+            // Create instance, and loop through value to set
+            $object = new $type;
+            foreach ($value as $property => $defined) {
+                $object->{$property} = $defined;
+            }
+
+            $params[$position] = $object;
+        }
+
+        return $params;
+    }
 }

+ 5 - 3
tests/Zend/Amf/ServerTest.php

@@ -25,11 +25,13 @@ if (!defined("PHPUnit_MAIN_METHOD")) {
     define("PHPUnit_MAIN_METHOD", "Zend_Amf_ServerTest::main");
 }
 
+require_once 'Zend/Config.php';
 require_once 'Zend/Amf/Server.php';
 require_once 'Zend/Amf/Request.php';
 require_once 'Zend/Amf/Parse/TypeLoader.php';
 require_once 'Zend/Amf/Value/Messaging/RemotingMessage.php';
 require_once 'Zend/Amf/Adobe/Auth.php';
+require_once 'Zend/Amf/Adobe/Introspector.php';
 require_once 'Zend/Acl.php';
 require_once 'ServiceA.php';
 require_once 'ServiceB.php';
@@ -1146,9 +1148,9 @@ class Zend_Amf_ServerTest extends PHPUnit_Framework_TestCase
 
         // Create a mock message
         $message = new Zend_Amf_Value_Messaging_RemotingMessage();
-        $message->operation = 'createEmployee';
-        $message->source = 'EmployeeService';
-        $message->body = json_encode(array(
+        $message->operation   = 'createEmployee';
+        $message->source      = 'EmployeeService'; // original raw request used "destination"
+        $message->body        = array(array(
             'office'       => 322,
             'departmentid' => 3,
             'street'       => 32,

+ 4 - 0
tests/Zend/Amf/_files/zf-6130/services/EmployeeService.php

@@ -3,6 +3,10 @@ class EmployeeService
 {
     public static $employee;
 
+    /**
+     * @param Employee $item
+     * @return string
+     */
     public function createEmployee(Employee $item) 
     {
         $item->id       = uniqid();