We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Decent PHP SOAP client?

Hey guys, has anyone used decent PHP SOAP Client recently and can recommend it?

Thanks!

edited Oct '17

I remember horrors working with damn SOAP services. And it's not about PHP support for SOAP. Thankfully world ran away from that shitware towards REST.

If you really have to do it, I suggest to rely on SoapClient class found in raw PHP. Back in the day, nuSOAP was also good alternative / option. Nowdays it's deprecated, but I see someone ported it to 7.1 even: https://github.com/econea/nusoap

Give it a try and good luck, I mean it! :D

Yeah... had few interactions wiath SOAP in the past years and it was not fun at all.

I'll check it out after I get the WSDL file :) Either will use nusoap or write a wrapper class over PHP's built in client.

Thanks :)

edited Oct '17

XML should've died out years ago, it offers no structure that you cannot replicate in json.... and the latter needs third the bandwidth.

Only services written using microsoft products still use soap, and unfortunately there are quite a few :D

PS: if you want to generate classes of the WSDL schema: https://github.com/wsdl2phpgenerator/wsdl2phpgenerator

Should have, but sadly it did not.. yet.. :)



9.7k
edited Oct '17

SOAP, Simple Object Access Protocol, is not simple, objective, easy to access, and the protocol leaves a lot left undefined. I usually ignore generic SOAP and use the protocol definition provided by the data source. 10 pages instead of 220 pages. Do they have other PHP based users? What does the data source recommend?

I do not find any problems with XML. When the original data is in XML, it is usually safer to leave the data in the same XML instead of converting it to another format.

edited Oct '17

@petermoo I remember when I had a chance to work with OSB (Oracle services bus) with XML-DSIG on top of it... oh boy what a pain that was. Thing is very simple but they made it way too complex. Same as with SOAP. SOAP and XML-DSIG are thankfully history and even eGov services today do not rely on those anymore like they used to.

@stamster speak for yourself, the hungarian tax agency still uses java + xml (+ dsig) xD

edited Apr '18

Hey again :) Just wanted to update this with what I actually did... After browsing for some library and seing that this company Soap service is quite specific, I just gave up searching and made a simple class with the built in PHP client.

class CostaSoapClient
{
    private $_client;
    private $_config = [
        'wsdl' => '...',
        'agencyCode' => '...',
        'culture' => '...',
        'namespace' => '...',
        'auth' => [
            'username' => '...',
            'password' => '...'
        ],
    ];

    // Construct
    public function __construct()
    {
        $headers = [
            new \SoapHeader($this->_config['namespace'], 'Partner', ['Name' => $this->_config['auth']['username'], 'Password' => $this->_config['auth']['password']]),
            new \SoapHeader($this->_config['namespace'], 'Agency', ['Code' => $this->_config['agencyCode'], 'Culture' => $this->_config['culture']])
        ];
        $this->_client = new \SoapClient($this->_config['wsdl']);
        $this->_client->__setSoapHeaders($headers);
    }

    /**
     *  @brief Request for archive links
     *
     *  @param string $specificService Specific service to be requested or `all` by default.
     *  @return array
     *
     *  @details Costa services are async and designed to return link for the future .zip file.
     *           This means we have to save the address and check again later if the job is finished.
     */
    public function requestArchives($specificService = 'all')
    {
        $services = [
            'ExportAvailability' => ['serviceName' => 'ExportAvailability', 'apiParams' => []],
            'ExportPorts' => ['serviceName' => 'ExportPorts', 'apiParams' => []],
            'ExportPrice' => ['serviceName' => 'ExportPrice', 'apiParams' => []],
            'ExportCatalog' => ['serviceName' => 'ExportCatalog', 'apiParams' => []],
            'ExportExcursions' => ['serviceName' => 'ExportExcursions', 'apiParams' => []],
            'ExportItineraryAndSteps' => ['serviceName' => 'ExportItineraryAndSteps', 'apiParams' => []],
            'ExportPriceWithPaxBreakdown__Individual__TwoPax' => [
                'serviceName' => 'ExportPriceWithPaxBreakdown',
                'apiParams' => [
                    'expPriceType' => 'Individual',
                    'maxOccupancy' => 'TwoPax',
                ]
            ],
            'ExportPriceWithPaxBreakdown__Costa__TwoPax' => [
                'serviceName' => 'ExportPriceWithPaxBreakdown',
                'apiParams' => [
                    'expPriceType' => 'Costa',
                    'maxOccupancy' => 'TwoPax',
                ]
            ],
            'ExportPriceWithPaxBreakdown__Basic__TwoPax' => [
                'serviceName' => 'ExportPriceWithPaxBreakdown',
                'apiParams' => [
                    'expPriceType' => 'Basic',
                    'maxOccupancy' => 'TwoPax',
                ]
            ],
        ];

        // After 26.03 every year we do not need Individual price types.
        $summerOffersStartDate = date('Y') . '0326';
        if (date('Ymd') > $summerOffersStartDate) {
            unset($services['ExportPriceWithPaxBreakdown__Individual__TwoPax']);
        }

        // Only a Specific service?
        if ($specificService != 'all') {
            $services = [
                $specificService => $services[$specificService]
            ];
        }

        // Gather all links
        $archiveLinks = [];
        foreach ($services as $key => $data) {
            $service = $data['serviceName'];
            $resultKey = $service . 'Result';
            $apiParams = $data['apiParams'];
            $response = $this->_client->__call($service, [$apiParams]);
            if ($response->{$resultKey}) {
                $archiveLinks[$key] = $response->{$resultKey};
            }
        }
        return $archiveLinks;
    }
}

Usage:

$filesCollection = (new \Helpers\CostaSoapClient)->requestArchives();