Suchen
Inside Wiki
Nützliche Links
phpforum.de Tipp
 
phpforum.de bei Facebook
 
phpforum.de bei Twitter
 

Zurück   PHP Forum: phpforum.de > phpforum.de Wiki > phpforum.de Wiki

PHP Wiki Dieses Wiki sammelt Lösungen, zu Problemen, welche immer wieder im Forum auftauchen.

 
 
Artikel-Optionen Ansicht
  #1  

Standard Soap Client

 
 

Tutorials - Inhalte

Entwicklung eines SOAP Clients


Dieses Tutorial beschreibt eine naive, aber konsequente, Vorgehensweise um öffentliche Soap Services zu nutzen. Das hier geschilderte Vorgehen ist auf etliche andere Soap Services übertragbar. Wie viele Tutorials braucht auch dieses ein Beispiel, ein Ziel. In diesem konkreten Fall soll die Aufgabe das Beschaffen von Bankdaten anhand einer Bankleitzahl sein.




Der erste konsequent naive Schritt


GOOGLE-ANREGE-SERVICE(TM)

Sofort ein Volltreffer: http://www.predic8.de/soap/blz-webservice.htm


Dann wollen wir diesen Service mal untersuchen...


Zitat:
Nutzung: Die Nutzung ist kostenlos und auf eigenes Risiko. Für die Verfügbarkeit des Services sowie die Richtigkeit der Daten wird keine Haftung übernommen.
Evtl. nicht 100% zuverlässig, aber für dieses Tutorial längst gut genug.

Interssant ist auch die etwas laxe Beschreibung:
Zitat:
Dieser Web Service ermittelt zu einer Bankleitzahl den Namen des Kreditinstitutes, die Postleitzahl und den Ort. Falls eine Bankleitzahl nicht gefunden werden kann, wird eine Fehlermeldung zurückgegeben.
Eine API Dokumentation ist was anderes

Aber es ist eine Url angegeben, welche auf eine wsdl zeigt:
http://www.thomas-bayer.com/axis2/se...LZService?wsdl
Oje, was wir sehen, ist ein xml Gewussel.
Macht nichts!
Naiv wie wir sind, wollen wir nix damit zu tun haben.


Der erste Versuch


Beim Überfliegen der Website und der wsdl haben wir entdeckt, dass es wohl eine Funktion "getBank" geben soll.

Also ran, Versuch macht kluch..
PHP Quellcode:
<?php
error_reporting(-1);
ini_set('display_errors', TRUE);


// testdaten
$wsdl         = 'http://www.thomas-bayer.com/axis2/services/BLZService?wsdl';
$bankleitzahl = '12070000';

// der Versuch
$soapclient = new SoapClient($wsdl);
$result     = $soapclient->getBank($bankleitzahl);


// Ausgabe
?>
<h1>Erster naiver Versuch</h1>
<pre> <?php var_dump($result)?> </pre>

An dieser Stelle erstmal der Hinweis: Doku zum PHP Soap Client


Aber schade... klappt nicht so recht... bei einem anderen Service könnte es einfach so funktionieren, hier leider nicht... mal schauen...

Es wird eine Exception geworfen:
Code:
Fatal error: Uncaught SoapFault exception: [soapenv:Server] org.apache.axis2.databinding.ADBException: Unexpected subelement getBank in blz.php:12
Stack trace:
#0 [internal function]: SoapClient->__call('getBank', Array)
#1 blz.php(12): SoapClient->getBank('12070000')
#2 {main}
  thrown in blz.php on line 12

Was können wir der Meldung entnehmen?
1. Ganz wichtig: Wir erreichen den "gegnerischen" Server.
2. Er wirft eine Exception! (mag unsere Anfrage nicht)
3. org.apache.axis2.databinding.ADBException <<-- vermutlich ist der Server in Java geschrieben (soll uns egal sein)
4. Eine databinding Exception....irgendwas stimmt mit unserer Daten Bindung nicht.


Dann fragen wir ihn mal


Mittlerweile haben wir ja die Soap Doku gelesen.
haben wir?

Also fragen wir jetzt den Service, wie er es denn gerne hätte:
PHP Quellcode:
<?php
error_reporting(-1);
ini_set('display_errors', TRUE);

$wsdl       = 'http://www.thomas-bayer.com/axis2/services/BLZService?wsdl';
$soapclient = new SoapClient($wsdl);

?>
<h1>Funktionen</h1>
<pre> <?php var_dump($soapclient->__getFunctions())?> </pre>
<h1>Typen</h1>
<pre> <?php var_dump($soapclient->__getTypes())?> </pre>


Aha, ja!
Er sagt:
Code:
Funktionen
 array(2) {
  [0]=>
  string(52) "getBankResponseType getBank(getBankType $parameters)"
  [1]=>
  string(52) "getBankResponseType getBank(getBankType $parameters)"
}
 
