0 follower

Webservice

Webservices bilden ein Softwaresystem, das entwickelt wurde, um kompatible Interaktion zwischen Maschinen über ein Netzwerk zu unterstützen. Im Zusammenhang mit Webanwendungen beziehen sie sich in der Regel auf eine Reihe von APIs, die über das Internet zugänglich sind und auf einem entfernten Rechner ausgeführt werden können, der den angeforderten Dienst beherbergt. Ein flex-basierter Client könnte zum Beispiel serverseitig Funktionen einer PHP-basierten Webanwendung aufrufen. Webservices bauen auf SOAP als grundlegendem Kommunikations-Protokollstapel auf.

Um die Verwirklichung von Webservices in einer Webanwendung zu vereinfachen, beinhaltet Yii CWebService und CWebServiceAction. Die APIs werden zu Klassen gruppiert, den sogenannten Dienstanbietern (engl.: service provider). Für jede Klasse erzeugt Yii eine WSDL-Spezifikation, die die verfügbaren APIs und deren Aufruf von Clientseite beschreibt. Wenn eine API von einem Client aufgerufen wird, instanziiert Yii den enstprechenden Dienstanbieter und ruft die angeforderte API auf, um die Anfrage zu verarbeiten.

Hinweis: CWebService basiert auf der SOAP-Erweiterung von PHP. Stellen Sie sicher, dass diese Erweiterung aktiviert wurde, bevor Sie die Beispiele in diesem Abschnitt ausprobieren.

1. Definieren eines Dienstanbieters

Wie erwähnt, ist ein Dienstanbieter eine Klasse mit entfernt aufrufbaren Methoden. Yii verwendet Doc Comments und Reflection von Klassen, um herauszufinden, welche Methoden entfernt aufrufbar sind und wie deren Parameter und Rückgabewerte aussehen.

Beginnen wir mit einem einfachen Dienst zur Abfrage von Börsenkursen. Mit diesem Dienst kann ein Client den Kurs einer bestimmten Aktie abfragen. Wir definieren den Dienstanbieter wie folgt. Beachten Sie, dass wir die Anbieterklasse von CController ableiten. Das ist nicht unbedingt nötigt. Wir erklären in Kürze, warum wir das machen.

class StockController extends CController
{
    /**
     * @param string das symbol der Aktie
     * @return float der Preis der Aktie
     * @soap
     */
    public function getPrice($symbol)
    {
        $prices=array('IBM'=>100, 'GOOGLE'=>350);
        return isset($prices[$symbol])?$prices[$symbol]:0;
        //...Aktienpreis für $symbol zurückliefern
    }
}

In diesem Beispiel deklarieren wir die Methode getPrice als API eines Webservices, indem wir sie in ihrem Doc Comment mit dem Tag @soap markieren. Wir stützen uns auf die Angaben im Doc Comment, um die Datentypen der Eingangsparameter und des Rückgabewerts zu bestimmen. Weitere APIs können auf ähnliche weise deklariert werden.

2. Deklarieren einer Webservice-Action

Nachdem wir den Dienstanbieter definiert haben, müssen wir ihn für Clients verfügbar machen. Im einzelnen heißt das, wir müssen eine Controller-Action erstellen, die diesen Dienst öffentlich bereitstellt. Dies kann einfach dadurch erreicht werden, indem wir eine CWebServiceAction-Action in einer Controllerklasse deklarieren. Für unser Beispiel bringen wir diese einfach in StockController unter:

class StockController extends CController
{
    public function actions()
    {
        return array(
            'quote'=>array(
                'class'=>'CWebServiceAction',
            ),
        );
    }
 
    /**
     * @param string das symbol der Aktie
     * @return float der Preis der Aktie
     * @soap
     */
    public function getPrice($symbol)
    {
        //...Aktienpreis für $symbol zurückliefern
    }
}

Das ist alles, was wir tun müssen, um einen Webservice zu erstellen! Wenn wir die Action über die URL http://hostname/pfad/zu/index.php?r=stock/quote aufrufen, sehen wir eine Menge XML-Inhalte, die die WSDL für den von uns definierten Webservice darstellen.

