eZ Publish  [trunk]
ezsoapresponse.php
Go to the documentation of this file.
00001 <?php
00002 /**
00003  * File containing the eZSOAPResponse class.
00004  *
00005  * @copyright Copyright (C) 1999-2012 eZ Systems AS. All rights reserved.
00006  * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License v2
00007  * @version //autogentag//
00008  * @package lib
00009  */
00010 
00011 /*!
00012   \class eZSOAPResponse ezsoapresponse.php
00013   \ingroup eZSOAP
00014   \brief eZSOAPResponse handles SOAP response packages
00015 
00016 */
00017 
00018 class eZSOAPResponse extends eZSOAPEnvelope
00019 {
00020     /*!
00021       Constructs a new SOAP response
00022     */
00023     function eZSOAPResponse( $name="", $namespace="" )
00024     {
00025         $this->Name = $name;
00026         $this->Namespace = $namespace;
00027 
00028         // call the parents constructor
00029         $this->eZSOAPEnvelope();
00030     }
00031 
00032     /*!
00033       Decodes the SOAP response stream
00034     */
00035     function decodeStream( $request, $stream )
00036     {
00037         $dom = new DOMDocument( "1.0" );
00038 
00039         $success = $dom->loadXML( $this->stripHTTPHeader( $stream ) );
00040         $this->DOMDocument = $dom;
00041 
00042         if ( $success && !empty( $dom ) )
00043         {
00044             // check for fault
00045             $response = $dom->getElementsByTagNameNS( eZSOAPEnvelope::ENV, 'Fault' );
00046 
00047             if ( $response->length  == 1 )
00048             {
00049                 $this->IsFault = 1;
00050                 foreach( $dom->getElementsByTagName( "faultstring" ) as $faultNode )
00051                 {
00052                     $this->FaultString = $faultNode->textContent;
00053                     break;
00054                 }
00055 
00056                 foreach( $dom->getElementsByTagName( "faultcode" ) as $faultNode )
00057                 {
00058                     $this->FaultCode = $faultNode->textContent;
00059                     break;
00060                 }
00061                 return;
00062             }
00063 
00064             // get the response
00065             $response = $dom->getElementsByTagNameNS( $request->ns(), $request->name() . "Response" );
00066 
00067             /* Some protocols do not use namespaces, and do not work with an empty namespace.
00068             So, if we get no response, try again without namespace.
00069             */
00070             if ( $response->length == 0 )
00071             {
00072                 $response = $dom->getElementsByTagName( $request->name() . "Response" );
00073             }
00074 
00075             $response = $response->item(0);
00076 
00077             if ( !empty( $response ) )
00078             {
00079                 /* Cut from the SOAP spec:
00080                 The method response is viewed as a single struct containing an accessor
00081                 for the return value and each [out] or [in/out] parameter.
00082                 The first accessor is the return value followed by the parameters
00083                 in the same order as in the method signature.
00084 
00085                 Each parameter accessor has a name corresponding to the name
00086                 of the parameter and type corresponding to the type of the parameter.
00087                 The name of the return value accessor is not significant.
00088                 Likewise, the name of the struct is not significant.
00089                 However, a convention is to name it after the method name
00090                 with the string "Response" appended.
00091                 */
00092 
00093                 $responseAccessors = $response->getElementsByTagName( 'return' );
00094                 if ( $responseAccessors->length > 0 )
00095                 {
00096                     $returnObject = $responseAccessors->item( 0 );
00097                     $this->Value  = $this->decodeDataTypes( $returnObject );
00098                 }
00099             }
00100             else
00101             {
00102                 eZDebug::writeError( "Got error from server" );
00103             }
00104         }
00105         else
00106         {
00107             eZDebug::writeError( "Could not process XML in response" );
00108         }
00109     }
00110 
00111     /*!
00112       \static
00113       Decodes a DOM node and returns the PHP datatype instance of it.
00114     */
00115     static function decodeDataTypes( $node, $type = "" )
00116     {
00117         $returnValue = false;
00118 
00119         $attributeValue = '';
00120         $attribute = $node->getAttributeNodeNS( eZSOAPEnvelope::SCHEMA_INSTANCE, 'type' );
00121         if ( !$attribute )
00122         {
00123             $attribute = $node->getAttributeNodeNS( 'http://www.w3.org/1999/XMLSchema-instance', 'type' );
00124         }
00125         $attributeValue = $attribute->value;
00126 
00127         $dataType = $type;
00128         $attrParts = explode( ":", $attributeValue );
00129         if ( $attrParts[1] )
00130         {
00131             $dataType = $attrParts[1];
00132         }
00133 
00134 /*
00135         $typeNamespacePrefix = $this->DOMDocument->namespaceByAlias( $attrParts[0] );
00136 
00137         check that this is a namespace type definition
00138                 if ( ( $typeNamespacePrefix == eZSOAPEnvelope::SCHEMA_DATA ) ||
00139                      ( $typeNamespacePrefix == eZSOAPEnvelope::ENC )
00140                      )
00141 TODO: add encoding checks with schema validation.
00142 */
00143 
00144         switch ( $dataType )
00145         {
00146             case "string" :
00147             case "int" :
00148             case "float" :
00149             case 'double' :
00150             {
00151                 $returnValue = $node->textContent;
00152             } break;
00153 
00154             case "boolean" :
00155             {
00156                 if ( $node->textContent == "true" )
00157                     $returnValue = true;
00158                 else
00159                     $returnValue = false;
00160             } break;
00161 
00162             case "base64" :
00163             {
00164                 $returnValue = base64_decode( $node->textContent );
00165             } break;
00166 
00167             case "Array" :
00168             {
00169                 // Get array type
00170                 $arrayType = $node->getAttributeNodeNS( eZSOAPEnvelope::ENC, 'arrayType' )->value;
00171                 $arrayTypeParts = explode( ":", $arrayType );
00172 
00173                 preg_match( "#(.*)\[(.*)\]#",  $arrayTypeParts[1], $matches );
00174 
00175                 $type = $matches[1];
00176                 $count = $matches[2];
00177 
00178                 $returnValue = array();
00179                 foreach( $node->childNodes as $child )
00180                 {
00181                     if ( $child instanceof DOMElement )
00182                     {
00183                         $returnValue[] = eZSOAPResponse::decodeDataTypes( $child, $type );
00184                     }
00185                 }
00186             }break;
00187 
00188             case "SOAPStruct" :
00189             {
00190                 $returnValue = array();
00191 
00192                 foreach( $node->childNodes as $child )
00193                 {
00194                     if ( $child instanceof DOMElement )
00195                     {
00196                         $returnValue[$child->tagName] = eZSOAPResponse::decodeDataTypes( $child );
00197                     }
00198                 }
00199             }break;
00200 
00201             default:
00202             {
00203                 foreach ( $node->childNodes as $childNode )
00204                 {
00205                     if ( $childNode instanceof DOMElement )
00206                     {
00207                         // check data type for child
00208                         $attr = $childNode->getAttributeNodeNS( eZSOAPEnvelope::SCHEMA_INSTANCE, 'type' )->value;
00209 
00210                         $dataType = false;
00211                         $attrParts = explode( ":", $attr );
00212                         $dataType = $attrParts[1];
00213 
00214                         $returnValue[$childNode->tagName] = eZSOAPResponse::decodeDataTypes( $childNode );
00215                     }
00216                 }
00217 
00218             } break;
00219         }
00220 
00221         return $returnValue;
00222     }
00223 
00224     /*!
00225       Returns the XML payload for the response.
00226     */
00227     function payload( )
00228     {
00229         $doc = new DOMDocument( '1.0', 'utf-8' );
00230         $doc->name = "eZSOAP message";
00231 
00232         $root = $doc->createElementNS( eZSOAPEnvelope::ENV, eZSOAPEnvelope::ENV_PREFIX . ':Envelope' );
00233 
00234         $root->setAttribute( 'xmlns:' . eZSOAPEnvelope::XSI_PREFIX, eZSOAPEnvelope::SCHEMA_INSTANCE );
00235         $root->setAttribute( 'xmlns:' . eZSOAPEnvelope::XSD_PREFIX, eZSOAPEnvelope::SCHEMA_DATA );
00236         $root->setAttribute( 'xmlns:' . eZSOAPEnvelope::ENC_PREFIX, eZSOAPEnvelope::ENC );
00237 
00238         // add the body
00239         $body = $doc->createElement(  eZSOAPEnvelope::ENV_PREFIX . ':Body' );
00240         $root->appendChild( $body );
00241 
00242         // Check if it's a fault
00243         if ( $this->Value instanceof eZSOAPFault )
00244         {
00245             $fault = $doc->createElement( eZSOAPEnvelope::ENV_PREFIX . ':Fault' );
00246 
00247             $faultCodeNode = $doc->createElement( "faultcode", $this->Value->faultCode() );
00248             $fault->appendChild( $faultCodeNode );
00249 
00250             $faultStringNode = $doc->createElement( "faultstring", $this->Value->faultString() );
00251             $fault->appendChild( $faultStringNode );
00252 
00253             $body->appendChild( $fault );
00254         }
00255         else
00256         {
00257             // add the request
00258             $responseName = $this->Name . "Response";
00259             if ( $this->Namespace == '' )
00260                 $response = $doc->createElement( "resp:".$responseName );
00261             else
00262                 $response = $doc->createElementNS( $this->Namespace, "resp:".$responseName );
00263 
00264             $return = $doc->createElement( "return" );
00265 
00266             $value = eZSOAPCodec::encodeValue( $doc, "return", $this->Value );
00267 
00268             $body->appendChild( $response );
00269 
00270             $response->appendChild( $value );
00271         }
00272 
00273         $doc->appendChild( $root );
00274 
00275         return $doc->saveXML();
00276     }
00277 
00278     /*!
00279       \static
00280       \private
00281       Strips the header information from the HTTP raw response.
00282     */
00283     function stripHTTPHeader( $data )
00284     {
00285         $missingxml = false;
00286         $start = strpos( $data, "<?xml" );
00287         if ( $start === false )
00288         {
00289             eZDebug::writeWarning( "missing <?xml ...> in HTTP response, attempting workaround", __METHOD__ );
00290             $start = strpos( $data, "<E:Envelope" );
00291             $missingxml = true;
00292         }
00293         $data = substr( $data, $start, strlen( $data ) - $start );
00294 
00295         if ( $missingxml == true )
00296         {
00297             $data = '<?xml version="1.0"?>' . $data;
00298         }
00299 
00300         return $data;
00301     }
00302 
00303     /*!
00304       Returns the response value.
00305     */
00306     function value()
00307     {
00308         return $this->Value;
00309     }
00310 
00311     /*!
00312      Sets the value of the response.
00313     */
00314     function setValue( $value )
00315     {
00316         $this->Value = $value;
00317     }
00318 
00319     /*!
00320      Returns true if the response was a fault
00321     */
00322     function isFault()
00323     {
00324         return $this->IsFault;
00325     }
00326 
00327     /*!
00328      Returns the fault code
00329     */
00330     function faultCode()
00331     {
00332         return $this->FaultCode;
00333     }
00334 
00335     /*!
00336      Returns the fault string
00337     */
00338     function faultString()
00339     {
00340         return $this->FaultString;
00341     }
00342 
00343     /// Contains the response value
00344     public $Value = false;
00345     /// Contains the response type
00346     public $Type = false;
00347     /// Contains fault string
00348     public $FaultString = false;
00349     /// Contains the fault code
00350     public $FaultCode = false;
00351     /// Contains true if the response was an fault
00352     public $IsFault = false;
00353     /// Contains the name of the response, i.e. function call name
00354     public $Name;
00355     /// Contains the target namespace for the response
00356     public $Namespace;
00357 
00358     /// Contains the DOM document for the current SOAP response
00359     public $DOMDocument = false;
00360 }
00361 
00362 ?>