Typen
 array(3) {
  [0]=>
  string(35) "struct getBankType {
 string blz;
}"
  [1]=>
  string(52) "struct getBankResponseType {
 detailsType details;
}"
  [2]=>
  string(82) "struct detailsType {
 string bezeichnung;
 string bic;
 string ort;
 string plz;
}"
}


Was sagt uns das?
Es gibt 2 Funktionen mit dem Bezeichner "getBank"!
Warum zwei? Die Analyse der wsdl würde uns zeigen, dass eine Funktion an SOAP_1_1 gebunden ist, und die andere an SOAP_1_2.
Soll uns aber hier nicht belasten.
Und es gibt 3 Datentypen, bzw. Strukturen.
Wir sehen, dass "getBank" seine Daten in der "getBankType" Struktur erwartet und uns das Ergebnis in einer verschachtelten Struktur "getBankResponseType" zurück liefert.



Jetzt mit Struktur


Aus den vorherigen Versuchen wissen wir jetzt, dass der Service seine Anfrage gerne in einer Struktur verpackt haben möchte. PHP bietet nur 2 Struktur Typen, Arrays und Klassen.

Da wir ja die Soap Doku gelesen haben, wissen wir auch wie wir dem SoapClient eine solche Struktur unterschieben können. Wir schreiben eine "RequestType" Klasse und teilen dem Client das in einem $options Array mit.

PHP Quellcode:
<?php
error_reporting(-1);
ini_set('display_errors', TRUE);

$wsdl         = 'http://www.thomas-bayer.com/axis2/services/BLZService?wsdl';
$bankleitzahl = '12070000'; // testdaten


 
class RequestType
{
    public $blz;
}
 
$options = array();
$options['classmap']['getBankType']  = 'RequestType';

$bank         = new RequestType;
$bank->blz    = $bankleitzahl;

$soapclient = new SoapClient($wsdl,$options);
$result     = $soapclient->getBank($bank);

?>
<h1>Result</h1>
<pre> <?php var_dump($result)?> </pre>


Jawoll!
Code:
Result
 object(stdClass)#3 (1) {
  ["details"]=>
  object(stdClass)#4 (4) {
    ["bezeichnung"]=>
    string(28) "Deutsche Bank Ld Brandenburg"
    ["bic"]=>
    string(11) "DEUTDEBB160"
    ["ort"]=>
    string(7) "Potsdam"
    ["plz"]=>
    string(5) "14405"
  }
}

Kernaufgabe erfüllt!




Verschönerung


Nach dem wir in den vorherigen Kapiteln die Grundfunktion herstellen konnten, dreht es sich im folgenden um mögliche Verbesserungen. Es soll "eleganter" werden.


Konsequenter Einsatz der Type Klassen


Die vorherige 'Version liefert uns alles in "stdClass", das geht auch schöner.
Man beachte auch die phpdoc Kommentare. Hier dienen sie nur der reinen Dokumentation. Diese bekommen zusätzlichen Sinn, wenn wir die Datentypen in Verbindung mit dem Zend_Soap_Server einsetzen.
PHP Quellcode:
<?php
error_reporting(-1);
ini_set('display_errors', TRUE);

$wsdl         = 'http://www.thomas-bayer.com/axis2/services/BLZService?wsdl';
$bankleitzahl = '12070001'; // testdaten


 
class RequestType
{
   /**
    * Bankleitzahl
    * @var string
    */

    public $blz;
}

class ResponseType
{
   /**
    * Details Struktur
    * @var DetailsType
    */

    public $details;
}

class DetailsType
{
   /**
    * Bank
    * @var string
    */

    public $bezeichnung;  
   
   /**
    * BIC
    * @var string
    */

    public $bic;  
           
   /**
    * Ort
    * @var string
    */

    public $ort;      
       
   /**
    * Postleitzahl
    * @var string
    */

    public $plz;          
}
 
$options = array();
$options['encoding']                        = 'ISO-8859-15';
$options['soap_version']                    = SOAP_1_2;
$options['classmap']                        = array();
$options['classmap']['getBankType']         = 'RequestType';
$options['classmap']['detailsType']         = 'DetailsType';
$options['classmap']['getBankResponseType'] = 'ResponseType';

$bank         = new RequestType;
$bank->blz    = $bankleitzahl;

$soapclient = new SoapClient($wsdl,$options);
$result     = $soapclient->getBank($bank);

// Ausgabe
echo "BLZ: ". $bank->blz ." Bank: ". $result->details->bezeichnung;


Es liefert:
Code:
BLZ: 12070000 Bank: Deutsche Bank Ld Brandenburg

Perfekt!






Im OOP Mäntelchen


Jetzt wirds mal Zeit die Sache "gesund zu schrumpfen" und in eine Form zu bringen, die man leichter in eigene Projekte oder Frameworks integrieren kann.

Quellcode des BLZAdapterInterface:
PHP Quellcode:
interface BLZAdapterInterface
{
  /**
   * Funktion getBank.
   *
   * @param string $bankleitzahl
   * @return stdClass
   **/

