How to Create a SOAP Web Service in a Symfony Controller
Warning: You are browsing the documentation for Symfony 2.x, which is no longer maintained.
Consider upgrading your projects to Symfony 7.1.
Setting up a controller to act as a SOAP server is simple with a couple tools. You must, of course, have the PHP SOAP extension installed. As the PHP SOAP extension cannot currently generate a WSDL, you must either create one from scratch or use a 3rd party generator.
Note
There are several SOAP server implementations available for use with PHP. Zend SOAP and NuSOAP are two examples. Although the PHP SOAP extension is used in these examples, the general idea should still be applicable to other implementations.
SOAP works by exposing the methods of a PHP object to an external entity
(i.e. the person using the SOAP service). To start, create a class - HelloService
-
which represents the functionality that you'll expose in your SOAP service.
In this case, the SOAP service will allow the client to call a method called
hello
, which happens to send an email:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
// src/Acme/SoapBundle/Services/HelloService.php
namespace Acme\SoapBundle\Services;
class HelloService
{
private $mailer;
public function __construct(\Swift_Mailer $mailer)
{
$this->mailer = $mailer;
}
public function hello($name)
{
$message = new \Swift_Message('Hello Service')
->setTo('me@example.com')
->setBody($name.' says hi!');
$this->mailer->send($message);
return 'Hello, '.$name;
}
}
Next, you can train Symfony to be able to create an instance of this class.
Since the class sends an email, it's been designed to accept a Swift_Mailer
instance. Using the Service Container, you can configure Symfony to construct
a HelloService
object properly:
1 2 3 4 5
# app/config/services.yml
services:
hello_service:
class: Acme\SoapBundle\Services\HelloService
arguments: ['@mailer']
1 2 3 4 5 6 7 8 9 10 11 12 13 14
<!-- app/config/services.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services
http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="hello_service" class="Acme\SoapBundle\Services\HelloService">
<argument type="service" id="mailer"/>
</service>
</services>
</container>
1 2 3 4 5 6
// app/config/services.php
use Acme\SoapBundle\Services\HelloService;
$container
->register('hello_service', HelloService::class)
->addArgument(new Reference('mailer'));
Below is an example of a controller that is capable of handling a SOAP
request. If indexAction()
is accessible via the route /soap
, then the
WSDL document can be retrieved via /soap?wsdl
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
namespace Acme\SoapBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
class HelloServiceController extends Controller
{
public function indexAction()
{
$soapServer = new \SoapServer('/path/to/hello.wsdl');
$soapServer->setObject($this->get('hello_service'));
$response = new Response();
$response->headers->set('Content-Type', 'text/xml; charset=ISO-8859-1');
ob_start();
$soapServer->handle();
$response->setContent(ob_get_clean());
return $response;
}
}
Take note of the calls to ob_start()
and ob_get_clean()
. These
methods control output buffering which allows you to "trap" the echoed
output of $server->handle()
. This is necessary because Symfony expects
your controller to return a Response
object with the output as its "content".
You must also remember to set the "Content-Type" header to "text/xml", as
this is what the client will expect. So, you use ob_start()
to start
buffering the STDOUT and use ob_get_clean()
to dump the echoed output
into the content of the Response and clear the output buffer. Finally, you're
ready to return the Response
.
Below is an example calling the service using a NuSOAP client. This example
assumes that the indexAction()
in the controller above is accessible via the
route /soap
:
1 2 3
$soapClient = new \SoapClient('http://example.com/app.php/soap?wsdl');
$result = $soapClient->call('hello', array('name' => 'Scott'));
An example WSDL is below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
<?xml version="1.0" encoding="ISO-8859-1"?>
<definitions xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tns="urn:arnleadservicewsdl"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns="http://schemas.xmlsoap.org/wsdl/"
targetNamespace="urn:helloservicewsdl">
<types>
<xsd:schema targetNamespace="urn:hellowsdl">
<xsd:import namespace="http://schemas.xmlsoap.org/soap/encoding/" />
<xsd:import namespace="http://schemas.xmlsoap.org/wsdl/" />
</xsd:schema>
</types>
<message name="helloRequest">
<part name="name" type="xsd:string" />
</message>
<message name="helloResponse">
<part name="return" type="xsd:string" />
</message>
<portType name="hellowsdlPortType">
<operation name="hello">
<documentation>Hello World</documentation>
<input message="tns:helloRequest"/>
<output message="tns:helloResponse"/>
</operation>
</portType>
<binding name="hellowsdlBinding" type="tns:hellowsdlPortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="hello">
<soap:operation soapAction="urn:arnleadservicewsdl#hello" style="rpc"/>
<input>
<soap:body use="encoded" namespace="urn:hellowsdl"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</input>
<output>
<soap:body use="encoded" namespace="urn:hellowsdl"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</output>
</operation>
</binding>
<service name="hellowsdl">
<port name="hellowsdlPort" binding="tns:hellowsdlBinding">
<soap:address location="http://example.com/app.php/soap" />
</port>
</service>
</definitions>