2013-08-24 8 views
6

Sto cercando di implementare un server SOAP utilizzando la classe Zend_Soap_Server in PHP.Gli spazi dei nomi di PHP5 generano un nome di tipo WSDL errato durante l'implementazione di un servizio web

Ecco il file webservice.php che è il punto di ingresso di richiesta:

<?php 
require_once 'library.php'; 
require_once 'Zend/Loader/Autoloader.php'; 
$autoloader = \Zend_Loader_Autoloader::getInstance(); 

class Math 
{ 
    /** 
    * This method takes ... 
    * 
    * @param integer $inputParam 
    * @return \Library\IncrementedInt 
    */ 
    public function increment($inputParam) 
    { 
     return new \Library\IncrementedInt($inputParam); 
    } 
} 

$options = array('uri' => 'http://localhost' . $_SERVER['REQUEST_URI']); 

if (isset($_GET['wsdl'])){ 
    $server = new Zend_Soap_AutoDiscover(); 
    $server->setClass('Math'); 
} 
else { 
    $server = new Zend_Soap_Server(null, $options); 
    $server->setClass('Math'); 
    $server->setObject(new Math()); 
} 

$server->handle(); 

e ho library.php file in questo modo:

<?php 
namespace Library; 

class IncrementedInt 
{ 
    public $original; 
    public $incremented; 

    public function __construct($num) 
    { 
     $this->original = $num; 
     $this->incremented = ++$num; 
    } 
} 

Una chiamata a http://localhost/webservice.php?wsdl uscita volontà:

<definitions xmlns="http://schemas.xmlsoap.org/wsdl/" 

xmlns:tns="http://localhost/webservice.php" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap-enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" name="Math" targetNamespace="http://localhost/webservice.php"> 
    <script/> 
    <types> 
     <xsd:schema targetNamespace="http://localhost/webservice.php"> 
      <xsd:complexType name="\Library\IncrementedInt"> 
       <xsd:all/> 
      </xsd:complexType> 
     </xsd:schema> 
    </types> 
    <portType name="MathPort"> 
     <operation name="increment"> 
      <documentation>This method takes ...</documentation> 
      <input message="tns:incrementIn"/> 
      <output message="tns:incrementOut"/> 
     </operation> 
    </portType> 
    <binding name="MathBinding" type="tns:MathPort"> 
     <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> 
     <operation name="increment"> 
      <soap:operation soapAction="http://localhost/webservice.php#increment"/> 
      <input> 
       <soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost/webservice.php"/> 
      </input> 
      <output> 
       <soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost/webservice.php"/> 
      </output> 
     </operation> 
    </binding> 
    <service name="MathService"> 
     <port name="MathPort" binding="tns:MathBinding"> 
      <soap:address location="http://localhost/webservice.php"/> 
     </port> 
    </service> 
    <message name="incrementIn"> 
     <part name="inputParam" type="xsd:int"/> 
    </message> 
    <message name="incrementOut"> 
     <part name="return" type="tns:\Library\IncrementedInt"/> 
    </message> 
</definitions> 

Ora per testare la funzionalità Io uso soapUI 4.5.1 che è un'applicazione Java che implementa un client SOAP. Dandogli l'URI http://localhost/webservice.php?wsdl dovrebbe portare alla funzione increment estratta ma non lo farà. Al contrario, viene visualizzato un messaggio di errore: The Value '\Library\IncrementInt' is an invalid name. Mi sembra che stia riscontrando un problema nell'accettare \ come parte di un nome di tipo. D'altra parte, PHP non può fare a meno di loro.

Per assicurarsi che tutto il resto sia OK, ho testato gli stessi file esatti senza lo spazio dei nomi e funziona senza intoppi.

Qualcuno ha affrontato un problema simile e, cosa più importante, qualcuno sa come superare questo problema?

[UPDATE]

sono riuscito a testare the same scenario with ZF2 e funziona. Forse devo rinunciare a ZF1!

+0

L'implementazione nativa di SOAP in PHP è orribilmente, completamente infranta. Abbiamo segnalato un [non così piccolo bug] (https://bugs.php.net/bug.php?id=50675) nel 2010 presso il mio vecchio posto di lavoro ed è ancora aperto. Anche se non ho controllato, ma le mie scommesse si sarebbero basate su Zend_Soap basato sull'implementazione nativa di SOAP, quindi è meglio fare attenzione. – Janoszen

risposta

4

Il tipo di oggetto XSD \Library\IncrementedIntnon è una classe PHP all'interno di uno spazio dei nomi di PHP come te delineare:

<?php 
namespace Library; 

class IncrementedInt 
{ 
    ... 

Il tipo actualy prefissato è:

tns:\Library\IncrementedInt 

E la mente il tns: davanti che è il prefisso. Non si poteva esprimere è in PHP, che diventa ancora più evidente quando si espande ad esso di namespace URI:

{http://localhost/webservice.php}\Library\IncrementedInt 

anche Zend SOAP viene da un momento prima PHP namespace (PHP 5.2), quindi ha bisogno di adottare una strategia diversa per aliasare questo tipo su un tipo PHP (nomenclatura).Prende il nome locale del tipo:

\Library\IncrementedInt 

e sostituisce ogni carattere "non valido" in quel nome-tipo con un carattere di sottolineatura:

_Library_IncrementedInt 

È pertanto necessario dare un nome al classe in questo modo:

<?php 

class _Library_IncrementedInt 
{ 
    ... 

Se si vuole farlo funzionare fuori dalla scatola.


È quindi chiesto tramite i commenti di chiarimento:

So what you are saying is that, there's nothing I can do to have a namespaced class as a type name, right?

Beh, per quanto riguarda il comportamento di default molto probabilmente non, tuttavia, come la strategia a lungo termine è coinvolto, direi che ci sono alcune meccanismo per estendere Zend Soap per quell'operazione e iniettarne uno diverso che, ad esempio, consente classi con nomi (classi con il loro FQCN), vedere Strategy Pattern.

E se questa è solo una singola classe, nel frattempo è possibile eseguire qualche trucco economico ed estendere la classe con nomi assegnati come nome breve o alias con class_alias.

+0

Quindi quello che stai dicendo è che, non c'è nulla che io possa fare per avere una classe namespaced come nome di un tipo, giusto? – Mehran

+0

Mi piace il modo class_alais. È pratico nel mio caso. – Mehran

+0

Ti presento con la taglia. Potresti considerare di aggiungere i due commenti nella risposta principale? Personalmente sto prendendo l'hack class_alias come risposta che stavo cercando. Grazie per l'aiuto. – Mehran

1

Zend_Soap_AutoDiscover prende il nome di tipo dal blocco phpdoc, vale a dire, da questa riga di commento:

* @return \Library\IncrementedInt 

basta solo cambiare quel tipo, ad esempio, IncrementedInt, senza un namespace e barre.

+0

Prima lascia che ti ringrazio per il tuo post. Ma temo che la tua soluzione non funzioni (anche se sembra abbastanza ragionevole). Quando l'ho provato, ecco cosa ho ottenuto: 'Errore irreversibile: eccezione non rilevata 'Zend_Soap_Wsdl_Exception' con messaggio 'Impossibile aggiungere un tipo complesso _Library_IncrementedInt che non è un oggetto o dove non è stato possibile trovare la classe nella strategia' DefaultComplexType '. in Zend/Soap/Wsdl/Strategy/DefaultComplexType.php alla riga 49'. AYCS, ho cambiato il percorso della classe in '_Library_IncrementedInt' ma sembra che ZF abbia bisogno che sia valido per funzionare. Grazie comunque. – Mehran