Tipp: Standardmäßig geht CWebServiceAction davon aus, dass der aktuelle Controller auch der Dienstanbieter ist. Deshalb haben wir die Methode getPrice in der StockController-Klasse definiert.

3. Einsatz des Webservice

Um das Beispiel abzuschließen, erstellen wir noch einen Client, der den eben erstellten Webservice verwendet. Der Beispielclient wurde in PHP geschrieben, könnte aber auch in anderen Sprachen wie Java, C# oder Flex vorliegen.

$client=new SoapClient('http://hostname/pfad/zu/index.php?r=stock/quote');
echo $client->getPrice('GOOGLE');

Wenn Sie dieses Script im Web- oder Konsolenmodus aufurfen, sollten wir 350 als Preis für GOOGLE erhalten.

4. Datentypen

Beim deklarieren der Klassenmethoden und -eigenschaften, die von Ferne verfügbar gemacht werden sollen, müssen wir die Datentypen der Ein- und Ausgangsparameter angeben. Die folgenden Grundtypen können verwendet werden:

  • str/string: wird abgebildet auf xsd:string;
  • int/integer: wird abgebildet auf xsd:int;
  • float/double: wird abgebildet auf xsd:float;
  • bool/boolean: wird abgebildet auf xsd:boolean;
  • date: wird abgebildet auf xsd:date;
  • time: wird abgebildet auf xsd:time;
  • datetime: wird abgebildet auf xsd:dateTime;
  • array: wird abgebildet auf xsd:string;
  • object: wird abgebildet auf xsd:struct;
  • mixed: wird abgebildet auf xsd:anyType.

Falls ein Typ nicht in der Liste dieser Grundtypen vorkommt, wird von einem aus Eigenschaften zusammengesetzten Typ (engl.: composite type) ausgegangen. Ein zusammengesetzter Typ wird als Klasse dargestellt, seine Eigenschaften als öffentliche und in den Doc Comments mit @soap markierte Eigenschaften dieser Klasse.

Wir können auch den Typ Array verwenden, indem wir [] hinter einem Grundtyp oder einem zusammengesetzten Typ anhängen. Damit würde ein Array des angegebenen Typs angegeben.

Untenstehend finden Sie ein Beispiel für die Web-API von getPosts, welches ein Array von Post-Objekten zurückliefert.

class PostController extends CController
{
    /**
     * @return Post[] eine Liste von Posts (Beiträgen)
     * @soap
     */
    public function getPosts()
    {
        return Post::model()->findAll();
    }
}
 
class Post extends CActiveRecord
{
    /**
     * @var integer post ID
     * @soap
     */
    public $id;
    /**
     * @var string post title (Beitragstitel)
     * @soap
     */
    public $title;
 
    public static function model($className=__CLASS__)
    {
        return parent::model($className);
    }
}

5. Abbildung von Klassen

Um die Parameter für einen zusammengesetzten Typ vom Client beziehen zu können, muss eine Anwendung eine Abbildung von WSDL-Typen auf die entsprechenden PHP-Klassen deklarieren. Dies geschieht, indem die Eigenschaft classMap von CWebServiceAction konfiguriert wird.

class PostController extends CController
{
    public function actions()
    {
        return array(
            'service'=>array(
                'class'=>'CWebServiceAction',
                'classMap'=>array(
                    'Post'=>'Post',  // oder einfach nur 'Post'
                ),
            ),
        );
    }
    ......
}

6. Abfangen entfernter Methodenaufrufe

Ein Dienstanbieter kann die entfernten Methodenaufrufe abfangen, wenn er das Interface IWebServiceProvider implementiert. In IWebServiceProvider::beforeWebMethod kann der Anbieter die aktuelle Instanz von CWebService beziehen und den Namen der angeforderten Methode über CWebService::methodName ermitteln. Sie kann false zurückgeben, falls die entfernte Methode aus irgendeinem Grund nicht ausgeführt werden soll (z.B. bei unberechtigtem Zugriff).