Completed
Push — master ( 2cc775...476323 )
by Meng
02:52
created

RequestBuilder::validate()   D

Complexity

Conditions 9
Paths 32

Size

Total Lines 33
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

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