/ php

Consume SOAP Services in PHP Using Zend

Level - Intermediate. Read Time ~ <10 minute.

Little to my bemusement I thought consuming SOAP Web Services in PHP was a trivial task. It is, once you know how. I spent several hours of trial and error until I got the solution nailed down. So I thought I'd share my thoughts here.

I'm going to make the following assumptions, that you are using the following: -

  • PHP 5+
  • Composer - like NPM if you are not that familiar with PHP.
Zend Soap Client

To achieve what I achieved when consuming a SOAP Web Service in PHP, you will want to use the Zend SOAP Client. Run this command in your terminal (within your the same directory as your composer.json) composer require zendframework/zend-soap. You will now have the Zend SOAP Client installed.

WSDL2PHP Generator

Next step is to generate PHP Classes which match the schema definitions of the Web Service you want to consume. For this I used WSDL2PHP Generator. There are other options, but this worked for me. Version 3 of the CLI is underway, so you may benefit from that.

Now run the command pointing to your WSDL replacing the necessary parts in the example command after you have cloned the repo php wsdl2phpgenerator-2.5.5.phar -i input.wsdl -o tmp/my/directory/wsdl. After these have been generated, maybe copy them to a 'Model' or 'Entity' folder within your project. Dependant on your project structure and style.

Another point to bear in mind the generated files may need a little work to get them in shape with the rest of your codebase. I refactored them as they didn't match the style I was using.

Example Client.php file

Once you have installed the Zend client and generated the PHP classes which can be used for Requests and Responses, you will want to use them. Below is an example based on how I used the Zend Client. You will want to change the Class Maps and SOAP method to match Web Service you are consuming: -

<?php

namespace MyProject;

use MyProject\Model\GetCustomerRequest;
use MyProject\Model\GetCustomerResponse;
use Zend\Soap\Client;

class SoapClient
{
    /** @var string */
    private $endpointUrl;

    /** @var string */
    private $wsdlPath;

    /** @var string */
    private $username;

    /** @var string */
    private $password;

    /** @var Client */
    private $soapClient;

    /**
     * @param string $endpointUrl
     * @param string $wsdlPath
     * @param string $username
     * @param string $password
     * @throws \Exception
     */
    public function __construct(
        $endpointUrl,
        $wsdlPath,
        $username,
        $password
    ) {
        if (empty($endpointUrl)) {
            throw new \InvalidArgumentException('Endpoint URL cannot be empty');
        }

        if (empty($wsdlPath)) {
            throw new \InvalidArgumentException('WSDL Path cannot be empty');
        }

        if (empty($username)) {
            throw new \InvalidArgumentException('Username cannot be empty');
        }

        if (empty($password)) {
            throw new \InvalidArgumentException('Password cannot be empty');
        }

        $this->setEndpointUrl($endpointUrl);
        $this->setWsdlPath($wsdlPath);
        $this->setUsername($username);
        $this->setPassword($password);
    }

    /**
     * @return string
     */
    public function getUsername()
    {
        return $this->username;
    }

    /**
     * @param string $username
     */
    public function setUsername($username)
    {
        $this->username = $username;
    }

    /**
     * @return string
     */
    public function getPassword()
    {
        return $this->password;
    }

    /**
     * @param string $password
     */
    public function setPassword($password)
    {
        $this->password = $password;
    }

    /**
     * @return string
     */
    public function getEndpointUrl()
    {
        return $this->endpointUrl;
    }

    /**
     * @param string $endpointUrl
     */
    public function setEndpointUrl($endpointUrl)
    {
        $this->endpointUrl = $endpointUrl;
    }

    /**
     * @return string
     */
    public function getWsdlPath()
    {
        return $this->wsdlPath;
    }

    /**
     * @param string $wsdlPath
     */
    public function setWsdlPath($wsdlPath)
    {
        $this->wsdlPath = $wsdlPath;
    }

    /**
     * @return Client
     */
    public function getSoapClient()
    {
        return $this->soapClient;
    }

    /**
     * @param Client $soapClient
     */
    public function setSoapClient(Client $soapClient)
    {
        $this->soapClient = $soapClient;
    }

    /**
     * @param string $customer
     * @return GetCustomerResponse
     */
    public function getCustomer($customer)
    {
        try {
            $getCustomerRequest = new GetCustomerRequest($customer);
            $response = $this->buildSoapClient()->GetCustomer($getCustomerRequest);
        } catch (\SoapFault $soapFault) {
            $this->handleSoapFault($soapFault);
            return $soapFault;
        }

        return $response;
    }

    /**
     * @return Client
     */
    public function buildSoapClient()
    {
        $soapClient = $this->getSoapClient();

        if ($soapClient != null) {
            return $soapClient;
        }

        $options = [
            "login" => $this->getUsername(),// Used for HTTP Basic Auth
            "password" => $this->getPassword(),// Used for HTTP Basic Auth
            "location" => $this->getEndpointUrl(),
            "soap_version" => SOAP_1_1
        ];

        $client = new Client($this->getWsdlPath(), $options);
        $client->setClassmap($this->buildClassMap());
        $client->setWSDLCache(false);// Set to true for Production
        $client->setCompressionOptions(SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP);

        return $client;
    }

    /**
     * @return array Class Map used by the GetCustomer SOAP Call
     */
    private function buildClassMap()
    {
        return [
            'GetCustomerRequest'     => 'MyProject\Model\GetCustomerRequest',
            'GetCustomerResponse'    => 'MyProject\Model\GetCustomerResponse'
        ];
    }

    /**
     * @param \SoapFault
     */
    private function handleSoapFault(\SoapFault $fault)
    {
        $errorMessage = 'ERROR: [' . $fault->getCode() . '] ' . $fault->getFile() . '   '
            . $fault->getLine() . '   '
            . $fault->getMessage() . '   '
            . $fault->getTraceAsString();
        echo $errorMessage;
    }
}