]> granicus.if.org Git - php/commitdiff
Added ability to make SOAP call userspace PHP<->XML converters
authorDmitry Stogov <dmitry@php.net>
Wed, 20 Sep 2006 13:42:52 +0000 (13:42 +0000)
committerDmitry Stogov <dmitry@php.net>
Wed, 20 Sep 2006 13:42:52 +0000 (13:42 +0000)
18 files changed:
NEWS
ext/soap/php_encoding.c
ext/soap/php_encoding.h
ext/soap/php_sdl.c
ext/soap/php_soap.h
ext/soap/soap.c
ext/soap/tests/typemap001.phpt [new file with mode: 0755]
ext/soap/tests/typemap002.phpt [new file with mode: 0755]
ext/soap/tests/typemap003.phpt [new file with mode: 0755]
ext/soap/tests/typemap004.phpt [new file with mode: 0755]
ext/soap/tests/typemap005.phpt [new file with mode: 0755]
ext/soap/tests/typemap006.phpt [new file with mode: 0755]
ext/soap/tests/typemap007.phpt [new file with mode: 0755]
ext/soap/tests/typemap008.phpt [new file with mode: 0755]
ext/soap/tests/typemap009.phpt [new file with mode: 0755]
ext/soap/tests/typemap010.phpt [new file with mode: 0755]
ext/soap/tests/typemap011.phpt [new file with mode: 0755]
ext/soap/tests/typemap012.phpt [new file with mode: 0755]

diff --git a/NEWS b/NEWS
index 052be56a5bb8a94751fcbd82d94388f0ae4bc494..541bafa14d21fff779bc3973d9fcd0bf54b3f773 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,8 @@
 PHP                                                                        NEWS
 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
 ?? Sep 2006, PHP 5.2.0
+- Added ability to make SOAP call userspace PHP<->XML converters. (Dmitry)
+
 - Fixed mess with CGI/CLI -d option (now it works with cgi; constants are
   working exactly like in php.ini; with FastCGI -d affects all requests).
   (Dmitry)
index 2c92e5dd0f2058194e317f3cb695aae972f8a815..b0ecba34676de23d91f67162e610926fe787557b 100644 (file)
@@ -287,13 +287,27 @@ xmlNodePtr master_to_xml(encodePtr encode, zval *data, int style, xmlNodePtr par
                        soap_error0(E_ERROR, "Encoding: SoapVar hasn't 'enc_type' propery");
                }
 
