2008年9月27日星期六

使用 NuSOAP 结合 WSDL 来编程

Defining New Data Structures

WSDL 一个重要的方面是它封装了一个或多个 XML 结构,允许程序员通过 service 来描述数据结构,为了说明 NuSOAP 如何支持这个,我会在 Programming with NuSOAP Part 2 文章中的 SOAP struct 实例中加入 WSDL 代码。

service 代码的改变已经显示在 Hello, World 实例中,但是它也包含了定义 Person 数据结构的代码:

// Pull in the NuSOAP code
require_once(\'nusoap.php\');
// Create the server instance
$server = new soap_server();
// Initialize WSDL support
$server->configureWSDL(\'hellowsdl2\', \'urn:hellowsdl2\');
// Register the data structures used by the service
$server->wsdl->addComplexType(
\'Person\',
\'complexType\',
\'struct\',
\'all\',
\'\',
array(
\'firstname\' => array(\'name\' => \'firstname\', \'type\' => \'xsd:string\'),
\'age\' => array(\'name\' => \'age\', \'type\' => \'xsd:int\'),
\'gender\' => array(\'name\' => \'gender\', \'type\' => \'xsd:string\')
)
);
$server->wsdl->addComplexType(
\'SweepstakesGreeting\',
\'complexType\',
\'struct\',
\'all\',
\'\',
array(
\'greeting\' => array(\'name\' => \'greeting\', \'type\' => \'xsd:string\'),
\'winner\' => array(\'name\' => \'winner\', \'type\' => \'xsd:boolean\')
)
);
// Register the method to expose
$server->register(\'hello\', // method name
array(\'person\' => \'tns:Person\'), // input parameters
array(\'return\' => \'tns:SweepstakesGreeting\'), // output parameters
\'urn:hellowsdl2\', // namespace
\'urn:hellowsdl2#hello\', // soapaction
\'rpc\', // style
\'encoded\', // use
\'Greet a person entering the sweepstakes\' // documentation
);
// Define the method as a PHP function
function hello($person) {
$greeting = \'Hello, \' . $person[\'firstname\'] .
\'. It is nice to meet a \' . $person[\'age\'] .
\' year old \' . $person[\'gender\'] . \'.\';

$winner = $person[\'firstname\'] == \'Scott\';

return array(
\'greeting\' => $greeting,
\'winner\' => $winner
);
}
// Use the request to (try to) invoke the service
$HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : \'\';
$server->service($HTTP_RAW_POST_DATA);
?>

除了支持 WSDL 的附加代码之外,service 方法的代码本身也有一点改变,使用 WSDL ,不再需要使用 soapval 对象来为返回值指定名称和数据类型。

相似的, WSDL 客户端不需要使用 soapval 指定参数的名称和数据类型,演示代码如下:

// Pull in the NuSOAP code
require_once(\'nusoap.php\');
// Create the client instance
$client = new soapclient(\'http://localhost/phphack/hellowsdl2.php?wsdl\', true);
// Check for an error
$err = $client->getError();
if ($err) {
// Display the error
echo \'

Constructor error

\' . $err . \'
\';
// At this point, you know the call that follows will fail
}
// Call the SOAP method
$person = array(\'firstname\' => \'Willi\', \'age\' => 22, \'gender\' => \'male\');
$result = $client->call(\'hello\', array(\'person\' => $person));
// Check for a fault
if ($client->fault) {
echo \'

Fault

\';
print_r($result);
echo \'
\';
} else {
// Check for errors
$err = $client->getError();
if ($err) {
// Display the error
echo \'

Error

\' . $err . \'
\';
} else {
// Display the result
echo \'

Result

\';
print_r($result);
echo \'
\';
}
}
// Display the request and response
echo \'

Request

\';
echo \'
\' . htmlspecialchars($client->request, ENT_QUOTES) . \'
\';
echo \'

Response

\';
echo \'
\' . htmlspecialchars($client->response, ENT_QUOTES) . \'
\';
// Display the debug messages
echo \'

Debug

\';
echo \'
\' . htmlspecialchars($client->debug_str, ENT_QUOTES) . \'
\';
?>

WSDL 是客户端多于一个功能,使用代理而不是用 soapclinet 类的 call 方法。代理(proxy)是一个类,它映射到 service 。因此,它具备了与 service 相同参数的相同方法,一些程序员更喜欢使用代理因为方法是作为用户一个实例的方法来调用的,而不是通过 call 方法,一个使用代理的实例如下:

// Pull in the NuSOAP code
require_once(\'nusoap.php\');
// Create the client instance
$client = new soapclient(\'http://localhost/phphack/hellowsdl2.php?wsdl\', true);
// Check for an error
$err = $client->getError();
if ($err) {
// Display the error
echo \'

Constructor error

\' . $err . \'
\';
// At this point, you know the call that follows will fail
}
// Create the proxy
$proxy = $client->getProxy();
// Call the SOAP method
$person = array(\'firstname\' => \'Willi\', \'age\' => 22, \'gender\' => \'male\');
$result = $proxy->hello($person);
// Check for a fault
if ($proxy->fault) {
echo \'

Fault

\';
print_r($result);
echo \'
\';
} else {
// Check for errors
$err = $proxy->getError();
if ($err) {
// Display the error
echo \'

Error

\' . $err . \'
\';
} else {
// Display the result
echo \'

Result

\';
print_r($result);
echo \'
\';
}
}
// Display the request and response
echo \'

Request

\';
echo \'
\' . htmlspecialchars($proxy->request, ENT_QUOTES) . \'
\';
echo \'

Response

\';
echo \'
\' . htmlspecialchars($proxy->response, ENT_QUOTES) . \'
\';
// Display the debug messages
echo \'

Debug

\';
echo \'
\' . htmlspecialchars($proxy->debug_str, ENT_QUOTES) . \'
\';
?>