2013-08-24 16 views
6

Próbuję zaimplementować serwer SOAP przy użyciu klasy Zend_Soap_Server w PHP.Przestrzenie nazw PHP5 prowadzą do niepoprawnej nazwy typu WSDL podczas implementacji usługi internetowej

Oto plik webservice.php który jest punktem wejścia żądanie:

<?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(); 

I mam library.php plik tak:

<?php 
namespace Library; 

class IncrementedInt 
{ 
    public $original; 
    public $incremented; 

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

Wywołanie http://localhost/webservice.php?wsdl wyjście wola:

<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> 

Teraz, aby przetestować funkcjonalność używam soapUI 4.5.1, która jest aplikacją Java, która implementuje klienta SOAP. Podanie jej URI http://localhost/webservice.php?wsdl powinno prowadzić do wyodrębnienia funkcji increment, ale nie będzie. Zamiast tego wyświetla komunikat o błędzie: The Value '\Library\IncrementInt' is an invalid name. Wydaje mi się, że ma problem z zaakceptowaniem \ jako części nazwy typu. Z drugiej strony PHP nie może się bez nich obejść.

Aby upewnić się, że wszystko inne jest w porządku, przetestowałem dokładnie te same pliki bez przestrzeni nazw i działało płynnie.

Czy ktoś miał podobny problem, a co ważniejsze, czy ktoś wie, jak rozwiązać ten problem?

[UPDATE]

udało mi się przetestować the same scenario with ZF2 i to działa. Być może muszę zrezygnować z ZF1!

+0

Natywna implementacja protokołu SOAP w PHP jest potwornie, całkowicie zepsuta. Zgłoszono [niewielki błąd] (https://bugs.php.net/bug.php?id=50675) w 2010 roku w moim starym miejscu pracy i jest on nadal otwarty. Chociaż nie sprawdziłem, ale moje zakłady byłyby oparte na Zend_Soap na natywnej implementacji SOAP, więc najlepiej z tym uważać. – Janoszen

Odpowiedz

4

Typ obiektu XSD \Library\IncrementedIntnie klasa PHP wewnątrz przestrzeni nazw PHP jak ty zarys:

<?php 
namespace Library; 

class IncrementedInt 
{ 
    ... 

wcześniej ustalonej typ właściwie jest:

tns:\Library\IncrementedInt 

i umysłu tns: z przodu, który jest przedrostkiem. Nie można wyrazić to w PHP, który staje się jeszcze bardziej oczywiste po rozwinięciu go To nazw URI:

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

także Zend SOAP pochodzi z czasów przed PHP przestrzeni nazw (PHP 5.2), dlatego potrzebuje wybrać inną strategię alias tego typu na typ PHP (classname).Zajmuje local-name typu:

\Library\IncrementedInt 

i zastępuje każdy znak "nieważny" w tym typu nazwy znakiem podkreślenia:

_Library_IncrementedInt 

można zatem trzeba wymienić klasa w ten sposób:

<?php 

class _Library_IncrementedInt 
{ 
    ... 

Jeśli chcesz mieć to działa po wyjęciu z pudełka.


Następnie poprosił o wyjaśnienie poprzez komentarze:

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

Cóż, o ile dla domyślnego zachowania najprawdopodobniej jednak nie jako strategia termin jest zaangażowany, powiedziałbym, że nie jest pewne mechanizm rozszerzania Zend Soap dla tej operacji i wstrzykiwania innego, który na przykład pozwala na klasy z przypisanymi imionami (klasy według ich FQCN), patrz Strategy Pattern.

A jeśli jest to tylko jedna klasa, w międzyczasie można zrobić tanią sztuczkę i rozszerzyć swoją klasę o nazwach z nazwami jako krótką lub aliasową z class_alias.

+0

Więc to, co mówisz, to to, że nic nie mogę zrobić, żeby mieć nazwę z wpisaną nazwą jako nazwę, prawda? – Mehran

+0

Podoba mi się sposób class_alais. Jest to praktyczne w moim przypadku. – Mehran

+0

Przedstawiam ci nagrodę. Czy mógłbyś rozważyć dodanie dwóch komentarzy do głównej odpowiedzi? Osobiście używam hack class_alias jako odpowiedzi, której szukałem. Dzięki za pomoc. – Mehran

1

Zend_Soap_AutoDiscover bierze nazwę typu z bloku PHPDoc, czyli od tej linii komentarza:

* @return \Library\IncrementedInt 

Można tylko zmienić tego typu, na przykład, IncrementedInt bez nazw i ukośników.

+0

Najpierw pozwól mi podziękować za twój post. Obawiam się jednak, że twoje rozwiązanie nie zadziała (nawet jeśli brzmi to całkiem rozsądnie). Kiedy go wypróbowałem, oto co otrzymałem: 'Błąd krytyczny: Niezamknięty wyjątek 'Zend_Soap_Wsdl_Exception' z komunikatem" Nie można dodać typu złożonego _Biblioteka_InstrementedInt, który nie jest obiektem lub gdzie nie można znaleźć klasy w strategii "DefaultComplexType". w Zend/Soap/Wsdl/Strategy/DefaultComplexType.php w linii 49'. AYCS, zmieniłem ścieżkę klasy na '_Library_IncrementedInt', ale wygląda na to, że ZF musi być poprawny, aby działał. Dzięki i tak. – Mehran