Completed
Pull Request — master (#5)
by Meng
01:16
created

RequestBuilder::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
1
<?php
2
3
namespace Meng\Soap\HttpBinding;
4
5
use Psr\Http\Message\RequestFactoryInterface;
6
use Psr\Http\Message\RequestInterface;
7
use Psr\Http\Message\StreamFactoryInterface;
8
use Psr\Http\Message\StreamInterface;
9
10
/**
11
 * This class create PSR HTTP requests that embed SOAP messages.
12
 */
13
class RequestBuilder
14
{
15
    const SOAP11 = '1.1';
16
    const SOAP12 = '1.2';
17
18
    /**
19
     * @var string
20
     */
21
    private $endpoint;
22
    /**
23
     * @var string
24
     */
25
    private $soapVersion = self::SOAP11;
26
    /**
27
     * @var string
28
     */
29
    private $soapAction = '';
30
    /**
31
     * @var StreamInterface
32
     */
33
    private $soapMessage;
34
    /**
35
     * @var bool
36
     */
37
    private $hasSoapMessage = false;
38
    /**
39
     * @var string
40
     */
41
    private $httpMethod = 'POST';
42
43
    private $streamFactory;
44
45
    private $requestFactory;
46
47
    public function __construct(StreamFactoryInterface $streamFactory, RequestFactoryInterface $requestFactory)
48
    {
49
        $this->streamFactory = $streamFactory;
50
        $this->requestFactory = $requestFactory;
51
    }
52
53
    /**
54
     * @return RequestInterface
55
     * @throws RequestException
56
     */
57
    public function getSoapHttpRequest()
58
    {
59
        $this->validate();
60
        $headers = $this->prepareHeaders();
61
        $message = $this->prepareMessage();
62
        $request = $this->requestFactory->createRequest($this->httpMethod, $this->endpoint);
63
        foreach ($headers as $key => $value) {
64
            $request = $request->withHeader($key, $value);
65
        }
66
        $request = $request->withBody($message);
67
        $this->unsetAll();
68
        return $request;
69
    }
70
71
    /**
72
     * @param string $endpoint
73
     * @return self
74
     */
75
    public function setEndpoint($endpoint)
76
    {
77
        $this->endpoint = $endpoint;
78
        return $this;
79
    }
80
81
    /**
82
     * @return self
83
     */
84
    public function isSOAP11()
85
    {
86
        $this->soapVersion = self::SOAP11;
87
        return $this;
88
    }
89
90
    public function isSOAP12()
91
    {
92
        $this->soapVersion = self::SOAP12;
93
        return $this;
94
    }
95
96
97
    /**
98
     * @param string $soapAction
99
     * @return self
100
     */
101
    public function setSoapAction($soapAction)
102
    {
103
        $this->soapAction = $soapAction;
104
        return $this;
105
    }
106
107
    /**
108
     * @param StreamInterface $message
109
     * @return self
110
     */
111
    public function setSoapMessage(StreamInterface $message)
112
    {
113
        $this->soapMessage = $message;
114
        $this->hasSoapMessage = true;
115
        return $this;
116
    }
117
118
    /**
119
     * @param string $method
120
     * @return self
121
     */
122
    public function setHttpMethod($method)
123
    {
124
        $this->httpMethod = $method;
125
        return $this;
126
    }
127
128
    private function validate()
129
    {
130
        $isValid = true;
131
132
        if (!$this->endpoint) {
133
            $isValid = false;
134
        }
135
136
        if (!$this->hasSoapMessage && $this->httpMethod == 'POST') {
137
            $isValid = false;
138
        }
139
140
        /**
141
         * SOAP 1.1 only defines HTTP binding with POST method.
142
         * @link https://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383527
143
         */
144
        if ($this->soapVersion == self::SOAP11 && $this->httpMethod != 'POST') {
145
            $isValid = false;
146
        }
147
148
        /**
149
         * SOAP 1.2 only defines HTTP binding with POST and GET methods.
150
         * @link https://www.w3.org/TR/2007/REC-soap12-part0-20070427/#L10309
151
         */
152
        if ($this->soapVersion == self::SOAP12 && !in_array($this->httpMethod, ['GET', 'POST'])) {
153
            $isValid = false;
154
        }
155
156
        if (!$isValid) {
157
            $this->unsetAll();
158
            throw new RequestException;
159
        }
160
    }
161
162
    /**
163
     * @return array
164
     */
165
    private function prepareHeaders()
166
    {
167
        if ($this->soapVersion == self::SOAP11) {
168
            return $this->prepareSoap11Headers();
169
        } else {
170
            return $this->prepareSoap12Headers();
171
        }
172
    }
173
174
    /**
175
     * @link https://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383526
176
     * @return array
177
     */
178
    private function prepareSoap11Headers()
179
    {
180
        $headers = [];
181
        $headers['Content-Length'] = $this->soapMessage->getSize();
182
        $headers['SOAPAction'] = $this->soapAction;
183
        $headers['Content-Type'] = 'text/xml; charset="utf-8"';
184
        return $headers;
185
    }
186
187
    /**
188
     * SOSPAction header is removed in SOAP 1.2 and now expressed as a value of
189
     * an (optional) "action" parameter of the "application/soap+xml" media type.
190
     * @link https://www.w3.org/TR/soap12-part0/#L4697
191
     * @return array
192
     */
193
    private function prepareSoap12Headers()
194
    {
195
        $headers = [];
196
        if ($this->httpMethod == 'POST') {
197
            $headers['Content-Length'] = $this->soapMessage->getSize();
198
            $headers['Content-Type'] = 'application/soap+xml; charset="utf-8"' . '; action="' . $this->soapAction . '"';
199
        } else {
200
            $headers['Accept'] = 'application/soap+xml';
201
        }
202
        return $headers;
203
    }
204
205
    /**
206
     * @return StreamInterface
207
     */
208
    private function prepareMessage()
209
    {
210
        if ($this->httpMethod == 'POST') {
211
            return $this->soapMessage;
212
        } else {
213
            return $this->streamFactory->createStream();
214
        }
215
    }
216
217
    private function unsetAll()
218
    {
219
        $this->endpoint = null;
220
        if ($this->hasSoapMessage) {
221
            $this->soapMessage = null;
222
            $this->hasSoapMessage = false;
223
        }
224
        $this->soapAction = '';
225
        $this->soapVersion = self::SOAP11;
226
        $this->httpMethod = 'POST';
227
    }
228
}
229