/** * Write object to output stream * * @param mixed $object * @return Amf3Serializer * @throws AmfException */ public function writeObject($object) { if ($this->writeObjectReference($object)) { return $this; } //Check to see if the object is a typed object and we need to change switch (true) { // the return class mapped name back to actionscript class name. case $className = TypeLoader::getMappedClassName(get_class($object)): break; // Check to see if the user has defined an explicit Action Script type. // Check to see if the user has defined an explicit Action Script type. case isset($object->_explicitType): $className = $object->_explicitType; break; // Check if user has defined a method for accessing the Action Script type // Check if user has defined a method for accessing the Action Script type case method_exists($object, 'getASClassName'): $className = $object->getASClassName(); break; // No return class name is set make it a generic object // No return class name is set make it a generic object case $object instanceof \stdClass: $className = ''; break; // By default, use object's class name // By default, use object's class name default: $className = get_class($object); break; } //check to see, if we have a corresponding definition if (array_key_exists($className, $this->_referenceDefinitions)) { $traitsInfo = $this->_referenceDefinitions[$className]['id']; $encoding = $this->_referenceDefinitions[$className]['encoding']; $propertyNames = $this->_referenceDefinitions[$className]['propertyNames']; if (array_key_exists('reflectProperties', $this->_referenceDefinitions[$className])) { $reflectProperties = $this->_referenceDefinitions[$className]['reflectProperties']; } $traitsInfo = $traitsInfo << 2 | 0x1; $writeTraits = false; } else { $propertyNames = []; $reflectProperties = null; if ($className == '') { //if there is no className, we interpret the class as dynamic without any sealed members $encoding = Constants::ET_DYNAMIC; } else { $encoding = Constants::ET_PROPLIST; foreach ($object as $key => $value) { if ($key[0] != "_") { $propertyNames[] = $key; } if (is_array($value) && is_null($reflectProperties)) { $reflector = new AmfReflector($object); $reflectProperties = $reflector->annotations; } } } $this->_referenceDefinitions[$className] = ['id' => count($this->_referenceDefinitions), 'encoding' => $encoding, 'propertyNames' => $propertyNames]; if (!empty($reflectProperties)) { $this->_referenceDefinitions[$className]['reflectProperties'] = $reflectProperties; } $traitsInfo = Constants::AMF3_OBJECT_ENCODING; $traitsInfo |= $encoding << 2; $traitsInfo |= count($propertyNames) << 4; $writeTraits = true; } $this->writeInteger($traitsInfo); if ($writeTraits) { $this->writeString($className); foreach ($propertyNames as $key) { $this->writeString($key); } } try { switch ($encoding) { case Constants::ET_PROPLIST: //Write the sealed values to the output stream. foreach ($propertyNames as $key) { $markerType = null; $extraData = false; if (!empty($reflectProperties) && !is_null($object->{$key})) { if (array_key_exists($key, $reflectProperties)) { if ($reflectProperties[$key]['isVector']) { $markerType = $reflectProperties[$key]['vectorElementType']; $extraData = ['elementType' => $reflectProperties[$key]['typeName'], 'fixed' => $reflectProperties[$key]['isFixedVector']]; } } } $this->writeTypeMarker($object->{$key}, $markerType, $extraData); } break; case Constants::ET_DYNAMIC: //Write the sealed values to the output stream. foreach ($propertyNames as $key) { $this->writeTypeMarker($object->{$key}); } //Write remaining properties foreach ($object as $key => $value) { if (!in_array($key, $propertyNames) && $key[0] != "_") { $this->writeString($key); $this->writeTypeMarker($value); } } //Write an empty string to end the dynamic part $this->writeString($this->_strEmpty); break; case Constants::ET_EXTERNAL: throw new AmfException('External Object Encoding not implemented'); break; default: throw new AmfException('Unknown Object Encoding type: ' . $encoding); } } catch (\Exception $e) { throw new AmfException('Unable to writeObject output: ' . $e->getMessage(), 0, $e); } return $this; }
/** * Find if the class name is a class mapped name and return the * respective classname if it is. * * @param object $object * @return false|string $className */ protected function getClassName($object) { //Check to see if the object is a typed object and we need to change //$className = ''; switch (true) { // the return class mapped name back to actionscript class name. case TypeLoader::getMappedClassName(get_class($object)): $className = TypeLoader::getMappedClassName(get_class($object)); break; // Check to see if the user has defined an explicit Action Script type. // Check to see if the user has defined an explicit Action Script type. case isset($object->_explicitType): $className = $object->_explicitType; break; // Check if user has defined a method for accessing the Action Script type // Check if user has defined a method for accessing the Action Script type case method_exists($object, 'getASClassName'): $className = $object->getASClassName(); break; // No return class name is set make it a generic object // No return class name is set make it a generic object case $object instanceof \stdClass: $className = ''; break; // By default, use object's class name // By default, use object's class name default: $className = get_class($object); break; } if (!$className == '') { return $className; } else { return false; } }
/** * Add a class mapping and lookup the mapping to make sure * the mapping succeeds */ public function testClassMap() { $this->_server->setClassMap('controller.test', 'Zend_Amf_testclass'); $className = TypeLoader::getMappedClassName('Zend_Amf_testclass'); $this->assertEquals('controller.test', $className); }
/** * Test that adding our own mappping will result in it being added to the classMap * */ public function testSetMappingClass() { TypeLoader::setMapping('com.example.vo.Contact', 'Contact'); $class = TypeLoader::getMappedClassName('com.example.vo.Contact'); $this->assertEquals('Contact', $class); }
/** * Loads a remote class or method and executes the function and returns * the result * * @param string $method Is the method to execute * @param null|array $params argument values for the method * @param null|array $source * @return mixed $response the result of executing the method * @throws AmfException */ protected function _dispatch($method, $params = null, $source = null) { if ($source) { if (($mapped = TypeLoader::getMappedClassName($source)) !== false) { $source = $mapped; } } $qualifiedName = empty($source) ? $method : $source . '.' . $method; if (!isset($this->_table[$qualifiedName])) { // if source is null a method that was not defined was called. if ($source) { $className = str_replace('.', '_', $source); if (class_exists($className, false) && !isset($this->_classAllowed[$className])) { throw new AmfException('Can not call "' . $className . '" - use setClass()'); } try { $this->getLoader()->load($className); } catch (Exception $e) { throw new AmfException('Class "' . $className . '" does not exist: ' . $e->getMessage(), 0, $e); } // Add the new loaded class to the server. $this->setClass($className, $source); } if (!isset($this->_table[$qualifiedName])) { // Source is null or doesn't contain specified method throw new AmfException('Method "' . $method . '" does not exist'); } } $info = $this->_table[$qualifiedName]; $argv = $info->getInvokeArguments(); if (0 < count($argv)) { $params = array_merge($params, $argv); } $params = $this->_castParameters($info, $params); if ($info instanceof FunctionReflector) { $func = $info->getName(); $this->_checkAcl(null, $func); $return = call_user_func_array($func, $params); } elseif ($info instanceof MethodReflector) { // Get class $class = $info->getDeclaringClass()->getName(); if ('static' == $info->isStatic()) { // for some reason, invokeArgs() does not work the same as // invoke(), and expects the first argument to be an object. // So, using a callback if the method is static. $this->_checkAcl($class, $info->getName()); $return = call_user_func_array(array($class, $info->getName()), $params); } else { // Object methods try { $object = $info->getDeclaringClass()->newInstance(); } catch (Exception $e) { throw new AmfException('Error instantiating class ' . $class . ' to invoke method ' . $info->getName() . ': ' . $e->getMessage(), 621, $e); } $this->_checkAcl($object, $info->getName()); $return = $info->invokeArgs($object, $params); } } else { throw new AmfException('Method missing implementation ' . get_class($info)); } return $return; }