Completed
Push — master ( 48aedc...366f16 )
by thomas
06:09
created

GuzzleHttpClient::post()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

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

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
157
            $payment->setMemo($memo);
158
        }
159
160
        $paymentData = $payment->serialize();
161
        $result = $this->post($details->getPaymentUrl(), MIMEType::PAYMENT_ACK, MIMEType::PAYMENT, $paymentData);
162
163
        $ack = new PaymentACK();
164
165
        try {
166
            $ack->parse($result->getBody()->getContents());
167
        } catch (\Exception $e) {
168
            throw new \RuntimeException("Failed to decode Payment ACK message");
169
        }
170
171
        return $ack;
172
    }
173
}
174