Passed
Pull Request — master (#22)
by Rhodri
07:11
created

Client::store()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 11
c 1
b 0
f 0
nc 5
nop 2
dl 0
loc 18
rs 9.6111
1
<?php
2
3
declare(strict_types=1);
4
5
namespace TheCodingMachine\Gotenberg;
6
7
use Exception;
8
use GuzzleHttp\Psr7\MultipartStream;
9
use Http\Client\HttpClient;
10
use Http\Discovery\HttpClientDiscovery;
11
use Http\Discovery\MessageFactoryDiscovery;
12
use Psr\Http\Message\RequestInterface;
13
use Psr\Http\Message\ResponseInterface;
14
use function fclose;
15
use function fopen;
16
use function fwrite;
17
18
final class Client
19
{
20
    /** @var HttpClient */
21
    private $client;
22
23
    /** @var string */
24
    private $apiURL;
25
26
    public function __construct(string $apiURL, ?HttpClient $client = null)
27
    {
28
        $this->apiURL = $apiURL;
29
        $this->client = $client ?: HttpClientDiscovery::find();
30
    }
31
32
    /**
33
     * Sends the given documents to the API and returns the response.
34
     *
35
     * @throws ClientException
36
     * @throws Exception
37
     */
38
    public function post(GotenbergRequestInterface $request): ResponseInterface
39
    {
40
        return $this->handleResponse($this->client->sendRequest($this->makeMultipartFormDataRequest($request)));
41
    }
42
43
    /**
44
     * Sends the given documents to the API, stores the resulting PDF in the given destination.
45
     *
46
     * @throws ClientException
47
     * @throws RequestException
48
     * @throws Exception
49
     * @throws FilesystemException
50
     */
51
    public function store(GotenbergRequestInterface $request, string $destination): void
52
    {
53
        if ($request->hasWebhook()) {
54
            throw new RequestException('Cannot use method store with a webhook.');
55
        }
56
        $response = $this->handleResponse($this->client->sendRequest($this->makeMultipartFormDataRequest($request)));
57
        $fileStream = $response->getBody();
58
        $fp = fopen($destination, 'w');
59
        if ($fp === false) {
60
            throw FilesystemException::createFromPhpError();
61
        }
62
63
        if (fwrite($fp, $fileStream->getContents()) === false) {
64
            throw FilesystemException::createFromPhpError();
65
        }
66
67
        if (fclose($fp) === false) {
68
            throw FilesystemException::createFromPhpError();
69
        }
70
    }
71
72
    private function makeMultipartFormDataRequest(GotenbergRequestInterface $request): RequestInterface
73
    {
74
        $multipartData = [];
75
        foreach ($request->getFormValues() as $fieldName => $fieldValue) {
76
            $multipartData[] = [
77
                'name' => $fieldName,
78
                'contents' => $fieldValue,
79
            ];
80
        }
81
        /**
82
         * @var string $filename
83
         * @var Document $document
84
         */
85
        foreach ($request->getFormFiles() as $filename => $document) {
86
            $multipartData[] = [
87
                'name' => 'files',
88
                'filename' => $filename,
89
                'contents' => $document->getFileStream(),
90
            ];
91
        }
92
        $body = new MultipartStream($multipartData);
93
        $messageFactory = MessageFactoryDiscovery::find();
94
        $message = $messageFactory
95
            ->createRequest('POST', $this->apiURL . $request->getPostURL())
96
            ->withHeader('Content-Type', 'multipart/form-data; boundary="' . $body->getBoundary() . '"')
97
            ->withBody($body);
98
        foreach ($request->getCustomHTTPHeaders() as $key => $value) {
99
            $message = $message->withHeader($key, $value);
100
        }
101
102
        return $message;
103
    }
104
105
    /**
106
     * @throws ClientException
107
     */
108
    private function handleResponse(ResponseInterface $response): ResponseInterface
109
    {
110
        switch ($response->getStatusCode()) {
111
            case 200:
112
                return $response;
113
            default:
114
                throw new ClientException($response->getBody()->getContents(), $response->getStatusCode());
115
        }
116
    }
117
}
118