GuzzleHttpClient::getRequest()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 19
ccs 11
cts 11
cp 1
rs 9.6333
c 0
b 0
f 0
cc 3
nc 4
nop 3
crap 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Bip70\Client;
6
7
use Bip70\Client\Exception\ProtocolException;
8
use Bip70\Client\NetworkConfig\NetworkConfigInterface;
9
use Bip70\Protobuf\Codec\NonDiscardingBinaryCodec;
10
use Bip70\Protobuf\Proto\Payment;
11
use Bip70\Protobuf\Proto\PaymentACK;
12
use Bip70\Protobuf\Proto\PaymentDetails;
13
use Bip70\Protobuf\Proto\PaymentRequest;
14
use Bip70\X509\RequestValidation;
15
use Bip70\X509\PKIType;
16
use GuzzleHttp\Client;
17
use Psr\Http\Message\ResponseInterface;
18
19
class GuzzleHttpClient
20
{
21
    /**
22
     * @var \GuzzleHttp\Client
23
     */
24
    private $client;
25
26
    /**
27
     * @var bool
28
     */
29
    private $checkContentType = true;
30
31
    /**
32
     * HttpClient constructor.
33
     * @param Client|null $client
34
     */
35 6
    public function __construct(Client $client = null)
36
    {
37 6
        $this->client = $client ?: new Client();
38 6
    }
39
40
    /**
41
     * @param bool $setting
42
     * @return void
43
     */
44
    public function setCheckContentType(bool $setting)
45
    {
46
        $this->checkContentType = $setting;
47
    }
48
49
    /**
50
     * @param string $url
51
     * @param string $acceptType
52
     * @return ResponseInterface
53
     */
54 6
    private function get($url, string $acceptType)
55
    {
56
        $options = [
57 6
            "headers" => ["Accept" => $acceptType,]
58
        ];
59
60 6
        $response = $this->client->get($url, $options);
61
62 6
        if ($this->checkContentType) {
63 6
            $this->checkContentType($acceptType, $response);
64
        }
65
66 4
        return $response;
67
    }
68
69
    /**
70
     * @param string $url
71
     * @param string $acceptType
72
     * @param string $dataMIMEType
73
     * @param string $data
74
     * @return ResponseInterface
75
     */
76
    private function post(string $url, string $acceptType, string $dataMIMEType, string $data): ResponseInterface
77
    {
78
        $options = [
79
            "headers" => [
80
                "Accept" => $acceptType,
81
                "Content-Type" => $dataMIMEType,
82
            ],
83
            'body' => $data,
84
        ];
85
86
        $response = $this->client->post($url, $options);
87
88
        if ($this->checkContentType) {
89
            $this->checkContentType($acceptType, $response);
90
        }
91
92
        return $response;
93
    }
94
95
    /**
96
     * @param string $expectType
97
     * @param ResponseInterface $response
98
     */
99 6
    public function checkContentType(string $expectType, ResponseInterface $response)
100
    {
101 6
        if (!$response->hasHeader("Content-Type")) {
102 1
            throw new ProtocolException("Missing Content-Type header");
103
        }
104
105 5
        $contentType = $response->getHeader("Content-Type");
106 5
        if (!in_array($expectType, $contentType)) {
107 1
            throw new ProtocolException("Content-Type was not " . $expectType);
108
        }
109 4
    }
110
111
    /**
112
     * @param string $requestUrl
113
     * @param RequestValidation $requestValidation
114
     * @param NetworkConfigInterface $networkConfig
115
     * @return PaymentRequestInfo
116
     * @throws ProtocolException
117
     * @throws \Bip70\Exception\X509Exception
118
     */
119 6
    public function getRequest(string $requestUrl, RequestValidation $requestValidation, NetworkConfigInterface $networkConfig): PaymentRequestInfo
120
    {
121 6
        $response = $this->get($requestUrl, $networkConfig->getPaymentRequestMimeType());
122 4
        $paymentRequest = new PaymentRequest();
123
124
        try {
125 4
            $contents = $response->getBody()->getContents();
126 4
            $paymentRequest->parse($contents, new NonDiscardingBinaryCodec());
127 1
        } catch (\Exception $e) {
128 1
            throw new ProtocolException("Failed to decode payment request", 0, $e);
129
        }
130
131 3
        $validationResult = null;
132 3
        if ($paymentRequest->getPkiType() !== PKIType::NONE) {
133 2
            $validationResult = $requestValidation->verifyX509Details($paymentRequest);
134
        }
135
136 3
        return new PaymentRequestInfo($paymentRequest, $validationResult);
137
    }
138
139
    /**
140
     * @param PaymentDetails $details
141
     * @param NetworkConfigInterface $networkConfig
142
     * @param string|null $memo
143
     * @param string ...$transactions
144
     * @return PaymentACK
145
     */
146
    public function sendPayment(PaymentDetails $details, NetworkConfigInterface $networkConfig, string $memo = null, string ...$transactions): PaymentACK
147
    {
148
        if (!$details->hasPaymentUrl()) {
149
            throw new \RuntimeException("No payment url set on details");
150
        }
151
152
        $payment = new Payment();
153
        foreach ($transactions as $transaction) {
154
            $payment->addTransactions($transaction);
155
        }
156
157
        if ($details->hasMerchantData()) {
158
            $payment->setMerchantData($details->getMerchantData());
159
        }
160
161
        if ($memo !== null) {
162
            $payment->setMemo($memo);
163
        }
164
165
        $paymentData = $payment->serialize();
166
        $result = $this->post($details->getPaymentUrl(), $networkConfig->getPaymentAckMimeType(), $networkConfig->getPaymentMimeType(), $paymentData);
167
168
        $ack = new PaymentACK();
169
170
        try {
171
            $ack->parse($result->getBody()->getContents());
172
        } catch (\Exception $e) {
173
            throw new \RuntimeException("Failed to decode Payment ACK message");
174
        }
175
176
        return $ack;
177
    }
178
}
179