function objectToArray($object) { if (!is_object($object) && !is_array($object)) { return $object; } if (is_object($object)) { $object = get_object_publics($object); } return array_map('objectToArray', $object); }
/** * serializes PHP values in accordance w/ section 5. Type information is * not serialized if $use == 'literal'. * * @param mixed $val The value to serialize * @param string $name The name (local part) of the XML element * @param string $type The XML schema type (local part) for the element * @param string $name_ns The namespace for the name of the XML element * @param string $type_ns The namespace for the type of the element * @param array $attributes The attributes to serialize as name=>value pairs * @param string $use The WSDL "use" (encoded|literal) * @param boolean $soapval Whether this is called from soapval. * @return string The serialized element, possibly with child elements * @access public */ function serialize_val($val, $name = false, $type = false, $name_ns = false, $type_ns = false, $attributes = false, $use = 'encoded', $soapval = false) { $this->debug("in serialize_val: name={$name}, type={$type}, name_ns={$name_ns}, type_ns={$type_ns}, use={$use}, soapval={$soapval}"); $this->appendDebug('value=' . $this->publicDump($val)); $this->appendDebug('attributes=' . $this->publicDump($attributes)); if (is_object($val) && get_class($val) == 'soapval' && !$soapval) { $this->debug("serialize_val: serialize soapval"); $xml = $val->serialize($use); $this->appendDebug($val->getDebug()); $val->clearDebug(); $this->debug("serialize_val of soapval returning {$xml}"); return $xml; } // force valid name if necessary if (is_numeric($name)) { $name = '__numeric_' . $name; } elseif (!$name) { $name = 'noname'; } // if name has ns, add ns prefix to name $xmlns = ''; if ($name_ns) { $prefix = 'nu' . rand(1000, 9999); $name = $prefix . ':' . $name; $xmlns .= " xmlns:{$prefix}=\"{$name_ns}\""; } // if type is prefixed, create type prefix if ($type_ns != '' && $type_ns == $this->namespaces['xsd']) { // need to fix this. shouldn't default to xsd if no ns specified // w/o checking against typemap $type_prefix = 'xsd'; } elseif ($type_ns) { $type_prefix = 'ns' . rand(1000, 9999); $xmlns .= " xmlns:{$type_prefix}=\"{$type_ns}\""; } // serialize attributes if present $atts = ''; if ($attributes) { foreach ($attributes as $k => $v) { $atts .= " {$k}=\"" . $this->expandEntities($v) . '"'; } } // serialize null value if (is_null($val)) { $this->debug("serialize_val: serialize null"); if ($use == 'literal') { // TODO: depends on minOccurs $xml = "<{$name}{$xmlns}{$atts}/>"; $this->debug("serialize_val returning {$xml}"); return $xml; } else { if (isset($type) && isset($type_prefix)) { $type_str = " xsi:type=\"{$type_prefix}:{$type}\""; } else { $type_str = ''; } $xml = "<{$name}{$xmlns}{$type_str}{$atts} xsi:nil=\"true\"/>"; $this->debug("serialize_val returning {$xml}"); return $xml; } } // serialize if an xsd built-in primitive type if ($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])) { $this->debug("serialize_val: serialize xsd built-in primitive type"); if (is_bool($val)) { if ($type == 'boolean') { $val = $val ? 'true' : 'false'; } elseif (!$val) { $val = 0; } } else { if (is_string($val)) { $val = $this->expandEntities($val); } } if ($use == 'literal') { $xml = "<{$name}{$xmlns}{$atts}>{$val}</{$name}>"; $this->debug("serialize_val returning {$xml}"); return $xml; } else { $xml = "<{$name}{$xmlns} xsi:type=\"xsd:{$type}\"{$atts}>{$val}</{$name}>"; $this->debug("serialize_val returning {$xml}"); return $xml; } } // detect type and serialize $xml = ''; switch (true) { case is_bool($val) || $type == 'boolean': $this->debug("serialize_val: serialize boolean"); if ($type == 'boolean') { $val = $val ? 'true' : 'false'; } elseif (!$val) { $val = 0; } if ($use == 'literal') { $xml .= "<{$name}{$xmlns}{$atts}>{$val}</{$name}>"; } else { $xml .= "<{$name}{$xmlns} xsi:type=\"xsd:boolean\"{$atts}>{$val}</{$name}>"; } break; case is_int($val) || is_long($val) || $type == 'int': $this->debug("serialize_val: serialize int"); if ($use == 'literal') { $xml .= "<{$name}{$xmlns}{$atts}>{$val}</{$name}>"; } else { $xml .= "<{$name}{$xmlns} xsi:type=\"xsd:int\"{$atts}>{$val}</{$name}>"; } break; case is_float($val) || is_double($val) || $type == 'float': $this->debug("serialize_val: serialize float"); if ($use == 'literal') { $xml .= "<{$name}{$xmlns}{$atts}>{$val}</{$name}>"; } else { $xml .= "<{$name}{$xmlns} xsi:type=\"xsd:float\"{$atts}>{$val}</{$name}>"; } break; case is_string($val) || $type == 'string': $this->debug("serialize_val: serialize string"); $val = $this->expandEntities($val); if ($use == 'literal') { $xml .= "<{$name}{$xmlns}{$atts}>{$val}</{$name}>"; } else { $xml .= "<{$name}{$xmlns} xsi:type=\"xsd:string\"{$atts}>{$val}</{$name}>"; } break; case is_object($val): $this->debug("serialize_val: serialize object"); if (get_class($val) == 'soapval') { $this->debug("serialize_val: serialize soapval object"); $pXml = $val->serialize($use); $this->appendDebug($val->getDebug()); $val->clearDebug(); } else { if (!$name) { $name = get_class($val); $this->debug("In serialize_val, used class name {$name} as element name"); } else { $this->debug("In serialize_val, do not override name {$name} for element name for class " . get_class($val)); } foreach (get_object_publics($val) as $k => $v) { $pXml = isset($pXml) ? $pXml . $this->serialize_val($v, $k, false, false, false, false, $use) : $this->serialize_val($v, $k, false, false, false, false, $use); } } if (isset($type) && isset($type_prefix)) { $type_str = " xsi:type=\"{$type_prefix}:{$type}\""; } else { $type_str = ''; } if ($use == 'literal') { $xml .= "<{$name}{$xmlns}{$atts}>{$pXml}</{$name}>"; } else { $xml .= "<{$name}{$xmlns}{$type_str}{$atts}>{$pXml}</{$name}>"; } break; break; case is_array($val) || $type: // detect if struct or array $valueType = $this->isArraySimpleOrStruct($val); if ($valueType == 'arraySimple' || preg_match('/^ArrayOf/', $type)) { $this->debug("serialize_val: serialize array"); $i = 0; if (is_array($val) && count($val) > 0) { foreach ($val as $v) { if (is_object($v) && get_class($v) == 'soapval') { $tt_ns = $v->type_ns; $tt = $v->type; } elseif (is_array($v)) { $tt = $this->isArraySimpleOrStruct($v); } else { $tt = gettype($v); } $array_types[$tt] = 1; // TODO: for literal, the name should be $name $xml .= $this->serialize_val($v, 'item', false, false, false, false, $use); ++$i; } if (count($array_types) > 1) { $array_typename = 'xsd:anyType'; } elseif (isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) { if ($tt == 'integer') { $tt = 'int'; } $array_typename = 'xsd:' . $tt; } elseif (isset($tt) && $tt == 'arraySimple') { $array_typename = 'SOAP-ENC:Array'; } elseif (isset($tt) && $tt == 'arrayStruct') { $array_typename = 'unnamed_struct_use_soapval'; } else { // if type is prefixed, create type prefix if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']) { $array_typename = 'xsd:' . $tt; } elseif ($tt_ns) { $tt_prefix = 'ns' . rand(1000, 9999); $array_typename = "{$tt_prefix}:{$tt}"; $xmlns .= " xmlns:{$tt_prefix}=\"{$tt_ns}\""; } else { $array_typename = $tt; } } $array_type = $i; if ($use == 'literal') { $type_str = ''; } else { if (isset($type) && isset($type_prefix)) { $type_str = " xsi:type=\"{$type_prefix}:{$type}\""; } else { $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"" . $array_typename . "[{$array_type}]\""; } } // empty array } else { if ($use == 'literal') { $type_str = ''; } else { if (isset($type) && isset($type_prefix)) { $type_str = " xsi:type=\"{$type_prefix}:{$type}\""; } else { $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\""; } } } // TODO: for array in literal, there is no wrapper here $xml = "<{$name}{$xmlns}{$type_str}{$atts}>" . $xml . "</{$name}>"; } else { // got a struct $this->debug("serialize_val: serialize struct"); if (isset($type) && isset($type_prefix)) { $type_str = " xsi:type=\"{$type_prefix}:{$type}\""; } else { $type_str = ''; } if ($use == 'literal') { $xml .= "<{$name}{$xmlns}{$atts}>"; } else { $xml .= "<{$name}{$xmlns}{$type_str}{$atts}>"; } foreach ($val as $k => $v) { // Apache Map if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') { $xml .= '<item>'; $xml .= $this->serialize_val($k, 'key', false, false, false, false, $use); $xml .= $this->serialize_val($v, 'value', false, false, false, false, $use); $xml .= '</item>'; } else { $xml .= $this->serialize_val($v, $k, false, false, false, false, $use); } } $xml .= "</{$name}>"; } break; default: $this->debug("serialize_val: serialize unknown"); $xml .= 'not detected, got ' . gettype($val) . ' for ' . $val; break; } $this->debug("serialize_val returning {$xml}"); return $xml; }
/** * serializes the elements for a complexType * * @param array $typeDef our internal representation of an XML schema type (or element) * @param mixed $value a native PHP value (parameter value) * @param string $ns the namespace of the type * @param string $uqType the local part of the type * @param string $use use for part (encoded|literal) * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style) * @return string value serialized as an XML string * @access private */ function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use = 'encoded', $encodingStyle = false) { $this->debug("in serializeComplexTypeElements for XML Schema type {$ns}:{$uqType}"); $xml = ''; if (isset($typeDef['extensionBase'])) { $nsx = $this->getPrefix($typeDef['extensionBase']); $uqTypex = $this->getLocalPart($typeDef['extensionBase']); if ($this->getNamespaceFromPrefix($nsx)) { $nsx = $this->getNamespaceFromPrefix($nsx); } if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) { $this->debug("serialize elements for extension base {$nsx}:{$uqTypex}"); $xml .= $this->serializeComplexTypeElements($typeDefx, $value, $nsx, $uqTypex, $use, $encodingStyle); } else { $this->debug("extension base {$nsx}:{$uqTypex} is not a supported type"); } } if (isset($typeDef['elements']) && is_array($typeDef['elements'])) { $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type {$ns}:{$uqType}"); if (is_array($value)) { $xvalue = $value; } elseif (is_object($value)) { $xvalue = get_object_publics($value); } else { $this->debug("value is neither an array nor an object for XML Schema type {$ns}:{$uqType}"); $xvalue = array(); } // toggle whether all elements are present - ideally should validate against schema if (count($typeDef['elements']) != count($xvalue)) { $optionals = true; } foreach ($typeDef['elements'] as $eName => $attrs) { if (!isset($xvalue[$eName])) { if (isset($attrs['default'])) { $xvalue[$eName] = $attrs['default']; $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName); } } // if user took advantage of a minOccurs=0, then only serialize named parameters if (isset($optionals) && !isset($xvalue[$eName]) && (!isset($attrs['nillable']) || $attrs['nillable'] != 'true')) { if (isset($attrs['minOccurs']) && $attrs['minOccurs'] != '0') { $this->debug("apparent error: no value provided for element {$eName} with minOccurs=" . $attrs['minOccurs']); } // do nothing $this->debug("no value provided for complexType element {$eName} and element is not nillable, so serialize nothing"); } else { // get value if (isset($xvalue[$eName])) { $v = $xvalue[$eName]; } else { $v = null; } if (isset($attrs['form'])) { $unqualified = $attrs['form'] == 'unqualified'; } else { $unqualified = false; } if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') { $vv = $v; foreach ($vv as $k => $v) { if (isset($attrs['type']) || isset($attrs['ref'])) { // serialize schema-defined type $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); } else { // serialize generic type (can this ever really happen?) $this->debug("calling serialize_val() for {$v}, {$eName}, false, false, false, false, {$use}"); $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use); } } } else { if (is_null($v) && isset($attrs['minOccurs']) && $attrs['minOccurs'] == '0') { // do nothing } elseif (is_null($v) && isset($attrs['nillable']) && $attrs['nillable'] == 'true') { // TODO: serialize a nil correctly, but for now serialize schema-defined type $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); } elseif (isset($attrs['type']) || isset($attrs['ref'])) { // serialize schema-defined type $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); } else { // serialize generic type (can this ever really happen?) $this->debug("calling serialize_val() for {$v}, {$eName}, false, false, false, false, {$use}"); $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use); } } } } } else { $this->debug("no elements to serialize for XML Schema type {$ns}:{$uqType}"); } return $xml; }