  public function getBank($bankleitzahl);
}

Zweck des Interfaces:
1. Falls wir den Service mal austauschen wollen, brauchen wir nur einen neuen Adapter mit der selben Schnittstelle zu schreiben und können den Rest unverändert weiter verwenden.
2. So können wir den Service dekorieren.

Quellcode des BLZAdapter:
PHP Quellcode:
class BLZAdapter implements BLZAdapterInterface
{
  protected $soapclient = null;
 
  public function __construct()
  {
    $wsdl = 'http://www.thomas-bayer.com/axis2/services/BLZService?wsdl';
    $this->soapclient = new SoapClient($wsdl);
  }
 
  public function getBank($bankleitzahl)
  {
     return $this->soapclient->getBank(array('blz'=>$bankleitzahl))->details;
  }
}

Zweck:
Den Service in einer Klasse zu kapsen und durch Implementierung des BLZAdapterInterface austauschbar zu machen.


Wie oben schon angedeutet bietet uns das Interface die Möglichkeit den Service zu dekorieren.
Quellcode des BLZAdapterCacheDecorator:
PHP Quellcode:
class BLZAdapterCacheDecorator implements BLZAdapterInterface
{
    protected $service = null;
    protected $cache   = array();

    public function __construct(BLZAdapterInterface $service)
    {
      $this->service = $service;
    }
     
    public function getBank($bankleitzahl)
    {
       if(empty($this->cache[$bankleitzahl]))
          $this->cache[$bankleitzahl] = $this->service->getBank($bankleitzahl);
       return  $this->cache[$bankleitzahl];
    }
}

Der Zweck dieses konkreten Dekorierers ist es, die Anzahl Soap Requests zu minimieren.

Damit können wir uns auch solche Verfahren erlauben:
PHP Quellcode:
<?php
$bankleitzahl = '12070000'; // testdaten
$service      = new BLZAdapterCacheDecorator(new BLZAdapter);

?>
<h1>Resultat</h1>
Bankleitzahl: <?php echo $bankleitzahl ?> <br>
Name der Bank: <?php echo $service->getBank($bankleitzahl)->bezeichnung ?> <br>
BIC: <?php echo $service->getBank($bankleitzahl)->bic ?> <br>
Postleitzahl: <?php echo $service->getBank($bankleitzahl)->plz ?> <br>
Ort: <?php echo $service->getBank($bankleitzahl)->ort ?> <br>

Ohne den CacheDecorator würde dieses Script 5 Requests absetzen. Mit Cache nur zwei. Einen für die wsdl und einen um die Daten zu holen.



Nachwort


Das fangen von Exceptions ist nicht Teil dieses Tutorials, da ist noch etwas Nacharbeit nötig. Im Gegensatz zu den, in diesem Tutorial, verwendeten Bezeichnen, sollte man in der Praxis konsequent auf das Zend/PEAR Benennungsschema setzen. Siehe dazu Stichwort: Autoload Auch muss die Frage erlaubt sein, ob man sich wirklich so auf automatische Typekonvertierung von PHP verlassen sollte, wie es in der Klasse BLZAdapter gemacht wird. Oder ob es besser ist die weiter oben eingeführten Type Klassen zu verwenden.

Links


PHP Soap Dokumentation
Adapter Design Pattern
Decorator Design Pattern
Implement SOAP services with the Zend Framework
Stichwort: Autoload

« Vorheriges Kapitel   Tutorials
  Nächstes Kapitel »

Mitwirkende: combie, dacat
Erstellt von combie, 14.11.2010 am 14:18
Zuletzt bearbeitet von combie, 21.12.2012 am 10:43
0 Kommentare , 28617 Betrachtungen

Dieser Text steht unter der GNU-Lizenz für freie Dokumentation


 

Lesezeichen

Stichworte
soap, soap client

Artikel-Optionen
Ansicht

Forumregeln
Es ist Ihnen nicht erlaubt, neue Themen zu verfassen.
Es ist Ihnen nicht erlaubt, auf Beiträge zu antworten.
Es ist Ihnen nicht erlaubt, Anhänge hochzuladen.
Es ist Ihnen nicht erlaubt, Ihre Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.

Gehe zu
Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
PHP - SOAP (Webdienst u. Client) chetti PHP 1 16.06.2010 09:02
PHP Soap Client jessica79 PHP 2 12.02.2010 18:45
soap php client to .net webservice tob1as12 PHP 0 06.02.2009 09:54
Soap Client mit Php rcode PHP 5 04.03.2007 19:34


Alle Zeitangaben in WEZ +2. Es ist jetzt 16:02 Uhr.


Powered by vBulletin® Version 3.8.8 (Deutsch)
Copyright ©2000 - 2016, Jelsoft Enterprises Ltd.
Powered by NuWiki v1.3 RC1 Copyright ©2006-2007, NuHit, LLC