-               if (SOAP_GLOBAL(sdl)) {
-                       if (zend_hash_find(ht, "enc_stype", sizeof("enc_stype"), (void **)&zstype) == SUCCESS) {
-                               if (zend_hash_find(ht, "enc_ns", sizeof("enc_ns"), (void **)&zns) == SUCCESS) {
-                                 enc = get_encoder(SOAP_GLOBAL(sdl), Z_STRVAL_PP(zns), Z_STRVAL_PP(zstype));
-                               } else {
-                                 enc = get_encoder_ex(SOAP_GLOBAL(sdl), Z_STRVAL_PP(zstype), Z_STRLEN_PP(zstype));
+               if (zend_hash_find(ht, "enc_stype", sizeof("enc_stype"), (void **)&zstype) == SUCCESS) {
+                       if (zend_hash_find(ht, "enc_ns", sizeof("enc_ns"), (void **)&zns) == SUCCESS) {
+                               enc = get_encoder(SOAP_GLOBAL(sdl), Z_STRVAL_PP(zns), Z_STRVAL_PP(zstype));
+                       } else {
+                               zns = NULL;
+                               enc = get_encoder_ex(SOAP_GLOBAL(sdl), Z_STRVAL_PP(zstype), Z_STRLEN_PP(zstype));
+                       }
+                       if (enc == NULL && SOAP_GLOBAL(typemap)) {
+                               encodePtr *new_enc;
+                               smart_str nscat = {0};
+
+                               if (zns != NULL) {
+                                       smart_str_appendl(&nscat, Z_STRVAL_PP(zns), Z_STRLEN_PP(zns));
+                                       smart_str_appendc(&nscat, ':');
                                }
+                               smart_str_appendl(&nscat, Z_STRVAL_PP(zstype), Z_STRLEN_PP(zstype));
+                               smart_str_0(&nscat);
+                               if (zend_hash_find(SOAP_GLOBAL(typemap), nscat.c, nscat.len + 1, (void**)&new_enc) == SUCCESS) {
+                                       enc = *new_enc;
+                               }
+                               smart_str_free(&nscat);                 
                        }
                }
                if (enc == NULL) {
@@ -363,15 +377,24 @@ xmlNodePtr master_to_xml(encodePtr encode, zval *data, int style, xmlNodePtr par
                if (encode == NULL) {
                        encode = get_conversion(UNKNOWN_TYPE);
                }
-               if (encode->to_xml_before) {
-                       data = encode->to_xml_before(&encode->details, data);
+               if (SOAP_GLOBAL(typemap) && encode->details.type_str) {
+                       smart_str nscat = {0};
+                       encodePtr *new_enc;
+
+                       if (encode->details.ns) {
+                               smart_str_appends(&nscat, encode->details.ns);
+                               smart_str_appendc(&nscat, ':');
+                       }
+                       smart_str_appends(&nscat, encode->details.type_str);
+                       smart_str_0(&nscat);
+                       if (zend_hash_find(SOAP_GLOBAL(typemap), nscat.c, nscat.len + 1, (void**)&new_enc) == SUCCESS) {
+                               encode = *new_enc;
+                       }
+                       smart_str_free(&nscat);                 
                }
                if (encode->to_xml) {
                        node = encode->to_xml(&encode->details, data, style, parent);
                }
-               if (encode->to_xml_after) {
-                       node = encode->to_xml_after(&encode->details, node, style);
-               }
        }
        return node;
 }
@@ -379,16 +402,52 @@ xmlNodePtr master_to_xml(encodePtr encode, zval *data, int style, xmlNodePtr par
 static zval *master_to_zval_int(encodePtr encode, xmlNodePtr data)
 {
        zval *ret = NULL;
+       TSRMLS_FETCH();
+
+       if (SOAP_GLOBAL(typemap)) {
+               if (encode->details.type_str) {
+                       smart_str nscat = {0};
+                       encodePtr *new_enc;
 
-       if (encode->to_zval_before) {
-               data = encode->to_zval_before(&encode->details, data, 0);
+                       if (encode->details.ns) {
+                               smart_str_appends(&nscat, encode->details.ns);
+                               smart_str_appendc(&nscat, ':');
+                       }
+                       smart_str_appends(&nscat, encode->details.type_str);
+                       smart_str_0(&nscat);
+                       if (zend_hash_find(SOAP_GLOBAL(typemap), nscat.c, nscat.len + 1, (void**)&new_enc) == SUCCESS) {
+                               encode = *new_enc;
+                       }
+                       smart_str_free(&nscat);                 
+               } else {
+                       xmlAttrPtr type_attr = get_attribute_ex(data->properties,"type", XSI_NAMESPACE);
+
+                       if (type_attr != NULL) {
+                               encodePtr *new_enc;
+                               xmlNsPtr nsptr;
+                               char *ns, *cptype;
+                               smart_str nscat = {0};
+
+                               parse_namespace(type_attr->children->content, &cptype, &ns);
+                               nsptr = xmlSearchNs(data->doc, data, BAD_CAST(ns));
+                               if (nsptr != NULL) {
+                                       smart_str_appends(&nscat, (char*)nsptr->href);
+                                       smart_str_appendc(&nscat, ':');
+                               }
+                               smart_str_appends(&nscat, cptype);
+                               smart_str_0(&nscat);
+                               efree(cptype);
+                               if (ns) {efree(ns);}
+                               if (zend_hash_find(SOAP_GLOBAL(typemap), nscat.c, nscat.len + 1, (void**)&new_enc) == SUCCESS) {
+                                       encode = *new_enc;
+                               }
+                               smart_str_free(&nscat);                 
+                       }
+               }
        }
        if (encode->to_zval) {
                ret = encode->to_zval(&encode->details, data);
        }
-       if (encode->to_zval_after) {
-               ret = encode->to_zval_after(&encode->details, ret);
-       }
        return ret;
 }
 
@@ -400,7 +459,7 @@ zval *master_to_zval(encodePtr encode, xmlNodePtr data)
        if (encode == NULL) {
                encode = get_conversion(UNKNOWN_TYPE);
        } else {
-         /* Use xsi:type if it is defined */
+               /* Use xsi:type if it is defined */
                xmlAttrPtr type_attr = get_attribute_ex(data->properties,"type", XSI_NAMESPACE);
 
                if (type_attr != NULL) {
@@ -427,125 +486,67 @@ zval *master_to_zval(encodePtr encode, xmlNodePtr data)
        return master_to_zval_int(encode, data);
 }
 
-#ifdef HAVE_PHP_DOMXML
-zval *to_xml_before_user(encodeTypePtr type, zval *data)
-{
-       TSRMLS_FETCH();
-
-       if (type.map->map_functions.to_xml_before) {
-               if (call_user_function(EG(function_table), NULL, type.map->map_functions.to_xml_before, data, 1, &data  TSRMLS_CC) == FAILURE) {
-                       soap_error0(E_ERROR, "Encoding: Error calling to_xml_before");
-               }
-       }
-       return data;
-}
-
 xmlNodePtr to_xml_user(encodeTypePtr type, zval *data, int style, xmlNodePtr parent)
 {
-       zval *ret, **addr;
-       xmlNodePtr node;
+       xmlNodePtr ret = NULL;
+       zval *return_value;
        TSRMLS_FETCH();
 
-       if (type.map->map_functions.to_xml) {
-               MAKE_STD_ZVAL(ret);
-               if (call_user_function(EG(function_table), NULL, type.map->map_functions.to_xml, ret, 1, &data  TSRMLS_CC) == FAILURE) {
-                       soap_error0(E_ERROR, "Encoding: Error calling to_xml");
-               }
+       if (type && type->map && type->map->to_xml) {
+               MAKE_STD_ZVAL(return_value);
 
-               if (Z_TYPE_P(ret) != IS_OBJECT) {
-                       soap_error0(E_ERROR, "Encoding: Error serializing object from to_xml_user");
+               if (call_user_function(EG(function_table), NULL, type->map->to_xml, return_value, 1, &data TSRMLS_CC) == FAILURE) {
+                       soap_error0(E_ERROR, "Encoding: Error calling to_xml callback");
                }
-
-               if (zend_hash_index_find(Z_OBJPROP_P(ret), 1, (void **)&addr) == SUCCESS) {
-                       node = (xmlNodePtr)Z_LVAL_PP(addr);
-                       node = xmlCopyNode(node, 1);
-                       set_ns_and_type(node, type);
+               if (Z_TYPE_P(return_value) == IS_STRING) {              
+                       xmlDocPtr doc = soap_xmlParseMemory(Z_STRVAL_P(return_value), Z_STRLEN_P(return_value));
+                       if (doc && doc->children) {                             
+                               ret = xmlDocCopyNode(doc->children, parent->doc, 1);
+                       }
+                       xmlFreeDoc(doc);
                }
-               zval_ptr_dtor(&ret);
-       }
-       return node;
-}
-
-xmlNodePtr to_xml_after_user(encodeTypePtr type, xmlNodePtr node, int style)
-{
-       zval *ret, *param, **addr;
-       int found;
-       TSRMLS_FETCH();
-
-       if (type.map->map_functions.to_xml_after) {
-               MAKE_STD_ZVAL(ret);
-               MAKE_STD_ZVAL(param);
-               param = php_domobject_new(node, &found, NULL TSRMLS_CC);
 
-               if (call_user_function(EG(function_table), NULL, type.map->map_functions.to_xml_after, ret, 1, &param  TSRMLS_CC) == FAILURE) {
-                       soap_error0(E_ERROR, "Encoding: Error calling to_xml_after");
-               }
-               if (zend_hash_index_find(Z_OBJPROP_P(ret), 1, (void **)&addr) == SUCCESS) {
-                       node = (xmlNodePtr)Z_LVAL_PP(addr);
-                       set_ns_and_type(node, type);
-               }
-               zval_ptr_dtor(&ret);
-               zval_ptr_dtor(&param);
+               zval_ptr_dtor(&return_value);
        }
-       return node;
-}
-
-xmlNodePtr to_zval_before_user(encodeTypePtr type, xmlNodePtr node, int style)
-{
-       zval *ret, *param, **addr;
-       int found;
-       TSRMLS_FETCH();
-
-       if (type.map->map_functions.to_zval_before) {
-               MAKE_STD_ZVAL(ret);
-               MAKE_STD_ZVAL(param);
-               param = php_domobject_new(node, &found, NULL TSRMLS_CC);
-
-               if (call_user_function(EG(function_table), NULL, type.map->map_functions.to_zval_before, ret, 1, &param  TSRMLS_CC) == FAILURE) {
-                       soap_error0(E_ERROR, "Encoding: Error calling to_zval_before");
-               }
-               if (zend_hash_index_find(Z_OBJPROP_P(ret), 1, (void **)&addr) == SUCCESS) {
-                       node = (xmlNodePtr)Z_LVAL_PP(addr);
-                       set_ns_and_type(node, type);
-               }
-               zval_ptr_dtor(&ret);
-               zval_ptr_dtor(&param);
+       if (!ret) {
+               ret = xmlNewNode(NULL, BAD_CAST("BOGUS"));
        }
-       return node;
-}
-
-zval *to_zval_user(encodeTypePtr type, xmlNodePtr node)
-{
-       zval *ret, *param;
-       int found;
-       TSRMLS_FETCH();
-
-       if (type.map->map_functions.to_zval) {
-               MAKE_STD_ZVAL(ret);
-               MAKE_STD_ZVAL(param);
-               param = php_domobject_new(node, &found, NULL TSRMLS_CC);
-
-               if (call_user_function(EG(function_table), NULL, type.map->map_functions.to_zval, ret, 1, &param  TSRMLS_CC) == FAILURE) {
-                       soap_error0(E_ERROR, "Encoding: Error calling to_zval");
-               }
-               zval_ptr_dtor(&param);
-               efree(param);
+       xmlAddChild(parent, ret);
+       if (style == SOAP_ENCODED) {
+               set_ns_and_type(ret, type);
        }
        return ret;
 }
 
-zval *to_zval_after_user(encodeTypePtr type, zval *data)
+zval *to_zval_user(encodeTypePtr type, xmlNodePtr node)
 {
+       zval *return_value;
        TSRMLS_FETCH();
 
-       if (type.map->map_functions.to_zval_after) {
-               if (call_user_function(EG(function_table), NULL, type.map->map_functions.to_zval_after, data, 1, &data  TSRMLS_CC) == FAILURE) {
-                       soap_error0(E_ERROR, "Encoding: Error calling to_zval_after");
-               }
+       if (type && type->map && type->map->to_zval) {
+               xmlBufferPtr buf;
+               zval *data;
+               xmlNodePtr copy;
+
+               copy = xmlCopyNode(node, 1);
+               buf = xmlBufferCreate();
+               xmlNodeDump(buf, NULL, copy, 0, 0);
+               MAKE_STD_ZVAL(data);
+               ZVAL_STRING(data, (char*)xmlBufferContent(buf), 1);
+               xmlBufferFree(buf);
+               xmlFreeNode(copy);
+
+               ALLOC_INIT_ZVAL(return_value);
+               
+               if (call_user_function(EG(function_table), NULL, type->map->to_zval, return_value, 1, &data TSRMLS_CC) == FAILURE) {
+                       soap_error0(E_ERROR, "Encoding: Error calling from_xml callback");
+               }
+               zval_ptr_dtor(&data);
+       } else {
+               ALLOC_INIT_ZVAL(return_value);
        }
-       return data;
+       return return_value;
 }
-#endif
 
 /* TODO: get rid of "bogus".. ither by passing in the already created xmlnode or passing in the node name */
 /* String encode/decode */
@@ -3090,26 +3091,8 @@ encodePtr get_conversion(int encode)
        TSRMLS_FETCH();
 
        if (zend_hash_index_find(&SOAP_GLOBAL(defEncIndex), encode, (void **)&enc) == FAILURE) {
-               if (SOAP_GLOBAL(overrides)) {
-                       smart_str nscat = {0};
-
-                       smart_str_appendl(&nscat, (*enc)->details.ns, strlen((*enc)->details.ns));
-                       smart_str_appendc(&nscat, ':');
-                       smart_str_appendl(&nscat, (*enc)->details.type_str, strlen((*enc)->details.type_str));
-                       smart_str_0(&nscat);
-
-                       if (zend_hash_find(SOAP_GLOBAL(overrides), nscat.c, nscat.len + 1, (void **)&enc) == FAILURE) {
-                               smart_str_free(&nscat);
-                               soap_error0(E_ERROR,  "Encoding: Cannot find encoding");
-                               return NULL;
-                       } else {
-                               smart_str_free(&nscat);
-                               return *enc;
-                       }
-               } else {
-                       soap_error0(E_ERROR,  "Encoding: Cannot find encoding");
-                       return NULL;
-               }
+               soap_error0(E_ERROR,  "Encoding: Cannot find encoding");
+               return NULL;
        } else {
                return *enc;
        }
@@ -3256,32 +3239,11 @@ static void delete_mapping(void *data)
 {
        soapMappingPtr map = (soapMappingPtr)data;
 
-       if (map->ns) {
-               efree(map->ns);
+       if (map->to_xml) {
+               zval_ptr_dtor(&map->to_xml);
        }
-       if (map->ctype) {
-               efree(map->ctype);
-       }
-
-       if (map->type == SOAP_MAP_FUNCTION) {
-               if (map->map_functions.to_xml_before) {
-                       zval_ptr_dtor(&map->map_functions.to_xml_before);
-               }
-               if (map->map_functions.to_xml) {
-                       zval_ptr_dtor(&map->map_functions.to_xml);
-               }
-               if (map->map_functions.to_xml_after) {
-                       zval_ptr_dtor(&map->map_functions.to_xml_after);
-               }
-               if (map->map_functions.to_zval_before) {
-                       zval_ptr_dtor(&map->map_functions.to_zval_before);
-               }
-               if (map->map_functions.to_zval) {
-                       zval_ptr_dtor(&map->map_functions.to_zval);
-               }
-               if (map->map_functions.to_zval_after) {
-                       zval_ptr_dtor(&map->map_functions.to_zval_after);
-               }
+       if (map->to_zval) {
+               zval_ptr_dtor(&map->to_zval);
        }
        efree(map);
 }
index 2e92ec37573550a1391c0bfac3db53064db982a2..c007925dd0d92a55c77c59ba5d21b479413b47ae 100644 (file)
@@ -185,27 +185,15 @@ struct _encode {
        encodeType details;
        zval *(*to_zval)(encodeTypePtr type, xmlNodePtr data);
        xmlNodePtr (*to_xml)(encodeTypePtr type, zval *data, int style, xmlNodePtr parent);
-
-       xmlNodePtr (*to_zval_before)(encodeTypePtr type, xmlNodePtr data, int style);
-       zval *(*to_zval_after)(encodeTypePtr type, zval *data);
-
-       zval *(*to_xml_before)(encodeTypePtr type, zval *data);
-       xmlNodePtr (*to_xml_after)(encodeTypePtr type, xmlNodePtr data, int style);
 };
 
 /* Master functions all encode/decode should be called thur these functions */
 xmlNodePtr master_to_xml(encodePtr encode, zval *data, int style, xmlNodePtr parent);
 zval *master_to_zval(encodePtr encode, xmlNodePtr data);
 
-#ifdef HAVE_PHP_DOMXML
 /* user defined mapping */
-zval *to_xml_before_user(encodeTypePtr type, zval *data);
 xmlNodePtr to_xml_user(encodeTypePtr type, zval *data, int style, xmlNodePtr parent);
-xmlNodePtr to_xml_after_user(encodeTypePtr type, xmlNodePtr node, int style);
-xmlNodePtr to_zval_before_user(encodeTypePtr type, xmlNodePtr node, int style);
 zval *to_zval_user(encodeTypePtr type, xmlNodePtr node);
-zval *to_zval_after_user(encodeTypePtr type, zval *data);
-#endif
 
 void whiteSpace_replace(xmlChar* str);
 void whiteSpace_collapse(xmlChar* str);
index c36444e37cf25a87c1d3a8b7941df662947ae98e..53c9a1a5a035bb01388f3b6c11cd6b51673d71ed 100644 (file)
@@ -1326,10 +1326,6 @@ static void sdl_deserialize_encoder(encodePtr enc, sdlTypePtr *types, char **in)
                        if (real_enc) {
                                enc->to_zval = real_enc->to_zval;
                                enc->to_xml = real_enc->to_xml;
-                               enc->to_zval_before = real_enc->to_zval_before;
-                               enc->to_xml_before = real_enc->to_xml_before;
-                               enc->to_zval_after = real_enc->to_zval_after;
-                               enc->to_xml_after = real_enc->to_xml_after;
                        }
                }
        }       
index 39dbe3e5d36ccedea40e69874986b5eeb95f56b1..776381a5c7e6950f2590c4b83fa7310185bd3d95 100644 (file)
 #include <libxml/parser.h>
 #include <libxml/xpath.h>
 
-#ifdef HAVE_PHP_DOMXML
-# include "ext/domxml/php_domxml.h"
-#endif
-
 #ifndef PHP_HAVE_STREAMS
 # error You lose - must be compiled against PHP 4.3.0 or later
 #endif
@@ -78,23 +74,8 @@ typedef struct _soapService soapService, *soapServicePtr;
 #include "php_packet_soap.h"
 
 struct _soapMapping {
-       char *ns;
-       char *ctype;
-       int type;
-
-       struct _map_functions {
-               zval *to_xml_before;
-               zval *to_xml;
-               zval *to_xml_after;
-               zval *to_zval_before;
-               zval *to_zval;
-               zval *to_zval_after;
-       } map_functions;
-
-       struct _map_class {
-               int type;
-               zend_class_entry *ce;
-       } map_class;
+       zval *to_xml;
+       zval *to_zval;
 };
 
 struct _soapHeader;
@@ -116,7 +97,7 @@ struct _soapService {
 
        zval *soap_object;
 
-       HashTable *mapping;
+       HashTable *typemap;
        int        version;
        int        type;
        char      *actor;
@@ -170,7 +151,7 @@ ZEND_BEGIN_MODULE_GLOBALS(soap)
        HashTable  defEncNs;     /* mapping of default namespaces to prefixes */
        HashTable  defEnc;
        HashTable  defEncIndex;
-       HashTable *overrides;
+       HashTable *typemap;
        int        cur_uniq_ns;
        int        soap_version;
        sdlPtr     sdl;
index e7f1999cea441320b8903506698668ff8c29313b..3bb48defd3a53c058fb06ec2c8c341c95614c091 100644 (file)
@@ -33,6 +33,7 @@
 static int le_sdl = 0;
 int le_url = 0;
 static int le_service = 0;
+static int le_typemap = 0;
 
 typedef struct _soapHeader {
        sdlFunctionPtr                    function;
@@ -66,6 +67,7 @@ static xmlNodePtr serialize_zval(zval *val, sdlParamPtr param, char *paramName,
 
 static void delete_service(void *service);
 static void delete_url(void *handle);
+static void delete_hashtable(void *hashtable);
 
 #ifndef ZEND_ENGINE_2
 static void soap_call_function_handler(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference);
@@ -157,6 +159,9 @@ static void soap_error_handler(int error_num, const char *error_filename, const
 #define FIND_SDL_PROPERTY(ss,tmp) zend_hash_find(Z_OBJPROP_P(ss), "sdl", sizeof("sdl"), (void **)&tmp)
 #define FETCH_SDL_RES(ss,tmp) ss = (sdlPtr) zend_fetch_resource(tmp TSRMLS_CC, -1, "sdl", NULL, 1, le_sdl)
 
+#define FIND_TYPEMAP_PROPERTY(ss,tmp) zend_hash_find(Z_OBJPROP_P(ss), "typemap", sizeof("typemap"), (void **)&tmp)
+#define FETCH_TYPEMAP_RES(ss,tmp) ss = (HashTable*) zend_fetch_resource(tmp TSRMLS_CC, -1, "typemap", NULL, 1, le_typemap)
+
 #define FETCH_THIS_SERVICE(ss) \
        { \
                zval **tmp; \
@@ -246,9 +251,6 @@ PHP_METHOD(SoapServer, handle);
 PHP_METHOD(SoapServer, setPersistence);
 PHP_METHOD(SoapServer, fault);
 PHP_METHOD(SoapServer, addSoapHeader);
-#ifdef HAVE_PHP_DOMXML
-PHP_METHOD(PHP_SOAP_SERVER_CLASS, map);
-#endif
 
 /* Client Functions */
 PHP_METHOD(SoapClient, SoapClient);
@@ -282,10 +284,6 @@ PHP_METHOD(SoapHeader, SoapHeader);
 #define SOAP_CTOR(class_name, func_name, arginfo, flags) PHP_ME(class_name, func_name, arginfo, flags)
 
 static zend_function_entry soap_functions[] = {
-#ifdef HAVE_PHP_DOMXML
-       PHP_FE(soap_encode_to_xml, NULL)
-       PHP_FE(soap_encode_to_zval, NULL)
-#endif
        PHP_FE(use_soap_error_handler, NULL)
        PHP_FE(is_soap_fault, NULL)
        {NULL, NULL, NULL}
@@ -309,9 +307,6 @@ static zend_function_entry soap_server_functions[] = {
        PHP_ME(SoapServer, handle, NULL, 0)
        PHP_ME(SoapServer, fault, NULL, 0)
        PHP_ME(SoapServer, addSoapHeader, NULL, 0)
-#ifdef HAVE_PHP_DOMXML
-       PHP_ME(SoapServer, map, NULL, 0)
-#endif
        {NULL, NULL, NULL}
 };
 
@@ -478,7 +473,7 @@ static void php_soap_init_globals(zend_soap_globals *soap_globals TSRMLS_DC)
        soap_globals->defEnc = defEnc;
        soap_globals->defEncIndex = defEncIndex;
        soap_globals->defEncNs = defEncNs;
-       soap_globals->overrides = NULL;
+       soap_globals->typemap = NULL;
        soap_globals->use_soap_error_handler = 0;
        soap_globals->error_code = NULL;
        soap_globals->error_object = NULL;
@@ -503,7 +498,7 @@ PHP_MSHUTDOWN_FUNCTION(soap)
 
 PHP_RINIT_FUNCTION(soap)
 {
-       SOAP_GLOBAL(overrides) = NULL;
+       SOAP_GLOBAL(typemap) = NULL;
        SOAP_GLOBAL(use_soap_error_handler) = 0;
        SOAP_GLOBAL(error_code) = NULL;
        SOAP_GLOBAL(error_object) = NULL;
@@ -584,6 +579,7 @@ PHP_MINIT_FUNCTION(soap)
        le_sdl = register_list_destructors(delete_sdl, NULL);
        le_url = register_list_destructors(delete_url, NULL);
        le_service = register_list_destructors(delete_service, NULL);
+       le_typemap = register_list_destructors(delete_hashtable, NULL);
 
        REGISTER_LONG_CONSTANT("SOAP_1_1", SOAP_1_1, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SOAP_1_2", SOAP_1_2, CONST_CS | CONST_PERSISTENT);
@@ -689,42 +685,6 @@ PHP_MINFO_FUNCTION(soap)
        DISPLAY_INI_ENTRIES();
 }
 
-#ifdef HAVE_PHP_DOMXML
-PHP_FUNCTION(soap_encode_to_xml)
-{
-       zval *pzval, *ret;
-       encodePtr enc;
-       char *name;
-       int found, name_len;
-
-       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &name, &name_len, &pzval) == FAILURE) {
-               php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid parameters");
-       }
-
-       enc = get_conversion(Z_TYPE_P(pzval));
-       ret = php_domobject_new(serialize_zval(pzval, NULL, name, SOAP_ENCODED), &found, NULL TSRMLS_CC);
-       *return_value = *ret;
-       zval_copy_ctor(return_value);
-       zval_ptr_dtor(&ret);
-}
-
-PHP_FUNCTION(soap_encode_to_zval)
-{
-       zval *dom, **addr, *ret;
-       xmlNodePtr node;
-
-       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &dom) == FAILURE) {
-               php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid parameters");
-       }
-
-       if (zend_hash_index_find(Z_OBJPROP_P(dom), 1, (void **)&addr) == FAILURE) {
-       }
-
-       node = (xmlNodePtr)Z_LVAL_PP(addr);
-       ret = master_to_zval(NULL, node);
-       *return_value = *ret;
-}
-#endif
 
 /* {{{ proto object SoapParam::SoapParam ( mixed data, string name)
    SoapParam constructor */
@@ -932,6 +892,122 @@ PHP_METHOD(SoapVar, SoapVar)
 /* }}} */
 
 
+static HashTable* soap_create_typemap(sdlPtr sdl, HashTable *ht TSRMLS_DC)
+{
+       zval **tmp;
+       HashTable *ht2;
+       HashPosition pos1, pos2;
+       HashTable *typemap = NULL;
+       
+       zend_hash_internal_pointer_reset_ex(ht, &pos1);
+       while (zend_hash_get_current_data_ex(ht, (void**)&tmp, &pos1) == SUCCESS) {
+               char *type_name = NULL;
+               char *type_ns = NULL;
+               zval *to_xml = NULL;
+               zval *to_zval = NULL;
+               encodePtr enc, new_enc;
+
+               if (Z_TYPE_PP(tmp) != IS_ARRAY) {
+                       php_error_docref(NULL TSRMLS_CC, E_ERROR, "Wrong 'typemap' option");
+               }
+               ht2 = Z_ARRVAL_PP(tmp);
+
+               zend_hash_internal_pointer_reset_ex(ht2, &pos2);
+               while (zend_hash_get_current_data_ex(ht2, (void**)&tmp, &pos2) == SUCCESS) {
+                       char *name = NULL;
+                       unsigned int name_len;
+                       ulong index;
+
+                       zend_hash_get_current_key_ex(ht2, &name, &name_len, &index, 0, &pos2);
+                       if (name) {
+                               if (name_len == sizeof("type_name") &&
+                                   strncmp(name, "type_name", sizeof("type_name")-1) == 0) {
+                                       if (Z_TYPE_PP(tmp) == IS_STRING) {
+                                               type_name = Z_STRVAL_PP(tmp);
+                                       } else if (Z_TYPE_PP(tmp) != IS_NULL) {
+                                       }
+                               } else if (name_len == sizeof("type_ns") &&
+                                   strncmp(name, "type_ns", sizeof("type_ns")-1) == 0) {
+                                       if (Z_TYPE_PP(tmp) == IS_STRING) {
+                                               type_ns = Z_STRVAL_PP(tmp);
+                                       } else if (Z_TYPE_PP(tmp) != IS_NULL) {
+                                       }
+                               } else if (name_len == sizeof("to_xml") &&
+                                   strncmp(name, "to_xml", sizeof("to_xml")-1) == 0) {
+                                       to_xml = *tmp;
+                               } else if (name_len == sizeof("from_xml") &&
+                                   strncmp(name, "from_xml", sizeof("from_xml")-1) == 0) {
+                                       to_zval = *tmp;
+                               }
+                       }
+                       zend_hash_move_forward_ex(ht2, &pos2);
+               }               
+
+               if (type_name) {
+                       smart_str nscat = {0};
+
+                       if (type_ns) {
+                               enc = get_encoder(sdl, type_ns, type_name);
+                       } else {
+                               enc = get_encoder_ex(sdl, type_name, strlen(type_name));
+                       }
+
+                       new_enc = emalloc(sizeof(encode));
+                       memset(new_enc, 0, sizeof(encode));
+
+                       if (enc) {
+                               new_enc->details.type = enc->details.type;
+                               new_enc->details.ns = estrdup(enc->details.ns);
+                               new_enc->details.type_str = estrdup(enc->details.type_str);
+                               new_enc->details.sdl_type = enc->details.sdl_type;
+                       } else {
+                               enc = get_conversion(UNKNOWN_TYPE);
+                               new_enc->details.type = enc->details.type;
+                               if (type_ns) {
+                                       new_enc->details.ns = estrdup(type_ns);
+                               }
+                               new_enc->details.type_str = estrdup(type_name);
+                       }
+                       new_enc->to_xml = enc->to_xml;
+                       new_enc->to_zval = enc->to_zval;
+                       new_enc->details.map = emalloc(sizeof(soapMapping));
+                       memset(new_enc->details.map, 0, sizeof(soapMapping));                   
+                       if (to_xml) {
+                               zval_add_ref(&to_xml);
+                               new_enc->details.map->to_xml = to_xml;
+                               new_enc->to_xml = to_xml_user;
+                       } else if (enc->details.map && enc->details.map->to_xml) {
+                               zval_add_ref(&enc->details.map->to_xml);
+                               new_enc->details.map->to_xml = enc->details.map->to_xml;
+                       }
+                       if (to_zval) {
+                               zval_add_ref(&to_zval);
+                               new_enc->details.map->to_zval = to_zval;
+                               new_enc->to_zval = to_zval_user;
+                       } else if (enc->details.map && enc->details.map->to_zval) {
+                               zval_add_ref(&enc->details.map->to_zval);
+                               new_enc->details.map->to_zval = enc->details.map->to_zval;
+                       }
+                       if (!typemap) {
+                               typemap = emalloc(sizeof(HashTable));
+                               zend_hash_init(typemap, 0, NULL, delete_encoder, 0);
+                       }
+
+                       if (type_ns) {
+                               smart_str_appends(&nscat, type_ns);
+                               smart_str_appendc(&nscat, ':');
+                       }
+                       smart_str_appends(&nscat, type_name);
+                       smart_str_0(&nscat);
+                       zend_hash_update(typemap, nscat.c, nscat.len + 1, &new_enc, sizeof(encodePtr), NULL);
+                       smart_str_free(&nscat);
+               }
+               zend_hash_move_forward_ex(ht, &pos1);
+       }
+       return typemap;
+}
+
+
 /* {{{ proto object SoapServer::SoapServer ( mixed wsdl [, array options])
    SoapServer constructor */
 PHP_METHOD(SoapServer, SoapServer)
@@ -941,6 +1017,7 @@ PHP_METHOD(SoapServer, SoapServer)
        int ret;
        int version = SOAP_1_1;
        long cache_wsdl;
+       HashTable *typemap_ht = NULL;
 
        SOAP_SERVER_BEGIN_CODE();
 
@@ -1005,6 +1082,12 @@ PHP_METHOD(SoapServer, SoapServer)
                        zend_hash_copy(service->class_map, (*tmp)->value.ht, (copy_ctor_func_t) zval_add_ref, (void *) &ztmp, sizeof(zval *));
                }
 
+               if (zend_hash_find(ht, "typemap", sizeof("typemap"), (void**)&tmp) == SUCCESS &&
+                       Z_TYPE_PP(tmp) == IS_ARRAY &&
+                       zend_hash_num_elements(Z_ARRVAL_PP(tmp)) > 0) {
+                       typemap_ht = Z_ARRVAL_PP(tmp);
+               }
+
                if (zend_hash_find(ht, "features", sizeof("features"), (void**)&tmp) == SUCCESS &&
                        Z_TYPE_PP(tmp) == IS_LONG) {
                        service->features = Z_LVAL_PP(tmp);
@@ -1036,6 +1119,10 @@ PHP_METHOD(SoapServer, SoapServer)
                        }
                }
        }
+       
+       if (typemap_ht) {
+               service->typemap = soap_create_typemap(service->sdl, typemap_ht TSRMLS_CC);
+       }
 
        ret = zend_list_insert(service, le_service);
        add_property_resource(this_ptr, "service", ret);
@@ -1045,127 +1132,6 @@ PHP_METHOD(SoapServer, SoapServer)
 /* }}} */
 
 
-#define NULL_OR_STRING(zval) \
-       (!zval || Z_TYPE_P(zval) == IS_NULL || Z_TYPE_P(zval) == IS_STRING)
-
-#define IS_VALID_FUNCTION(zval) \
-       (zval && Z_TYPE_P(zval) != IS_NULL)
-
-#ifdef HAVE_PHP_DOMXML
-PHP_FUNCTION(PHP_SOAP_SERVER_CLASS, map)
-{
-       char *type, *class_name;
-       zval *to_xml_before = NULL, *to_xml = NULL, *to_xml_after = NULL,
-               *to_zval_before = NULL, *to_zval = NULL, *to_zval_after = NULL;
-       int type_len, class_name_len;
-       char *ns, *ctype;
-       soapServicePtr service;
-
-       SOAP_SERVER_BEGIN_CODE();
-
-       if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "sz|zzzzz",
-               &type, &type_len, &to_xml_before, &to_xml, &to_xml_after, &to_zval_before, &to_zval,
-               &to_zval_after) == SUCCESS && NULL_OR_STRING(to_xml_before) && NULL_OR_STRING(to_xml) &&
-               NULL_OR_STRING(to_xml_after) && NULL_OR_STRING(to_zval_before) && NULL_OR_STRING(to_zval) &&
-               NULL_OR_STRING(to_zval_after)) {
-
-               soapMappingPtr map;
-               encodePtr enc, new_enc;
-               smart_str resloved_ns = {0};
-
-               FETCH_THIS_SERVICE(service);
-
-               new_enc = emalloc(sizeof(encode));
-               memset(new_enc, 0, sizeof(encode));
-
-               ctype = strrchr(type, ':');
-               if (ctype) {
-                       smart_str_appendl(&resloved_ns, type, ctype - type);
-                       smart_str_0(&resloved_ns);
-                       ctype++;
-               } else {
-                       ns = NULL;
-               }
-
-               if (ns) {
-                       if (zend_hash_find(SOAP_GLOBAL(defEncPrefix),  resloved_ns.c, resloved_ns.len + 1, &ns) == SUCCESS) {
-                               enc = get_encoder(service->sdl, ns, ctype);
-                               smart_str_free(&resloved_ns);
-                               smart_str_appendl(&resloved_ns, ns, strlen(ns));
-                               smart_str_appendc(&resloved_ns, ':');
-                               smart_str_appendl(&resloved_ns, ctype, strlen(ctype));
-                               smart_str_0(&resloved_ns);
-                               type = resloved_ns.c;
-                               type_len = resloved_ns.len;
-                       } else {
-                               enc = get_encoder_ex(service->sdl, type);
-                       }
-               } else {
-                       enc = get_encoder_ex(service->sdl, type);
-               }
-
-               new_enc->details.type = enc->details.type;
-               new_enc->details.ns = estrdup(enc->details.ns);
-               new_enc->details.type_str = estrdup(enc->details.type_str);
-               new_enc->details.sdl_type = enc->details.sdl_type;
-               new_enc->to_xml = enc->to_xml;
-               new_enc->to_zval = enc->to_zval;
-               new_enc->to_xml_before = enc->to_xml_before;
-               new_enc->to_zval_before = enc->to_zval_before;
-               new_enc->to_xml_after = enc->to_xml_after;
-               new_enc->to_zval_after = enc->to_zval_after;
-
-               map = emalloc(sizeof(soapMapping));
-               memset(map, 0, sizeof(soapMapping));
-
-               map->type = SOAP_MAP_FUNCTION;
-               if (IS_VALID_FUNCTION(to_xml_before)) {
-                       zval_add_ref(&to_xml_before);
-                       map->map_functions.to_xml_before = to_xml_before;
-                       new_enc->to_xml_before = to_xml_before_user;
-               }
-               if (IS_VALID_FUNCTION(to_xml)) {
-                       zval_add_ref(&to_xml);
-                       map->map_functions.to_xml = to_xml;
-                       new_enc->to_xml = to_xml_user;
-               }
-               if (IS_VALID_FUNCTION(to_xml_after)) {
-                       zval_add_ref(&to_xml_after);
-                       map->map_functions.to_xml_after = to_xml_after;
-                       new_enc->to_xml_after = to_xml_after_user;
-               }
-               if (IS_VALID_FUNCTION(to_zval_before)) {
-                       zval_add_ref(&to_zval_before);
-                       map->map_functions.to_zval_before = to_zval_before;
-                       new_enc->to_zval_before = to_zval_before_user;
-               }
-               if (IS_VALID_FUNCTION(to_zval)) {
-                       zval_add_ref(&to_zval);
-                       map->map_functions.to_zval = to_zval;
-                       new_enc->to_zval = to_zval_user;
-               }
-               if (IS_VALID_FUNCTION(to_zval_after)) {
-                       zval_add_ref(&to_zval_after);
-                       map->map_functions.to_zval_after = to_zval_after;
-                       new_enc->to_zval_after = to_zval_after_user;
-               }
-
-               new_enc->details.map = map;
-
-               if (!service->mapping) {
-                       service->mapping = emalloc(sizeof(HashTable));
-                       zend_hash_init(service->mapping, 0, NULL, delete_encoder, 0);
-               }
-               zend_hash_update(service->mapping, type, type_len + 1, &new_enc, sizeof(encodePtr), NULL);
-               smart_str_free(&resloved_ns);
-       } else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", &type, &type_len, &class_name, &class_name_len, &type) == SUCCESS) {
-       } else {
-               php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid parameters");
-       }
-}
-#endif
-
-
 /* {{{ proto object SoapServer::setPersistence ( int mode )
    Sets persistence mode of SoapServer */
 PHP_METHOD(SoapServer, setPersistence)
@@ -1444,7 +1410,7 @@ PHP_METHOD(SoapServer, handle)
        char *arg = NULL;
        int arg_len;
        xmlCharEncodingHandlerPtr old_encoding;
-       HashTable *old_class_map;
+       HashTable *old_class_map, *old_typemap;
        int old_features;
 
        SOAP_SERVER_BEGIN_CODE();
@@ -1585,12 +1551,25 @@ PHP_METHOD(SoapServer, handle)
        SOAP_GLOBAL(encoding) = service->encoding;
        old_class_map = SOAP_GLOBAL(class_map);
        SOAP_GLOBAL(class_map) = service->class_map;
+       old_typemap = SOAP_GLOBAL(typemap);
+       SOAP_GLOBAL(typemap) = service->typemap;
        old_features = SOAP_GLOBAL(features);
        SOAP_GLOBAL(features) = service->features;
        old_soap_version = SOAP_GLOBAL(soap_version);
        function = deserialize_function_call(service->sdl, doc_request, service->actor, &function_name, &num_params, &params, &soap_version, &soap_headers TSRMLS_CC);
        xmlFreeDoc(doc_request);
        
+#ifdef ZEND_ENGINE_2
+       if (EG(exception)) {
+               php_end_ob_buffer(0, 0 TSRMLS_CC);
+               if (Z_TYPE_P(EG(exception)) == IS_OBJECT &&
+                   instanceof_function(Z_OBJCE_P(EG(exception)), soap_fault_class_entry TSRMLS_CC)) {
+                       soap_server_fault_ex(function, EG(exception), NULL TSRMLS_CC);
+               }
+               goto fail;
+       }
+#endif
+
        service->soap_headers_ptr = &soap_headers;
 
        soap_obj = NULL;
@@ -1835,14 +1814,32 @@ PHP_METHOD(SoapServer, handle)
                        memcpy(response_name,Z_STRVAL(function_name),Z_STRLEN(function_name));
                        memcpy(response_name+Z_STRLEN(function_name),"Response",sizeof("Response"));
                }
-               SOAP_GLOBAL(overrides) = service->mapping;
                doc_return = serialize_response_call(function, response_name, service->uri, &retval, soap_headers, soap_version TSRMLS_CC);
-               SOAP_GLOBAL(overrides) = NULL;
                efree(response_name);
        } else {
                php_error_docref(NULL TSRMLS_CC, E_ERROR, "Function '%s' call failed", Z_STRVAL(function_name));
        }
 
+#ifdef ZEND_ENGINE_2
+       if (EG(exception)) {
+               php_end_ob_buffer(0, 0 TSRMLS_CC);
+               if (Z_TYPE_P(EG(exception)) == IS_OBJECT &&
+                   instanceof_function(Z_OBJCE_P(EG(exception)), soap_fault_class_entry TSRMLS_CC)) {
+                       soap_server_fault_ex(function, EG(exception), NULL TSRMLS_CC);
+               }
+               if (service->type == SOAP_CLASS) {
+#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
+                       if (soap_obj && service->soap_class.persistance != SOAP_PERSISTENCE_SESSION) {
+#else
+                       if (soap_obj) {
+#endif
+                         zval_ptr_dtor(&soap_obj);
+                       }
+               }
+               goto fail;
+       }
+#endif
+
        /* Flush buffer */
        php_end_ob_buffer(0, 0 TSRMLS_CC);
 
@@ -1875,6 +1872,7 @@ fail:
        SOAP_GLOBAL(encoding) = old_encoding;
        SOAP_GLOBAL(sdl) = old_sdl;
        SOAP_GLOBAL(class_map) = old_class_map;
+       SOAP_GLOBAL(typemap) = old_typemap;
        SOAP_GLOBAL(features) = old_features;
 
        /* Free soap headers */
@@ -2182,6 +2180,8 @@ PHP_METHOD(SoapClient, SoapClient)
        int  soap_version = SOAP_1_1;
        php_stream_context *context = NULL;
        long cache_wsdl;
+       sdlPtr sdl = NULL;
+       HashTable *typemap_ht = NULL;
 
        SOAP_CLIENT_BEGIN_CODE();
 
@@ -2333,6 +2333,12 @@ PHP_METHOD(SoapClient, SoapClient)
                        add_property_zval(this_ptr, "_classmap", class_map);
                }
 
+               if (zend_hash_find(ht, "typemap", sizeof("typemap"), (void**)&tmp) == SUCCESS &&
+                       Z_TYPE_PP(tmp) == IS_ARRAY &&
+                       zend_hash_num_elements(Z_ARRVAL_PP(tmp)) > 0) {
+                       typemap_ht = Z_ARRVAL_PP(tmp);
+               }
+
                if (zend_hash_find(ht, "features", sizeof("features"), (void**)&tmp) == SUCCESS &&
                        Z_TYPE_PP(tmp) == IS_LONG) {
                        add_property_long(this_ptr, "_features", Z_LVAL_PP(tmp));
@@ -2366,7 +2372,6 @@ PHP_METHOD(SoapClient, SoapClient)
 
        if (wsdl) {
                int    old_soap_version, ret;
-               sdlPtr sdl;
 
                old_soap_version = SOAP_GLOBAL(soap_version);
                SOAP_GLOBAL(soap_version) = soap_version;
@@ -2379,6 +2384,15 @@ PHP_METHOD(SoapClient, SoapClient)
                SOAP_GLOBAL(soap_version) = old_soap_version;
        }
 
+       if (typemap_ht) {
+               HashTable *typemap = soap_create_typemap(sdl, typemap_ht TSRMLS_CC);
+               if (typemap) {
+                       int ret;
+
+                       ret = zend_list_insert(typemap, le_typemap);
+                       add_property_resource(this_ptr, "typemap", ret);
+               }
+       }
        SOAP_CLIENT_END_CODE();
 }
 /* }}} */
@@ -2477,6 +2491,7 @@ static void do_soap_call(zval* this_ptr,
        xmlCharEncodingHandlerPtr old_encoding;
        HashTable *old_class_map;
        int old_features;
+       HashTable *old_typemap, *typemap = NULL;
 
        SOAP_CLIENT_BEGIN_CODE();
 
@@ -2502,6 +2517,9 @@ static void do_soap_call(zval* this_ptr,
        if (FIND_SDL_PROPERTY(this_ptr,tmp) != FAILURE) {
                FETCH_SDL_RES(sdl,tmp);
        }
+       if (FIND_TYPEMAP_PROPERTY(this_ptr,tmp) != FAILURE) {
+               FETCH_TYPEMAP_RES(typemap,tmp);
+       }
 
        clear_soap_fault(this_ptr TSRMLS_CC);
 
@@ -2522,6 +2540,8 @@ static void do_soap_call(zval* this_ptr,
        } else {
                SOAP_GLOBAL(class_map) = NULL;
        }
+       old_typemap = SOAP_GLOBAL(typemap);
+       SOAP_GLOBAL(typemap) = typemap;
        old_features = SOAP_GLOBAL(features);
        if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_features", sizeof("_features"), (void **) &tmp) == SUCCESS &&
            Z_TYPE_PP(tmp) == IS_LONG) {
@@ -2624,7 +2644,8 @@ static void do_soap_call(zval* this_ptr,
                }
        }
 #ifdef ZEND_ENGINE_2
-       if (Z_TYPE_P(return_value) == IS_OBJECT &&
+       if (!EG(exception) &&
+           Z_TYPE_P(return_value) == IS_OBJECT &&
            instanceof_function(Z_OBJCE_P(return_value), soap_fault_class_entry TSRMLS_CC) &&
            (zend_hash_find(Z_OBJPROP_P(this_ptr), "_exceptions", sizeof("_exceptions"), (void **) &tmp) != SUCCESS ||
                   Z_TYPE_PP(tmp) != IS_BOOL || Z_LVAL_PP(tmp) != 0)) {
@@ -2641,6 +2662,7 @@ static void do_soap_call(zval* this_ptr,
                xmlCharEncCloseFunc(SOAP_GLOBAL(encoding));
        }
        SOAP_GLOBAL(features) = old_features;
+       SOAP_GLOBAL(typemap) = old_typemap;
        SOAP_GLOBAL(class_map) = old_class_map;
        SOAP_GLOBAL(encoding) = old_encoding;
        SOAP_GLOBAL(sdl) = old_sdl;
@@ -4606,9 +4628,9 @@ static void delete_service(void *data)
                efree(service->soap_functions.ft);
        }
 
-       if (service->mapping) {
-               zend_hash_destroy(service->mapping);
-               efree(service->mapping);
+       if (service->typemap) {
+               zend_hash_destroy(service->typemap);
+               efree(service->typemap);
        }
 
        if (service->soap_class.argc) {
@@ -4640,3 +4662,10 @@ static void delete_service(void *data)
        }
        efree(service);
 }
+
+static void delete_hashtable(void *data)
+{
+       HashTable *ht = (HashTable*)data;
+       zend_hash_destroy(ht);
+       efree(ht);
+}
diff --git a/ext/soap/tests/typemap001.phpt b/ext/soap/tests/typemap001.phpt
new file mode 100755 (executable)
index 0000000..d76170a
--- /dev/null
@@ -0,0 +1,60 @@
+--TEST--
+SOAP typemap 1: SoapServer support for typemap's from_xml()
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+$GLOBALS['HTTP_RAW_POST_DATA']="
+<env:Envelope xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\" 
+       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" 
+       xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" 
+       xmlns:enc=\"http://schemas.xmlsoap.org/soap/encoding/\"
+       xmlns:ns1=\"http://schemas.nothing.com\"
+>
+  <env:Body>
+ <ns1:dotest>
+  <book xsi:type=\"ns1:book\">
+    <a xsi:type=\"xsd:string\">foo</a>
+    <b xsi:type=\"xsd:string\">bar</b>
+</book>
+</ns1:dotest>
+ </env:Body>
+<env:Header/>
+</env:Envelope>";      
+
+function book_from_xml($xml) {
+       $sxe = simplexml_load_string($xml);
+       $obj = new book;
+       $obj->a = (string)$sxe->a;
+       $obj->b = (string)$sxe->b;
+       return $obj;
+}
+
+class test{
+       function dotest($book){
+               $classname=get_class($book);
+               return "Object: ".$classname. "(".$book->a.",".$book->b.")";
+       }       
+}
+
+class book{
+       public $a="a";
+       public $b="c";
+               
+}
+$options=Array(
+               'actor'   =>'http://schemas.nothing.com',
+               'typemap' => array(array("type_ns"   => "http://schemas.nothing.com",
+                                        "type_name" => "book",
+                                        "from_xml"  => "book_from_xml"))
+               );
+
+$server = new SoapServer(dirname(__FILE__)."/classmap.wsdl",$options);
+$server->setClass("test");
+$server->handle();
+echo "ok\n";
+?>
+--EXPECT--
+<?xml version="1.0" encoding="UTF-8"?>
+<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://schemas.nothing.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:dotestResponse><res xsi:type="xsd:string">Object: book(foo,bar)</res></ns1:dotestResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>
+ok
diff --git a/ext/soap/tests/typemap002.phpt b/ext/soap/tests/typemap002.phpt
new file mode 100755 (executable)
index 0000000..ee80c59
--- /dev/null
@@ -0,0 +1,56 @@
+--TEST--
+SOAP typemap 2: SoapServer support for typemap's to_xml()
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+$GLOBALS['HTTP_RAW_POST_DATA']="
+<env:Envelope xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\" 
+       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" 
+       xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" 
+       xmlns:enc=\"http://schemas.xmlsoap.org/soap/encoding/\"
+       xmlns:ns1=\"http://schemas.nothing.com\"
+>
+  <env:Body>
+<ns1:dotest2>
+<dotest2 xsi:type=\"xsd:string\">???</dotest2>
+</ns1:dotest2>
+ </env:Body>
+<env:Header/>
+</env:Envelope>";      
+
+function book_to_xml($book) {
+       return '<book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><a xsi:type="xsd:string">'.$book->a.'!</a><b xsi:type="xsd:string">'.$book->b.'!</b></book>';
+}
+
+class test{
+       function dotest2($str){
+               $book = new book;
+               $book->a = "foo";
+               $book->b = "bar";
+               return $book;
+       }       
+}
+
+class book{
+       public $a="a";
+       public $b="c";
+               
+}
+
+$options=Array(
+               'actor'   =>'http://schemas.nothing.com',
+               'typemap' => array(array("type_ns"   => "http://schemas.nothing.com",
+                                        "type_name" => "book",
+                                        "to_xml"    => "book_to_xml"))
+               );
+
+$server = new SoapServer(dirname(__FILE__)."/classmap.wsdl",$options);
+$server->setClass("test");
+$server->handle();
+echo "ok\n";
+?>
+--EXPECT--
+<?xml version="1.0" encoding="UTF-8"?>
+<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://schemas.nothing.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:dotest2Response><book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns1:book"><a xsi:type="xsd:string">foo!</a><b xsi:type="xsd:string">bar!</b></book></ns1:dotest2Response></SOAP-ENV:Body></SOAP-ENV:Envelope>
+ok
diff --git a/ext/soap/tests/typemap003.phpt b/ext/soap/tests/typemap003.phpt
new file mode 100755 (executable)
index 0000000..17bd6c1
--- /dev/null
@@ -0,0 +1,54 @@
+--TEST--
+SOAP Typemap 3: SoapClient support for typemap's from_xml()
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+class TestSoapClient extends SoapClient{
+  function __doRequest($request, $location, $action, $version) {
+               return <<<EOF
+<?xml version="1.0" encoding="UTF-8"?>
+<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://schemas.nothing.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body>
+<ns1:dotest2Response><res xsi:type="ns1:book">
+  <a xsi:type="xsd:string">foo</a>
+  <b xsi:type="xsd:string">bar</b>
+</res>
+</ns1:dotest2Response></SOAP-ENV:Body></SOAP-ENV:Envelope>
+EOF;
+       }       
+}
+
+class book{
+       public $a="a";
+       public $b="c";
+               
+}
+
+function book_from_xml($xml) {
+       $sxe = simplexml_load_string($xml);
+       $obj = new book;
+       $obj->a = (string)$sxe->a;
+       $obj->b = (string)$sxe->b;
+       return $obj;
+}
+
+$options=Array(
+               'actor' =>'http://schemas.nothing.com',
+               'typemap' => array(array("type_ns"   => "http://schemas.nothing.com",
+                                        "type_name" => "book",
+                                        "from_xml"  => "book_from_xml"))
+               );
+
+$client = new TestSoapClient(dirname(__FILE__)."/classmap.wsdl",$options);
+$ret = $client->dotest2("???");
+var_dump($ret);
+echo "ok\n";
+?>
+--EXPECTF--
+object(book)#%d (2) {
+  ["a"]=>
+  string(3) "foo"
+  ["b"]=>
+  string(3) "bar"
+}
+ok
diff --git a/ext/soap/tests/typemap004.phpt b/ext/soap/tests/typemap004.phpt
new file mode 100755 (executable)
index 0000000..f94af49
--- /dev/null
@@ -0,0 +1,41 @@
+--TEST--
+SOAP Typemap 4: SoapClient support for typemap's to_xml()
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+class TestSoapClient extends SoapClient{
+  function __doRequest($request, $location, $action, $version) {
+               echo $request;
+               exit;
+       }       
+}
+
+class book{
+       public $a="a";
+       public $b="c";
+               
+}
+
+function book_to_xml($book) {
+       return '<book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><a xsi:type="xsd:string">'.$book->a.'!</a><b xsi:type="xsd:string">'.$book->b.'!</b></book>';
+}
+
+$options=Array(
+               'actor' =>'http://schemas.nothing.com',
+               'typemap' => array(array("type_ns"   => "http://schemas.nothing.com",
+                                        "type_name" => "book",
+                                        "to_xml"  => "book_to_xml"))
+               );
+
+$client = new TestSoapClient(dirname(__FILE__)."/classmap.wsdl",$options);
+$book = new book();
+$book->a = "foo";
+$book->b = "bar";
+$ret = $client->dotest($book);
+var_dump($ret);
+echo "ok\n";
+?>
+--EXPECT--
+<?xml version="1.0" encoding="UTF-8"?>
+<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://schemas.nothing.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:dotest><book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns1:book"><a xsi:type="xsd:string">foo!</a><b xsi:type="xsd:string">bar!</b></book></ns1:dotest></SOAP-ENV:Body></SOAP-ENV:Envelope>
diff --git a/ext/soap/tests/typemap005.phpt b/ext/soap/tests/typemap005.phpt
new file mode 100755 (executable)
index 0000000..b016519
--- /dev/null
@@ -0,0 +1,61 @@
+--TEST--
+SOAP typemap 5: SoapServer support for typemap's from_xml() (without WSDL)
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+$GLOBALS['HTTP_RAW_POST_DATA']="
+<env:Envelope xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\" 
+       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" 
+       xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" 
+       xmlns:enc=\"http://schemas.xmlsoap.org/soap/encoding/\"
+       xmlns:ns1=\"http://schemas.nothing.com\"
+>
+  <env:Body>
+ <ns1:dotest>
+  <book xsi:type=\"ns1:book\">
+    <a xsi:type=\"xsd:string\">foo</a>
+    <b xsi:type=\"xsd:string\">bar</b>
+</book>
+</ns1:dotest>
+ </env:Body>
+<env:Header/>
+</env:Envelope>";      
+
+function book_from_xml($xml) {
+       $sxe = simplexml_load_string($xml);
+       $obj = new book;
+       $obj->a = (string)$sxe->a;
+       $obj->b = (string)$sxe->b;
+       return $obj;
+}
+
+class test{
+       function dotest($book){
+               $classname=get_class($book);
+               return "Object: ".$classname. "(".$book->a.",".$book->b.")";
+       }       
+}
+
+class book{
+       public $a="a";
+       public $b="c";
+               
+}
+$options=Array(
+               'uri'     => "http://schemas.nothing.com",
+               'actor'   => 'http://schemas.nothing.com',
+               'typemap' => array(array("type_ns"   => "http://schemas.nothing.com",
+                                        "type_name" => "book",
+                                        "from_xml"  => "book_from_xml"))
+               );
+
+$server = new SoapServer(NULL,$options);
+$server->setClass("test");
+$server->handle();
+echo "ok\n";
+?>
+--EXPECT--
+<?xml version="1.0" encoding="UTF-8"?>
+<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://schemas.nothing.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:dotestResponse><return xsi:type="xsd:string">Object: book(foo,bar)</return></ns1:dotestResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>
+ok
diff --git a/ext/soap/tests/typemap006.phpt b/ext/soap/tests/typemap006.phpt
new file mode 100755 (executable)
index 0000000..1e3609a
--- /dev/null
@@ -0,0 +1,57 @@
+--TEST--
+SOAP typemap 6: SoapServer support for typemap's to_xml() (without WSDL, using SoapVar)
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+$GLOBALS['HTTP_RAW_POST_DATA']="
+<env:Envelope xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\" 
+       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" 
+       xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" 
+       xmlns:enc=\"http://schemas.xmlsoap.org/soap/encoding/\"
+       xmlns:ns1=\"http://schemas.nothing.com\"
+>
+  <env:Body>
+<ns1:dotest2>
+<dotest2 xsi:type=\"xsd:string\">???</dotest2>
+</ns1:dotest2>
+ </env:Body>
+<env:Header/>
+</env:Envelope>";      
+
+function book_to_xml($book) {
+       return '<book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><a xsi:type="xsd:string">'.$book->a.'!</a><b xsi:type="xsd:string">'.$book->b.'!</b></book>';
+}
+
+class test{
+       function dotest2($str){
+               $book = new book;
+               $book->a = "foo";
+               $book->b = "bar";
+               return new SoapVar($book, null, "book", "http://schemas.nothing.com");
+       }       
+}
+
+class book{
+       public $a="a";
+       public $b="c";
+               
+}
+
+$options=Array(
+               'uri'     => "http://schemas.nothing.com",
+               'actor'   => 'http://schemas.nothing.com',
+               'typemap' => array(array("type_ns"   => "http://schemas.nothing.com",
+                                        "type_name" => "book",
+                                        "to_xml"    => "book_to_xml"))
+               );
+
+$server = new SoapServer(NULL,$options);
+$server->setClass("test");
+$server->handle();
+echo "ok\n";
+?>
+--EXPECT--
+<?xml version="1.0" encoding="UTF-8"?>
+<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://schemas.nothing.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:dotest2Response><book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns1:book"><a xsi:type="xsd:string">foo!</a><b xsi:type="xsd:string">bar!</b></book></ns1:dotest2Response></SOAP-ENV:Body></SOAP-ENV:Envelope>
+ok
diff --git a/ext/soap/tests/typemap007.phpt b/ext/soap/tests/typemap007.phpt
new file mode 100755 (executable)
index 0000000..8e2880b
--- /dev/null
@@ -0,0 +1,56 @@
+--TEST--
+SOAP Typemap 7: SoapClient support for typemap's from_xml() (without WSDL)
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+class TestSoapClient extends SoapClient{
+  function __doRequest($request, $location, $action, $version) {
+               return <<<EOF
+<?xml version="1.0" encoding="UTF-8"?>
+<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://schemas.nothing.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body>
+<ns1:dotest2Response><res xsi:type="ns1:book">
+  <a xsi:type="xsd:string">foo</a>
+  <b xsi:type="xsd:string">bar</b>
+</res>
+</ns1:dotest2Response></SOAP-ENV:Body></SOAP-ENV:Envelope>
+EOF;
+       }       
+}
+
+class book{
+       public $a="a";
+       public $b="c";
+               
+}
+
+function book_from_xml($xml) {
+       $sxe = simplexml_load_string($xml);
+       $obj = new book;
+       $obj->a = (string)$sxe->a;
+       $obj->b = (string)$sxe->b;
+       return $obj;
+}
+
+$options=Array(
+        'uri'      => 'http://schemas.nothing.com',
+        'location' => 'test://',
+               'actor'    => 'http://schemas.nothing.com',
+               'typemap'  => array(array("type_ns"   => "http://schemas.nothing.com",
+                                         "type_name" => "book",
+                                         "from_xml"  => "book_from_xml"))
+               );
+
+$client = new TestSoapClient(NULL, $options);
+$ret = $client->dotest2("???");
+var_dump($ret);
+echo "ok\n";
+?>
+--EXPECTF--
+object(book)#%d (2) {
+  ["a"]=>
+  string(3) "foo"
+  ["b"]=>
+  string(3) "bar"
+}
+ok
diff --git a/ext/soap/tests/typemap008.phpt b/ext/soap/tests/typemap008.phpt
new file mode 100755 (executable)
index 0000000..aaaa715
--- /dev/null
@@ -0,0 +1,43 @@
+--TEST--
+SOAP Typemap 8: SoapClient support for typemap's to_xml() (without WSDL, using SoapVar)
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+class TestSoapClient extends SoapClient{
+  function __doRequest($request, $location, $action, $version) {
+               echo $request;
+               exit;
+       }       
+}
+
+class book{
+       public $a="a";
+       public $b="c";
+               
+}
+
+function book_to_xml($book) {
+       return '<book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><a xsi:type="xsd:string">'.$book->a.'!</a><b xsi:type="xsd:string">'.$book->b.'!</b></book>';
+}
+
+$options=Array(
+        'uri'      => 'http://schemas.nothing.com',
+        'location' => 'test://',
+               'actor'    => 'http://schemas.nothing.com',
+               'typemap'  => array(array("type_ns"   => "http://schemas.nothing.com",
+                                         "type_name" => "book",
+                                         "to_xml"  => "book_to_xml"))
+               );
+
+$client = new TestSoapClient(NULL, $options);
+$book = new book();
+$book->a = "foo";
+$book->b = "bar";
+$ret = $client->dotest(new SoapVar($book, null, "book", "http://schemas.nothing.com"));
+var_dump($ret);
+echo "ok\n";
+?>
+--EXPECT--
+<?xml version="1.0" encoding="UTF-8"?>
+<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://schemas.nothing.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:dotest><book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns1:book"><a xsi:type="xsd:string">foo!</a><b xsi:type="xsd:string">bar!</b></book></ns1:dotest></SOAP-ENV:Body></SOAP-ENV:Envelope>
diff --git a/ext/soap/tests/typemap009.phpt b/ext/soap/tests/typemap009.phpt
new file mode 100755 (executable)
index 0000000..337aea6
--- /dev/null
@@ -0,0 +1,56 @@
+--TEST--
+SOAP typemap 9: SoapServer support for typemap's from_xml() (SoapFault)
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+$GLOBALS['HTTP_RAW_POST_DATA']="
+<env:Envelope xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\" 
+       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" 
+       xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" 
+       xmlns:enc=\"http://schemas.xmlsoap.org/soap/encoding/\"
+       xmlns:ns1=\"http://schemas.nothing.com\"
+>
+  <env:Body>
+ <ns1:dotest>
+  <book xsi:type=\"ns1:book\">
+    <a xsi:type=\"xsd:string\">foo</a>
+    <b xsi:type=\"xsd:string\">bar</b>
+</book>
+</ns1:dotest>
+ </env:Body>
+<env:Header/>
+</env:Envelope>";      
+
+function book_from_xml($xml) {
+       throw new SoapFault("Server", "Conversion Failed");
+}
+
+class test{
+       function dotest($book){
+               $classname=get_class($book);
+               return "Object: ".$classname. "(".$book->a.",".$book->b.")";
+       }       
+}
+
+class book{
+       public $a="a";
+       public $b="c";
+               
+}
+$options=Array(
+               'actor'   =>'http://schemas.nothing.com',
+               'typemap' => array(array("type_ns"   => "http://schemas.nothing.com",
+                                        "type_name" => "book",
+                                        "from_xml"  => "book_from_xml"))
+               );
+
+$server = new SoapServer(dirname(__FILE__)."/classmap.wsdl",$options);
+$server->setClass("test");
+$server->handle();
+echo "ok\n";
+?>
+--EXPECT--
+<?xml version="1.0" encoding="UTF-8"?>
+<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>SOAP-ENV:Server</faultcode><faultstring>Conversion Failed</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>
+ok
diff --git a/ext/soap/tests/typemap010.phpt b/ext/soap/tests/typemap010.phpt
new file mode 100755 (executable)
index 0000000..44d2746
--- /dev/null
@@ -0,0 +1,56 @@
+--TEST--
+SOAP typemap 10: SoapServer support for typemap's to_xml() (SoapFault)
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+$GLOBALS['HTTP_RAW_POST_DATA']="
+<env:Envelope xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\" 
+       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" 
+       xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" 
+       xmlns:enc=\"http://schemas.xmlsoap.org/soap/encoding/\"
+       xmlns:ns1=\"http://schemas.nothing.com\"
+>
+  <env:Body>
+<ns1:dotest2>
+<dotest2 xsi:type=\"xsd:string\">???</dotest2>
+</ns1:dotest2>
+ </env:Body>
+<env:Header/>
+</env:Envelope>";      
+
+function book_to_xml($book) {
+       throw new SoapFault("Server", "Conversion Fault");
+}
+
+class test{
+       function dotest2($str){
+               $book = new book;
+               $book->a = "foo";
+               $book->b = "bar";
+               return $book;
+       }       
+}
+
+class book{
+       public $a="a";
+       public $b="c";
+               
+}
+
+$options=Array(
+               'actor'   =>'http://schemas.nothing.com',
+               'typemap' => array(array("type_ns"   => "http://schemas.nothing.com",
+                                        "type_name" => "book",
+                                        "to_xml"    => "book_to_xml"))
+               );
+
+$server = new SoapServer(dirname(__FILE__)."/classmap.wsdl",$options);
+$server->setClass("test");
+$server->handle();
+echo "ok\n";
+?>
+--EXPECT--
+<?xml version="1.0" encoding="UTF-8"?>
+<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>SOAP-ENV:Server</faultcode><faultstring>Conversion Fault</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>
+ok
diff --git a/ext/soap/tests/typemap011.phpt b/ext/soap/tests/typemap011.phpt
new file mode 100755 (executable)
index 0000000..52acde2
--- /dev/null
@@ -0,0 +1,49 @@
+--TEST--
+SOAP Typemap 11: SoapClient support for typemap's from_xml() (SoapFault)
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+class TestSoapClient extends SoapClient{
+  function __doRequest($request, $location, $action, $version) {
+               return <<<EOF
+<?xml version="1.0" encoding="UTF-8"?>
+<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://schemas.nothing.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body>
+<ns1:dotest2Response><res xsi:type="ns1:book">
+  <a xsi:type="xsd:string">foo</a>
+  <b xsi:type="xsd:string">bar</b>
+</res>
+</ns1:dotest2Response></SOAP-ENV:Body></SOAP-ENV:Envelope>
+EOF;
+       }       
+}
+
+class book{
+       public $a="a";
+       public $b="c";
+               
+}
+
+function book_from_xml($xml) {
+       throw new SoapFault("Client", "Conversion Error");
+}
+
+$options=Array(
+               'actor' =>'http://schemas.nothing.com',
+               'typemap' => array(array("type_ns"   => "http://schemas.nothing.com",
+                                        "type_name" => "book",
+                                        "from_xml"  => "book_from_xml"))
+               );
+
+$client = new TestSoapClient(dirname(__FILE__)."/classmap.wsdl",$options);
+try {
+       $ret = $client->dotest2("???");
+} catch (SoapFault $e) {
+       $ret = "SoapFault = " . $e->faultcode . " - " . $e->faultstring;
+}
+var_dump($ret);
+echo "ok\n";
+?>
+--EXPECT--
+string(37) "SoapFault = Client - Conversion Error"
+ok
diff --git a/ext/soap/tests/typemap012.phpt b/ext/soap/tests/typemap012.phpt
new file mode 100755 (executable)
index 0000000..aa06215
--- /dev/null
@@ -0,0 +1,45 @@
+--TEST--
+SOAP Typemap 12: SoapClient support for typemap's to_xml() (SoapFault)
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+class TestSoapClient extends SoapClient{
+  function __doRequest($request, $location, $action, $version) {
+               echo $request;
+               exit;
+       }       
+}
+
+class book{
+       public $a="a";
+       public $b="c";
+               
+}
+
+function book_to_xml($book) {
+       throw new SoapFault("Client", "Conversion Error");
+}
+
+$options=Array(
+               'actor' =>'http://schemas.nothing.com',
+               'typemap' => array(array("type_ns"   => "http://schemas.nothing.com",
+                                        "type_name" => "book",
+                                        "to_xml"  => "book_to_xml"))
+               );
+
+$client = new TestSoapClient(dirname(__FILE__)."/classmap.wsdl",$options);
+$book = new book();
+$book->a = "foo";
+$book->b = "bar";
+try {
+       $ret = $client->dotest($book);
+} catch (SoapFault $e) {
+       $ret = "SoapFault = " . $e->faultcode . " - " . $e->faultstring;
+}
+var_dump($ret);
+echo "ok\n";
+?>
+--EXPECT--
+string(37) "SoapFault = Client - Conversion Error"
+ok