codenix-sv/api-client

View on GitHub
src/BaseClient.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php

declare(strict_types=1);

namespace Codenixsv\ApiClient;

use Codenixsv\ApiClient\Configurator\RequestConfiguratorInterface;
use Psr\Http\Client\ClientExceptionInterface;
use Http\Discovery\Psr17FactoryDiscovery;
use Http\Discovery\Psr18ClientDiscovery;
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamFactoryInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UriFactoryInterface;

/**
 * Class BaseClient
 * @package Codenixsv\ApiClient
 */
class BaseClient implements BaseClientInterface
{
    /** @var ClientInterface  */
    private $httpClient;
    /** @var RequestFactoryInterface  */
    private $requestFactory;
    /** @var UriFactoryInterface  */
    private $uriFactory;
    /** @var StreamFactoryInterface  */
    private $streamFactory;
    /** @var string  */
    private $baseUri = '';
    /** @var RequestConfiguratorInterface[] */
    private $requestConfigurators = [];

    public function __construct(
        ?ClientInterface $httpClient = null,
        ?RequestFactoryInterface $requestFactory = null,
        ?UriFactoryInterface $uriFactory = null,
        ?StreamFactoryInterface $streamFactory = null
    ) {
        $this->httpClient = $httpClient ?: Psr18ClientDiscovery::find();
        $this->requestFactory = $requestFactory ?: Psr17FactoryDiscovery::findRequestFactory();
        $this->uriFactory = $uriFactory ?: Psr17FactoryDiscovery::findUrlFactory();
        $this->streamFactory = $streamFactory ?: Psr17FactoryDiscovery::findStreamFactory();
    }

    /**
     * @return ClientInterface
     */
    public function getHttpClient(): ClientInterface
    {
        return $this->httpClient;
    }

    /**
     * @return string
     */
    public function getBaseUri(): string
    {
        return $this->baseUri;
    }

    /**
     * @param string $baseUri
     */
    public function setBaseUri(string $baseUri): void
    {
        $this->baseUri = $baseUri;
    }

    /**
     * @param RequestConfiguratorInterface $configurator
     */
    public function addRequestConfigurator(RequestConfiguratorInterface $configurator): void
    {
        $this->requestConfigurators[] = $configurator;
    }

    /**
     * @return void
     */
    public function clearRequestConfigurators(): void
    {
        $this->requestConfigurators = [];
    }

    /**
     * @return RequestConfiguratorInterface[]
     */
    public function getRequestConfigurators(): array
    {
        return $this->requestConfigurators;
    }

    /**
     * @param string $method
     * @param string $endpoint
     * @param null|string|StreamInterface|resource $body
     * @param array $headers
     * @return ResponseInterface
     * @throws ClientExceptionInterface
     */
    public function request(string $method, string $endpoint, $body = null, array $headers = []): ResponseInterface
    {
        $request = $this->buildRequest($method, $endpoint, $body, $headers);
        return $this->httpClient->sendRequest($request);
    }

    /**
     * @param RequestInterface $request
     * @return RequestInterface
     */
    private function configureRequest(RequestInterface $request): RequestInterface
    {
        foreach ($this->requestConfigurators as $configurator) {
            $request = $configurator->configure($request);
        }
        return $request;
    }

    /**
     * @param string $endpoint
     * @param array $headers
     * @return ResponseInterface
     * @throws ClientExceptionInterface
     */
    public function get(string $endpoint, array $headers = []): ResponseInterface
    {
        return $this->request('GET', $endpoint, null, $headers);
    }

    /**
     * @param string $endpoint
     * @param $body
     * @param array $headers
     * @return ResponseInterface
     * @throws ClientExceptionInterface
     */
    public function post(string $endpoint, $body, array $headers = []): ResponseInterface
    {
        return $this->request('POST', $endpoint, $body, $headers);
    }

    /**
     * @param string $endpoint
     * @param $body
     * @param array $headers
     * @return ResponseInterface
     * @throws ClientExceptionInterface
     */
    public function patch(string $endpoint, $body, array $headers = []): ResponseInterface
    {
        return $this->request('PATCH', $endpoint, $body, $headers);
    }

    /**
     * @param string $endpoint
     * @param $body
     * @param array $headers
     * @return ResponseInterface
     * @throws ClientExceptionInterface
     */
    public function put(string $endpoint, $body, array $headers = []): ResponseInterface
    {
        return $this->request('PUT', $endpoint, $body, $headers);
    }

    /**
     * @param string $endpoint
     * @param array $headers
     * @return ResponseInterface
     * @throws ClientExceptionInterface
     */
    public function delete(string $endpoint, array $headers = []): ResponseInterface
    {
        return $this->request('DELETE', $endpoint, null, $headers);
    }

    /**
     * @param string $method
     * @param string $endpoint
     * @param $body
     * @param array $headers
     * @return RequestInterface
     */
    protected function buildRequest(
        string $method,
        string $endpoint,
        $body = null,
        array $headers = []
    ): RequestInterface {
        $uri = $this->uriFactory->createUri($this->getBaseUri() . $endpoint);

        $request = $this->requestFactory->createRequest($method, $uri);
        $request = $this->appendBodyToRequest($request, $body);
        $request = $this->appendHeadersToRequest($request, $headers);
        $request = $this->configureRequest($request);

        return $request;
    }

    /**
     * @param RequestInterface $request
     * @param array $headers
     * @return RequestInterface
     */
    protected function appendHeadersToRequest(RequestInterface $request, array $headers)
    {
        foreach ($headers as $name => $value) {
            $request = $request->withHeader($name, $value);
        }
        return $request;
    }

    /**
     * @param RequestInterface $request
     * @param $body
     * @return RequestInterface
     */
    protected function appendBodyToRequest(RequestInterface $request, $body)
    {
        if ($body !== null) {
            if (is_resource($body)) {
                $body = $this->streamFactory->createStreamFromResource($body);
            }
            if (!($body instanceof StreamInterface)) {
                $body = $this->streamFactory->createStream((string) $body);
            }
            $request = $request->withBody($body);
        }

        return $request;
    }
}