$client = new SoapClient('http://acme.com/product.wsdl', array(
'exceptions' => true,
'trace' => true,
));
try {
var_dump($client‐>listProducts());
} catch(SoapFault $e) {
// here be dragons
}
array
0 =>
object(stdClass)[3]
public 'id' => int 8172401
public 'name' => string 'TPS Report Cover Sheet' (length=22)
public 'price' => float 0.89
1 =>
object(stdClass)[4]
public 'id' => int 917246
public 'name' => string 'Weighted Companion Cube' (length=23)
public 'price' => float 129.99
by the way
I will not talk about non-WSDL modes
because using SOAP without a WSDL is stupid
SOAP CLIENTS
If You Want To Consume Services
OMNOMNOM SERVICE
BASICS
$client = new SoapClient(
'http://acme.com/product.wsdl', // URL to WSDL describing the service
array( // array of additional options for the client
'exceptions' => true, // throw SoapFault exceptions on errors
'trace' => true, // allow use of SoapClient::__getLast…()
)
);
$allProducts = $client‐>listProducts(); // $allProducts contains return value
FAULT HANDLING
$client = new SoapClient('http://acme.com/product.wsdl', array(
'exceptions' => true,
'trace' => true,
));
try {
$newThing = $client‐>createProduct(new stdClass());
} catch(SoapFault $e) {
// could be a client‐side fault e.g. if fields are missing
// or a server‐side fault if the server had any objections :)
}
SOAP HEADERS
$client = new SoapClient('http://acme.com/product.wsdl', array(
'exceptions' => true,
'trace' => true,
));
$client‐>setSoapHeader(
new SoapHeader('http://acme.com/soap/products', 'username', 'Chuck Norris')
);
$client‐>setSoapHeader(
new SoapHeader('http://acme.com/soap/products', 'password', 'r0undh0usek!ck')
);
// headers will be sent along with the request
$allProducts = $client‐>listProducts();
CLASSMAPS
class Product {
protected $id, $name, $price;
// imagine getters and setters here
}
$client = new SoapClient('http://acme.com/product.wsdl', array(
'exceptions' => true,
'trace' => true,
'classmap' => array(
'Product' => 'Product', // no namespace here, which can be problematic…
),
));
var_dump($client‐>getProduct(123456));
object(Product)[2]
protected 'id' => int 123456
protected 'name' => string 'Red Stapler' (length=11)
protected 'price' => float 3.14
TYPEMAPS
• Used for custom serialization and deserialization
• Needs two callbacks:
• one for XML->PHP conversion
• one for PHP->XML conversion
• Only necessary in very, very rare cases
SOAP SERVERS
Slightly More Complicated
A BASIC SERVER
class ProductService {
public function getProduct($id) {
// witchcraft here
return $product;
}
public function listProducts() {
// more witchcraft here
return $products;
}
}
$server = new SoapServer('/path/to/local/products.wsdl', array(/* options… */));
// register a class to instantiate that has all the methods
$server‐>setClass('ProductService');
// alternative: use an existing instance
// $server‐>setObject(new ProductService());
// rock and roll
$server‐>handle();
you can also register functions instead of class methods
wanna know how?
RTFM :X
DEALING WITH HEADERS
class ProductService {
public function getProduct($id) {
// witchcraft here
return $product;
}
public function listProducts() {
// more witchcraft here
return $products;
}
public function username($value) {
// check if it's really chuck norris
}
public function password($value) {
// check if he did a roundhouse kick
}
}
$server = new SoapServer('/path/to/local/products.wsdl', array(/* options… */));
// register a class to instantiate that has all the methods
$server‐>setClass('ProductService');
// rock and roll
$server‐>handle();
PRODUCING FAULTS
class ProductService {
public function getProduct($id) {
if($product = ProductFinder::retrieveById($id)) {
return $product;
} else {
return new SoapFault('Server', 'No such product');
}
}
public function listProducts() {
// more witchcraft here
return $products;
}
}
MULTI-PART RETURN VALUES
class ProductService {
public function getTwoThings() {
// rocket science here
return array($foo, $bar);
}
}
LITTLE SECRETS
Did You Know That ext/soap Supports...
LITTLE DISAPPOINTMENTS
Things That ext/soap Does Not Support...
DateTime objects
document/literal wrapped
DOS AND DON’TS
Keep This in Mind
enable the SOAP_SINGLE_ELEMENT_ARRAYS feature
don’t use SoapServer::fault()
use the exceptions option
double-check soap_use_error_handler()
don’t use cookies or other forms of state, ever
FRAMEWORK HIGHLIGHTS
Zend Framework & Agavi
ZEND FRAMEWORK
• Zend_Soap_Client as a wrapper for SOAPClient
• Zend_Soap_Server as a wrapper for SOAPServer
• Zend_Soap_Wsdl for constructing WSDL documents
• Zend_Soap_Autodiscover for automatic WSDL generation
Zend_Soap_Autodiscover generates WSDLs for you!
using PHPDoc comments
class AcmeProductService {
/**
* @param int The ID of the product.
*
* @return Product The product object.
*
* @deprecated Call Joe from sales if you want to know details about a product…
*/
public function getProduct($id) {
// witchcraft goes here
return $product;
}
}
$autodiscover = new Zend_Soap_AutoDiscover();
$autodiscover‐>setClass('AcmeProductService');
$autodiscover‐>handle(); // dumps a WSDL
also very nice for prototyping
but might get difficult with complex stuff
AGAVI
• Re-use existing Actions for SOAP Services
• Needs some information about the service in WSDL format
• WSDL auto-generated by the Routing
• Requires basic knowledge of XML Schema and WSDL
• Supports Document/Literal Wrapped for Servers
Demo
SOAP VERSUS REST
Your Thoughts Please
!e End
Questions?
THANK YOU!
• Shoot me an E-Mail: david.zuelke@bitextender.com
• Follow @dzuelke on Twitter
• Slides will be online at http://talks.wombert.de/
0 comments
Post a comment