Skip to content

Why?

Imagine you have to fetch some data from an external WebService.

You need to instanciate some client, make the call, parse the response, cache it, handle exceptions, manually manage concurrent calls, log, etc.

All this code could be repeated in multiple places and projects:

use GuzzleHttp\Client;

$client = new Client();
$response = $client->request('GET', 'https://api.example.com/get-data');

$data = json_decode(
    $response->getBody()->getContents(),
    true,
    512,
    JSON_THROW_ON_ERROR
);

// Here you might have to handle the cache, exceptions, etc

echo $data['foo'];

Exemple

With WebZ you can abstract all this. Let say we want to fetch this data object:

namespace Acme;

class Place
{
    private string $name;

    public function __construct(string $name)
    {
        $this->name = $name;
    }

    public function name(): string
    {
        return $this->name;
    }
}

HTTP

It can be fetched from an HTTP request:

use Acme\Place;
use CuyZ\WebZ\Core\WebService;
use CuyZ\WebZ\Http\Payload\HttpPayload;

class GetPlace extends WebService
{
    private int $id;

    public function __construct(int $id)
    {
        $this->id = $id;
    }

    protected function payload(): HttpPayload
    {
        return HttpPayload::request(
            'GET',
            'https://my-api.com/v1/place/' . $this->id
        );
    }

    public function parse(array $data): Place
    {
        return new Place($data['name']);
    }
}

SOAP

Or from SOAP:

use Acme\Place;
use CuyZ\WebZ\Core\WebService;
use CuyZ\WebZ\Soap\SoapPayload;

class GetPlace extends WebService
{
    private int $id;

    public function __construct(int $id)
    {
        $this->id = $id;
    }

    protected function payload(): SoapPayload
    {
        return SoapPayload::forWsdl('https://my-example.com/api/wsdl.xml')
            ->withAction('getPlace')
            ->withArguments([$this->id]);
    }

    public function parse(array $data): Place
    {
        return new Place($data['name']);
    }
}

The call

You then call any WebService via the Bus and a compatible transport will call the WebService:

use Acme\Place;
use CuyZ\WebZ\Core\Bus\WebServiceBus;
use CuyZ\WebZ\Http\HttpTransport;
use CuyZ\WebZ\Soap\SoapTransport;

$bus = WebServiceBus::builder()
    ->withTransport(new HttpTransport())
    ->withTransport(new SoapTransport())
    ->build();

$place = $bus->call(new GetPlace(123));

echo $place->name();

// You can also call multiple webservices in concurrency
$promises = $bus->callAsync(
    new GetPlace(123),
    new GetPlace(456),
);

foreach ($promises as $promise) {
    /** @var Place $place */
    $place = $promise->wait();

    echo $place->name();
}

In the end the GetPlace class looks transport agnostic and can be reused anywhere in your project.

And if the WebService changes anything (url, parameters, protocol, etc) you only have one place to update in your code.